[
  {
    "path": ".github/DISCUSSION_TEMPLATE/q-a.yml",
    "content": "labels: [question]\nbody:\n  - type: checkboxes\n    id: guidelines\n    attributes:\n      label: Contributing guidelines\n      options:\n      - label: I have read [CODE_OF_CONDUCT.md](https://github.com/nvim-mini/mini.nvim/blob/main/CODE_OF_CONDUCT.md)\n        required: true\n  - type: dropdown\n    id: module\n    attributes:\n      label: \"Module(s)\"\n      description: \"Choose one or several modules this question is related to\"\n      multiple: true\n      options:\n        - mini.ai\n        - mini.align\n        - mini.animate\n        - mini.base16\n        - mini.basics\n        - mini.bracketed\n        - mini.bufremove\n        - mini.clue\n        - mini.cmdline\n        - mini.colors\n        - mini.comment\n        - mini.completion\n        - mini.cursorword\n        - mini.deps\n        - mini.diff\n        - mini.doc\n        - mini.extra\n        - mini.files\n        - mini.fuzzy\n        - mini.git\n        - mini.hipatterns\n        - mini.hues\n        - mini.icons\n        - mini.indentscope\n        - mini.jump\n        - mini.jump2d\n        - mini.keymap\n        - mini.map\n        - mini.misc\n        - mini.move\n        - mini.notify\n        - mini.operators\n        - mini.pairs\n        - mini.pick\n        - mini.sessions\n        - mini.snippets\n        - mini.splitjoin\n        - mini.starter\n        - mini.statusline\n        - mini.surround\n        - mini.tabline\n        - mini.test\n        - mini.trailspace\n        - mini.visits\n        - none of the above\n        - all of the above\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: \"Question\"\n    validations:\n      required: true\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "content": "name: Bug report\ndescription: Report a problem with the existing module(s)\nlabels: [bug]\nbody:\n  - type: checkboxes\n    id: guidelines\n    attributes:\n      label: Contributing guidelines\n      options:\n      - label: I have read [CONTRIBUTING.md](https://github.com/nvim-mini/mini.nvim/blob/main/CONTRIBUTING.md)\n        required: true\n      - label: I have read [CODE_OF_CONDUCT.md](https://github.com/nvim-mini/mini.nvim/blob/main/CODE_OF_CONDUCT.md)\n        required: true\n      - label: I have updated 'mini.nvim' to latest version of the `main` branch\n        required: true\n  - type: dropdown\n    id: module\n    attributes:\n      label: \"Module(s)\"\n      description: \"Choose one or several modules the problem is related to\"\n      multiple: true\n      options:\n        - mini.ai\n        - mini.align\n        - mini.animate\n        - mini.base16\n        - mini.basics\n        - mini.bracketed\n        - mini.bufremove\n        - mini.clue\n        - mini.cmdline\n        - mini.colors\n        - mini.comment\n        - mini.completion\n        - mini.cursorword\n        - mini.deps\n        - mini.diff\n        - mini.doc\n        - mini.extra\n        - mini.files\n        - mini.fuzzy\n        - mini.git\n        - mini.hipatterns\n        - mini.hues\n        - mini.icons\n        - mini.indentscope\n        - mini.jump\n        - mini.jump2d\n        - mini.keymap\n        - mini.map\n        - mini.misc\n        - mini.move\n        - mini.notify\n        - mini.operators\n        - mini.pairs\n        - mini.pick\n        - mini.sessions\n        - mini.snippets\n        - mini.splitjoin\n        - mini.starter\n        - mini.statusline\n        - mini.surround\n        - mini.tabline\n        - mini.test\n        - mini.trailspace\n        - mini.visits\n    validations:\n      required: true\n  - type: dropdown\n    id: nvim-version\n    attributes:\n      label: \"Neovim version\"\n      description: \"Choose the latest Neovim version on which you can reproduce the problem\"\n      multiple: false\n      options:\n        - 0.9.x\n        - 0.10.x\n        - 0.11.x\n        - 0.12 (!at least latest Nightly build!)\n      default: 2\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: \"Description\"\n      description: \"A short description of a problem; include expected behavior\"\n    validations:\n      required: true\n  - type: textarea\n    id: reproduction\n    attributes:\n      label: \"Reproduction\"\n      description: \"Steps to reproduce the issue. Suggested steps involve creating an independent config from scratch. If can not reproduce like this, please ask a usage question first.\"\n      value: |\n        1. Create separate 'nvim-repro' config directory:\n            - '~/.config/nvim-repro/' on Unix\n            - '~/AppData/Local/nvim-repro/' on Windows\n\n        2. Inside 'nvim-repro' directory create a file named 'init.lua'.\n           Populate it with the following content:\n\n            ```lua\n            -- Clone latest 'mini.nvim' (requires Git CLI installed)\n            vim.cmd('echo \"Installing `mini.nvim`\" | redraw')\n            local mini_path = vim.fn.stdpath('data') .. '/site/pack/deps/start/mini.nvim'\n            local clone_cmd = { 'git', 'clone', '--depth=1', 'https://github.com/nvim-mini/mini.nvim', mini_path }\n            vim.fn.system(clone_cmd)\n            vim.cmd('echo \"`mini.nvim` is installed\" | redraw')\n\n            -- Make sure 'mini.nvim' is available\n            vim.cmd('packadd mini.nvim')\n            require('mini.deps').setup()\n\n            -- Add extra setup steps needed to reproduce the behavior\n            -- Use `MiniDeps.add('user/repo')` to install another plugin from GitHub\n            ```\n\n        3. Run `NVIM_APPNAME=nvim-repro nvim` (i.e. execute `nvim` with `NVIM_APPNAME` environment variable set to \"nvim-repro\").\n           Wait for all dependencies to install.\n\n        4. Replace this with description of interactive reproduction steps along with the behavior you observe.\n           Feel free to include images/videos/etc, this helps a lot.\n\n        <details><summary>What to do after reporting an issue</summary>\n\n        After reporting the issue, it is safe (and even recommended for cleaner possible future bug reports) to remove 'nvim-repro' config from the system:\n        - Delete config directory ('~/.config/nvim-repro' on Unix).\n        - Delete data directory ('~/.local/share/nvim-repro' on Unix).\n        - Delete state directory ('~/.local/state/nvim-repro' on Unix).\n\n        </details>\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Question\n    url: https://github.com/nvim-mini/mini.nvim/discussions/new?category=q-a\n    about: Ask about configuration and usage of 'mini.nvim'\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "name: Feature request\ndescription: Describe a new feature you would like to see\nlabels: [feature-request]\nbody:\n  - type: checkboxes\n    id: guidelines\n    attributes:\n      label: Contributing guidelines\n      options:\n      - label: I have read [CONTRIBUTING.md](https://github.com/nvim-mini/mini.nvim/blob/main/CONTRIBUTING.md)\n        required: true\n      - label: I have read [CODE_OF_CONDUCT.md](https://github.com/nvim-mini/mini.nvim/blob/main/CODE_OF_CONDUCT.md)\n        required: true\n  - type: dropdown\n    id: module\n    attributes:\n      label: \"Module(s)\"\n      description: \"Choose one or several modules this feature is related to. Choose 'new' for a new module suggestion.\"\n      multiple: true\n      options:\n        - mini.ai\n        - mini.align\n        - mini.animate\n        - mini.base16\n        - mini.basics\n        - mini.bracketed\n        - mini.bufremove\n        - mini.clue\n        - mini.cmdline\n        - mini.colors\n        - mini.comment\n        - mini.completion\n        - mini.cursorword\n        - mini.deps\n        - mini.diff\n        - mini.doc\n        - mini.extra\n        - mini.files\n        - mini.fuzzy\n        - mini.git\n        - mini.hipatterns\n        - mini.hues\n        - mini.icons\n        - mini.indentscope\n        - mini.jump\n        - mini.jump2d\n        - mini.keymap\n        - mini.map\n        - mini.misc\n        - mini.move\n        - mini.notify\n        - mini.operators\n        - mini.pairs\n        - mini.pick\n        - mini.sessions\n        - mini.snippets\n        - mini.splitjoin\n        - mini.starter\n        - mini.statusline\n        - mini.surround\n        - mini.tabline\n        - mini.test\n        - mini.trailspace\n        - mini.visits\n        - new\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: \"Description\"\n      description: \"A concise and justified description of a feature\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "- [ ] I have read [CONTRIBUTING.md](https://github.com/nvim-mini/mini.nvim/blob/main/CONTRIBUTING.md)\n- [ ] I have read [CODE_OF_CONDUCT.md](https://github.com/nvim-mini/mini.nvim/blob/main/CODE_OF_CONDUCT.md)\n"
  },
  {
    "path": ".github/workflows/quality-control.yml",
    "content": "name: Quality Control\n\non:\n  push:\n    branches-ignore: [ sync, stable ]\n  pull_request:\n    branches-ignore: [ sync, stable ]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}-${{ github.actor }}\n  cancel-in-progress: true\n\njobs:\n  detect-changes:\n    name: Detect changes\n    runs-on: ubuntu-latest\n    outputs:\n      code: ${{ steps.filter.outputs.code }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: dorny/paths-filter@v3\n        id: filter\n        with:\n          filters: |\n            code:\n              - 'colors/**'\n              - 'lua/**'\n              - 'tests/**'\n              - 'scripts/minimal_init.lua'\n              - '.github/workflows/**'\n\n  test:\n    name: Test\n    # Run only if testable code has changed (to save time and resources)\n    needs: detect-changes\n    if: ${{ needs.detect-changes.outputs.code == 'true' }}\n    timeout-minutes: 15\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-latest ]\n        neovim_version: [ 'v0.9.5', 'v0.10.4', 'v0.11.5', 'nightly' ]\n        include:\n        - os: macos-latest\n          neovim_version: v0.11.5\n        - os: windows-latest\n          neovim_version: v0.11.5\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup neovim\n        uses: rhysd/action-setup-vim@v1\n        with:\n          neovim: true\n          version: ${{ matrix.neovim_version }}\n\n      - name: Run tests\n        run: make test\n\n  lint-gendoc:\n    name: Lint document generation\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install Neovim\n        uses: rhysd/action-setup-vim@v1\n        with:\n          neovim: true\n          version: v0.11.5\n\n      - name: Generate documentation\n        run: make --silent documentation\n\n      - name: Check for changes\n        run: if [[ -n $(git status -s) ]]; then exit 1; fi\n\n  lint-formatting:\n    name: Lint formatting\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: JohnnyMorganz/stylua-action@v4\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          version: v2.1.0\n          # CLI arguments\n          args: --color always --respect-ignores --check .\n\n  lint-commit:\n    name: Lint new commits\n    runs-on: ubuntu-latest\n    env:\n      LINTCOMMIT_STRICT: true\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n          ref: ${{ github.event.pull_request.head.sha || github.ref }}\n\n      - name: Install Neovim\n        uses: rhysd/action-setup-vim@v1\n        with:\n          neovim: true\n          version: v0.11.5\n\n      - name: Lint new commits\n        run: make --silent lintcommit-ci\n\n  lint-filename:\n    name: Lint filenames\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Check filename legnths\n        run: make --silent lint-filename-length-ci\n\n      - name: Check case sensitivity\n        uses: credfeto/action-case-checker@v1.2.1\n\n  check-workflow-status:\n    name: Check workflow status\n    runs-on: ubuntu-latest\n    needs: [ test, lint-gendoc, lint-formatting, lint-commit, lint-filename ]\n    if: always()\n\n    steps:\n      - name: Check workflow status\n        run: |\n          exit_on_result() {\n            if [[ \"$2\" == \"failure\" || \"$2\" == \"cancelled\" ]]; then\n              echo \"Job '$1' failed or was cancelled.\"\n              exit 1\n            fi\n          }\n          exit_on_result \"test\" \"${{ needs.test.result }}\"\n          exit_on_result \"lint-gendoc\" \"${{ needs.lint-gendoc.result }}\"\n          exit_on_result \"lint-formatting\" \"${{ needs.lint-formatting.result }}\"\n          exit_on_result \"lint-commit\" \"${{ needs.lint-commit.result }}\"\n          exit_on_result \"lint-filename\" \"${{ needs.lint-filename.result }}\"\n"
  },
  {
    "path": ".gitignore",
    "content": "doc/tags\ndual\n.nvim.lua\nSession.vim\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: local\n    hooks:\n      - id: stylua\n        name: StyLua\n        language: system\n        entry: stylua\n        args: [--respect-ignores]\n        types: [lua]\n      - id: gendocs\n        name: Gendocs\n        language: system\n        entry: make --silent documentation\n        types: [lua]\n      - id: lintcommit\n        name: LintCommit\n        language: system\n        entry: nvim\n        args: ['--headless', '--noplugin', '-u', 'scripts/lintcommit.lua', '--']\n        stages: ['commit-msg']\n"
  },
  {
    "path": ".stylua.toml",
    "content": "column_width = 120\nline_endings = \"Unix\"\nindent_type = \"Spaces\"\nindent_width = 2\nquote_style = \"AutoPreferSingle\"\ncall_parentheses = \"Always\"\ncollapse_simple_statement = \"Always\"\n"
  },
  {
    "path": ".styluaignore",
    "content": "dual\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "This is the log of changes for past and current development versions. It lists changes in user-facing functionality per module (or all modules) and type.\n\nThere are following change types:\n\n- `Evolve` - change in previously intended functionality *while* adding a new one.\n- `Refine` - change in previously intended functionality *without* adding new one. This is usually described as a \"breaking change\", but used here in a sense that it might break user's expectations about existing functionality.\n- `Expand` - adding new functionality without affecting existing ones. This is essentially new features.\n\n# Version 0.18.0-dev\n\n## mini.base16\n\n### Expand\n\n- Add new plugin integrations:\n    - 'folke/snacks.nvim'\n\n## mini.clue\n\n### Expand\n\n- Allow mode arrays for clues and triggers for parity with `modes` parameter of `vim.keymap.set`. By @pkazmier, PR #2202.\n\n## mini.extra\n\n### Expand\n\n- Add `pickers.manpages` picker.\n\n## mini.hues\n\n### Expand\n\n- Add new plugin integrations:\n    - 'folke/snacks.nvim'\n\n## mini.jump\n\n### Evolve\n\n- Make dot-repeat behave exactly as in clean Neovim, i.e. make it less interfere with regular jumping. This allows doing something like `dte` -> `fx` -> `.` to perform `dte` again and not `dfx` (which is the latest regular jumping state). By @abeldekat, PR #2284.\n\n## mini.misc\n\n### Evolve\n\n- Update `setup_termbg_sync()` to use OSC 111 control sequence to reset terminal emulator's background color. This provides a more robust behavior across platforms (like `tmux`).\n\n    The previous \"reset by explicitly setting initial background color\" behavior is available by setting the new `opts.explicit_reset` option to `true`.\n\n### Expand\n\n- Add `safely()` to execute a function reporting its possible error as warning. It can also postpone execution until certain condition (like event, fixed delay, etc.).\n\n    It is intended to be a future replacement for `MiniDeps.now()` and `MiniDeps.later()`.\n\n## mini.pairs\n\n### Refine\n\n- Update neighborhood patterns for default mappings to work better with multibyte characters. Their meaning is the same, just the form is adjusted to be more versatile.\n\n## mini.pick\n\n### Expand\n\n- Allow `source.preview` to directly set another buffer into picker's main window. The recommended way is still to adjust the provided `buf_id` buffer, but there is now a workaround if this is not reasonably possible.\n\n### Refine\n\n- Stop forcing redraw every `config.delay.async` milliseconds while the picker is active. It added visible CPU usage and code/test lines for its benefit (mostly to show \"background\" changes/notifications).\n\n    One side effect of this is that previews with an asynchronous highlighting (like after `vim.treesitter.start()`) might require extra care. There are built-in several (but limited) number of explicit `:redraw` with `config.delay.async` milliseconds apart. If that is not enough, make sure to explicitly redraw when needed.\n\n## mini.surround\n\n### Expand\n\n- Create Visual and Operator-pending mode mappings for `find` and `find_left` actions.\n\n## mini.test\n\n### Refine\n\n- Update `expect.error` and `expect.no_error` to not accept extra arguments for tested function. It will mostly work until the next 'mini.nvim' release, but not after that.\n\n    Use them explicitly inside anonymous function: `expect.error(f, \"\", 1, 2)` -> `expect.error(function() f(1, 2) end, \"\")` and `expect.no_error(f, 1, 2)` -> `expect.no_error(function() f(1, 2) end)`.\n\n    Sorry for the inconvenience.\n\n- Update all built-in reporters (`gen_reporter.buffer` and `gen_reporter.stdout`) to first show all fails followed by all notes. This makes it easier to find failed cases when there are many notes (like from `MiniTest.skip()`).\n\n### Expand\n\n- Update all `MiniTest.expect` expectations to allow customization of failure reason instead of default \"Failed expectation for ...\". This also consistently introduces `opts` last argument.\n\n- Update `MiniTest.expect.equality` to show more detailed cause of failed equality. Like which character is different in two string or which values are different in two tables and at what key branch.\n\n\n# Version 0.17.0\n\n## All\n\n### Evolve\n\n- Move repository hosting from personal 'echasnovski' GitHub account to the 'nvim-mini' organization. All `git pull` and `git clone` should be automatically redirected from previous to new locations without breaking user configurations. Yet updating source links to point to new locations (like `'echasnovski/mini.nvim'` -> `'nvim-mini/mini.nvim'` and standalone repos) is recommended.\n\n    This change is made to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n- Start setting custom Neovim method implementation during `setup()` (if module provides one). This is usually the expected behavior for majority of use cases and should improve \"out of the box\" experience. Modules should still export a function to manually adjust the implementation.\n\n    It is a breaking change only if the implementation was not explicitly used. Can still be done if set or restored *after* calling module's `setup()`.\n\n    Affected modules:\n\n    - 'mini.notify' sets `vim.notify`.\n    - 'mini.pick' sets `vim.ui.select`.\n\n### Refine\n\n- Stop official support of Neovim 0.8.\n\n### Expand\n\n- Add new bundled color schemes based on 'mini.hues':\n    - `miniwinter`: \"icy winter\" palette with azure background.\n    - `minispring`: \"blooming spring\" palette with green background.\n    - `minisummer`: \"hot summer\" palette with brown/yellow background.\n    - `miniautumn`: \"cooling autumn\" palette with purple background.\n\n## mini.ai\n\n### Refine\n\n- Update `gen_spec.treesitter()` to have `use_nvim_treesitter = false` as default option value (instead of `true`). It used to implement more advanced behavior, but as built-in `vim.treesitter` is capable enough, there is no need in extra dependency. The option will be removed after the release.\n\n### Expand\n\n- Add `gen_spec.user_prompt` that acts the same as `?` built-in textobject. It can be used for using this textobject under another identifier.\n\n## mini.basics\n\n### Refine\n\n- Change default value of `options.win_border` to be `'auto'`.\n\n### Expand\n\n- Update `options.win_border` to allow value `'auto'` which infers target 'fillchars' values from 'winborder' option.\n\n## mini.colors\n\n- Update `add_transparency()` color scheme method to adjust more groups:\n    - `XxxMsg` groups in case of `opts.general = true`.\n    - `DiagnosticSignXxx` groups in case of `opts.statuscolumn = true`.\n\n## mini.completion\n\n### Evolve\n\n- Update `setup()` to remove \"t\" flag from 'complete' option (if not previously set and fallback action is default) as it leads to visible lags.\n\n### Expand\n\n- Add `MiniCompletionWindowOpen` and `MiniCompletionWindowUpdate` events.\n\n- Add support for highlighting LSP item label via setting `abbr_hlgroup` field as part of an LSP item (like inside `config.lsp_completion.process_items`).\n\n## mini.clue\n\n### Evolve\n\n- Use current query clue (if not immediately after trigger) as a window title instead of showing keys verbatim. This shows extra context when navigating through mappings.\n\n### Expand\n\n- Add `gen_clues.square_brackets` to generate clues for `[` and `]` keys. By @TheLeoP, PR #1937.\n\n- Ensure triggers for 'mini.starter' buffers, but not override its query updaters (like for \"g\" and \"z\" triggers).\n\n## mini.cmdline\n\n- Introduction of a new module.\n\n## mini.diff\n\n### Expand\n\n- Add support for working with files containing BOM bytes.\n\n## mini.doc\n\n### Refine\n\n- Update default `write_pre` hook to remove `===` and `---` delimiters from the top of the file to better comply with `:h local-additions`.\n\n## mini.extra\n\n### Expand\n\n- Add `pickers.colorschemes` picker. By @pkazmier, PR #1789.\n\n- Add `workspace_symbol_live` scope to `pickers.lsp` picker. It allows searching for LSP symbols in the workspace with live feedback. Relates to `workspace_symbol` scope similarly to how `MiniPick.builtin.grep_live()` relates to `MiniPick.builtin.grep()`.\n\n- Add `<C-e>` mapping for `pickers.history` picker to edit commands or searches in cmdline. By @TheLeoP, PR #1960.\n\n## mini.files\n\n### Evolve\n\n- Allow appending `/` to a file name to mean \"delete file\" + \"create directory\". This is useful when initial intention was to create a directory but there was no `/` at the end.\n\n### Refine\n\n- Ensure preview window is never hidden, even if cursor is on the line for a not (yet) existing file system entry. This reduces flickering of preview window when creating new files in Insert mode.\n\n### Expand\n\n- Add `config.content.highlight` to customize how file system entry is highlighted. Defaults to a new `default_highlight()` function.\n\n## mini.hues\n\n### Evolve\n\n- Add auto adjusting of highlight groups based on certain events. It can be disabled via new `autoadjust` config setting or `opts.autoadjust` in `apply_palette()`. Affected groups:\n    - `MsgSeparator` depends on `msgsep` flag of 'fillchars' option.\n    - `Pmenu` depends on 'pumborder' option value (on Neovim>=0.12).\n\n### Refine\n\n- Make black (0 and 8) and white (7 and 15) colors for built-in terminal different from regular background and foreground. This improves color coverage and does not affect default uncolored text (it is highlighted as `Normal`).\n\n### Expand\n\n- Add `get_palette()` function.\n\n## mini.jump\n\n### Expand\n\n- Trigger dedicated events during steps of jumping life cycle. See `:h MiniJump-events`.\n\n## mini.jump2d\n\n### Evolve\n\n- Update `builtin_opts.word_start` to use built-in notion of \"keyword\" (see `:h 'iskeyword'`) when computing word start.\n\n### Refine\n\n- Move `gen_xxx_spotter` into separate `gen_spotter` table for consistency with other modules:\n    - `gen_pattern_spotter` -> `gen_spotter.pattern`\n    - `gen_union_spotter` -> `gen_spotter.union`\n\n    The `gen_xxx_spotter` functions will work (with warning) until at least next release.\n\n- Not focusable windows are now ignored when computing jump spots.\n\n### Expand\n\n- Add `gen_spotter.vimpattern()` that can generate spotter based on Vimscript (not Lua) pattern.\n\n## mini.map\n\n### Expand\n\n- Update `gen_integration.builtin_search()` to react to change of `v:hlsearch`.\n\n## mini.misc\n\n### Expand\n\n- Update `zoom()` to return whether current buffer is zoomed in. By @loichyan, PR #1954.\n\n- Add `log_add()` and related functions (`log_get()`, `log_show()`, `log_clear()`) to work with a special in-memory log array. Useful when debugging Lua code (instead of `print()`).\n\n## mini.pick\n\n### Evolve\n\n- Pickers `grep` and `grep_live` with `rg` tool now respect Neovim's `'ignorecase'` and `'smartcase'` options. This forces corresponding case matching flag (thus overriding global configuration) in favor of a more consistent user experience.\n\n### Expand\n\n- \"Paste\" action now supports special registers: `<C-w>` (word at cursor), `<C-a>` (WORD at cursor), `<C-l>` (line at cursor), `<C-f>` (filename at cursor).\n\n- Key query process now respects most language mappings. By @yehorb, PR #2026.\n\n## mini.sessions\n\n### Refine\n\n- Update `read()` to write currently read session only if `MiniSessions.config.autowrite` is set to `true`.\n\n## mini.surround\n\n### Evolve\n\n- Stop creating `update_n_lines` mapping: it occupies \"mapping real estate\" while being rarely needed and straightforward to create manually using `MiniSurround.update_n_lines()`.\n\n- Automatically map `s` key to `<Nop>` if the key is not already mapped and any of created mappings starts with it. This prevents accidental trigger of built-in `s` if there is a long delay between pressing \"s\" and the next key.\n\n### Refine\n\n- Update `gen_spec.inpuf.treesitter()` to have `use_nvim_treesitter = false` as default option value (instead of `true`). It used to implement more advanced behavior, but as built-in `vim.treesitter` is capable enough, there is no need in extra dependency. The option will be removed after the release.\n\n## mini.test\n\n### Refine\n\n- Soft deprecate `ignore_lines` option in `expect.reference_screenshot()` in favor of more capable `ignore_text` and `ignore_attr` options. For example, `ignore_lines = { 1 }` is the same as supplying both `ignore_text = { 1 }` and `ignore_attr = { 1 }`.\n\n    It will work at least until the next release, after which its support will be removed. Sorry for the inconvenience.\n\n### Expand\n\n- Update `expect.reference_screenshot()` to support separate ignoring of text and attribute screenshot data via new `ignore_text` and `ignore_attr` options.\n\n\n# Version 0.16.0\n\n## All\n\n### Evolve\n\n- Unify behavior of floating windows:\n    - Truncate title/footer from left if it is too wide.\n    - Set default title if window is allowed to have border.\n    - Use single space padding for default title/footer.\n    - Use 'single' as default window border in modules where it can be configured. On Neovim>=0.11 also respect non-empty 'winborder' option with lower precedence than explicitly configured value for the module.\n\n- Unify how module-related buffers are named: `mini<module-name>://<buffer-number>/<useful-info>`. This structure allows creating identifiable, reasonably unique, and useful buffer names. This is a user facing change because in some cases the shown buffer's name will change (like in statusline of opened 'mini.starter' buffer or output of `:buffers!`).\n\n- Stop forcing recommended option values behind `set_vim_settings` config setting. Instead set them automatically in `setup()`. If it is not essential, do so only if it was not set by user/plugin beforehand (no matter the value). Document this as a new general principle to be followed in the future. Affected modules:\n    - 'mini.bufremove' (do nothing as recommended 'hidden' is on by default)\n    - 'mini.completion' (conditionally set 'completeopt=menuone,noselect' and flags \"c\" in 'shortmess')\n    - 'mini.statusline' (do nothing as recommended 'laststatus=2' is default)\n    - 'mini.tabline' (unconditionally set 'showtabline=2', as it is essential to module's functinonality)\n\n### Refine\n\n- Soft deprecate support for Neovim 0.8. It will be fully stopped in next release.\n\n## mini.ai\n\n### Refine\n\n- Visual textobject selection now puts the cursor on the right edge instead of left. This better aligns with the (undocumented) behavior of how built-in `a` / `i` textobjects work in Visual mode, as opposed to the (documented in `:h operator-resulting-pos`) behavior of how it is done after applying the operator.\n\n### Expand\n\n- Textobject identifier can now be any single character supported by `:h getcharstr()`. This also makes it possible to use characters outside of Latin alphanumeric and punctuation sets as `custom_textobjects` keys. Default textobject is extended to be anything but Latin letters (to fall back to `:h text-objects`).\n\n- Update `gen_spec.treesitter()` to respect capture ranges specified by query directives (like `(#offset! @table.inner 0 1 0 -1)`).\n\n## mini.base16\n\n### Refine\n\n- Update 'mini.pick' highlight groups to show prompt text with same colors as match ranges, as they are connected.\n\n### Expand\n\n- Add support for colored markdown headings.\n\n- Add new plugin integrations:\n    - 'ibhagwan/fzf-lua'\n    - 'MeanderingProgrammer/render-markdown.nvim'\n    - 'OXY2DEV/helpview.nvim'\n    - 'OXY2DEV/markview.nvim'\n\n## mini.colors\n\n### Expand\n\n- Update `convert()` to have `adjust_lightness` option which can be used to disable lightness adjustment (which is enabled by default for a more uniform progression from 0 to 100). This can be useful for output to be more consistent with other Oklab/Oklch implementations.\n\n## mini.comment\n\n### Expand\n\n- Update textobject to respect `ignore_blank_line` option. Blank lines between commented lines are treated as part of a textobject.\n\n## mini.completion\n\n### Evolve\n\n- Add snippet support. By default uses 'mini.snippets' to manage snippet session (if enabled, **highly recommended), falls back to `vim.snippet` on Neovim>=0.10. See \"Snippets\" section in `:h MiniCompletion` for more details.\n\n    This affect existing functionality because items with `Snippet` kind are no longer filtered out by default.\n\n- Rework how LSP completion items are converted to Neovim's completion items:\n    - Show `detail` highlighted as buffer's language at the start of info window, but only if `detail` provides information not already present in `documentation`. It was previously used as extra text in the popup menu (via `menu` field), but this doesn't quite follow LSP specification: `detail` and `documentation` fields can be delayed up until `completionItem/resolve` request which implies they should be treated similarly.\n    - Show `labelDetails` as a part of the popup menu via `menu` completion item field.\n\n- Rework how information window is shown with the goal to reduce flickering during fast up/down navigation through completion candidates:\n    - Do not close the window immediately after the move. Instead highlight border with `MiniCompletionInfoBorderOutdated` immediately while update window when its content is ready. Close the window only if no candidate is selected.\n    - Show content of already visited/resolved candidate without delay.\n    - Show default `-No-info-` text if there is no extra information about the candidate.\n\n- Update behavior and capabilities of `default_process_items()`:\n    - Add `filtersort` option to control how items are filtered and/or sorted. Its new default value has changed behavior: do fuzzy matching if 'completeopt' option contains \"fuzzy\" entry; same as before otherwise.\n    - Add `kind_priority` option to allow arranging items by completion item kind (like \"Variable\", \"Snippet\", \"Text\", etc.) after applying `filtersort`. This allows finer filter and/or sort based on kind, like \"put Variable on top, Snippet on bottom, remove Text\".\n    - Use `filterText` and `label` item fields during matching (instead of `textEdit.newText`, `insertText`, and `label` as before). This is more aligned with LSP specification.\n\n### Refine\n\n- Prefer in some cases to use `nil` as default config value with explicit fallback. This should not have any user facing effects and marked as breaking only because a structure of a default config has changed. Affected fields:\n    - `lsp_completion.process_items` (use `default_process_items` as fallback) and `fallback_action` (use `'<C-n>'` as fallback). This makes it more aligned with other modules that usually avoid using function values in default config.\n    - `window.info.border` and `window.signature.border` (use non-empty 'winborder' and `'single'` as fallback).\n\n- Change default value of `MiniCompletionActiveParameter` highlight group to link to `LspSignatureActiveParameter` (instead of forcing underline).\n\n- Call `lsp_completion.process_items` with an array of items from all buffer servers at once (and not for each server separately). This can be used for more elaborate filter/sort strategies.\n\n### Expand\n\n- Add scrolling in info and signature window. By default can be done with `<C-f>` / `<C-b>` when target window is shown. Can be configured via `mappings.scroll_down` and `mappings.scroll_up` config options.\n\n- Respect `isIncomplete` in LSP completion response and immediately force new completion request on the next key press.\n\n- Add support for context in 'textDocument/completion' request.\n\n- Both info and signature help windows now use tree-sitter highlighting:\n    - Info window uses \"markdown\" parser (works best on Neovim>=0.10 as its parser is built-in). Special markdown characters are concealed (i.e. hidden) which might result into seemingly unnecessary whitespace as dimensions are computed not accounting for that.\n    - Signature help uses same parser as in current filetype.\n\n- Update signature help without delay if it is already shown. This helps to keep signature help up to date after cursor jumps in Insert mode (like during snippet session).\n\n- Add support for item defaults in `CompletionList` response.\n\n- Add `get_lsp_capabilities()` that returns data about which part of LSP specification is supported in 'mini.completion'.\n\n- Input items for `lsp_completion.process_items` now have `client_id` field with the identifier of the server that item came from. Use `vim.lsp.get_client_by_id()` to get an actual data about the server.\n\n## mini.diff\n\n### Expand\n\n- The `config.source` can now be array of sources, which will be attempted to attach in order. Important for source's `attach` to either return `false` or call `MiniDiff.fail_attach()` (even not immediately) to signal that source has failed to attach to a particular buffer.\n\n- Overlay virtual lines now scroll horizontally along with buffer lines. Requires Neovim>=0.11 and disabled 'wrap' option.\n\n- Highlighting of buffer parts of change hunks can now be customized with these new highlight groups:\n    - `MiniDiffOverChangeBuf` - changed buffer text. Previously used `MiniDiffOverChange` (for changed reference text); links to it by default.\n    - `MiniDiffOverContextBuf` - context of a change shown in buffer overlay. Previously not highlighted, default highlight group is not created.\n\n## mini.doc\n\n### Expand\n\n- FEATURE: improve detection and formatting for types in `@param`, `@return`, and similar.\n\n## mini.fuzzy\n\n### Refine\n\n- Update `process_lsp_items()` to only use `filterText` and `label` item fields during fuzzy matching (instead of `textEdit.newText`, `insertText`, and `label` as before). This is more aligned with LSP specification.\n\n- Treat empty `word` as matching any candidate (matched positions is empty array and score is -1). This behavior is usually more useful in practice.\n\n## mini.hues\n\n### Evolve\n\n### Refine\n\n- Update 'mini.pick' highlight groups to show prompt text with same colors as match ranges, as they are connected.\n\n### Expand\n\n- Add support for colored markdown headings.\n\n- Add new plugin integrations:\n    - 'ibhagwan/fzf-lua'\n    - 'MeanderingProgrammer/render-markdown.nvim'\n    - 'OXY2DEV/helpview.nvim'\n    - 'OXY2DEV/markview.nvim'\n\n\n## mini.keymap\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.notify\n\n### Expand\n\n- Add `lsp_progress.level` option to control level of LSP progress notifications.\n\n- Add `MiniNotifyLspProgress` highlight group to be used for LSP progress notifications.\n\n- Add `data` field to notification specification and as a new argument to `MiniNotify.add()`. It can be used to store any data relevant to the notification. For example, notifications from `make_notify()` output set `source` field to `'vim.notify'`, while notifications from LSP progress set `source` to `'lsp_progress'`.\n\n## mini.operators\n\n### Expand\n\n- Update `setup()` to remap built-in `gx` Normal/Visual mode mappings (for opening an URI under cursor) to `gX` (if that is not already taken).\n\n## mini.pairs\n\n### Expand\n\n- Update all actions to work with pairs containing multibyte characters (like \"¿?\", \"「」\", and similar).\n\n## mini.pick\n\n### Refine\n\n- Rename `prompt_cursor` in `config.window` to `prompt_caret` for better naming consistency. It works for now, but will stop in the next release. Sorry for the inconvenience.\n\n### Expand\n\n- Add `MiniPickPromptCaret` and `MiniPickPromptPrefix` highlight groups to allow finer customization of picker's prompt.\n\n- Update `get_picker_matches()` to return data (items and indexes) about currently shown items.\n\n- Update `set_picker_match_inds()` to be able to set current match and marked items indexes.\n\n## mini.snippets\n\n### Expand\n\n- Add `start_lsp_server()` to start specialized in-process LSP server to show loaded snippets inside (auto)completion engines (like 'mini.completion').\n\n## mini.statusline\n\n### Refine\n\n- Function `section_fileinfo()` got several updates:\n    - File size is now computed based on the current buffer text and not for file's saved version.\n    - File info is now shown even for buffers with empty 'filetype'. It previously was treated as a sign of a \"temporary buffer\", but it might be a result of an unsuccessful filetype matching.\n\n## mini.surround\n\n### Expand\n\n- Surrounding identifier can now be any single character supported by `:h getcharstr()`. This also makes it possible to use characters outside of Latin alphanumeric and punctuation sets as `custom_surroundings` keys.\n\n- Update `gen_spec.input.treesitter()` to respect capture ranges specified by query directives (like `(#offset! @table.inner 0 1 0 -1)`).\n\n## mini.tabline\n\n### Expand\n\n- Add support for showing special (truncation) characters at left and/or right if there are more tabs to the left and/or right. They are shown with the new `MiniTablineTrunc` highlight group in case 'list' option is enabled (i.e. user deliberately enabled similar functionality for windows). Exact characters are taken from 'listchars' option: `precedes` and `extends` fields.\n\n- Labels for quickfix and location lists are now different.\n\n\n# Version 0.15.0\n\n## mini.align\n\n### Expand\n\n- Add built-in modifier for \"|\" character with aligning Markdown-like tables in mind.\n\n## mini.animate\n\n### Evolve\n\n- Add `max_output_steps` option to `gen_path.line()` and `gen_path.angle()` to limit the number of steps the return. Default is 1000 to improve performance on large cursor jumps which also is set for `config.cursor.path`.\n\n## mini.files\n\n### Expand\n\n- Closing and refreshing explorer now requires confirmation only if there are pending file system actions (and not in case of at least one modified buffer present).\n\n- Confirming file system actions in `synchronize()` now can cancel synchronization (by pressing `c`) while keeping buffer contents the same. `synchronize()` also returns a boolean representing whether synchronization was done.\n\n## mini.git\n\n### Expand\n\n- Git data is computed after resolving symlinks. This allows working with files symlinked into outside of Git repo. This behavior is the same as in 'mini.diff'.\n\n## mini.hipatterns\n\n### Refine\n\n- Make `MiniHipatterns{Fixme,Hack,Todo,Note}` highlight groups by default be reverse and bold variant of `Diagnostic{Error,Warn,Info,Hint}` group instead of directly link to them. This ensures better visibility for color schemes which don't have explicit 'mini.hipatterns' support.\n\n## mini.hues\n\n### Expand\n\n- Add `'lowmedium'` and `'mediumhigh'` saturation levels.\n\n## mini.icons\n\n### Expand\n\n- Add distinctive glyphs and highlighting for special Neovim directories (from `:h 'runtimepath'`).\n\n## mini.indentscope\n\n### Evolve\n\n- Add `options.n_lines` option to limit the scope computation (for better performance). It's default value is 10000 while previous behavior behavior had no restriction (as with `n_lines = math.huge`) which should matter only in very big scopes.\n\n- Add `draw.predicate` configuration to customize whether the scope should be autodrawn. It's default value does not draw scope with incomplete computation (i.e. interrupted due to `options.n_lines` value), which should matter only in very big scopes.\n\n## mini.notify\n\n- FEATURE: `setup()` now also can be used to clean history (for example, like `MiniNotify.setup(MiniNotify.config)`).\n\n## mini.pick\n\n### Evolve\n\n- Picker window now has local current directory set to source's `cwd`. This allows easier code for \"in window\" functions (callable items, choose, preview, etc.) as relative paths will be properly resolved. It also results in some changes:\n    - Calling `set_picker_items_from_cli()` with active picker now resolves explicitly set to relative path `spawn_opts.cwd` against picker's `cwd` (and not against global current directory as was done previously).\n\n### Expand\n\n- Update `grep` and `grep_live` pickers to allow `globs` local option which restricts search to files that match any of its glob patterns (for example, `{ '*.lua', 'lua/**' }` will only search in Lua files and files in 'lua' directory). The `grep_live` picker also has custom `<C-o>` mapping to add globs interactively after picker is opened.\n\n- Update `help` picker to have `default_split` local option which customizes split direction of `choose` action (`<CR>` by default).\n\n- Update `ui_select()` to allow fourth argument `start_opts` to customize `MiniPick.start()` call.\n\n- Add `MiniPickMatch` event triggered after updating query matches or setting items. Can be used, for example, to adjust window height based on current matches.\n\n## mini.snippets\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.surround\n\n### Refine\n\n- Created mappings for `find`, `find_left`, and `highlight` are now *not* dot-repeatable. Dot-repeat should repeat last text change but neither of those actions change text. Having them dot-repeatable breaks the common \"move cursor -> press dot\" workflow. Initially making them dot-repeatable was a \"you can but you should not\" type of mistake.\n\n## mini.test\n\n### Evolve\n\n- Now calling `skip()` in set's `pre_case` hook results in skipping all test cases in a set. Calling in other hooks has no effect. This enables a more structured skipping of all test cases inside a set. To skip inside hooks, use `add_note()` followed by `return`.\n\n### Expand\n\n- Add `n_retry` test set property. When set, each case will be tried that at most that many times until first success (if any).\n\n- Add `hooks.pre_source` and `hooks.post_source` fields to collected cases. They can be either `'once'` or `'case'` and allow a more granular control over case execution.\n\n- Function `finally()` now can be called several times inside a single function with callbacks executed in order of how they were registered.\n\n- Update `expect.reference_screenshot()` to allow `directory` option pointing to a directory where automatically constructed reference path is located.\n\n\n# Version 0.14.0\n\n## All\n\n### Evolve\n\n- Update help files to use code blocks with language annotation, as it results in a better code highlighting. Implies enabled tree-sitter highlighting in 'help' filetype:\n    - It is default in Neovim>=0.10.\n    - Tree-sitter parser is built-in in Neovim 0.9.x, needs manual enabling via `vim.treesitter.start()`.\n    - Has visual regressions on Neovim 0.8.0 and 0.8.1 without enabled tree-sitter (code blocks are highlighted as normal text). Use 0.8.2 or newer.\n\n- Universally prefer 'mini.icons' module over 'nvim-tree/nvim-web-devicons'.\n\n### Refine\n\n- Stop official support of Neovim 0.7.\n\n### Expand\n\n- Start automated testing on Windows and MacOS.\n\n- Universally ensure that all plugin's highlight groups are defined after any color scheme takes effect.\n\n## mini.base16\n\n### Expand\n\n- Add 'kevinhwang91/nvim-bqf' plugin integration.\n\n## mini.completion\n\n### Expand\n\n- Add highlighting of LSP kind (like \"Function\", \"Keyword\", etc.). Works only on Neovim>=0.11. Requires enabled 'mini.icons' to work out of the box.\n\n## mini.doc\n\n### Evolve\n\n- Update `afterlines_to_code()` to result into Lua code block in help file by using `>lua` at the start instead of `>`. NOTE: users need enabled `help` tree-sitter parser (which is default on Neovim>=0.9) for code blocks to have proper highlighting.\n\n## mini.extra\n\n### Refine\n\n- Use \"│\" as line/position separator instead of \":\". This aligns with changes in 'mini.pick' and makes line/position more easily visible.\n\n### Expand\n\n- Update `oldfiles` picker to have `current_dir` option which if `true` shows files only from picker's working directory. By @abeldekat, PR #997.\n\n- Update `git_hunks`, `list`, and `lsp` pickers to show icons. Scopes `document_symbol` and `workspace_symbol` in `lsp` picker show icon based on LSP kind (requires set up 'mini.icons'), others - based on path data.\n\n- Update `buf_lines` and `oldfiles` pickers to have `preserve_order` local option, similar to `visit_paths` picker. Other possible candidates for this option are intentionally not updated to not increase maintenance (manually override `match` source method to call `MiniPick.default_match()` with `{ preserve_order = true }` options).\n\n- Update `buf_lines` picker to pad line numbers to achieve more aligned look.\n\n## mini.git\n\n### Expand\n\n- Update `show_at_cursor()` to include commit's statistics when showing commit.\n\n- Update `show_at_cursor()` to show relevant at cursor commit data inside 'mini.deps' confirmation buffer.\n\n## mini.hipatterns\n\n### Evolve\n\n- Update `compute_hex_color_group()` to compute based on combination of `hex_color` and `style`, opposed to just `hex_color`. This allows simultaneous usage of several styles in user's custom highlighters.\n\n## mini.hues\n\n### Expand\n\n- Implement `apply_palette()` (to compliment `make_palette()`) providing a way to tweak applied palette before applying it.\n\n- Add 'kevinhwang91/nvim-bqf' plugin integration.\n\n## mini.files\n\n### Evolve\n\n### Refine\n\n- Update how confirmation lines are computed:\n    - Show create actions in the group directory where text manipulation took place. This matters during creating nested entries and is usually a more intuitive representation.\n    - For delete show its type after the file name (\"permanently\" or \"to trash\") as an additional visual indication of delete type.\n    - For create, copy and move prefer showing its \"to\" path relative to group directory.\n    - Separate action name and paths with \"│\" (instead of \":\") for better visual separation.\n    - Don't enclose paths in quotes. Initially it was done to reliably show possible whitespace in paths, but inferring it from overall line structure should be good enough.\n\n- Soft deprecate `get_target_window()` in favor of `get_explorer_state().target_window`. Will be completely removed after the next release.\n\n### Expand\n\n- Prefer using 'mini.icons' as icon provider.\n\n- Implement bookmarks. With default config:\n    - Type `m` followed by a single character `<char>` to set directory path of focused window as a bookmark with id `<char>`.\n    - Type `'` followed by a bookmark id to make bookmark's path focused in explorer.\n    - Use `MiniFiles.set_bookmark()` inside `MiniFilesExplorerOpen` event to set custom bookmarks.\n\n- Make data for `MiniFilesActionDelete` contain `to` field in case of not permanent delete.\n\n- Make file manipulation work better for special complex/overlapping cases (like delete 'file-a' and copy 'file-b' as 'file-a'). It is **still** a better idea to split overlapping manipulations into smaller and not related steps, as there *are* cases which won't work.\n\n- Add `get_explorer_state()` to allow more reliable user customizations.\n\n- Add `set_branch()` to allow to set what paths should be displayed and focused.\n\n## mini.icons\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.misc\n\n### Expand\n\n- Implement `setup_termbg_sync()` to set up terminal background synchronization (removes possible \"frame\" around current Neovim instance). Works only on Neovim>=0.10.\n\n## mini.pick\n\n### Evolve\n\n### Refine\n\n- Update `default_match()` to have table `opts` as fourth argument (instead of boolean `do_sync`). Use `{ sync = true }` to run synchronously. The new design is more aligned with other functions and is more forward compatible.\n\n- Encoding line or position in string items has changed:\n    - Use \"\\0\" (null character; use \"\\000\" form if it is in a string before digit) instead of \":\" as delimiter. This makes it work with files similar to \":\" position encoding (like \"time_12:34:56\"). This only matters for custom sources which provide line or position in string items.\n    - Update `default_show()` to display \"│\" character instead of \"\\0\" in item's string representation (previously was \":\"). In particular, this changes how line/position is displayed in `grep` and `grep_live` built-in pickers. This change was done because \"│\" is more visible as separator.\n\n### Expand\n\n- Prefer using 'mini.icons' as icon provider.\n\n- Add `preserve_order` option to `default_match()` to allow asynchronous matching which preserves order (i.e. doesn't do sort step of fuzzy matching).\n\n- Explicitly hide cursor when picker is active (instead of putting it in command line).\n\n## mini.starter\n\n### Refine\n\n- Change filetype of Starter buffer from 'starter' to 'ministarter'. This is a more robust value and more aligned with other modules.\n\n## mini.statusline\n\n### Refine\n\n- Update `section_fileinfo()` to show non-empty filetype even in not normal buffers (like plugin's scratch buffers, help, quickfix, etc.). Previously it showed nothing, which was a mistake as filetype can be a valuable information.\n\n- The default `set_vim_settings` config value now does not affect `laststatus = 3` (aka global statusline).\n\n### Expand\n\n- Prefer using 'mini.icons' as icon provider for `section_fileinfo()`.\n\n## mini.surround\n\n### Refine\n\n- Adding surrounding in linewise mode now also ignores trailing whitespace on the last line (same as it ignores indent on the first line).\n\n## mini.tabline\n\n### Expand\n\n- Prefer using 'mini.icons' as icon provider.\n\n## mini.test\n\n### Expand\n\n- Make it work on Windows. By @cameronr, PR #1101.\n\n\n# Version 0.13.0\n\n## mini.comment\n\n### Refine\n\n- Blank lines are now completely ignored when deciding the toggling action. In practice this means that if target block consists only from commented and/or blank lines, it will be uncommented rather than commented.\n\n- Whitespace in comment parts is now treated more explicitly. In particular:\n    - Default `options.pad_comment_parts = true` now more explicitly means that any value of 'commentstring' is transformed so that comment parts have exactly single space inner padding.\n\n      Example: any `/*%s*/`, ` /* %s */ `, or `/*  %s  */` is equivalent to having `/* %s */`.\n\n    - Detection of whether consecutive lines are commented or not does not depend on whitespace in comment parts. Uncommenting is first attempted with exact comment parts and falls back on trying its trimmed parts.\n\n      Example of toggling comment on single line with `/* %s */` 'commentstring' value:\n        - `/* this is commented */` -> `this is commented`.\n        - `/*this is also commented */` -> `this is also commented ` (notice trailing space).\n\n    - Commenting blank lines is done with trimmed comments parts, while uncommenting explicitly results into empty lines.\n\n### Expand\n\n- Support dot-repeat after initial commenting is done for visual selection; repeating is done for same relative range.\n\n## mini.deps\n\n### Expand\n\n- Add `MiniDepsMsgBreaking` highlight group for messages indicating a breaking change in a conventional commit style.\n\n## mini.diff\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.files\n\n### Expand\n\n- Add new `MiniFilesExplorerOpen` and `MiniFilesExplorerClose` events.\n\n## mini.git\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.hues\n\n### Refine\n\n- Update some highlight groups for better usability:\n    - `DiffChange` and `DiffText` - make changed diff lines have colored background.\n    - `Folded` - make folds differ from `CursorLine`.\n    - `QuickFixLine` - make current quickfix item differ from `CursorLine`.\n\n## mini.map\n\n### Expand\n\n- Add `gen_integration.diff()` which highlights general diff hunks from 'mini.diff'.\n\n## mini.pick\n\n### Evolve\n\n### Refine\n\n- Stop trying to parse path for special format (\"path:row\" and \"path:row:col\") if supplied inside a table item. This made impossible working with paths containing \":\".\n\n- Update `builtin.files()` to use table items when string item might be ambiguous.\n\n### Expand\n\n- Respect general URI format for paths inside table items.\n\n## mini.starter\n\n### Refine\n\n- Explicitly block all events in `open()` during startup for a better performance.\n\n## mini.statusline\n\n### Evolve\n\n- Update `section_git()` to prefer using data from 'mini.git' with fallback on pure HEAD data from 'lewis6991/gistigns.nvim'.\n\n- Update default active content:\n    - Add `section_diff()` (shows diff data near  icon) following refactor of `section_git()`.\n    - Add `section_lsp()` (shows number of attached LSP servers near 󰰎 icon) following refactor of `section_diagnostics()`.\n\n### Refine\n\n- Update `section_diagnostics()` to depend only on defined diagnostic. This means:\n    - Something is shown **only** if there is any diagnostic actually present in the buffer. No diagnostic entries - nothing is shown. Previously it did not show if there was no LSP servers attached (as initially diagnostics came only from LSP) or buffer was not normal.\n    - Fallback icon is \"Diag\" instead of \"LSP\".\n\n### Expand\n\n- Update `section_diagnostics()` to support `signs` table option to customize signs for severity levels.\n\n- Add `section_diff()` to show data from 'mini.diff' with fallback on diff data from 'lewis6991/gistigns.nvim'.\n\n- Add `section_lsp()` to show indicator of LSP servers attached to the buffer.\n\n## mini.tabline\n\n### Expand\n\n- Implement `config.format` for custom label formatting.\n\n## mini.test\n\n### Refine\n\n- Child process is now created with extra `--headless --cmd \"set lines=24 columns=80\"` arguments making it headless but still reasonably similar to fully functioning Neovim during interactive usage. This change should generally not break a lot of things, while enabling a faster and more robust test execution.\n\n\n# Version 0.12.0\n\n## mini.basics\n\n### Refine\n\n- Remove `<C-z>` mapping, as it is more useful in most terminal emulators for suspending Neovim process (to later resume with `fg` command). To correct latest misspelled word, use mappings like this:\n\n    ```lua\n    vim.keymap.set('n', '<C-z>', '[s1z=',                     { desc = 'Correct latest misspelled word' })\n    vim.keymap.set('i', '<C-z>', '<C-g>u<Esc>[s1z=`]a<C-g>u', { desc = 'Correct latest misspelled word' })\n    ```\n\n### Expand\n\n- Add `tab:> ` to 'listchars' option when `options.extra_ui` is set. This prevents showing `^I` instead of a tab and actual value comes from Neovim's default.\n\n- Set `termguicolors` only on Neovim<0.10, as later versions should have it on by default (if terminal emulator supports it).\n\n## mini.comment\n\n### Expand\n\n- Hooks are now called with data about commenting action.\n\n## mini.deps\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.doc\n\n### Refine\n\n- Stop using `:echo` to display messages and warnings in favor of `vim.notify()`.\n\n- Update default `write_post` hook to not display current time in success message.\n\n- Update to include space before `~` in generated section headings.\n\n## mini.files\n\n### Expand\n\n- Update `go_in()` to have `close_on_file` option.\n\n- Show warning if action is set to override existing path.\n\n## mini.hues\n\n### Refine\n\n- Update verbatim text (`@text.literal` and `@markup.raw`) color to be distinctive instead of dimmed.\n\n### Expand\n\n- Add support for new standard tree-sitter captures on Neovim>=0.10 (see https://github.com/neovim/neovim/pull/27067).\n\n## mini.misc\n\n### Refine\n\n- Update `bench_time()` to use `vim.loop.hrtime()` (as better designed for benchmarking) instead of `vim.loop.gettimeofday()`.\n\n## mini.notify\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.pick\n\n### Expand\n\n- Implement `window.prompt_cursor` and `window.prompt_prefix` config options.\n\n- Update `builtin.help()` to use tree-sitter highlighting (if there is any).\n\n## mini.sessions\n\n### Refine\n\n- Update `read()` to first `write()` current session (if there is any).\n\n## mini.starter\n\n### Expand\n\n- Add `sections.pick()` with 'mini.pick' pickers.\n\n## mini.statusline\n\n### Evolve\n\n- Add `search_count` section to default active content.\n\n## mini.visits\n\n### Expand\n\n- Introduction of a new module.\n\n\n# Version 0.11.0\n\n## mini.base16\n\n### Refine\n\n- Stop supporting deprecated 'HiPhish/nvim-ts-rainbow2'.\n\n## mini.bufremove\n\n### Evolve\n\n- Applying `delete()` and `wipeout()` without `force` in a modified buffer now asks for confirmation instead of declining and showing message.\n\n## mini.clue\n\n### Expand\n\n- Value of `config.window.config` now can be callable returning window config.\n\n## mini.comment\n\n### Expand\n\n- Implement `config.mappings.comment_visual` to configure mapped keys in Visual mode.\n\n## mini.completion\n\n### Evolve\n\n- Start adding `C` flag to `shortmess` option on Neovim>=0.9. By @yamin-shihab, PR #554.\n\n## mini.extra\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.files\n\n### Refine\n\n- Opening file which is present in unlisted buffer now makes the buffer listed.\n\n- Highlight in preview now is not enabled if file is sufficiently large.\n\n### Expand\n\n- Explorer now tracks if focus is lost and properly closes on detection.\n\n- Implement `MiniFilesCursorLine` highlight group.\n\n## mini.hipatterns\n\n### Refine\n\n- Field `priority` in highlighter definitions is soft deprecated in favor of `extmark_opts = { priority = <value> }`.\n\n### Expand\n\n- Allow `pattern` in highlighter definitions to be an array to highlight several patterns under the same highlighter name.\n\n- Implement `extmark_opts` in highlighter definitions for a more control over extmarks placed at matches.\n\n- Update `compute_hex_color_group()` to allow `style = 'fg'`.\n\n- Update `gen_highlighter.hex_color()` to allow `style = 'inline'` (requires Neovim>=0.10 with support of inline extmarks).\n\n- Implement `get_matches()` to get buffer matches.\n\n## mini.hues\n\n### Refine\n\n- Stop supporting deprecated 'HiPhish/nvim-ts-rainbow2'.\n\n## mini.map\n\n### Expand\n\n- Implement `config.window.zindex` to configure z-index of map window.\n\n## mini.misc\n\n### Expand\n\n- Update `setup_auto_root()` and `find_root()` to now have `fallback` argument to be applied when no root is found with `vim.fn.find()`.\n\n## mini.pick\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.starter\n\n### Expand\n\n- Value of `show_path` in `sections.recent_files()` can now be callable for more control on how full path is displayed.\n\n## mini.test\n\n### Evolve\n\n- Update `child.get_screenshot()` to now by default call `:redraw` prior to computing screenshot. Can be disabled by new `opts.redraw` argument.\n\n### Refine\n\n- Error in any \"pre\" hook now leads to test case not being executed (with note).\n\n### Expand\n\n- New method `child.lua_func()` can execute simple functions inside child process and return the result (stasjok, #437).\n\n- Update `expect.reference_screenshot()` to now have `ignore_lines` option allowing to ignore specified lines during screenshot compare.\n\n\n# Version 0.10.0\n\n## mini.ai\n\n### Expand\n\n- Allow `vis_mode` field in custom texobject region to force Visual mode with which textobject is selected.\n\n## mini.animate\n\n### Expand\n\n- Add `MiniAnimateNormalFloat` highlight group to tweak highlighting of `open` and `close` animations.\n\n## mini.base16\n\n### Expand\n\n- Add 'HiPhish/rainbow-delimiters.nvim' integration.\n\n## mini.basics\n\n### Refine\n\n- Remove `<C-w>` mapping in Terminal mode, as it is more useful inside terminal emulator itself.\n\n## mini.bracketed\n\n### Expand\n\n- Add `add_to_jumplist` option to relevant targets (which move cursor and don't already add to jumplist).\n\n## mini.bufremove\n\n### Refine\n\n- Create normal buffer instead of scratch when there is no reasonable target to focus (#394).\n\n## mini.clue\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.files\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.hues\n\n### Expand\n\n- Add 'HiPhish/rainbow-delimiters.nvim' integration.\n\n## mini.jump2d\n\n### Expand\n\n- Add `gen_union_spotter()` to allow combining separate spotters into one.\n\n## mini.operators\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.pairs\n\n### Expand\n\n- Allow `false` in `config.mappings` to not map the key.\n\n## mini.surround\n\n### Expand\n\n- Update `add` (`sa`) with ability to replicate left and right parts by respecting `[count]`. In Normal mode two kinds of `[count]` is respected: one for operator (replicates left and right parts) and one for textobject/motion. In Visual mode `[count]` replicates parts.\n\n\n# Version 0.9.0\n\n## All\n\n### Evolve\n\n- Use Lua API to create autocommands. Stop exporting functions only related to autocommands.\n\n- Use `vim.keymap` to deal with mappings. Stop exporting functions only related to mappings.\n\n### Refine\n\n- Stop official support of Neovim 0.6.\n\n### Expand\n\n- Add 'randomhue' color scheme.\n\n## mini.base16\n\n### Evolve\n\n- Stop supporting archived 'p00f/nvim-ts-rainbow' in favor of 'HiPhish/nvim-ts-rainbow2'.\n\n### Expand\n\n- Add new integrations:\n    - Lsp semantic tokens.\n    - 'folke/lazy.nvim'.\n    - 'folke/noice.nvim'.\n    - 'kevinhwang91/nvim-ufo'.\n\n## mini.basics\n\n### Expand\n\n- Add dot-repeat support for adding empty lines (`go` and `gO` mappings).\n\n## mini.colors\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.comment\n\n### Expand\n\n- Use tree-sitter information about locally active language to infer 'commentstring' option value.\n\n- Add `options.custom_commentstring` option for a more granular customization of comment structure.\n\n- Add `get_commentstring()` function representing built-in logic of computing relevant 'commentstring'.\n\n## mini.hipatterns\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.hues\n\n### Expand\n\n- Introduction of a new module.\n\n\n# Version 0.8.0\n\n## All\n\n### Expand\n\n- Add and implement design principle for silencing module by setting `config.silent = true`. It is now present in modules capable of showing non-error feedback:\n    - mini.ai\n    - mini.align\n    - mini.basics\n    - mini.bufremove\n    - mini.doc\n    - mini.jump\n    - mini.jump2d\n    - mini.starter\n    - mini.surround\n    - mini.test\n\n## mini.bracketed\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.comment\n\n### Expand\n\n- Add `options.start_of_line` option which controls whether to recognize as comment only lines without indent.\n\n- Add `options.ignore_blank_line` option which controls whether to ignore blank lines.\n\n- Add `options.pad_comment_parts` option which controls whether to ensure single space pad for comment leaders.\n\n## mini.doc\n\n### Expand\n\n- Add `config.hooks.write_pre` hook to be executed before writing to a file.\n\n## mini.indentscope\n\n### Expand\n\n- Add `MiniIndentscopeSymbolOff` highlight group to be used if scope's indent is not multiple of 'shiftwidth'.\n\n- Add `draw.priority` option to control priority of scope line draw.\n\n## mini.jump2d\n\n### Expand\n\n- Add `view.n_steps_ahead` option which controls how many steps ahead to show. Appearance is controlled by new `MiniJump2dSpotAhead` highlight group.\n\n- Add `view.dim` option which controls whether to dim lines with at least one jump spot. Appearance is controlled by new `MiniJump2dDim` highlight group.\n\n- Add `MiniJump2dSpotUnique` highlight group to be used for spots with unique label for next step.\n\n## mini.pairs\n\n### Expand\n\n- Both `MiniPairs.br()` and `MiniPairs.cr()` can now take a key which will be used instead of default `<BS>` and `<CR>`.\n\n## mini.sessions\n\n### Expand\n\n- Update `setup()` to now create global directory at path `config.directory` if it doesn't exist.\n\n- All actions now keep list of detected sessions up to date.\n\n## mini.splitjoin\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.surround\n\n### Expand\n\n- Add `respect_selection_type` option which, when enabled, makes adding and deleting surrounding respect selection type:\n    - Linewise adding places surrounding parts on separate lines while indenting surrounded lines once.\n    - Deleting surrounding which looks like a result of linewise adding will act to revert it: delete lines with surrounding parts and dedent surrounded lines once.\n    - Blockwise adding places surrounding parts on whole edges, not only start and end of selection.\n\n\n# Version 0.7.0\n\n## All\n\n### Expand\n\n- Start dual distribution. Every module is now distributed both as part of 'mini.nvim' library and as standalone plugin (in separate git repository).\n\n## mini.ai\n\n### Refine\n\n- In `MiniAi.gen_spec.argument()` option `separators` (plural; array of characters) is soft deprecated in favor of `separator` (singular; Lua pattern) option.\n\n## mini.animate\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.basics\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.completion\n\n### Refine\n\n- Rename `MiniCompletion.config.window_dimensions` to `MiniCompletion.config.window` to be able to handle more general configuration.\n\n### Expand\n\n- Add `MiniCompletion.config.window.info.border` and `MiniCompletion.config.window.signature.border` which can be used to define border of info and signature floating windows respectively.\n\n## mini.indentscope\n\n### Refine\n\n- Stop using (deprecate) `MiniIndentscopePrefix` highlight groups. It was initially introduced as a way to properly show scope indicator on empty lines. It had a drawback of overshadowing 'listchars' symbols (see #125) and vertical guides from 'lukas-reineke/indent-blankline.nvim'. As the other implementation approach was found by @mivort (see #161), `MiniIndentscopePrefix` is no longer needed and no overshadowing is done.\n\n- Update `MiniIndentscope.gen_animation` to now be a table (for consistency with other `gen_*` functions in 'mini.nvim'). See \"Migrate from function type\" section of `:h MiniIndentscope.gen_animation`. Calling it as function will be available until next release.\n\n## mini.misc\n\n### Expand\n\n- Add `MiniMisc.setup_auto_root()` and `MiniMisc.find_root()` for root finding functionality. NOTE: requires Neovim>=0.8.\n\n- Add `MiniMisc.setup_restore_cursor()` for automatically restoring latest cursor position on file reopen. By @cryptomilk, PR #198.\n\n## mini.move\n\n### Expand\n\n- Introduction of a new module.\n\n\n# Version 0.6.0\n\n## All\n\n### Refine\n\n- Stop official support of Neovim 0.5.\n\n### Expand\n\n- Make all messages use colors and not cause hit-enter-prompt.\n\n## mini.align\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.base16\n\n### Refine\n\n- Change some 'mini.nvim' highlights:\n    - `MiniCompletionActiveParameter` now highlights with background instead of underline.\n    - `MiniJump2dSpot` now explicitly defined to use plugin's palette.\n    - `MiniStarterItemPrefix` and `MiniStarterQuery` are now bold for better visibility.\n\n- Update highlight for changed git diff to be more visible and to comply more with general guidelines.\n\n### Expand\n\n- Add support for many plugin integrations.\n\n- Implement `MiniBase16.config.plugins` for configuring plugin integrations.\n\n## mini.jump\n\n### Refine\n\n- Allow cursor to be positioned past the end of previous/current line (#113).\n\n## mini.map\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.starter\n\n### Refine\n\n- Item evaluation is now prepended with query reset, as it is rarely needed any more (#105).\n\n- All hooks are now called with `(content, buf_id)` signature allowing them properly use current window layout.\n\n## mini.surround\n\n### Evolve\n\n- Update 'mini.surround' to share as much with 'mini.ai' as possible. This provides more integrated experience while enabling more useful features. Details:\n    - Custom surrounding specification for input action has changed. Instead of `{ find = <string>, extract = <string> }` it is now `{ <function or composed pattern> }`. Previous format will work until the next release. See more in help file.\n    - Algorithm for finding surrounding is now more powerful. It allows searching for more complex surroundings (via composed patterns or array of region pairs) and respects `v:count`.\n    - Multiline input and output surroundings are now supported.\n    - Opening brackets (`(`, `[`, `{`, `<`) now include whitespace in surrounding: input surrounding selects all inner edge whitespace, output surrounding is padded with single space.\n    - Surrounding identifier `i` (\"interactive\") is soft deprecated in favor of `?` (\"user prompt\").\n    - New surrounding aliases:\n        - `b` for \"brackets\". Input - any of balanced `()`, `[]` `{}`. Output - `()`.\n        - `q` for \"quotes\". Input - any of `\"`, `'`, `` ` ``. Output - `\"\"`.\n    - Three new search methods `'prev'`, `'next'`, and `'nearest'` for finding non-covering previous and next surrounding.\n\n- Implement \"last\"/\"next\" extended mappings which force `'prev'` or `'next'` search method. Controlled with `config.mappings.suffix_last` and `config.mappings.suffix_next`respectively. This also means that custom surroundings with identifier equal to \"last\"/\"next\" mappings suffixes (defaults to 'l' and 'n') will work only with long enough delay after typing action mapping.\n\n### Expand\n\n- Implement `MiniSurround.gen_spec` with generators of common surrounding specifications (like `MiniSurround.gen_spec.input.treesitter` for tree-sitter based input surrounding).\n\n\n# Version 0.5.0\n\n## All\n\n### Refine\n\n- Update all tests to use new 'mini.test' module.\n\n### Expand\n\n- Implement buffer local configuration. This is done with `vim.b.mini*_config` buffer variables.\n\n- Add new `minicyan` color scheme.\n\n## mini.ai\n\n- Introduction of a new module.\n\n## mini.comment\n\n### Expand\n\n- Now hooks can be used to terminate further actions by returning `false` (#108).\n\n## mini.indentscope\n\n### Refine\n\n- Soft deprecate `vim.b.miniindentscope_options` in favor of using `options` field of `miniindentscope_config`.\n\n## mini.sessions\n\n### Expand\n\n- Hooks are now called with active session data as argument.\n\n## mini.starter\n\n### Evolve\n\n### Refine\n\n- Deprecate `MiniStarter.content` in favor of `MiniStarter.get_content()`.\n\n### Expand\n\n- Make it possible to open multiple Starter buffers at the same time (#82).\n\n- All functions dealing with Starter buffer now have `buf_id` as argument.\n\n## mini.statusline\n\n### Expand\n\n- Implement `config.use_icons` which controls whether to use icons by default.\n\n## mini.test\n\n- Introduction of a new module.\n\n## mini.trailspace\n\n### Expand\n\n- Implement `MiniTrailspace.trim_last_lines()`.\n\n\n# Version 0.4.0\n\n## All\n\n### Expand\n\n- Update all modules to supply mapping description for Neovim>=0.7.\n\n- Cover all modules with extensive tests.\n\n## mini.comment\n\n### Expand\n\n- Implement `config.hooks` with `pre` and `post` hooks (executed before and after successful commenting). Fixes #50, #59.\n\n## mini.completion\n\n### Expand\n\n- Implement support for `additionalTextEdits` (issue #61).\n\n## mini.jump\n\n### Refine\n\n- Soft deprecate `config.highlight_delay` in favor of `config.delay.highlight`.\n\n### Expand\n\n- Implement idle timeout to stop jumping automatically (@annenpolka, #56).\n\n- Implement `MiniJump.state`: table with useful model-related information.\n\n- Update process of querying target symbol: show help message after delay, allow `<C-c>` to stop selecting target.\n\n## mini.jump2d\n\n- Introduction of a new module.\n\n## mini.pairs\n\n### Refine\n\n- Create mappings for `<BS>` and `<CR>` in certain mode only after some pair is registered in that mode.\n\n## mini.sessions\n\n### Refine\n\n- All feedback about incorrect behavior is now an error instead of message notifications.\n\n### Expand\n\n- Implement `MiniSessions.select()` to select session interactively and perform action on it.\n\n- Implement `config.hooks` to execute hook functions before and after successful action.\n\n## mini.starter\n\n### Expand\n\n- Allow `config.header` and `config.footer` be any value, which will be converted to string via `tostring()`.\n\n- Update query logic to not allow queries which result into no items.\n\n- Add `<C-n>` and `<C-p>` to default mappings.\n\n## mini.statusline\n\n### Refine\n\n- Change default icon for `MiniStatusline.section_diagnostics()` from ﯭ to  due to former having issues in some terminal emulators.\n\n## mini.surround\n\n### Evolve\n\n### Refine\n\n- Deprecate `config.funname_pattern` option in favor of manually modifying `f` surrounding.\n\n- Always move cursor to the right of left surrounding in `add()`, `delete()`, and `replace()` (instead of moving only if it was on the same line as left surrounding).\n\n### Expand\n\n- Implement `config.search_method`.\n\n- Implement custom surroundings via `config.custom_surroundings`.\n\n- Implement `MiniSurround.user_input()`.\n\n- Update process of getting user input: allow `<C-c>` to cancel and make empty string a valid input.\n\n## mini.tabline\n\n### Refine\n\n- Show listed buffers also in case of multiple tabpages (instead of using builtin behavior).\n\n### Expand\n\n- Implement `config.tabpage_section`.\n\n- Show quickfix/loclist buffers with special `*quickfix*` label.\n\n\n# Version 0.3.0\n\n## All\n\n### Expand\n\n- Update all modules to have annotations formatted for 'mini.doc'.\n\n## mini.cursorword\n\n### Expand\n\n- Current word under cursor now can be highlighted differently.\n\n## mini.doc\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.indentscope\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.starter\n\n### Expand\n\n- Implement `MiniStarter.set_query()` and make `<Esc>` mapping for resetting query.\n\n\n# Version 0.2.0\n\n## mini.base16\n\n### Expand\n\n- Use new `Diagnostic*` highlight groups in Neovim 0.6.0.\n\n## mini.comment\n\n### Expand\n\n- Respect tab indentation (#20).\n\n## mini.jump\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.pairs\n\n### Expand\n\n- Implement pair registration with custom mapping functions:\n    - Implement `MiniPairs.map()`, `MiniPairs.map_buf()`, `MiniPairs.unmap()`, `MiniPairs.unmap_buf()` to (un)make mappings for pairs which automatically register them for `<BS>` and `<CR>`. Note, that this has a minor break of previous behavior: now `MiniPairs.bs()` and `MiniPairs.cr()` don't have any input argument. But default behavior didn't change.\n    - Allow setting global pair mappings inside `config` of `MiniPairs.setup()`.\n\n## mini.sessions\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.starter\n\n### Expand\n\n- Introduction of a new module.\n\n## mini.statusline\n\n### Expand\n\n- Implement new section `MiniStatusline.section_searchcount()`.\n\n- Update `section_diagnostics` to use `vim.diagnostic` in Neovim 0.6.0.\n\n\n# Version 0.1.0\n\n## All\n\n### Expand\n\n- Initial stable version.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n`evgeni <dot> chasnovski |at| gmail >dot< com` .\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for  specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThank you for your willingness to contribute to 'mini.nvim'. It means a lot!\n\nYou can make contributions in the following ways:\n\n- **Mention it** somehow to help reach broader audience. This helps a lot.\n- **Create a GitHub issue**. It can be one of the following types:\n    - **Bug report**. Describe your actions in a reproducible way along with their effect and what you expected should happen. Before making one, please make your best efforts to:\n        - Make sure that it is not an intended behavior, i.e. not described in documentation as such.\n        - Make sure that it was not reported before, i.e. there is no bug report already created (no matter open or closed).\n    - **Feature request**. A concise and justified description of what one or several modules should be able to do. Before making one, please make your best efforts to make sure that it is not a feature that won't get implemented (these should be described in documentation; for example: block comments in 'mini.comment').\n- **Create a pull request (PR)**. It can be one of the following types:\n    - **Code related**. For example, fix a bug or implement a feature. **Before even starting one, please make sure that it is aligned with project vision and goals**. The best way to do so is to receive positive feedback from maintainer on your initiative in one of the GitHub issues (existing or created by you). Please, make sure to regenerate latest help file and that all tests pass (see later sections).\n    - **Documentation related**. For example, fix typo/wording in 'README.md', code comments or annotations (which are used to generate Neovim documentation; see later section). Feel free to make these without creating a GitHub issue.\n    - **Add plugin integration to 'mini.base16' and 'mini.hues' modules**.\n- **Add explicit support to other colorschemes**. Every 'mini.nvim' module supports any colorscheme right out of the box. This is done by making most highlight groups be linked to a semantically similar builtin highlight group. Other groups are hard-coded based on personal preference. However, these choices might be out of tune with a particular colorscheme. Updating as many colorschemes as possible to have explicit 'mini.nvim' support is highly appreciated. For your convenience, there is a list of all highlight groups in later section of this file.\n- **Participate in [discussions](https://github.com/nvim-mini/mini.nvim/discussions)**.\n\nAll well-intentioned, polite, and respectful contributions are always welcome! Thanks for reading this!\n\n## Commit messages\n\n- Try to make commit message as concise as possible while giving enough information about nature of a change. Think about whether it will be easy to understand in one year time when browsing through commit history.\n\n- Single commit should change either zero or one module, or affect all modules (i.e. enforcing some universal rule but not necessarily change files). Changes for two or more modules should be split in several module-specific commits.\n\n- Use [Conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) style:\n    - Messages should have the following structure:\n\n        ```\n        <type>[optional scope][!]: <description>\n        <empty line>\n        [optional body]\n        <empty line>\n        [optional footer(s)]\n        ```\n\n    - `<type>` is **mandatory** and can be one of:\n        - `ci` - change in how automation (GitHub actions, dual distribution scripts, etc.) is done.\n        - `docs` - change in user facing documentation (help, README, CONTRIBUTING, etc.).\n        - `feat` - adding new user facing feature.\n        - `fix` - resolving user facing issue.\n        - `refactor` - change in code or documentation that should not affect users.\n        - `style` - change in convention of how something should be done (formatting, wording, etc.) and its effects.\n        - `test` - change in tests.\n      For temporary commits which later should be squashed (when working on PR, for example), use `fixup` type.\n    - `[optional scope]`, if present, should be done in parenthesis `()`. If commit changes single module (as it usually should), using scope with module name is **mandatory**. If commit enforces something for all modules, use `ALL` scope.\n    - Breaking change, if present, should be expressed with `!` before `:`.\n    - `<description>` is a change overview in imperative, present tense (\"change\" not \"changed\" nor \"changes\"). Should result into first line under 72 characters. Should start with not capitalized word and NOT end with sentence ending punctuation (i.e. one of `.,?!;`).\n    - `[optional body]`, if present, should contain details and motivation about the change in plain language. Should be formatted to have maximum 80 characters in line.\n    - `[optional footer(s)]`, if present, should be instruction(s) to Git or Github. Use \"Resolve #xxx\" on separate line if this commit resolves issue or PR.\n\n- Use module's function and field names without module's name. Like `add()` and not `MiniSurround.add()`.\n\nExamples:\n\n```\nfeat(deps): add folds in update confirmation buffer\n```\n\n```\nfix(jump): make operator not delete one character if target is not found\n\nOne main goal is to do that in a dot-repeatable way, because this is very\nlikely to be repeated after an unfortunate first try.\n\nResolve #688\n```\n\n```\nrefactor(bracketed): do not source 'vim.treesitter' on `require()`\n\nAlthough less explicit, this considerably reduces startup footprint of\n'mini.bracketed' in isolation.\n```\n\n```\nfeat(hues)!: update verbatim text to be distinctive\n```\n\n```\ntest(ALL): update screenshots to work on Nightly\n```\n\n### Automated commit linting\n\n- To lint messages of already done commits, execute `scripts/lintcommit-ci.sh <git-log-range>`. For example, to lint currently latest commit use `scripts/lintcommit-ci.sh HEAD~..HEAD`.\n- To lint commit message before doing commit, install [`pre-commit`](https://pre-commit.com/#install) and enable it with `pre-commit install --hook-type commit-msg` (from the root directory). NOTE: requires `nvim` executable. If it throws (usually descriptive) error - recommit with proper message.\n\n## Generating help file\n\nIf your contribution updates annotations used to generate help file, please regenerate it. You can make this with one of the following (assuming current directory being project root):\n\n- From command line execute `make documentation`.\n- Inside Neovim instance run `:luafile scripts/minidoc.lua` or `:lua require('mini.doc').generate()`.\n\n## Testing\n\nIf your contribution updates code, please make sure that it doesn't break existing tests. If it adds new functionality or fixes a recognized bug, add new test case(s). There are two ways of running tests:\n\n- From command line:\n    - Execute `make test` to run all tests (with `nvim` as executable).\n    - Execute `make test_xxx` to run tests only from file `tests/test_xxx.lua` (with `nvim` as executable). For example, `make test_ai`.\n    - If you have multiple Neovim executables (say, `nvim_07`, `nvim_08`, `nvim_09`, `nvim_010`), you can use `NVIM_EXEC` variable to tests against multiple versions like this:\n      `NVIM_EXEC=\"nvim_07 nvim_08 nvim_09 nvim_010\" make test` or `NVIM_EXEC=\"nvim_07 nvim_08 nvim_09 nvim_010\" make test_xxx`.\n- Inside Neovim instance execute `:lua require('mini.test').setup(); MiniTest.run()` to run all tests or `:lua require('mini.test').setup(); MiniTest.run_file()` to run tests only from current buffer.\n\nThis plugin uses 'mini.test' to manage its tests. For a more hands-on introduction, see [TESTING.md](TESTING.md).\n\n**Notes**:\n\n- If new functionality relies on an external dependency (`git` CLI tool, LSP server, etc.), use mocking (writing Lua code which emulates dependency usage as close as reasonably possible). For examples, take a look at tests for 'mini.pick', 'mini.completion', and 'mini.statusline'.\n- There is a certain number of tests that are flaky (i.e. will sometimes report an error due to other reasons than actual functionality being broke). It is usually the ones which test time related functionality (i.e. that certain action was done after specific amount of delay).\n\n    A commonly used way to know if the test is flaky is that it fails on non-nightly Neovim version yet there were no changes to its tested module after it had passed in the past. For example, some 'mini.animate' test is shown to break but there were no changes to it since test passed in CI couple of days before.\n\n    This issue is addressed by having test cases being executed several times in case of failure (with more retries in slow context). See [\"Retry\" section in 'TESTING.md'](TESTING.md#Retry).\n\n    In case there is some test breaking which reasonably should not, rerun that test (or the whole file) at least several times.\n- Advice for writing more robust tests:\n    - To test asynchronous or slow execution, use common `sleep()` test helper. For a more robust testing code, **never** directly use numbers to compute sleep time. Use precomputed time delay constants, which should always take into account different testing OSs (like be bigger on Windows, etc.). If module testing requires its extensive use and tests can not be made robust enough (examples are 'mini.animate', 'mini.jump', etc.), consider using it with argument that skips entire test case if `sleep()` is called in slow context.\n    - Take into account that Windows uses \"\\\" as default path separator instead of Unix \"/\". This should be accounted either in module's code (preferably) or in test files (for example, by computing path separator and relying on it).\n\n## Formatting\n\nThis project uses [StyLua](https://github.com/JohnnyMorganz/StyLua) version 2.1.0 for formatting Lua code. Before making changes to code, please:\n\n- [Install StyLua](https://github.com/JohnnyMorganz/StyLua#installation). NOTE: use `v2.1.0`.\n- Format with it. Currently there are two ways to do this:\n    - Manually run `stylua .` from the root directory of this project.\n    - Install [`pre-commit`](https://pre-commit.com/#install) and enable it with `pre-commit install` (from the root directory). This will auto-format relevant code before making commits.\n\n## List of highlight groups\n\nHere is a list of all highlight groups defined inside 'mini.nvim' modules. See documentation in 'doc' directory to find out what they are used for.\n\n- 'mini.animate':\n    - `MiniAnimateCursor`\n    - `MiniAnimateNormalFloat`\n\n- 'mini.clue':\n    - `MiniClueBorder`\n    - `MiniClueDescGroup`\n    - `MiniClueDescSingle`\n    - `MiniClueNextKey`\n    - `MiniClueNextKeyWithPostkeys`\n    - `MiniClueSeparator`\n    - `MiniClueTitle`\n\n- 'mini.cmdline':\n    - `MiniCmdlinePeekBorder`\n    - `MiniCmdlinePeekLineNr`\n    - `MiniCmdlinePeekNormal`\n    - `MiniCmdlinePeekSep`\n    - `MiniCmdlinePeekSign`\n    - `MiniCmdlinePeekTitle`\n\n- 'mini.completion':\n    - `MiniCompletionActiveParameter`\n    - `MiniCompletionDeprecated`\n    - `MiniCompletionInfoBorderOutdated`\n\n- 'mini.cursorword':\n    - `MiniCursorword`\n    - `MiniCursorwordCurrent`\n\n- 'mini.deps':\n    - `MiniDepsChangeAdded`\n    - `MiniDepsChangeRemoved`\n    - `MiniDepsHint`\n    - `MiniDepsInfo`\n    - `MiniDepsMsgBreaking`\n    - `MiniDepsPlaceholder`\n    - `MiniDepsTitle`\n    - `MiniDepsTitleError`\n    - `MiniDepsTitleSame`\n    - `MiniDepsTitleUpdate`\n\n- 'mini.diff':\n    - `MiniDiffSignAdd`\n    - `MiniDiffSignChange`\n    - `MiniDiffSignDelete`\n    - `MiniDiffOverAdd`\n    - `MiniDiffOverChange`\n    - `MiniDiffOverChangeBuf`\n    - `MiniDiffOverContext`\n    - `MiniDiffOverContextBuf`\n    - `MiniDiffOverDelete`\n\n- 'mini.files':\n    - `MiniFilesBorder`\n    - `MiniFilesBorderModified`\n    - `MiniFilesCursorLine`\n    - `MiniFilesDirectory`\n    - `MiniFilesFile`\n    - `MiniFilesNormal`\n    - `MiniFilesTitle`\n    - `MiniFilesTitleFocused`\n\n- 'mini.hipatterns':\n    - `MiniHipatternsFixme`\n    - `MiniHipatternsHack`\n    - `MiniHipatternsNote`\n    - `MiniHipatternsTodo`\n\n- 'mini.icons':\n    - `MiniIconsAzure`\n    - `MiniIconsBlue`\n    - `MiniIconsCyan`\n    - `MiniIconsGreen`\n    - `MiniIconsGrey`\n    - `MiniIconsOrange`\n    - `MiniIconsPurple`\n    - `MiniIconsRed`\n    - `MiniIconsYellow`\n\n- 'mini.indentscope':\n    - `MiniIndentscopeSymbol`\n    - `MiniIndentscopeSymbolOff`\n\n- 'mini.jump':\n    - `MiniJump`\n\n- 'mini.jump2d':\n    - `MiniJump2dDim`\n    - `MiniJump2dSpot`\n    - `MiniJump2dSpotAhead`\n    - `MiniJump2dSpotUnique`\n\n- 'mini.map':\n    - `MiniMapNormal`\n    - `MiniMapSymbolCount`\n    - `MiniMapSymbolLine`\n    - `MiniMapSymbolView`\n\n- 'mini.notify':\n    - `MiniNotifyBorder`\n    - `MiniNotifyLspProgress`\n    - `MiniNotifyNormal`\n    - `MiniNotifyTitle`\n\n- 'mini.operators':\n    - `MiniOperatorsExchangeFrom`\n\n- 'mini.pick':\n    - `MiniPickBorder`\n    - `MiniPickBorderBusy`\n    - `MiniPickBorderText`\n    - `MiniPickCursor`\n    - `MiniPickIconDirectory`\n    - `MiniPickIconFile`\n    - `MiniPickHeader`\n    - `MiniPickMatchCurrent`\n    - `MiniPickMatchMarked`\n    - `MiniPickMatchRanges`\n    - `MiniPickNormal`\n    - `MiniPickPreviewLine`\n    - `MiniPickPreviewRegion`\n    - `MiniPickPrompt`\n    - `MiniPickPromptCaret`\n    - `MiniPickPromptPrefix`\n\n- 'mini.snippets':\n    - `MiniSnippetsCurrent`\n    - `MiniSnippetsCurrentReplace`\n    - `MiniSnippetsFinal`\n    - `MiniSnippetsUnvisited`\n    - `MiniSnippetsVisited`\n\n- 'mini.starter':\n    - `MiniStarterCurrent`\n    - `MiniStarterFooter`\n    - `MiniStarterHeader`\n    - `MiniStarterInactive`\n    - `MiniStarterItem`\n    - `MiniStarterItemBullet`\n    - `MiniStarterItemPrefix`\n    - `MiniStarterSection`\n    - `MiniStarterQuery`\n\n- 'mini.statusline':\n    - `MiniStatuslineDevinfo`\n    - `MiniStatuslineFileinfo`\n    - `MiniStatuslineFilename`\n    - `MiniStatuslineInactive`\n    - `MiniStatuslineModeCommand`\n    - `MiniStatuslineModeInsert`\n    - `MiniStatuslineModeNormal`\n    - `MiniStatuslineModeOther`\n    - `MiniStatuslineModeReplace`\n    - `MiniStatuslineModeVisual`\n\n- 'mini.surround':\n    - `MiniSurround`\n\n- 'mini.tabline':\n    - `MiniTablineCurrent`\n    - `MiniTablineFill`\n    - `MiniTablineHidden`\n    - `MiniTablineModifiedCurrent`\n    - `MiniTablineModifiedHidden`\n    - `MiniTablineModifiedVisible`\n    - `MiniTablineTabpagesection`\n    - `MiniTablineTrunc`\n    - `MiniTablineVisible`\n\n- 'mini.test':\n    - `MiniTestEmphasis`\n    - `MiniTestFail`\n    - `MiniTestPass`\n\n- 'mini.trailspace':\n    - `MiniTrailspace`\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Evgeni Chasnovski\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": "MAINTAINING.md",
    "content": "# Maintaining\n\nThis document contains knowledge about specifically maintaining 'mini.nvim'. It assumes general knowledge about how Open Source and GitHub issues/PRs work.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for how to generate help files, run tests, and format.\n\n## General advice\n\n- Follow common boilerplate code as much as possible when creating new module, as it makes easier to use \"search and replace\" in the long term. This includes:\n    - Documentation at the beginning: describing module, its setup, highlight groups, similar plugins, disabling, `setup()`, and `config`.\n    - Create and use `H` helper table at the beginning to allow having exported code written before helpers (severely improves readability).\n    - Structure of `setup()` function with its helper functions: `H.setup_config()`, `H.apply_config()`, `H.create_autocommands()`, `H.create_default_hl()`, `H.create_user_commands()`.\n- Use module's `H.get_config()` and `H.is_disabled()` helpers. They both should respect buffer local configuration.\n- From time to time some test cases will break on Neovim Nightly. This is usually due to the following reasons:\n    - There was an intended change in Neovim Nightly to which affected module(s) should adapt. Update module and/or tests.\n    - There was a change in Neovim Nightly disrupting only tests (usually screenshots due to changed way of how highlight attributes are computed). Update test: ideally so that it passes on all versions (by adjusting test logic or by selectively ignoring attributes / text of not matching lines with `ignore_text` / `ignore_attr` *behind narrowest Neovim version check*), but testing some parts only on Nightly is allowed if needed (regenerate screenshot on Nightly and verify it only on versions starting from it).\n    - There was an unintended change in Neovim Nightly which breaks functionality it should not break. Create an issue in ['neovim/neovim' repo](https://github.com/neovim/neovim). If the issue is not resolved for a long-ish time (i.e. more than a week) try to make tests pass and/or adapt the code to new behavior.\n- Write help annotations in a way that after help generation they are usable in both built-in `:help`and on nvim-mini.org site. In particular:\n    - Prefer using `# Section ~` and `## Subsection ~` explicit sections. This allows more structured table of contents and adds anchors for all of them.\n    - Prefer using \"naturally sounding\" help tags for an entire section because they are transformed into a title. So like `---@tag MiniAi-builtin-textobjects` and not `---@tag MiniAi-textobjects-builtin`.\n        - As a consequence, don't add \"# Title ~\" title at the beginning of the section. This is a role for the tag (in both help file and site).\n    - Do not use explicit right aligned tags, as they result into a separate high level heading on the site. This usually breaks hierarchical structure of the page (like if added as part of a `MiniXxx.config` section, it ends the `config` section and starts its own). Prefer to \"naturally\" incorporate a tag into a text in first line of its info or add it directly below a dedicated section. Examples:\n\n        ```\n        --- # Important topic ~\n        --- *MiniXxx-important-topic*\n        ---\n        --- A text about important topic of 'mini.xxx' module.\n        ---\n        --- # Another topic ~\n        ---\n        --- *MiniXxx-another-topic* is also important.\n        ---\n        --- *MiniXxx-last-resort*\n        --- As last resort just add left aligned tag before first line\n        --- or at line start.\n        ```\n\n## Maintainer setup\n\nMandatory:\n- Have `nvim` executable for latest stable release.\n- Install [`git`](https://www.git-scm.com).\n- Install [`StyLua`](https://github.com/JohnnyMorganz/StyLua) with version described in [CONTRIBUTING.md](CONTRIBUTING.md).\n- Install [`make`](https://www.gnu.org/software/make/).\n\nRecommended:\n- Have executables for all supported Neovim versions. For example, `nvim_07`, `nvim_08`, `nvim_09`, `nvim_010`. This is useful for running tests on multiple versions.\n- Install [`lua-language-server`](https://github.com/LuaLS/lua-language-server).\n- Install [`pre-commit`](https://pre-commit.com/#install) and enable it with `pre-commit install` and `pre-commit install --hook-type commit-msg` (run from repository's root).\n- Set up 'mini.doc' and 'mini.test' and make mappings for the following frequently used commands:\n    - `'<Cmd>lua MiniDoc.generate()<CR>'` - to generate documentation.\n    - `'<Cmd>lua MiniTest.run_at_location()<CR>'` - to run test under cursor.\n    - `'<Cmd>lua MiniTest.run_file()<CR>'` - to run current test file.\n\n## Supported Neovim versions\n\nAim for supporting 4 latest minor Neovim releases: current stable, current Nightly, and two latest stable releases.\n\nFor example, if 0.9.x is current stable, then all latest patch versions of 0.7, 0.8, 0.9 should be supported plus Nightly (0.10.0).\n\nNOTE: some modules can have less supported versions during their release **only** if it is absolutely necessary for the core functionality.\n\n## Dual distribution\n\nModules of 'mini.nvim' are distributed both as part of 'mini.nvim' repository and each one in its standalone repository. All development takes place in 'mini.nvim' while being synced to standalone ones. This is done by having special `sync` branch which points to the latest commit which was synced to standalone repositories.\n\nUsual workflow involves performing these steps after every commit in 'mini.nvim':\n\n- Check out to `main` branch.\n- Ensure there are no immediate defects. Usually it means to wait until all CI checks passed.\n- Run `make dual_sync`. This should:\n    - Create 'dual' directory if doesn't exist yet.\n    - Pull standalone repositories in 'dual/repos'.\n    - Create patches in 'dual/patches' and apply them for standalone repositories.\n\n    See 'scripts/dual_sync.sh' for more details.\n- Run `make dual_log` to make sure that all and correct patches were applied. If some commit touches files from several modules, it results into commits for every affected standalone repository.\n- Run `make dual_push`. This should:\n    - Push updates for affected standalone repositories.\n    - Clean up 'dual/patches'.\n    - Update `sync` branch to point to latest commit and push it to `origin`.\n\n## Typical workflow for adding change\n\n- Solve the problem.\n- If change is in code, write test which breaks before problem is solved and passes after.\n- If change introduces new config setting, consult with [dedicated checklist](#adding-new-config-settings).\n- If change is worth to be seen by users (notable/breaking feature/fix), update 'CHANGELOG.md' following formatting from previous versions.\n- Make sure that all tests in affected module(s) pass in all supported versions. See [Maintainer setup](#maintainer-setup) and ['Testing' section in CONTRIBUTING.md](CONTRIBUTING.md#testing).\n- Stage and commit changes into a separate Git branch. Push the branch.\n- Make sure that all CI pass.\n- Merge branch into `main` branch. Push `main`.\n- Make sure that all CI pass (again).\n- Synchronize dual distribution:\n    - `make dual_sync` to sync.\n    - `make dual_log` and look at changes which are about to be applied to standalone repositories. Make sure that they are what you'd expect.\n    - `make dual_push` to push changes to standalone repositories.\n\n## Typical workflow for processing a GitHub issue\n\n- Add label with module name issue is about (if any). If issue is worded politely and/or with much details, thank user for opening an issue.\n- Make sure the underlying problem is valid, i.e. it can be reproduced and the root cause is in this project. If it can not be reproduced, politely explain that and ask for more reproduction details. If the cause is not related to the project, politely explain that, close an issue, and direct towards the real root cause.\n- Check already existing issues for possible duplicates. If there is at least one, review its reasoning before making decision about the current issue.\n- Decide whether and how an issue should be resolved. Use [\"General principles\"](README.md#general-principles), module's help and code documentation while making the decision.\n    - If decision is to not resolve, politely explain that and close an issue (possibly mentioning similar reasoning in the past).\n    - If decision is to resolve, resolve the issue while putting `Resolve #xxx` at the bottom of commit message.\n\n## Typical workflow for processing GitHub pull request\n\n- Add label with module name pull request (PR) is about (if any). If PR is worded politely, thank user for doing that.\n- Make sure the PR is valid, i.e. resolves an issue or adds a feature any of which aligns with the project. Ideally, it should have been agreed in the prior created issue (as per [CONTRIBUTING.md](CONTRIBUTING.md)).\n- Review PR code and iterate towards making it have enough code quality. Use first steps of [\"Typical workflow for adding change\"](#typical-workflow-for-adding-change) as reference. **Note**: if what is left to do requires some overly specific project knowledge (i.e. can be done _much_ quicker if you know how, but requires non-trivial amount of reading/discovering first time), consider merging PR in a new separate branch and finish it manually (usually with preserving original commit authorship).\n- When change is of enough quality, merge it and proceed treating it as regular change.\n\n## Stopping support for old Neovim version\n\nBegin the process of stopping official support for outdated Neovim version shortly after (week or two) the release of the new stable one. Usually it is stopping support for Neovim 0.x (say, 0.8) shortly after the release of 0.(x+3).0 (say, 0.11.0). The deprecation should be done in two stages:\n\n- Stage 1, soft deprecation (to notify old version users about upcoming support drop):\n    - Add version of the following code snippet at the beginning of `setup()` function body in **every** module:\n\n    ```lua\n    -- TODO: Remove after Neovim=0.8 support is dropped\n    if vim.fn.has('nvim-0.9') == 0 then\n      vim.notify(\n        '(mini.ai) Neovim<0.9 is soft deprecated (module works but not supported).'\n          .. ' It will be deprecated after next \"mini.nvim\" release (module might not work).'\n          .. ' Please update your Neovim version.'\n      )\n    end\n    ```\n\n    - Modify CI to not test on old Neovim version.\n    - Update issue template to not include old Neovim version.\n    - Update README and repo description to indicate new oldest supported Neovim version.\n    - Wait for a considerable amount of time (at least about a month) *and* a new 'mini.nvim' stable release (so that there is no actual deprecation in the stable release).\n\n- Stage 2, deprecation:\n    - Remove all notification snippets added in Stage 1.\n    - Adjust code that is conditioned on `vim.fn.has('nvim-0.x')` and `vim.fn.exists('+option')` (if the option is present in all currently supported Neovim versions).\n    - Adjust code/comments/documentation that contains any combination of `Neovim{<,<=,=,>=,>}{0.x,0.(x+1)}` (like `Neovim<0.x`, `Neovim>=0.(x+1)`, etc.).\n    - Add entry \"Stop official support of Neovim 0.x.\" in 'CHANGELOG.md' at the start of current development version block.\n\n## Reacting to new minor Neovim version\n\n- Modify CI to test on new Neovim version.\n- Update issue template to mention new Neovim version as released one, make it default choice, and bump Nightly version.\n\n## Reacting to failing tests after Neovim Nightly changes\n\nAs Neovim is in active development, from time to time there will be test failures only on Neovim Nightly (and not on earlier versions). Adjusting tests to pass on all supported versions is important. The sooner the better, as it will allow for an easier deduction of what Neovim change is responsible here.\n\nFor examples of how this was done in the past, search `git log --oneline` output for \"Nightly\". This is probably the best way to learn about different approaches.\n\nHere is a rough outline of how to act (with some Git commit hashes for illustration):\n\n- Investigate if the change actually affects plugin functionality or is it only due to how the test is set up. Trying to manually reproduce the tested behavior on Nightly version is usually helpful for this decision.\n\n    Common examples of code related changes on Nightly:\n    - Changing how certain functions work: different arguments or a breaking change. Like in `848c5e8f428faf843051768e0d56104cd02aea1f`.\n    - Deprecating functions. Like in `0f85c464605cab5ba922644d3f2508c6d62f258e`.\n\n    However, usually it is about how a test is set up. Some common examples:\n\n    - Screenshot testing fails in areas that are not relevant to what is being tested. For example, highlighting attributes of the command line are different (like in `bac6c8bb77fe0a872719ea43c39e35c7c695f05e`) or the number of picker items in 'mini.pick' has changed (like in `b409fd1d8b9ea7ec7c0923eb2562b52ed5d1ab0a`)\n    - New option/mapping/command/etc. is added that broke assumptions about testing environment. Like in `0a8a1072137d916406507c941698a4bfa9dbbe7a`.\n    - Mocking (like LSP or system interaction) is not precise enough for the actually behavior anymore. Like in `c889667a9d73b106bd303a043eb37a91da4a41a2`.\n\n- If the change affects the code:\n    - Adjust the code to work on all supported versions. This should always be the priority.\n    - If you think the Nightly change is unintended, open an issue upstream. Usually requires narrowing down to a reproducible example that does not involve this plugin at all (this is hard!).\n    - If needed, also adjust the tests to pass on all versions.\n    - If needed, prioritize version support in order: current release, Nightly, previous releases. Like if there is a question of different performance trade-offs.\n\n- If the change only affects the test:\n    - First try to adjust the test to pass on all supported Neovim versions. Like adding different code paths for Neovim>=0.xx and Neovim<0.xx.\n\n        This is usually not the case for failing screenshot testing. If feasible and can be done concisely, replace failing screenshot testing with other means of equivalent testing. Like in `68955a915c45ae7c988c539abe6e89f0971a9a2d`.\n\n    - If the previous path is not possible or is significantly complex, make an educated decision of whether test fail is related to the actually tested functionality or not.\n\n        If it tests something crucial, make the best effort to test on the widest *forward-compatible* set of Neovim versions. I.e. it should test on Neovim>=0.yy and not Neovim<=0.yy.\n\n        Usually it is good enough for non-crucial part of the test to make only a forward-compatible test that starts on current Nightly (as long as that version is being tested in CI).\n        Like in `3f5d06a6f710966cb93baaadc4897eeb6d6210e5` or `be6979dddb339c4a548d2f1dac5c290b5bf73306`.\n\n- Make adjustments and commit. Use commit message with title that contains \"Nightly\" and (preferably) with body describing the culprit for the change. This helps when searching the Git history for similar cases.\n\n## Adding new config settings\n\n- Add code which uses new setting.\n- Add default value to `Mini*.config` definition.\n- Update module's `H.setup_config()` with type check of new setting.\n- Update tests to test default config value and its type check.\n- Regenerate help file.\n- Update module's README in 'readmes' directory.\n- Possibly update demo for it to be aligned with current config values.\n- Update 'CHANGELOG.md'. In module's section of current version add line starting with `- FEATURE: Implement ...`.\n\n## Adding new color scheme plugin integration\n\n- Update color scheme module file in a way similar to other already added plugins:\n    - Add definitions for highlight groups.\n    - Add plugin entry in a list of supported plugins in help annotations.\n    - Add plugin entry in a module's README.\n- Regenerate documentation (see [corresponding section in CONTRIBUTING.md](CONTRIBUTING.md#generating-help-file)).\n\n## Adding new module\n\n### Preparation\n\n- Create new module-related assets in https://github.com/nvim-mini/assets:\n    - Logo files. See 'logo-2/generate.lua' in the repo for more details.\n    - Demo video. Preferably under 1 minute screencast showcasing main features. Usually should also display module's config. Use config as close to bare MiniMax as possible. See other demos for reference.\n- Write release blog post for nvim-mini.org. Copy file naming and structure from previous release posts. Mention future beta-testing issue with a placeholder link.\n\n### Initial\n\n- Add Lua source code in 'lua' directory.\n- Add tests in 'tests' directory. Use 'tests/dir-xxx' name for module-specific non-test helpers.\n- Update 'lua/init.lua' to mention new module: both in initial table of contents and list of modules.\n- Add new module to the following files:\n    - 'scripts/minidoc.lua' to generate separate help file.\n    - 'scripts/dual_sync.sh' to include new module.\n    - 'scripts/dual_release.sh' to include new module.\n    - '.github/ISSUE_TEMPLATE/bug-report.yml' to be included in a dropdown menu.\n    - '.github/ISSUE_TEMPLATE/feature-request.yml' to be included in a dropdown menu.\n    - '.github/DISCUSSION_TEMPLATE/q-a.yml' to be included in a dropdown menu.\n- Generate help files.\n- Add README to 'readmes' directory following the structure of some of already existing README (preferably one of the latest). NOTE: comment out mentions of `stable` branch, as it won't work during beta-testing.\n- Update main README:\n    - Mention new module in table of contents.\n    - Remove the module from \"Planned modules\" section (if present).\n- Update 'CHANGELOG.md' to mention introduction of new module.\n- Update 'CONTRIBUTING.md' to mention new highlight groups (if there are any).\n- Create separate release branch and commit changes with message 'feat(xxx): add NEW MODULE'. NOTE: it is cleaner to synchronize standalone repositories prior to this commit.\n- If there are new highlight groups, follow up with adding explicit support in color scheme modules.\n- Push release branch. Make sure CI is green.\n\n### Site integration\n\n- Checkout to module release branch.\n- Verify that nvim-mini.org handles new module. For that:\n    - Modify 'mini.nvim' dependency to checkout into release branch.\n    - `make sync`.\n    - Add release blog post.\n    - `quarto preview`.\n    - Verify that new content looks as expected.\n\n### Release\n\n- Make standalone plugin:\n    - Create new empty GitHub repository. Disable Issues, limit PRs.\n    - Clone the repo manually. Copy 'LICENSE' file to it, stage, and commit (\"docs: add license\"). Push.\n    - Add the following GitHub tags: \"lua\", \"neovim\", \"neovim-plugin\", \"mini-nvim\".\n- Merge release branch into `main`. Push `main` and sync dual distribution.\n- Check that standalone repo doesn't have some known issues:\n    - Make sure that all tracked files are synchronized. For list of tracked files see 'scripts/dual_sync.sh'. Initially they are 'doc/mini-xxx.txt', 'lua/mini/xxx.lua', 'LICENSE', and 'readmes/mini-xxx.md' (copied to be 'README.md' in standalone repository).\n    - Make sure that 'README.md' in standalone repository has appropriate relative links (see patch script).\n    - If there are issues, manually adjust in the repo, amend to latest commit, and force push.\n- Create a beta-testing issue and pin it.\n- Update nvim-mini.org:\n    - `make sync` on `main` branch.\n    - Add release blog post. NOTE: update it with proper beta-testing issue link.\n    - Push.\n\n### Post release\n\n- Wait for at least several weeks of beta-testing before including new module to MiniMax.\n\n## Making stable release\n\n### When\n\nThere is no clear guidelines for when a stable (minor) release should be made. Mostly \"when if feels right\" but \"not too often\". If it has to be put in words, it is something like \"After 3 new modules have finished beta-testing or 4 months, whichever is sooner\". No patch releases have been made yet.\n\n### Preparation\n\n- Write release blog post for nvim-mini.org. Copy file naming and structure from previous version release posts.\n\n### Initial\n\n- Check for `TODO`s about actions to be done *before* release.\n- Checkout `release-0.xx` branch.\n- Update READMEs of new modules to mention `stable` branch. Commit.\n- Bump version in 'CHANGELOG.md'. Commit.\n- Make a dummy change in 'lua/mini/init.lua' file to trigger code CI. Commit.\n- Push to check on CI. **Proceed only if it is successful**.\n- Remove dummy change commit.\n\n### Release\n\n- Merge `release-0.xx` to `main` and push it. Check that CI has passed.\n- Synchronize standalone repositories.\n- Make annotated tag: `git tag -a v0.xx.0 -m 'Version 0.xx.0'`. Push it.\n- Make GitHub release. Get description from copying entries of version's 'CHANGELOG.md' section.\n- Move `stable` branch to point at new tag (`git branch --force stable` when on latest tag's commit). Push it.\n- Release standalone repositories. It should be enough to use 'scripts/dual_release.sh' like so:\n    ```\n    # REPLACE `xx` with your version number\n    TAG_NAME=\"v0.xx.0\" TAG_MESSAGE=\"Version 0.xx.0\" make dual_release\n    ```\n- Check that standalone repositories actually got updates (tag + `stable`): manually visit some of them (at least new modules) on GitHub.\n\n### After release\n\n- Synchronize nvim-mini.org. Merge blog post. Push. Post on Reddit and other social media.\n- Finish beta-testing new modules:\n    - Close beta-testing issues.\n    - Add them to MiniMax.\n- Use development version in 'CHANGELOG.md' ('0.(xx+1).0-dev'). Commit.\n- Check for `TODO`s about actions to be done *after* release.\n"
  },
  {
    "path": "Makefile",
    "content": "NVIM_EXEC ?= nvim\n\nall: test documentation\n\n# Use `make test` to run tests for all modules\ntest:\n\tfor nvim_exec in $(NVIM_EXEC); do \\\n\t\tprintf \"\\n======\\n\\n\" ; \\\n\t\t$$nvim_exec --version | head -n 1 && echo '' ; \\\n\t\t$$nvim_exec --headless --noplugin -u ./scripts/minimal_init.lua \\\n\t\t\t-c \"lua require('mini.test').setup()\" \\\n\t\t\t-c \"lua MiniTest.run()\" ; \\\n\tdone\n\n# Use `make test_xxx` to run tests for module 'mini.xxx'\nTEST_MODULES = $(basename $(notdir $(wildcard tests/test_*.lua)))\n\n$(TEST_MODULES):\n\tfor nvim_exec in $(NVIM_EXEC); do \\\n\t\tprintf \"\\n======\\n\\n\" ; \\\n\t\t$$nvim_exec --version | head -n 1 && echo '' ; \\\n\t\t$$nvim_exec --headless --noplugin -u ./scripts/minimal_init.lua \\\n\t\t\t-c \"lua require('mini.test').setup()\" \\\n\t\t\t-c \"lua MiniTest.run_file('tests/$@.lua')\" ; \\\n\tdone\n\ndocumentation:\n\t$(NVIM_EXEC) --headless --noplugin -u ./scripts/minimal_init.lua -c \"lua require('mini.doc').generate()\" -c \"qa!\"\n\nlintcommit-ci:\n\texport LINTCOMMIT_STRICT=true && chmod u+x scripts/lintcommit-ci.sh && scripts/lintcommit-ci.sh\n\nlint-filename-length-ci:\n\tchmod u+x scripts/lint-filename-length.sh && scripts/lint-filename-length.sh\n\ndual_sync:\n\tchmod u+x scripts/dual_sync.sh && scripts/dual_sync.sh\n\ndual_log:\n\tchmod u+x scripts/dual_log.sh && scripts/dual_log.sh\n\ndual_push:\n\tchmod u+x scripts/dual_push.sh && scripts/dual_push.sh\n\tprintf \"\\n\\033[1mAdjusting `sync` branch\\033[0m\\n\"\n\tgit branch --force sync\n\tgit push origin sync\n\tprintf \"\\n\\033[1mRemoving local patches\\033[0m\\n\"\n\trm -r dual/patches\n\ndual_release:\n\tchmod u+x scripts/dual_release.sh && scripts/dual_release.sh \"$(TAG_NAME)\" \"$(TAG_MESSAGE)\"\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\"> <img src=\"logo.png\" alt=\"mini.nvim\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### All-in-one plugin\n\nLibrary of 40+ independent Lua modules improving overall [Neovim](https://github.com/neovim/neovim) (version 0.9 and higher) experience with minimal effort. They all share same configuration approaches and general design principles.\n\nThink about this project as \"Swiss Army knife\" among Neovim plugins: it has many different independent tools (modules) suitable for most common tasks. Each module can be used separately without any startup and usage overhead.\n\nIf you want to help this project grow but don't know where to start:\n\n- Leave a Github star for 'mini.nvim' and/or any other [MINI projects](https://nvim-mini.org).\n- Check out [contributing guides](CONTRIBUTING.md).\n\nSee [change log](CHANGELOG.md) for a history of changes, including current development version.\n\nSee [MiniMax](https://nvim-mini.org/MiniMax) for a full config example based on 'mini.nvim'.\n\n> [!NOTE]\n> This was previously hosted at `echasnovski/mini.nvim`. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n## Table of contents\n\n- [Installation](#installation)\n- [Modules](#modules)\n- [General principles](#general-principles)\n- [Plugin color schemes](#plugin-color-schemes)\n- [Planned modules](#planned-modules)\n\n## Installation\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods:\n\n- Manually with `git clone` (compatible with [mini.deps](https://nvim-mini.org/mini.nvim/readmes/mini-deps)):\n\n```lua\n-- Put this at the top of 'init.lua'\nlocal path_package = vim.fn.stdpath('data') .. '/site'\nlocal mini_path = path_package .. '/pack/deps/start/mini.nvim'\nif not vim.loop.fs_stat(mini_path) then\n  vim.cmd('echo \"Installing `mini.nvim`\" | redraw')\n  local clone_cmd = {\n    'git', 'clone', '--filter=blob:none',\n    -- Uncomment next line to use 'stable' branch\n    -- '--branch', 'stable',\n    'https://github.com/nvim-mini/mini.nvim', mini_path\n  }\n  vim.fn.system(clone_cmd)\n  vim.cmd('packadd mini.nvim | helptags ALL')\n  vim.cmd('echo \"Installed `mini.nvim`\" | redraw')\nend\n```\n\n- With [folke/lazy.nvim](https://github.com/folke/lazy.nvim):\n\n| Branch | Code snippet                                  |\n|--------|-----------------------------------------------|\n| Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n| Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- With [junegunn/vim-plug](https://github.com/junegunn/vim-plug):\n\n| Branch | Code snippet                                         |\n|--------|------------------------------------------------------|\n| Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n| Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Every module is also distributed as a standalone Git repository. Check out module's information for more details.\n\n**Important**: don't forget to call module's `setup()` (if required) to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Modules\n\n'mini.nvim' contains many modules which is slightly daunting at first. All of them can be used independently, one at a time.\n\nFor easier exploration, here they are presented in groups based on module's primary functionality (although some modules can fit in several groups). See more detailed listing [here](doc/mini-nvim.txt).\n\n### Text editing\n\nThese modules improve your text editing experience. Start with 'mini.ai', 'mini.operators', and 'mini.surround'.\n\n| Module          | Description                           | Overview                             | Details                                  |\n|-----------------|---------------------------------------|--------------------------------------|------------------------------------------|\n| mini.ai         | Extend and create `a`/`i` textobjects | [README](readmes/mini-ai.md)         | [Documentation](doc/mini-ai.txt)         |\n| mini.align      | Align text interactively              | [README](readmes/mini-align.md)      | [Documentation](doc/mini-align.txt)      |\n| mini.comment    | Comment lines                         | [README](readmes/mini-comment.md)    | [Documentation](doc/mini-comment.txt)    |\n| mini.completion | Completion and signature help         | [README](readmes/mini-completion.md) | [Documentation](doc/mini-completion.txt) |\n| mini.keymap     | Special key mappings                  | [README](readmes/mini-keymap.md)     | [Documentation](doc/mini-keymap.txt)     |\n| mini.move       | Move any selection in any direction   | [README](readmes/mini-move.md)       | [Documentation](doc/mini-move.txt)       |\n| mini.operators  | Text edit operators                   | [README](readmes/mini-operators.md)  | [Documentation](doc/mini-operators.txt)  |\n| mini.pairs      | Autopairs                             | [README](readmes/mini-pairs.md)      | [Documentation](doc/mini-pairs.txt)      |\n| mini.snippets   | Manage and expand snippets            | [README](readmes/mini-snippets.md)   | [Documentation](doc/mini-snippets.txt)   |\n| mini.splitjoin  | Split and join arguments              | [README](readmes/mini-splitjoin.md)  | [Documentation](doc/mini-splitjoin.txt)  |\n| mini.surround   | Surround actions                      | [README](readmes/mini-surround.md)   | [Documentation](doc/mini-surround.txt)   |\n\n### General workflow\n\nThese modules improve your general workflow. Start with 'mini.bracketed', 'mini.files', and 'mini.pick'.\n\n| Module         | Description                              | Overview                            | Details                                 |\n|----------------|------------------------------------------|-------------------------------------|-----------------------------------------|\n| mini.basics    | Common configuration presets             | [README](readmes/mini-basics.md)    | [Documentation](doc/mini-basics.txt)    |\n| mini.bracketed | Go forward/backward with square brackets | [README](readmes/mini-bracketed.md) | [Documentation](doc/mini-bracketed.txt) |\n| mini.bufremove | Remove buffers                           | [README](readmes/mini-bufremove.md) | [Documentation](doc/mini-bufremove.txt) |\n| mini.clue      | Show next key clues                      | [README](readmes/mini-clue.md)      | [Documentation](doc/mini-clue.txt)      |\n| mini.cmdline   | Command line tweaks                      | [README](readmes/mini-cmdline.md)   | [Documentation](doc/mini-cmdline.txt)   |\n| mini.deps      | Plugin manager                           | [README](readmes/mini-deps.md)      | [Documentation](doc/mini-deps.txt)      |\n| mini.diff      | Work with diff hunks                     | [README](readmes/mini-diff.md)      | [Documentation](doc/mini-diff.txt)      |\n| mini.extra     | Extra 'mini.nvim' functionality          | [README](readmes/mini-extra.md)     | [Documentation](doc/mini-extra.txt)     |\n| mini.files     | Navigate and manipulate file system      | [README](readmes/mini-files.md)     | [Documentation](doc/mini-files.txt)     |\n| mini.git       | Git integration                          | [README](readmes/mini-git.md)       | [Documentation](doc/mini-git.txt)       |\n| mini.jump      | Jump to next/previous single character   | [README](readmes/mini-jump.md)      | [Documentation](doc/mini-jump.txt)      |\n| mini.jump2d    | Jump within visible lines                | [README](readmes/mini-jump2d.md)    | [Documentation](doc/mini-jump2d.txt)    |\n| mini.misc      | Miscellaneous functions                  | [README](readmes/mini-misc.md)      | [Documentation](doc/mini-misc.txt)      |\n| mini.pick      | Pick anything                            | [README](readmes/mini-pick.md)      | [Documentation](doc/mini-pick.txt)      |\n| mini.sessions  | Session management                       | [README](readmes/mini-sessions.md)  | [Documentation](doc/mini-sessions.txt)  |\n| mini.visits    | Track and reuse file system visits       | [README](readmes/mini-visits.md)    | [Documentation](doc/mini-visits.txt)    |\n\n### Appearance\n\nThese modules improve your Neovim appearance. Start with 'mini.hues', 'mini.icons', and 'mini.statusline'.\n\n| Module           | Description                          | Overview                              | Details                                   |\n|------------------|--------------------------------------|---------------------------------------|-------------------------------------------|\n| mini.animate     | Animate common Neovim actions        | [README](readmes/mini-animate.md)     | [Documentation](doc/mini-animate.txt)     |\n| mini.base16      | Base16 colorscheme creation          | [README](readmes/mini-base16.md)      | [Documentation](doc/mini-base16.txt)      |\n| mini.colors      | Tweak and save any color scheme      | [README](readmes/mini-colors.md)      | [Documentation](doc/mini-colors.txt)      |\n| mini.cursorword  | Autohighlight word under cursor      | [README](readmes/mini-cursorword.md)  | [Documentation](doc/mini-cursorword.txt)  |\n| mini.hipatterns  | Highlight patterns in text           | [README](readmes/mini-hipatterns.md)  | [Documentation](doc/mini-hipatterns.txt)  |\n| mini.hues        | Generate configurable color scheme   | [README](readmes/mini-hues.md)        | [Documentation](doc/mini-hues.txt)        |\n| mini.icons       | Icon provider                        | [README](readmes/mini-icons.md)       | [Documentation](doc/mini-icons.txt)       |\n| mini.indentscope | Visualize and work with indent scope | [README](readmes/mini-indentscope.md) | [Documentation](doc/mini-indentscope.txt) |\n| mini.map         | Window with buffer text overview     | [README](readmes/mini-map.md)         | [Documentation](doc/mini-map.txt)         |\n| mini.notify      | Show notifications                   | [README](readmes/mini-notify.md)      | [Documentation](doc/mini-notify.txt)      |\n| mini.starter     | Start screen                         | [README](readmes/mini-starter.md)     | [Documentation](doc/mini-starter.txt)     |\n| mini.statusline  | Statusline                           | [README](readmes/mini-statusline.md)  | [Documentation](doc/mini-statusline.txt)  |\n| mini.tabline     | Tabline                              | [README](readmes/mini-tabline.md)     | [Documentation](doc/mini-tabline.txt)     |\n| mini.trailspace  | Trailspace (highlight and remove)    | [README](readmes/mini-trailspace.md)  | [Documentation](doc/mini-trailspace.txt)  |\n\n### Other\n\nThese modules don't quite fit in any of the previous categories.\n\n| Module     | Description                | Overview                        | Details                             |\n|------------|----------------------------|---------------------------------|-------------------------------------|\n| mini.doc   | Generate Neovim help files | [README](readmes/mini-doc.md)   | [Documentation](doc/mini-doc.txt)   |\n| mini.fuzzy | Fuzzy matching             | [README](readmes/mini-fuzzy.md) | [Documentation](doc/mini-fuzzy.txt) |\n| mini.test  | Test Neovim plugins        | [README](readmes/mini-test.md)  | [Documentation](doc/mini-test.txt)  |\n\n## General principles\n\n### Design\n\nEach module is designed to solve a particular problem targeting balance between feature-richness (handling as many edge-cases as possible) and simplicity of implementation/support. Granted, not all of them ended up with the same balance, but it is the goal nevertheless.\n\n### Independence\n\nModules are independent of each other and can be run without external dependencies. Although some of them may need dependencies for full experience.\n\n### Structure\n\nEach module is a submodule for a placeholder \"mini\" module. So, for example, \"surround\" module should be referred to as \"mini.surround\".  As later will be explained, this plugin can also be referred to as \"MiniSurround\".\n\n### Setup\n\n- Each module you want to use should be enabled separately with `require(<name of module>).setup({})`. Possibly replace `{}` with your config table or omit altogether to use defaults. You can supply only parts of config, the rest will be inferred from defaults.\n\n- Call to module's `setup()` always creates a global Lua object with coherent camel-case name: `require('mini.surround').setup()` creates `_G.MiniSurround`. This allows for a simpler usage of plugin functionality: instead of `require('mini.surround')` use `MiniSurround` (or manually `:lua MiniSurround.*` in command line); available from `v:lua` like `v:lua.MiniSurround`. Considering this, \"module\" and \"Lua object\" names can be used interchangeably: 'mini.surround' and 'MiniSurround' will mean the same thing.\n\n- Each supplied `config` table is stored in `config` field of global object. Like `MiniSurround.config`.\n\n- Values of `config` which affect runtime activity can be changed on the fly to have effect. For example, `MiniSurround.config.n_lines` can be changed during runtime; but changing `MiniSurround.config.mappings` won't have any effect (as mappings are created once during `setup()`).\n\n- If module works best with some specific non-default option value, it is set during `setup()`. If the value is not essential to module's functionality, it is done only if user or another plugin hasn't set it beforehand (no matter the value).\n\n### Buffer local configuration\n\nEach module can be additionally configured to use certain runtime config settings locally to buffer. See `mini.nvim-buffer-local-config` section in help file for more information.\n\n### Buffer names\n\nAll module-related buffers are named according to the following format: `mini<module-name>://<buffer-number>/<useful-info>` (forward slashes are used on any platform; `<useful-info>` may be empty). This structure allows creating identifiable, reasonably unique, and useful buffer names. For example, 'mini.files' buffers are created per displayed directory/file with names like `minifiles://10/path/to/displayed/directory`.\n\n### Disabling\n\nEach module's core functionality can be disabled globally or locally to buffer. See \"Disabling\" section in module's help page for more details. See `mini.nvim-disabling-recipes` section in main help file for common recipes.\n\n### Silencing\n\nEach module providing non-error feedback (like a reminder to press a key after some idle time in 'mini.ai', 'mini.jump2d', 'mini.surround') can be configured to not do that by setting `config.silent = true` (either inside `setup()` call or on the fly).\n\n### Highlighting\n\nAppearance of module's output is controlled by certain set of highlight groups (see `:h highlight-groups`). By default they usually link to some semantically close built-in highlight group and are ensured to be defined after any color scheme takes effect. Use `:highlight` command or `vim.api.nvim_set_hl()` Lua function to customize highlighting. To see a more calibrated look, use 'mini.hues', 'mini.base16', or plugin's color scheme.\n\n### Stability\n\nEach module upon release is considered to be relatively stable: both in terms of setup and functionality. Any non-bugfix backward-incompatible change will be released gradually as much as possible.\n\n### Not filetype and language specific\n\nIncluding functionality which needs several filetype/language specific implementations is an explicit no-goal of this project. This is mostly due to the potential increase in maintenance to keep implementation up to date. However, any part which might need filetype/language specific tuning should be designed to allow it by letting user set proper buffer options and/or local configuration.\n\n## Plugin color schemes\n\nThis plugin comes with several color schemes (all have both dark and light variants). Activate any of them as a regular `colorscheme` (like `:colorscheme miniwinter` or `vim.cmd.colorscheme('miniwinter')`).\n\n- Based on ['mini.hues'](readmes/mini-hues.md) (recommended):\n    - `miniwinter`: \"icy winter\" palette with azure background.\n    - `minispring`: \"blooming spring\" palette with green background.\n    - `minisummer`: \"hot summer\" palette with brown/yellow background.\n    - `miniautumn`: \"cooling autumn\" palette with purple background.\n    - `randomhue`: random background and foreground of the same hue with medium saturation.\n\n    You can see how they look in ['mini.hues' README](readmes/mini-hues.md#bundled-color-schemes).\n\n- Based on ['mini.base16'](readmes/mini-base16.md):\n    - `minicyan`: cyan and grey main colors with medium contrast and saturation palette.\n    - `minischeme`: blue and yellow main colors with high contrast and saturation palette.\n\n    You can see how they look in ['mini.base16' README](readmes/mini-base16.md#demo).\n\n## Planned modules\n\nThis is the list of modules I currently intend to implement eventually (as my free time and dedication will allow), in alphabetical order:\n\n- 'mini.abbrev' - helper to manage/setup Insert mode abbreviations.\n- 'mini.cycle' - cycle through alternatives with pre-defined rules. Something like [monaqa/dial.nvim](https://github.com/monaqa/dial.nvim) and [AndrewRadev/switch.vim](https://github.com/AndrewRadev/switch.vim)\n- 'mini.folds' - more capable and user-friendly folds.\n- 'mini.repl' - extendable wrapper for REPLs with built-in support for R, Python, Julia, and maybe (just maybe) some AI tools.\n- 'mini.sendtext' - send text between buffers. In particular between regular and built-in terminal buffers.\n- 'mini.statuscolumn' - customizable 'statuscolumn'.\n- 'mini.terminals' - coherently manage interactive terminal buffers. Something like [kassio/neoterm](https://github.com/kassio/neoterm). Might also incorporate functionality to asynchronously run code in shell with post-processed results.\n- 'mini.quickfix' - more capable and user-friendly quickfix list. Possibly with preview and inline editing for search-and-replace workflow.\n- 'mini.windows' - window manager. Interactive picker, layout organizer, and maybe more.\n"
  },
  {
    "path": "TESTING.md",
    "content": "# How to test with 'mini.test'\n\nWriting tests for Neovim Lua plugin is hard. Writing good tests for Neovim Lua plugin is even harder. The 'mini.test' module is designed to make it reasonably easier while still allowing lots of flexibility. It deliberately favors a more verbose and program-like style of writing tests, opposite to \"human readable, DSL like\" approach of [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim) (\"busted-style testing\" from [Olivine-Labs/busted](https://github.com/Olivine-Labs/busted)). Although the latter is also possible.\n\nThis file is intended as a hands-on introduction to 'mini.test' with examples. For more details, see [its documentation](doc/mini-test.txt) and tests of this plugin's modules.\n\nGeneral approach of writing test files:\n\n- Organize tests in separate Lua files.\n- Each file should be associated with a test set table (output of `MiniTest.new_set()`). Recommended approach is to create it manually in each test file and then return it.\n- Each test action should be defined in separate function assign to an entry of test set.\n- It is strongly encouraged to use custom Neovim processes to do actual testing inside test action. See [Using child process](#using-child-process).\n\n**NOTES**:\n\n- All commands are assumed to be executed with current working directory being a root of your Neovim plugin project. That is both for shell and Neovim commands.\n- All paths are assumed to be relative to current working directory.\n\n## Example plugin\n\nIn this file we will be testing 'hello_lines' plugin (once some basic concepts are introduced). It will have functionality to add prefix 'Hello ' to lines implemented in a single file 'lua/hello_lines/init.lua':\n\n<details><summary>'lua/hello_lines/init.lua'</summary>\n\n```lua\nlocal M = {}\n\n--- Prepend 'Hello ' to every element\n---@param lines table Array. Default: { 'world' }.\n---@return table Array of strings.\nM.compute = function(lines)\n  lines = lines or { 'world' }\n  return vim.tbl_map(function(x) return 'Hello ' .. tostring(x) end, lines)\nend\n\nlocal ns_id = vim.api.nvim_create_namespace('hello_lines')\n\n--- Set lines with highlighted 'Hello ' prefix\n---@param buf_id number Buffer handle where lines should be set. Default: 0.\n---@param lines table Array. Default: { 'world' }.\nM.set_lines = function(buf_id, lines)\n  buf_id = buf_id or 0\n  lines = lines or { 'world' }\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n  vim.api.nvim_buf_set_lines(buf_id or 0, 0, -1, true, M.compute(lines))\n  for i = 1, #lines do\n    local extmark_opts = { end_row = i - 1, end_col = 5, hl_group = 'Special' }\n    vim.api.nvim_buf_set_extmark(buf_id, ns_id, i - 1, 0, extmark_opts)\n  end\nend\n\nreturn M\n```\n\n</details>\n\n## Quick demo\n\nHere is a quick demo of how tests with 'mini.test' look like:\n\n<details><summary>'tests/test_hello_lines.lua'</summary>\n\n```lua\n-- Define helper aliases\nlocal new_set = MiniTest.new_set\nlocal expect, eq = MiniTest.expect, MiniTest.expect.equality\n\n-- Create (but not start) child Neovim object\nlocal child = MiniTest.new_child_neovim()\n\n-- Define main test set of this file\nlocal T = new_set({\n  -- Register hooks\n  hooks = {\n    -- This will be executed before every (even nested) case\n    pre_case = function()\n      -- Restart child process with custom 'init.lua' script\n      child.restart({ '-u', 'scripts/minimal_init.lua' })\n      -- Load tested plugin\n      child.lua([[M = require('hello_lines')]])\n    end,\n    -- This will be executed one after all tests from this set are finished\n    post_once = child.stop,\n  },\n})\n\n-- Test set fields define nested structure\nT['compute()'] = new_set()\n\n-- Define test action as callable field of test set.\n-- If it produces error - test fails.\nT['compute()']['works'] = function()\n  -- Execute Lua code inside child process, get its result and compare with\n  -- expected result\n  eq(child.lua_get([[M.compute({'a', 'b'})]]), { 'Hello a', 'Hello b' })\nend\n\nT['compute()']['uses correct defaults'] = function()\n  eq(child.lua_get([[M.compute()]]), { 'Hello world' })\nend\n\n-- Make parametrized tests. This will create three copies of each case\nT['set_lines()'] = new_set({ parametrize = { {}, { 0, { 'a' } }, { 0, { 1, 2, 3 } } } })\n\n-- Use arguments from test parametrization\nT['set_lines()']['works'] = function(buf_id, lines)\n  -- Directly modify some options to make better test\n  child.o.lines, child.o.columns = 10, 20\n  child.bo.readonly = false\n\n  -- Execute Lua code without returning value\n  child.lua('M.set_lines(...)', { buf_id, lines })\n\n  -- Test screen state. On first run it will automatically create reference\n  -- screenshots with text and look information in predefined location. On\n  -- later runs it will compare current screenshot with reference. Will throw\n  -- informative error with helpful information if they don't match exactly.\n  expect.reference_screenshot(child.get_screenshot())\nend\n\n-- Return test set which will be collected and execute inside `MiniTest.run()`\nreturn T\n```\n\n</details>\n\n## File organization\n\nIt might be a bit overwhelming. It actually is for most of the people. However, it should be done once and then you rarely need to touch it.\n\nOverview of full file structure used in for testing 'hello_lines' plugin:\n\n```\n.\n├── deps\n│   └── mini.nvim # Mandatory\n├── lua\n│   └── hello_lines\n│       └── init.lua # Mandatory\n├── Makefile # Recommended\n├── scripts\n│   ├── minimal_init.lua # Mandatory\n│   └── minitest.lua # Recommended\n└── tests\n    └── test_hello_lines.lua # Mandatory\n```\n\nTo write tests, you'll need these files:\n\nMandatory:\n\n- **Your Lua plugin in 'lua' directory**. Here we will be testing 'hello_lines' plugin.\n\n- **Test files**. By default they should be Lua files located in 'tests/' directory and named with 'test_' prefix. For example, we will write everything in 'test_hello_lines.lua'. It is usually a good idea to follow this template (will be assumed for the rest of this file):\n\n    <details><summary>Template for test files</summary>\n\n    ```lua\n    local new_set = MiniTest.new_set\n    local expect, eq = MiniTest.expect, MiniTest.expect.equality\n\n    local T = new_set()\n\n    -- Actual tests definitions will go here\n\n    return T\n    ```\n\n    </details>\n\n- **'mini.nvim' dependency**. It is needed to use its 'mini.test' module. Proposed way to store it is in 'deps/mini.nvim' directory. Create it with `git`:\n\n    ```bash\n    mkdir -p deps\n    git clone --filter=blob:none https://github.com/nvim-mini/mini.nvim deps/mini.nvim\n    ```\n\n- **Manual Neovim startup file** (a.k.a 'init.lua') with proposed path 'scripts/minimal_init.lua'. It will be used to ensure that Neovim processes can recognize your tested plugin and 'mini.nvim' dependency. Proposed minimal content:\n\n    <details><summary>'scripts/minimal_init.lua'</summary>\n\n    ```lua\n    -- Add current directory to 'runtimepath' to be able to use 'lua' files\n    vim.cmd([[let &rtp.=','.getcwd()]])\n\n    -- Set up 'mini.test' only when calling headless Neovim (like with `make test`)\n    if #vim.api.nvim_list_uis() == 0 then\n      -- Add 'mini.nvim' to 'runtimepath' to be able to use 'mini.test'\n      -- Assumed that 'mini.nvim' is stored in 'deps/mini.nvim'\n      vim.cmd('set rtp+=deps/mini.nvim')\n\n      -- Set up 'mini.test'\n      require('mini.test').setup()\n    end\n    ```\n\n    </details>\n\nRecommended:\n\n- **Makefile**. In order to simplify running tests from shell and inside Continuous Integration services (like Github Actions), it is recommended to define Makefile. It will define steps for running tests. Proposed template:\n\n    <details><summary>Template for Makefile</summary>\n\n    ```\n    # Run all test files\n    test: deps/mini.nvim\n    \tnvim --headless --noplugin -u ./scripts/minimal_init.lua -c \"lua MiniTest.run()\"\n\n    # Run test from file at `$FILE` environment variable\n    test_file: deps/mini.nvim\n    \tnvim --headless --noplugin -u ./scripts/minimal_init.lua -c \"lua MiniTest.run_file('$(FILE)')\"\n\n    # Download 'mini.nvim' to use its 'mini.test' testing module\n    deps/mini.nvim:\n    \t@mkdir -p deps\n    \tgit clone --filter=blob:none https://github.com/nvim-mini/mini.nvim $@\n    ```\n\n    </details>\n\n- **'mini.test' script** at 'scripts/minitest.lua'. Use it to customize what is tested (which files, etc.) and how. Usually not needed, but otherwise should have some variant of a call to `MiniTest.run()`.\n\n## Running tests\n\nThe 'mini.test' module out of the box supports two major ways of running tests:\n\n- **Interactive**. All test files will be run directly inside current Neovim session. This proved to be very useful for debugging while writing tests. To run tests, simply execute `:lua MiniTest.run()` / `:lua MiniTest.run_file()` / `:lua MiniTest.run_at_location()` (assuming, you already have 'mini.test' set up with `require('mini.test').setup()`). With default configuration this will result into floating window with information about results of test execution. Press `q` to close it. **Note**: Be careful though, as it might affect your current setup. To avoid this, [use child processes](#using-child-process) inside tests.\n- **Headless** (from shell). Start headless Neovim process with proper startup file and execute `lua MiniTest.run()`. Assuming full file organization from previous section, this can be achieved with `make test`. This will show information about results of test execution directly in shell.\n\n## Basics\n\nThese sections will show some basic capabilities of 'mini.test' and how to use them. In all examples code blocks represent some whole test file (like 'tests/test_basics.lua').\n\n### First test\n\nA test is defined as function assigned to a field of test set. If it throws error, test has failed. Test file should return single test set. Here is an example:\n\n```lua\nlocal T = MiniTest.new_set()\n\nT['works'] = function()\n  local x = 1 + 1\n  if x ~= 2 then\n    error('`x` is not equal to 2')\n  end\nend\n\nreturn T\n```\n\nWriting `if .. error() .. end` is too tiresome. That is why 'mini.test' comes with very minimal but usually quite enough set of *expectations*: `MiniTest.expect`. They display the intended expectation between objects and will throw error with informative message if it doesn't hold. Here is a rewritten previous example:\n\n```lua\nlocal T = MiniTest.new_set()\n\nT['works'] = function()\n  local x = 1 + 1\n  MiniTest.expect.equality(x, 2)\nend\n\nreturn T\n```\n\nTest sets can be nested. This will be useful in combination with [hooks](#hooks) and [parametrization](#test-parametrization):\n\n```lua\nlocal T = MiniTest.new_set()\n\nT['big scope'] = new_set()\n\nT['big scope']['works'] = function()\n  local x = 1 + 1\n  MiniTest.expect.equality(x, 2)\nend\n\nT['big scope']['also works'] = function()\n  local x = 2 + 2\n  MiniTest.expect.equality(x, 4)\nend\n\nT['out of scope'] = function()\n  local x = 3 + 3\n  MiniTest.expect.equality(x, 6)\nend\n\nreturn T\n```\n\n**NOTE**: 'mini.test' supports emulation of busted-style testing by default. So previous example can be written like this:\n\n```lua\ndescribe('big scope', function()\n  it('works', function()\n    local x = 1 + 1\n    MiniTest.expect.equality(x, 2)\n  end)\n\n  it('also works', function()\n    local x = 2 + 2\n    MiniTest.expect.equality(x, 4)\n  end)\nend)\n\nit('out of scope', function()\n  local x = 3 + 3\n  MiniTest.expect.equality(x, 6)\nend)\n\n-- NOTE: when using this style, no test set should be returned\n```\n\nAlthough this is possible, the rest of this file will use a recommended test set approach.\n\n### Builtin expectations\n\nThese four builtin expectations are the ones used most commonly:\n\n```lua\nlocal T = MiniTest.new_set()\nlocal expect, eq = MiniTest.expect, MiniTest.expect.equality\n\nlocal x = 1 + 1\n\n-- This is so frequently used that having short alias proved useful\nT['expect.equality'] = function()\n  eq(x, 2)\nend\n\nT['expect.no_equality'] = function()\n  expect.no_equality(x, 1)\nend\n\nT['expect.error'] = function()\n  -- This expectation will pass because function will throw an error\n  expect.error(function()\n    if x == 2 then error('Deliberate error') end\n  end)\nend\n\nT['expect.no_error'] = function()\n  -- This expectation will pass because function will *not* throw an error\n  expect.no_error(function()\n    if x ~= 2 then error('This should not be thrown') end\n  end)\nend\n\nreturn T\n```\n\n### Writing custom expectation\n\nAlthough you can use `if ... error() ... end` approach, there is `MiniTest.new_expectation()` to simplify this process for some repetitive expectation. Here is an example used in this plugin:\n\n```lua\nlocal T = MiniTest.new_set()\n\nlocal expect_match = MiniTest.new_expectation(\n  -- Expectation subject\n  'string matching',\n  -- Predicate\n  function(str, pattern) return str:find(pattern) ~= nil end,\n  -- Fail context\n  function(str, pattern)\n    return string.format('Pattern: %s\\nObserved string: %s', vim.inspect(pattern), str)\n  end\n)\n\nT['string matching'] = function()\n  local x = 'abcd'\n  -- This will pass\n  expect_match(x, '^a')\n\n  -- This will fail\n  expect_match(x, 'x')\nend\n\nreturn T\n```\n\nExecuting this content from file 'tests/test_basics.lua' will fail with the following message:\n\n```\nFAIL in \"tests/test_basics.lua | string matching\":\n  Failed expectation for string matching.\n  Pattern: \"x\"\n  Observed string: abcd\n  Traceback:\n    tests/test_basics.lua:20\n```\n\n### Hooks\n\nHooks are functions that will be called without arguments at predefined stages of test execution. They are defined for a test set. There are four types of hooks:\n\n- **pre_once** - executed before first (filtered) node.\n- **pre_case** - executed before each case (even nested).\n- **post_case** - executed after each case (even nested).\n- **post_once** - executed after last (filtered) node.\n\nExample:\n\n```lua\nlocal new_set = MiniTest.new_set\nlocal expect, eq = MiniTest.expect, MiniTest.expect.equality\n\nlocal T = new_set()\n\nlocal n = 0\nlocal increase_n = function() n = n + 1 end\n\nT['hooks'] = new_set({\n  hooks = { pre_once = increase_n, pre_case = increase_n, post_case = increase_n, post_once = increase_n },\n})\n\nT['hooks']['work'] = function()\n  -- `n` will be increased twice: in `pre_once` and `pre_case`\n  eq(n, 2)\nend\n\nT['hooks']['work again'] = function()\n  -- `n` will be increased twice: in `post_case` from previous case and\n  -- `pre_case` before this one\n  eq(n, 4)\nend\n\nT['after hooks set'] = function()\n  -- `n` will be again increased twice: in `post_case` from previous case and\n  -- `post_once` after last case in T['hooks'] test set\n  eq(n, 6)\nend\n\nreturn T\n```\n\n### Test parametrization\n\nOne of the distinctive features of 'mini.test' is ability to leverage test parametrization. As hooks, it is a feature of test set.\n\nExample of simple parametrization:\n\n```lua\nlocal new_set = MiniTest.new_set\nlocal eq = MiniTest.expect.equality\n\nlocal T = new_set()\n\n-- Each parameter should be an array to allow parametrizing multiple arguments\nT['parametrize'] = new_set({ parametrize = { { 1 }, { 2 } } })\n\n-- This will result into two cases. First will fail.\nT['parametrize']['works'] = function(x)\n  eq(x, 2)\nend\n\n-- Parametrization can be nested. Cases are \"multiplied\" with every combination\n-- of parameters.\nT['parametrize']['nested'] = new_set({ parametrize = { { '1' }, { '2' } } })\n\n-- This will result into four cases. Two of them will fail.\nT['parametrize']['nested']['works'] = function(x, y)\n  eq(tostring(x), y)\nend\n\n-- Parametrizing multiple arguments\nT['parametrize multiple arguments'] = new_set({ parametrize = { { 1, 1 }, { 2, 2 } } })\n\n-- This will result into two cases. Both will pass.\nT['parametrize multiple arguments']['works'] = function(x, y)\n  eq(x, y)\nend\n\nreturn T\n```\n\n### Retry\n\nSome tests can be inherently flaky (can randomly fail even if its tested feature is correct). For example, testing that sequence of events is executed with correct delay between each other. Such tests can work reliably on fast machines, but can spuriously fail on slow ones (like during Continuous Integrations checks) while underlying feature is correct.\n\nTo reduce flakiness, there is a feature of test set called `n_retry`: a maximum number of times to retry each its test case until success.\n\nExample of how it can be used:\n\n```lua\nlocal new_set = MiniTest.new_set\n\nlocal T = new_set()\n\n-- Each case will be attempted until first success at most 5 times\nT['n_retry'] = new_set({ n_retry = 5 })\n\n-- With default `n_retry = 1` this case will fail 1 out of 2 runs.\n-- With `n_retry = 5` this case will fail 1 out of 32 runs.\nT['n_retry']['case'] = function()\n  math.randomseed(vim.loop.hrtime())\n  assert(math.random() < 0.5)\nend\n\nreturn T\n```\n\n### Runtime access to current cases\n\nThere is `MiniTest.current` table containing information about \"current\" test cases. It has `all_cases` and `case` fields with all currently executed tests and *the* current case.\n\nTest case is a single unit of sequential test execution. It contains all information needed to execute test case along with data about its execution. Example:\n\n```lua\nlocal new_set = MiniTest.new_set\nlocal eq = MiniTest.expect.equality\n\nlocal T = new_set()\n\nT['MiniTest.current.all_cases'] = function()\n  -- A useful hack: show runtime data with expecting it to be something else\n  eq(MiniTest.current.all_cases, 0)\nend\n\nT['MiniTest.current.case'] = function()\n  eq(MiniTest.current.case, 0)\nend\n\nreturn T\n```\n\nThis will result into following lengthy fails:\n\n<details><summary>Fail information</summary>\n\n```\nFAIL in \"tests/test_basics.lua | MiniTest.current.all_cases\":\n  Failed expectation for equality.\n  Left: { {\n      args = {},\n      data = {},\n      desc = { \"tests/test_basics.lua\", \"MiniTest.current.all_cases\" },\n      exec = {\n        fails = {},\n        notes = {},\n        state = \"Executing test\"\n      },\n      hooks = {\n        post = {},\n        pre = {}\n      },\n      test = <function 1>\n    }, {\n      args = {},\n      data = {},\n      desc = { \"tests/test_basics.lua\", \"MiniTest.current.case\" },\n      hooks = {\n        post = {},\n        pre = {}\n      },\n      test = <function 2>\n    } }\n  Right: 0\n  Traceback:\n    tests/test_basics.lua:8\n\nFAIL in \"tests/test_basics.lua | MiniTest.current.case\":\n  Failed expectation for equality.\n  Left: {\n    args = {},\n    data = {},\n    desc = { \"tests/test_basics.lua\", \"MiniTest.current.case\" },\n    exec = {\n      fails = {},\n      notes = {},\n      state = \"Executing test\"\n    },\n    hooks = {\n      post = {},\n      pre = {}\n    },\n    test = <function 1>\n  }\n  Right: 0\n  Traceback:\n    tests/test_basics.lua:12\n```\n\n</details>\n\n### Case helpers\n\nThere are some functions intended to help writing more robust cases: `skip()`, `finally()`, and `add_note()`. The `MiniTest.current` table contains useful information about the current state of tests execution.\n\nExample:\n\n```lua\nlocal T = MiniTest.new_set()\n\n-- `MiniTest.skip()` allows skipping rest of test execution while giving an\n-- informative note. This test will pass with notes.\nT['skip()'] = function()\n  if 1 + 1 == 2 then\n    MiniTest.skip('Apparently, 1 + 1 is 2')\n  end\n  error('1 + 1 is not 2')\nend\n\n-- `MiniTest.add_note()` allows adding notes. Final state will have\n-- \"with notes\" suffix.\nT['add_note()'] = function()\n  MiniTest.add_note('This test is not important.')\n  error('Custom error.')\nend\n\n-- `MiniTest.finally()` allows registering some function to be executed after\n-- this case is finished executing (with or without an error).\nT['finally()'] = function()\n  -- Add note only if test fails\n  MiniTest.finally(function()\n    if #MiniTest.current.case.exec.fails > 0 then\n      MiniTest.add_note('This test is flaky.')\n    end\n  end)\n  error('Expected error from time to time')\nend\n\nreturn T\n```\n\nThis will result into following messages:\n\n```\nNOTE in \"tests/test_basics.lua | skip()\": Apparently, 1 + 1 is 2\n\nFAIL in \"tests/test_basics.lua | add_note()\": tests/test_basics.lua:16: Custom error.\nNOTE in \"tests/test_basics.lua | add_note()\": This test is not important.\n\nFAIL in \"tests/test_basics.lua | finally()\": tests/test_basics.lua:28: Expected error from time to time\nNOTE in \"tests/test_basics.lua | finally()\": This test is flaky.\n```\n\n## Customizing test run\n\nTest run consists from two stages:\n\n- **Collection**. It will source each appropriate file (customizable), combine all test sets into single test set, convert it from hierarchical to sequential form (array of test cases), and filter cases based on customizable predicate.\n- **Execution**. It will safely execute array of test cases (with each pre-hooks, test action, post-hooks) one after another in scheduled asynchronous fashion while collecting information about how it went and calling customizable reporter methods.\n\nAll configuration goes into `opts` argument of `MiniTest.run()`.\n\n### Collection: custom files and filter\n\nYou can customize which files will be sourced and which cases will be later executed. Example:\n\n```lua\nlocal new_set = MiniTest.new_set\n\nlocal T = new_set()\n\n-- Use `data` field to pass custom information for easier test management\nT['fast'] = new_set({ data = { type = 'fast' } })\nT['fast']['first test'] = function() end\nT['fast']['second test'] = function() end\n\nT['slow'] = new_set({ data = { type = 'slow' } })\nT['slow']['first test'] = function() vim.loop.sleep(1000) end\nT['slow']['second test'] = function() vim.loop.sleep(1000) end\n\nreturn T\n```\n\nYou can run only this file ('tests/test_basics.lua') and only \"fast\" cases with this call:\n\n```lua\nMiniTest.run({\n  collect = {\n    find_files = function() return { 'tests/test_basics.lua' } end,\n    filter_cases = function(case) return case.data.type == 'fast' end,\n  }\n})\n```\n\n### Execution: custom reporter and stop on first error\n\nYou can customize execution of test cases with custom reporter (how test results are displayed in real time) and whether to stop execution after the first test case fail/error. Execution doesn't result into any output, instead it updates `MiniTest.current.all_cases` in place: each case gets an `exec` field with information about how its execution went.\n\nExample of showing status summary table in the command line after everything is finished:\n\n```lua\nlocal reporter = {\n  -- Other used methods are `start(cases)` and `update(case_num)`\n  finish = function()\n    local summary = {}\n    for _, c in ipairs(MiniTest.current.all_cases) do\n      local state = c.exec.state\n      summary[state] = (summary[state] or 0) + 1\n    end\n\n    print(vim.inspect(summary, { newline = ' ', indent = '' }))\n  end,\n}\n\nMiniTest.run({ execute = { reporter = reporter } })\n```\n\n## Using child process\n\nMain feature of 'mini.test' which makes it different from other Lua testing frameworks is its design towards **custom usage of child Neovim process inside tests**. Ultimately, each test should be done with fresh Neovim process initialized with bare minimum setup (like allowing to load your plugin). To make this easier, there is a dedicated function `MiniTest.new_child_neovim()`. It returns an object with many useful helper methods, like for start/stop/restart, redirected execution (write code in current process, it gets executed in child one), emulating typing keys, **testing screen state**, etc.\n\n### Start/stop/restart\n\nYou can start/stop/restart child process associated with this child Neovim object. Current (from which testing is initiated) and child Neovim processes can \"talk\" to each through RPC messages (see `:h RPC`). It means you can programmatically execute code inside child process, get its output inside current process, and test if it meets your expectation. Child process is headless but fully functioning process which allows you to test things such as extmarks, floating windows, etc.\n\nAlthough this approach proved to be useful and efficient, it is not ideal. Here are some limitations:\n  - Due to current RPC protocol implementation functions and userdata can't be used in both input and output with child process. Indicator of this issue is a `Cannot convert given lua type` error. Usual solution is to move some logic on the side of child process, like create and use global functions (note that they will be \"forgotten\" after next restart).\n  - Sometimes hanging process will occur: it stops executing without any output. Most of the time it is because Neovim process is \"blocked\", i.e. it waits for user input and won't return from other call. Common causes are active hit-enter-prompt (solution: increase prompt height to a bigger value) or Operator-pending mode (solution: exit it). To mitigate this experience, most helper methods will throw an error if they can deduce that immediate execution will lead to hanging state.\n\nHere is recommended setup for managing child processes. It will make fresh Neovim process before every test case:\n\n```lua\nlocal child = MiniTest.new_child_neovim()\n\nlocal T = MiniTest.new_set({\n  hooks = {\n    pre_case = function()\n      -- Restart child process with custom 'init.lua' script\n      child.restart({ '-u', 'scripts/minimal_init.lua' })\n      -- Load tested plugin\n      child.lua([[M = require('hello_lines')]])\n    end,\n    -- Stop once all test cases are finished\n    post_once = child.stop,\n  },\n})\n\n-- Define some tests here\n\nreturn T\n```\n\n### Executing Lua code\n\nPrevious section already demonstrated that there is a `child.lua()` method. It will execute arbitrary Lua code in the form of a single string. This is basically a wrapper for `vim.api.nvim_exec_lua()`. There is also a convenience wrapper `child.lua_get()` which is essentially a `child.lua('return ' .. s, ...)`. Examples:\n\n```lua\nlocal eq = MiniTest.expect.equality\n\nlocal child = MiniTest.new_child_neovim()\n\nlocal T = MiniTest.new_set({\n  hooks = {\n    pre_case = function()\n      child.restart({ '-u', 'scripts/minimal_init.lua' })\n      child.lua([[M = require('hello_lines')]])\n    end,\n    post_once = child.stop,\n  },\n})\n\nT['lua()'] = MiniTest.new_set()\n\nT['lua()']['works'] = function()\n  child.lua('_G.n = 0; _G.n = _G.n + 1')\n  eq(child.lua('return _G.n'), 1)\nend\n\nT['lua()']['can use tested plugin'] = function()\n  eq(child.lua('return M.compute()'), { 'Hello world' })\n  eq(child.lua([[return M.compute({'a', 'b'})]]), { 'Hello a', 'Hello b' })\nend\n\nT['lua_get()'] = function()\n  child.lua('_G.n = 0')\n  eq(child.lua_get('_G.n'), child.lua('return _G.n'))\nend\n\nreturn T\n```\n\n### Managing Neovim options and state\n\nAlthough ability to execute arbitrary Lua code is technically enough to write any tests, it gets cumbersome very quickly due it using only string input. That is why there are many convenience helpers with the same idea: write code inside current Neovim process that will be automatically executed same way in child process. Here is the showcase:\n\n```lua\nlocal new_set = MiniTest.new_set\nlocal eq = MiniTest.expect.equality\n\nlocal child = MiniTest.new_child_neovim()\n\nlocal T = MiniTest.new_set({\n  hooks = {\n    pre_case = function()\n      child.restart({ '-u', 'scripts/minimal_init.lua' })\n      child.lua([[M = require('hello_lines')]])\n    end,\n    post_once = child.stop,\n  },\n})\n\n-- These methods will \"redirect\" execution to child through `vim.rpcrequest()`\n-- and `vim.rpcnotify()` respectively. Any call `child.api.xxx(...)` returns\n-- the output of `vim.api.xxx(...)` executed inside child process.\nT['api()/api_notify()'] = function()\n  -- Set option. For some reason, first buffer is 'readonly' which leads to\n  -- high delay in test execution\n  child.api.nvim_set_option_value('readonly', false, { buf = 0 })\n\n  -- Set all lines\n  child.api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa' })\n\n  -- Get all lines and test with expected ones\n  eq(child.api.nvim_buf_get_lines(0, 0, -1, true), { 'aaa' })\nend\n\n-- Execute Vimscript with or without capturing its output\nT['cmd()/cmd()'] = function()\n  child.cmd('hi Comment guifg=#aaaaaa')\n  eq(child.cmd_capture('hi Comment'), 'Comment        xxx guifg=#aaaaaa')\nend\n\n-- There are redirection tables for most of the main Neovim functionality\nT['various redirection tables with methods'] = function()\n  eq(child.fn.fnamemodify('hello_lines.lua', ':t:r'), 'hello_lines')\n  eq(child.loop.hrtime() > 0, true)\n  eq(child.lsp.get_clients(), {})\n\n  -- And more\nend\n\n-- There are redirection tables for scoped (buffer, window, etc.) variables\n-- You can use them to both set and get values\nT['redirection tables for variables'] = function()\n  child.b.aaa = true\n  eq(child.b.aaa, true)\n  eq(child.b.aaa, child.lua_get('vim.b.aaa'))\nend\n\n-- There are redirection tables for scoped (buffer, window, etc.) options\n-- You can use them to both set and get values\nT['redirection tables for options'] = function()\n  child.o.lines, child.o.columns = 5, 12\n  eq(child.o.lines, 5)\n  eq({ child.o.lines, child.o.columns }, child.lua_get('{ vim.o.lines, vim.o.columns }'))\nend\n\nreturn T\n```\n\n### Emulate typing keys\n\nVery important part of testing is emulating user typing keys. There is a special `child.type_keys()` helper method for that. Examples:\n\n```lua\nlocal eq = MiniTest.expect.equality\n\nlocal child = MiniTest.new_child_neovim()\n\nlocal T = MiniTest.new_set({\n  hooks = {\n    pre_case = function()\n      child.restart({ '-u', 'scripts/minimal_init.lua' })\n      child.bo.readonly = false\n      child.lua([[M = require('hello_lines')]])\n    end,\n    post_once = child.stop,\n  },\n})\n\nlocal get_lines = function() return child.api.nvim_buf_get_lines(0, 0, -1, true) end\n\nT['type_keys()'] = MiniTest.new_set()\n\nT['type_keys()']['works'] = function()\n  -- It can take one string\n  child.type_keys('iabcde<Esc>')\n  eq(get_lines(), { 'abcde' })\n  eq(child.fn.mode(), 'n')\n\n  -- Or several strings which improves readability\n  child.type_keys('cc', 'fghij', '<Esc>')\n  eq(get_lines(), { 'fghij' })\n\n  -- Or tables of strings (possibly nested)\n  child.type_keys({ 'cc', { 'j', 'k', 'l', 'm', 'n' } })\n  eq(get_lines(), { 'jklmn' })\nend\n\nT['type_keys()']['allows custom delay'] = function()\n  -- This adds delay of 500 ms after each supplied string (three times here)\n  child.type_keys(500, 'i', 'abcde', '<Esc>')\n  eq(get_lines(), { 'abcde' })\nend\n\nreturn T\n```\n\n### Test screen state with screenshots\n\nOne of the main difficulties in testing Neovim plugins is verifying that something is actually displayed in the way you intend. Like general highlighting, statusline, tabline, sign column, extmarks, etc. Testing screen state with screenshots makes this a lot easier. There is a `child.get_screenshot()` method which basically calls `screenstring()` (`:h screenstring()`) and `screenattr()` (`:h screenattr()`) for every visible cell (row from 1 to 'lines' option, column from 1 to 'columns' option). It then returns screenshot with two layers:\n\n- `text` - \"2d array\" (row-column) of single characters displayed at particular cells.\n- `attr` - \"2d array\" (row-column) of symbols representing how text is displayed (basically, \"coded\" appearance/highlighting). They should be used only in relation to each other: same/different symbols for two cells mean same/different visual appearance. Note: there will be false positives if there are more than 94 different attribute values. To make output more portable and visually useful, outputs of `screenattr()` are coded with single character symbols.\n\nCouple of caveats:\n\n- As is apparent from use of `screenattr()`, these screenshots **can't tell how exactly cell is highlighted**, only **if two cells are highlighted the same**. This is due to the currently lacking functionality in Neovim itself. This might change in the future.\n\nTo help manage testing screen state, there is a special `MiniTest.expect.reference_screenshot(screenshot, path, opts)` method. It takes screenshot table along with optional path of where to save this screenshot (if not supplied, inferred from test case description and put in 'tests/screenshots' directory). On first run it will automatically create reference screenshot at `path`. On later runs it will compare current screenshot with reference. Will throw informative error with helpful information if they don't match exactly.\n\nExample:\n\n```lua\nlocal expect = MiniTest.expect\n\nlocal child = MiniTest.new_child_neovim()\n\nlocal T = MiniTest.new_set({\n  hooks = {\n    pre_case = function()\n      child.restart({ '-u', 'scripts/minimal_init.lua' })\n      child.bo.readonly = false\n      child.lua([[M = require('hello_lines')]])\n    end,\n    post_once = child.stop,\n  },\n})\n\nT['set_lines()'] = MiniTest.new_set({ parametrize = { {}, { 0, { 'a' } }, { 0, { 1, 2, 3 } } } })\n\nT['set_lines()']['works'] = function(buf_id, lines)\n  child.o.lines, child.o.columns = 10, 15\n  child.lua('M.set_lines(...)', { buf_id, lines })\n  expect.reference_screenshot(child.get_screenshot())\nend\n\nreturn T\n```\n\nThis will result into three files in 'tests/screenshots' with names containing test case description along with supplied arguments. Here is example reference screenshot for `{ 0, { 1, 2, 3 } }` arguments (line numbers and ruler for columns is added as file specification to make it easier to find differences between two screenshots):\n\n```\n--|---------|-----\n01|Hello 1        \n02|Hello 2        \n03|Hello 3        \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|<e] [+] 1,1 All\n10|               \n\n--|---------|-----\n01|000001111111111\n02|000001111111111\n03|000001111111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n```\n\nTo update already existing screenshot either delete the corresponding screenshot file and rerun test case or temporarily add `{ force = true }` option to `reference_screenshot()` to force updating the screenshot file.\n\n## General tips\n\n- Create a 'tests/helpers.lua' file with code that can be useful in multiple files. It can have \"monkey-patched\" versions of 'mini.test' functions. Example:\n\n```lua\nlocal Helpers = {}\n\nHelpers.new_child_neovim = function()\n  local child = MiniTest.new_child_neovim()\n\n  child.setup = function()\n    child.restart({'-u', 'scripts/minimal_init.lua'})\n    child.bo.readonly = false\n    child.lua([[M = require('hello_lines')]])\n  end\n\n  return child\nend\n\nreturn Helpers\n```\n\n- Write aliases for commonly used functions at top of the file. It will make your life a little bit easier and usually will lead to more readable tests. Example:\n\n```lua\n-- Some code setting up `child`\nlocal set_lines = function(lines) child.api.nvim_buf_set_lines(0, 0, -1, true, lines) end\n```\n\n- When working with automatically named screenshots, beware of the following caveats:\n    - Some systems are case insensitive (like usually Windows and MacOS). So having two different file names which are the same ignoring case will introduce problems for users to properly install plugin.\n    - Some system setups have restrictions on full path length (like 260 bytes on some Git+Windows combinations) or file name length (like 255 bytes on ext4 Windows partitions and 143 bytes on eCryptfs Linux partitions). Restriction on full path is hard to accommodate for (apart from limiting file name size to some reasonable number), but trying to not have file names longer than 143 bytes (by having shorter test case names) should be reasonable.\n\n- To make reading strings that contain Lua code easier (for `child.lua` and `child.lua_get`), you can add the following tree-sitter capture to your personal configuration. Put it in the file 'after/queries/lua/injections.scm'. Don't forget to add `; extends` at the beginning of the file (see `:h treesitter-query-modeline-extends`):\n\n    ```query\n    ; extends\n    (function_call\n      name: (dot_index_expression\n        table: (identifier) @_table\n        field: (identifier) @_field)\n      arguments: (arguments\n        (string\n          content: (string_content) @injection.content))\n      (#eq? @_table child)\n      (#any-of? @_field lua lua_get)\n      (#set! injection.language \"lua\"))\n    ```\n"
  },
  {
    "path": "benchmarks/starter/.gitignore",
    "content": "startup-times.csv\n"
  },
  {
    "path": "benchmarks/starter/README.md",
    "content": "# Benchmarks for 'mini.starter'\n\nThis directory contains code and results of benchmarking 'mini.starter' and its alternatives. Target benchmarked value is a total startup time using configuration file (with `-u <init-file>`) corresponding to benchmarked setup. Configuration files are created in three different groups:\n\n- 'init_starter-default.lua' and 'init_empty.lua' represent default 'mini.starter' setup and corresponding 'init.lua' without 'mini.starter'.\n- 'init_startify-starter', 'init_startify-original', and 'init_startify-alpha' have comparable output imitating default 'vim-startify' with empty header.\n- 'init_dashboard-starter', 'init_dashboard-original', and 'init_dashboard-alpha' have comparable output imitating default 'dashboard-nvim' enabled keybindings.\n\nSummary of startup-times for various 'init' files from 'init-files/' directory can be seen in 'startup-summary.md'. Current benchmark was done with Neovim 0.5.1 on Ubuntu 18.04 (i3-6100). Exact states of plugins used:\n\n- [nvim-mini/mini.nvim](https://github.com/nvim-mini/mini.nvim/tree/cfa108eeaead1abd8854a1f1cfb02e72482641ce)\n- [mhinz/vim-startify](https://github.com/mhinz/vim-startify/tree/81e36c352a8deea54df5ec1e2f4348685569bed2)\n- [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim/tree/ba98ab86487b8eda3b0934b5423759944b5f7ebd)\n- [goolord/alpha-nvim](https://github.com/goolord/alpha-nvim/tree/7a49086bf9197f573b396d4ac46262c02dfb9aec)\n\nTo rerun locally execute these commands (preferably without anything else running in the background and monitor always on):\n\n```bash\nchmod +x install.sh\n./install.sh\n\n# This will create file 'startup-times.csv' and update 'startup-summary.md'\n# WARNING: this will lead to screen flicker\nchmod +x benchmark.sh\n./benchmark.sh\n```\n\nStructure:\n\n- 'init-files/' - directory with all configuration files being benchmarked. NOTE: all of them contain auto-closing command at the end (`defer_fn(...)`) to most accurately measure startup time. To view its output, remove this command.\n- 'benchmark.sh' - script for performing benchmark which is as close to real-world usage as reasonably possible and computing its summary. Its outputs are 'startup-times.csv' and 'startup-summary.md'. All configuration files are benchmarked in alternate fashion: first 'init' file, second, ..., last, first, etc. WARNING: EXECUTION OF THIS SCRIPT LEADS TO MONITOR FLICKERING WHICH MAY CAUSE HARM TO YOUR HEALTH. This is needed to ensure that Neovim was actually opened and something was drawn.\n- 'install.sh' - script for installing all required plugins. NOTE: run `chmod +x install.sh` to make it executable.\n- 'make_summary.py' - Python script to compute summary statistics of csv-file.\n- 'startup-times.csv' (ignored by Git, latest one can be seen in [this gist](https://gist.github.com/echasnovski/85c334396df6fd0cea7bb42246efb97b)) - csv-file with measured startup times. Each row represent single startup round: when all 'init' files are run alternately. Each column represents startup times of single 'init' file.\n- 'startup-summary.md' - markdown file as output of 'make_summary.py'. Contains summaries of 'startup-times.csv'.\n"
  },
  {
    "path": "benchmarks/starter/benchmark.sh",
    "content": "#! /bin/bash\n\n# Perform benchmarking of startup times with different Neovim 'init' files.\n# Execute `nvim -u <*> --startuptime <*>` several times (as closely to actual\n# usage as possible) in rounds alternating between input 'init' files (to \"mix\"\n# possible random noise). Store output in .csv file with rows containing\n# startup times for a single round, columns - for a single 'init' file.\n\n# WARNING: EXECUTION OF THIS SCRIPT LEADS TO FLICKERING OF SCREEN WHICH WHICH\n# MAY CAUSE HARM TO YOUR HEALTH. This is because every 'init' file leads to an\n# actual opening of Neovim with later automatic closing.\n\n# Number of rounds to perform benchmark\nn_rounds=1000\n\n# Path to output .csv file with startup times per round\ncsv_file=startup-times.csv\n\n# Path to output .md file with summary table\nsummary_file=startup-summary.md\n\n# 'Init' files ids with actual paths computed as 'init-files/init_*.lua'\ninit_files=(starter-default empty startify-starter startify-original startify-alpha dashboard-starter dashboard-original dashboard-alpha)\n\nfunction comma_join { local IFS=\",\"; shift; echo \"$*\"; }\n\nfunction benchmark {\n  rm -f \"$csv_file\"\n  touch \"$csv_file\"\n\n  local tmp_bench_file=\"tmp-bench.txt\"\n  touch \"$tmp_bench_file\"\n\n  comma_join -- \"$@\" >> startup-times.csv\n\n  for i in $(seq 1 $n_rounds); do\n    echo \"Round $i\"\n\n    local bench_times=()\n\n    for init_file in \"$@\"; do\n      nvim -u \"init-files/init_$init_file.lua\" --startuptime \"$tmp_bench_file\"\n      local b_time=$(tail -n 1 \"$tmp_bench_file\" | cut -d \" \" -f1)\n      bench_times=(\"${bench_times[@]}\" \"$b_time\")\n    done\n\n    comma_join -- \"${bench_times[@]}\" >> \"$csv_file\"\n\n    rm \"$tmp_bench_file\"\n  done\n}\n\nbenchmark \"${init_files[@]}\"\n\n# Produce output summary\n./make_summary.py \"${csv_file}\" \"${summary_file}\"\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_dashboard-alpha.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd alpha-nvim]])\n\nlocal alpha = require('alpha')\nlocal dashboard = require('alpha.themes.dashboard')\nalpha.setup(dashboard.opts)\n\nvim.g.mapleader = ' '\n\n-- Some of these keybindings doesn't exactly match with what is shown in\n-- buffer, but this doesn't really matter. Main point is that some keybindings\n-- should be pre-made.\nvim.api.nvim_set_keymap('n', '<Leader>ff', ':Telescope find_files<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>fh', ':Telescope oldfiles<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>fr', ':Telescope jumplist<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>fg', ':Telescope live_grep<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>fm', ':Telescope marks<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>sl', ':Telescope command_history<CR>', { noremap = true, silent = true })\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_dashboard-original.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd dashboard-nvim]])\n\nvim.g.mapleader = ' '\nvim.g.dashboard_default_executive = 'telescope'\nvim.api.nvim_set_keymap('n', '<Leader>ss', ':<C-u>SessionSave<CR>', {})\nvim.api.nvim_set_keymap('n', '<Leader>sl', ':<C-u>SessionLoad<CR>', {})\n\nvim.api.nvim_set_keymap('n', '<Leader>fh', ':DashboardFindHistory<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>ff', ':DashboardFindFile<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>tc', ':DashboardChangeColorscheme<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>fa', ':DashboardFindWord<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>fb', ':DashboardJumpMark<CR>', { noremap = true, silent = true })\nvim.api.nvim_set_keymap('n', '<Leader>cn', ':DashboardNewFile<CR>', { noremap = true, silent = true })\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_dashboard-starter.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd mini.nvim]])\n\nlocal starter = require('mini.starter')\nstarter.setup({\n  items = {\n    { name = 'Edit file', action = [[enew]], section = 'Actions' },\n    { name = 'Quit', action = [[quit]], section = 'Actions' },\n    starter.sections.telescope(),\n  },\n  content_hooks = {\n    starter.gen_hook.adding_bullet(),\n    starter.gen_hook.aligning('center', 'center'),\n  },\n})\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_empty.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_starter-default.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd mini.nvim]])\n\nrequire('mini.starter').setup()\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_startify-alpha.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd alpha-nvim]])\n\nlocal alpha = require('alpha')\nlocal startify = require('alpha.themes.startify')\nstartify.nvim_web_devicons.enabled = false\nalpha.setup(startify.opts)\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_startify-original.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd vim-startify]])\n\nvim.g.startify_custom_header = ''\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/init-files/init_startify-starter.lua",
    "content": "vim.cmd([[set packpath=/tmp/nvim/site]])\nvim.cmd([[packadd mini.nvim]])\n\nlocal starter = require('mini.starter')\nstarter.setup({\n  evaluate_single = true,\n  items = {\n    starter.sections.builtin_actions(),\n    starter.sections.recent_files(10, false),\n    starter.sections.recent_files(10, true),\n  },\n  content_hooks = {\n    starter.gen_hook.adding_bullet(),\n    starter.gen_hook.indexing('all', { 'Builtin actions' }),\n    starter.gen_hook.padding(3, 2),\n  },\n})\n\n-- Close Neovim just after fully opening it. Randomize to make \"more real\".\nvim.defer_fn(function() vim.cmd([[quit]]) end, 100 + 200 * math.random())\n"
  },
  {
    "path": "benchmarks/starter/install.sh",
    "content": "#! /bin/bash\nPLUGINPATH=/tmp/nvim/site/pack/bench/opt\nrm -rf $PLUGINPATH\nmkdir -p $PLUGINPATH\ncd $PLUGINPATH\n\ngit clone --depth 1 https://github.com/nvim-mini/mini.nvim\ngit clone --depth 1 https://github.com/goolord/alpha-nvim\ngit clone --depth 1 https://github.com/glepnir/dashboard-nvim\ngit clone --depth 1 https://github.com/mhinz/vim-startify\n"
  },
  {
    "path": "benchmarks/starter/make_summary.py",
    "content": "#!/usr/bin/env python\nimport argparse\nimport csv\nimport statistics\n\n\ndef read_csv_columns(csv_path):\n    with open(csv_path, \"r\") as csvfile:\n        reader = csv.DictReader(csvfile)\n        res = {h: [] for h in reader.fieldnames}\n        for line_dict in reader:\n            for h, val in line_dict.items():\n                res[h].append(float(val))\n\n    return res\n\n\ndef summarise_array(x):\n    return {\n        \"median\": statistics.median(x),\n        \"mean\": statistics.mean(x),\n        \"stdev\": statistics.stdev(x),\n        \"minimum\": min(x),\n        \"maximum\": max(x),\n    }\n\n\ndef save_md_summary(summary, output_path):\n    lines = []\n\n    row_names = list(summary.keys())\n    col_names = [\"init file\"] + list(summary[row_names[0]].keys())\n    lines.append(\" | \".join(col_names))\n    lines.append(\" | \".join(\"---\" for _ in col_names))\n\n    for row_n in row_names:\n        l = [row_n] + [str(round(x, 1)) + 'ms' for x in summary[row_n].values()]\n        lines.append(\" | \".join(l))\n\n    lines = [\"| \" + l + \" |\\n\" for l in lines]\n\n    with open(output_path, \"w\") as output:\n        for l in lines:\n            output.write(l)\n\n\ndef compute_summary(csv_path):\n    columns = read_csv_columns(csv_path)\n    return {h: summarise_array(x) for h, x in columns.items()}\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"input_csv\", help=\"path to file with startup times in csv format\", type=str\n    )\n    parser.add_argument(\n        \"output_md\",\n        help=\"output path where markdown summary table will be written\",\n        type=str,\n    )\n    args = parser.parse_args()\n\n    save_md_summary(compute_summary(args.input_csv), args.output_md)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "benchmarks/starter/startup-summary.md",
    "content": "| init file          | median | mean   | stdev | minimum | maximum |\n| ---                | ---    | ---    | ---   | ---     | ---     |\n| starter-default    | 69.0ms | 70.8ms | 4.3ms | 63.6ms  | 82.7ms  |\n| empty              | 64.1ms | 65.8ms | 4.3ms | 60.0ms  | 79.4ms  |\n| startify-starter   | 70.2ms | 71.9ms | 4.5ms | 64.3ms  | 85.7ms  |\n| startify-original  | 80.3ms | 82.2ms | 4.5ms | 76.4ms  | 107.2ms |\n| startify-alpha     | 72.1ms | 73.8ms | 4.3ms | 66.5ms  | 86.9ms  |\n| dashboard-starter  | 68.4ms | 70.3ms | 4.5ms | 63.3ms  | 102.9ms |\n| dashboard-original | 70.6ms | 72.3ms | 4.4ms | 65.5ms  | 99.6ms  |\n| dashboard-alpha    | 69.8ms | 71.5ms | 4.4ms | 64.7ms  | 97.2ms  |\n"
  },
  {
    "path": "colors/miniautumn.lua",
    "content": "-- \"Cooling autumn\"\n--\n-- Params for `make_palette` used to make palette (colors in OKLch):\n--   Dark : bg=15-2-315; fg=85-1-100; saturation=fg:'lowmedium', bg:'medium'\n--   Light: bg=90-1-315; fg=20-1-100; saturation=fg:'mediumhigh',bg:'high'\n--   Accent: 'bg'\n--\n-- Notes:\n-- - Fg hues have different temperature than bg for more contrast.\n--   They are tweaked to maximize palette's bg colors visibility.\n-- - Fg is less saturated than spring and summer for \"cool\" period.\n-- - Bg is more saturated than fg for more legible diffs.\n-- - Accent is 'bg' for `make_palette`, but `accent_bg` is set to `red_bg`\n--   for colorful statusline.\n--   No `accent='red'` to avoid accent be exactly red: improves legibility\n--   of diff \"delete\" color (like in number column with 'mini.diff').\nlocal palette\n\n--stylua: ignore\nif vim.o.background == 'dark' then\n  palette = {\n    bg_edge2 = '#0b060e', bg_edge = '#1a141d', bg = '#262029', bg_mid = '#423b45', bg_mid2 = '#5e5762',\n    fg_edge2 = '#f3f1e9', fg_edge = '#e5e3db', fg = '#d7d5cd', fg_mid = '#b7b5ad', fg_mid2 = '#97958e',\n\n    accent = '#e4caf1', accent_bg = '#3a0f2f',\n\n    red    = '#f1c6e2', red_bg    = '#3a0f2f',\n    orange = '#fac6c1', orange_bg = '#410d0d',\n    yellow = '#efcfab', yellow_bg = '#492c00',\n    green  = '#d3daad', green_bg  = '#323700',\n    cyan   = '#b4e2c7', cyan_bg   = '#003c24',\n    azure  = '#a7e1e8', azure_bg  = '#004b51',\n    blue   = '#b8d9fc', blue_bg   = '#00284a',\n    purple = '#d7cef9', purple_bg = '#261844',\n  }\nelse\n  palette = {\n    bg_edge2 = '#f8f4fa', bg_edge = '#eeeaf0', bg = '#e5e1e7', bg_mid = '#c5c1c7', bg_mid2 = '#a4a0a6',\n    fg_edge2 = '#0e0d09', fg_edge = '#1f1f1a', fg = '#2f2e29', fg_mid = '#4a4944', fg_mid2 = '#686661',\n\n    accent = '#431256', accent_bg = '#ffb0e9',\n\n    red    = '#52073f', red_bg    = '#ffb0e9',\n    orange = '#5c0207', orange_bg = '#ffaba1',\n    yellow = '#6c4300', yellow_bg = '#ffca87',\n    green  = '#4b5400', green_bg  = '#ddf069',\n    cyan   = '#005e3d', cyan_bg   = '#7bffc2',\n    azure  = '#006a74', azure_bg  = '#7df1ff',\n    blue   = '#003b6d', blue_bg   = '#92c8ff',\n    purple = '#351962', purple_bg = '#cab3ff',\n  }\nend\n\nrequire('mini.hues').apply_palette(palette)\nvim.g.colors_name = 'miniautumn'\n"
  },
  {
    "path": "colors/minicyan.lua",
    "content": "-- Color scheme 'minicyan'\n-- Derived from base16 (https://github.com/chriskempson/base16) and\n-- mini_palette palette generator\nlocal use_cterm, palette\n\n-- Dark palette is an output of 'MiniBase16.mini_palette':\n-- - Background '#0A2A2A' (LCh(uv) = 15-10-192)\n-- - Foreground '#D0D0D0' (Lch(uv) = 83-0-0)\n-- - Accent chroma 50\nif vim.o.background == 'dark' then\n  palette = {\n    base00 = '#0a2a2a',\n    base01 = '#324747',\n    base02 = '#556868',\n    base03 = '#788a8a',\n    base04 = '#bbbbbb',\n    base05 = '#d0d0d0',\n    base06 = '#e6e6e6',\n    base07 = '#fcfcfc',\n    base08 = '#ebcd91',\n    base09 = '#9f8340',\n    base0A = '#209870',\n    base0B = '#82e3ba',\n    base0C = '#bb6d9b',\n    base0D = '#a9d4ff',\n    base0E = '#ffb9e5',\n    base0F = '#598ab9',\n  }\n  use_cterm = {\n    base00 = 235,\n    base01 = 238,\n    base02 = 241,\n    base03 = 102,\n    base04 = 250,\n    base05 = 252,\n    base06 = 254,\n    base07 = 231,\n    base08 = 186,\n    base09 = 136,\n    base0A = 29,\n    base0B = 115,\n    base0C = 132,\n    base0D = 153,\n    base0E = 218,\n    base0F = 67,\n  }\nend\n\n-- Light palette is an 'inverted dark', output of 'MiniBase16.mini_palette':\n-- - Background '#C0D2D2' (LCh(uv) = 83-10-192)\n-- - Foreground '#262626' (Lch(uv) = 15-0-0)\n-- - Accent chroma 80\nif vim.o.background == 'light' then\n  palette = {\n    base00 = '#c0d2d2',\n    base01 = '#9badad',\n    base02 = '#778989',\n    base03 = '#546767',\n    base04 = '#353535',\n    base05 = '#262626',\n    base06 = '#181818',\n    base07 = '#040404',\n    base08 = '#402100',\n    base09 = '#855f00',\n    base0A = '#007d3c',\n    base0B = '#003d00',\n    base0C = '#b12985',\n    base0D = '#003fb6',\n    base0E = '#7e0052',\n    base0F = '#006cb4',\n  }\n  use_cterm = {\n    base00 = 252,\n    base01 = 248,\n    base02 = 102,\n    base03 = 241,\n    base04 = 237,\n    base05 = 235,\n    base06 = 234,\n    base07 = 232,\n    base08 = 235,\n    base09 = 94,\n    base0A = 29,\n    base0B = 22,\n    base0C = 126,\n    base0D = 25,\n    base0E = 89,\n    base0F = 25,\n  }\nend\n\nif palette then\n  require('mini.base16').setup({ palette = palette, use_cterm = use_cterm })\n  vim.g.colors_name = 'minicyan'\nend\n"
  },
  {
    "path": "colors/minischeme.lua",
    "content": "-- Color scheme 'minischeme'\n-- Derived from base16 (https://github.com/chriskempson/base16) and\n-- mini_palette palette generator\nlocal use_cterm, palette\n\n-- Dark palette is an output of 'MiniBase16.mini_palette':\n-- - Background '#112641' (LCh(uv) = 15-20-250)\n-- - Foreground '#e2e98f' (Lch(uv) = 90-60-90)\n-- - Accent chroma 75\nif vim.o.background == 'dark' then\n  palette = {\n    base00 = '#112641',\n    base01 = '#3a475e',\n    base02 = '#606b81',\n    base03 = '#8691a7',\n    base04 = '#d5dc81',\n    base05 = '#e2e98f',\n    base06 = '#eff69c',\n    base07 = '#fcffaa',\n    base08 = '#ffcfa0',\n    base09 = '#cc7e46',\n    base0A = '#46a436',\n    base0B = '#9ff895',\n    base0C = '#ca6ecf',\n    base0D = '#42f7ff',\n    base0E = '#ffc4ff',\n    base0F = '#00a5c5',\n  }\n  use_cterm = {\n    base00 = 235,\n    base01 = 238,\n    base02 = 242,\n    base03 = 246,\n    base04 = 186,\n    base05 = 186,\n    base06 = 229,\n    base07 = 229,\n    base08 = 223,\n    base09 = 173,\n    base0A = 71,\n    base0B = 156,\n    base0C = 170,\n    base0D = 51,\n    base0E = 189,\n    base0F = 38,\n  }\nend\n\n-- Light palette is an 'inverted dark', output of 'MiniBase16.mini_palette':\n-- - Background '#e2e5ca' (LCh(uv) = 90-20-90)\n-- - Foreground '#002a83' (Lch(uv) = 15-60-250)\n-- - Accent chroma 75\nif vim.o.background == 'light' then\n  palette = {\n    base00 = '#e2e5ca',\n    base01 = '#bcbfa4',\n    base02 = '#979a7e',\n    base03 = '#73765a',\n    base04 = '#324490',\n    base05 = '#002a83',\n    base06 = '#0000e4',\n    base07 = '#080500',\n    base08 = '#5e2200',\n    base09 = '#a86400',\n    base0A = '#008818',\n    base0B = '#004500',\n    base0C = '#b34aad',\n    base0D = '#004b76',\n    base0E = '#7d0077',\n    base0F = '#0086ae',\n  }\n  use_cterm = {\n    base00 = 254,\n    base01 = 250,\n    base02 = 246,\n    base03 = 243,\n    base04 = 239,\n    base05 = 18,\n    base06 = 20,\n    base07 = 232,\n    base08 = 52,\n    base09 = 130,\n    base0A = 28,\n    base0B = 22,\n    base0C = 133,\n    base0D = 24,\n    base0E = 90,\n    base0F = 31,\n  }\nend\n\nif palette then\n  require('mini.base16').setup({ palette = palette, use_cterm = use_cterm })\n  vim.g.colors_name = 'minischeme'\nend\n"
  },
  {
    "path": "colors/minispring.lua",
    "content": "-- \"Blooming spring\"\n--\n-- Params for `make_palette` used to make palette (colors in OKLch):\n--   Dark : bg=15-3-135; fg=85-1-265; saturation='medium'\n--   Light: bg=90-1-135; fg=20-1-265; saturation='high'\n--   Accent: 'bg'\n--\n-- Notes:\n-- - Fg hues have different temperature than bg for more contrast.\n--   They are tweaked to maximize palette's bg colors visibility.\n-- - Accent is 'bg' for `make_palette`, but `accent_bg` is set to `green_bg`\n--   for colorful statusline.\n--   No `accent='green'` to avoid accent be exactly green: improves legibility\n--   of diff \"add\" color (like in number column with 'mini.diff').\nlocal palette\n\n--stylua: ignore\nif vim.o.background == 'dark' then\n  palette = {\n    bg_edge2 = '#040b02', bg_edge = '#101a0b', bg = '#1c2617', bg_mid = '#374231', bg_mid2 = '#535f4d',\n    fg_edge2 = '#eef1f7', fg_edge = '#e0e3e9', fg = '#d2d5db', fg_mid = '#b2b5bb', fg_mid2 = '#92959b',\n\n    accent = '#bee2ad', accent_bg = '#00381d',\n\n    red    = '#ffc1bf', red_bg    = '#410d12',\n    orange = '#facb9e', orange_bg = '#492900',\n    yellow = '#d8da9d', yellow_bg = '#373700',\n    green  = '#abe5be', green_bg  = '#00381d',\n    cyan   = '#94e5ea', cyan_bg   = '#004c4f',\n    azure  = '#a9d8ff', azure_bg  = '#002d4d',\n    blue   = '#d3ccff', blue_bg   = '#231946',\n    purple = '#f7c2ea', purple_bg = '#381031',\n  }\nelse\n  palette = {\n    bg_edge2 = '#f3f7f1', bg_edge = '#e9ede7', bg = '#e0e4de', bg_mid = '#c0c4be', bg_mid2 = '#a0a39e',\n    fg_edge2 = '#0b0d11', fg_edge = '#1d1e23', fg = '#2c2e33', fg_mid = '#47494f', fg_mid2 = '#64666c',\n\n    accent = '#2e5e00', accent_bg = '#80ffb8',\n\n    red    = '#700015', red_bg    = '#ffaaa7',\n    orange = '#804c00', orange_bg = '#ffc688',\n    yellow = '#676900', yellow_bg = '#e6ed62',\n    green  = '#006d3f', green_bg  = '#80ffb8',\n    cyan   = '#007f86', cyan_bg   = '#72f6ff',\n    azure  = '#005085', azure_bg  = '#90ccff',\n    blue   = '#350775', blue_bg   = '#c2b3ff',\n    purple = '#600051', purple_bg = '#ffb2f2',\n  }\nend\n\nrequire('mini.hues').apply_palette(palette)\nvim.g.colors_name = 'minispring'\n"
  },
  {
    "path": "colors/minisummer.lua",
    "content": "-- \"Hot summer\"\n--\n-- Params for `make_palette` used to make palette (colors in OKLch):\n--   Dark:  bg=15-1-45; fg=85-1-270; saturation=fg:'medium'\n--   Light: bg=90-1-45; fg=20-1-270; saturation=fg:'high'\n--   Accent: 'yellow'\n--\n-- Notes:\n-- - Fg hues have different temperature than bg for more contrast.\n--   They are tweaked to maximize palette's bg colors visibility.\nlocal palette\n\n--stylua: ignore\nif vim.o.background == 'dark' then\n  palette = {\n    bg_edge2 = '#0c0705', bg_edge = '#1b1512', bg = '#27211e', bg_mid = '#433c39', bg_mid2 = '#605855',\n    fg_edge2 = '#eef1f8', fg_edge = '#e0e2e9', fg = '#d2d4db', fg_mid = '#b2b4bb', fg_mid2 = '#93949b',\n\n    accent = '#f6cc9b', accent_bg = '#492c00',\n\n    red    = '#fac0e4', red_bg    = '#3a0f2e',\n    orange = '#ffc1b9', orange_bg = '#410d0c',\n    yellow = '#f6cc9b', yellow_bg = '#492c00',\n    green  = '#d1db9f', green_bg  = '#313600',\n    cyan   = '#a6e5c3', cyan_bg   = '#003d26',\n    azure  = '#93e4ee', azure_bg  = '#004a51',\n    blue   = '#acd6ff', blue_bg   = '#002649',\n    purple = '#d8caff', purple_bg = '#271844',\n  }\nelse\n  palette = {\n    bg_edge2 = '#fcf4f0', bg_edge = '#f2eae6', bg = '#e9e1dd', bg_mid = '#c9c1bd', bg_mid2 = '#a8a19d',\n    fg_edge2 = '#0b0d11', fg_edge = '#1d1e23', fg = '#2c2e33', fg_mid = '#47494f', fg_mid2 = '#64666c',\n\n    accent = '#804e00', accent_bg = '#ffc888',\n\n    red    = '#61004f', red_bg    = '#ffb2ee',\n    orange = '#700011', orange_bg = '#ffaba5',\n    yellow = '#804e00', yellow_bg = '#ffc888',\n    green  = '#636900', green_bg  = '#e3ee65',\n    cyan   = '#006f44', cyan_bg   = '#7fffbd',\n    azure  = '#007e87', azure_bg  = '#79f4ff',\n    blue   = '#004d84', blue_bg   = '#91caff',\n    purple = '#370674', purple_bg = '#c5b3ff',\n  }\nend\n\nrequire('mini.hues').apply_palette(palette)\nvim.g.colors_name = 'minisummer'\n"
  },
  {
    "path": "colors/miniwinter.lua",
    "content": "-- \"Icy winter\"\n--\n-- Params for `make_palette` used to make palette (colors in OKLch):\n--   Dark:  bg=15-3-225; fg=85-1-80; saturation=fg:'lowmedium', bg:'medium'\n--   Light: bg=90-1-225; fg=20-1-80; saturation=fg:'mediumhigh',bg:'high'\n--   Accent: 'azure'\n--\n-- Notes:\n-- - Fg hues have different temperature than bg for more contrast.\n--   They are tweaked to maximize palette's bg colors visibility.\n-- - Fg is less saturated than spring and summer for \"cool\" period.\n-- - Bg is more saturated than fg for more legible diffs.\nlocal palette\n\n--stylua: ignore\nif vim.o.background == 'dark' then\n  palette = {\n    bg_edge2 = '#000f15', bg_edge = '#051a20', bg = '#11262d', bg_mid = '#2c4249', bg_mid2 = '#485f67',\n    fg_edge2 = '#f4f0e9', fg_edge = '#e6e2db', fg = '#d8d4cd', fg_mid = '#b8b4ad', fg_mid2 = '#98948e',\n\n    accent = '#b3daf9', accent_bg = '#00324f',\n\n    red    = '#fac5c7',    red_bg = '#410d14',\n    orange = '#f2ccad', orange_bg = '#492600',\n    yellow = '#d9d8aa', yellow_bg = '#3a3800',\n    green  = '#b8e1c1',  green_bg = '#003415',\n    cyan   = '#a6e1e2',   cyan_bg = '#004c4e',\n    azure  = '#b3daf9',  azure_bg = '#00324f',\n    blue   = '#d1cffb',   blue_bg = '#211a46',\n    purple = '#edc7e7', purple_bg = '#371134',\n  }\nelse\n  palette = {\n    bg_edge2 = '#eff7fb', bg_edge = '#e5edf1', bg = '#dce4e8', bg_mid = '#bcc4c8', bg_mid2 = '#9ca4a7',\n    fg_edge2 = '#0f0d09', fg_edge = '#211e1a', fg = '#312e29', fg_mid = '#4c4944', fg_mid2 = '#6a6661',\n\n    accent = '#014772', accent_bg = '#90ceff',\n\n    red    = '#5c0113', red_bg    = '#ffaaaa',\n    orange = '#6c3e00', orange_bg = '#ffc488',\n    yellow = '#565600', yellow_bg = '#eaeb5f',\n    green  = '#00562e', green_bg  = '#83ffb3',\n    cyan   = '#016d71', cyan_bg   = '#6af9ff',\n    azure  = '#014772', azure_bg  = '#90ceff',\n    blue   = '#301d65', blue_bg   = '#beb3ff',\n    purple = '#4f0b46', purple_bg = '#ffb3f6',\n  }\nend\n\nrequire('mini.hues').apply_palette(palette)\nvim.g.colors_name = 'miniwinter'\n"
  },
  {
    "path": "colors/randomhue.lua",
    "content": "local hues = require('mini.hues')\n\n-- Generate random config with initialized random seed (otherwise it won't be\n-- random during startup)\nmath.randomseed(vim.loop.hrtime())\nlocal base_colors = hues.gen_random_base_colors()\n\nhues.setup({\n  background = base_colors.background,\n  foreground = base_colors.foreground,\n  n_hues = 8,\n  saturation = vim.o.background == 'dark' and 'medium' or 'high',\n  accent = 'bg',\n})\n\nvim.g.colors_name = 'randomhue'\n"
  },
  {
    "path": "doc/mini-ai.txt",
    "content": "*mini.ai* Extend and create a/i textobjects\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                        *MiniAi*\nEnhance some builtin |text-objects| (like |a(|, |a)|, |a'|, and more),\ncreate new ones (like `a*`, `a<Space>`, `af`, `a?`, and more), and allow\nuser to create their own.\n\nFeatures:\n- Customizable creation of `a`/`i` textobjects using Lua patterns and functions.\n  Supports:\n    - Dot-repeat.\n    - |v:count|.\n    - Different search methods (see |MiniAi.config|).\n    - Consecutive application (update selection without leaving Visual mode).\n    - Aliases for multiple textobjects.\n\n- Comprehensive builtin textobjects (see more in |MiniAi-builtin-textobjects|):\n    - Balanced brackets (with and without whitespace) plus alias.\n    - Balanced quotes plus alias.\n    - Function call.\n    - Argument.\n    - Tag.\n    - Derived from user prompt.\n    - Default for anything but Latin letters (to fall back to |text-objects|).\n\n    For more textobjects see |MiniExtra.gen_ai_spec|.\n\n- Motions for jumping to left/right edge of textobject.\n\n- Set of specification generators to tweak some builtin textobjects (see\n  |MiniAi.gen_spec|).\n\n- Treesitter textobjects (through |MiniAi.gen_spec.treesitter()| helper).\n\nThis module works by defining mappings for both `a` and `i` in Visual and\nOperator-pending mode. After typing, they wait for single character user input\ntreated as textobject identifier and apply resolved textobject specification\n(fall back to other mappings if can't find proper textobject id). For more\ninformation see |MiniAi-textobject-specification| and |MiniAi-algorithm|.\n\nKnown issues which won't be resolved:\n- Search for builtin textobjects is done mostly using Lua patterns\n  (regex-like approach). Certain amount of false positives is to be expected.\n\n- During search for builtin textobjects there is no distinction if it is\n  inside string or comment. For example, in the following case there will\n  be wrong match for a function call: `f(a = \")\", b = 1)`.\n\nGeneral rule of thumb: any instrument using available parser for document\nstructure (like treesitter) will usually provide more precise results. This\nmodule has builtins mostly for plain text textobjects which are useful\nmost of the times (like \"inside brackets\", \"around quotes/underscore\", etc.).\nFor advanced use cases define function specification for custom textobjects.\n\nWhat it doesn't (and probably won't) do:\n- Have special operators to specially handle whitespace (like `I` and `A`\n  in 'targets.vim'). Whitespace handling is assumed to be done inside\n  textobject specification (like `i(` and `i)` handle whitespace differently).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.ai').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniAi`\nwhich you can use for scripting or manually (with `:lua MiniAi.*`).\n\nSee |MiniAi.config| for available config settings.\n\nYou can override runtime config settings (like `config.custom_textobjects`)\nlocally to buffer inside `vim.b.miniai_config` which should have same structure\nas `MiniAi.config`. See |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Comparisons ~\n\n- [wellle/targets.vim](https://github.com/wellle/targets.vim):\n    - Has limited support for creating own textobjects: it is constrained\n      to pre-defined detection rules. 'mini.ai' allows creating own rules\n      via Lua patterns and functions (see |MiniAi-textobject-specification|).\n    - Doesn't provide any programmatical API for getting information about\n      textobjects. 'mini.ai' does it via |MiniAi.find_textobject()|.\n    - Has no implementation of \"moving to edge of textobject\". 'mini.ai'\n      does it via |MiniAi.move_cursor()| and `g[` and `g]` default mappings.\n    - Both implement the notion of manual \"next\"/\"last\" search directions.\n    - Implements `A`, `I` operators. 'mini.ai' does not by design: it is\n      assumed to be a property of textobject, not operator.\n    - Doesn't implement \"function call\" and \"user prompt\" textobjects.\n      'mini.ai' does (with `f` and `?` identifiers).\n    - Has limited support for \"argument\" textobject. Although it works in\n      most situations, it often misdetects commas as argument separator\n      (like if it is inside quotes or `{}`). 'mini.ai' deals with these cases.\n- [nvim-treesitter/nvim-treesitter-textobjects](https://github.com/nvim-treesitter/nvim-treesitter-textobjects):\n    - Along with textobject functionality provides a curated and maintained\n      set of popular textobject queries for many languages (which can power\n      |MiniAi.gen_spec.treesitter()| functionality).\n    - Both support working with |treesitter-directives| allowing more\n      fine-tuned textobjects.\n    - Implements only textobjects based on treesitter.\n    - Doesn't support |v:count|.\n    - Doesn't support multiple search method (basically, only 'cover').\n    - Doesn't support consecutive application of target textobject.\n\n# Disabling ~\n\nTo disable, set `vim.g.miniai_disable` (globally) or `vim.b.miniai_disable`\n(for a buffer) to `true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                    *MiniAi-builtin-textobjects*\nThis table describes all builtin textobjects along with what they\nrepresent. Explanation:\n- `Key` represents the textobject identifier: single character which should\n  be typed after `a`/`i`.\n- `Name` is a description of textobject.\n- `Example line` contains a string for which examples are constructed. The\n  `*` denotes the cursor position.\n- `a`/`i` describe inclusive region representing `a` and `i` textobjects.\n  Use numbers in separators for easier navigation.\n- `2a`/`2i` describe either `2a`/`2i` (support for |v:count|) textobjects\n  or `a`/`i` textobject followed by another `a`/`i` textobject (consecutive\n  application leads to incremental selection).\n\nExample: typing `va)` with cursor on `*` leads to selection from column 2\nto column 12. Another typing `a)` changes selection to [1; 13]. Also, besides\nvisual selection, any |operator| can be used or `g[`/`g]` motions to move\nto left/right edge of `a` textobject.\n>\n ┌───┬───────────────┬──────────────────┬────────┬────────┬────────┬────────┐\n │Key│     Name      │   Example line   │   a    │   i    │   2a   │   2i   │\n ├───┴───────────────┴──────────────────┴────────┴────────┴────────┴────────┤\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ ( │  Balanced ()  │ (( *a (bb) ))    │        │        │        │        │\n │ [ │  Balanced []  │ [[ *a [bb] ]]    │ [2;12] │ [4;10] │ [1;13] │ [2;12] │\n │ { │  Balanced {}  │ {{ *a {bb} }}    │        │        │        │        │\n │ < │  Balanced <>  │ << *a <bb> >>    │        │        │        │        │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ ) │  Balanced ()  │ (( *a (bb) ))    │        │        │        │        │\n │ ] │  Balanced []  │ [[ *a [bb] ]]    │        │        │        │        │\n │ } │  Balanced {}  │ {{ *a {bb} }}    │ [2;12] │ [3;11] │ [1;13] │ [2;12] │\n │ > │  Balanced <>  │ << *a <bb> >>    │        │        │        │        │\n │ b │  Alias for    │ [( *a {bb} )]    │        │        │        │        │\n │   │  ), ], or }   │                  │        │        │        │        │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ \" │  Balanced \"   │ \"*a\" \" bb \"      │        │        │        │        │\n │ ' │  Balanced '   │ '*a' ' bb '      │        │        │        │        │\n │ ` │  Balanced `   │ `*a` ` bb `      │ [1;4]  │ [2;3]  │ [6;11] │ [7;10] │\n │ q │  Alias for    │ '*a' \" bb \"      │        │        │        │        │\n │   │  \", ', or `   │                  │        │        │        │        │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ ? │  User prompt  │ e*e o e o o      │ [3;5]  │ [4;4]  │ [7;9]  │ [8;8]  │\n │   │(typed e and o)│                  │        │        │        │        │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ t │      Tag      │ <x><y>*a</y></x> │ [4;12] │ [7;8]  │ [1;16] │ [4;12] │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ f │ Function call │ f(a, g(*b, c) )  │ [6;13] │ [8;12] │ [1;15] │ [3;14] │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ a │   Argument    │ f(*a, g(b, c) )  │ [3;5]  │ [3;4]  │ [5;14] │ [7;13] │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │   │    Default    │ aa_*b__cc___     │ [4;7]  │ [4;5]  │ [8;12] │ [8;9]  │\n │   │   (typed _)   │                  │        │        │        │        │\n └───┴───────────────┴──────────────────┴────────┴────────┴────────┴────────┘\n<\nNotes:\n- All examples assume default `config.search_method`.\n- Open brackets differ from close brackets by how they treat inner edge\n  whitespace for `i` textobject: open ignores it, close - includes.\n- Default textobject is activated for identifiers which are not Latin letters.\n  They are designed to be treated as separators, so include only right edge\n  in `a` textobject. To include both edges, use custom textobjects\n  (see |MiniAi-textobject-specification| and |MiniAi.config|). Note:\n    - When cursor is exactly on the identifier character while there are\n      two matching candidates on both left and right, the resulting region\n      with smaller width is preferred.\n\n------------------------------------------------------------------------------\n                                                               *MiniAi-glossary*\nNote: this is similar to |MiniSurround-glossary|.\n\nREGION ~\nTable representing region in a buffer. Fields:\n- <from> and <to> for inclusive start and end positions (<to> might be\n  `nil` to describe empty region). Each position is also a table with\n  line <line> and column <col> (both start at 1).\n- <vis_mode> for which Visual mode will be used to select textobject.\n  See `opts` argument of |MiniAi.select_textobject()|.\n  One of `'v'`, `'V'`, `'\\22'` (escaped `'<C-v>'`).\n\nExamples: >lua\n\n  { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }\n\n  -- Forced linewise mode\n  {\n    from = { line = 1, col = 1 }, to = { line = 2, col = 1 },\n    vis_mode = 'V',\n  }\n\n  -- Empty region\n  { from = { line = 10, col = 10 } }\n<\nPATTERN ~\nString describing Lua pattern.\n\nSPAN ~\nInterval inside a string (end-exclusive). Like [1, 5). Equal `from` and `to` edges\ndescribe empty span at that point.\n\nSpan `A = [a1, a2)` covers `B = [b1, b2)` if every element of `B` is within\n`A` (`a1 <= b < a2`). It also is described as \"B is nested inside A\".\n\nNESTED PATTERN ~\nArray of patterns aimed to describe nested spans.\n\nSPAN MATCHES NESTED PATTERN ~\nIf there is a sequence of consecutively nested spans each matching\ncorresponding pattern within substring of previous span (or input string\nfor first span). Example: >lua\n\n  -- Nested patterns for balanced `()` with inner space\n  { '%b()', '^. .* .$' }\n\n  -- Example input string (with columns underneath for easier reading):\n     \"( ( () ( ) ) )\"\n  --  12345678901234\n<\nHere are all matching spans [1, 15) and [3, 13). Both [5, 7) and [8, 10)\nmatch first pattern but not second. All other combinations of `(` and `)`\ndon't match first pattern (not balanced).\n\nCOMPOSED PATTERN ~\nArray with each element describing possible pattern (or array of them) at\nthat place. Composed pattern basically defines all possible combinations of\nnested pattern (their cartesian product). Examples:\n\n1. Either balanced `()` or balanced `[]` but both with inner edge space: >lua\n\n    -- Composed pattern\n    { { '%b()', '%b[]' }, '^. .* .$' }\n\n    -- Composed pattern expanded into equivalent array of nested patterns\n    { '%b()', '^. .* .$' } -- and\n    { '%b[]', '^. .* .$' }\n<\n2. Either \"balanced `()` with inner edge space\" or \"balanced `[]` with no\n   inner edge space\", both with 5 or more characters: >lua\n\n    -- Composed pattern\n    { { { '%b()', '^. .* .$' }, { '%b[]', '^.[^ ].*[^ ].$' } }, '.....' }\n\n    -- Composed pattern expanded into equivalent array of nested patterns\n    { '%b()', '^. .* .$', '.....' } -- and\n    { '%b[]', '^.[^ ].*[^ ].$', '.....' }\n<\nSPAN MATCHES COMPOSED PATTERN ~\nIf it matches at least one nested pattern from expanded composed pattern.\n\n------------------------------------------------------------------------------\n                                               *MiniAi-textobject-specification*\nTextobject specification has a structure of composed pattern (see\n|MiniAi-glossary|) with two differences:\n- Last pattern(s) should have even number of empty capture groups denoting\n  how the last string should be processed to extract `a` or `i` textobject:\n    - Zero captures mean that whole string represents both `a` and `i`.\n      Example: `xxx` will define textobject matching string `xxx` literally.\n    - Two captures represent `i` textobject inside of them. `a` - whole string.\n      Example: `x()x()x` defines `a` textobject to be `xxx`, `i` - middle `x`.\n    - Four captures define `a` textobject inside captures 1 and 4, `i` -\n      inside captures 2 and 3. Example: `x()()x()x()` defines `a`\n      textobject to be last `xx`, `i` - middle `x`.\n- Allows callable objects (see |vim.is_callable()|) in certain places\n  (enables more complex textobjects in exchange of increase in configuration\n  complexity and computations):\n    - If specification itself is a callable, it will be called with the same\n      arguments as |MiniAi.find_textobject()| and should return one of:\n        - Composed pattern. Useful for implementing user input. Example of\n          simplified variant of textobject for function call with name taken\n          from user prompt: >lua\n\n            function()\n              local left_edge = vim.pesc(vim.fn.input('Function name: '))\n              return { left_edge .. '%b()', '^.-%(().*()%)$' }\n            end\n<\n        - Single output region. Useful to allow full control over\n          textobject. Will be taken as is. Example of returning whole buffer: >lua\n\n            function()\n              local from = { line = 1, col = 1 }\n              local to = {\n                line = vim.fn.line('$'),\n                col = math.max(vim.fn.getline('$'):len(), 1)\n              }\n              return { from = from, to = to, vis_mode = 'V' }\n            end\n<\n        - Array of output region(s). Useful for incorporating other\n          instruments, like treesitter (see |MiniAi.gen_spec.treesitter()|).\n          The best region will be picked in the same manner as with composed\n          pattern (respecting options `n_lines`, `search_method`, etc.).\n          Example of selecting \"best\" line with display width more than 80: >lua\n\n            function(_, _, _)\n              local res = {}\n              for i = 1, vim.api.nvim_buf_line_count(0) do\n                local cur_line = vim.fn.getline(i)\n                if vim.fn.strdisplaywidth(cur_line) > 80 then\n                  local region = {\n                    from = { line = i, col = 1 },\n                    to = { line = i, col = cur_line:len() },\n                  }\n                  table.insert(res, region)\n                end\n              end\n              return res\n            end\n<\n    - If there is a callable instead of assumed string pattern, it is expected\n      to have signature `(line, init)` and behave like `pattern:find()`.\n      It should return two numbers representing span in `line` next after\n      or at `init` (`nil` if there is no such span).\n      !IMPORTANT NOTE!: it means that output's `from` shouldn't be strictly\n      to the left of `init` (it will lead to infinite loop). Not allowed as\n      last item (as it should be pattern with captures).\n      Example of matching only balanced parenthesis with big enough width: >lua\n\n        {\n          '%b()',\n          function(s, init)\n            if init > 1 or s:len() < 5 then return end\n            return 1, s:len()\n          end,\n          '^.().*().$'\n        }\n<\nMore examples: >lua\n\n  -- Pair of balanced brackets from set (used for builtin `b` identifier):\n  { { '%b()', '%b[]', '%b{}' }, '^.().*().$' }\n\n  -- Imitate word ignoring digits and punctuation (only for Latin alphabet):\n  { '()()%f[%w]%w+()[ \\t]*()' }\n\n  -- Word with camel case support (also supports only Latin alphabet):\n  {\n    {\n      '%u[%l%d]+%f[^%l%d]',\n      '%f[%S][%l%d]+%f[^%l%d]',\n      '%f[%P][%l%d]+%f[^%l%d]',\n      '^[%l%d]+%f[^%l%d]',\n    },\n    '^().*()$'\n  }\n\n  -- Number:\n  { '%f[%d]%d+' }\n\n  -- Date in 'YYYY-MM-DD' format:\n  { '()%d%d%d%d%-%d%d%-%d%d()' }\n\n  -- Lua block string:\n  { '%[%[().-()%]%]' }\n<\nSee |MiniAi.gen_spec| for function wrappers to create commonly used\ntextobject specifications.\n\n------------------------------------------------------------------------------\n                                                              *MiniAi-algorithm*\nSearch for the textobjects relies on these principles:\n- It uses same input data as described in |MiniAi.find_textobject()|,\n  i.e. whether it is `a` or `i` textobject, its identifier, reference region, etc.\n- Textobject specification is constructed based on textobject identifier\n  (see |MiniAi-textobject-specification|).\n- General search is done by converting some 2d buffer region (neighborhood\n  of reference region) into 1d string (each line is appended with `\\n`).\n  Then search for a best span matching textobject specification is done\n  inside string (see |MiniAi-glossary|). After that, span is converted back\n  into 2d region. Note: first search is done inside reference region lines,\n  and only after that - inside its neighborhood within `config.n_lines`\n  (see |MiniAi.config|).\n- The best matching span is chosen by iterating over all spans matching\n  textobject specification and comparing them with \"current best\".\n  Comparison also depends on reference region (tighter covering is better,\n  otherwise closer is better) and search method (if span is even considered).\n- Extract span based on extraction pattern (last item in nested pattern).\n- If task is to perform a consecutive search (`opts.n_times` is greater than 1),\n  steps are repeated with current best match becoming reference region.\n  One such additional step is also done if final region is equal to\n  reference region (this enables consecutive application).\n\nNotes:\n- Iteration over all matched spans is done in depth-first fashion with\n  respect to nested pattern.\n- It is guaranteed that span is compared only once.\n- For the sake of increasing functionality, during iteration over all\n  matching spans, some Lua patterns in composed pattern are handled\n  specially.\n    - `%bxx` (`xx` is two identical characters). It denotes balanced pair\n      of identical characters and results into \"paired\" matches. For\n      example, `%b\"\"` for `\"aa\" \"bb\"` would match `\"aa\"` and `\"bb\"`, but\n      not middle `\" \"`.\n    - `x.-y` (`x` and `y` are different strings). It results only in matches with\n      smallest width. For example, `e.-o` for `e e o o` will result only in\n      middle `e o`. Note: it has some implications for when parts have\n      quantifiers (like `+`, etc.), which usually can be resolved with\n      frontier pattern `%f[]` (see examples in |MiniAi-textobject-specification|).\n\n------------------------------------------------------------------------------\n                                                                *MiniAi.setup()*\n                            `MiniAi.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniAi.config|.\n\nUsage ~\n>lua\n  require('mini.ai').setup() -- use default config\n  -- OR\n  require('mini.ai').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                                 *MiniAi.config*\n                                `MiniAi.config`\nDefaults ~\n>lua\n  MiniAi.config = {\n    -- Table with textobject id as fields, textobject specification as values.\n    -- Also use this to disable builtin textobjects. See |MiniAi.config|.\n    custom_textobjects = nil,\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      -- Main textobject prefixes\n      around = 'a',\n      inside = 'i',\n\n      -- Next/last textobjects\n      -- NOTE: These override built-in LSP selection mappings on Neovim>=0.12\n      -- Map LSP selection manually to use it (see `:h MiniAi.config`)\n      around_next = 'an',\n      inside_next = 'in',\n      around_last = 'al',\n      inside_last = 'il',\n\n      -- Move cursor to corresponding edge of `a` textobject\n      goto_left = 'g[',\n      goto_right = 'g]',\n    },\n\n    -- Number of lines within which textobject is searched\n    n_lines = 50,\n\n    -- How to search for object (first inside current line, then inside\n    -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev',\n    -- 'cover_or_nearest', 'next', 'prev', 'nearest'.\n    search_method = 'cover_or_next',\n\n    -- Whether to disable showing non-error feedback\n    -- This also affects (purely informational) helper messages shown after\n    -- idle time if user input is required.\n    silent = false,\n  }\n<\n# Custom textobjects ~\n\nUser can define own textobjects by supplying `config.custom_textobjects`.\nIt should be a table with keys being single character textobject identifier\n(supported by |getcharstr()|) and values - textobject specification\n(see |MiniAi-textobject-specification|).\n\nGeneral recommendations:\n- This can be used to override builtin ones (|MiniAi-builtin-textobjects|).\n  Supply non-valid input (not in specification format) to disable module's\n  builtin textobject in favor of external or Neovim's builtin mapping.\n- Keys should use character representation which can be |getcharstr()| output.\n  For example, `'\\r'` and not `'<CR>'`.\n\nExamples:\n>lua\n  require('mini.ai').setup({\n    custom_textobjects = {\n      -- Tweak argument textobject\n      a = require('mini.ai').gen_spec.argument({ brackets = { '%b()' } }),\n\n      -- Disable brackets alias in favor of builtin block textobject\n      b = false,\n\n      -- Now `vax` should select `xxx` and `vix` - middle `x`\n      x = { 'x()x()x' },\n\n      -- Whole buffer\n      g = function()\n        local from = { line = 1, col = 1 }\n        local to = {\n          line = vim.fn.line('$'),\n          col = math.max(vim.fn.getline('$'):len(), 1)\n        }\n        return { from = from, to = to }\n      end\n    }\n  })\n\n  -- Use `vim.b.miniai_config` to customize per buffer\n  -- Example of specification useful for Markdown files:\n  local spec_pair = require('mini.ai').gen_spec.pair\n  vim.b.miniai_config = {\n    custom_textobjects = {\n      ['*'] = spec_pair('*', '*', { type = 'greedy' }),\n      ['_'] = spec_pair('_', '_', { type = 'greedy' }),\n    },\n  }\n<\nThere are more example specifications in |MiniAi-textobject-specification|.\n\n# Search method ~\n\nValue of `config.search_method` defines how best match search is done.\nBased on its value, one of the following matches will be selected:\n- Covering match. Left/right edge is before/after left/right edge of\n  reference region.\n- Previous match. Left/right edge is before left/right edge of reference\n  region.\n- Next match. Left/right edge is after left/right edge of reference region.\n- Nearest match. Whichever is closest among previous and next matches.\n\nPossible values are:\n- `'cover'` - use only covering match. Don't use either previous or\n  next; report that there is no textobject found.\n- `'cover_or_next'` (default) - use covering match. If not found, use next.\n- `'cover_or_prev'` - use covering match. If not found, use previous.\n- `'cover_or_nearest'` - use covering match. If not found, use nearest.\n- `'next'` - use next match.\n- `'prev'` - use previous match.\n- `'nearest'` - use nearest match.\n\nNote: search is first performed on the reference region lines and only\nafter failure - on the whole neighborhood defined by `config.n_lines`. This\nmeans that with `config.search_method` not equal to `'cover'`, \"prev\" or\n\"next\" textobject will end up as search result if they are found on first\nstage although covering match might be found in bigger, whole neighborhood.\nThis design is based on observation that most of the time operation is done\nwithin reference region lines (usually cursor line).\n\nHere is an example of what `a)` textobject is based on a value of\n`'config.search_method'` when cursor is inside `bbb` word:\n- `'cover'`:         `(a) bbb (c)` -> none\n- `'cover_or_next'`: `(a) bbb (c)` -> `(c)`\n- `'cover_or_prev'`: `(a) bbb (c)` -> `(a)`\n- `'cover_or_nearest'`: depends on cursor position.\n  For first and second `b` - as in `cover_or_prev` (as previous match is\n  nearer), for third - as in `cover_or_next` (as next match is nearer).\n- `'next'`: `(a) bbb (c)` -> `(c)`. Same outcome for `(bbb)`.\n- `'prev'`: `(a) bbb (c)` -> `(a)`. Same outcome for `(bbb)`.\n- `'nearest'`: depends on cursor position (same as in `'cover_or_nearest'`).\n\n# Mappings ~\n\nMappings `around_next` / `inside_next` and `around_last` / `inside_last` are\nessentially `around` / `inside` but using search method `'next'` and `'prev'`.\n\nNOTE: with default config, built-in LSP mappings |v_an| and |v_in| on Neovim>=0.12\nare overridden. Either use different `around_next` / `inside_next` keys or\nmap manually using |vim.lsp.buf.selection_range()|. For example: >lua\n\n  local map_lsp_selection = function(lhs, desc)\n    local s = vim.startswith(desc, 'Increase') and 1 or -1\n    local rhs = function() vim.lsp.buf.selection_range(s * vim.v.count1) end\n    vim.keymap.set('x', lhs, rhs, { desc = desc })\n  end\n  map_lsp_selection('<Leader>ls', 'Increase selection')\n  map_lsp_selection('<Leader>lS', 'Decrease selection')\n<\n------------------------------------------------------------------------------\n                                                      *MiniAi.find_textobject()*\n               `MiniAi.find_textobject`({ai_type}, {id}, {opts})\nFind textobject region\n\nParameters ~\n{ai_type} `(string)` One of `'a'` or `'i'`.\n{id} `(string)` Single character string representing textobject id. It is\n  used to get specification which is later used to compute textobject region.\n  Note: if specification is a function, it is called with all present\n  arguments (`opts` is populated with default arguments).\n{opts} `(table|nil)` Options. Possible fields:\n  - <n_lines> - Number of lines within which textobject is searched.\n    Default: `config.n_lines` (see |MiniAi.config|).\n  - <n_times> - Number of times to perform a consecutive search. Each one\n    is done with reference region being previous found textobject region.\n    Default: 1.\n  - <reference_region> - region to try to cover (see |MiniAi-glossary|). It\n    is guaranteed that output region will not be inside or equal to this one.\n    Default: empty region at cursor position.\n  - <search_method> - Search method. Default: `config.search_method`.\n\nReturn ~\n`(table|nil)` Region of textobject or `nil` if no textobject different\n  from `opts.reference_region` was consecutively found `opts.n_times` times.\n\n------------------------------------------------------------------------------\n                                                          *MiniAi.move_cursor()*\n             `MiniAi.move_cursor`({side}, {ai_type}, {id}, {opts})\nMove cursor to edge of textobject\n\nParameters ~\n{side} `(string)` One of `'left'` or `'right'`.\n{ai_type} `(string)` One of `'a'` or `'i'`.\n{id} `(string)` Single character string representing textobject id.\n{opts} `(table|nil)` Same as in |MiniAi.find_textobject()|.\n  `opts.n_times` means number of actual jumps (important when cursor\n  already on the potential jump spot).\n\n------------------------------------------------------------------------------\n                                                               *MiniAi.gen_spec*\n                               `MiniAi.gen_spec`\nGenerate common textobject specifications\n\nThis is a table with function elements. Call to actually get specification.\n\nExample: >lua\n\n  local gen_spec = require('mini.ai').gen_spec\n  require('mini.ai').setup({\n    custom_textobjects = {\n      -- Tweak argument to be recognized only inside `()` between `;`\n      a = gen_spec.argument({ brackets = { '%b()' }, separator = ';' }),\n\n      -- Tweak function call to not detect dot in function name\n      f = gen_spec.function_call({ name_pattern = '[%w_]' }),\n\n      -- Function definition (needs treesitter queries with these captures)\n      F = gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' }),\n\n      -- Make `|` select both edges in non-balanced way\n      ['|'] = gen_spec.pair('|', '|', { type = 'non-balanced' }),\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                                    *MiniAi.gen_spec.argument()*\n                       `MiniAi.gen_spec.argument`({opts})\nArgument specification\n\nArgument textobject (has default `a` identifier) is a region inside\nbalanced bracket between allowed not excluded separators. Use this function\nto tweak how it works.\n\nExamples:\n- `argument({ brackets = { '%b()' } })` will search for an argument only\n  inside balanced `()`.\n- `argument({ separator = '[,;]' })` will treat both `,` and `;` as separators.\n- `argument({ exclude_regions = { '%b()' } })` will exclude separators\n  which are inside balanced `()` (inside outer brackets).\n\nParameters ~\n{opts} `(table|nil)` Options. Allowed fields:\n  - <brackets> - array of patterns for outer balanced brackets.\n    Default: `{ '%b()', '%b[]', '%b{}' }` (any `()`, `[]`, or `{}` can\n    enclose arguments).\n  - <separator> - separator pattern. Default: `','`.\n    One of the practical usages of this option is to include whitespace\n    around character to be a part of separator. For example, `'%s*,%s*'`\n    will treat as separator not only ',', but its possible surrounding\n    whitespace. This has both positive and negative effects. On one hand,\n    `daa` executed over the first argument will delete whitespace after\n    first comma, leading to a more expected outcome. On the other hand it\n    is ambiguous which argument is picked when cursor is over whitespace\n    near the character separator.\n  - <exclude_regions> - array with patterns for regions inside which\n    separators will be ignored.\n    Default: `{ '%b\"\"', \"%b''\", '%b()', '%b[]', '%b{}' }` (separators\n    inside balanced quotes or brackets are ignored).\n\n------------------------------------------------------------------------------\n                                               *MiniAi.gen_spec.function_call()*\n                    `MiniAi.gen_spec.function_call`({opts})\nFunction call specification\n\nFunction call textobject (has default `f` identifier) is a region with some\ncharacters followed by balanced `()`. Use this function to tweak how it works.\n\nExample:\n- `function_call({ name_pattern = '[%w_]' })` will recognize function name with\n  only alphanumeric or underscore (not dot).\n\nParameters ~\n{opts} `(table|nil)` Options. Allowed fields:\n  - <name_pattern> - string pattern of character set allowed in function name.\n    Default: `'[%w_%.]'` (alphanumeric, underscore, or dot).\n    Note: should be enclosed in `[]`.\n\n------------------------------------------------------------------------------\n                                                        *MiniAi.gen_spec.pair()*\n                `MiniAi.gen_spec.pair`({left}, {right}, {opts})\nPair specification\n\nUse it to define textobject for region surrounded with `left` from left and\n`right` from right. The `a` textobject includes both edges, `i` - excludes them.\n\nRegion can be one of several types (controlled with `opts.type`). All\nexamples are for default search method, `a` textobject, and use `'_'` as\nboth `left` and `right`:\n- Non-balanced (`{ type = 'non-balanced' }`), default. Equivalent to using\n  `x.-y` as first pattern. Example: on line '_a_b_c_' it consecutively\n  matches '_a_', '_b_', '_c_'.\n- Balanced (`{ type = 'balanced' }`). Equivalent to using `%bxy` as first\n  pattern. Example: on line '_a_b_c_' it consecutively matches '_a_', '_c_'.\n  Note: both `left` and `right` should be single character.\n- Greedy (`{ type = 'greedy' }`). Like non-balanced but will select maximum\n  consecutive `left` and `right` edges. Example: on line '__a__b_' it\n  consecutively selects '__a__' and '__b_'. Note: both `left` and `right`\n  should be single character.\n\nParameters ~\n{left} `(string)` Left edge.\n{right} `(string)` Right edge.\n{opts} `(table|nil)` Options. Possible fields:\n  - <type> - Type of a pair. One of `'non-balanced'` (default), `'balanced'`,\n  `'greedy'`.\n\n------------------------------------------------------------------------------\n                                                  *MiniAi.gen_spec.treesitter()*\n              `MiniAi.gen_spec.treesitter`({ai_captures}, {opts})\nTreesitter specification\n\nThis is a specification in function form. When called with a pair of\ntreesitter captures, it returns a specification function outputting an\narray of regions that match corresponding (`a` or `i`) capture.\n\nIn order for this to work, apart from working treesitter parser for desired\nlanguage, user should have a reachable language-specific 'textobjects'\nquery (see |vim.treesitter.query.get()|).\nThe most straightforward way for this is to have 'textobjects.scm' query\nfile with treesitter captures stored in some recognized path. This is\nprimarily designed to be compatible with plugin\n'nvim-treesitter/nvim-treesitter-textobjects', but can be used without it.\n\nTwo most common approaches for having a query file:\n- Install 'nvim-treesitter/nvim-treesitter-textobjects'. It has curated and\n  well maintained builtin query files for many languages with a standardized\n  capture names, like `function.outer`, `function.inner`, etc.\n- Manually create file 'after/queries/<language name>/textobjects.scm' in\n  your |$XDG_CONFIG_HOME| directory. It should contain queries with\n  captures (later used to define textobjects). See |lua-treesitter-query|.\nTo verify that query file is reachable, run (example for \"lua\" language,\noutput should have at least an intended file): >vim\n\n  :lua print(vim.inspect(vim.treesitter.query.get_files('lua','textobjects')))\n<\nExample configuration for function definition textobject with\n'nvim-treesitter/nvim-treesitter-textobjects' captures:\n>lua\n  local spec_treesitter = require('mini.ai').gen_spec.treesitter\n  require('mini.ai').setup({\n    custom_textobjects = {\n      F = spec_treesitter({ a = '@function.outer', i = '@function.inner' }),\n      o = spec_treesitter({\n        a = { '@conditional.outer', '@loop.outer' },\n        i = { '@conditional.inner', '@loop.inner' },\n      })\n    }\n  })\n<\nNotes:\n- Be sure that query files don't contain unknown |treesitter-directives|\n  (like `#make-range!`, for example). Otherwise textobject for such capture\n  might not be found as |lua-treesitter-core| won't treat them as captures.\n  Verify with `:=vim.treesitter.query.get('lang', 'textobjects')` and see\n  if the target capture is recognized as one.\n- It uses buffer's |filetype| to determine query language.\n- On large files it is slower than pattern-based textobjects. Still very\n  fast though (one search should be magnitude of milliseconds or tens of\n  milliseconds on really large file).\n\nParameters ~\n{ai_captures} `(table)` Captures for `a` and `i` textobjects: table with\n  <a> and <i> fields with captures for `a` and `i` textobjects respectively.\n  Each value can be either a string capture (should start with `'@'`) or an\n  array of such captures (best among all matches will be chosen).\n{opts} `(table|nil)` Options. Possible values:\n  - <use_nvim_treesitter> - whether to try to use 'nvim-treesitter' plugin\n    (if present) to do the query. It used to implement more advanced behavior\n    and more coherent experience if 'nvim-treesitter-textobjects' queries are\n    used. However, as |lua-treesitter-core| methods are more capable now,\n    the option will soon be removed. Only present for backward compatibility.\n    Default: `false`.\n\nReturn ~\n`(function)` Function with |MiniAi.find_textobject()| signature which\n  returns array of current buffer regions representing matches for\n  corresponding (`a` or `i`) treesitter capture.\n\nSee also ~\n- |MiniAi-textobject-specification| for how this type of textobject\n  specification is processed.\n- |vim.treesitter.query.get()| for how query is fetched.\n- |Query:iter_captures()| for how all query captures are iterated in case of\n  no 'nvim-treesitter'.\n\n------------------------------------------------------------------------------\n                                                 *MiniAi.gen_spec.user_prompt()*\n                        `MiniAi.gen_spec.user_prompt`()\nSpecification from user prompt\n\n- Ask user for left and right textobject edges as raw strings (no pattern).\n- Construct specification for a textobject that matches from left edge string\n  to right edge string: `a` includes both strings, `i` only insides.\n\nUsed for |MiniAi-builtin-textobjects| with identifier `?`.\n\nReturn ~\n`(function)` Textobject specification as function.\n\n------------------------------------------------------------------------------\n                                                    *MiniAi.select_textobject()*\n              `MiniAi.select_textobject`({ai_type}, {id}, {opts})\nVisually select textobject region\n\nDoes nothing if no region is found.\n\nParameters ~\n{ai_type} `(string)` One of `'a'` or `'i'`.\n{id} `(string)` Single character string representing textobject id.\n{opts} `(table|nil)` Same as in |MiniAi.find_textobject()|. Extra fields:\n  - <vis_mode> - One of `'v'`, `'V'`, or `'\\22'` (escaped version of `'<C-v>'`).\n    Default: Latest visual mode.\n  - <operator_pending> - Whether selection is for Operator-pending mode.\n    Used in that mode's mappings, shouldn't be used directly. Default: `false`.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-align.txt",
    "content": "*mini.align* Align text interactively\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                     *MiniAlign*\nRich and flexible customization of both alignment rules and user interaction.\nWorks with charwise, linewise, and blockwise selections in both Normal mode\n(on textobject/motion; with dot-repeat) and Visual mode.\n\nFeatures:\n- Alignment is done in three main steps:\n    - <Split> lines into parts based on Lua pattern(s) or user-supplied rule.\n    - <Justify> parts for certain side(s) to be same width inside columns.\n    - <Merge> parts to be lines, with customizable delimiter(s).\n\n    Each main step can be preceded by other steps (pre-steps) to achieve\n    highly customizable outcome. See `steps` value in |MiniAlign.config|.\n    For more details, see |MiniAlign-glossary| and |MiniAlign-algorithm|.\n\n- User can control alignment interactively by pressing customizable modifiers\n  (single keys representing how alignment steps and/or options should change).\n  Some of default modifiers:\n    - Press `s` to enter split Lua pattern.\n    - Press `j` to choose justification side from available ones (\"left\",\n      \"center\", \"right\", \"none\").\n    - Press `m` to enter merge delimiter.\n    - Press `f` to enter filter Lua expression to configure which parts\n      will be affected (like \"align only first column\").\n    - Press `i` to ignore some commonly unwanted split matches.\n    - Press `p` to pair neighboring parts so they be aligned together.\n    - Press `t` to trim whitespace from parts.\n    - Press `<BS>` (backspace) to delete some last pre-step.\n\n    For more details, see |MiniAlign-modifiers-builtin| and |MiniAlign-examples|.\n\n- Alignment can be done with instant preview (result is updated after each\n  modifier) or without it (result is shown and accepted after non-default\n  split pattern is set).\n\n- Every user interaction is accompanied with helper status message showing\n  relevant information about current alignment process.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.align').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniAlign`\nwhich you can use for scripting or manually (with `:lua MiniAlign.*`).\n\nSee |MiniAlign.config| for available config settings.\n\nYou can override runtime config settings (like `config.modifiers`) locally\nto buffer inside `vim.b.minialign_config` which should have same structure\nas `MiniAlign.config`. See |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Comparisons ~\n\n- [junegunn/vim-easy-align](https://github.com/junegunn/vim-easy-align):\n    - 'mini.align' is mostly designed after 'junegunn/vim-easy-align', so\n      there are a lot of similarities.\n    - Both plugins allow users to change alignment options interactively by\n      pressing modifier keys (albeit completely different default ones).\n      'junegunn/vim-easy-align' has those modifiers fixed, while 'mini.align'\n      allows their full customization. See |MiniAlign.config| for examples.\n    - 'junegunn/vim-easy-align' is designed to treat delimiters differently\n      than other parts of strings. 'mini.align' doesn't distinguish split\n      parts from one another by design: splitting is allowed to be done\n      based on some other logic than by splitting on delimiters.\n    - 'junegunn/vim-easy-align' initially aligns by only first delimiter.\n      'mini.align' initially aligns by all delimiter.\n    - 'junegunn/vim-easy-align' implements special filtering by delimiter\n      row number. 'mini.align' has builtin filtering based on Lua code\n      supplied by user in modifier phase. See |MiniAlign.gen_step.filter()|\n      and 'f' builtin modifier.\n    - 'mini.align' treats any non-registered modifier as a plain delimiter\n      pattern, while 'junegunn/vim-easy-align' does not.\n    - 'mini.align' exports core Lua function used for aligning strings\n      (|MiniAlign.align_strings()|).\n- [godlygeek/tabular](https://github.com/godlygeek/tabular):\n    - 'godlygeek/tabular' is mostly designed around single command which is\n      customized by printing its parameters. 'mini.align' implements\n      different concept of interactive alignment through pressing\n      customizable single character modifiers.\n    - 'godlygeek/tabular' can detect region upon which alignment can be\n      desirable. 'mini.align' does not by design: use Visual selection or\n      textobject/motion to explicitly define region to align.\n\n# Disabling ~\n\nTo disable, set `vim.g.minialign_disable` (globally) or `vim.b.minialign_disable`\n(for a buffer) to `true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                            *MiniAlign-glossary*\nPARTS ~\n2d array of strings (array of arrays of strings).\nSee more in |MiniAlign.as_parts()|.\n\nROW ~\nFirst-level array of parts (like `parts[1]`).\n\nCOLUMN ~\nArray of strings, constructed from parts elements with the same\nsecond-level index (like `{ parts[1][1],` `parts[2][1], ... }`).\n\nSTEP ~\nA named callable. See |MiniAlign.new_step()|. When used in terms of alignment\nsteps, callable takes two arguments: some object (parts or string array)\nand option table.\n\nSPLIT ~\nProcess of taking array of strings and converting it into parts.\n\nJUSTIFY ~\nProcess of taking parts and converting them to aligned parts (all elements\nhave same widths inside columns).\n\nMERGE ~\nProcess of taking parts and converting it back to array of strings. Usually\nby concatenating rows into strings.\n\nREGION ~\nTable representing region in a buffer. Fields <from> / <to> have inclusive\nstart / end positions (<to> might be `nil` to describe empty region).\nPositions are also tables with <line> and <col> fields (both start at 1).\n\nMODE ~\nEither charwise (\"char\", `v`, |charwise|), linewise (\"line\", `V`, |linewise|)\nor blockwise (\"block\", `<C-v>`, |blockwise-visual|)\n\n------------------------------------------------------------------------------\n                                                           *MiniAlign-algorithm*\nThere are two main processes implemented in 'mini.align': strings alignment\nand interactive region alignment. See |MiniAlign-glossary| for more information\nabout used terms.\n\n# Strings alignment ~\n\nMain implementation is in |MiniAlign.align_strings()|. Its input is array of\nstrings and output - array of aligned strings. The process consists from three\nmain steps (split, justify, merge) which can be preceded by any number of\npreliminary steps (pre-split, pre-justify, pre-merge).\n\nAlgorithm:\n- <Pre-split>. Take input array of strings and consecutively apply all\n  pre-split steps (`steps.pre_split`). Each one has `(strings, opts)` signature\n  and should modify array in place.\n- <Split>. Take array of strings and convert it to parts with `steps.split()`.\n  It has `(strings, opts)` signature and should return parts.\n- <Pre-justify>. Take parts and consecutively apply all pre-justify\n  steps (`steps.pre_justify`). Each one has `(parts, opts)` signature and\n  should modify parts in place.\n- <Justify>. Take parts and apply `steps.justify()`. It has `(parts, opts)`\n  signature and should modify parts in place.\n- <Pre-merge>. Take parts and consecutively apply all pre-merge\n  steps (`steps.pre_merge`). Each one has `(parts, opts)` signature and\n  should modify parts in place.\n- <Merge>. Take parts and convert it to array of strings with `steps.merge()`.\n  It has `(parts, opts)` signature and should return array of strings.\n\nNotes:\n- All table objects are initially copied so that modification in place doesn't\n  affect workflow.\n- Default main steps are designed to be controlled via options. See\n  |MiniAlign.align_strings()| and default step entries in |MiniAlign.gen_step|.\n- All steps are guaranteed to take same option table as second argument.\n  This allows steps to \"talk\" to each other, i.e. earlier steps can pass data\n  to later ones.\n\n# Interactive region alignment ~\n\nInteractive alignment is a main entry point for most users. It can be done\nin two flavors:\n- <Without-preview>. Initiated via mapping defined in `start` of\n  `MiniAlign.config.mappings`. Alignment is accepted once split pattern becomes\n  non-default.\n- <With-preview>. Initiated via mapping defined in `start_with_preview` of\n  `MiniAlign.config.mappings`. Alignment result is shown after every modifier\n  and is accepted after `<CR>` (`Enter`) is hit. Note: each preview is done by\n  applying current alignment steps and options to the initial region lines,\n  not the ones currently displaying in preview.\n\nLifecycle (assuming default mappings):\n- <Initiate-alignment>:\n    - In Normal mode type `ga` (or `gA` to show preview) followed by textobject\n      or motion defining region to be aligned.\n    - In Visual mode select region and type `ga` (or `gA` to show preview).\n  Strings contained in selected region will be used as input to\n  |MiniAlign.align_strings()|.\n  Beware of mode when selecting region: charwise (`v`), linewise (`V`), or\n  blockwise (`<C-v>`). They all behave differently.\n- <Press-modifiers>. Press single keys one at a time:\n    - If pressed key is among table keys of `modifiers` table of\n      |MiniAlign.config|, its function value is executed. It usually modifies\n      some options(s) and/or affects some pre-step(s).\n    - If pressed key is not among defined modifiers, it is treated as plain\n      split pattern.\n  This process can either end by itself (usually in case of no preview and\n  non-default split pattern being set) or you can choose to end it manually.\n- <Accept-or-discard>. In case of active preview, accept current result by\n  pressing `<CR>`. Discard any result and return to initial regions with\n  either `<Esc>` or `<C-c>`.\n\nSee more in |MiniAlign-modifiers-builtin| and |MiniAlign-examples|.\n\nNotes:\n- Visual blockwise selection works best with 'virtualedit' equal to \"block\"\n  or \"all\".\n- Alignment with preview works best with 'showmode' disabled.\n\n------------------------------------------------------------------------------\n                                                   *MiniAlign-modifiers-builtin*\nOverview of builtin modifiers\n\nAll examples assume interactive alignment with preview in linewise mode. With\ndefault mappings, use `V` to select lines and `gA` to initiate alignment. It\nmight be helpful to copy lines into modifiable buffer and experiment yourself.\n\nNotes:\n- Any pressed key which doesn't have defined modifier will be treated as\n  plain split pattern.\n- All modifiers can be customized inside |MiniAlign.setup()|. See \"Modifiers\"\n  section of |MiniAlign.config|.\n\n# Main option modifiers ~\n\n<s> Enter split pattern (confirm prompt by pressing `<CR>`). Input is treated\n  as plain delimiter.\n\n  Before: >\n  a-b-c\n  aa-bb-cc\n<\n  After typing `s-<CR>`: >\n  a -b -c\n  aa-bb-cc\n<\n<j> Choose justify side. Prompts user (with helper message) to type single\n  character identifier of side: `l`eft, `c`enter, `r`ight, `n`one.\n\n  Before: >\n  a_b_c\n  aa_bb_cc\n<\n  After typing `_jr` (first make split by `_`): >\n   a_ b_ c\n  aa_bb_cc\n<\n<m> Enter merge delimiter (confirm prompt by pressing `<CR>`).\n\n  Before: >\n  a_b_c\n  aa_bb_cc\n<\n  After typing `_m--<CR>` (first make split by `_`): >\n  a --_--b --_--c\n  aa--_--bb--_--cc\n<\n# Modifiers adding pre-steps ~\n\n<f> Enter filter expression. See more details in |MiniAlign.gen_step.filter()|.\n\n  Before: >\n  a_b_c\n  aa_bb_cc\n<\n  After typing `_fn==1<CR>` (first make split by `_`): >\n  a _b_c\n  aa_bb_cc\n<\n<i> Ignore some split matches. It modifies `split_exclude_patterns` option by\n  adding commonly wanted patterns. See more details in\n  |MiniAlign.gen_step.ignore_split()|.\n\n  Before: >\n  /* This_is_assumed_to_be_comment */\n  a\"_\"_b\n  aa_bb\n<\n  After typing `_i` (first make split by `_`): >\n  /* This_is_assumed_to_be_comment */\n  a\"_\"_b\n  aa  _bb\n<\n<p> Pair neighboring parts.\n\n  Before: >\n  a_b_c\n  aaa_bbb_ccc\n<\n  After typing `_p` (first make split by `_`): >\n  a_  b_  c\n  aaa_bbb_ccc\n<\n<t> Trim parts from whitespace on both sides (keeping indentation).\n\n  Before: >\n  a   _   b   _   c\n    aa _bb _cc\n<\n  After typing `_t` (first make split by `_`): >\n  a   _b _c\n    aa_bb_cc\n<\n# Delete some last pre-step ~\n\n<BS> Delete one of the pre-steps. If there is only one kind of pre-steps,\n  remove its latest added one. If not, prompt user to choose pre-step kind\n  by entering single character: `s`plit, `j`ustify, `m`erge.\n\n  Examples:\n  - `tp<BS>` results in only \"trim\" step to be left.\n  - `it<BS>` prompts to choose which step to delete (pre-split or\n    pre-justify in this case).\n\n# Special configurations for common splits ~\n\n<=> Use special pattern to align by a group of consecutive \"=\". It can be\n  preceded by any number of punctuation marks and followed by some sommon\n  punctuation characters. Trim whitespace and merge with single space.\n\n  Before: >\n  a=b\n  aa<=bb\n  aaa===bbb\n  aaaa   =   cccc\n<\n  After typing `=`: >\n  a    =   b\n  aa   <=  bb\n  aaa  === bbb\n  aaaa =   cccc\n<\n<,> Besides splitting by \",\" character, trim whitespace, pair neighboring\n  parts and merge with single space.\n\n  Before: >\n  a,b\n  aa,bb\n  aaa    ,    bbb\n<\n  After typing `,`: >\n  a,   b\n  aa,  bb\n  aaa, bbb\n<\n<|> Split by \"|\" character, trim whitespace, merge with single space.\n\n  Before: >\n  |a|b|\n  |aa|bb|\n  |aaa    |    bbb   |\n<\n  After typing `|`: >\n  | a   | b   |\n  | aa  | bb  |\n  | aaa | bbb |\n<\n<Space> (Space bar) Squash consecutive whitespace into single space (except\n  possible indentation) and split by `%s+` pattern (keeps indentation).\n\n  Before: >\n  a b c\n    aa    bb   cc\n<\n  After typing `<Space>`: >\n    a  b  c\n    aa bb cc\n<\n------------------------------------------------------------------------------\n                                                            *MiniAlign-examples*\nCopy lines in modifiable buffer, initiate alignment with preview (`gAip`)\nand try typing suggested key sequences.\nThese are modified examples taken from 'junegunn/vim-easy-align'.\n\n# Equal sign ~\n\nLines: >\n\n  # This=is=assumed=to be a comment\n  \"a =\"\n  a =\n  a = 1\n  bbbb = 2\n  ccccccc = 3\n  ccccccccccccccc\n  ddd = 4\n  eeee === eee = eee = eee=f\n  fff = ggg += gg &&= gg\n  g != hhhhhhhh == 888\n  i   := 5\n  i     %= 5\n  i       *= 5\n  j     =~ 5\n  j   >= 5\n  aa      =>         123\n  aa <<= 123\n  aa        >>= 123\n  bbb               => 123\n  c     => 1233123\n  d   =>      123\n  dddddd &&= 123\n  dddddd ||= 123\n  dddddd /= 123\n  gg <=> ee\n<\nKey sequences:\n- `=`\n- `=jc`\n- `=jr`\n- `=m!<CR>`\n- `=p`\n- `=i` (execute `:lua vim.o.commentstring = '# %s'` for full experience)\n- `=<BS>`\n- `=<BS>p`\n- `=fn==1<CR>`\n- `=<BS>fn==1<CR>t`\n- `=frow>7<CR>`\n\n------------------------------------------------------------------------------\n                                                             *MiniAlign.setup()*\n                          `MiniAlign.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniAlign.config|.\n\nUsage ~\n>lua\n  require('mini.align').setup() -- use default config\n  -- OR\n  require('mini.align').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                              *MiniAlign.config*\n                               `MiniAlign.config`\nDefaults ~\n>lua\n  MiniAlign.config = {\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      start = 'ga',\n      start_with_preview = 'gA',\n    },\n\n    -- Modifiers changing alignment steps and/or options\n    modifiers = {\n      -- Main option modifiers\n      ['s'] = --<function: enter split pattern>,\n      ['j'] = --<function: choose justify side>,\n      ['m'] = --<function: enter merge delimiter>,\n\n      -- Modifiers adding pre-steps\n      ['f'] = --<function: filter parts by entering Lua expression>,\n      ['i'] = --<function: ignore some split matches>,\n      ['p'] = --<function: pair parts>,\n      ['t'] = --<function: trim parts>,\n\n      -- Delete some last pre-step\n      ['<BS>'] = --<function: delete some last pre-step>,\n\n      -- Special configurations for common splits\n      ['='] = --<function: enhanced setup for '='>,\n      [','] = --<function: enhanced setup for ','>,\n      ['|'] = --<function: enhanced setup for '|'>,\n      [' '] = --<function: enhanced setup for ' '>,\n    },\n\n    -- Default options controlling alignment process\n    options = {\n      split_pattern = '',\n      justify_side = 'left',\n      merge_delimiter = '',\n    },\n\n    -- Default steps performing alignment (if `nil`, default is used)\n    steps = {\n      pre_split = {},\n      split = nil,\n      pre_justify = {},\n      justify = nil,\n      pre_merge = {},\n      merge = nil,\n    },\n\n    -- Whether to disable showing non-error feedback\n    -- This also affects (purely informational) helper messages shown after\n    -- idle time if user input is required.\n    silent = false,\n  }\n<\n# Modifiers ~\n\n`MiniAlign.config.modifiers` is used to define interactive user experience\nof managing alignment process. It is a table with single character keys and\nmodifier function values.\n\nEach modifier function:\n- Is called when corresponding modifier key is pressed.\n- Has signature `(steps, opts)` and should modify any of its input in place.\n\nExamples:\n- Modifier function used for default 'i' modifier: >lua\n\n  function(steps, _)\n    table.insert(steps.pre_split, MiniAlign.gen_step.ignore_split())\n  end\n<\n- Tweak 't' modifier to use highest indentation instead of keeping it: >lua\n\n  require('mini.align').setup({\n    modifiers = {\n      t = function(steps, _)\n        local trim_high = MiniAlign.gen_step.trim('both', 'high')\n        table.insert(steps.pre_justify, trim_high)\n      end\n    }\n  })\n<\n- Tweak `j` modifier to cycle through available \"justify_side\" option\n  values (like in 'junegunn/vim-easy-align'): >lua\n\n  require('mini.align').setup({\n    modifiers = {\n      j = function(_, opts)\n        local next_option = ({\n          left = 'center', center = 'right', right = 'none', none = 'left',\n        })[opts.justify_side]\n        opts.justify_side = next_option or 'left'\n      end,\n    },\n  })\n<\n# Options ~\n\n`MiniAlign.config.options` defines default values of options used to control\nbehavior of steps.\n\nExamples:\n- Set `justify_side = 'center'` to center align at initialization.\n\nFor more details about options see |MiniAlign.align_strings()| and entries of\n|MiniAlign.gen_step| for default main steps.\n\n# Steps ~\n\n`MiniAlign.config.steps` defines default steps to be applied during\nalignment process.\n\nExamples:\n- Align by default only first pair of columns: >lua\n\n  local align = require('mini.align')\n  align.setup({\n    steps = {\n      pre_justify = { align.gen_step.filter('n == 1') }\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                                     *MiniAlign.align_strings()*\n             `MiniAlign.align_strings`({strings}, {opts}, {steps})\nAlign strings\n\nFor details about alignment process see |MiniAlign-algorithm|.\n\nParameters ~\n{strings} `(table)` Array of strings.\n{opts} `(table|nil)` Options. Its copy will be passed to steps as second\n  argument. Extended with `MiniAlign.config.options`.\n  This is a place to control default main steps:\n  - `opts.split_pattern` - Lua pattern(s) used to make split parts.\n  - `opts.split_exclude_patterns` - which split matches should be ignored.\n  - `opts.justify_side` - which direction(s) alignment should be done.\n  - `opts.justify_offsets` - offsets tweaking width of first column\n  - `opts.merge_delimiter` - which delimiter(s) to use when merging.\n  For more information see |MiniAlign.gen_step| entry for corresponding\n  default step.\n{steps} `(table|nil)` Steps. Extended with `MiniAlign.config.steps`.\n  Possible `nil` values are replaced with corresponding default steps:\n  - `split` - |MiniAlign.gen_step.default_split()|.\n  - `justify` - |MiniAlign.gen_step.default_justify()|.\n  - `merge` - |MiniAlign.gen_step.default_merge()|.\n\n------------------------------------------------------------------------------\n                                                        *MiniAlign.align_user()*\n                         `MiniAlign.align_user`({mode})\nAlign current region with user-supplied steps\n\nMostly designed to be used inside mappings.\n\nWill use |MiniAlign.align_strings()| and set the following options in `opts`:\n- `justify_offsets` - array of offsets used to achieve actual alignment of\n  a region. It is non-trivial (not array of zeros) only for charwise\n  selection: offset of first string is computed as width of prefix to the\n  left of region start.\n- `region` - current affected region (see |MiniAlign-glossary|). Can be\n  used to create more advanced steps.\n- `mode` - mode of selection (see |MiniAlign-glossary|).\n\nParameters ~\n{mode} `(string)` Selection mode. One of \"char\", \"line\", \"block\".\n\n------------------------------------------------------------------------------\n                                                          *MiniAlign.as_parts()*\n                         `MiniAlign.as_parts`({arr2d})\nConvert 2d array of strings to parts\n\nThis function verifies if input is a proper 2d array of strings and adds\nmethods to its copy.\n\nClass ~\n{parts}\n\nFields ~\n{apply} `(function)` Takes callable `f` and applies it to every part.\n  Callable should have signature `(s, data)`: `s` is a string part,\n  `data` - table with its data (<row> has row number, <col> has column number).\n  Returns new 2d array.\n\n{apply_inplace} `(function)` Takes callable `f` and applies it to every part.\n  Should have same signature as in `apply` method. Outputs (should all be\n  strings) are assigned in place to a corresponding parts element. Returns\n  parts itself to enable method chaining.\n\n{get_dims} `(function)` Return dimensions of parts array: a table with\n  <row> and <col> keys having number of rows and number of columns (maximum\n  number of elements across all rows).\n\n{group} `(function)` Concatenate neighboring strings based on supplied\n  boolean mask and direction (one of \"left\", default, or \"right\"). Has\n  signature `(mask, direction)` and modifies parts in place. Returns parts\n  itself to enable method chaining.\n  Example:\n  - Parts: `{ { \"a\", \"b\", \"c\" }, { \"d\", \"e\" }, { \"f\" } }`\n  - Mask: `{ { false, false, true }, { true, false }, { false } }`\n  - Result for direction \"left\":  `{ { \"abc\" },    { \"d\", \"e\" }, { \"f\" } }`\n  - Result for direction \"right\": `{ { \"ab\",\"c\" }, { \"de\" },     { \"f\" } }`\n\n{pair} `(function)` Concatenate neighboring element pairs. Takes\n  `direction` as input (one of \"left\", default, or \"right\") and applies\n  `group()` for an alternating mask.\n  Example:\n  - Parts: `{ { \"a\", \"b\", \"c\" }, { \"d\", \"e\" }, { \"f\" } }`\n  - Result for direction \"left\":  `{ { \"ab\", \"c\" }, { \"de\" }, { \"f\" } }`\n  - Result for direction \"right\": `{ { \"a\", \"bc\" }, { \"de\" }, { \"f\" } }`\n\n{slice_col} `(function)` Return column with input index `j`. Note: it might\n  not be an array if rows have unequal number of columns.\n\n{slice_row} `(function)` Return row with input index `i`.\n\n{trim} `(function)` Trim elements whitespace. Has signature `(direction, indent)`\n  and modifies parts in place. Returns parts itself to enable method chaining.\n  - Possible values of `direction`: \"both\" (default), \"left\", \"right\",\n  \"none\". Defines from which side whitespaces should be removed.\n  - Possible values of `indent`: \"keep\" (default), \"low\", \"high\", \"remove\".\n  Defines what to do with possible indent (left whitespace of first string\n  in a row). Value \"keep\" keeps it; \"low\" makes all indent equal to the\n  lowest across rows; \"high\" - highest across rows; \"remove\" - removes indent.\n\nUsage ~\n>lua\n  parts = MiniAlign.as_parts({ { 'a', 'b' }, { 'c' } })\n  print(vim.inspect(parts.get_dims())) -- Should be { row = 2, col = 2 }\n\n  parts.apply_inplace(function(s, data)\n    return ' ' .. data.row .. s .. data.col .. ' '\n  end)\n  print(vim.inspect(parts)) -- Should be { { ' 1a1 ', ' 1b2 ' }, { ' 2c1 ' } }\n\n  parts.trim('both', 'remove').pair()\n  print(vim.inspect(parts)) -- Should be { { '1a11b2' }, { '2c1' } }\n<\n------------------------------------------------------------------------------\n                                                          *MiniAlign.new_step()*\n                     `MiniAlign.new_step`({name}, {action})\nCreate step\n\nA step is basically a named callable object. Having a name bundled with\nsome action powers helper status message during interactive alignment process.\n\nParameters ~\n{name} `(string)` Step name.\n{action} `(function|table)` Step action. Should be a callable object\n  (see |vim.is_callable()|).\n\nReturn ~\n`(table)` A table with keys: <name> with `name` argument, <action> with `action`.\n\n------------------------------------------------------------------------------\n                                                            *MiniAlign.gen_step*\n                              `MiniAlign.gen_step`\nGenerate common action steps\n\nThis is a table with function elements. Call to actually get step.\n\nEach step action is a function that has signature `(object, opts)`, where\n`object` is either parts or array of strings (depends on which stage of\nalignment process it is assumed to be applied) and `opts` is table of options.\n\nOutputs of elements named `default_*` are used as default corresponding main\nstep (split, justify, merge). Behavior of all of them depend on values from\nsupplied options (second argument).\n\nOutputs of other elements depend on both step generator input values and\noptions supplied at execution. This design is mostly because their output\ncan be used several times in pre-steps.\n\nUsage ~\n>lua\n  local align = require('mini.align')\n  align.setup({\n    modifiers = {\n      -- Use 'T' modifier to remove both whitespace and indent\n      T = function(steps, _)\n        table.insert(steps.pre_justify, align.gen_step.trim('both', 'remove'))\n      end,\n    },\n    options = {\n      -- By default align \"right\", \"left\", \"right\", \"left\", ...\n      justify_side = { 'right', 'left' },\n    },\n    steps = {\n      -- Align by default only first pair of columns\n      pre_justify = { align.gen_step.filter('n == 1') },\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                            *MiniAlign.gen_step.default_split()*\n                      `MiniAlign.gen_step.default_split`()\nGenerate default split step\n\nOutput splits strings using matches of Lua pattern(s) from `split_pattern`\noption which are not dismissed by `split_exclude_patterns` option.\n\nOutline of how single string is split:\n- Convert `split_pattern` option to array of strings (string is converted\n  as one-element array). This array will be recycled in case there are more\n  split matches than in converted `split_pattern` array (which almost always).\n- Find all forbidden spans (intervals inside string) - all matches of all\n  patterns in `split_exclude_patterns`.\n- Find match for the next pattern. If it is not inside any forbidden span,\n  add preceding unmatched substring and matched split as two parts. Repeat\n  with the next pattern.\n- If no pattern match is found, add the rest of string as final part.\n\nOutput uses following options (as part second argument, `opts` table):\n- <split_pattern> - string or array of strings used to detect split matches\n  and create parts. Default: `''` meaning no matches (whole string is used\n  as part). Examples: `'%s+'`, `{ '<', '>' }`.\n- <split_exclude_patterns> - array of strings defining which regions to\n  exclude from being matched. Default: `{}`. Examples: `{ '\".-\"', '^%s*#.*' }`.\n\nReturn ~\n`(table)` A step named \"split\" and with appropriate callable action.\n\nSee also ~\n|MiniAlign.gen_step.ignore_split()| heavily uses `split_exclude_patterns`.\n\n------------------------------------------------------------------------------\n                                          *MiniAlign.gen_step.default_justify()*\n                     `MiniAlign.gen_step.default_justify`()\nGenerate default justify step\n\nOutput makes column elements of string parts have equal width by adding\nleft and/or right whitespace padding. Which side(s) to pad is defined by\n`justify_side` option. Width of first column can be tweaked with `justify_offsets`\noption.\n\nOutline of how parts are justified:\n- Convert `justify_side` option to array of strings (single string is\n  converted as one-element array). Recycle this array to have length equal\n  to number of columns in parts.\n- For all columns compute maximum width of strings from it (add offsets from\n  `justify_offsets` to first column widths). Note: for left alignment, width\n  of last row element does not affect column width. This is mainly because\n  it won't be padded and helps dealing with \"no single match\" lines.\n- Make all elements have same width inside column by adding appropriate\n  amount of whitespace. Which side(s) to add is controlled by the corresponding\n  `justify_side` array element. Note: padding is done with spaces which\n  might conflict with tab indentation.\n\nOutput uses following options (as part second argument, `opts` table):\n- <justify_side> - string or array of strings. Each element can be one of\n  \"left\" (pad right side), \"center\" (pad both sides equally), \"right\" (pad\n  left side), \"none\" (no padding). Default: \"left\".\n- <justify_offsets> - array of numeric left offsets of rows. Used to adjust\n  for possible not equal indents, like in case of charwise selection when\n  left edge is not on the first column. Default: array of zeros. Set\n  automatically during interactive alignment in charwise mode.\n\nReturn ~\n`(table)` A step named \"justify\" and with appropriate callable action.\n\n------------------------------------------------------------------------------\n                                            *MiniAlign.gen_step.default_merge()*\n                      `MiniAlign.gen_step.default_merge`()\nGenerate default merge step\n\nOutput merges rows of parts into strings by placing merge delimiter(s)\nbetween them.\n\nOutline of how parts are converted to array of strings:\n- Convert `merge_delimiter` option to array of strings (single string is\n  converted as one-element array). Recycle this array to have length equal\n  to number of columns in parts minus 1. Also possibly trim leading whitespace\n  in first merge character to not affect indentation.\n- Exclude empty strings from parts. They add nothing to output except extra\n  usage of merge delimiter.\n- Concatenate each row interleaving with array of merge delimiters.\n\nOutput uses following options (as part second argument, `opts` table):\n- <merge_delimiter> - string or array of strings. Default: `''`.\n  Examples: `' '`, `{ '', ' ' }`.\n\nReturn ~\n`(table)` A step named \"merge\" and with appropriate callable action.\n\n------------------------------------------------------------------------------\n                                                   *MiniAlign.gen_step.filter()*\n                      `MiniAlign.gen_step.filter`({expr})\nGenerate filter step\n\nConstruct function predicate from supplied Lua string expression and make\nstep evaluating it on every part element.\n\nOutline of how filtering is done:\n- Convert Lua filtering expression into function predicate which can be\n  evaluated in manually created context (some specific variables being set).\n- Compute boolean mask for parts by applying predicate to each element of\n  2d array with special variables set to specific values (see next section).\n- Group parts with computed mask. See `group()` method of parts in\n  |MiniAlign.as_parts()|.\n\nSpecial variables which can be used in expression:\n- <row> - row number of current element.\n- <ROW> - total number of rows in parts.\n- <col> - column number of current element.\n- <COL> - total number of columns in current row.\n- <s>   - string value of current element.\n- <n>   - column pair number of current element. Useful when filtering by\n          result of pattern splitting.\n- <N>   - total number of column pairs in current row.\n- All variables from global table `_G`.\n\nTips:\n- This general filtering approach can be used to both include and exclude\n  certain parts from alignment. Examples:\n    - Use `row ~= 2` to align all parts except from second row.\n    - Use `n == 1` to align only by first pair of columns.\n- Filtering by last equal sign usually can be done with `n >= (N - 1)`\n  (because there is usually something to the right of it).\n\nParameters ~\n{expr} `(string)` Lua expression as a string which will be used as predicate.\n\nReturn ~\n`(table|nil)` A step named \"filter\" and with appropriate callable action.\n\n------------------------------------------------------------------------------\n                                             *MiniAlign.gen_step.ignore_split()*\n        `MiniAlign.gen_step.ignore_split`({patterns}, {exclude_comment})\nGenerate ignore step\n\nOutput adds certain values to `split_exclude_patterns` option. Should be\nused as pre-split step.\n\nParameters ~\n{patterns} `(table)` Array of patterns to be added to\n  `split_exclude_patterns` as is. Default: `{ [[\".-\"]] }` (excludes strings\n  for most cases).\n{exclude_comment} `(boolean|nil)` Whether to add comment pattern to\n  `split_exclude_patterns`. Comment pattern is derived from 'commentstring'\n  option. Default: `true`.\n\nReturn ~\n`(table)` A step named \"ignore\" and with appropriate callable action.\n\nSee also ~\n|MiniAlign.gen_step.default_split()| for details about\n  `split_exclude_patterns` option.\n\n------------------------------------------------------------------------------\n                                                     *MiniAlign.gen_step.pair()*\n                     `MiniAlign.gen_step.pair`({direction})\nGenerate pair step\n\nOutput calls `pair()` method of parts (see |MiniAlign.as_parts()|) with\nsupplied `direction` argument.\n\nParameters ~\n{direction} `(string)` Which direction to pair. One of \"left\" (default) or\n\n\nReturn ~\n`(table)` A step named \"pair\" and with appropriate callable action.\n\n------------------------------------------------------------------------------\n                                                     *MiniAlign.gen_step.trim()*\n                `MiniAlign.gen_step.trim`({direction}, {indent})\nGenerate trim step\n\nOutput calls `trim()` method of parts (see |MiniAlign.as_parts()|) with\nsupplied `direction` and `indent` arguments.\n\nParameters ~\n{direction} `(string|nil)` Which sides to trim whitespace. One of \"both\"\n  (default), \"left\", \"right\", \"none\".\n{indent} `(string|nil)` What to do with possible indent (left whitespace\n  of first string in a row). One of \"keep\" (default), \"low\", \"high\", \"remove\".\n\nReturn ~\n`(table)` A step named \"trim\" and with appropriate callable action.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-animate.txt",
    "content": "*mini.animate* Animate common Neovim actions\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                   *MiniAnimate*\nFeatures:\n- Works out of the box with a single `require('mini.animate').setup()`.\n  No extra mappings or commands needed.\n\n- Animate cursor movement inside same buffer by showing customizable path.\n  See |MiniAnimate.config.cursor| for more details.\n\n- Animate scrolling with a series of subscrolls (\"smooth scrolling\").\n  See |MiniAnimate.config.scroll| for more details.\n\n- Animate window resize by gradually changing sizes of all windows.\n  See |MiniAnimate.config.resize| for more details.\n\n- Animate window open/close with visually updating floating window.\n  See |MiniAnimate.config.open| and |MiniAnimate.config.close| for more details.\n\n- Timings for all actions can be customized independently.\n  See |MiniAnimate-timing| for more details.\n\n- Action animations can be enabled/disabled independently.\n\n- All animations are asynchronous/non-blocking and trigger a targeted event\n  which can be used to perform actions after animation is done.\n\n- |MiniAnimate.animate()| function which can be used to perform own animations.\n\nNotes:\n- Cursor movement is animated inside same window and buffer, not as cursor\n  moves across the screen.\n\n- Scroll and resize animations are done with \"side effects\": they actually\n  change the state of what is animated (window view and sizes\n  respectively). This has a downside of possibly needing extra work to\n  account for asynchronous nature of animation (like adjusting certain\n  mappings, etc.). See |MiniAnimate.config.scroll| and\n  |MiniAnimate.config.resize| for more details.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.animate').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniAnimate`\nwhich you can use for scripting or manually (with `:lua MiniAnimate.*`).\n\nSee |MiniAnimate.config| for available config settings.\n\nYou can override runtime config settings (like `config.modifiers`) locally\nto buffer inside `vim.b.minianimate_config` which should have same structure\nas `MiniAnimate.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [Neovide](https://neovide.dev/):\n    - Neovide is a standalone GUI which has more control over its animations.\n      While 'mini.animate' works inside terminal emulator (with all its\n      limitations, like lack of pixel-size control over animations).\n    - Neovide animates cursor movement across screen, while 'mini.animate' -\n      as it moves across same buffer.\n    - Neovide has fixed number of animation effects per action, while\n      'mini.animate' is fully customizable.\n    - 'mini.animate' implements animations for window open/close, while\n      Neovide does not.\n- [edluffy/specs.nvim](https://github.com/edluffy/specs.nvim):\n    - 'mini.animate' approaches cursor movement visualization via\n      customizable path function (uses extmarks), while 'specs.nvim' can\n      customize within its own visual effects (shading and floating\n      window resizing).\n- [karb94/neoscroll.nvim](https://github.com/karb94/neoscroll.nvim):\n    - Scroll animation is triggered only inside dedicated mappings.\n      'mini.animate' animates scroll resulting from any window view change.\n- [anuvyklack/windows.nvim](https://github.com/anuvyklack/windows.nvim):\n    - Resize animation is done only within custom commands and mappings,\n      while 'mini.animate' animates any resize with appropriate values of\n      'winheight' / 'winwidth' and 'winminheight' / 'winminwidth').\n\n# Highlight groups ~\n\n- `MiniAnimateCursor` - highlight of cursor during its animated movement.\n- `MiniAnimateNormalFloat` - highlight of floating window for `open` and\n  `close` animations.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minianimate_disable` (globally) or\n`vim.b.minianimate_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                           *MiniAnimate.setup()*\n                         `MiniAnimate.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniAnimate.config|.\n\nUsage ~\n>lua\n  require('mini.animate').setup() -- use default config\n  -- OR\n  require('mini.animate').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                            *MiniAnimate.config*\n                              `MiniAnimate.config`\nDefaults ~\n>lua\n  MiniAnimate.config = {\n    -- Cursor path\n    cursor = {\n      -- Whether to enable this animation\n      enable = true,\n\n      -- Timing of animation (how steps will progress in time)\n      timing = --<function: linear animation, total 250ms>,\n\n      -- Path generator for visualized cursor movement\n      path = --<function: implements shortest line path no longer than 1000>,\n    },\n\n    -- Vertical scroll\n    scroll = {\n      -- Whether to enable this animation\n      enable = true,\n\n      -- Timing of animation (how steps will progress in time)\n      timing = --<function: linear animation, total 250ms>,\n\n      -- Subscroll generator based on total scroll\n      subscroll = --<function: implements equal scroll with at most 60 steps>,\n    },\n\n    -- Window resize\n    resize = {\n      -- Whether to enable this animation\n      enable = true,\n\n      -- Timing of animation (how steps will progress in time)\n      timing = --<function: linear animation, total 250ms>,\n\n      -- Subresize generator for all steps of resize animations\n      subresize = --<function: implements equal linear steps>,\n    },\n\n    -- Window open\n    open = {\n      -- Whether to enable this animation\n      enable = true,\n\n      -- Timing of animation (how steps will progress in time)\n      timing = --<function: linear animation, total 250ms>,\n\n      -- Floating window config generator visualizing specific window\n      winconfig = --<function: implements static window for 25 steps>,\n\n      -- 'winblend' (window transparency) generator for floating window\n      winblend = --<function: implements equal linear steps from 80 to 100>,\n    },\n\n    -- Window close\n    close = {\n      -- Whether to enable this animation\n      enable = true,\n\n      -- Timing of animation (how steps will progress in time)\n      timing = --<function: linear animation, total 250ms>,\n\n      -- Floating window config generator visualizing specific window\n      winconfig = --<function: implements static window for 25 steps>,\n\n      -- 'winblend' (window transparency) generator for floating window\n      winblend = --<function: implements equal linear steps from 80 to 100>,\n    },\n  }\n<\n# General ~\n\n- *MiniAnimate-timing* Every animation is a non-blockingly scheduled series of\n  specific actions. They are executed in a sequence of timed steps controlled\n  by `timing` option. It is a callable which, given next and total step numbers,\n  returns wait time (in ms).\n  See |MiniAnimate.gen_timing| for builtin timing functions.\n  See |MiniAnimate.animate()| for more details about animation process.\n\n- Every animation can be enabled/disabled independently by setting `enable`\n  option to `true`/`false`.\n\n- *MiniAnimate-done-event* Every animation triggers custom |User| event when it\n  is finished. It is named `MiniAnimateDoneXxx` with `Xxx` replaced by capitalized\n  supported animation action name (like `MiniAnimateDoneCursor`). Use it to\n  schedule some action after certain animation is completed. Alternatively,\n  you can use |MiniAnimate.execute_after()| (usually preferred in mappings).\n\n- Each animation has its main step generator which defines how particular\n  animation is done. They all are callables which take some input data and\n  return an array of step data. Length of that array determines number of\n  animation steps. Outputs `nil` and empty table result in no animation.\n\n# Cursor ~\n*MiniAnimate.config.cursor*\n\nThis animation is triggered for each movement of cursor inside same window\nand buffer. Its visualization step consists from placing single extmark (see\n|extmarks|) at certain position. This extmark contains single space and is\nhighlighted with `MiniAnimateCursor` highlight group.\n\nExact places of extmark and their number is controlled by `path` option. It\nis a callable which takes `destination` argument (2d integer point in\n`(line, col)` coordinates) and returns array of relative to `(0, 0)` places\nfor extmark to be placed. Example:\n- Input `(2, -3)` means cursor jumped 2 lines forward and 3 columns backward.\n- Output `{ {0, 0 }, { 0, -1 }, { 0, -2 }, { 0, -3 }, { 1, -3 } }` means\n  that path is first visualized along the initial line and then along final\n  column.\n\nSee |MiniAnimate.gen_path| for builtin path generators.\n\nNotes:\n- Input `destination` value is computed ignoring folds. This is by design\n  as it helps better visualize distance between two cursor positions.\n- Outputs of path generator resulting in a place where extmark can't be\n  placed are silently omitted during animation: this step won't show any\n  visualization.\n\nConfiguration example: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    cursor = {\n      -- Animate for 200 milliseconds with linear easing\n      timing = animate.gen_timing.linear({ duration = 200, unit = 'total' }),\n\n      -- Animate with shortest line for any cursor move\n      path = animate.gen_path.line({\n        predicate = function() return true end,\n      }),\n    }\n  })\n<\nAfter animation is done, `MiniAnimateDoneCursor` event is triggered.\n\n# Scroll ~\n*MiniAnimate.config.scroll*\n\nThis animation is triggered for each vertical scroll of current window.\nIts visualization step consists from performing a small subscroll which all\nin total will result into needed total scroll.\n\nExact subscroll values and their number is controlled by `subscroll` option.\nIt is a callable which takes `total_scroll` argument (single non-negative\ninteger) and returns array of non-negative integers each representing the\namount of lines needed to be scrolled inside corresponding step. All\nsubscroll values should sum to input `total_scroll`.\nExample:\n- Input `5` means that total scroll consists from 5 lines (either up or down,\n  which doesn't matter).\n- Output of `{ 1, 1, 1, 1, 1 }` means that there are 5 equal subscrolls.\n\nSee |MiniAnimate.gen_subscroll| for builtin subscroll generators.\n\nNotes:\n- Input value of `total_scroll` is computed taking folds into account.\n- As scroll animation is essentially a precisely scheduled non-blocking\n  subscrolls, this has two important interconnected consequences:\n    - If another scroll is attempted during the animation, it is done based\n      on the **currently visible** window view. Example: if user presses\n      |CTRL-D| and then |CTRL-U| when animation is half done, window will not\n      display the previous view half of 'scroll' above it. This especially\n      affects mouse wheel scrolling, as each its turn results in a new scroll\n      for number of lines defined by 'mousescroll'. Tweak it to your liking.\n    - It breaks the use of several relative scrolling commands in the same\n      command. Use |MiniAnimate.execute_after()| to schedule action after\n      reaching target window view.\n      Example: a useful `nnoremap n nzvzz` mapping (consecutive application\n      of |n|, |zv|, and |zz|) should be expressed in the following way: >lua\n\n        '<Cmd>lua vim.cmd(\"normal! n\"); ' ..\n          'MiniAnimate.execute_after(\"scroll\", \"normal! zvzz\")<CR>'\n<\n- Default timing might conflict with scrolling via holding a key (like `j` or `k`\n  with 'wrap' enabled) due to high key repeat rate: next scroll is done before\n  first step of current one finishes. Resolve this by not scrolling like that\n  or by ensuring maximum value of step duration to be lower than between\n  repeated keys: set timing like `function(_, n) return math.min(250/n, 10) end`\n  or use timing with constant step duration.\n\nConfiguration example: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    scroll = {\n      -- Animate for 200 milliseconds with linear easing\n      timing = animate.gen_timing.linear({ duration = 200, unit = 'total' }),\n\n      -- Animate equally but with at most 120 steps instead of default 60\n      subscroll = animate.gen_subscroll.equal({ max_output_steps = 120 }),\n    }\n  })\n<\nAfter animation is done, `MiniAnimateDoneScroll` event is triggered.\n\n# Resize ~\n*MiniAnimate.config.resize*\n\nThis animation is triggered for window resize while having same layout of\nsame windows. For example, it won't trigger when window is opened/closed or\nafter something like |CTRL-W_K|. Its visualization step consists from setting\ncertain sizes to all visible windows (last step being for \"true\" final sizes).\n\nExact window step sizes and their number is controlled by `subresize` option.\nIt is a callable which takes `sizes_from` and `sizes_to` arguments (both\ntables with window id as keys and dimension table as values) and returns\narray of same shaped data.\nExample:\n- Input: >lua\n\n  -- First\n  { [1000] = {width = 7, height = 5}, [1001] = {width = 7, height = 10} }\n  -- Second\n  { [1000] = {width = 9, height = 5}, [1001] = {width = 5, height = 10} }\n  -- Means window 1000 increased its width by 2 in expense of window 1001\n<\n- The following output demonstrates equal resizing: >lua\n\n  {\n    { [1000] = {width = 8, height = 5}, [1001] = {width = 6, height = 10} },\n    { [1000] = {width = 9, height = 5}, [1001] = {width = 5, height = 10} },\n  }\n<\nSee |MiniAnimate.gen_subresize| for builtin subresize generators.\n\nNotes:\n\n- As resize animation is essentially a precisely scheduled non-blocking\n  subresizes, this has two important interconnected consequences:\n    - If another resize is attempted during the animation, it is done based\n      on the **currently visible** window sizes. This might affect relative\n      resizing.\n    - It breaks the use of several relative resizing commands in the same\n      command. Use |MiniAnimate.execute_after()| to schedule action after\n      reaching target window sizes.\n\nConfiguration example: >lua\n\n  local is_many_wins = function(sizes_from, sizes_to)\n    return vim.tbl_count(sizes_from) >= 3\n  end\n  local animate = require('mini.animate')\n  animate.setup({\n    resize = {\n      -- Animate for 200 milliseconds with linear easing\n      timing = animate.gen_timing.linear({ duration = 200, unit = 'total' }),\n\n      -- Animate only if there are at least 3 windows\n      subresize = animate.gen_subscroll.equal({ predicate = is_many_wins }),\n    }\n  })\n<\nAfter animation is done, `MiniAnimateDoneResize` event is triggered.\n\n# Window open/close ~\n*MiniAnimate.config.open*\n*MiniAnimate.config.close*\n\nThese animations are similarly triggered for regular (non-floating) window\nopen/close. Their visualization step consists from drawing empty floating\nwindow with customizable config and transparency.\n\nExact window visualization characteristics are controlled by `winconfig`\nand `winblend` options.\n\nThe `winconfig` option is a callable which takes window id (|window-ID|) as\ninput and returns an array of floating window configs (as in `config`\nargument of |nvim_open_win()|). Its length determines number of animation steps.\nExample:\n- The following output results into two animation steps with second being\n  upper left quarter of a first: >lua\n\n  {\n    {\n      row      = 0,        col    = 0,\n      width    = 10,       height = 10,\n      relative = 'editor', anchor = 'NW',   focusable = false,\n      zindex   = 1,        border = 'none', style  = 'minimal',\n    },\n    {\n      row      = 0,        col    = 0,\n      width    = 5,        height = 5,\n      relative = 'editor', anchor = 'NW',   focusable = false,\n      zindex   = 1,        border = 'none', style  = 'minimal',\n    },\n  }\n<\nThe `winblend` option is similar to `timing` option: it is a callable\nwhich, given current and total step numbers, returns value of floating\nwindow's 'winblend' option. Note, that it is called for current step (so\nstarts from 0), as opposed to `timing` which is called before step.\nExample:\n- Function `function(s, n) return 80 + 20 * s / n end` results in linear\n  transition from `winblend` value of 80 to 100.\n\nSee |MiniAnimate.gen_winconfig| for builtin window config generators.\nSee |MiniAnimate.gen_winblend| for builtin window transparency generators.\n\nConfiguration example: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    open = {\n      -- Animate for 400 milliseconds with linear easing\n      timing = animate.gen_timing.linear({ duration = 400, unit = 'total' }),\n\n      -- Animate with wiping from nearest edge instead of default static one\n      winconfig = animate.gen_winconfig.wipe({ direction = 'from_edge' }),\n\n      -- Make bigger windows more transparent\n      winblend = animate.gen_winblend.linear({ from = 80, to = 100 }),\n    },\n\n    close = {\n      -- Animate for 400 milliseconds with linear easing\n      timing = animate.gen_timing.linear({ duration = 400, unit = 'total' }),\n\n      -- Animate with wiping to nearest edge instead of default static one\n      winconfig = animate.gen_winconfig.wipe({ direction = 'to_edge' }),\n\n      -- Make bigger windows more transparent\n      winblend = animate.gen_winblend.linear({ from = 100, to = 80 }),\n    },\n  })\n<\nAfter animation is done, `MiniAnimateDoneOpen` or `MiniAnimateDoneClose`\nevent is triggered for `open` and `close` animation respectively.\n\n------------------------------------------------------------------------------\n                                                       *MiniAnimate.is_active()*\n                   `MiniAnimate.is_active`({animation_type})\nCheck animation activity\n\nParameters ~\n{animation_type} `(string)` One of supported animation types\n  (entries of |MiniAnimate.config|, like `'cursor'`, etc.).\n\nReturn ~\n`(boolean)` Whether the animation is currently active.\n\n------------------------------------------------------------------------------\n                                                   *MiniAnimate.execute_after()*\n            `MiniAnimate.execute_after`({animation_type}, {action})\nExecute action after some animation is done\n\nExecute action immediately if animation is not active (checked with\n|MiniAnimate.is_active()|). Else, schedule its execution until after\nanimation is done (on corresponding \"done event\", see\n|MiniAnimate-done-event|).\n\nMostly meant to be used inside mappings.\n\nExample:\n\nA useful `nnoremap n nzvzz` mapping (consecutive application of |n|, |zv|, and |zz|)\nshould be expressed in the following way: >lua\n\n  '<Cmd>lua vim.cmd(\"normal! n\"); ' ..\n    'MiniAnimate.execute_after(\"scroll\", \"normal! zvzz\")<CR>'\n<\nParameters ~\n{animation_type} `(string)` One of supported animation types\n  (as in |MiniAnimate.is_active()|).\n{action} `(string|function)` Action to be executed. If string, executed as\n  command (via |vim.cmd()|).\n\n------------------------------------------------------------------------------\n                                                         *MiniAnimate.animate()*\n          `MiniAnimate.animate`({step_action}, {step_timing}, {opts})\nAnimate action\n\nThis is equivalent to asynchronous execution of the following algorithm:\n- Call `step_action(0)` immediately after calling this function. Stop if\n  action returned `false` or `nil`.\n- Wait `step_timing(1)` milliseconds.\n- Call `step_action(1)`. Stop if it returned `false` or `nil`.\n- Wait `step_timing(2)` milliseconds.\n- Call `step_action(2)`. Stop if it returned `false` or `nil`.\n- ...\n\nNotes:\n- Animation is also stopped on action error or if maximum number of steps\n  is reached.\n- Asynchronous execution is done with |uv.new_timer()|. It only allows\n  integer parts as repeat value. This has several implications:\n    - Outputs of `step_timing()` are accumulated in order to preserve total\n      execution time.\n    - Any wait time less than 1 ms means that action will be executed\n      immediately.\n\nParameters ~\n{step_action} `(function|table)` Callable which takes `step` (integer 0, 1, 2,\n  etc. indicating current step) and executes some action. Its return value\n  defines when animation should stop: values `false` and `nil` (equivalent\n  to no explicit return) stop animation timer; any other continues it.\n{step_timing} `(function|table)` Callable which takes `step` (integer 1, 2, etc.\n  indicating next step) and returns how many milliseconds to wait before\n  executing this step action.\n{opts} `(table|nil)` Options. Possible fields:\n  - <max_steps> - Maximum value of allowed step to execute. Default: 10000000.\n\n------------------------------------------------------------------------------\n                                                        *MiniAnimate.gen_timing*\n                            `MiniAnimate.gen_timing`\nGenerate animation timing\n\nEach field corresponds to one family of progression which can be customized\nfurther by supplying appropriate arguments.\n\nThis is a table with function elements. Call to actually get timing function.\n\nExample: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    cursor = {\n      timing = animate.gen_timing.linear({ duration = 100, unit = 'total' })\n    },\n  })\n<\nSee also ~\n|MiniIndentscope.gen_animation| for similar concept in 'mini.indentscope'.\n\n------------------------------------------------------------------------------\n                                                 *MiniAnimate.gen_timing.none()*\n                        `MiniAnimate.gen_timing.none`()\nGenerate timing with no animation\n\nShow final result immediately. Usually better to use `enable` field in `config`\nif you want to disable animation.\n\n------------------------------------------------------------------------------\n                                               *MiniAnimate.gen_timing.linear()*\n                    `MiniAnimate.gen_timing.linear`({opts})\nGenerate timing with linear progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Timing function (see |MiniAnimate-timing|).\n\n------------------------------------------------------------------------------\n                                            *MiniAnimate.gen_timing.quadratic()*\n                   `MiniAnimate.gen_timing.quadratic`({opts})\nGenerate timing with quadratic progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Timing function (see |MiniAnimate-timing|).\n\n------------------------------------------------------------------------------\n                                                *MiniAnimate.gen_timing.cubic()*\n                     `MiniAnimate.gen_timing.cubic`({opts})\nGenerate timing with cubic progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Timing function (see |MiniAnimate-timing|).\n\n------------------------------------------------------------------------------\n                                              *MiniAnimate.gen_timing.quartic()*\n                    `MiniAnimate.gen_timing.quartic`({opts})\nGenerate timing with quartic progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Timing function (see |MiniAnimate-timing|).\n\n------------------------------------------------------------------------------\n                                          *MiniAnimate.gen_timing.exponential()*\n                  `MiniAnimate.gen_timing.exponential`({opts})\nGenerate timing with exponential progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Timing function (see |MiniAnimate-timing|).\n\n------------------------------------------------------------------------------\n                                                          *MiniAnimate.gen_path*\n                             `MiniAnimate.gen_path`\nGenerate cursor animation path\n\nFor more information see |MiniAnimate.config.cursor|.\n\nThis is a table with function elements. Call to actually get generator.\n\nExample: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    cursor = {\n      -- Animate with line-column angle instead of shortest line\n      path = animate.gen_path.angle(),\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                                   *MiniAnimate.gen_path.line()*\n                      `MiniAnimate.gen_path.line`({opts})\nGenerate path as shortest line\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `destination` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: `false` if `destination` is within one line of origin (reduces\n    flickering), `true` otherwise.\n  - <max_output_steps> `(number)` - maximum number of steps in output.\n    Default: 1000.\n\nReturn ~\n`(function)` Path function (see |MiniAnimate.config.cursor|).\n\n------------------------------------------------------------------------------\n                                                  *MiniAnimate.gen_path.angle()*\n                      `MiniAnimate.gen_path.angle`({opts})\nGenerate path as line/column angle\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `destination` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: `false` if `destination` is within one line of origin (reduces\n    flickering), `true` otherwise.\n  - <max_output_steps> `(number)` - maximum number of steps per side in output.\n    Default: 1000.\n  - <first_direction> `(string)` - one of `\"horizontal\"` (default; animates\n    across initial line first) or `\"vertical\"` (animates across initial\n    column first).\n\nReturn ~\n`(function)` Path function (see |MiniAnimate.config.cursor|).\n\n------------------------------------------------------------------------------\n                                                  *MiniAnimate.gen_path.walls()*\n                      `MiniAnimate.gen_path.walls`({opts})\nGenerate path as closing walls at final position\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `destination` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: `false` if `destination` is within one line of origin (reduces\n    flickering), `true` otherwise.\n  - <width> `(number)` - initial width of left and right walls. Default: 10.\n\nReturn ~\n`(function)` Path function (see |MiniAnimate.config.cursor|).\n\n------------------------------------------------------------------------------\n                                                 *MiniAnimate.gen_path.spiral()*\n                     `MiniAnimate.gen_path.spiral`({opts})\nGenerate path as diminishing spiral at final position\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `destination` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: `false` if `destination` is within one line of origin (reduces\n    flickering), `true` otherwise.\n  - <width> `(number)` - initial width of spiral. Default: 2.\n\nReturn ~\n`(function)` Path function (see |MiniAnimate.config.cursor|).\n\n------------------------------------------------------------------------------\n                                                     *MiniAnimate.gen_subscroll*\n                          `MiniAnimate.gen_subscroll`\nGenerate scroll animation subscroll\n\nFor more information see |MiniAnimate.config.scroll|.\n\nThis is a table with function elements. Call to actually get generator.\n\nExample: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    scroll = {\n      -- Animate equally but with 120 maximum steps instead of default 60\n      subscroll = animate.gen_subscroll.equal({ max_output_steps = 120 }),\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                             *MiniAnimate.gen_subscroll.equal()*\n                   `MiniAnimate.gen_subscroll.equal`({opts})\nGenerate subscroll with equal steps\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `total_scroll` as\n    input and returns boolean value indicating whether animation should be\n    done. Default: `false` if `total_scroll` is 1 or less (reduces\n    unnecessary waiting), `true` otherwise.\n  - <max_output_steps> `(number)` - maximum number of subscroll steps in output.\n    Adjust this to reduce computations in expense of reduced smoothness.\n    Default: 60.\n\nReturn ~\n`(function)` Subscroll function (see |MiniAnimate.config.scroll|).\n\n------------------------------------------------------------------------------\n                                                     *MiniAnimate.gen_subresize*\n                          `MiniAnimate.gen_subresize`\nGenerate resize animation subresize\n\nFor more information see |MiniAnimate.config.resize|.\n\nThis is a table with function elements. Call to actually get generator.\n\nExample: >lua\n\n  local is_many_wins = function(sizes_from, sizes_to)\n    return vim.tbl_count(sizes_from) >= 3\n  end\n  local animate = require('mini.animate')\n  animate.setup({\n    resize = {\n      -- Animate only if there are at least 3 windows\n      subresize = animate.gen_subresize.equal({ predicate = is_many_wins }),\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                             *MiniAnimate.gen_subresize.equal()*\n                   `MiniAnimate.gen_subresize.equal`({opts})\nGenerate subresize with equal steps\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `sizes_from` and\n    `sizes_to` as input and returns boolean value indicating whether\n    animation should be done. Default: always `true`.\n\nReturn ~\n`(function)` Subresize function (see |MiniAnimate.config.resize|).\n\n------------------------------------------------------------------------------\n                                                     *MiniAnimate.gen_winconfig*\n                          `MiniAnimate.gen_winconfig`\nGenerate open/close animation winconfig\n\nFor more information see |MiniAnimate.config.open| or |MiniAnimate.config.close|.\n\nThis is a table with function elements. Call to actually get generator.\n\nExample: >lua\n\n  local is_not_single_window = function(win_id)\n    local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n    return #vim.api.nvim_tabpage_list_wins(tabpage_id) > 1\n  end\n  local animate = require('mini.animate')\n  animate.setup({\n    open = {\n      -- Animate with wiping from nearest edge instead of default static one\n      -- and only if it is not a single window in tabpage\n      winconfig = animate.gen_winconfig.wipe({\n        predicate = is_not_single_window,\n        direction = 'from_edge',\n      }),\n    },\n    close = {\n      -- Animate with wiping to nearest edge instead of default static one\n      -- and only if it is not a single window in tabpage\n      winconfig = animate.gen_winconfig.wipe({\n        predicate = is_not_single_window,\n        direction = 'to_edge',\n      }),\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                            *MiniAnimate.gen_winconfig.static()*\n                   `MiniAnimate.gen_winconfig.static`({opts})\nGenerate winconfig for static floating window\n\nThis will result into floating window statically covering whole target\nwindow.\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `win_id` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: always `true`.\n  - <n_steps> `(number)` - number of output steps, all with same config.\n    Useful to tweak smoothness of transparency animation (done inside\n    `winblend` config option). Default: 25.\n\nReturn ~\n`(function)` Winconfig function (see |MiniAnimate.config.open|\n  or |MiniAnimate.config.close|).\n\n------------------------------------------------------------------------------\n                                            *MiniAnimate.gen_winconfig.center()*\n                   `MiniAnimate.gen_winconfig.center`({opts})\nGenerate winconfig for center-focused animated floating window\n\nThis will result into floating window growing from or shrinking to the\ntarget window center.\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `win_id` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: always `true`.\n  - <direction> `(string)` - one of `\"to_center\"` (default; window will\n    shrink from full coverage to center) or `\"from_center\"` (window will\n    grow from center to full coverage).\n\nReturn ~\n`(function)` Winconfig function (see |MiniAnimate.config.open|\n  or |MiniAnimate.config.close|).\n\n------------------------------------------------------------------------------\n                                              *MiniAnimate.gen_winconfig.wipe()*\n                    `MiniAnimate.gen_winconfig.wipe`({opts})\nGenerate winconfig for wiping animated floating window\n\nThis will result into floating window growing from or shrinking to the\nnearest edge. This also takes into account the split type of target window:\nvertically split window will progress towards vertical edge; horizontally -\ntowards horizontal.\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <predicate> `(function)` - a callable which takes `win_id` as input and\n    returns boolean value indicating whether animation should be done.\n    Default: always `true`.\n  - <direction> `(string)` - one of `\"to_edge\"` (default; window will\n    shrink from full coverage to nearest edge) or `\"from_edge\"` (window\n    will grow from edge to full coverage).\n\nReturn ~\n`(function)` Winconfig function (see |MiniAnimate.config.open|\n  or |MiniAnimate.config.close|).\n\n------------------------------------------------------------------------------\n                                                      *MiniAnimate.gen_winblend*\n                           `MiniAnimate.gen_winblend`\nGenerate open/close animation `winblend` progression\n\nFor more information see |MiniAnimate.config.open| or |MiniAnimate.config.close|.\n\nThis is a table with function elements. Call to actually get transparency\nfunction.\n\nExample: >lua\n\n  local animate = require('mini.animate')\n  animate.setup({\n    open = {\n      -- Change transparency from 60 to 80 instead of default 80 to 100\n      winblend = animate.gen_winblend.linear({ from = 60, to = 80 }),\n    },\n    close = {\n      -- Change transparency from 60 to 80 instead of default 80 to 100\n      winblend = animate.gen_winblend.linear({ from = 60, to = 80 }),\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                             *MiniAnimate.gen_winblend.linear()*\n                   `MiniAnimate.gen_winblend.linear`({opts})\nGenerate linear `winblend` progression\n\nParameters ~\n{opts} `(table|nil)` Options that control generator. Possible keys:\n  - <from> `(number)` - initial value of 'winblend'.\n  - <to> `(number)` - final value of 'winblend'.\n\nReturn ~\n`(function)` Winblend function (see |MiniAnimate.config.open|\n  or |MiniAnimate.config.close|).\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-base16.txt",
    "content": "*mini.base16* Base16 colorscheme creation\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniBase16*\nFast implementation of [chriskempson/base16](https://github.com/chriskempson/base16)\ncolor scheme (with Copyright (C) 2012 Chris Kempson) adapted for modern Neovim\nLua plugins. Extra features:\n- Configurable automatic support of cterm colors (see |highlight-cterm|).\n- Opinionated palette generator based only on background and foreground\n  colors.\n\nSupported highlight groups:\n- Built-in Neovim LSP and diagnostic.\n\n- Plugins (either with explicit definition or by verification that default\n  highlighting works appropriately):\n    - [nvim-mini/mini.nvim](https://nvim-mini.org/mini.nvim)\n    - [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n    - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n    - [DanilaMihailov/beacon.nvim](https://github.com/DanilaMihailov/beacon.nvim)\n    - [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n    - [folke/noice.nvim](https://github.com/folke/noice.nvim)\n    - [folke/snacks.nvim](https://github.com/folke/snacks.nvim)\n    - [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n    - [folke/trouble.nvim](https://github.com/folke/trouble.nvim)\n    - [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n    - [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n    - [ggandor/lightspeed.nvim](https://github.com/ggandor/lightspeed.nvim)\n    - [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n    - [glepnir/lspsaga.nvim](https://github.com/glepnir/lspsaga.nvim)\n    - [HiPhish/rainbow-delimiters.nvim](https://github.com/HiPhish/rainbow-delimiters.nvim)\n    - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n    - [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n    - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n    - [kevinhwang91/nvim-bqf](https://github.com/kevinhwang91/nvim-bqf)\n    - [kevinhwang91/nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n    - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n    - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n    - [MeanderingProgrammer/render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)\n    - [neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)\n    - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n    - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n    - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n    - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n    - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n    - [OXY2DEV/helpview.nvim](https://github.com/OXY2DEV/helpview.nvim)\n    - [OXY2DEV/markview.nvim](https://github.com/OXY2DEV/markview.nvim)\n    - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim)\n    - [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)\n    - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n    - [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n    - [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n    - [stevearc/aerial.nvim](https://github.com/stevearc/aerial.nvim)\n    - [williamboman/mason.nvim](https://github.com/williamboman/mason.nvim)\n\n# Setup ~\n\nThis module needs a setup with `require('mini.base16').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table\n`MiniBase16` which you can use for scripting or manually (with\n`:lua MiniBase16.*`).\n\nSee |MiniBase16.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minibase16_config`\nwill have no effect here.\n\nExample: >lua\n\n  require('mini.base16').setup({\n    palette = {\n      base00 = '#112641',\n      base01 = '#3a475e',\n      base02 = '#606b81',\n      base03 = '#8691a7',\n      base04 = '#d5dc81',\n      base05 = '#e2e98f',\n      base06 = '#eff69c',\n      base07 = '#fcffaa',\n      base08 = '#ffcfa0',\n      base09 = '#cc7e46',\n      base0A = '#46a436',\n      base0B = '#9ff895',\n      base0C = '#ca6ecf',\n      base0D = '#42f7ff',\n      base0E = '#ffc4ff',\n      base0F = '#00a5c5',\n    },\n    use_cterm = true,\n    plugins = {\n      default = false,\n      ['nvim-mini/mini.nvim'] = true,\n    },\n  })\n<\n# Notes ~\n\n1. This is used to create some of plugin's color schemes\n   (see |MiniBase16-color-schemes|).\n2. Using `setup()` doesn't actually create a |:colorscheme|. It basically\n   creates a coordinated set of |highlight-groups|. To create your own theme:\n    - Put \"myscheme.lua\" file (name after your chosen theme name) inside\n      any \"colors\" directory reachable from 'runtimepath' (\"colors\" inside\n      your Neovim config directory is usually enough).\n    - Inside \"myscheme.lua\" call `require('mini.base16').setup()` with your\n      palette and only after that set |g:colors_name| to \"myscheme\".\n\n------------------------------------------------------------------------------\n                                                      *MiniBase16-color-schemes*\n# Base16 colorschemes ~\n\nThis module comes with several pre-built color schemes. Each of them is\na |mini.base16| theme created with faster version of the following Lua code: >lua\n\n  require('mini.base16').setup({ palette = palette, use_cterm = true })\n<\nActivate them as regular |:colorscheme| (for example, `:colorscheme minischeme`).\n\n## minischeme ~\n*minischeme*\n\nBlue and yellow main colors with high contrast and saturation palette.\nPalettes are: >lua\n\n  -- For dark 'background':\n  MiniBase16.mini_palette('#112641', '#e2e98f', 75)\n\n  -- For light 'background':\n  MiniBase16.mini_palette('#e2e5ca', '#002a83', 75)\n<\n## minicyan ~\n*minicyan*\n\nCyan and grey main colors with moderate contrast and saturation palette.\nPalettes are: >lua\n\n  -- For dark 'background':\n  MiniBase16.mini_palette('#0A2A2A', '#D0D0D0', 50)\n\n  -- For light 'background':\n  MiniBase16.mini_palette('#C0D2D2', '#262626', 80)\n<\n------------------------------------------------------------------------------\n                                                            *MiniBase16.setup()*\n                          `MiniBase16.setup`({config})\nModule setup\n\nSetup is done by applying base16 palette to enable colorscheme. Highlight\ngroups make an extended set from original\n[base16-vim](https://github.com/chriskempson/base16-vim/) plugin. It is a\ngood idea to have `config.palette` respect the original [styling\nprinciples](https://github.com/chriskempson/base16/blob/master/styling.md).\n\nBy default only 'gui highlighting' (see |highlight-gui| and\n|'termguicolors'|) is supported. To support 'cterm highlighting' (see\n|highlight-cterm|) supply `config.use_cterm` argument in one of the formats:\n- `true` to auto-generate from `palette` (as closest colors).\n- Table with similar structure to `palette` but having terminal colors\n  (integers from 0 to 255) instead of hex strings.\n\nParameters ~\n{config} `(table)` Module config table. See |MiniBase16.config|.\n\nUsage ~\n>lua\n  require('mini.base16').setup({}) -- replace {} with your config table\n                                   -- needs `palette` field present\n<\n------------------------------------------------------------------------------\n                                                             *MiniBase16.config*\n                              `MiniBase16.config`\nDefaults ~\n>lua\n  MiniBase16.config = {\n    -- Table with names from `base00` to `base0F` and values being strings of\n    -- HEX colors with format \"#RRGGBB\". NOTE: this should be explicitly\n    -- supplied in `setup()`.\n    palette = nil,\n\n    -- Whether to support cterm colors. Can be boolean, `nil` (same as\n    -- `false`), or table with cterm colors. See `setup()` documentation for\n    -- more information.\n    use_cterm = nil,\n\n    -- Plugin integrations. Use `default = false` to disable all integrations.\n    -- Also can be set per plugin (see |MiniBase16.config|).\n    plugins = { default = true },\n  }\n<\n# Plugin integrations ~\n\n`config.plugins` defines for which supported plugins highlight groups will\nbe created. Limiting number of integrations slightly decreases startup time.\nIt is a table with boolean (`true`/`false`) values which are applied as follows:\n- If plugin name (as listed in |mini.base16|) has entry, it is used.\n- Otherwise `config.plugins.default` is used.\n\nExample which will load only \"mini.nvim\" integration: >lua\n\n  require('mini.base16').setup({\n    palette = require('mini.base16').mini_palette('#112641', '#e2e98f', 75),\n    plugins = {\n      default = false,\n      ['nvim-mini/mini.nvim'] = true,\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                                     *MiniBase16.mini_palette()*\n     `MiniBase16.mini_palette`({background}, {foreground}, {accent_chroma})\nCreate 'mini' palette\n\nCreate base16 palette based on the HEX (string '#RRGGBB') colors of main\nbackground and foreground with optional setting of accent chroma (see\ndetails).\n\n# Algorithm design ~\n\n- Main operating color space is\n  [CIELCh(uv)](https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_(CIELCh))\n  which is a cylindrical representation of a perceptually uniform CIELUV\n  color space. It defines color by three values: lightness L (values from 0\n  to 100), chroma (positive values), and hue (circular values from 0 to 360\n  degrees). Useful converting tool: https://www.easyrgb.com/en/convert.php\n- There are four important lightness values: background, foreground, focus\n  (around the middle of background and foreground, leaning towards\n  foreground), and edge (extreme lightness closest to foreground).\n- First four colors have the same chroma and hue as `background` but\n  lightness progresses from background towards focus.\n- Second four colors have the same chroma and hue as `foreground` but\n  lightness progresses from foreground towards edge in such a way that\n  'base05' color is main foreground color.\n- The rest eight colors are accent colors which are created in pairs\n    - Each pair has same hue from set of hues 'most different' to\n      background and foreground hues (if respective chorma is positive).\n    - All colors have the same chroma equal to `accent_chroma` (if not\n      provided, chroma of foreground is used, as they will appear next\n      to each other). Note: this means that in case of low foreground\n      chroma, it is a good idea to set `accent_chroma` manually.\n      Values from 30 (low chorma) to 80 (high chroma) are common.\n    - Within pair there is base lightness (equal to foreground\n      lightness) and alternative (equal to focus lightness). Base\n      lightness goes to colors which will be used more frequently in\n      code: base08 (variables), base0B (strings), base0D (functions),\n      base0E (keywords).\n  How exactly accent colors are mapped to base16 palette is a result of\n  trial and error. One rule of thumb was: colors within one hue pair should\n  be more often seen next to each other. This is because it is easier to\n  distinguish them and seems to be more visually appealing. That is why\n  `base0D` and `base0F` have same hues because they usually represent\n  functions and delimiter (brackets included).\n\nParameters ~\n{background} `(string)` Background HEX color (formatted as `#RRGGBB`).\n{foreground} `(string)` Foreground HEX color (formatted as `#RRGGBB`).\n{accent_chroma} `(number)` Optional positive number (usually between 0\n  and 100). Default: chroma of foreground color.\n\nReturn ~\n`(table)` Table with base16 palette.\n\nUsage ~\n>lua\n  local p = require('mini.base16').mini_palette('#112641', '#e2e98f', 75)\n  require('mini.base16').setup({ palette = p })\n<\n------------------------------------------------------------------------------\n                                     *MiniBase16.rgb_palette_to_cterm_palette()*\n              `MiniBase16.rgb_palette_to_cterm_palette`({palette})\nConverts palette with RGB colors to terminal colors\n\nUseful for caching `use_cterm` variable to increase speed.\n\nParameters ~\n{palette} `(table)` Table with base16 palette (same as in\n  `MiniBase16.config.palette`).\n\nReturn ~\n`(table)` Table with base16 palette using |highlight-cterm|.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-basics.txt",
    "content": "*mini.basics* Common configuration presets\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniBasics*\nInstall, create 'init.lua', add `require('mini.basics').setup()`, and you\nare good to go.\n\nFeatures:\n- Presets for common options. It will only change option if it wasn't\n  manually set before. See more in |MiniBasics.config.options|.\n\n- Presets for common mappings. It will only add a mapping if it wasn't\n  manually created before. See more in |MiniBasics.config.mappings|.\n\n- Presets for common autocommands. See more in |MiniBasics.config.autocommands|.\n\n- Reverse compatibility is a high priority. Any decision to change already\n  present behavior will be made with great care.\n\nNotes:\n- Main goal of this module is to provide a relatively easier way for\n  new-ish Neovim users to have better \"works out of the box\" experience\n  while having documented relevant options/mappings/autocommands to study.\n  It is based partially on survey among Neovim users and partially is\n  coming from personal preferences.\n\n  However, more seasoned users almost surely will find something useful.\n\n  Still, it is recommended to read about used options/mappings/autocommands\n  and decide if they are needed. The main way to do that is by reading\n  Neovim's help pages (linked in help file) and this module's source code\n  (thoroughly documented for easier comprehension).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.basics').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniBasics`\nwhich you can use for scripting or manually (with `:lua MiniBasics.*`).\n\nSee |MiniBasics.config| for available config settings.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Comparisons ~\n\n- [tpope/vim-sensible](https://github.com/tpope/vim-sensible):\n    - Most of 'tpope/vim-sensible' is already incorporated as default\n      options in Neovim (see |nvim-defaults|). This module has a much\n      broader effect.\n- [tpope/vim-unimpaired](https://github.com/tpope/vim-unimpaired):\n    - The 'tpope/vim-unimpaired' has mapping for toggling options with `yo`\n      prefix. This module implements similar functionality with `\\` prefix\n      (see |MiniBasics.config.mappings|).\n\n------------------------------------------------------------------------------\n                                                            *MiniBasics.setup()*\n                          `MiniBasics.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniBasics.config|.\n\nUsage ~\n>lua\n  require('mini.basics').setup() -- use default config\n  -- OR\n  require('mini.basics').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                             *MiniBasics.config*\n                              `MiniBasics.config`\nDefaults ~\n>lua\n  MiniBasics.config = {\n    -- Options. Set field to `false` to disable.\n    options = {\n      -- Basic options ('number', 'ignorecase', and many more)\n      basic = true,\n\n      -- Extra UI features ('winblend', 'listchars', 'pumheight', ...)\n      extra_ui = false,\n\n      -- Presets for window borders ('single', 'double', ...)\n      -- Default 'auto' infers from 'winborder' option\n      win_borders = 'auto',\n    },\n\n    -- Mappings. Set field to `false` to disable.\n    mappings = {\n      -- Basic mappings (better 'jk', save with Ctrl+S, ...)\n      basic = true,\n\n      -- Prefix for mappings that toggle common options ('wrap', 'spell', ...).\n      -- Supply empty string to not create these mappings.\n      option_toggle_prefix = [[\\]],\n\n      -- Window navigation with <C-hjkl>, resize with <C-arrow>\n      windows = false,\n\n      -- Move cursor in Insert, Command, and Terminal mode with <M-hjkl>\n      move_with_alt = false,\n    },\n\n    -- Autocommands. Set field to `false` to disable\n    autocommands = {\n      -- Basic autocommands (highlight on yank, start Insert in terminal, ...)\n      basic = true,\n\n      -- Set 'relativenumber' only in linewise and blockwise Visual mode\n      relnum_in_visual_mode = false,\n    },\n\n    -- Whether to disable showing non-error feedback\n    silent = false,\n  }\n<\n# Options ~\n*MiniBasics.config.options*\n\nUsage example: >lua\n\n  require('mini.basics').setup({\n    options = {\n      basic = true,\n      extra_ui = true,\n      win_borders = 'double',\n    }\n  })\n<\n## options.basic ~\n\nThe `config.options.basic` sets certain options to values which are quite\ncommonly used (judging by study of available Neovim pre-configurations,\npublic dotfiles, and surveys).\nAny option is changed only if it was not set manually beforehand.\nFor exact changes, please see source code ('lua/mini/basics.lua').\n\nHere is the list of affected options (put cursor on it and press |CTRL-]|):\n- General:\n    - Sets |<Leader>| key to |<Space>|. Be sure to make all Leader mappings\n      after this (otherwise they are made with default <Leader>).\n    - Runs `:filetype plugin indent on` (see |:filetype-overview|)\n    - |'backup'|\n    - |'mouse'|\n    - |'undofile'|\n    - |'writebackup'|\n- Appearance\n    - |'breakindent'|\n    - |'cursorline'|\n    - |'fillchars'|\n    - |'linebreak'|\n    - |'number'|\n    - |'ruler'|\n    - |'showmode'|\n    - |'signcolumn'|\n    - |'shortmess'|\n    - |'splitbelow'|\n    - |'splitkeep'|\n    - |'splitright'|\n    - |'termguicolors'| (on Neovim<0.10; later versions have it smartly enabled)\n    - |'wrap'|\n- Editing\n    - |'completeopt'|\n    - |'formatoptions'|\n    - |'ignorecase'|\n    - |'incsearch'|\n    - |'infercase'|\n    - |'smartcase'|\n    - |'smartindent'|\n    - |'virtualedit'|\n\n## options.extra_ui ~\n\nThe `config.options.extra_ui` sets certain options for visual appearance\nwhich might not be aligned with common preferences, but still worth trying.\nAny option is changed only if it was not set manually beforehand.\nFor exact changes, please see source code ('lua/mini/basics.lua').\n\nList of affected options:\n- |'list'|\n- |'listchars'|\n- |'pumblend'|\n- |'pumheight'|\n- |'winblend'|\n- Runs `:syntax on` (see |:syntax-on|)\n\n## options.win_borders ~\n\nThe `config.options.win_borders` updates |'fillchars'| to have a consistent set\nof characters for window border (`vert`, `horiz`, `msgsep`, etc.).\n\nAvailable values:\n- `'auto'` - infer from |'winborder'|. On Neovim<0.11 do nothing.\n- `'bold'` - bold lines.\n- `'dot'` - dot in every cell.\n- `'double'` - double line.\n- `'single'` - single line.\n- `'solid'` - no symbol, only background.\n\n# Mappings ~\n*MiniBasics.config.mappings*\n\nUsage example: >lua\n\n  require('mini.basics').setup({\n    mappings = {\n      basic = true,\n      option_toggle_prefix = [[\\]],\n      windows = true,\n      move_with_alt = true,\n    }\n  })\n<\nIf you want some mappings to be different or not made at all, set or delete\nthem after calling |MiniBasics.setup()|.\n\n## mappings.basic ~\n\nThe `config.mappings.basic` creates mappings for certain commonly mapped actions\n(judging by study of available Neovim pre-configurations and public dotfiles).\n\nSome of the mappings override built-in ones to either improve their\nbehavior or override its default not very useful action.\nIt will only add a mapping if it wasn't manually created before.\n\nHere is a table with created mappings : >\n\n |Keys   |     Modes       |                  Description                  |\n |-------|-----------------|-----------------------------------------------|\n | j     | Normal, Visual  | Move down by visible lines with no [count]    |\n | k     | Normal, Visual  | Move up by visible lines with no [count]      |\n | go    | Normal          | Add [count] empty lines after cursor          |\n | gO    | Normal          | Add [count] empty lines before cursor         |\n | gy    | Normal, Visual  | Copy to system clipboard                      |\n | gp    | Normal, Visual  | Paste from system clipboard                   |\n | gV    | Normal          | Visually select latest changed or yanked text |\n | g/    | Visual          | Search inside current visual selection        |\n | *     | Visual          | Search forward for current visual selection   |\n | #     | Visual          | Search backward for current visual selection  |\n | <C-s> | Normal, Visual, | Save and go to Normal mode                    |\n |       |     Insert      |                                               |\n<\nNotes:\n- See |[count]| for its meaning.\n- On Neovim>=0.10 mappings for `#` and `*` are not created as their\n  enhanced variants are made built-in. See |v_star-default| and |v_#-default|.\n- On Neovim>=0.11 there are |[<Space>| / |]<Space>| for adding empty lines.\n  The `gO` and `go` mappings are still created as they are more aligned with\n  similarly purposed |O| and |o| keys (although sometimes conflict with |gO|).\n\n## mappings.option_toggle_prefix ~\n\nThe `config.mappings.option_toggle_prefix` defines a prefix used for\ncreating mappings that toggle common options. The result mappings will be\n`<prefix> + <suffix>`. For example, with default value, `\\w` will toggle |'wrap'|.\n\nOther viable choices for prefix are\n- `,` (as a mnemonic for several values to toggle).\n- `|` (as a same mnemonic).\n- `yo` (used in 'tpope/vim-unimpaired')\n- Something with |<Leader>| key, like `<Leader>t` (`t` for \"toggle\"). Note:\n  if your prefix contains `<Leader>` key, make sure to set it before\n  calling |MiniBasics.setup()| (as is done with default `basic` field of\n  |MiniBasics.config.options|).\n\nAfter toggling, there will be a feedback about the current option value if\nprior to `require('mini.basics').setup()` module wasn't silenced (see\n\"Silencing\" section in |mini.basics|).\n\nIt will only add a mapping if it wasn't manually created before.\n\nHere is a list of suffixes for created toggling mappings (all in Normal mode):\n\n- `b` - |'background'|.\n- `c` - |'cursorline'|.\n- `C` - |'cursorcolumn'|.\n- `d` - diagnostic (via |vim.diagnostic| functions).\n- `h` - |'hlsearch'| (or |v:hlsearch| to be precise).\n- `i` - |'ignorecase'|.\n- `l` - |'list'|.\n- `n` - |'number'|.\n- `r` - |'relativenumber'|.\n- `s` - |'spell'|.\n- `w` - |'wrap'|.\n\n## mappings.windows ~\n\nThe `config.mappings.windows` creates mappings for easiere window manipulation.\n\nIt will only add a mapping if it wasn't manually created before.\n\nHere is a list with created Normal mode mappings (all respect |[count]|):\n- Window navigation:\n    - `<C-h>` - focus on left window (see |CTRL-W_H|).\n    - `<C-j>` - focus on below window (see |CTRL-W_J|).\n    - `<C-k>` - focus on above window (see |CTRL-W_K|).\n    - `<C-l>` - focus on right window (see |CTRL-W_L|).\n- Window resize (all use arrow keys; variants of |:resize|; respect |[count]|):\n    - `<C-left>`  - decrease window width.\n    - `<C-down>`  - decrease window height.\n    - `<C-up>`    - increase window height.\n    - `<C-right>` - increase window width.\n\n## mappings.move_with_alt ~\n\nThe `config.mappings.move_with_alt` creates mappings for a more consistent\ncursor move in Insert, Command, and Terminal modes. For example, it proves\nuseful in combination of autopair plugin (like |mini.pairs|) to move right\noutside of inserted pairs (no matter what the pair is).\n\nIt will only add a mapping if it wasn't manually created before.\n\nHere is a list of created mappings (`<M-x>` means `Alt`/`Meta` plus `x`):\n- `<M-h>` - move cursor left.  Modes: Insert, Terminal, Command.\n- `<M-j>` - move cursor down.  Modes: Insert, Terminal.\n- `<M-k>` - move cursor up.    Modes: Insert, Terminal.\n- `<M-l>` - move cursor right. Modes: Insert, Terminal, Command.\n\n# Autocommands ~\n*MiniBasics.config.autocommands*\n\nUsage example: >lua\n\n  require('mini.basics').setup({\n    autocommands = {\n      basic = true,\n      relnum_in_visual_mode = true,\n    }\n  })\n<\n## autocommands.basic ~\n\nThe `config.autocommands.basic` creates some common autocommands:\n\n- Starts insert mode when opening terminal (see |:startinsert| and |TermOpen|).\n- Highlights yanked text for a brief period of time (see |vim.hl.on_yank()|;\n  on Neovim<0.11 - |vim.hl.on_yank()|) and |TextYankPost|).\n\n## autocommands.relnum_in_visual_mode ~\n\nThe `config.autocommands.relnum_in_visual_mode` creates autocommands that\nenable |'relativenumber'| in linewise and blockwise Visual modes and disable\notherwise. See |ModeChanged|.\n\n------------------------------------------------------------------------------\n                                                *MiniBasics.toggle_diagnostic()*\n                        `MiniBasics.toggle_diagnostic`()\nToggle diagnostic for current buffer\n\nThis uses |vim.diagnostic| functions per buffer.\n\nReturn ~\n`(string)` String indicator for new state. Similar to what |:set| `{option}?` shows.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-bracketed.txt",
    "content": "*mini.bracketed* Go forward/backward with square brackets\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                 *MiniBracketed*\nFeatures:\n- Configurable Lua functions to go forward/backward to a certain target.\n  Each function can be customized with:\n    - Direction. One of \"forward\", \"backward\", \"first\" (forward starting\n      from first one), \"last\" (backward starting from last one).\n    - Number of times to go.\n    - Whether to wrap on edges (going forward on last one goes to first).\n    - Some other target specific options.\n\n- Mappings using square brackets. They are created using configurable\n  target suffix and can be selectively disabled.\n\n  Each mapping supports |[count]|. Mappings are created in Normal mode; for\n  targets which move cursor in current buffer also Visual and\n  Operator-pending (with dot-repeat) modes are supported.\n\n  Using `lower-suffix` and `upper-suffix` (lower and upper case suffix) for\n  a single target the following mappings are created:\n    - `[` + `upper-suffix` : go first.\n    - `[` + `lower-suffix` : go backward.\n    - `]` + `lower-suffix` : go forward.\n    - `]` + `upper-suffix` : go last.\n\n- Supported targets (for more information see help for corresponding Lua\n  function):\n\n  `Target`                           `Mappings`         `Lua function`\n  Buffer ......................... `[B` `[b` `]b` `]B` .... |MiniBracketed.buffer()|\n  Comment block .................. `[C` `[c` `]c` `]C` .... |MiniBracketed.comment()|\n  Conflict marker ................ `[X` `[x` `]x` `]X` .... |MiniBracketed.conflict()|\n  Diagnostic ..................... `[D` `[d` `]d` `]D` .... |MiniBracketed.diagnostic()|\n  File on disk ................... `[F` `[f` `]f` `]F` .... |MiniBracketed.file()|\n  Indent change .................. `[I` `[i` `]i` `]I` .... |MiniBracketed.indent()|\n  Jump inside current buffer ..... `[J` `[j` `]j` `]J` .... |MiniBracketed.jump()|\n  Location from |location-list| .... `[L` `[l` `]l` `]L` .... |MiniBracketed.location()|\n  Old files ...................... `[O` `[o` `]o` `]O` .... |MiniBracketed.oldfile()|\n  Quickfix entry from |Quickfix| ... `[Q` `[q` `]q` `]Q` .... |MiniBracketed.quickfix()|\n  Tree-sitter node and parents ... `[T` `[t` `]t` `]T` .... |MiniBracketed.treesitter()|\n  Undo from linear history ....... `[U` `[u` `]u` `]U` .... |MiniBracketed.undo()|\n  Window in current tab .......... `[W` `[w` `]w` `]W` .... |MiniBracketed.window()|\n  Yank entry over put region ..... `[Y` `[y` `]y` `]Y` .... |MiniBracketed.yank()|\n\nNotes:\n- The `undo` target remaps |u| and |CTRL-R| keys to register undo state\n  after undo and redo respectively. If this conflicts with your setup,\n  either disable `undo` target or make your remaps after calling\n  |MiniBracketed.setup()|. To use `undo` target, remap your undo/redo keys\n  to call |MiniBracketed.register_undo_state()| after the action.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.bracketed').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniBracketed`\nwhich you can use for scripting or manually (with `:lua MiniBracketed.*`).\n\nSee |MiniBracketed.config| for available config settings.\n\nYou can override runtime config settings (like target options) locally\nto buffer inside `vim.b.minibracketed_config` which should have same structure\nas `MiniBracketed.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [tpope/vim-unimpaired](https://github.com/tpope/vim-unimpaired):\n    - Supports buffer, conflict, file, location, and quickfix targets mostly\n      via built-in commands (like |:bprevious|, etc.) without configuration.\n    - Supports files from argument list and tags. This module does not.\n    - Doesn't support most other this module's targets (comment, indent, ...).\n- |mini.indentscope|:\n    - Target |MiniBracketed.indent()| target can go to \"first\" and \"last\"\n      indent change. It also can go not only to line with smaller indent,\n      but also bigger or different one.\n    - Mappings from 'mini.indentscope' have more flexibility in computation of\n      indent scope, like how to treat empty lines near border or whether to\n      compute indent at cursor.\n\n# Disabling ~\n\nTo disable, set `vim.g.minibracketed_disable` (globally) or\n`vim.b.minibracketed_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                         *MiniBracketed.setup()*\n                        `MiniBracketed.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniBracketed.config|.\n\nUsage ~\n>lua\n  require('mini.bracketed').setup() -- use default config\n  -- OR\n  require('mini.bracketed').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                          *MiniBracketed.config*\n                             `MiniBracketed.config`\nDefaults ~\n>lua\n  MiniBracketed.config = {\n    -- First-level elements are tables describing behavior of a target:\n    --\n    -- - <suffix> - single character suffix. Used after `[` / `]` in mappings.\n    --   For example, with `b` creates `[B`, `[b`, `]b`, `]B` mappings.\n    --   Supply empty string `''` to not create mappings.\n    --\n    -- - <options> - table overriding target options.\n    --\n    -- See `:h MiniBracketed.config` for more info.\n\n    buffer     = { suffix = 'b', options = {} },\n    comment    = { suffix = 'c', options = {} },\n    conflict   = { suffix = 'x', options = {} },\n    diagnostic = { suffix = 'd', options = {} },\n    file       = { suffix = 'f', options = {} },\n    indent     = { suffix = 'i', options = {} },\n    jump       = { suffix = 'j', options = {} },\n    location   = { suffix = 'l', options = {} },\n    oldfile    = { suffix = 'o', options = {} },\n    quickfix   = { suffix = 'q', options = {} },\n    treesitter = { suffix = 't', options = {} },\n    undo       = { suffix = 'u', options = {} },\n    window     = { suffix = 'w', options = {} },\n    yank       = { suffix = 'y', options = {} },\n  }\n<\nOptions ~\n\nEach entry configures target with the same name and can have data configuring\nmapping suffix and target options.\n\nExample of configuration: >lua\n\n  require('mini.bracketed').setup({\n    -- Map [N, [n, ]n, ]N for conflict marker like in 'tpope/vim-unimpaired'\n    conflict = { suffix = 'n' },\n\n    -- Make diagnostic advance only by errors\n    diagnostic = { options = { severity = vim.diagnostic.severity.ERROR } },\n\n    -- Disable creation of mappings for `indent` target (for example,\n    -- in favor of ones from |mini.indentscope|)\n    indent = { suffix = '' },\n\n    -- Disable mappings for `window` target in favor of custom ones\n    window = { suffix = '' },\n  })\n\n  -- Create custom `window` mappings\n  local map = vim.keymap.set\n  map('n', '<Leader>wH', \"<Cmd>lua MiniBracketed.window('first')<CR>\")\n  map('n', '<Leader>wh', \"<Cmd>lua MiniBracketed.window('backward')<CR>\")\n  map('n', '<Leader>wl', \"<Cmd>lua MiniBracketed.window('forward')<CR>\")\n  map('n', '<Leader>wL', \"<Cmd>lua MiniBracketed.window('last')<CR>\")\n<\n## Suffix ~\n\nThe `suffix` key is used to create target mappings.\n\nSupply empty string to disable mapping creation for that particular target.\nTo create a completely different mapping (like with |<Leader>|) use target\nfunction manually.\n\nUsing `lower-suffix` and `upper-suffix` (lower and upper case suffix) for\na single target the following mappings are created:\n- `[` + `upper-suffix` : go first.\n- `[` + `lower-suffix` : go backward.\n- `]` + `lower-suffix` : go forward.\n- `]` + `upper-suffix` : go last.\n\nWhen supplied with a non-letter, only forward/backward mappings are created.\n\n## Options ~\n\nThe `options` key is directly forwarded as `opts` to corresponding Lua function.\n\n------------------------------------------------------------------------------\n                                                        *MiniBracketed.buffer()*\n                  `MiniBracketed.buffer`({direction}, {opts})\nListed buffer\n\nGo to next/previous listed buffer. Order by their number (see |bufnr()|).\n\nDirection \"forward\" increases number, \"backward\" - decreases.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                       *MiniBracketed.comment()*\n                  `MiniBracketed.comment`({direction}, {opts})\nComment block\n\nGo to next/previous comment block. Only linewise comments using\n'commentsring' are recognized.\n\nDirection \"forward\" increases line number, \"backward\" - decreases.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n  - <add_to_jumplist> (`boolean`) - Whether to add current position to jumplist.\n    Default: `false`.\n  - <block_side> `(string)` - which side of comment block to use. One of\n    \"near\" (default; use nearest side), \"start\" (use first line), \"end\"\n    (use last line), \"both\" (use both first and last lines).\n\n------------------------------------------------------------------------------\n                                                      *MiniBracketed.conflict()*\n                 `MiniBracketed.conflict`({direction}, {opts})\nGit conflict marker\n\nGo to next/previous lines containing Git conflict marker. That is, if it\nstarts with \"<<<<<<< \", \">>>>>>> \", or is \"=======\".\n\nDirection \"forward\" increases line number, \"backward\" - decreases.\n\nNotes:\n- Using this target in Operator-pending mode allows the following approach\n  at resolving merge conflicts:\n    - Place cursor on `=======` line.\n    - Execute one of these: `d]x[xdd` (choose upper part) or\n      `d[x]xdd` (choose lower part).\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n  - <add_to_jumplist> (`boolean`) - Whether to add current position to jumplist.\n    Default: `false`.\n\n------------------------------------------------------------------------------\n                                                    *MiniBracketed.diagnostic()*\n                `MiniBracketed.diagnostic`({direction}, {opts})\nDiagnostic\n\nGo to next/previous diagnostic. This is mostly similar to built-in\n|vim.diagnostic.jump()| (on Neovim<0.11 it is |vim.diagnostic.goto_next()| and\n|vim.diagnostic.goto_prev()|) which has an interface and behavior\nconsistent with other methods of the module.\n\nDirection \"forward\" increases line number, \"backward\" - decreases.\n\nNotes:\n- Using `severity` option, this target can be used in mappings like \"go to\n  next/previous error\" (), etc. Using code similar to this: >lua\n\n  local severity_error = vim.diagnostic.severity.ERROR\n  -- Use these inside custom mappings\n  MiniBracketed.diagnostic('forward', { severity = severity_error })\n  MiniBracketed.diagnostic('backward', { severity = severity_error })\n<\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n  - <float> `(boolean|table)` - control floating window after movement.\n    For available values see |vim.diagnostic.goto_next()|.\n  - <severity> `(string|table)` - which severity to use.\n    For available values see |diagnostic-severity|.\n\n------------------------------------------------------------------------------\n                                                          *MiniBracketed.file()*\n                   `MiniBracketed.file`({direction}, {opts})\nFile on disk\n\nGo to next/previous file on disk alphabetically. Files are taken from\ndirectory of file in current buffer (or current working directory if buffer\ndoesn't contain a readable file). Only first-level files are used, i.e. it\ndoesn't go inside subdirectories.\n\nDirection \"forward\" goes forward alphabetically, \"backward\" - backward.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                        *MiniBracketed.indent()*\n                  `MiniBracketed.indent`({direction}, {opts})\nIndent change\n\nGo to next/previous line with different indent (see |indent()|).\nCan be used to go to lines with smaller, bigger, or different indent.\n\nNotes:\n- Directions \"first\" and \"last\" work differently from most other targets\n  for performance reasons. They are essentially \"backward\" and \"forward\"\n  with very big `n_times` option.\n- For similar reasons, `wrap` is not supported.\n- Blank line inherit indent from near non-blank line in direction of movement.\n\nDirection \"forward\" increases line number, \"backward\" - decreases.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <add_to_jumplist> (`boolean`) - Whether to add current position to jumplist.\n    Default: `false`.\n  - <change_type> `(string)` - which type of indent change to use.\n    One of \"less\" (default; smaller indent), \"more\" (bigger indent),\n    \"diff\" (different indent).\n\n------------------------------------------------------------------------------\n                                                          *MiniBracketed.jump()*\n                   `MiniBracketed.jump`({direction}, {opts})\nJump inside current buffer\n\nGo to next/previous jump from |jumplist| which is inside current buffer.\n\nNotes:\n- There are no Visual mode mappings due to implementation problems.\n\nDirection \"forward\" increases jump number, \"backward\" - decreases.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                      *MiniBracketed.location()*\n                 `MiniBracketed.location`({direction}, {opts})\nLocation from location list\n\nGo to next/previous location from |location-list|. This is similar to\n|:lfirst|, |:lprevious|, |:lnext|, and |:llast| but with support of\nwrapping around edges and |[count]| for \"first\"/\"last\" direction.\n\nDirection \"forward\" increases location number, \"backward\" - decreases.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                       *MiniBracketed.oldfile()*\n                  `MiniBracketed.oldfile`({direction}, {opts})\nOld files from previous and current sessions\n\nGo to older/newer readable file either from previous session (see |v:oldfiles|)\nor the current one (updated automatically after |MiniBracketed.setup()| call).\n\nDirection \"forward\" goes to more recent files, \"backward\" - to older.\n\nNotes:\n- In current session it tracks only normal buffers (see |'buftype'|) for\n  some readable file.\n- No new file is tracked when advancing this target. Only after buffer\n  change is done not through this target (like with |MiniBracketed.buffer()|),\n  it updates recency of last advanced and new buffers.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                      *MiniBracketed.quickfix()*\n                 `MiniBracketed.quickfix`({direction}, {opts})\nQuickfix from quickfix list\n\nGo to next/previous entry from |quickfix| list. This is similar to\n|:cfirst|, |:cprevious|, |:cnext|, and |:clast| but with support of\nwrapping around edges and |[count]| for \"first\"/\"last\" direction.\n\nDirection \"forward\" increases location number, \"backward\" - decreases.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                    *MiniBracketed.treesitter()*\n                `MiniBracketed.treesitter`({direction}, {opts})\nTree-sitter node\n\nGo to end/start of current tree-sitter node and its parents (except root).\n\nNotes:\n- Requires loaded tree-sitter parser in the current buffer.\n- Directions \"first\" and \"last\" work differently from most other targets\n  for performance reasons. They are essentially \"backward\" and \"forward\"\n  with very big `n_times` option.\n- For similar reasons, `wrap` is not supported.\n\nDirection \"forward\" moves cursor forward to node's end, \"backward\" - backward\nto node's start.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <add_to_jumplist> (`boolean`) - Whether to add current position to jumplist.\n    Default: `false`.\n\n------------------------------------------------------------------------------\n                                                          *MiniBracketed.undo()*\n                   `MiniBracketed.undo`({direction}, {opts})\nUndo along a tracked linear history\n\nIn a nutshell:\n- Keys |u| and |CTRL-R| (although remapped) can be used as usual, but every\n  their execution new state is recorded in this module's linear undo history.\n- Advancing this target goes along linear undo history revealing undo states\n  **in order they actually appeared**.\n- One big difference with built-in methods is that tracked linear history\n  can repeat undo states (not consecutively, though).\n\nNeovim's default way of managing undo history is through branches (see\n|undo-branches|). Basically it means that if you undo several changes and then\nmake new ones, it creates new undo branch while usually (see |'undolevels'|)\nsaving previous buffer states in another branch. While there are commands\nto navigate by time of undo state creation (like |:earlier| and |:later|),\nthere is no intuitive way to cycle through them. Existing |g-| and |g+|\ncycle through undo states **based on their creation time**, which often\ngets confusing really guickly in extensively edited buffer.\n\nThis `undo()` target provides a way to cycle through linear undo history\n**in order states actually appeared**. It does so by registering any new undo\nstates plus every time |MiniBracketed.register_undo_state()| is called. To have\nmore \"out of the box\" experience, |u| and |CTRL-R| are remapped to call it after\nthey perform their undo/redo.\n\nExample:\n\nTo show more clearly the difference between advancing this target and using\nbuilt-in functionality, here is an example:\n\n- Create undo history in a new buffer (|:new|):\n    - Enter `one two three` text.\n    - Delete first word with `daw` and undo the change with `u`.\n    - Delete second word with `daw` and undo the change with `u`.\n    - Delete third word with `daw` and undo the change with `u`.\n\n- Now try one of the following (each one after performing previous steps in\n  separate new buffer):\n    - Press `u`. It goes back to empty buffer. Press `<C-R>` twice and it\n      goes to the latest change (`one two`). No way to get to other states\n      (like `two three` or `one three`) with these two keys.\n\n    - Press `g-`. It goes to an empty buffer. Press `g+` 4 times. It cycles\n      through all available undo states **in order they were created**.\n\n    - Finally, press `[u`. It goes back to `one two` - state which was\n      **previously visited** by the user. Another `[u` restores `one two three`.\n      Use `]U` to go to latest visited undo state.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                           *MiniBracketed.register_undo_state()*\n                     `MiniBracketed.register_undo_state`()\nRegister state for undo target\n\nUse this function to add current undo state to this module's linear undo\nhistory. It is used in |MiniBracketed.setup()| to remap |u| and |CTRL-R| keys\nto add their new state to linear undo history.\n\n------------------------------------------------------------------------------\n                                                        *MiniBracketed.window()*\n                  `MiniBracketed.window`({direction}, {opts})\nNormal window\n\nGo to next/previous normal window. Order by their number (see |winnr()|).\n\nDirection \"forward\" increases window number, \"backward\" - decreases.\n\nOnly normal (non-floating) windows are used.\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                          *MiniBracketed.yank()*\n                   `MiniBracketed.yank`({direction}, {opts})\nReplace \"latest put region\" with yank history entry\n\nAfter |MiniBracketed.setup()| is called, on every yank/delete/change operation\n(technically, every trigger of |TextYankPost| event) the object of operation\nis added to yank history. Advancing this target will replace the region of\nlatest put operation with entry from yank history.\n\nBy default works best if called **right after** text paste (like with |p| or |P|).\n\nTo better detect \"latest put region\", use |MiniBracketed.register_put_region()|\nas described later.\n\nDirection \"forward\" goes to newer yank history entry, \"backward\" - to older.\n\nExample:\n\n- Type `one two three`.\n- Yank each word with `yiw`.\n- Create new line and press `p`. This should paste `three`.\n- Type `[y`. This should replace latest `three` with `two`.\n\n# Latest put region ~\n\n\"Latest put region\" is (in order of decreasing priority):\n- The one from latest advance of this target.\n- The one registered by user with |MiniBracketed.register_put_region()|.\n- The one taken from |'[| and |']| marks.\n\nFor users there are these approaches to manage which region will be used:\n- Do nothing. In this case region between `[` / `]` marks will always be used\n  for first `yank` advance.\n  Although doable, this has several drawbacks: it will use latest yanked or\n  changed region or the entire buffer if marks are not set.\n  If remember to advance this target only after recent put operation, this\n  should work as expected.\n\n- Remap common put operations to use |MiniBracketed.register_put_region()|.\n  After that, only regions from mapped put operations will be used for first\n  advance. Example of custom mappings (note use of |:map-expression|): >lua\n\n    local put_keys = { 'p', 'P' }\n    for _, lhs in ipairs(put_keys) do\n      local rhs = 'v:lua.MiniBracketed.register_put_region(\"' .. lhs .. '\")'\n      vim.keymap.set({ 'n', 'x' }, lhs, rhs, { expr = true })\n    end\n<\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n  - <operators> `(table)` - array of operator names (\"c\", \"d\", or \"y\") for\n    which yank entry should be used to advance. For example, use `{ \"y\" }`\n    to advance only by entries actually resulted from yank operation with |y|.\n    Default: `{ 'c', 'd', 'y' }`.\n\n------------------------------------------------------------------------------\n                                           *MiniBracketed.register_put_region()*\n                 `MiniBracketed.register_put_region`({put_key})\nRegister \"latest put region\"\n\nThis function should be called after put register becomes relevant\n(|v:register| is appropriately set) but before put operation takes place\n(|'[| and |']| marks become relevant).\n\nDesigned to be used in a user-facing expression mapping (see |:map-expression|).\nFor mapping examples see |MiniBracketed.yank()|.\n\nParameters ~\n{put_key} `(string)` Put keys to be remapped.\n\nReturn ~\n`(string)` Returns `put_key` for a better usage inside expression mappings.\n\n------------------------------------------------------------------------------\n                                                       *MiniBracketed.advance()*\n            `MiniBracketed.advance`({iterator}, {direction}, {opts})\nAdvance iterator\n\nThis is the main function which performs any forward/backward/first/last\nadvance in this module. Its basic idea is to take iterator (object containing\ninformation about current state and how to go to next/previous one) and go\nin certain direction until needed/allowed.\n\nNotes:\n- Directions \"first\" and \"last\" are convenience wrappers for \"forward\" and\n  \"backward\" with pre-setting initial state to `start_edge` and `end_edge`.\n- Iterators `next()` and `prev()` methods should be able to handle `nil` as input.\n- This function only returns new state and doesn't modify `iterator.state`.\n\nParameters ~\n{iterator} `(table)` Table:\n  - Methods:\n      - <next> - given state, return state in forward direction (no wrap).\n      - <prev> - given state, return state in backward direction (no wrap).\n  - Fields:\n      - <state> - object describing current state.\n      - <start_edge> (optional) - object with `forward(start_edge)` describing\n        first state. If `nil`, can't wrap forward or use direction \"first\".\n      - <end_edge> (optional) - object with `backward(end_edge)` describing\n        last state. If `nil`, can't wrap backward or use direction \"last\".\n{direction} `(string)` Direction. One of \"first\", \"backward\", \"forward\", \"last\".\n{opts} `(table|nil)` Options with the following keys:\n  - <n_times> `(number)` - number of times to go in input direction.\n    Default: `v:count1`.\n  - <wrap> `(boolean)` - whether to wrap around edges when `next()` or\n    `prev()` return `nil`. Default: `true`.\n\nReturn ~\n`(any)` Result state. If `nil`, could not reach any valid result state.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-bufremove.txt",
    "content": "*mini.bufremove* Remove buffers\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                 *MiniBufremove*\nFeatures:\n- Unshow, delete, and wipeout buffer while saving window layout\n  (opposite to builtin Neovim's commands).\n\n# Setup ~\n\nThis module doesn't need setup, but it can be done to improve usability.\nSetup with `require('mini.bufremove').setup({})` (replace `{}` with your\n`config` table). It will create global Lua table `MiniBufremove` which you\ncan use for scripting or manually (with `:lua MiniBufremove.*`).\n\nSee |MiniBufremove.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minibufremove_config`\nwill have no effect here.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Notes ~\n\n1. Which buffer to show in window(s) after its current buffer is removed is\n   decided by the algorithm:\n   - If alternate buffer (see |CTRL-^|) is listed (see |buflisted()|), use it.\n   - If previous listed buffer (see |:bprevious|) is different, use it.\n   - Otherwise create a new one with `nvim_create_buf(true, false)` and use it.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.minibufremove_disable` (globally) or\n`vim.b.minibufremove_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                         *MiniBufremove.setup()*\n                        `MiniBufremove.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniBufremove.config|.\n\nUsage ~\n>lua\n  require('mini.bufremove').setup() -- use default config\n  -- OR\n  require('mini.bufremove').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                          *MiniBufremove.config*\n                             `MiniBufremove.config`\nDefaults ~\n>lua\n  MiniBufremove.config = {\n    -- Whether to disable showing non-error feedback\n    silent = false,\n  }\n<\n------------------------------------------------------------------------------\n                                                        *MiniBufremove.delete()*\n                   `MiniBufremove.delete`({buf_id}, {force})\nDelete buffer `buf_id` with |:bdelete| after unshowing it\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier (see |bufnr()|) to use.\n  Default: 0 for current.\n{force} `(boolean|nil)` Whether to ignore unsaved changes (using `!` version of\n  command). If `false`, calling with unsaved changes will prompt confirm dialog.\n  Default: `false`.\n\nReturn ~\n`(boolean|nil)` Whether operation was successful. If `nil`, no operation was done.\n\n------------------------------------------------------------------------------\n                                                       *MiniBufremove.wipeout()*\n                   `MiniBufremove.wipeout`({buf_id}, {force})\nWipeout buffer `buf_id` with |:bwipeout| after unshowing it\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier (see |bufnr()|) to use.\n  Default: 0 for current.\n{force} `(boolean|nil)` Whether to ignore unsaved changes (using `!` version of\n  command). If `false`, calling with unsaved changes will prompt confirm dialog.\n  Default: `false`.\n\nReturn ~\n`(boolean|nil)` Whether operation was successful. If `nil`, no operation was done.\n\n------------------------------------------------------------------------------\n                                                        *MiniBufremove.unshow()*\n                        `MiniBufremove.unshow`({buf_id})\nStop showing buffer `buf_id` in all windows\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier (see |bufnr()|) to use.\n  Default: 0 for current.\n\nReturn ~\n`(boolean|nil)` Whether operation was successful. If `nil`, no operation was done.\n\n------------------------------------------------------------------------------\n                                              *MiniBufremove.unshow_in_window()*\n                   `MiniBufremove.unshow_in_window`({win_id})\nStop showing current buffer of window `win_id`\n\nNotes:\n- If `win_id` represents |cmdline-window|, this function will close it.\n\nParameters ~\n{win_id} `(number|nil)` Window identifier (see |win_getid()|) to use.\n  Default: 0 for current.\n\nReturn ~\n`(boolean|nil)` Whether operation was successful. If `nil`, no operation was done.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-clue.txt",
    "content": "*mini.clue* Show next key clues\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniClue*\nFeatures:\n- Implement custom key query process to reach target key combination:\n    - Starts after customizable opt-in triggers (mode + keys).\n\n    - Each key press narrows down set of possible targets.\n      Pressing `<BS>` removes previous user entry.\n      Pressing `<Esc>` or `<C-c>` leads to an early stop.\n      Doesn't depend on 'timeoutlen' and has basic support for 'langmap'.\n\n    - Ends when there is at most one target left or user pressed `<CR>`.\n      Results into emulating pressing all query keys plus possible postkeys.\n\n- Show window (after configurable delay) with clues. It lists available\n  next keys along with their descriptions (auto generated from descriptions\n  present keymaps and user-supplied clues; preferring the former).\n\n- Configurable \"postkeys\" for key combinations - keys which will be emulated\n  after combination is reached during key query process.\n\n- Provide customizable sets of clues for common built-in keys/concepts:\n    - `g` key.\n    - `z` key.\n    - Window commands.\n    - Built-in completion.\n    - Marks.\n    - Registers.\n\n- Lua functions to disable/enable triggers globally or per buffer.\n\nFor more details see:\n- |MiniClue-key-query-process|.\n- |MiniClue-examples|.\n- |MiniClue.config|.\n- |MiniClue.gen_clues|.\n\nNotes:\n- There is no functionality to create mappings while defining clues.\n  This is done to clearly separate these two different actions.\n  The best suggested practice is to manually create mappings with\n  descriptions (`desc` field in options), as they will be automatically\n  used inside clue window.\n\n- Triggers are implemented as special buffer-local mappings. This leads to\n  several caveats:\n    - They will override same regular buffer-local mappings and have\n      precedence over global one.\n\n      Example: having set `<C-w>` as Normal mode trigger means that\n      there should not be another `<C-w>` mapping.\n\n    - They need to be the latest created buffer-local mappings or they will\n      not function properly. Most common indicator of this is that some\n      mapping starts to work only after clue window is shown.\n\n      Example: `g` is set as Normal mode trigger, but `gcc` from |mini.comment|\n      doesn't work right away. This is probably because there are some\n      other buffer-local mappings starting with `g` which were created after\n      mapping for `g` trigger. Most common places for this are in LSP server's\n      `on_attach` or during tree-sitter start in buffer.\n\n      To check if trigger is the most recent buffer-local mapping, execute\n      `:<mode-char>map <trigger-keys>` (like `:nmap g` for previous example).\n      Mapping for trigger should be the first listed.\n\n      This module makes the best effort to work out of the box and cover\n      most common cases, but it is not foolproof. The solution here is to\n      ensure that triggers are created after making all buffer-local mappings:\n      run either |MiniClue.setup()| or |MiniClue.ensure_buf_triggers()|.\n\n- Descriptions from existing mappings take precedence over user-supplied\n  clues. This is to ensure that information shown in clue window is as\n  relevant as possible. To add/customize description of an already existing\n  mapping, use |MiniClue.set_mapping_desc()|.\n\n- Due to technical difficulties, there is no foolproof support for\n  Operator-pending mode triggers (like `a`/`i` from |mini.ai|):\n    - Doesn't work as part of a command in \"temporary Normal mode\" (like\n      after |i_CTRL-O|) due to implementation difficulties.\n    - Can have unexpected behavior with custom operators.\n\n- Has (mostly solved) issues with macros:\n    - All triggers are disabled during macro recording due to technical\n      reasons.\n    - The `@` and `Q` keys are specially mapped inside |MiniClue.setup()|\n      (if the key is not already mapped) to temporarily disable triggers.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.clue').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniClue`\nwhich you can use for scripting or manually (with `:lua MiniClue.*`).\n\nConfig table **needs to have triggers configured**, none is set up by default.\n\nSee |MiniClue.config| for available config settings.\n\nYou can override runtime config settings (like clues or window options)\nlocally to a buffer inside `vim.b.miniclue_config` which should have same\nstructure as `MiniClue.config`. See |mini.nvim-buffer-local-config| for\nmore details.\n\n# Comparisons ~\n\n- [folke/which-key.nvim](https://github.com/folke/which-key.nvim):\n    - Both have the same main goal: show available next keys along with\n      their customizable descriptions.\n    - Has different UI and content layout.\n    - Allows creating mappings inside its configuration, while this module\n      doesn't have this by design (to clearly separate two different tasks).\n    - Doesn't allow creating submodes, while this module does (via `postkeys`).\n\n- [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim):\n    - Both allow creating submodes: state which starts at certain key\n      combination; treats some keys differently; ends after `<Esc>`.\n    - Doesn't show information about available next keys (outside of\n      submodes), while that is this module's main goal.\n\n# Highlight groups ~\n\n- `MiniClueBorder` - window border.\n- `MiniClueDescGroup` - group description in clue window.\n- `MiniClueDescSingle` - single target description in clue window.\n- `MiniClueNextKey` - next key label in clue window.\n- `MiniClueNextKeyWithPostkeys` - next key label with postkeys in clue window.\n- `MiniClueSeparator` - separator in clue window.\n- `MiniClueTitle` - window title.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable creating triggers, set `vim.g.miniclue_disable` (globally) or\n`vim.b.miniclue_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                    *MiniClue-key-query-process*\n# General info ~\n\nThis module implements custom key query process imitating a usual built-in\nmechanism of user pressing keys in order to execute a mapping. General idea\nis the same: narrow down key combinations until the target is reached.\n\nMain goals of its existence are:\n\n- Allow reaching certain mappings be independent of 'timeoutlen'. That is,\n  there is no fixed timeout after which currently typed keys are executed.\n\n- Enable automated showing of next key clues after user-supplied delay\n  (also independent of 'timeoutlen').\n\n- Allow emulating configurable key presses after certain key combination is\n  reached. This granular control allows creating so called \"submodes\".\n  See more at |MiniClue-examples-submodes|.\n\nThis process is primarily designed for nested `<Leader>` mappings in Normal\nmode but works in all other main modes: Visual, Insert, Operator-pending\n(with caveats; no foolproof guarantees), Command-line, Terminal.\n\n# Lifecycle ~\n\n- Key query process starts when user types a trigger: certain keys in certain\n  mode. Those keys are put into key query as a single user input. All possible\n  mode key combinations are filtered to ones starting with the trigger keys.\n\n  Note: trigger is implemented as a regular mapping, so if it has at least\n  two keys, they should be pressed within 'timeoutlen' milliseconds.\n\n- Wait (indefinitely) for user to press a key. Advance depending on the key:\n\n    - Special key:\n\n        - If `<Esc>` or `<C-c>`, stop the process without any action.\n\n        - If `<CR>`, stop the process and execute current key query, meaning\n          emulate (with |nvim_feedkeys()|) user pressing those keys.\n\n        - If `<BS>`, remove previous user input from the query. If query becomes\n          empty, stop the process without any action.\n\n        - If a key for scrolling clue window (`scroll_down` / `scroll_up`\n          in `config.window`; `<C-d>` / `<C-u>` by default), scroll clue window\n          and wait for the next user key.\n          Note: if clue window is not shown, treated as a not special key.\n\n    - Not special key. Add key to the query while filtering all available\n      key combinations to start with the current key query. Advance:\n\n        - If there is a single available key combination matching current\n          key query, execute it.\n\n        - If there is no key combinations starting with the current query,\n          execute it. This, for instance, allows a seamless execution of\n          operators in presence of a longer key combinations. Example: with\n          `g` as trigger in Normal mode and available mappings `gc` / `gcc`\n          (like from |mini.comment|), this allows typing `gcip` to comment\n          current paragraph, although there are no key combinations\n          starting with `gci`.\n\n        - Otherwise wait for the new user key press.\n\n# Clue window ~\n\nAfter initiating key query process and after each key press, a timer is\nstarted to show a clue window: floating window with information about\navailable next keys along with their descriptions. Note: if window is\nalready shown, its content is updated right away.\n\nClues can have these types:\n\n- \"Terminal next key\": when pressed, will lead to query execution.\n\n- \"Terminal next key with postkeys\": when pressed, will lead to query\n  execution plus some configured postkeys.\n\n- \"Group next key\": when pressed, will narrow down available key combinations\n  and wait for another key press. Note: can have configured description\n  (inside `config.clues`) or it will be auto generated based on the number of\n  available key combinations.\n\n------------------------------------------------------------------------------\n                                                             *MiniClue-examples*\n# Full starter example ~\n\nIf not sure where to start, try this example with all provided clues from\nthis module plus all |<Leader>| mappings in Normal and Visual modes: >lua\n\n  local miniclue = require('mini.clue')\n  miniclue.setup({\n    triggers = {\n      -- Leader triggers\n      { mode = { 'n', 'x' }, keys = '<Leader>' },\n\n      -- `[` and `]` keys\n      { mode = 'n', keys = '[' },\n      { mode = 'n', keys = ']' },\n\n      -- Built-in completion\n      { mode = 'i', keys = '<C-x>' },\n\n      -- `g` key\n      { mode = { 'n', 'x' }, keys = 'g' },\n\n      -- Marks\n      { mode = { 'n', 'x' }, keys = \"'\" },\n      { mode = { 'n', 'x' }, keys = '`' },\n\n      -- Registers\n      { mode = { 'n', 'x' }, keys = '\"' },\n      { mode = { 'i', 'c' }, keys = '<C-r>' },\n\n      -- Window commands\n      { mode = 'n', keys = '<C-w>' },\n\n      -- `z` key\n      { mode = { 'n', 'x' }, keys = 'z' },\n    },\n\n    clues = {\n      -- Enhance this by adding descriptions for <Leader> mapping groups\n      miniclue.gen_clues.square_brackets(),\n      miniclue.gen_clues.builtin_completion(),\n      miniclue.gen_clues.g(),\n      miniclue.gen_clues.marks(),\n      miniclue.gen_clues.registers(),\n      miniclue.gen_clues.windows(),\n      miniclue.gen_clues.z(),\n    },\n  })\n<\n# Leader clues ~\n\nAssume there are these |<Leader>| mappings set up: >lua\n\n  -- Set `<Leader>` before making any mappings and configuring 'mini.clue'\n  vim.g.mapleader = ' '\n\n  local nmap_leader = function(suffix, rhs, desc)\n    vim.keymap.set('n', '<Leader>' .. suffix, rhs, { desc = desc })\n  end\n  local xmap_leader = function(suffix, rhs, desc)\n    vim.keymap.set('x', '<Leader>' .. suffix, rhs, { desc = desc })\n  end\n\n  nmap_leader('bd', '<Cmd>lua MiniBufremove.delete()<CR>',  'Delete')\n  nmap_leader('bw', '<Cmd>lua MiniBufremove.wipeout()<CR>', 'Wipeout')\n\n  nmap_leader('lf', '<Cmd>lua vim.lsp.buf.format()<CR>',     'Format')\n  xmap_leader('lf', '<Cmd>lua vim.lsp.buf.format()<CR>',     'Format')\n  nmap_leader('lr', '<Cmd>lua vim.lsp.buf.rename()<CR>',     'Rename')\n  nmap_leader('lR', '<Cmd>lua vim.lsp.buf.references()<CR>', 'References')\n<\nThe following setup will enable |<Leader>| as trigger in Normal and Visual\nmodes and add descriptions to mapping groups: >lua\n\n  require('mini.clue').setup({\n    -- Register `<Leader>` as trigger\n    triggers = {\n      { mode = { 'n', 'x' }, keys = '<Leader>' },\n    },\n\n    -- Add descriptions for mapping groups\n    clues = {\n      { mode = 'n', keys = '<Leader>b', desc = '+Buffers' },\n      { mode = 'n', keys = '<Leader>l', desc = '+LSP' },\n    },\n  })\n<\n# Clues without mappings ~\n\nClues can be shown not only for actually present mappings. This is helpful for\nshowing clues for built-in key combinations. Here is an example of clues for\na subset of built-in completion (see |MiniClue.gen_clues.builtin_completion()|\nto generate clues for all available completion sources): >lua\n\n  require('mini.clue').setup({\n    -- Make `<C-x>` a trigger. Otherwise, key query process won't start.\n    triggers = {\n      { mode = 'i', keys = '<C-x>' },\n    },\n\n    -- Register custom clues\n    clues = {\n      { mode = 'i', keys = '<C-x><C-f>', desc = 'File names' },\n      { mode = 'i', keys = '<C-x><C-l>', desc = 'Whole lines' },\n      { mode = 'i', keys = '<C-x><C-o>', desc = 'Omni completion' },\n      { mode = 'i', keys = '<C-x><C-s>', desc = 'Spelling suggestions' },\n      { mode = 'i', keys = '<C-x><C-u>', desc = \"With 'completefunc'\" },\n    }\n  })\n<\n# Triggers in special buffers ~\n\nBy default triggers are automatically created in listed ('buflisted') and some\nspecial non-listed buffers. Use |MiniClue.ensure_buf_triggers()| to manually\nenable in when you need them. For example: >vim\n\n  au FileType special_ft lua MiniClue.ensure_buf_triggers()\n<\n# Submodes ~\n*MiniClue-examples-submodes*\n\nSubmode is a state initiated after pressing certain key combination (\"prefix\")\nduring which some keys are interpreted differently.\n\nIn this module submode can be implemented following these steps:\n\n- Create mappings for each key inside submode. Left hand side of mappings\n  should consist from prefix followed by the key.\n\n- Create clue for each key inside submode with `postkeys` value equal to\n  prefix. It would mean that after executing particular key combination from\n  this submode, pressing its prefix will be automatically emulated (leading\n  back to being inside submode).\n\n- Register submode prefix (or some of its starting part) as trigger. Do not\n  register \"overlapping\" triggers, like `<Leader>` and `<Leader>m`.\n\n## Submode examples ~\n\n- Submode for moving with |mini.move|:\n    - Press `<Leader>m` to start submode.\n    - Press any of `h`/`j`/`k`/`l` to move selection/line.\n    - Press `<Esc>` to stop submode.\n\n  The code: >lua\n\n  require('mini.move').setup({\n    mappings = {\n      left       = '<Leader>mh',\n      right      = '<Leader>ml',\n      down       = '<Leader>mj',\n      up         = '<Leader>mk',\n      line_left  = '<Leader>mh',\n      line_right = '<Leader>ml',\n      line_down  = '<Leader>mj',\n      line_up    = '<Leader>mk',\n    },\n  })\n\n  require('mini.clue').setup({\n    triggers = {\n      -- This can also set up directly `<Leader>m` as a trigger, but make\n      -- sure to not also use `<Leader>`, as they would \"overlap\"\n      { mode = { 'n', 'x' }, keys = '<Leader>' },\n    },\n    clues = {\n      { mode = 'n', keys = '<Leader>m', desc = '+Move' },\n\n      { mode = { 'n', 'x' }, keys = '<Leader>mh', postkeys = '<Leader>m' },\n      { mode = { 'n', 'x' }, keys = '<Leader>mj', postkeys = '<Leader>m' },\n      { mode = { 'n', 'x' }, keys = '<Leader>mk', postkeys = '<Leader>m' },\n      { mode = { 'n', 'x' }, keys = '<Leader>ml', postkeys = '<Leader>m' },\n    },\n  })\n<\n- Submode for iterating buffers and windows with |mini.bracketed|:\n    - Press `[` or `]` to start key query process for certain direction.\n    - Press `b` / `w` to iterate buffers/windows until reach target one.\n    - Press `<Esc>` to stop submode.\n\n  The code: >lua\n\n  require('mini.bracketed').setup()\n\n  require('mini.clue').setup({\n    triggers = {\n      { mode = 'n', keys = ']' },\n      { mode = 'n', keys = '[' },\n    },\n    clues = {\n      { mode = 'n', keys = ']b', postkeys = ']' },\n      { mode = 'n', keys = ']w', postkeys = ']' },\n\n      { mode = 'n', keys = '[b', postkeys = '[' },\n      { mode = 'n', keys = '[w', postkeys = '[' },\n    },\n  })\n<\n- Submode for window commands using |MiniClue.gen_clues.windows()|:\n    - Press `<C-w>` to start key query process.\n    - Press keys which move / change focus / resize windows.\n    - Press `<Esc>` to stop submode.\n\n  The code: >lua\n\n  local miniclue = require('mini.clue')\n  miniclue.setup({\n    triggers = {\n      { mode = 'n', keys = '<C-w>' },\n    },\n    clues = {\n      miniclue.gen_clues.windows({\n        submode_move = true,\n        submode_navigate = true,\n        submode_resize = true,\n      })\n    },\n  })\n<\n# Window config ~\n>lua\n  require('mini.clue').setup({\n    triggers = { { mode = 'n', keys = '<Leader>' } },\n\n    window = {\n      -- Show window immediately\n      delay = 0,\n\n      config = {\n        -- Compute window width automatically\n        width = 'auto',\n\n        -- Use double-line border\n        border = 'double',\n      },\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                                              *MiniClue.setup()*\n                           `MiniClue.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniClue.config|.\n\nUsage ~\n>lua\n  require('mini.clue').setup({}) -- replace {} with your config table\n                                 -- needs `triggers` field present\n<\n------------------------------------------------------------------------------\n                                                               *MiniClue.config*\n                               `MiniClue.config`\nDefaults ~\n>lua\n  MiniClue.config = {\n    -- Array of extra clues to show\n    clues = {},\n\n    -- Array of opt-in triggers which start custom key query process.\n    -- **Needs to have something in order to show clues**.\n    triggers = {},\n\n    -- Clue window settings\n    window = {\n      -- Floating window config\n      config = {},\n\n      -- Delay before showing clue window\n      delay = 1000,\n\n      -- Keys to scroll inside the clue window\n      scroll_down = '<C-d>',\n      scroll_up = '<C-u>',\n    },\n  }\n<\n# General info ~\n\n- To use |<Leader>| as part of the config (either as trigger or inside clues),\n  set it prior to running |MiniClue.setup()|.\n\n- See |MiniClue-examples| for examples.\n\n# Clues ~\n\n`config.clues` is an array with extra information about key combinations.\nEach element can be one of:\n- Clue table.\n- Array (possibly nested) of clue tables.\n- Callable (function) returning either of the previous two.\n\nA clue table is a table with the following fields:\n- <mode> `(string|table)` - single character describing mode short-name of\n  key combination as in `nvim_set_keymap()` ('n', 'x', 'i', 'o', 'c', etc.),\n  or a array thereof.\n- <keys> `(string)` - key combination for which clue will be shown.\n  \"Human-readable\" key names as in |key-notation| (like \"<Leader>\", \"<Space>\",\n  \"<Tab>\", etc.) are allowed.\n- <desc> `(string|function|nil)` - optional key combination description which is\n  shown in clue window. If function, should return string description.\n- <postkeys> `(string|nil)` - optional postkeys which will be executed\n  automatically after `keys`. Allows creation of submodes\n  (see |MiniClue-examples-submodes|).\n\nNotes:\n- Postkeys are literal simulation of keypresses with |nvim_feedkeys()|.\n\n- Suggested approach to configuring clues is to create mappings with `desc`\n  field while supplying to `config.clues` only elements describing groups,\n  postkeys, and built-in mappings.\n\n# Triggers ~\n\n`config.triggers` is an array with information when |MiniClue-key-query-process|\nshould start. Each element is a trigger table with the fields <mode> and\n<keys> which are treated the same as in clue table.\n\n# Window ~\n\n`config.window` defines behavior of clue window.\n\n`config.window.delay` is a number of milliseconds after which clue window will\nappear. Can be 0 to show immediately.\n\n`config.window.config` is a table defining floating window characteristics\nor a callable returning such table (will be called with identifier of\nwindow's buffer already showing all clues). It should have the same\nstructure as in |nvim_open_win()| with the following enhancements:\n- <width> field can be equal to `\"auto\"` leading to window width being\n  computed automatically based on its content. Default is fixed width of 30.\n- <row> and <col> can be equal to `\"auto\"` in which case they will be\n  computed to \"stick\" to set anchor (\"SE\" by default; see |nvim_open_win()|).\n  This allows changing corner in which window is shown: >lua\n\n  -- Pick one anchor\n  local anchor = 'NW' -- top-left\n  local anchor = 'NE' -- top-right\n  local anchor = 'SW' -- bottom-left\n  local anchor = 'SE' -- bottom-right\n\n  require('mini.clue').setup({\n    window = {\n      config = { anchor = anchor, row = 'auto', col = 'auto' },\n    },\n  })\n<\n`config.window.scroll_down` / `config.window.scroll_up` are strings defining\nkeys which will scroll clue window down / up which is useful in case not\nall clues fit in current window height. Set to empty string `''` to disable\neither of them.\n\n------------------------------------------------------------------------------\n                                                *MiniClue.enable_all_triggers()*\n                        `MiniClue.enable_all_triggers`()\nEnable triggers in loaded listed and some special buffers\n\n------------------------------------------------------------------------------\n                                                *MiniClue.enable_buf_triggers()*\n                    `MiniClue.enable_buf_triggers`({buf_id})\nEnable triggers in buffer\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier. Default: current buffer.\n\n------------------------------------------------------------------------------\n                                               *MiniClue.disable_all_triggers()*\n                       `MiniClue.disable_all_triggers`()\nDisable triggers in loaded buffers\n\n------------------------------------------------------------------------------\n                                               *MiniClue.disable_buf_triggers()*\n                   `MiniClue.disable_buf_triggers`({buf_id})\nDisable triggers in buffer\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier. Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                *MiniClue.ensure_all_triggers()*\n                        `MiniClue.ensure_all_triggers`()\nEnsure all triggers are valid\n\n------------------------------------------------------------------------------\n                                                *MiniClue.ensure_buf_triggers()*\n                    `MiniClue.ensure_buf_triggers`({buf_id})\nEnsure buffer triggers are valid\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier. Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                   *MiniClue.set_mapping_desc()*\n               `MiniClue.set_mapping_desc`({mode}, {lhs}, {desc})\nUpdate description of an existing mapping\n\nNotes:\n- Uses buffer-local mapping in case there are both global and buffer-local\n  mappings with same mode and LHS. Similar to |maparg()|.\n\nParameters ~\n{mode} `(string)` Mapping mode (as in `maparg()`).\n{lhs} `(string)` Mapping left hand side (as `name` in `maparg()`).\n{desc} `(string)` New description to set.\n\n------------------------------------------------------------------------------\n                                                            *MiniClue.gen_clues*\n                              `MiniClue.gen_clues`\nGenerate pre-configured clues\n\nThis is a table with function elements. Call to actually get array of clues.\n\n------------------------------------------------------------------------------\n                                       *MiniClue.gen_clues.builtin_completion()*\n                   `MiniClue.gen_clues.builtin_completion`()\nGenerate clues for built-in completion\n\nContains clues for the following triggers: >lua\n\n  { mode = 'i', keys = '<C-x>' }\n<\nReturn ~\n`(table)` Array of clues.\n\n------------------------------------------------------------------------------\n                                                        *MiniClue.gen_clues.g()*\n                            `MiniClue.gen_clues.g`()\nGenerate clues for `g` key\n\nContains clues for the following triggers: >lua\n\n  { mode = { 'n', 'x' }, keys = 'g' }\n<\nReturn ~\n`(table)` Array of clues.\n\n------------------------------------------------------------------------------\n                                          *MiniClue.gen_clues.square_brackets()*\n                     `MiniClue.gen_clues.square_brackets`()\nGenerate clues for `[` and `]` keys\n\nContains clues for the following triggers: >lua\n\n  { mode = 'n', keys = '[' }\n  { mode = 'n', keys = ']' }\n<\nReturn ~\n`(table)` Array of clues.\n\n------------------------------------------------------------------------------\n                                                    *MiniClue.gen_clues.marks()*\n                          `MiniClue.gen_clues.marks`()\nGenerate clues for marks\n\nContains clues for the following triggers: >lua\n\n  { mode = { 'n', 'x' }, keys = \"'\" }\n  { mode = { 'n', 'x' }, keys = \"g'\" }\n  { mode = { 'n', 'x' }, keys = '`' }\n  { mode = { 'n', 'x' }, keys = 'g`' }\n<\nNote: if you use \"g\" as trigger (like to enable |MiniClue.gen_clues.g()|),\ndon't add \"g'\" and \"g`\" as triggers: they already will be taken into account.\n\nReturn ~\n`(table)` Array of clues.\n\nSee also ~\n|mark-motions|\n\n------------------------------------------------------------------------------\n                                                *MiniClue.gen_clues.registers()*\n                     `MiniClue.gen_clues.registers`({opts})\nGenerate clues for registers\n\nContains clues for the following triggers: >lua\n\n  { mode = { 'n', 'x' }, keys = '\"' }\n  { mode = { 'i', 'c' }, keys = '<C-r>' }\n<\nParameters ~\n{opts} `(table|nil)` Options. Possible keys:\n  - <show_contents> `(boolean)` - whether to show contents of all possible\n    registers. If `false`, only description of special registers is shown.\n    Default: `false`.\n\nReturn ~\n`(table)` Array of clues.\n\nSee also ~\n|registers|\n\n------------------------------------------------------------------------------\n                                                  *MiniClue.gen_clues.windows()*\n                      `MiniClue.gen_clues.windows`({opts})\nGenerate clues for window commands\n\nContains clues for the following triggers: >lua\n\n  { mode = 'n', keys = '<C-w>' }\n<\nNote: only non-duplicated commands are included. For full list see |CTRL-W|.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible keys:\n  - <submode_move> `(boolean)` - whether to make move (change layout)\n    commands a submode by using `postkeys` field. Default: `false`.\n  - <submode_navigate> `(boolean)` - whether to make navigation (change\n    focus) commands a submode by using `postkeys` field. Default: `false`.\n  - <submode_resize> `(boolean)` - whether to make resize (change size)\n    commands a submode by using `postkeys` field. Default: `false`.\n\nReturn ~\n`(table)` Array of clues.\n\n------------------------------------------------------------------------------\n                                                        *MiniClue.gen_clues.z()*\n                            `MiniClue.gen_clues.z`()\nGenerate clues for `z` key\n\nContains clues for the following triggers: >lua\n\n  { mode = { 'n', 'x' }, keys = 'z' }\n<\nReturn ~\n`(table)` Array of clues.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-cmdline.txt",
    "content": "*mini.cmdline* Command line tweaks\n\nMIT License Copyright (c) 2025 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                   *MiniCmdline*\nFeatures:\n\n- Autocomplete with customizable delay. Enhances |cmdline-completion| and\n  manual |'wildchar'| pressing experience.\n  Requires Neovim>=0.11, though Neovim>=0.12 is recommended.\n\n- Autocorrect words as-you-type. Only words that must come from a fixed set of\n  candidates (like commands and options) are autocorrected by default.\n\n- Autopeek command range as-you-type. Shows a floating window with range lines\n  along with customizable context lines.\n\nWhat it doesn't do:\n\n- Customization of command line UI. Use |vim._extui| (on Neovim>=0.12).\n\n- Customization of autocompletion candidates. They are computed\n  via |cmdline-completion|.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.cmdline').setup({})` (replace `{}`\nwith your `config` table). It will create global Lua table `MiniCmdline` which\nyou can use for scripting or manually (with `:lua MiniCmdline.*`).\n\nSee |MiniCmdline.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minicmdline_config` which should have same structure as\n`MiniCmdline.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Suggested option values ~\n\nSome options are set automatically (if not set before |MiniCmdline.setup()|):\n- |'wildmode'| is set to \"noselect,full\" for less intrusive autocompletion.\n  Requires Neovim>=0.11 and enabled `config.autocomplete`.\n- |'wildoptions'| is set to \"pum,fuzzy\" to enable fuzzy matching.\n\n# Comparisons ~\n\n- [folke/noice.nvim](https://github.com/folke/noice.nvim):\n    - Mostly focuses on visual aspects of the Command line.\n      This modules is aimed to improve its workflow without changing UI.\n\n- [nacro90/numb.nvim](https://github.com/nacro90/numb.nvim):\n    - Designed to preview only a single line range defined by numbers.\n      This module handles any form of |:range| and |:range-offset| for both\n      one and two line ranges.\n    - Shows target line directly in the normal window.\n      This module uses a dedicated floating window.\n\n- Built-in |cmdline-autocompletion| (on Neovim>=0.12):\n    - This module on Neovim>=0.12 uses that as its base for autocompletion.\n      Ont top of that it also provides customizable delay and predicate.\n\n- Built-in |vim._extui| (on Neovim>=0.12):\n    - Mostly focuses on visual aspects of the Command line.\n      This modules is aimed to improve its workflow without changing UI.\n\n# Highlight groups ~\n\n- `MiniCmdlinePeekBorder` - border of autopeek window.\n- `MiniCmdlinePeekLineNr` - line numbers in autopeek window.\n- `MiniCmdlinePeekNormal` - basic foreground/background of autopeek window.\n- `MiniCmdlinePeekSep` - statuscolumn separator in autopeek window.\n- `MiniCmdlinePeekSign` - signs in autopeek window.\n- `MiniCmdlinePeekTitle` - title of autopeek window.\n\n# Disabling ~\n\nTo disable acting in mappings, set `vim.g.minicmdline_disable` (globally) or\n`vim.b.minicmdline_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user.\nSee |mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                           *MiniCmdline.setup()*\n                         `MiniCmdline.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniCmdline.config|.\n\nUsage ~\n>lua\n  require('mini.cmdline').setup() -- use default config\n  -- OR\n  require('mini.cmdline').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                            *MiniCmdline.config*\n                              `MiniCmdline.config`\nDefaults ~\n>lua\n  MiniCmdline.config = {\n    -- Autocompletion: show `:h 'wildmenu'` as you type\n    autocomplete = {\n      enable = true,\n\n      -- Delay (in ms) after which to trigger completion\n      -- Neovim>=0.12 is recommended for positive values\n      delay = 0,\n\n      -- Custom rule of when to trigger completion\n      predicate = nil,\n\n      -- Whether to map arrow keys for more consistent wildmenu behavior\n      map_arrows = true,\n    },\n\n    -- Autocorrection: adjust non-existing words (commands, options, etc.)\n    autocorrect = {\n      enable = true,\n\n      -- Custom autocorrection rule\n      func = nil,\n    },\n\n    -- Autopeek: show command's target range in a floating window\n    autopeek = {\n      enable = true,\n\n      -- Number of lines to show above and below range lines\n      n_context = 1,\n\n      -- Custom rule of when to show peek window\n      predicate = nil,\n\n      -- Window options\n      window = {\n        -- Floating window config\n        config = {},\n\n        -- Function to render statuscolumn\n        statuscolumn = nil,\n      },\n    },\n  }\n<\n# General ~\n\n- Each feature is configured via separate table.\n- Use `enable = false` to disable a feature.\n\nAutocomplete ~\n\n`config.autocomplete` is used to configure autocompletion: automatic show\nof |'wildmenu'|.\n\n`autocomplete.delay` defines a (debounce style) delay after which |'wildchar'|\nis triggered to show wildmenu.\nDefault: 0. Note: Neovim>=0.12 is recommended for positive values if you\nwant to reduce flicker (thanks to |wildtrigger()|).\n\n`autocomplete.predicate` defines a condition of whether to trigger completion\nat the current command line state. Takes a table with input data and should\nreturn `true` to show completion and `false` otherwise. Will be called before\nthe possible delay at current command line state.\nDefault: |MiniCmdline.default_autocomplete_predicate()|.\n\nInput data fields:\n- <line> `(string)` - current command line text. See |getcmdline()|.\n- <pos> `(number)` - current command line column. See |getcmdpos()|.\n- <line_prev> `(string)` - command line text before the latest change.\n- <pos_prev> `(number)` - command line column before the latest cursor move.\n\nExample of blocking completion based on completion type (as some may be slow): >lua\n\n  local block_compltype = { shellcmd = true }\n  require('mini.cmdline').setup({\n    autocomplete = {\n      predicate = function()\n        return not block_compltype[vim.fn.getcmdcompltype()]\n      end,\n    },\n  })\n<\nSimilar approach can be used to enable completion only for normal Ex commands.\nUse `return vim.fn.getcmdtype() == ':'` as a predicate output.\n\nAutocorrect ~\n\n`config.autocorrect` is used to configure autocorrection: automatic adjustment\nof bad words as you type them. This works only when appending single character\nat the end of the command line. Editing already typed words does not trigger\nautocorrect (allows correcting the autocorrection).\n\nWhen to autocorrect is computed automatically based on |getcmdcomplpat()| after\nevery key press: if it doesn't add the character to completion pattern, then\nthe pattern before the key press is attempted to be corrected.\nThere is also an autocorrection attempt for the last word just before\nexecuting the command.\n\nNotes:\n- This is intended mostly for fixing typos and not as a shortcut for fuzzy\n  matching. Performing the latter automatically is too intrusive. Explicitly\n  use fuzzy completion for that (set up by default).\n\n- Default autocorrection is done only for words that must come from a fixed\n  set of candidates (like commands and options) by choosing the one with\n  the lowest string distance.\n  See |MiniCmdline.default_autocorrect_func()| for details.\n\n- Word that matches some Command-line |abbreviation| is not autocorrected.\n\n- If current command expects only a single argument (like |:colorscheme|), then\n  autocorrection will happen only just before executing the command.\n\n`autocorrect.func` is a function that can be used to customize autocorrection.\nTakes a table with input data and should return a string with the correct word\nor `nil` for no autocorrection. Default: |MiniCmdline.default_autocorrect_func()|.\n\nInput data fields:\n- <word> `(string)` - word to be autocorrected. Never empty string.\n- <type> `(string)` - word type. Output of |getcmdcompltype()|.\n\nAutopeek ~\n\n`config.autopeek` is used to configure automatic peeking: show command's target\nrange in a floating window. The window will appear above command line and show\ncurrent buffer with the focus on left and right (if present and differs from\nleft) range lines.\n\n`autopeek.n_context` defines how many lines to show above and below the target.\nThe range itself is visualized by default with the statuscolumn signs.\nDefault: 1.\n\n`autopeek.predicate` defines a condition of whether to show peek window at\nthe current command line state. Takes a table with input data and should\nreturn `true` to peek and `false` otherwise.\nWill be called only if it is possible to parse range from the current command\nline text and it is for buffer lines (no command or |:command-addr| is `lines`)\nDefault: |MiniCmdline.default_autopeek_predicate()|.\n\nInput data fields:\n- <left> `(number)` - left range edge. Not necessarily smallest.\n- <right> `(number)` - right range edge. Same as `left` for a single line range.\n- <cmd> `(string)` - full command name. Can be empty string if no valid\n  command is (yet) entered.\n\n`autopeek.window` defines behavior of a peek window.\n`autopeek.window.config` is a table defining floating window characteristics\nor a callable returning such table.\nIt should have the same structure as in |nvim_open_win()|.\n\n`autopeek.window.statuscolumn` is a special function that can be used to\ncustomize |'statuscolumn'| value for the peek window. Takes a table with input\ndata and should return a string to display for line |v:lnum|.\nDefault: |MiniCmdline.default_autopeek_statuscolumn()|.\nInput data fields are the same as for `autopeek.predicate`.\n\nExample of showing `<` and `>` signs on range lines: >lua\n\n  function(data)\n    local n, l, r = vim.v.lnum, data.left, data.right\n    local s = n == l and (n == r and '* ' or '< ') or n == r and '> ' or ''\n    -- Needs explicit highlighting via `:h 'statusline'` syntax\n    return '%#MiniCmdlinePeekSign#' .. s\n  end\n<\nNotes:\n- Peek window directly shows current buffer, which means that all its\n  extmarks, virtual text, virtual lines, etc. are also shown.\n- Non-zero context might work unreliably if there are virtual lines.\n- Peeking intentionally hides Visual selection if Command-line mode is entered\n  directly from it. Peeking `'<,'>` range already visualizes the selection.\n  To disable autopeek for this case, add the following code BEFORE\n  executing `require('mini.cmdline').setup()`: >lua\n\n    local disable = vim.schedule_wrap(function()\n      local is_from_visual = vim.startswith(vim.fn.getcmdline(), \"'<,'>\")\n      MiniCmdline.config.autopeek.enable = not is_from_visual\n    end)\n    local reenable = function() MiniCmdline.config.autopeek.enable = true end\n\n    vim.api.nvim_create_autocmd('CmdlineEnter', { callback = disable })\n    vim.api.nvim_create_autocmd('CmdlineLeave', { callback = reenable })\n<\n------------------------------------------------------------------------------\n                                  *MiniCmdline.default_autocomplete_predicate()*\n          `MiniCmdline.default_autocomplete_predicate`({data}, {opts})\nDefault autocompletion predicate\n\nParameters ~\n{data} `(table)` Input autocompletion data. As described in |MiniCmdline.config|.\n{opts} `(table|nil)` Options. Reserved for future use.\n\nReturn ~\n`(boolean)` If command line does not (yet) contain a letter - `false`,\n  otherwise - `true`. This makes autopeek easier to use for a numerical range.\n\n------------------------------------------------------------------------------\n                                        *MiniCmdline.default_autocorrect_func()*\n             `MiniCmdline.default_autocorrect_func`({data}, {opts})\nDefault autocorrection function\n\n- Return input word if `opts.strict_type=true` and input `type` is not proper.\n- Get candidates via `opts.get_candidates()`.\n  Default: mostly via |getcompletion()| with empty pattern and input `type`.\n  Exceptions are `help` and `option` types: both list all available candidates\n  in their own ways.\n- Choose the candidate with the lowest Damerau–Levenshtein distance\n  (smallest number of deletion/insertion/substitution/transposition needed\n  to transform one word into another; slightly prefers transposition).\n  Notes:\n    - Type `'command'` also chooses from all valid candidate abbreviations.\n    - Comparison is done both respecting and ignoring case.\n\nParameters ~\n{data} `(table)` Input autocorrection data. As described in |MiniCmdline.config|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <strict_type> `(boolean)` - whether to restrict output only for types which\n    must have words from a fixed set of candidates (like command or option\n    names). Note: does not include `help` type since |:help| already has\n    \"sophisticated algorithm\" to handle typos. Default: `true`.\n  - <get_candidates> `(function)` - source of candidates. Will be called\n    with `data` as argument and should return array of string candidates to\n    choose from.\n    Default: for most types -  |getcompletion()| with empty pattern and\n    input `type`; for `help` and `option` type - all available help tags and\n    option names (long and short) respectively.\n\nReturn ~\n`(string)` Autocorrected word.\n\n------------------------------------------------------------------------------\n                                      *MiniCmdline.default_autopeek_predicate()*\n            `MiniCmdline.default_autopeek_predicate`({data}, {opts})\nDefault autopeek predicate\n\nParameters ~\n{data} `(table)` Input autopeek data. As described in |MiniCmdline.config|.\n{opts} `(table|nil)` Options. Reserved for future use.\n\nReturn ~\n`(boolean)` If command defines |:command-preview| - `false`, otherwise - `true`.\n  This makes autopeek easier to use for commands like |:substitute|,\n  especially if |'inccommand'| is set to `split`.\n\n------------------------------------------------------------------------------\n                                   *MiniCmdline.default_autopeek_statuscolumn()*\n          `MiniCmdline.default_autopeek_statuscolumn`({data}, {opts})\nDefault autopeek statuscolumn\n\n- Show signs next to lines depending on their relation to peeked range.\n  Highlighted with `MiniCmdlinePeekSign` group.\n- Show line numbers for left and right parts of the range.\n  Highlighted with `MiniCmdlinePeekLineNr` group.\n- Separate statuscolumn and buffer text with dedicated separator character.\n  Highlighted with `MiniCmdlinePeekSep` group.\n\nNotes:\n- Intended to only be used as a part of |'statuscolumn'| function, as it\n  uses |v:lnum| and |v:virtnum| to compute the output.\n\nExample of adjusting a `mid` sign: >lua\n\n  local peek_stc_opts = { signs = { mid = '+' } }\n  local peek_stc = function(data)\n    return MiniCmdline.default_autopeek_statuscolumn(data, peek_stc_opts)\n  end\n  require('mini.cmdline').setup({\n    autopeek = { window = { statuscolumn = peek_stc } },\n  })\n<\nParameters ~\n{data} `(table)` Input peek data. As described in |MiniCmdline.config|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <signs> `(table)` - signs to show. Possible fields:\n      - <same> `(string)` - on range if `left=right`. Default: `'🭬'`.\n      - <left> `(string)`  - on `left` line.  Default: `'┌'`.\n      - <mid> `(string)`   - inside range.  Default: `'┊'`.\n      - <right> `(string)` - on `right` line. Default: `'└'`.\n      - <out> `(string)` - outside of range. Default: `''` (no sign).\n      - <virt> `(string)` - virtual line. Default: `'•'`.\n      - <wrap> `(string)` - wrapped line. Default: `'↳'`.\n  - <sep> `(string)` - string to put at the end to separate statuscolumn and\n    buffer text. Default: `'│'`\n\n  Note: Any sign and separator should have every `%` escaped as `%%` (due to its\n  special meaning in |'statuscolumn'|).\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-colors.txt",
    "content": "*mini.colors* Tweak and save any color scheme\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniColors*\nFeatures:\n- Create colorscheme object: either manually (|MiniColors.as_colorscheme()|)\n  or by querying present color schemes (including currently active one; see\n  |MiniColors.get_colorscheme()|).\n\n- Infer data about color scheme and/or modify based on it:\n    - Add transparency by removing background color (requires transparency\n      in terminal emulator).\n    - Infer cterm attributes (|cterm-colors|) based on gui colors making it\n      compatible with 'notermguicolors'.\n    - Resolve highlight group links (|:highlight-link|).\n    - Compress by removing redundant highlight groups.\n    - Extract palette of used colors and/or infer terminal colors\n      (|terminal-config|) based on it.\n\n- Modify colors to better fit your taste and/or goals (see more in\n  |MiniColors-colorscheme-methods|):\n    - Apply any function to color hex string.\n    - Update channels (like lightness, saturation, hue, temperature, red,\n      green, blue, etc.; see more in |MiniColors-channels|).\n      Use either own function or one of the implemented methods:\n        - Add value to channel or multiply it by coefficient. Like \"add 10\n          to saturation of every color\" or \"multiply saturation by 2\" to\n          make colors more saturated (less gray).\n        - Invert. Like \"invert lightness\" to convert between dark/light theme.\n        - Set to one or more values (picks closest to current one). Like\n          \"set to one or two hues\" to make mono- or dichromatic color scheme.\n        - Repel from certain source(s) with stronger effect for closer values.\n          Like \"repel from hue 30\" to remove red color from color scheme.\n          Repel hue (how much is removed) is configurable.\n    - Simulate color vision deficiency.\n\n- Once color scheme is ready, either apply it to see effects right away or\n  write it into a Lua file as a fully functioning separate color scheme.\n\n- Experiment interactively with a feedback (|MiniColors.interactive()|).\n\n- Animate transition between color schemes either with |MiniColors.animate()|\n  or with |:Colorscheme| user command.\n\n- Convert within supported color spaces (|MiniColors.convert()|):\n    - Hex string.\n    - 8-bit number (terminal colors).\n    - RGB.\n    - Oklab, Oklch, Okhsl (https://bottosson.github.io/posts/oklab/).\n\nNotes:\n- There is a collection of |MiniColors-recipes| with code snippets for some\n  common tasks.\n- There is no goal to support as many color spaces as possible, only the\n  already present ones.\n\n# Tweak quick start ~\n\n- Execute `:lua require('mini.colors').interactive()`.\n\n- Experiment by writing calls to exposed color scheme methods and applying\n  them with `<M-a>`. For more information, see |MiniColors-colorscheme-methods|\n  and |MiniColors-recipes|.\n\n- If you are happy with result, write color scheme with `<M-w>`. If not,\n  reset to initial color scheme with `<M-r>`.\n\n- If only some highlight groups can be made better, adjust them manually\n  inside written color scheme file.\n\n# Setup ~\n\nThis module doesn't need setup, but it can be done to improve usability.\nSetup with `require('mini.colors').setup({})` (replace `{}` with your\n`config` table). It will create global Lua table `MiniColors` which you can\nuse for scripting or manually (with `:lua MiniColors.*`).\n\nSee |MiniColors.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minicolors_config`\nwill have no effect here.\n\n# Comparisons ~\n\n- [rktjmp/lush.nvim](https://github.com/rktjmp/lush.nvim):\n    - Oriented towards tweaking separate highlight groups, while 'mini.colors'\n      is more designed to work with color scheme as a whole.\n    - Uses HSL and HSLuv color spaces, while 'mini.colors' uses Oklab, Oklch,\n      and Okhsl which have slightly better perceptual uniformity properties.\n    - Doesn't have functionality to infer and repair missing data in color\n      scheme (like cterm attributes, terminal colors, transparency, etc.),\n      while 'mini.colors' does.\n    - Doesn't implement animation of color scheme transition, while\n      'mini.colors' does.\n- [lifepillar/vim-colortemplate](https://github.com/lifepillar/vim-colortemplate):\n    - Comparisons are similar to that of 'rktjmp/lush.nvim'.\n- [tjdevries/colorbuddy.nvim](https://github.com/tjdevries/colorbuddy.nvim):\n    - Comparisons are similar to that of 'rktjmp/lush.nvim'.\n\n------------------------------------------------------------------------------\n                                                            *MiniColors-recipes*\nAll following code snippets assume to be executed inside interactive buffer\n(|MiniColors.interactive()|). They are directly copy-pasteable.\n\nTo apply single method to current color scheme, use >vim\n  :lua MiniColors.get_colorscheme():<method goes here>:apply().\n<\nRecipes:\n- Tweak lightness: >lua\n\n  -- Invert dark/light color scheme to be light/dark\n  chan_invert('lightness', { gamut_clip = 'cusp' })\n\n  -- Ensure constant contrast ratio\n  chan_set('lightness', 15, { filter = 'bg' })\n  chan_set('lightness', 85, { filter = 'fg' })\n<\n- Tweak saturation: >lua\n\n  -- Make background colors less saturated and foreground - more\n  chan_add('saturation', -20, { filter = 'bg' })\n  chan_add('saturation', 20,  { filter = 'fg' })\n\n  -- Convert to grayscale\n  chan_set('saturation', 0)\n<\n- Tweak hue: >lua\n\n  -- Create monochromatic variant (this uses green color)\n  chan_set('hue', 135)\n\n  -- Create dichromatic variant (this uses Neovim-themed hues)\n  chan_set('hue', { 140, 245 })\n<\n- Tweak temperature: >lua\n\n  -- Invert temperature (make cold theme become warm and vice versa)\n  chan_invert('temperature')\n\n  -- Make background colors colder and foreground warmer\n  chan_add('temperature', -40, { filter = 'bg' })\n  chan_add('temperature', 40,  { filter = 'fg' })\n<\n- Counter color vision deficiency (try combinations of these to see which\n  one works best for you):\n\n    - Improve text saturation contrast (usually the best starting approach): >lua\n\n      chan_set('saturation', { 10, 90 }, { filter = 'fg' })\n<\n    - Remove certain hues from all colors (use 30 for red, 90 for yellow,\n      135 for green, 270 for blue): >lua\n\n      -- Repel red color\n      chan_repel('hue', 30, 45)\n<\n    - Force equally spaced palette (remove ones with which you know you\n      have trouble): >lua\n\n      -- Might be a good choice for red-green color blindness\n      chan_set('hue', { 90, 180, 270})\n\n      -- Might be a good choice for blue-yellow color blindness\n      chan_set('hue', { 0, 90, 180 })\n<\n    - Inverting temperature or pressure can sometimes improve readability: >lua\n\n      chan_invert('temperature')\n      chan_invert('pressure')\n<\n    - If all hope is lost, hue random generation might help if you are lucky: >lua\n\n      chan_modify('hue', function() return math.random(0, 359) end)\n<\n- For color scheme creators use |MiniColors-colorscheme:simulate_cvd()| to\n  simulate various color vision deficiency types to see how color scheme\n  would look in the eyes of color blind person.\n\n------------------------------------------------------------------------------\n                                                       *MiniColors-color-spaces*\nColor space is a way to quantitatively describe a color. In this module\ncolor spaces are used both as source for |MiniColors-channels| and inputs\nfor |MiniColors.convert()|\n\nList of supported color spaces (along with their id in parenthesis):\n- 8-bit (`8-bit`) - integer between 16 and 255. Usually values 0-15 are also\n  supported, but they depend on terminal emulator theme which is not reliable.\n  See https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit .\n\n- Hex (`hex`) - string of the form \"#xxxxxx\" where `x` is a hexadecimal number.\n\n- RGB (`rgb`) - table with numeric fields `r` (red), `g` (green), `b` (blue).\n  Visible range is from 0 to 255.\n\n- Oklab (`oklab`) - table with fields `l` (lightness; numeric in [0; 100]),\n  `a`, `b` (both are unbounded numeric; visible range is usually between\n  -30 to 30). Field `l` describes how light is color; `a` - how \"green-red\" it is;\n  `b` - how \"blue-yellow\" it is.\n\n- Oklch (`oklch`) - table with fields `l` (same as in Oklab),\n  `c` (chroma; positive numeric, visible range usually lower than 32),\n  `h` (`nil` for grays or periodic numeric in [0, 360)). Field `c` describes how\n  colorful a color is; `h` is a value of \"true color\" on color circle/wheel.\n  NOTE: gray colors, being achromatic by nature, don't have hue.\n\n- Okhsl (`okhsl`) - Oklch but with `c` replaced by `s` (saturation; numeric\n  in [0; 100]). Field `s` describes a percent of chroma relative to maximum\n  visible chroma for the particular lightness and hue combination. Note,\n  that mathematical model used to compute maximum visible chroma is\n  approximate which might lead to inaccuracies for highly saturated colors\n  with relatively low or high lightness.\n\nSources for Oklab/Oklch/Okhsl:\n- https://bottosson.github.io/posts/oklab/ - initial derivation and\n  introduction of Oklab and Oklch.\n- https://bottosson.github.io/misc/colorpicker - interactive color picker.\n  Great way for a hands-on introduction to concepts of lightness, chroma,\n  saturation, and hue.\n\nNote that Oklab/Oklch/Okhsl use channel normalization for `l`, `a`, `b`, `c`, `s` that\nis more oriented towards integer numbers (according to the above sources).\nSome implementations (like in CSS) are more oriented towards [0; 1] range or\npercentages. Adjust accordingly by dividing/multiplying output by 100.\nAlso use `adjust_lightness = false` in |MiniColors.convert()|.\n\n# Gamut clip ~\n*MiniColors-gamut-clip*\n\nIn Neovim highlight group colors are usually specified by their red, green,\nand blue values from 0 to 255 in the form of HEX string (see |gui-colors|).\nAlthough plenty, these are not all possible colors.\n\nWhen performing color manipulation using |MiniColors-colorscheme-methods|,\nit is possible to end up with \"impossible\" color (which can't be directly\nconverted to HEX string). For example, inverting lightness of color \"#fce094\"\nwill lead to a color `{ l = 10, c = 10, h = 90 }` in Oklch space, i.e.\n\"dark yellow\" which is impossible to show in HEX.\n\n**Gamut clipping** is an action of converting color outside of visible gamut\n(colors representable with HEX string) to be inside it while preserving\ncertain perceptual characteristics as much as possible.\n\nGamut clipping in this module is done inside Oklch color space. The goal is to\npreserve hue as much as possible while manipulating lightness and/or chroma.\n\nList of supported gamut clip methods (along with their id in parenthesis):\n- Clip chroma (`'chroma'`) - reduce chroma while preserving lightness until\n  color is inside visible gamut. Default method.\n\n- Clip lightness (`'lightness'`) - reduce lightness while preserving chroma\n  until color is inside visible gamut.\n\n- Clip according to \"cusp\" (`'cusp'`) - reduce both lightness and chroma in\n  a compromise way depending on hue.\n  Cusp is a color with the highest chroma inside slice of visible gamut\n  with the same hue (hue leaf). It is called that way because the slice has\n  a roughly triangular shape with points at (0, 0) - (0, 100) - \"cusp\" in\n  (chroma, lightness) coordinates.\n  Gamut clipping using \"cusp\" as reference is done by changing color towards\n  (0, cusp_lightness) point (gray with lightness equal to that of a current\n  cusp) until color is inside visible gamut.\n\nIn short:\n- Usually `'chroma'` is enough.\n- If colors are too desaturated - try `'cusp'`.\n- If still not colorful enough - try `'lightness'`.\n\nNotes:\n- Currently implemented formulas are approximate (by design; to reduce code\n  complexity) so there might be problems for highly saturated colors with\n  relatively low or high lightness.\n\n------------------------------------------------------------------------------\n                                                           *MiniColors-channels*\nA color channel is a number describing one particular aspect of a color.\nIt is usually direct or modified coordinate of a color space. See\n|MiniColors-color-spaces| for information on color spaces.\n\nList of supported channels (along with their id in parenthesis):\n- Lightness (`lightness`) - corrected `l` component of Oklch. Describes how\n  light is a color. Ranges from 0 (black dark) to 100 (white light).\n\n- Chroma (`chroma`) - `c` component of Oklch. Describes how colorful is\n  a color in absolute units. Ranges from 0 (gray) to infinity (more like\n  around 30 in practice).\n\n- Saturation (`saturation`) - `s` component of Okhsl. Describes how colorful\n  is color in relative units. Ranges from 0 (gray) to 100 (maximum saturation\n  for a given lightness-hue pair).\n\n- Hue (`hue`) - `h` component of Oklch. Describes \"true color value\" (like\n  red/green/blue) as a number. It is a periodic value from 0 (included) to\n  360 (not included). Best perceived as a degree on a color circle/wheel.\n\n  Approximate values for common color names:\n    - 0   - pink.\n    - 30  - red.\n    - 60  - orange.\n    - 90  - yellow.\n    - 135 - green.\n    - 180 - cyan.\n    - 225 - light blue.\n    - 270 - blue.\n    - 315 - magenta/purple.\n\n- Temperature (`temperature`) - circular distance from current hue to hue 270\n  angle (blue). Ranges from 0 (cool) to 180 (hot) anchored at hues 270 (blue)\n  and 90 (yellow). Similar to `b` channel but tries to preserve chroma.\n\n- Pressure (`pressure`) - circular distance from current hue to hue 180.\n  Ranges from 0 (low; green-ish) to 180 (high; red-ish) anchored at hues\n  180 and 0. Similar to `a` channel but tries to preserve chroma.\n  Not widely used; added to have something similar to temperature.\n\n- a (`a`) - `a` component of Oklab. Describes how \"green-red\" a color is.\n  Can have any value. Negative values are \"green-ish\", positive - \"red-ish\".\n\n- b (`b`) - `b` component of Oklab. Describes how \"blue-yellow\" a color is.\n  Can have any value. Negative values are \"blue-ish\", positive - \"yellow-ish\".\n\n- Red (`red`) - `r` component of RGB. Describes how much red a color has.\n  Ranges from 0 (no red) to 255 (full red).\n\n- Green (`green`) - `g` component of RGB. Describes how much green a color has.\n  Ranges from 0 (no green) to 255 (full green).\n\n- Blue (`blue`) - `b` component of RGB. Describes how much blue a color has.\n  Ranges from 0 (no blue) to 255 (full blue).\n\n------------------------------------------------------------------------------\n                                                        *MiniColors-colorscheme*\nColorscheme object is a central structure of this module. It contains all\ndata relevant to colors in fields and provides methods to modify it.\n\nCreate colorscheme object manually with |MiniColors.as_colorscheme()|: >lua\n\n  MiniColors.as_colorscheme({\n    name = 'my_cs',\n    groups = {\n      Normal   = { fg = '#dddddd', bg = '#222222' },\n      SpellBad = { sp = '#dd2222', undercurl = true },\n    },\n    terminal = { [0] = '#222222', [1] = '#dd2222' },\n  })\n<\nGet any registered color scheme (including currently active) as colorscheme\nobject with |MiniColors.get_colorscheme()|: >lua\n\n  -- Get current color scheme\n  MiniColors.get_colorscheme()\n\n  -- Get registered color scheme by name\n  MiniColors.get_colorscheme('minischeme', { new_name = 'maxischeme' })\n<\nClass ~\n{Colorscheme}\n\n*MiniColors-colorscheme-fields*\n\nFields ~\n{name} `(string|nil)` Name of the color scheme (as in |g:colors_name|).\n\n{groups} `(table|nil)` Table with highlight groups data. Keys are group\n  names appropriate for `name` argument of |nvim_set_hl()|, values - tables\n  appropriate for its `val` argument. Note: gui colors are accepted only in\n  short form (`fg`, `bg`, `sp`).\n\n{terminal} `(table|nil)` Table with terminal colors data (|terminal-config|).\n  Keys are numbers from 0 to 15, values - strings representing color (hex\n  string or plain color name; see |nvim_get_color_by_name()|).\n\n# Methods ~\n*MiniColors-colorscheme-methods*\n\nNotes about all methods:\n- They never modify underlying colorscheme object instead returning deep\n  copy with modified fields.\n- They accept `self` colorscheme object as first argument meaning they should be\n  called with `:` notation (like `cs:method()`).\n\nExample calling methods: >lua\n\n  -- Get current color scheme, set hue of colors to 135, infer cterm\n  -- attributes and apply\n  local cs = MiniColors.get_colorscheme()\n  cs:chan_set('hue', 135):add_cterm_attributes():apply()\n<\n## add_cterm_attributes() ~\n*MiniColors-colorscheme:add_cterm_attributes()*\n\nInfer |cterm-colors| based on present |gui-colors|. It updates `ctermbg`/`ctermfg`\nbased on `fg`/`bg` by approximating in perceptually uniform distance in Oklab\nspace (|MiniColors-color-spaces|).\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <force> `(boolean)` - Whether to replace already present cterm attributes\n    with inferred ones. Default: `true`.\n\n## add_terminal_colors() ~\n*MiniColors-colorscheme:add_terminal_colors()*\n\nInfer terminal colors (|terminal-config|) based on colorscheme palette\n(see |MiniColors-colorscheme:get_palette()|). It updates `terminal` field\nbased on color scheme's palette by picking the most appropriate entry to\nrepresent terminal color. Colors from 0 to 7 are attempted to be black,\nred, green, yellow, blue, magenta, cyan, white. Colors from 8 to 15 are\nthe same as from 0 to 7.\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <force> `(boolean)` - Whether to replace already present terminal colors\n    with inferred ones. Default: `true`.\n  - <palette_args> `(table)` - |MiniColors-colorscheme:get_palette()| arguments.\n\n## add_transparency() ~\n*MiniColors-colorscheme:add_transparency()*\n\nAdd transparency by removing background from a certain highlight groups.\nRequires actual transparency from terminal emulator to see background image.\nHas no effect on linked groups; use |MiniColors-colorscheme:resolve_links()|\nexplicitly before applying transparency.\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields can be used to configure which\n  sets of highlight groups to update:\n  - <general> `(boolean)` - general groups (like `Normal`). Default: `true`.\n  - <float> `(boolean)` - built-in groups for floating windows. Default: `false`.\n  - <statuscolumn> `(boolean)` - groups related to 'statuscolumn' (signcolumn,\n    numbercolumn, foldcolumn, `DiagnosticSignXxx`, and `XxxMsg` groups). Also\n    updates groups for all currently defined signs. Default: `false`.\n  - <statusline> `(boolean)` - built-in groups for 'statusline'. Default: `false`.\n  - <tabline> `(boolean)` - built-in groups for 'tabline'. Default: `false`.\n  - <winbar> `(boolean)` - built-in groups for 'winbar'. Default: `false`.\n\n## apply() ~\n*MiniColors-colorscheme:apply()*\n\nApply colorscheme:\n- Set |g:colors_name| to a `name` field.\n- Apply highlight groups in a `groups` field.\n- Set terminal colors from a `terminal` field.\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <clear> `(boolean)` - whether to execute |:hi-clear| first. Default: `true`.\n\n## chan_add() ~\n*MiniColors-colorscheme:chan_add()*\n\nAdd value to a channel (see |MiniColors-channels|).\n\n### Parameters ~\n{channel} `(string)` One of supported |MiniColors-channels|.\n{value} `(number)` Number to add (can be negative).\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function|string)` - filter colors to update. Possible values:\n      - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n        `'term'` (only terminal colors).\n      - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n    Default: `nil` to update all colors.\n  - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n    `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n\n## chan_invert() ~\n*MiniColors-colorscheme:chan_invert()*\n\nInvert value in a channel (see |MiniColors-channels|).\n\nNotes:\n- Most Oklab/Oklch inversions are not exactly invertible: applying it twice\n  might lead to slightly different colors depending on gamut clip method\n  (|MiniColors-gamut-clip|) like smaller chroma with default `'chroma'` method.\n\n### Parameters ~\n{channel} `(string)` One of supported |MiniColors-channels|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function|string)` - filter colors to update. Possible values:\n      - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n        `'term'` (only terminal colors).\n      - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n    Default: `nil` to update all colors.\n  - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n    `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n## chan_modify() ~\n*MiniColors-colorscheme:chan_modify()*\n\nModify channel with a callable.\n\n### Parameters ~\n{channel} `(string)` One of supported |MiniColors-channels|.\n{f} `(function)` - callable which defines modification. Should take current\n  value of a channel and return a new one.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function|string)` - filter colors to update. Possible values:\n      - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n        `'term'` (only terminal colors).\n      - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n    Default: `nil` to update all colors.\n  - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n    `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n## chan_multiply() ~\n*MiniColors-colorscheme:chan_multiply()*\n\nMultiply value of a channel (see |MiniColors-channels|).\n\n### Parameters ~\n{channel} `(string)` One of supported |MiniColors-channels|.\n{coef} `(number)` Number to multiply with (can be negative).\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function|string)` - filter colors to update. Possible values:\n      - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n        `'term'` (only terminal colors).\n      - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n    Default: `nil` to update all colors.\n  - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n    `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n## chan_repel() ~\n*MiniColors-colorscheme:chan_repel()*\n\nRepel from certain sources.\n\nGiven an array of repel centers (`sources`) and repel degree (`coef`) add to\ncurrent channel value some amount (\"nudge\") with the following properties:\n- Nudges from several sources are added together.\n- Nudge is directly proportional to `coef`: bigger `coef` means bigger nudge.\n- Nudge is inversely proportional to the distance between current value and\n  source: for positive `coef` bigger distance means smaller nudge, i.e.\n  repel effect weakens with distance.\n- With positive `coef` nudges close to source are computed in a way to remove\n  whole `[source - coef; source + coef]` range.\n- Negative `coef` results into attraction to source. Nudges in\n  `[source - coef; source + coef]` range are computed to completely collapse it\n  into `source`.\n\nExamples: >lua\n\n  -- Repel hue from red color removing hue in range from 20 to 40\n  chan_repel('hue', 30, 10)\n\n  -- Attract hue to red color collapsing [20; 40] range into 30.\n  chan_repel('hue', 30, -10)\n<\n### Parameters ~\n{channel} `(string)` One of supported |MiniColors-channels|.\n{sources} `(table|number)` Single or multiple source from which to repel.\n{coef} `(number)` Repel degree (can be negative to attract).\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function|string)` - filter colors to update. Possible values:\n      - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n        `'term'` (only terminal colors).\n      - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n    Default: `nil` to update all colors.\n  - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n    `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n## chan_set() ~\n*MiniColors-colorscheme:chan_set()*\n\nSet channel to certain value(s). This can be used to ensure that channel has\nvalue(s) only within supplied set. If more than one is supplied, closest\nelement to current value is used.\n\n### Parameters ~\n{channel} `(string)` One of supported |MiniColors-channels|.\n{values} `(table|number)` Single or multiple values to set.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function|string)` - filter colors to update. Possible values:\n      - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n        `'term'` (only terminal colors).\n      - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n    Default: `nil` to update all colors.\n  - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n    `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n## color_modify() ~\n*MiniColors-colorscheme:color_modify()*\n\nModify all colors with a callable. It should return new color value (hex\nstring or `nil` to remove attribute) base on the following input:\n- Current color as hex string.\n- Data about the color: a table with fields:\n    - <attr> - one of `'fg'`, `'bg'`, `'sp'`, and `'term'` for terminal color.\n    - <name> - name of color source. Either a name of highlight group or\n      string of the form `terminal_color_x` for terminal color (as in\n      |terminal-config|).\n\nExample: >lua\n\n  -- Set to '#dd2222' all foreground colors for groups starting with \"N\"\n  color_modify(function(hex, data)\n    if data.attr == 'fg' and data.name:find('^N') then\n      return '#dd2222'\n    end\n    return hex\n  end)\n<\n### Parameters ~\n{f} `(function)` Callable returning new color value.\n\n## compress() ~\n*MiniColors-colorscheme:compress()*\n\nRemove redundant highlight groups. These are one of the two kinds:\n- Having values identical to ones after |:hi-clear| (meaning they usually\n  don't add new information).\n- Coming from a curated list of plugins with highlight groups usually not\n  worth keeping around. Current list of such plugins:\n    - [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n    - [norcalli/nvim-colorizer.lua](https://github.com/norcalli/nvim-colorizer.lua)\n\nThis method is useful to reduce size of color scheme before writing into\nthe file with |MiniColors-colorscheme:write()|.\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <plugins> `(boolean)` - whether to remove highlight groups from a curated\n    list of plugins. Default: `true`.\n\n## get_palette() ~\n*MiniColors-colorscheme:get_palette()*\n\nGet commonly used colors. This basically counts number of all color\noccurrences and filter out rare ones.\n\nIt is usually a good idea to apply both |MiniColors-colorscheme:compress()|\nand |MiniColors-colorscheme:resolve_links()| before applying this.\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <threshold> `(number)` - relative threshold for groups to keep. A group\n    is not included in output if it has less than this many occurrences\n    relative to a total number of colors. Default: 0.01.\n\n## resolve_links() ~\n*MiniColors-colorscheme:resolve_links()*\n\nResolve links (|:highlight-link|). This makes all highlight groups with `link`\nattribute have data from a linked one.\n\nNotes:\n- Resolves nested links.\n- If some group is linked to a group missing in current colorscheme object,\n  it is not resolved.\n\n## simulate_cvd() ~\n*MiniColors-colorscheme:simulate_cvd()*\n\nSimulate color vision deficiency (CVD, color blindness). This is basically\na wrapper using |MiniColors.simulate_cvd()| as a part of\ncall to |MiniColors-colorscheme:color_modify()| method.\n\n### Parameters ~\n{cvd_type} `(string)` One of `'protan'`, `'deutan'`, `'tritan'`, `'mono'`.\n{severity} `(number|nil)` Severity of CVD, number between 0 and 1. Default: 1.\n\n## write() ~\n*MiniColors-colorscheme:write()*\n\nWrite color scheme to a file. It will be a Lua script readily usable as\na regular color scheme. Useful to both save results of color scheme tweaking\nand making local snapshot of some other color scheme.\n\nSourcing this file on startup usually leads to a better performance that\nsourcing initial color scheme, as it is essentially a conditioned\n|:hi-clear| call followed by a series of |nvim_set_hl()| calls.\n\nDefault writing location is a \"colors\" directory of your Neovim config\ndirectory (see |base-directories|). After writing, it should be available\nfor sourcing with |:colorscheme| or |:Colorscheme|.\n\nName of the file by default is taken from `name` field (`'mini_colors'` is\nused if it is `nil`). If color scheme with this name already exists, it\nappends prefix based on current time to make it unique.\n\nNotes:\n- If colors were updated, it is usually a good idea to infer cterm attributes\n  with |MiniColors-colorscheme:add_cterm_attributes()| prior to writing.\n\n### Parameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <compress> `(boolean)` - whether to call |MiniColors-colorscheme:compress()|\n    prior to writing. Default: `true`.\n  - <name> `(string|nil)` - basename of written file. Default: `nil` to infer\n    from `name` field.\n  - <directory> `(string)` - directory to where file should be saved.\n    Default: \"colors\" subdirectory of Neovim home config (`stdpath(\"config\")`).\n\n------------------------------------------------------------------------------\n                                                            *MiniColors.setup()*\n                          `MiniColors.setup`({config})\nModule setup\n\n# :Colorscheme ~\n*:Colorscheme*\n\nCalling this function creates a `:Colorscheme` user command. It takes one or\nmore registered color scheme names and performs animated transition between\nthem (starting from currently active color scheme).\nIt uses |MiniColors.animate()| with default options.\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniColors.config|.\n\nUsage ~\n>lua\n  require('mini.colors').setup() -- use default config\n  -- OR\n  require('mini.colors').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                             *MiniColors.config*\n                              `MiniColors.config`\nDefaults ~\n>lua\n  MiniColors.config = {}\n<\n------------------------------------------------------------------------------\n                                                   *MiniColors.as_colorscheme()*\n                        `MiniColors.as_colorscheme`({x})\nCreate colorscheme object\n\nParameters ~\n{x} `(table)` Table to be transformed into |MiniColors-colorscheme| object.\n\nReturn ~\n`(table)` Copy of `x` transformed into a colorscheme object.\n\n------------------------------------------------------------------------------\n                                                  *MiniColors.get_colorscheme()*\n                  `MiniColors.get_colorscheme`({name}, {opts})\nGet colorscheme object from registered color scheme\n\nParameters ~\n{name} `(string|nil)` Name of color scheme to use. If `nil` (default) creates\n colorscheme object based on currently active data (|g:colors_name|,\n highlight groups, terminal colors). If string, converts color scheme with\n that name to a colorscheme object.\n{opts} `(table|nil)` Options. Possible fields:\n  - <new_name> `(string|nil)` - new name of colorscheme object.\n\nReturn ~\n`(table)` Colorscheme object (|MiniColors-colorscheme|).\n\n------------------------------------------------------------------------------\n                                                      *MiniColors.interactive()*\n                        `MiniColors.interactive`({opts})\nStart interactive experiments\n\nCreate a special buffer in which user can write plain Lua code to tweak\ncolor scheme and apply to get visual feedback.\n\n# General principles ~\n- Initial colorscheme object is fixed to interactive buffer on its creation.\n\n- There are special buffer convenience mappings:\n    - Apply (source) current buffer content.\n    - Reset color scheme (make initial colorscheme the current one).\n    - Write to a file the result of applying current buffer content.\n      This sources current content and calls |MiniColors-colorscheme:write()|.\n    - Quit interactive buffer.\n\n- User is expected to iteratively tweak color scheme by writing general Lua\n  code in interactive buffer and applying it using convenience mapping.\n\n- Application of interactive buffer is essentially these steps:\n    - Expose `self` as initial colorscheme object on any application.\n      It is always the same for every application.\n    - Expose initial colorscheme methods as standalone functions. So instead\n      of writing `self = self:add_transparency()` user can only write\n      `add_transparency()`.\n    - Source buffer content as plain Lua code.\n\nExample of interactive buffer content: >lua\n\n  chan_modify('hue', function() return math.random(0, 359) end)\n  simulate_cvd('protan')\n  add_cterm_attributes()\n  add_terminal_colors()\n<\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <colorscheme> `(table|nil)` - |MiniColors-colorscheme| object to be\n    used as initial colorscheme for executed code. By default uses current\n    color scheme.\n  - <mappings> `table` - buffer mappings for actions. Possible fields:\n      - <Apply> `(string)` - apply buffer code. Default: `'<M-a>'`.\n      - <Reset> `(string)` - apply initial color scheme as is. Default: `'<M-r>'`.\n      - <Quit> `(string)` - close interactive buffer. Default: `'<M-q>'`.\n      - <Write> `(string)` - write result of buffer code into a file.\n        Prompts for file name with |vim.ui.input()| and then\n        uses |MiniColors-colorscheme:write()| with other options being default.\n        Default: `'<M-w>'`.\n\n------------------------------------------------------------------------------\n                                                          *MiniColors.animate()*\n                    `MiniColors.animate`({cs_array}, {opts})\nAnimate color scheme change\n\nStart from currently active color scheme and loop through `cs_array`.\n\nPowers |:Colorscheme| user command created in |MiniColors.setup()|.\n\nParameters ~\n{cs_array} `(table)` Array of |MiniColors-colorscheme| objects.\n{opts} `(table|nil)` Options. Possible fields:\n  - <transition_steps> `(number)` - number of intermediate steps to show\n    during transition between two color schemes. Bigger values result in\n    smoother visual feedback but require more computational power.\n    Default: 25.\n  - <transition_duration> `(number)` - number of milliseconds to spend\n    showing transition. Default: 1000.\n  - <show_duration> `(number)` - number of milliseconds to show intermediate\n    color schemes (all but last in `cs_array`). Default: 1000.\n\n------------------------------------------------------------------------------\n                                                          *MiniColors.convert()*\n                 `MiniColors.convert`({x}, {to_space}, {opts})\nConvert between color spaces\n\nFor a list of supported colors spaces see |MiniColors-color-spaces|.\n\nParameters ~\n{x} `(table|string|number|nil)` Color to convert from. Its color space is\n  inferred automatically.\n{to_space} `(string)` Id of allowed color space.\n{opts} `(table|nil)` Options. Possible fields:\n  - <adjust_lightness> `(boolean)` - whether to adjust lightness value to have\n    a more uniform progression from 0 to 100. Set `false` for results more\n    compatible with some other Oklab/Oklch implementations (like in CSS).\n    Source: \"Intermission - a new lightness estimate for Oklab\" section of\n    https://bottosson.github.io/posts/colorpicker\n    Default: `true`.\n  - <gamut_clip> `(string)` - method for |MiniColors-gamut-clip|.\n    Default: `'chroma'`.\n\nReturn ~\n`(table|string|number|nil)` Color in space `to_space` or `nil` if input is `nil`.\n\n------------------------------------------------------------------------------\n                                                   *MiniColors.modify_channel()*\n            `MiniColors.modify_channel`({x}, {channel}, {f}, {opts})\nModify channel\n\nParameters ~\n{x} `(table|string|number|nil)` Color which channel will be modified. Color\n  space is inferred automatically.\n{channel} `(string)` One of supported |MiniColors-channels|.\n{f} `(function)` Callable which defines modification. Should take current\n  value of a channel and return a new one.\n{opts} `(table|nil)` Options. Possible fields:\n  - <gamut_clip> `(string)` - method for |MiniColors-gamut-clip|.\n    Default: `'chroma'`.\n\nReturn ~\n`(string|nil)` Hex string of color with modified channel or `nil` if input is `nil`.\n\n------------------------------------------------------------------------------\n                                                     *MiniColors.simulate_cvd()*\n             `MiniColors.simulate_cvd`({x}, {cvd_type}, {severity})\nSimulate color vision deficiency\n\nParameters ~\n{x} `(table|string|number|nil)` Color to convert from. Its color space is\n  inferred automatically.\n{cvd_type} `(string)` Type of CVD. One of `'protan'`, `'deutan'`,\nor `'mono'` (equivalent to converting to graysacle).\n{severity} `(number|nil)` Severity of CVD. A number between 0 and 1 (default).\n\nReturn ~\n`(string|nil)` Hex string of simulated color or `nil` if input is `nil`.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-comment.txt",
    "content": "*mini.comment* Comment lines\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                   *MiniComment*\nFeatures:\n- Commenting in Normal mode respects |count| and is dot-repeatable.\n\n- Comment structure by default is inferred from 'commentstring': either\n  from current buffer or from locally active tree-sitter language.\n  It can be customized via `options.custom_commentstring`\n  (see |MiniComment.config| for details).\n\n- Allows custom hooks before and after successful commenting.\n\n- Configurable options for some nuanced behavior.\n\nWhat it doesn't do:\n- Block and sub-line comments. This will only support per-line commenting.\n\n- Handle indentation with mixed tab and space.\n\n- Preserve trailing whitespace in empty lines.\n\nNotes:\n- To use tree-sitter aware commenting, global value of 'commentstring'\n  should be `''` (empty string). This is the default value, so make sure to\n  not set it manually to a different value.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.comment').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table\n`MiniComment` which you can use for scripting or manually (with\n`:lua MiniComment.*`).\n\nSee |MiniComment.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minicomment_config` which should have same structure as\n`MiniComment.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.minicomment_disable` (globally) or\n`vim.b.minicomment_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                           *MiniComment.setup()*\n                         `MiniComment.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniComment.config|.\n\nUsage ~\n>lua\n  require('mini.comment').setup() -- use default config\n  -- OR\n  require('mini.comment').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                            *MiniComment.config*\n                              `MiniComment.config`\nDefaults ~\n>lua\n  MiniComment.config = {\n    -- Options which control module behavior\n    options = {\n      -- Function to compute custom 'commentstring' (optional)\n      custom_commentstring = nil,\n\n      -- Whether to ignore blank lines in actions and textobject\n      ignore_blank_line = false,\n\n      -- Whether to recognize as comment only lines without indent\n      start_of_line = false,\n\n      -- Whether to force single space inner padding for comment parts\n      pad_comment_parts = true,\n    },\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      -- Toggle comment (like `gcip` - comment inner paragraph) for both\n      -- Normal and Visual modes\n      comment = 'gc',\n\n      -- Toggle comment on current line\n      comment_line = 'gcc',\n\n      -- Toggle comment on visual selection\n      comment_visual = 'gc',\n\n      -- Define 'comment' textobject (like `dgc` - delete whole comment block)\n      -- Works also in Visual mode if mapping differs from `comment_visual`\n      textobject = 'gc',\n    },\n\n    -- Hook functions to be executed at certain stage of commenting\n    hooks = {\n      -- Before successful commenting. Does nothing by default.\n      pre = function() end,\n      -- After successful commenting. Does nothing by default.\n      post = function() end,\n    },\n  }\n<\n# Options ~\n\n## Custom commentstring ~\n\n`options.custom_commentstring` can be a function customizing 'commentstring'\noption used to infer comment structure. It is called once before every\ncommenting action with the following arguments:\n- `ref_position` - position at which to compute 'commentstring' (might be\n  relevant for a text with locally different commenting rules). Its structure\n  is the same as `opts.ref_position` in |MiniComment.toggle_lines()|.\n\nIts output should be a valid 'commentstring' (string containing `%s`).\n\nIf not set or the output is `nil`, |MiniComment.get_commentstring()| is used.\n\nFor example, this option can be used to always use buffer 'commentstring'\neven in case of present active tree-sitter parser: >lua\n\n  require('mini.comment').setup({\n    options = {\n      custom_commentstring = function() return vim.bo.commentstring end,\n    }\n  })\n<\n# Hooks ~\n\n`hooks.pre` and `hooks.post` functions are executed before and after successful\ncommenting action (toggle or computing textobject). They will be called\nwith a single table argument which has the following fields:\n- <action> `(string)` - action name. One of \"toggle\" (when actual toggle\n  direction is yet unknown), \"comment\", \"uncomment\", \"textobject\".\n- <line_start> `(number|nil)` - action start line. Can be absent if yet unknown.\n- <line_end> `(number|nil)` - action end line. Can be absent if yet unknown.\n- <ref_position> `(table|nil)` - reference position.\n\nNotes:\n- Changing 'commentstring' in `hooks.pre` is allowed and will take effect.\n- If hook returns `false`, any further action is terminated.\n\n------------------------------------------------------------------------------\n                                                        *MiniComment.operator()*\n                         `MiniComment.operator`({mode})\nMain function to be mapped\n\nIt is meant to be used in expression mappings (see |:map-<expr>|) to enable\ndot-repeatability and commenting on range. There is no need to do this\nmanually, everything is done inside |MiniComment.setup()|.\n\nIt has a somewhat unintuitive logic (because of how expression mapping with\ndot-repeatability works): it should be called without arguments inside\nexpression mapping and with argument when action should be performed.\n\nParameters ~\n{mode} `(string|nil)` Optional string with 'operatorfunc' mode (see |g@|).\n\nReturn ~\n`(string|nil)` 'g@' if called without argument, '' otherwise (but after\n  performing action).\n\n------------------------------------------------------------------------------\n                                                    *MiniComment.toggle_lines()*\n          `MiniComment.toggle_lines`({line_start}, {line_end}, {opts})\nToggle comments between two line numbers\n\nIt uncomments if lines are comment (every line is a comment or blank) and\ncomments otherwise. It respects indentation and doesn't insert trailing\nwhitespace. Toggle commenting not in visual mode is also dot-repeatable\nand respects |count|.\n\n# Notes ~\n\n- Comment structure is inferred from buffer's 'commentstring' option or\n  local language of tree-sitter parser (if active).\n\n- Call to this function will remove all |extmarks| from target range.\n\nParameters ~\n{line_start} `(number)` Start line number (inclusive from 1 to number of lines).\n{line_end} `(number)` End line number (inclusive from 1 to number of lines).\n{opts} `(table|nil)` Options. Possible fields:\n  - <ref_position> `(table)` - A two-value array with `{ row, col }` (both\n    starting at 1) of reference position at which 'commentstring' value\n    will be computed. Default: `{ line_start, 1 }`.\n\n------------------------------------------------------------------------------\n                                                      *MiniComment.textobject()*\n                           `MiniComment.textobject`()\nSelect comment textobject\n\nThis selects all commented lines adjacent to cursor line. If `ignore_blank_line`\noption is enabled (see |MiniComment.config|), blank lines between commented\nlines are treated as part of textobject.\nDesigned to be used with operator mode mappings (see |mapmode-o|).\n\n------------------------------------------------------------------------------\n                                               *MiniComment.get_commentstring()*\n                `MiniComment.get_commentstring`({ref_position})\nGet 'commentstring'\n\nThis function represents default approach of computing relevant\n'commentstring' option in current buffer. Used to infer comment structure.\n\nIt has the following logic:\n- If there is an active tree-sitter parser, try to get 'commentstring' from\n  the local language at `ref_position`.\n\n- If first step is not successful, use buffer's 'commentstring' directly.\n\nParameters ~\n{ref_position} `(table)` Reference position inside current buffer at which\n  to compute 'commentstring'. Same structure as `opts.ref_position`\n  in |MiniComment.toggle_lines()|.\n\nReturn ~\n`(string)` Relevant value of 'commentstring'.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-completion.txt",
    "content": "*mini.completion* Completion and signature help\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                *MiniCompletion*\nKey design ideas:\n- Have an async (with customizable \"debounce\" delay) \"two-stage chain\n  completion\": first try to get completion items from LSP client (if set\n  up) and if no result, fallback to custom action.\n\n- Managing completion is done as much with Neovim's built-in tools as\n  possible. |popupmenu-completion| is used to show completion suggestions.\n\nFeatures:\n- Two-stage chain completion:\n    - First stage is an LSP completion implemented via\n      |MiniCompletion.completefunc_lsp()|. It should be set up as either\n      |'completefunc'| or |'omnifunc'|. It tries to get completion items from\n      LSP client (via 'textDocument/completion' request). Custom\n      preprocessing of response items is possible (with\n      `MiniCompletion.config.lsp_completion.process_items`), for example\n      with fuzzy matching. By default items directly starting with completed\n      word are kept and are sorted according to LSP specification.\n      Supports `additionalTextEdits`, like auto-import and others (see 'Notes'),\n      and snippet items (best results require |mini.snippets| dependency).\n    - If first stage is not set up or resulted into no candidates, fallback\n      action is executed. The most tested actions are Neovim's built-in\n      insert completion (see |ins-completion|).\n\n- Automatic display in floating window of completion item info (via\n  'completionItem/resolve' request) and signature help (with highlighting\n  of active parameter if LSP server provides such information).\n  Signature help is shown if character to cursor's left is a dedicated trigger\n  character (configured in `signatureHelpProvider.triggerCharacters` of LSP\n  server capabilities) and updated without delay if is currently opened.\n  Already shown window for signature help is fixed and is closed when there\n  is nothing to show, its text is different, or when leaving Insert mode.\n  Scroll in either info/signature window with `<C-f>` / `<C-b>` (by default).\n\n- Automatic actions are done after some configurable amount of delay. This\n  reduces computational load and allows fast typing (completion and\n  signature help) and item selection (item info)\n\n- Force two-stage/fallback completion (`<C-Space>` / `<A-Space>` by default).\n\n- Customizable highlighting of LSP items. Requires Neovim>=0.11.\n  Use `config.lsp_completion.process_items` to set dedicated highlight group\n  in supported fields:\n    - <abbr_hlgroup> - item label (`abbr` in terms of |complete-items|).\n      By default only checks if item is marked as deprecated and sets\n      `MiniCompletionDeprecated` highlight group.\n    - <kind_hlgroup> - LSP kind (\"Function\", \"Keyword\", etc.). By default\n      uses \"lsp\" category of |mini.icons| (if enabled).\n\nWhat it doesn't do:\n- Many configurable sources.\n- Automatic mapping of `<CR>`, `<Tab>`, etc. Those tend to have highly\n  variable user expectations. See 'Helpful mappings' for suggestions or\n  use |MiniKeymap.map_multistep()| with `\"pmenu_*\"` built-in steps.\n\n# Dependencies ~\n\nSuggested dependencies (provide extra functionality, will work without them):\n\n- Enabled |mini.icons| module to highlight LSP kind (requires Neovim>=0.11).\n  If absent, |MiniCompletion.default_process_items()| does not add highlighting.\n  Also take a look at |MiniIcons.tweak_lsp_kind()|.\n- Enabled |mini.snippets| module for better snippet handling (much recommended).\n  If absent and custom snippet insert is not configured, |vim.snippet.expand()|\n  is used on Neovim>=0.10 (nothing extra is done on earlier versions).\n  See |MiniCompletion.default_snippet_insert()|.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.completion').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniCompletion` which you can use for scripting or manually (with\n`:lua MiniCompletion.*`).\n\nSee |MiniCompletion.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minicompletion_config` which should have same structure as\n`MiniCompletion.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Suggested option values ~\n\nSome options are set automatically (if not set before |MiniCompletion.setup()|):\n- 'completeopt' is set to \"menuone,noselect\" for less intrusive popup.\n  To enable fuzzy matching, manually set to \"menuone,noselect,fuzzy\". Consider\n  also adding \"nosort\" flag to preserve initial order when filtering.\n- 'shortmess' is appended with \"c\" flag for silent <C-n> fallback.\n- 'complete' gets removed \"t\" flag (if fallback action is default), as it\n  leads to visible lags.\n\n# Snippets ~\n\nAs per LSP specification, some completion items can be supplied in the form of\nsnippet - a template with both pre-defined text and places (called \"tabstops\")\nfor user to interactively change/add text during snippet session.\n\nIn 'mini.completion' items that will insert snippet have \"S\" symbol shown in\nthe popup (as part of `menu` in |complete-items|). To actually insert a snippet:\n- Select an item via <C-n> / <C-p>. This will insert item's label (usually not\n  full snippet) first to reduce visual flicker. The full snippet text will be\n  shown in info window if LSP server doesn't provide its own info for an item.\n- Press <C-y> (|complete_CTRL-Y|) or attempt inserting a non-keyword character\n  (like <CR>; new character will be removed). It will clear text from previous\n  step, set cursor, and call `lsp_completion.snippet_insert` with snippet text.\n- Press <C-e> (|complete_CTRL-E|) to cancel snippet insert and properly end\n  completion.\n\nSee |MiniCompletion.default_snippet_insert()| for overview of how to work with\ninserted snippets.\n\nNotes:\n- To stop LSP server from suggesting snippets, disable (set to `false`) the\n  following capability during LSP server start:\n  `textDocument.completion.completionItem.snippetSupport`.\n- If snippet body doesn't contain tabstop, variable, tab, or newline,\n  `lsp_completion.snippet_insert` is not called and text is inserted as-is.\n\n# Notes ~\n\n- A more appropriate (albeit slightly advanced) LSP completion setup is to set\n  it not on every |BufEnter| event (default), but on every attach of LSP client.\n  To do that:\n    - Use in |MiniCompletion.setup()| config: >lua\n\n      lsp_completion = { source_func = 'omnifunc', auto_setup = false }\n<\n    - Set 'omnifunc' option to exactly `v:lua.MiniCompletion.completefunc_lsp`\n      for every client attach in an |LspAttach| event. Like this: >lua\n\n      local on_attach = function(args)\n        vim.bo[args.buf].omnifunc = 'v:lua.MiniCompletion.completefunc_lsp'\n      end\n      vim.api.nvim_create_autocmd('LspAttach', { callback = on_attach })\n<\n  This setup is not default to allow simultaneous usage of filetype-specific\n  'omnifunc' (with manual |i_CTRL-X_CTRL-O|) and automated LSP completion.\n\n- Use |MiniCompletion.get_lsp_capabilities()| to get/set information about part\n  of LSP specification supported by module. See its help for usability notes.\n\n- Uses `vim.lsp.protocol.CompletionItemKind` map in LSP step to show a readable\n  version of item's kind. Modify it directly to change what is displayed.\n  If you have |mini.icons| enabled, take a look at |MiniIcons.tweak_lsp_kind()|.\n\n- If you have trouble using custom (overridden) |vim.ui.input()|, disable\n  'mini.completion' for input buffer (usually based on its 'filetype').\n\n# Comparisons ~\n\n- [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp):\n    - Implements own popup menu to show completion candidates, while this\n      module reuses |ins-completion-menu|.\n    - Has more complex design which allows multiple sources, each in a form of\n      a separate plugin. This module has two built-in: LSP and fallback.\n    - Requires separate plugin for automated signature help.\n    - Implements own \"ghost text\" feature, while this module does not.\n\n- [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp):\n    - Mostly similar to 'nvim-cmp' comparison: provides more features at the\n      cost of more code and config complexity, while this module is designed\n      to provide only a handful of \"enough\" features while relying on Neovim's\n      built-in capabilities as much as possible.\n    - Both provide automated signature help out of the box.\n\n# Helpful mappings ~\n\nIf there is |mini.keymap| available, prefer using |MiniKeymap.map_multistep()|\nwith `\"pmenu_*\"` built-in steps. See |MiniKeymap-examples| for examples.\n\nTo use `<Tab>` and `<S-Tab>` for navigation through completion list, make\nthese mappings: >lua\n\n  local imap_expr = function(lhs, rhs)\n    vim.keymap.set('i', lhs, rhs, { expr = true })\n  end\n  imap_expr('<Tab>',   [[pumvisible() ? \"\\<C-n>\" : \"\\<Tab>\"]])\n  imap_expr('<S-Tab>', [[pumvisible() ? \"\\<C-p>\" : \"\\<S-Tab>\"]])\n<\nTo get more consistent behavior of `<CR>`, you can use this template in\nyour 'init.lua' to make customized mapping: >lua\n\n  _G.cr_action = function()\n    -- If there is selected item in popup, accept it with <C-y>\n    if vim.fn.complete_info()['selected'] ~= -1 then return '\\25' end\n    -- Fall back to plain `<CR>`. You might want to customize according\n    -- to other plugins. For example if 'mini.pairs' is set up, replace\n    -- next line with `return MiniPairs.cr()`\n    return '\\r'\n  end\n\n  vim.keymap.set('i', '<CR>', 'v:lua.cr_action()', { expr = true })\n<\n# Highlight groups ~\n\n- `MiniCompletionActiveParameter` - signature active parameter.\n- `MiniCompletionDeprecated` - candidates that marked as deprecated.\n- `MiniCompletionInfoBorderOutdated` - info window border when text is outdated\n  due to explicit delay during fast movement through candidates.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minicompletion_disable` (globally) or\n`vim.b.minicompletion_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                         *MiniCompletion-events*\nTo allow user customization, certain |User| autocommand events are\ntriggered under common circumstances:\n\n- Info and signature help window:\n    - `MiniCompletionWindowOpen` - after opening new window.\n    - `MiniCompletionWindowUpdate` - after updating existing window.\n\n    Each event's |event-data| table contains `kind` (one of \"info\" or \"signature\")\n    and `win_id` (affected window identifier) fields.\n\n------------------------------------------------------------------------------\n                                                        *MiniCompletion.setup()*\n                        `MiniCompletion.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniCompletion.config|.\n\nUsage ~\n>lua\n  require('mini.completion').setup() -- use default config\n  -- OR\n  require('mini.completion').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                         *MiniCompletion.config*\n                            `MiniCompletion.config`\nDefaults ~\n>lua\n  MiniCompletion.config = {\n    -- Delay (debounce type, in ms) between certain Neovim event and action.\n    -- This can be used to (virtually) disable certain automatic actions by\n    -- setting very high delay time (like 10^7).\n    delay = { completion = 100, info = 100, signature = 50 },\n\n    -- Configuration for action windows:\n    -- - `height` and `width` are maximum dimensions.\n    -- - `border` defines border (as in `nvim_open_win()`; default \"single\").\n    window = {\n      info = { height = 25, width = 80, border = nil },\n      signature = { height = 25, width = 80, border = nil },\n    },\n\n    -- Way of how module does LSP completion\n    lsp_completion = {\n      -- `source_func` should be one of 'completefunc' or 'omnifunc'.\n      source_func = 'completefunc',\n\n      -- `auto_setup` should be boolean indicating if LSP completion is set up\n      -- on every `BufEnter` event.\n      auto_setup = true,\n\n      -- A function which takes LSP 'textDocument/completion' response items\n      -- (each with `client_id` field for item's server) and word to complete.\n      -- Output should be a table of the same nature as input. Common use case\n      -- is custom filter/sort. Default: `default_process_items`\n      process_items = nil,\n\n      -- A function which takes a snippet as string and inserts it at cursor.\n      -- Default: `default_snippet_insert` which tries to use 'mini.snippets'\n      -- and falls back to `vim.snippet.expand` (on Neovim>=0.10).\n      snippet_insert = nil,\n    },\n\n    -- Fallback action as function/string. Executed in Insert mode.\n    -- To use built-in completion (`:h ins-completion`), set its mapping as\n    -- string. Example: set '<C-x><C-l>' for 'whole lines' completion.\n    fallback_action = '<C-n>',\n\n    -- Module mappings. Use `''` (empty string) to disable one. Some of them\n    -- might conflict with system mappings.\n    mappings = {\n      -- Force two-step/fallback completions\n      force_twostep = '<C-Space>',\n      force_fallback = '<A-Space>',\n\n      -- Scroll info/signature window down/up. When overriding, check for\n      -- conflicts with built-in keys for popup menu (like `<C-u>`/`<C-o>`\n      -- for 'completefunc'/'omnifunc' source function; or `<C-n>`/`<C-p>`).\n      scroll_down = '<C-f>',\n      scroll_up = '<C-b>',\n    },\n  }\n<\n------------------------------------------------------------------------------\n                                            *MiniCompletion.complete_twostage()*\n            `MiniCompletion.complete_twostage`({fallback}, {force})\nRun two-stage completion\n\nParameters ~\n{fallback} `(boolean|nil)` Whether to use fallback completion. Default: `true`.\n{force} `(boolean|nil)` Whether to force update of completion popup.\n  Default: `true`.\n\n------------------------------------------------------------------------------\n                                            *MiniCompletion.complete_fallback()*\n                      `MiniCompletion.complete_fallback`()\nRun fallback completion\n\n------------------------------------------------------------------------------\n                                                       *MiniCompletion.scroll()*\n                      `MiniCompletion.scroll`({direction})\nScroll in info/signature window\n\nDesigned to be used in |:map-<expr>|.\nScrolling is done as if |CTRL-F| and |CTRL-B| is pressed inside target window.\nUsed in default `config.mappings.scroll_xxx` mappings.\n\nParameters ~\n{direction} `(string)` One of `\"down\"` or `\"up\"`.\n\nReturn ~\n`(boolean)` Whether scroll is scheduled to be done.\n\n------------------------------------------------------------------------------\n                                                         *MiniCompletion.stop()*\n                        `MiniCompletion.stop`({actions})\nStop actions\n\nThis stops currently active (because of module delay or LSP answer delay)\nactions.\n\nDesigned to be used with |autocmd|. No need to use it directly, everything\nis setup in |MiniCompletion.setup()|.\n\nParameters ~\n{actions} `(table|nil)` Array containing any of 'completion', 'info', or\n  'signature' string. Default: array containing all of them.\n\n------------------------------------------------------------------------------\n                                             *MiniCompletion.completefunc_lsp()*\n             `MiniCompletion.completefunc_lsp`({findstart}, {base})\nModule's |complete-functions|\n\nThis is the main function which enables two-stage completion. It should be\nset as one of |'completefunc'| or |'omnifunc'|.\n\nNo need to use it directly, everything is setup in |MiniCompletion.setup()|.\n\n------------------------------------------------------------------------------\n                                        *MiniCompletion.default_process_items()*\n        `MiniCompletion.default_process_items`({items}, {base}, {opts})\nDefault processing of LSP items\n\nSteps:\n- Filter and sort items according to supplied method.\n- Arrange items further by completion item kind according to their priority.\n- Add `MiniCompletionDeprecated` <abbr_hlgroup> if item is marked as deprecated.\n- If |mini.icons| is enabled, add <kind_hlgroup> based on the \"lsp\" category.\n\nExample of forcing fuzzy matching, filtering out `Text` items, and putting\n`Snippet` items last: >lua\n\n  local kind_priority = { Text = -1, Snippet = 99 }\n  local opts = { filtersort = 'fuzzy', kind_priority = kind_priority }\n  local process_items = function(items, base)\n    return MiniCompletion.default_process_items(items, base, opts)\n  end\n  require('mini.completion').setup({\n    lsp_completion = { process_items = process_items },\n  })\n<\nParameters ~\n{items} `(table)` Array of items from LSP response.\n{base} `(string)` Base for which completion is done. See |complete-functions|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filtersort> `(string|function)` - method of filtering and sorting items.\n    If string, should be one of the following:\n      - `'prefix'` - filter out items not starting with `base`, sort according\n        to LSP specification. Use `filterText` and `sortText` respectively with\n        fallback to `label`.\n      - `'fuzzy'` - filter and sort with |matchfuzzy()| using `filterText`.\n      - `'none'` - no filter and no sort.\n    If callable, should take `items` and `base` arguments and return items array.\n    Default: `'fuzzy'` if 'completeopt' contains \"fuzzy\", `'prefix'` otherwise.\n  - <kind_priority> `(table)` - map of completion item kinds (like `Variable`,\n    `Snippet`; see string keys of `vim.lsp.protocol.CompletionItemKind`) to\n    their numerical priority. It will be used after applying <filtersort> to\n    arrange by completion item kind: items with negative priority kinds will\n    be filtered out, the rest are sorted by decreasing priority (preserving\n    order in case of same priority).\n    Priorities can be any number, only matters how they compare to each other.\n    Value 100 is used for missing kinds (i.e. not all can be supplied).\n    Default: `{}` (all equal priority).\n\nReturn ~\n`(table)` Array of processed items from LSP response.\n\n------------------------------------------------------------------------------\n                                       *MiniCompletion.default_snippet_insert()*\n               `MiniCompletion.default_snippet_insert`({snippet})\nDefault snippet insert\n\nOrder of preference:\n- Use |mini.snippets| if set up (i.e. after `require('mini.snippets').setup()`).\n- Use |vim.snippet.expand()| on Neovim>=0.10\n- Add snippet text at cursor as is.\n\nAfter snippet is inserted, user is expected to navigate/jump between dedicated\nplaces (tabstops) to adjust inserted text as needed:\n- |mini.snippets| by default uses <C-l> / <C-h> to jump to next/previous tabstop.\n  Can be adjusted in `mappings` of |MiniSnippets.config|.\n- |vim.snippet| on Neovim=0.10 requires manually created mappings for jumping\n  between tabstops (see |vim.snippet.jump()|). Neovim>=0.11 sets them up\n  automatically to <Tab> / <S-Tab> (if not overridden by user).\n\nEnd session by navigating all the way to the last tabstop. In 'mini.snippets':\n- Also make any text edit or exit Insert mode to end the session. This allows\n  smoother navigation to previous tabstops in case of a lately spotted typo.\n- Press `<C-c>` to force session stop.\n\nParameters ~\n{snippet} `(string)` Snippet body to insert at cursor.\n\nSee also ~\n- |MiniSnippets-session| if 'mini.snippets' is set up.\n- |vim.snippet| for Neovim's built-in snippet engine.\n\n------------------------------------------------------------------------------\n                                         *MiniCompletion.get_lsp_capabilities()*\n                 `MiniCompletion.get_lsp_capabilities`({opts})\nGet client LSP capabilities\n\nPossible usages:\n- On Neovim>=0.11 via |vim.lsp.config()|: >lua\n\n  vim.lsp.config('*', {capabilities = MiniCompletion.get_lsp_capabilities()})\n<\n- Together with |vim.lsp.protocol.make_client_capabilities()| to get the full\n  client capabilities (use |vim.tbl_deep_extend()| to merge tables).\n\n- Manually execute `:=MiniCompletion.get_lsp_capabilities()` to see the info.\n\nNotes:\n- It declares completion resolve support for `'additionalTextEdits'` (usually\n  used for something like auto-import feature), as it is usually a more robust\n  choice for various LSP servers. As a consequence, this requires selecting\n  completion item and waiting for `config.delay.info` milliseconds plus server\n  response time (i.e. until information window shows relevant text).\n  To not have to wait after an item selection and if the server handles absent\n  `'additionalTextEdits'` well, set `opts.resolve_additional_text_edits = false`.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <resolve_additional_text_edits> `(boolean)` - whether to declare\n    `'additionalTextEdits'` as possible to resolve in `'completionitem/resolve'`\n    requrest. See above \"Notes\" section.\n    Default: `true`.\n\nReturn ~\n`(table)` Data about LSP capabilities supported by 'mini.completion'. Has same\n  structure as relevant parts of |vim.lsp.protocol.make_client_capabilities()|.\n\nSee also ~\nStructures of `completionClientCapabilities` and `signatureHelpClientCapabilities`\nat https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-cursorword.txt",
    "content": "*mini.cursorword* Autohighlight word under cursor\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                *MiniCursorword*\nFeatures:\n- Autohighlight word under cursor with customizable delay.\n\n- Current word under cursor can be highlighted differently.\n\n- Highlighting is triggered only if current cursor character is a |[:keyword:]|.\n\n- Highlighting stops in insert and terminal modes.\n\n- \"Word under cursor\" is meant as in Vim's |<cword>|: something user would\n  get as 'iw' text object.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.cursorword').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniCursorword` which you can use for scripting or manually (with\n`:lua MiniCursorword.*`).\n\nSee |MiniCursorword.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minicursorword_config` which should have same structure as\n`MiniCursorword.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Highlight groups ~\n\n- `MiniCursorword` - highlight group of a non-current cursor word.\n  Default: plain underline.\n\n- `MiniCursorwordCurrent` - highlight group of a current word under cursor.\n  Default: links to `MiniCursorword` (so `:hi clear MiniCursorwordCurrent`\n  will lead to showing `MiniCursorword` highlight group).\n  Note: To not highlight it, use the following Lua code: >lua\n\n  vim.api.nvim_set_hl(0, 'MiniCursorwordCurrent', {})\n<\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.minicursorword_disable` (globally) or\n`vim.b.minicursorword_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes. Note: after disabling\nthere might be highlighting left; it will be removed after next\nhighlighting update.\n\nModule-specific disabling:\n- Don't show highlighting if cursor is on the word that is in a blocklist\n  of current filetype. In this example, blocklist for \"lua\" is \"local\" and\n  \"require\" words, for \"javascript\" - \"import\": >lua\n\n  _G.cursorword_blocklist = function()\n    local curword = vim.fn.expand('<cword>')\n    local filetype = vim.bo.filetype\n\n    -- Add any disabling global or filetype-specific logic here\n    local blocklist = {}\n    if filetype == 'lua' then\n      blocklist = { 'local', 'require' }\n    elseif filetype == 'javascript' then\n      blocklist = { 'import' }\n    end\n\n    vim.b.minicursorword_disable = vim.tbl_contains(blocklist, curword)\n  end\n\n  -- Make sure to add this autocommand *before* calling module's `setup()`.\n  vim.cmd('au CursorMoved * lua _G.cursorword_blocklist()')\n<\n------------------------------------------------------------------------------\n                                                        *MiniCursorword.setup()*\n                        `MiniCursorword.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniCursorword.config|.\n\nUsage ~\n>lua\n  require('mini.cursorword').setup() -- use default config\n  -- OR\n  require('mini.cursorword').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                         *MiniCursorword.config*\n                            `MiniCursorword.config`\nDefaults ~\n>lua\n  MiniCursorword.config = {\n    -- Delay (in ms) between when cursor moved and when highlighting appeared\n    delay = 100,\n  }\n<\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-deps.txt",
    "content": "*mini.deps* Plugin manager\n\nMIT License Copyright (c) 2024 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniDeps*\nFeatures:\n\n- Manage plugins utilizing Git and built-in |packages| with these actions:\n    - Add plugin to current session, download if absent. See |MiniDeps.add()|.\n    - Update with/without confirm, with/without parallel download of new data.\n      See |MiniDeps.update()|.\n    - Delete unused plugins with/without confirm. See |MiniDeps.clean()|.\n    - Get / set / save / load snapshot. See `MiniDeps.snap_*()` functions.\n\n    All main actions are available both as Lua functions and user commands\n    (see |MiniDeps-commands|).\n\n- Minimal yet flexible plugin |MiniDeps-plugin-specification|:\n    - Plugin source.\n    - Name of target plugin directory.\n    - Checkout target: branch, commit, tag, etc.\n    - Monitor branch to track updates without checking out.\n    - Dependencies to be set up prior to the target plugin.\n    - Hooks to call before/after plugin is created/changed.\n\n- Helpers implementing two-stage startup: |MiniDeps.now()| and |MiniDeps.later()|.\n  See |MiniDeps-overview| for how to implement basic lazy loading with them.\n\nWhat it doesn't do:\n\n- Manage plugins which are developed without Git. The suggested approach is\n  to create a separate package (see |packages|).\n\n- Provide ways to completely remove or update plugin's functionality in\n  current session. Although this is partially doable, it can not be done\n  in full (yet) because plugins can have untraceable side effects\n  (autocmmands, mappings, etc.).\n  The suggested approach is to restart Nvim.\n\nSources with more details:\n- |MiniDeps-overview|\n- |MiniDeps-plugin-specification|\n- |MiniDeps-commands|\n\n# Dependencies ~\n\nFor most of its functionality this plugin relies on `git` CLI tool.\nSee https://git-scm.com/ for more information about how to install it.\nActual knowledge of Git is not required but helpful.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.deps').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniDeps`\nwhich you can use for scripting or manually (with `:lua MiniDeps.*`).\n\nSee |MiniDeps.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minideps_config` which should have same structure as\n`MiniDeps.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [folke/lazy.nvim](https://github.com/folke/lazy.nvim):\n    - More feature-rich and complex.\n    - Uses table specification with dedicated functions to add plugins,\n      while this module uses direct function call approach\n      (calling |MiniDeps.add()| ensures that plugin is usable).\n    - Uses version tags by default, while this module is more designed towards\n      tracking branches. Using tags is possible too (see |MiniDeps-overview|).\n\n- [savq/paq-nvim](https://github.com/savq/paq-nvim):\n    - Overall less feature-rich than this module (by design).\n    - Uses array of plugin specifications inside `setup()` call to define which\n      plugins should be installed. Requires separate `:PaqInstall` call to\n      actually install them. This module ensures installation on first load.\n\n- [junegunn/vim-plug](https://github.com/junegunn/vim-plug):\n    - Written in Vimscript, while this module is in Lua.\n    - Similar approach to defining and installing plugins as 'savq/paq-nvim'.\n    - Has basic lazy-loading built-in, while this module does not (by design).\n\n# Highlight groups ~\n\nHighlight groups are used inside confirmation buffers after\ndefault |MiniDeps.update()| and |MiniDeps.clean()|.\n\n- `MiniDepsChangeAdded`   - added change (commit) during update.\n- `MiniDepsChangeRemoved` - removed change (commit) during update.\n- `MiniDepsHint`          - various hints.\n- `MiniDepsInfo`          - various information.\n- `MiniDepsMsgBreaking`   - message for (conventional commit) breaking change.\n- `MiniDepsPlaceholder`   - placeholder when there is no valuable information.\n- `MiniDepsTitle`         - various titles.\n- `MiniDepsTitleError`    - title when plugin had errors during update.\n- `MiniDepsTitleSame`     - title when plugin has no changes to update.\n- `MiniDepsTitleUpdate`   - title when plugin has changes to update.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n------------------------------------------------------------------------------\n                                                             *MiniDeps-overview*\n# Directory structure ~\n\nThis module uses built-in |packages| to make plugins usable in current session.\nIt works with \"pack/deps\" package inside `config.path.package` directory.\n\nBy default \"opt\" subdirectory is used to install optional plugins which are\nloaded on demand with |MiniDeps.add()|.\nNon-optional plugins in \"start\" subdirectory are supported but only if moved\nthere manually after initial install. Use it if you know what you are doing.\n\n# Add plugin ~\n\nUse |MiniDeps.add()| to add plugin to current session. Supply plugin's URL\nsource as a string or |MiniDeps-plugin-specification| in general. If plugin is\nnot present in \"pack/deps\" package, it will be created (a.k.a. installed)\nbefore processing anything else.\n\nThe recommended way of adding a plugin is by calling |MiniDeps.add()| in the\n|init.lua| file (make sure |MiniDeps.setup()| is called prior): >lua\n\n  local add = MiniDeps.add\n\n  -- Add to current session (install if absent)\n  add({\n    source = 'neovim/nvim-lspconfig',\n    -- Supply dependencies near target plugin\n    depends = { 'williamboman/mason.nvim' },\n  })\n\n  add({\n    source = 'nvim-treesitter/nvim-treesitter',\n    -- Use 'master' while monitoring updates in 'main'\n    checkout = 'master',\n    monitor = 'main',\n    -- Perform action after every checkout\n    hooks = { post_checkout = function() vim.cmd('TSUpdate') end },\n  })\n  -- Possible to immediately execute code which depends on the added plugin\n  require('nvim-treesitter.configs').setup({\n    ensure_installed = { 'lua', 'vimdoc' },\n    highlight = { enable = true },\n  })\n<\nNOTE:\n- To increase performance, `add()` only ensures presence on disk and\n  nothing else. In particular, it doesn't ensure `opts.checkout` state.\n  Update or modify plugin state explicitly (see later sections).\n\n# Lazy loading ~\n\nAny lazy-loading is assumed to be done manually by calling |MiniDeps.add()|\nat appropriate time. This module provides helpers implementing special safe\ntwo-stage loading:\n- |MiniDeps.now()| safely executes code immediately. Use it to load plugins\n  with UI necessary to make initial screen draw.\n- |MiniDeps.later()| schedules code to be safely executed later, preserving\n  order. Use it (with caution) for everything else which doesn't need\n  precisely timed effect, as it will be executed some time soon on one of\n  the next event loops. >lua\n\n  local now, later = MiniDeps.now, MiniDeps.later\n\n  -- Safely execute immediately\n  now(function() vim.cmd('colorscheme miniwinter') end)\n  now(function() require('mini.statusline').setup() end)\n\n  -- Safely execute later\n  later(function() require('mini.pick').setup() end)\n<\n# Update ~\n\nTo update plugins from current session with new data from their sources,\nuse |:DepsUpdate|. This will download updates (utilizing multiple cores) and\nshow confirmation buffer. Follow instructions at its top to finish an update.\n\nNOTE: This updates plugins on disk which most likely won't affect current\nsession. Restart Nvim to have them properly loaded.\n\n# Modify ~\n\nTo change plugin's specification (like set different `checkout`, etc.):\n- Update corresponding |MiniDeps.add()| call.\n- Run `:DepsUpdateOffline <plugin_name>`.\n- Review changes and confirm.\n- Restart Nvim.\n\nNOTE: if `add()` prior used a single source string, make sure to convert\nits argument to `{ source = '<previous_argument>', checkout = '<state>'}`\n\n# Snapshots ~\n\nUse |:DepsSnapSave| to save state of all plugins from current session into\na snapshot file (see `config.path.snapshot`).\n\nUse |:DepsSnapLoad| to load snapshot. This will change (without confirmation)\nstate on disk. Plugins present in both snapshot file and current session\nwill be affected. Restart Nvim to see the effect.\n\nNOTE: loading snapshot does not change plugin's specification defined inside\n|MiniDeps.add()| call. This means that next update might change plugin's state.\nTo make it permanent, freeze plugin in target state manually.\n\n# Freeze ~\n\nModify plugin's specification to have `checkout` pointing to a static\ntarget: tag, state (commit hash), or 'HEAD' (to freeze in current state).\n\nFrozen plugins will not receive updates. You can monitor any new changes from\nits source by \"subscribing\" to `monitor` branch which will be shown inside\nconfirmation buffer after |:DepsUpdate|.\n\nExample: use `checkout = 'v0.10.0'` to freeze plugin at tag \"v0.10.0\" while\nmonitoring new versions in the log from `monitor` (usually default) branch.\n\n# Rollback ~\n\nTo roll back after an unfortunate update:\n- Get identifier of latest working state:\n    - Use |:DepsShowLog| to see update log, look for plugin's name, and copy\n      identifier listed as \"State before:\".\n    - See previously saved snapshot file for plugin's name and copy\n      identifier next to it.\n- Freeze plugin at that state while monitoring appropriate branch.\n  Revert to previous shape of |MiniDeps.add()| call to resume updating.\n\n# Remove ~\n\n- Make sure that target plugin is not registered in current session.\n  Usually it means removing corresponding |MiniDeps.add()| call.\n- Run |:DepsClean|. This will show confirmation buffer with a list of plugins to\n  be deleted from disk. Follow instructions at its top to finish cleaning.\n\nAlternatively, manually delete plugin's directory from \"pack/deps\" package.\n\n------------------------------------------------------------------------------\n                                                 *MiniDeps-plugin-specification*\nEach plugin dependency is managed based on its specification (a.k.a. \"spec\").\nSee |MiniDeps-overview| for some examples.\n\nSpecification can be a single string which is inferred as:\n- Plugin <name> if it doesn't contain \"/\".\n- Plugin <source> otherwise.\n\nPrimarily, specification is a table with the following fields:\n\n- <source> `(string|nil)` - field with URI of plugin source used during creation\n  or update. Can be anything allowed by `git clone`.\n  Default: `nil` to rely on source set up during install.\n  Notes:\n    - It is required for creating plugin, but can be omitted afterwards.\n    - As the most common case, URI of the format \"user/repo\" (if it contains\n      valid characters) is transformed into \"https://github.com/user/repo\".\n\n- <name> `(string|nil)` - directory basename of where to put plugin source.\n  It is put in \"pack/deps/opt\" subdirectory of `config.path.package`.\n  Default: basename of <source> if it is present, otherwise should be\n  provided explicitly.\n\n- <checkout> `(string|nil)` - checkout target used to set state during update.\n  Can be anything supported by `git checkout` - branch, commit, tag, etc.\n  Default: `nil` for default branch (usually \"main\" or \"master\").\n\n- <monitor> `(string|nil)` - monitor branch used to track new changes from\n  different target than `checkout`. Should be a name of present Git branch.\n  Default: `nil` for default branch (usually \"main\" or \"master\").\n\n- <depends> `(table|nil)` - array of plugin specifications (strings or tables)\n  to be added prior to the target.\n  Default: `nil` for no dependencies.\n\n- <hooks> `(table|nil)` - table with callable hooks to call on certain events.\n  Possible hook names:\n    - <pre_install>   - before creating plugin directory.\n    - <post_install>  - after  creating plugin directory (before |:packadd|).\n    - <pre_checkout>  - before making change in existing plugin.\n    - <post_checkout> - after  making change in existing plugin.\n  Each hook is executed with the following table as an argument:\n    - <path> (`string`)   - absolute path to plugin's directory\n      (might not yet exist on disk).\n    - <source> (`string`) - resolved <source> from spec.\n    - <name> (`string`)   - resolved <name> from spec.\n  Default: `nil` for no hooks.\n\n------------------------------------------------------------------------------\n                                                             *MiniDeps-commands*\nNote: Most commands have a Lua function alternative which they rely on.\nLike |:DepsAdd| uses |MiniDeps.add()|, etc.\n\n# :DepsAdd ~\n\n*:DepsAdd* with `user/repo` argument makes plugin https://github.com/user/repo\navailable in the current session (also creates it, if it is not present).\n`:DepsAdd name` adds already installed plugin `name` to current session.\nAccepts only single string compatible with |MiniDeps-plugin-specification|.\nTo add plugin in every session, put |MiniDeps.add()| in |init.lua|.\n\n# :DepsUpdate ~\n\n*:DepsUpdate* synchronizes plugins with their session specifications and\nupdates them with new changes from sources. It shows confirmation buffer in\na separate |tabpage| with information about an upcoming update to review\nand (selectively) apply. See |MiniDeps.update()| for more info.\n\n`:DepsUpdate name` updates plugin `name`. Any number of names is allowed.\n\n`:DepsUpdate!` and `:DepsUpdate! name` update without confirmation.\nYou can see what was done in the log file afterwards (|:DepsShowLog|).\n\n# :DepsUpdateOffline ~\n\n*:DepsUpdateOffline* is same as |:DepsUpdate| but doesn't download new updates\nfrom sources. Useful to only synchronize plugin specification in code and\non disk without unnecessary downloads.\n\n# :DepsShowLog ~\n\n*:DepsShowLog* opens log file to review.\n\n# :DepsClean ~\n\n*:DepsClean* deletes plugins from disk not added to current session. It shows\nconfirmation buffer in a separate |tabpage| with information about an upcoming\ndeletes to review and (selectively) apply. See |MiniDeps.clean()| for more info.\n\n`:DepsClean!` deletes plugins without confirmation.\n\n# :DepsSnapSave ~\n\n*:DepsSnapSave* creates snapshot file in default location (see |MiniDeps.config|).\n`:DepsSnapSave path` creates snapshot file at `path`.\n\n# :DepsSnapLoad ~\n\n*:DepsSnapLoad* loads snapshot file from default location (see |MiniDeps.config|).\n`:DepsSnapLoad path` loads snapshot file at `path`.\n\n------------------------------------------------------------------------------\n                                                              *MiniDeps.setup()*\n                           `MiniDeps.setup`({config})\nModule setup\n\nCalling this function creates user commands described in |MiniDeps-commands|.\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniDeps.config|.\n\nUsage ~\n>lua\n  require('mini.deps').setup() -- use default config\n  -- OR\n  require('mini.deps').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniDeps.config*\n                               `MiniDeps.config`\nDefaults ~\n>lua\n  MiniDeps.config = {\n    -- Parameters of CLI jobs\n    job = {\n      -- Number of parallel threads to use. Default: 80% of all available.\n      n_threads = nil,\n\n      -- Timeout (in ms) for each job before force quit\n      timeout = 30000,\n    },\n\n    -- Paths describing where to store data\n    path = {\n      -- Directory for built-in package.\n      -- All plugins are actually stored in 'pack/deps' subdirectory.\n      package = vim.fn.stdpath('data') .. '/site',\n\n      -- Default file path for a snapshot\n      snapshot = vim.fn.stdpath('config') .. '/mini-deps-snap',\n\n      -- Log file\n      log = vim.fn.stdpath('log') .. '/mini-deps.log'\n    },\n\n    -- Whether to disable showing non-error feedback\n    silent = false,\n  }\n<\n# Job ~\n\n`config.job` defines how CLI jobs are run.\n\n`job.n_threads` is a maximum number of parallel jobs used when needed.\nDefault: 80% of all available.\n\n`job.timeout` is a duration (in ms) from job start until it is forced to stop.\nDefault: 30000.\n\n# Paths ~\n\n`config.path` defines main paths used in this module.\n\n`path.package` is a string with path inside which \"pack/deps\" package is stored\n(see |MiniDeps-overview|).\nDefault: \"site\" subdirectory of \"data\" standard path (see |stdpath()|).\n\n`path.snapshot` is a string with default path for snapshot.\nSee |:DepsSnapSave| and |:DepsSnapLoad|.\nDefault: \"mini-deps-snap\" file in \"config\" standard path (see |stdpath()|).\n\n`path.log` is a string with path containing log of operations done by module.\nIn particular, it contains all changes done after making an update.\nDefault: \"mini-deps.log\" file in \"log\" standard path (see |stdpath()|).\n\n# Silent ~\n\n`config.silent` is a boolean controlling whether to suppress non-error feedback.\nDefault: `false`.\n\n------------------------------------------------------------------------------\n                                                                *MiniDeps.add()*\n                         `MiniDeps.add`({spec}, {opts})\nAdd plugin to current session\n\n- Process specification by expanding dependencies into single spec array.\n- Ensure plugin is present on disk along with its dependencies by installing\n  (in parallel) absent ones:\n    - Execute `opts.hooks.pre_install`.\n    - Use `git clone` to clone plugin from its source URI into \"pack/deps/opt\".\n    - Set state according to `opts.checkout`.\n    - Execute `opts.hooks.post_install`.\n- Register spec(s) in current session.\n- Make sure plugin(s) can be used in current session (see |:packadd|).\n- If not during startup and is needed, source all \"after/plugin/\" scripts.\n\nNotes:\n- Presence of plugin is checked by its name which is the same as the name\n  of its directory inside \"pack/deps\" package (see |MiniDeps-overview|).\n- To increase performance, this function only ensures presence on disk and\n  nothing else. In particular, it doesn't ensure `opts.checkout` state.\n  Use |MiniDeps.update()| or |:DepsUpdateOffline| explicitly.\n- Adding plugin several times updates its session specs.\n\nParameters ~\n{spec} `(table|string)` Plugin specification. See |MiniDeps-plugin-specification|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <bang> `(boolean)` - whether to use `:packadd!` instead of plain |:packadd|.\n\n------------------------------------------------------------------------------\n                                                             *MiniDeps.update()*\n                       `MiniDeps.update`({names}, {opts})\nUpdate plugins\n\n- Synchronize specs with state of plugins on disk (set `source`, etc.).\n- Infer data before downloading updates.\n- If not offline, download updates (in parallel).\n- Infer data after downloading updates.\n- If update is forced, apply all changes immediately while updating log\n  file (at `config.path.log`; use |:DepsShowLog| to review).\n  Otherwise show confirmation buffer with instructions on how to proceed.\n\nParameters ~\n{names} `(table|nil)` Array of plugin names to update.\n Default: all plugins from current session (see |MiniDeps.get_session()|).\n{opts} `(table|nil)` Options. Possible fields:\n  - <force> `(boolean)` - whether to force update without confirmation.\n    Default: `false`.\n  - <offline> `(boolean)` - whether to skip downloading updates from sources.\n    Default: `false`.\n\n------------------------------------------------------------------------------\n                                                              *MiniDeps.clean()*\n                            `MiniDeps.clean`({opts})\nClean plugins\n\n- Compute absent plugins: not registered in current session\n  (see |MiniDeps.get_session()|) but present on disk in dedicated \"pack/deps\"\n  package (inside `config.path.package`).\n- If cleaning is forced, delete all absent plugins from disk.\n  Otherwise show confirmation buffer with instructions on how to proceed.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <force> `(boolean)` - whether to force delete without confirmation.\n    Default: `false`.\n\n------------------------------------------------------------------------------\n                                                           *MiniDeps.snap_get()*\n                             `MiniDeps.snap_get`()\nCompute snapshot\n\nReturn ~\n`(table)` A snapshot table: plugin names as keys and state as values.\n  All plugins in current session are processed.\n\n------------------------------------------------------------------------------\n                                                           *MiniDeps.snap_set()*\n                          `MiniDeps.snap_set`({snap})\nApply snapshot\n\nNotes:\n- Checking out states from snapshot does not update session plugin spec\n  (`checkout` field in particular). Among others, it means that next call\n  to |MiniDeps.update()| might override the result of this function.\n  To make changes permanent, set `checkout` spec field to state from snapshot.\n\nParameters ~\n{snap} `(table)` A snapshot table: plugin names as keys and state as values.\n  Only plugins in current session are processed.\n\n------------------------------------------------------------------------------\n                                                          *MiniDeps.snap_save()*\n                          `MiniDeps.snap_save`({path})\nSave snapshot\n\nParameters ~\n{path} `(string|nil)` A valid path on disk where to write snapshot computed\n  with |MiniDeps.snap_get()|.\n  Default: `config.path.snapshot`.\n\n------------------------------------------------------------------------------\n                                                          *MiniDeps.snap_load()*\n                          `MiniDeps.snap_load`({path})\nLoad snapshot file\n\nNotes from |MiniDeps.snap_set()| also apply here.\n\nParameters ~\n{path} `(string|nil)` A valid path on disk from where to read snapshot.\n  Default: `config.path.snapshot`.\n\n------------------------------------------------------------------------------\n                                                        *MiniDeps.get_session()*\n                            `MiniDeps.get_session`()\nGet session\n\nPlugin is registered in current session if it either:\n- Was added with |MiniDeps.add()| (preserving order of calls).\n- Is a \"start\" plugin and present in 'runtimpath'.\n\nReturn ~\n`(table)` Array with specifications of all plugins registered in\n  current session.\n\n------------------------------------------------------------------------------\n                                                                *MiniDeps.now()*\n                              `MiniDeps.now`({f})\nExecute function now\n\nSafely execute function immediately. Errors are shown with |vim.notify()|\nlater, after all queued functions (including with |MiniDeps.later()|)\nare executed, thus not blocking execution of next code in file.\n\nAssumed to be used as a first step during two-stage config execution to\nload plugins immediately during startup. See |MiniDeps-overview|.\n\nParameters ~\n{f} `(function)` Callable to execute.\n\n------------------------------------------------------------------------------\n                                                              *MiniDeps.later()*\n                             `MiniDeps.later`({f})\nExecute function later\n\nQueue function to be safely executed later without blocking execution of\nnext code in file. All queued functions are guaranteed to be executed in\norder they were added.\nErrors are shown with |vim.notify()| after all queued functions are executed.\n\nAssumed to be used as a second step during two-stage config execution to\nload plugins \"lazily\" after startup. See |MiniDeps-overview|.\n\nParameters ~\n{f} `(function)` Callable to execute.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-diff.txt",
    "content": "*mini.diff* Work with diff hunks\n\nMIT License Copyright (c) 2024 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniDiff*\nFeatures:\n\n- Visualize difference between buffer text and its configurable reference\n  interactively (updates as you type). This is done per line showing whether\n  it is inside added, changed, or deleted part of difference (called hunk).\n  Visualization can be with customizable colored signs or line numbers.\n\n- Special toggleable overlay view with more hunk details inside text area.\n  See |MiniDiff.toggle_overlay()|.\n\n- Completely configurable per buffer source(s) of reference text used to keep\n  it up to date and define interactions with it. Can be array of sources which\n  are attempted to attach in order. See |MiniDiff-source-specification|.\n  By default uses Git source. See |MiniDiff.gen_source.git()|.\n\n- Configurable mappings to manage diff hunks:\n    - Apply and reset hunks inside region (selected visually or with\n      a dot-repeatable operator).\n    - \"Hunk range under cursor\" textobject to be used as operator target.\n    - Navigate to first/previous/next/last hunk. See |MiniDiff.goto_hunk()|.\n\nWhat it doesn't do:\n\n- Provide functionality to work directly with Git outside of visualizing\n  and staging (applying) hunks with (default) Git source. In particular,\n  unstaging hunks is not supported. See |MiniDiff.gen_source.git()|.\n\nSources with more details:\n- |MiniDiff-overview|\n- |MiniDiff-source-specification|\n- |MiniDiff-hunk-specification|\n- |MiniDiff-diff-summary|\n\n# Setup ~\n\nThis module needs a setup with `require('mini.diff').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniDiff`\nwhich you can use for scripting or manually (with `:lua MiniDiff.*`).\n\nSee |MiniDiff.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minidiff_config` which should have same structure as\n`MiniDiff.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim):\n    - Main inspiration for this module, so there are many similarities.\n    - Can display only Git hunks, while this module has extensible design.\n    - Provides more functionality to work with Git outside of hunks.\n      This module does not (by design).\n\n# Highlight groups ~\n\n- `MiniDiffSignAdd`        - \"add\" hunk lines visualization.\n- `MiniDiffSignChange`     - \"change\" hunk lines visualization.\n- `MiniDiffSignDelete`     - \"delete\" hunk lines visualization.\n- `MiniDiffOverAdd`        - added buffer text shown in overlay.\n- `MiniDiffOverChange`     - changed reference text shown in overlay.\n- `MiniDiffOverChangeBuf`  - changed buffer text shown in overlay.\n- `MiniDiffOverContext`    - context of a change shown in reference overlay.\n- `MiniDiffOverContextBuf` - context of a change shown in buffer overlay.\n- `MiniDiffOverDelete`     - deleted reference text shown in overlay.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo temporarily disable features without relying on |MiniDiff.disable()|,\nset `vim.g.minidiff_disable` (globally) or `vim.b.minidiff_disable` (for\na buffer) to `true`. Considering high number of different scenarios and\ncustomization intentions, writing exact rules for disabling module's\nfunctionality is left to user.\nSee |mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                             *MiniDiff-overview*\n# Diffs and hunks ~\n\nThe \"diff\" (short for \"difference\") is a result of computing how two text\nstrings differ from one another. This is done on per line basis, i.e. the\ngoal is to compute sequences of lines common to both files, interspersed\nwith groups of differing lines (called \"hunks\").\n\nAlthough computing diff is a general concept (used on its own, in Git, etc.),\nthis module computes difference between current text in a buffer and some\nreference text which is kept up to date specifically for that buffer.\nFor example, default reference text is computed as file content in Git index.\nThis can be customized in `config.source` (see |MiniDiff-source-specification|).\n\n# Hunk specification ~\n*MiniDiff-hunk-specification*\n\nHunk describes two sets (one from buffer text, one - from reference) of\nconsecutive lines which are different. In this module hunk is stored as\na table with the following fields:\n\n- <buf_start> `(number)` - start of hunk buffer lines. First line is 1.\n  Can be 0 if first reference lines are deleted.\n\n- <buf_count> `(number)` - number of consecutive buffer lines. Can be 0 in\n  case reference lines are deleted.\n\n- <ref_start> `(number)` - start of hunk reference lines. First line is 1.\n  Can be 0 if lines are added before first reference line.\n\n- <ref_count> `(number)` - number of consecutive reference lines. Can be 0 in\n  case buffer lines are added.\n\n- <type> `(string)` - hunk type. Can be one of:\n    - \"add\" - lines are present in buffer but absent in reference.\n    - \"change\" - lines are present in both buffer and reference.\n    - \"delete\" - lines are absent in buffer but present in reference.\n\n# Life cycle ~\n\n- When entering proper (not already enabled, valid, showing text) buffer,\n  it is attempted to be enabled for diff processing.\n- During enabling, attempt attaching the source. This should set up how\n  reference text is kept up to date.\n- On every text change, diff computation is scheduled in debounced fashion\n  after customizable delay (200 ms by default).\n- After the diff is computed, do the following:\n    - Update visualization based on configurable style: either by placing\n      colored text in sign column or coloring line numbers. Colors for both\n      styles are defined per hunk type in corresponding `MiniDiffSign*`\n      highlight group (see |mini.diff|) and sign text for \"sign\" style can\n      be configured in `view.signs` of |MiniDiff.config|.\n    - Update overlay view (if it is enabled).\n    - Update `vim.b.minidiff_summary` and `vim.b.minidiff_summary_string`\n      buffer-local variables. These can be used, for example, in statusline.\n    - *MiniDiff-update-event* Trigger `MiniDiffUpdated` `User` event.\n      See |MiniDiff-diff-summary| for example of how to use it.\n\nNotes:\n- Use |:edit| to reset (disable and re-enable) current buffer.\n- To work with BOM bytes, set 'bomb' and have `ucs-bom` in 'fileencodings'.\n\n# Overlay ~\n\nAlong with basic visualization, there is a special view called \"overlay\".\nAlthough it is meant for temporary overview of diff details and can be\nmanually toggled via |MiniDiff.toggle_overlay()|, text can be changed with\noverlay reacting accordingly.\n\nIt shows more diff details inside text area:\n\n- Added buffer lines are highlighted with `MiniDiffOverAdd` highlight group.\n\n- Deleted reference lines are shown as virtual lines and highlighted with\n  `MiniDiffOverDelete` highlight group.\n\n- \"Change\" hunks with equal number of buffer/reference lines show \"word diff\".\n  This is usually the case when `options.linematch` is enabled (as by default).\n  Reference line is shown next to its buffer counterpart. Changed parts are\n  highlighted with `MiniDiffOverChange` and `MiniDiffOverChangeBuf` in reference\n  and buffer lines. The rest of lines have `MiniDiffOverContext`\n  and `MiniDiffOverContextBuf` highlighting.\n\n  Change with unequal number of buffer/reference lines is shown with reference\n  part as virtual lines highlighted with `MiniDiffOverChange` group.\n  Corresponding buffer lines are treated as context for the change and are\n  highlighted with `MiniDiffOverContextBuf` group.\n\nNotes:\n- Word diff has non-zero context width. This means if changed characters\n  are close enough, whole range between them is also colored. This usually\n  reduces visual noise.\n- Virtual lines above line 1 (like deleted or changed lines) need manual\n  scroll to become visible (with |CTRL-Y|).\n\n# Mappings ~\n\nThis module provides mappings for common actions with diffs, like:\n- Apply and reset hunks.\n- \"Hunk range under cursor\" textobject.\n- Go to first/previous/next/last hunk range.\n\nExamples:\n- `vip` followed by `gh` / `gH` applies/resets hunks inside current paragraph.\n  Same can be achieved in operator form `ghip` / `gHip`, which has the\n  advantage of being dot-repeatable (see |single-repeat|).\n- `gh_` / `gH_` applies/resets current line (even if it is not a full hunk).\n- `ghgh` / `gHgh` applies/resets hunk range under cursor.\n- `dgh` deletes hunk range under cursor.\n- `[H` / `[h` / `]h` / `]H` navigate cursor to the first / previous / next / last\n  hunk range of the current buffer.\n\nMappings for some functionality are assumed to be done manually.\nSee |MiniDiff.operator()|.\n\n# Buffer-local variables ~\n*MiniDiff-diff-summary*\n\nEach enabled buffer has the following buffer-local variables which can be\nused in custom statusline to show an overview of hunks in current buffer:\n\n- `vim.b.minidiff_summary` is a table with the following fields:\n    - `source_name` - name of the active source. This is the only present field\n      if buffer's reference text is not (yet) set.\n    - `n_ranges` - number of hunk ranges (sequences of contiguous hunks).\n    - `add` - number of added lines.\n    - `change` - number of changed lines.\n    - `delete` - number of deleted lines.\n\n- `vim.b.minidiff_summary_string` is a string representation of summary\n  with a fixed format. Empty string if there is no reference text (yet).\n  It is expected to be used as is. To achieve different formatting, use\n  `vim.b.minidiff_summary` to construct one. The best way to do this is by\n  overriding `vim.b.minidiff_summary_string` inside |MiniDiff-update-event|: >lua\n\n  local format_summary = function(data)\n    local summary = vim.b[data.buf].minidiff_summary\n    local t = {}\n    if summary.add > 0 then table.insert(t, '+' .. summary.add) end\n    if summary.change > 0 then table.insert(t, '~' .. summary.change) end\n    if summary.delete > 0 then table.insert(t, '-' .. summary.delete) end\n    vim.b[data.buf].minidiff_summary_string = table.concat(t, ' ')\n  end\n  local au_opts = { pattern = 'MiniDiffUpdated', callback = format_summary }\n  vim.api.nvim_create_autocmd('User', au_opts)\n<\n------------------------------------------------------------------------------\n                                                              *MiniDiff.setup()*\n                           `MiniDiff.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniDiff.config|.\n\nUsage ~\n>lua\n  require('mini.diff').setup() -- use default config\n  -- OR\n  require('mini.diff').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniDiff.config*\n                               `MiniDiff.config`\nDefaults ~\n>lua\n  MiniDiff.config = {\n    -- Options for how hunks are visualized\n    view = {\n      -- Visualization style. Possible values are 'sign' and 'number'.\n      -- Default: 'number' if line numbers are enabled, 'sign' otherwise.\n      style = vim.go.number and 'number' or 'sign',\n\n      -- Signs used for hunks with 'sign' view\n      signs = { add = '▒', change = '▒', delete = '▒' },\n\n      -- Priority of used visualization extmarks\n      priority = 199,\n    },\n\n    -- Source(s) for how reference text is computed/updated/etc\n    -- Uses content from Git index by default\n    source = nil,\n\n    -- Delays (in ms) defining asynchronous processes\n    delay = {\n      -- How much to wait before update following every text change\n      text_change = 200,\n    },\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      -- Apply hunks inside a visual/operator region\n      apply = 'gh',\n\n      -- Reset hunks inside a visual/operator region\n      reset = 'gH',\n\n      -- Hunk range textobject to be used inside operator\n      -- Works also in Visual mode if mapping differs from apply and reset\n      textobject = 'gh',\n\n      -- Go to hunk range in corresponding direction\n      goto_first = '[H',\n      goto_prev = '[h',\n      goto_next = ']h',\n      goto_last = ']H',\n    },\n\n    -- Various options\n    options = {\n      -- Diff algorithm. See `:h vim.diff()`.\n      algorithm = 'histogram',\n\n      -- Whether to use \"indent heuristic\". See `:h vim.diff()`.\n      indent_heuristic = true,\n\n      -- The amount of second-stage diff to align lines\n      linematch = 60,\n\n      -- Whether to wrap around edges during hunk navigation\n      wrap_goto = false,\n    },\n  }\n<\n# View ~\n\n`config.view` contains settings for how diff hunks are visualized.\nExample of using custom signs: >lua\n\n  require('mini.diff').setup({\n    view = {\n      style = 'sign',\n      signs = { add = '+', change = '~', delete = '-' },\n    },\n  })\n<\n`view.style` is a string defining visualization style. Can be one of \"sign\"\n(as a colored sign in a |sign-column|) or \"number\" (colored line number).\nDefault: \"number\" if |'number'| option is enabled, \"sign\" otherwise.\nNote: with \"sign\" style it is better to have |'signcolumn'| always shown.\n\n`view.signs` is a table with one or two character strings used as signs for\ncorresponding (\"add\", \"change\", \"delete\") hunks.\nDefault: all hunks use \"▒\" character resulting in a contiguous colored lines.\n\n`view.priority` is a number with priority used for visualization and\noverlay |extmarks|.\nDefault: 199 which is one less than `user` in |vim.hl.priorities| (on Neovim<0.11\nsee |vim.hl.priorities|) to have higher priority than automated\nextmarks but not as in user enabled ones.\n\n# Source ~\n*MiniDiff-source-specification*\n\n`config.source` is a table with single source or array of them. Single source\ndefines how reference text is managed in a particular buffer. Sources in array\nare attempted to attach in order; call |MiniDiff.disable()| if none attaches.\n\nA single source table can have the following fields:\n\n- <attach> `(function)` - callable which defines how and when reference text\n  is updated inside a particular buffer. It is used inside |MiniDiff.enable()|\n  with a buffer identifier as a single argument.\n\n  Should execute logic which results into calling |MiniDiff.set_ref_text()|\n  when reference text for buffer needs to be updated. Like inside callback\n  for an |autocommand| or file watcher (see |watch-file|).\n\n  For example, default Git source watches when \".git/index\" file is changed\n  and computes reference text as the one from Git index for current file.\n\n  Can return `false` to indicate that attach has failed. If attach fail can\n  not be inferred immediately (for example, due to asynchronous execution),\n  should explicitly call |MiniDiff.fail_attach()| with appropriate arguments.\n  This is important to properly process array of sources.\n\n  No default value, should be always supplied.\n\n- <name> `(string|nil)` - source name. String `\"unknown\"` is used if not supplied.\n\n- <detach> `(function|nil)` - callable with cleanup action to be done when\n  buffer is disabled. It is called inside |MiniDiff.disable()| with a buffer\n  identifier as a single argument.\n\n  If not supplied, nothing is done during detaching.\n\n- <apply_hunks> `(function|nil)` - callable which defines how hunks are applied.\n  It is called with buffer identifier as first argument and array of hunks\n  (see |MiniDiff-hunk-specification|) as second. It should eventually update\n  reference text: either by explicitly calling |MiniDiff.set_ref_text()| or\n  performing action triggering its call.\n\n  For example, default Git source computes patch based on the hunks and\n  applies it inside file's git repo.\n\n  If not supplied, applying hunks throws an error.\n\nDefault: a single |MiniDiff.gen_source.git()|.\n\n# Delay ~\n\n`config.delay` contains settings for delays in asynchronous processes.\n\n`delay.text_change` is a number (in ms) defining how long to wait after latest\ntext change (in debounced fashion) before updating diff and visualization.\nDefault: 200.\n\n# Mappings ~\n\n`config.mappings` contains keys which are mapped during |MiniDiff.setup()|.\n\n`mappings.apply` keys can be used to apply hunks inside visual/operator region.\nWhat exactly \"apply hunks\" means depends on the source and its `apply_hunks()`.\nFor example, in default Git source it means stage hunks.\n\n`mappings.reset` keys can be used to reset hunks inside visual/operator region.\nReset means replacing buffer text in region with corresponding reference text.\n\n`mappings.textobject` keys define \"hunk range under cursor\" textobject\nwhich can be used in Operator-pending mode as target for operator (like\n|d|, |y|, apply/reset hunks, etc.). It is also set up in Visual mode if\nkeys do not conflict with `mappings.apply` and `mappings.reset`.\n\"Hunk range\" is used in a sense that contiguous (back-to-back) hunks are\nconsidered as parts of a same hunk range.\n\n`mappings.goto_first` / `mappings.goto_prev` / `mappings.goto_next` /\n`mappings.goto_last` keys can be used to navigate to first / previous / next /\nlast hunk range in the current buffer.\n\n# Options ~\n\n`config.options` contains various customization options.\n\n`options.algorithm` is a string defining which diff algorithm to use.\nDefault: \"histogram\". See |vim.diff()| for possible values.\n\n`options.indent_heuristic` is a boolean defining whether to use indent\nheuristic for a (possibly) more naturally aligned hunks.\nDefault: `true`.\n\n`options.linematch` is a number defining hunk size for which a second\nstage diff is executed for a better aligned and more granular hunks.\nDefault: 60. See |vim.diff()| and 'diffopt' for more details.\n\n`options.wrap_goto` is a boolean indicating whether to wrap around edges during\nhunk navigation (with |MiniDiff.goto_hunk()| or `goto_*` mappings). Like if\ncursor is after the last hunk, going \"next\" will put cursor on the first hunk.\nDefault: `false`.\n\n------------------------------------------------------------------------------\n                                                             *MiniDiff.enable()*\n                          `MiniDiff.enable`({buf_id})\nEnable diff processing in buffer\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                            *MiniDiff.disable()*\n                          `MiniDiff.disable`({buf_id})\nDisable diff processing in buffer\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                             *MiniDiff.toggle()*\n                          `MiniDiff.toggle`({buf_id})\nToggle diff processing in buffer\n\nEnable if disabled, disable if enabled.\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                     *MiniDiff.toggle_overlay()*\n                      `MiniDiff.toggle_overlay`({buf_id})\nToggle overlay view in buffer\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                             *MiniDiff.export()*\n                      `MiniDiff.export`({format}, {opts})\nExport hunks\n\nGet and convert hunks from current/all buffers. Example of using it: >lua\n\n  -- Set quickfix list from all available hunks\n  vim.fn.setqflist(MiniDiff.export('qf'))\n<\nParameters ~\n{format} `(string)` Output format. Currently only `'qf'` value is supported.\n{opts} `(table|nil)` Options. Possible fields:\n  - <scope> `(string)` - scope defining from which buffers to use hunks.\n    One of \"all\" (all enabled buffers) or \"current\".\n\nReturn ~\n`(table)` Result of export. Depends on the `format`:\n  - If \"qf\", an array compatible with |setqflist()| and |setloclist()|.\n\n------------------------------------------------------------------------------\n                                                       *MiniDiff.get_buf_data()*\n                       `MiniDiff.get_buf_data`({buf_id})\nGet buffer data\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\nReturn ~\n`(table|nil)` Table with buffer diff data or `nil` if buffer is not enabled.\n  Table has the following fields:\n  - <config> `(table)` - config used for this particular buffer.\n  - <hunks> `(table)` - array of hunks. See |MiniDiff-hunk-specification|.\n  - <overlay> `(boolean)` - whether an overlay view is shown.\n  - <ref_text> `(string|nil)` - current value of reference text. Lines are\n    separated with newline character (`'\\n'`). Can be `nil` indicating that\n    reference text was not yet set (for example, if source did not yet react).\n  - <summary> `(table)` - overall diff summary. See |MiniDiff-diff-summary|.\n\n------------------------------------------------------------------------------\n                                                       *MiniDiff.set_ref_text()*\n                   `MiniDiff.set_ref_text`({buf_id}, {text})\nSet reference text for the buffer\n\nNote: this will call |MiniDiff.enable()| for target buffer if it is not\nalready enabled.\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n{text} `(string|table)` New reference text. Either a string with `\\n` used to\n  separate lines or array of lines. Use empty table to unset current\n  reference text (results into no hunks shown). Default: `{}`.\n  Note: newline character is appended at the end (if it is not there already)\n  for better diffs.\n\n------------------------------------------------------------------------------\n                                                           *MiniDiff.gen_source*\n                             `MiniDiff.gen_source`\nGenerate builtin sources\n\nThis is a table with function elements. Call to actually get source.\nExamples: >lua\n\n  local diff = require('mini.diff')\n\n  -- Single `save` source\n  diff.setup({ source = diff.gen_source.save() })\n\n  -- Multiple sources (attempted to attach in order)\n  diff.setup({ source = { diff.gen_source.git(), diff.gen_source.save() } })\n<\n------------------------------------------------------------------------------\n                                                     *MiniDiff.gen_source.git()*\n                          `MiniDiff.gen_source.git`()\nGit source\n\nDefault source. Uses file text from Git index as reference. This results in:\n- \"Add\" hunks represent text present in current buffer, but not in index.\n- \"Change\" hunks represent modified text already present in index.\n- \"Delete\" hunks represent text deleted from index.\n\nApplying hunks means staging, a.k.a adding to index.\nNotes:\n- Requires Git version at least 2.38.0.\n- There is no capability for unstaging hunks. Use full Git client for that.\n\nReturn ~\n`(table)` Source. See |MiniDiff-source-specification|.\n\n------------------------------------------------------------------------------\n                                                    *MiniDiff.gen_source.none()*\n                          `MiniDiff.gen_source.none`()\n\"Do nothing\" source\n\nAllows buffers to be enabled while not setting any reference text.\nUse this if the goal is to rely on manual |MiniDiff.set_ref_text()| calls.\n\nReturn ~\n`(table)` Source. See |MiniDiff-source-specification|.\n\n------------------------------------------------------------------------------\n                                                    *MiniDiff.gen_source.save()*\n                          `MiniDiff.gen_source.save`()\nLatest save source\n\nUses text at latest save as the reference. This results into diff showing\ndifference after the latest save.\n\nReturn ~\n`(table)` Source. See |MiniDiff-source-specification|.\n\n------------------------------------------------------------------------------\n                                                           *MiniDiff.do_hunks()*\n                `MiniDiff.do_hunks`({buf_id}, {action}, {opts})\nPerform action on hunks in region\n\nCompute hunks inside a target region (even for hunks only partially inside it)\nand perform apply/reset/yank operation on them.\n\nThe \"yank\" action yanks all reference lines of target hunks into\na specified register (should be one of |registers|).\n\nNotes:\n- Whether hunk is inside a region is computed based on position of its\n  buffer lines.\n- If \"change\" or \"delete\" is only partially inside a target region, all\n  reference lines are used in computed \"intersection\" hunk.\n\nUsed directly in `config.mappings.apply` and `config.mappings.reset`.\nUsually there is no need to use this function manually.\nSee |MiniDiff.operator()| for how to set up a mapping for \"yank\".\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n{action} `(string)` One of \"apply\", \"reset\", \"yank\".\n{opts} `(table|nil)` Options. Possible fields:\n  - <line_start> `(number)` - start line of the region. Default: 1.\n  - <line_end> `(number)` - start line of the region. Default: last buffer line.\n  - <register> `(string)` - register to yank reference lines into.\n    Default: |v:register|.\n\n------------------------------------------------------------------------------\n                                                          *MiniDiff.goto_hunk()*\n                   `MiniDiff.goto_hunk`({direction}, {opts})\nGo to hunk range in current buffer\n\nParameters ~\n{direction} `(string)` One of \"first\", \"prev\", \"next\", \"last\".\n{opts} `(table|nil)` Options. A table with fields:\n  - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n  - <line_start> `(number)` - Line number to start from for directions\n    \"prev\" and \"next\". Default: cursor line.\n  - <wrap> `(boolean)` - Whether to wrap around edges.\n    Default: `options.wrap` value of the config.\n\n------------------------------------------------------------------------------\n                                                           *MiniDiff.operator()*\n                          `MiniDiff.operator`({mode})\nPerform action over region\n\nPerform action over region defined by marks. Used in mappings.\n\nExample of a mapping to yank reference lines of hunk range under cursor\n(assuming default 'config.mappings.textobject'): >lua\n\n  local rhs = function() return MiniDiff.operator('yank') .. 'gh' end\n  vim.keymap.set('n', 'ghy', rhs, { expr = true, remap = true })\n<\nParameters ~\n{mode} `(string)` One of \"apply\", \"reset\", \"yank\", or the ones used in |g@|.\n\n------------------------------------------------------------------------------\n                                                         *MiniDiff.textobject()*\n                            `MiniDiff.textobject`()\nSelect hunk range textobject\n\nSelects all contiguous lines adjacent to cursor line which are in any (not\nnecessarily same) hunk (if cursor line itself is in hunk).\nUsed in default mappings.\n\n------------------------------------------------------------------------------\n                                                        *MiniDiff.fail_attach()*\n                        `MiniDiff.fail_attach`({buf_id})\nIndicate source attach fail\n\nTry to attach next source; if there is none - call |MiniDiff.disable()|.\n\nParameters ~\n{buf_id} `(integer)` Buffer identifier for which attach has failed.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-doc.txt",
    "content": "*mini.doc* Generate Neovim help files\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                       *MiniDoc*\nKey design ideas:\n- Keep documentation next to code by writing EmmyLua-like annotation\n  comments. They will be parsed as is, so formatting should follow built-in\n  guide in |help-writing|. However, custom hooks are allowed at many\n  generation stages for more granular management of output help file.\n\n- Generation is done by processing a set of ordered files line by line.\n  Each line can either be considered as a part of documentation block (if\n  it matches certain configurable pattern) or not (considered to be an\n  \"afterline\" of documentation block). See |MiniDoc.generate()| for more\n  details.\n\n- Processing is done by using nested data structures (section, block, file,\n  doc) describing certain parts of help file. See |MiniDoc-data-structures|\n  for more details.\n\n- Project specific script can be written as plain Lua file with\n  configuratble path. See |MiniDoc.generate()| for more details.\n\nWhat it doesn't do:\n- It doesn't support markdown or other markup language inside annotations.\n- It doesn't use treesitter in favor of Lua string manipulation for basic\n  tasks (parsing annotations, formatting, auto-generating tags, etc.). This\n  is done to manage complexity and be dependency free.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.doc').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniDoc`\nwhich you can use for scripting or manually (with `:lua MiniDoc.*`).\n\nSee |MiniDoc.config| for available config settings.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minidoc_config` which should have same structure as `MiniDoc.config`.\nSee |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Tips ~\n\n- Some settings tips that might make writing annotation comments easier:\n    - Set up appropriate 'comments' for `lua` file type to respect\n      EmmyLua-like's `---` comment leader. Value `:---,:--` seems to work.\n    - Set up appropriate 'formatoptions' (see also |fo-table|). Consider\n      adding `j`, `n`, `q`, and `r` flags.\n    - Set up appropriate 'formatlistpat' to help auto-formatting lists (if\n      `n` flag is added to 'formatoptions'). One suggestion (not entirely\n      ideal) is a value `^\\s*[0-9\\-\\+\\*]\\+[\\.\\)]*\\s\\+`. This reads as 'at\n      least one special character (digit, `-`, `+`, `*`) possibly followed\n      by some punctuation (`.` or `)`) followed by at least one space is a\n      start of list item'.\n- Probably one of the most reliable resources for what is considered to be\n  best practice when using this module is this whole plugin. Look at source\n  code for the reference.\n\n# Comparisons ~\n\n- [tjdevries/tree-sitter-lua](https://github.com/tjdevries/tree-sitter-lua):\n    - Its key design is to use treesitter grammar to parse both Lua code\n      and annotation comments. This makes it not easy to install,\n      customize, and support.\n    - It takes more care about automating output formatting (like auto\n      indentation and line width fit). This plugin leans more to manual\n      formatting with option to supply customized post-processing hooks.\n\n------------------------------------------------------------------------------\n                                                       *MiniDoc-data-structures*\nData structures\n\nData structures are basically arrays of other structures accompanied with\nsome fields (keys with data values) and methods (keys with function\nvalues):\n- `Section structure` is an array of string lines describing one aspect\n  (determined by section id like '@param', '@return', '@text') of an\n  annotation subject. All lines will be used directly in help file.\n- `Block structure` is an array of sections describing one annotation\n  subject like function, table, concept.\n- `File structure` is an array of blocks describing certain file on disk.\n  Basically, file is split into consecutive blocks: annotation lines go\n  inside block, non-annotation - inside `block_afterlines` element of info.\n- `Doc structure` is an array of files describing a final help file. Each\n  string line from section (when traversed in depth-first fashion) goes\n  directly into output file.\n\nAll structures have these keys:\n- Fields:\n    - `info` - contains additional information about current structure.\n      For more details see next section.\n    - `parent` - table of parent structure (if exists).\n    - `parent_index` - index of this structure in its parent's array. Useful\n      for adding to parent another structure near current one.\n    - `type` - string with structure type (section, block, file, doc).\n- Methods (use them as `x:method(args)`):\n    - `insert(self, [index,] child)` - insert `child` to `self` at position\n      `index` (optional; if not supplied, child will be appended to end).\n      Basically, a `table.insert()`, but adds `parent` and `parent_index`\n      fields to `child` while properly updating `self`.\n    - `remove(self [,index])` - remove from `self` element at position\n      `index`. Basically, a `table.remove()`, but properly updates `self`.\n    - `has_descendant(self, predicate)` - whether there is a descendant\n      (structure or string) for which `predicate` returns `true`. In case of\n      success also returns the first such descendant as second value.\n    - `has_lines(self)` - whether structure has any lines (even empty ones)\n      to be put in output file. For section structures this is equivalent to\n      `#self`, but more useful for higher order structures.\n    - `clear_lines(self)` - remove all lines from structure. As a result,\n      this structure won't contribute to output help file.\n\nDescription of `info` fields per structure type:\n- `Section`:\n    - `id` - captured section identifier. Can be empty string meaning no\n      identifier is captured.\n    - `line_begin` - line number inside file at which section begins (-1 if\n      not generated from file).\n    - `line_end` - line number inside file at which section ends (-1 if not\n      generated from file).\n- `Block`:\n    - `afterlines` - array of strings which were parsed from file after\n      this annotation block (up until the next block or end of file).\n      Useful for making automated decisions about what is being documented.\n    - `line_begin` - line number inside file at which block begins  (-1 if\n      not generated from file).\n    - `line_end` - line number inside file at which block ends  (-1 if not\n      generated from file).\n- `File`:\n    - `path` - absolute path to a file (`''` if not generated from file).\n- `Doc`:\n    - `input` - array of input file paths (as in |MiniDoc.generate()|).\n    - `output` - output path (as in |MiniDoc.generate()|).\n    - `config` - configuration used (as in |MiniDoc.generate()|).\n\n------------------------------------------------------------------------------\n                                                               *MiniDoc.setup()*\n                           `MiniDoc.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniDoc.config|.\n\nUsage ~\n>lua\n  require('mini.doc').setup() -- use default config\n  -- OR\n  require('mini.doc').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                                *MiniDoc.config*\n                                `MiniDoc.config`\nDefaults ~\n>lua\n  MiniDoc.config = {\n    -- Function which extracts part of line used to denote annotation.\n    -- For more information see 'Notes' in |MiniDoc.config|.\n    annotation_extractor = function(l) return string.find(l, '^%-%-%-(%S*) ?') end,\n\n    -- Identifier of block annotation lines until first captured identifier\n    default_section_id = '@text',\n\n    -- Hooks to be applied at certain stage of document life cycle. Should\n    -- modify its input in place (and not return new one).\n    hooks = {\n      -- Applied to block before anything else\n      block_pre = --<function: infers header sections (tag and/or signature)>,\n\n      -- Applied to section before anything else\n      section_pre = --<function: replaces current aliases>,\n\n      -- Applied if section has specified captured id\n      sections = {\n        ['@alias'] = --<function: registers alias in MiniDoc.current.aliases>,\n        ['@class'] = --<function>,\n        ['@diagnostic'] = --<function: ignores any section content>,\n        -- For most typical usage see |MiniDoc.afterlines_to_code|\n        ['@eval'] = --<function: evaluates lines; replaces with their return>,\n        ['@field'] = --<function>,\n        ['@overload'] = --<function>,\n        ['@param'] = --<function>,\n        ['@private'] = --<function: registers block for removal>,\n        ['@return'] = --<function>,\n        ['@seealso'] = --<function>,\n        ['@signature'] = --<function: formats signature of documented object>,\n        ['@tag'] = --<function: turns its line in proper tag lines>,\n        ['@text'] = --<function: purposefully does nothing>,\n        ['@toc'] = --<function: clears all section lines>,\n        ['@toc_entry'] = --<function: registers lines for table of contents>,\n        ['@type'] = --<function>,\n        ['@usage'] = --<function>,\n      },\n\n      -- Applied to section after all previous steps\n      section_post = --<function: currently does nothing>,\n\n      -- Applied to block after all previous steps\n      block_post = --<function: does many things>,\n\n      -- Applied to file after all previous steps\n      file = --<function: adds separator>,\n\n      -- Applied to doc after all previous steps\n      doc = --<function: adds modeline>,\n\n      -- Applied before output file is written. Takes lines array as argument.\n      write_pre = --<function: removes delimiters at the top>,\n\n      -- Applied after output help file is written. Takes doc as argument.\n      write_post = --<function: various convenience actions>,\n    },\n\n    -- Path (relative to current directory) to script which handles project\n    -- specific help file generation (like custom input files, hooks, etc.).\n    script_path = 'scripts/minidoc.lua',\n\n    -- Whether to disable showing non-error feedback\n    silent = false,\n  }\n<\n# Notes ~\n\n- `annotation_extractor` takes single string line as input. Output\n  describes what makes an input to be an annotation (if anything). It\n  should be similar to `string.find` with one capture group: start and end\n  of annotation indicator (whole part will be removed from help line) with\n  third value being string of section id (if input describes first line of\n  section; `nil` or empty string otherwise). Output should be `nil` if line\n  is not part of annotation.\n  Default value means that annotation line should:\n    - Start with `---` at first column.\n    - Any non-whitespace after `---` will be treated as new section id.\n    - Single whitespace at the start of main text will be ignored.\n- Hooks are expected to be functions. Their default values might do many\n  things which might change over time, so for more information please look\n  at source code. Some more information can be found in\n  |MiniDoc.default_hooks|.\n\n------------------------------------------------------------------------------\n                                                               *MiniDoc.current*\n                               `MiniDoc.current`\nTable with information about current state of auto-generation\n\nIt is reset at the beginning and end of `MiniDoc.generate()`.\n\nAt least these keys are supported:\n- {aliases} - table with keys being alias name and values - alias\n  description and single string (using `\\n` to separate lines).\n- {eval_section} - input section of `@eval` section hook. Can be used for\n  information about current block, etc.\n- {toc} - array with table of contents entries. Each entry is a whole\n  `@toc_entry` section.\n\n------------------------------------------------------------------------------\n                                                         *MiniDoc.default_hooks*\n                            `MiniDoc.default_hooks`\nDefault hooks\n\nThis is default value of `MiniDoc.config.hooks`. Use it if only a little\ntweak is needed.\n\nSome more insight about their behavior:\n- Default inference of documented object metadata (tag and object signature\n  at the moment) is done in `block_pre`. Inference is based on string\n  pattern matching, so can lead to false results, although works in most\n  cases. It intentionally works only if first line after block has no\n  indentation and contains all necessary information to determine if\n  inference should happen.\n- Hooks for sections describing some \"variable-like\" object ('@class',\n  '@field', '@param') automatically enclose first word in '{}'.\n- Hooks for sections which supposed to have \"type-like\" data ('@field',\n  '@param', '@return', '@type') automatically enclose *first found*\n  \"type-like\" word and its neighbor characters in '`(<type>)`' (expect\n  false positives). Algorithm is far from being 100% correct, but seems to\n  work with present allowed type annotation. For allowed types see\n  https://github.com/sumneko/lua-language-server/wiki/EmmyLua-Annotations#types-and-type\n  or, better yet, look in source code of this module.\n- Automated creation of table of contents (TOC) is done in the following way:\n    - Put section with `@toc_entry` id in the annotation block. Section's\n      lines will be registered as TOC entry.\n    - Put `@toc` section where you want to insert rendered table of\n      contents. TOC entries will be inserted on the left, references for\n      their respective tag section (only first, if present) on the right.\n      Render is done in default `doc` hook (because it should be done after\n      processing all files).\n- The `write_post` hook executes some actions convenient for iterative\n  annotations writing:\n    - Generate `:helptags` for directory containing output file.\n    - Silently reload buffer containing output file (if such exists).\n    - Display notification message about result.\n\n------------------------------------------------------------------------------\n                                                            *MiniDoc.generate()*\n                `MiniDoc.generate`({input}, {output}, {config})\nGenerate help file\n\n# Algorithm ~\n\n- Main parameters for help generation are an array of input file paths and\n  path to output help file.\n- Parse all inputs:\n  - For each file, lines are processed top to bottom in order to create an\n    array of documentation blocks. Each line is tested whether it is an\n    annotation by applying `MiniDoc.config.annotation_extractor`: if\n    anything is extracted, it is considered to be an annotation. Annotation\n    line goes to \"current block\" after removing extracted annotation\n    indicator, otherwise - to afterlines of \"current block\".\n  - Each block's annotation lines are processed top to bottom. If line had\n    captured section id, it is a first line of \"current section\" (first\n    block lines are allowed to not specify section id; by default it is\n    `@text`). All subsequent lines without captured section id go into\n    \"current section\".\n- Apply structure hooks (they should modify its input in place, which is\n  possible due to 'table nature' of all inputs):\n    - Each block is processed by `MiniDoc.config.hooks.block_pre`. This is a\n      designated step for auto-generation of sections from described\n      annotation subject (like sections with id `@tag`, `@type`).\n    - Each section is processed by `MiniDoc.config.hooks.section_pre`.\n    - Each section is processed by corresponding\n      `MiniDoc.config.hooks.sections` function (table key equals to section\n      id). This is a step where most of formatting should happen (like\n      wrap first word of `@param` section with `{` and `}`, append empty\n      line to section, etc.).\n    - Each section is processed by `MiniDoc.config.hooks.section_post`.\n    - Each block is processed by `MiniDoc.config.hooks.block_post`. This is\n      a step for processing block after formatting is done (like add first\n      line with `----` delimiter).\n    - Each file is processed by `MiniDoc.config.hooks.file`. This is a step\n      for adding any file-related data (like add first line with `====`\n      delimiter).\n    - Doc is processed by `MiniDoc.config.hooks.doc`. This is a step for\n      adding any helpfile-related data (maybe like table of contents).\n- Collect all strings from sections in depth-first fashion (equivalent to\n  nested \"for all files -> for all blocks -> for all sections -> for all\n  strings -> add string to output\"). Strings can have `\\n` character\n  indicating start of new line.\n- Modify collected strings with `MiniDoc.config.write_pre`. Takes strings\n  from previous step as input and should return array of strings.\n- Write modified strings to output file.\n- Execute `MiniDoc.config.write_post` hook. This is useful for showing some\n  feedback and making actions involving newly updated help file (like\n  generate tags, etc.).\n\n# Project specific script ~\n\nIf all arguments have default `nil` values, first there is an attempt to\nsource project specific script. This is basically a\n`luafile <MiniDoc.config.script_path>` with current Lua runtime while caching\nand restoring current `MiniDoc.config`. Its successful execution stops any\nfurther generation actions while error means proceeding generation as if no\nscript was found.\n\nTypical script content might include definition of custom hooks, input and\noutput files with eventual call to `require('mini.doc').generate()` (with\nor without arguments).\n\nParameters ~\n{input} `(table|nil)` Array of file paths which will be processed in supplied\n  order. Default: all '.lua' files from current directory following by all\n  such files in these subdirectories: 'lua/', 'after/', 'colors/'. Note:\n  any 'init.lua' file is placed before other files from the same directory.\n{output} `(string|nil)` Path for output help file. Default:\n  `doc/<current_directory>.txt` (designed to be used for generating help\n  file for plugin).\n{config} `(table|nil)` Configuration overriding parts of |MiniDoc.config|.\n\nReturn ~\n`(table)` Document structure which was generated and used for output\n  help file. In case `MiniDoc.config.script_path` was successfully used,\n  this is a return from the latest call of this function.\n\n------------------------------------------------------------------------------\n                                                  *MiniDoc.afterlines_to_code()*\n                     `MiniDoc.afterlines_to_code`({struct})\nConvert afterlines to code\n\nThis function is designed to be used together with `@eval` section to\nautomate documentation of certain values (notably default values of a\ntable). It processes afterlines based on certain directives and makes\noutput look like a Lua code block.\n\nMost common usage is by adding the following section in your annotation: >\n\n  ---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n<\n# Directives ~\n\nDirectives are special comments that are processed using Lua string pattern\ncapabilities (so beware of false positives). Each directive should be put\non its separate line. Supported directives:\n- `--minidoc_afterlines_end` denotes a line at afterlines end. Only all\n  lines before it will be considered as afterlines. Useful if there is\n  extra code in afterlines which shouldn't be used.\n- `--minidoc_replace_start <replacement>` and `--minidoc_replace_end`\n  denote lines between them which should be replaced with `<replacement>`.\n  Useful for manually changing what should be placed in output like in case\n  of replacing function body with something else.\n\nHere is an example. Suppose having these afterlines: >lua\n\n  --minidoc_replace_start {\n  M.config = {\n    --minidoc_replace_end\n    param_one = 1,\n    --minidoc_replace_start param_fun = --<function>\n    param_fun = function(x)\n      return x + 1\n    end\n    --minidoc_replace_end\n  }\n  --minidoc_afterlines_end\n\n  return M\n<\nAfter adding `@eval` section those will be formatted as: >\n\n  {\n    param_one = 1,\n    param_fun = --<function>\n  }\n<\nParameters ~\n{struct} `(table)` Block or section structure which after lines will be\n  converted to code.\n\nReturn ~\n`(string|nil)` Single string (using `\\n` to separate lines) describing\n  afterlines as Lua code block in help file. If `nil`, input is not valid.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-extra.txt",
    "content": "*mini.extra* Extra 'mini.nvim' functionality\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                     *MiniExtra*\nExtra useful functionality which is not essential enough for other 'mini.nvim'\nmodules to include directly.\n\nFeatures:\n\n- Various pickers for |mini.pick|:\n    - Built-in diagnostic (|MiniExtra.pickers.diagnostic()|).\n    - File explorer (|MiniExtra.pickers.explorer()|).\n    - Git branches/commits/files/hunks (|MiniExtra.pickers.git_hunks()|, etc.).\n    - Command/search/input history (|MiniExtra.pickers.history()|).\n    - LSP references/symbols/etc. (|MiniExtra.pickers.lsp()|).\n    - Tree-sitter nodes (|MiniExtra.pickers.treesitter()|).\n    - And much more.\n  See |MiniExtra.pickers| for more.\n\n- Various textobject specifications for |mini.ai|. See |MiniExtra.gen_ai_spec|.\n\n- Various highlighters for |mini.hipatterns|. See |MiniExtra.gen_highlighter|.\n\nNotes:\n- This module requires only those 'mini.nvim' modules which are needed for\n  a particular functionality: 'mini.pick' for pickers, etc.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.extra').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniExtra`\nwhich you can use for scripting or manually (with `:lua MiniExtra.*`).\n\nSee |MiniExtra.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.miniextra_config`\nwill have no effect here.\n\n# Comparisons ~\n\n- [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim):\n    - With |MiniExtra.pickers|, 'mini.pick' is reasonably on par when it comes\n      to built-in pickers.\n\n- [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua):\n    - Same as 'nvim-telescope/telescope.nvim'.\n\n------------------------------------------------------------------------------\n                                                             *MiniExtra.setup()*\n                          `MiniExtra.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniExtra.config|.\n\nUsage ~\n>lua\n  require('mini.extra').setup() -- use default config\n  -- OR\n  require('mini.extra').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                              *MiniExtra.config*\n                               `MiniExtra.config`\nDefaults ~\n>lua\n  MiniExtra.config = {}\n<\n------------------------------------------------------------------------------\n                                                         *MiniExtra.gen_ai_spec*\n                            `MiniExtra.gen_ai_spec`\n|mini.ai| textobject specification generators\n\nThis is a table with function elements. Call to actually get specification.\n\nAssumed to be used as part of |MiniAi.setup()|. Example: >lua\n\n  local gen_ai_spec = require('mini.extra').gen_ai_spec\n  require('mini.ai').setup({\n    custom_textobjects = {\n      B = gen_ai_spec.buffer(),\n      D = gen_ai_spec.diagnostic(),\n      I = gen_ai_spec.indent(),\n      L = gen_ai_spec.line(),\n      N = gen_ai_spec.number(),\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                                *MiniExtra.gen_ai_spec.buffer()*\n                        `MiniExtra.gen_ai_spec.buffer`()\nCurrent buffer textobject\n\nNotes:\n- `a` textobject selects all lines in a buffer.\n- `i` textobject selects all lines except blank lines at start and end.\n\nReturn ~\n`(function)` Function implementing |MiniAi-textobject-specification|.\n\n------------------------------------------------------------------------------\n                                            *MiniExtra.gen_ai_spec.diagnostic()*\n                 `MiniExtra.gen_ai_spec.diagnostic`({severity})\nCurrent buffer diagnostic textobject\n\nNotes:\n- Both `a` and `i` textobjects return |vim.diagnostic.get()| output for the\n  current buffer. It is modified to fit |MiniAi-textobject-specification|.\n\nParameters ~\n{severity} `(any)` Which severity to use. Forwarded to |vim.diagnostic.get()|.\n  Default: `nil` to use all diagnostic entries.\n\nReturn ~\n`(function)` Function implementing |MiniAi-textobject-specification|.\n\n------------------------------------------------------------------------------\n                                                *MiniExtra.gen_ai_spec.indent()*\n                        `MiniExtra.gen_ai_spec.indent`()\nCurrent buffer indent scopes textobject\n\nIndent scope is a set of consecutive lines with the following properties:\n- Lines above first and below last are non-blank. They are called borders.\n- There is at least one non-blank line in a set.\n- All non-blank lines between borders have strictly greater indent\n  (perceived leading space respecting |'tabstop'|) than either of borders.\n\nNotes:\n- `a` textobject selects scope including borders.\n- `i` textobject selects the scope charwise.\n- Differences with |MiniIndentscope.textobject()|:\n    - This textobject always treats blank lines on top and bottom of `i`\n      textobject as part of it, while 'mini.indentscope' can configure that.\n    - This textobject can select non-covering scopes, while 'mini.indentscope'\n      can not (by design).\n    - In this textobject scope computation is done only by \"casting rays\" from\n      top to bottom and not in both ways as in 'mini.indentscope'.\n      This works in most common scenarios and doesn't work only if indent of\n      of the bottom border is expected to be larger than the top.\n\nReturn ~\n`(function)` Function implementing |MiniAi-textobject-specification|.\n  It returns array of regions representing all indent scopes in the buffer\n  ordered increasingly by the start line.\n\n------------------------------------------------------------------------------\n                                                  *MiniExtra.gen_ai_spec.line()*\n                         `MiniExtra.gen_ai_spec.line`()\nCurrent line textobject\n\nNotes:\n- `a` textobject selects whole line.\n- `i` textobject selects line after initial indent.\n\nReturn ~\n`(function)` Function implementing |MiniAi-textobject-specification|.\n\n------------------------------------------------------------------------------\n                                                *MiniExtra.gen_ai_spec.number()*\n                        `MiniExtra.gen_ai_spec.number`()\nNumber textobject\n\nNotes:\n- `a` textobject selects a whole number possibly preceded with \"-\" and\n  possibly followed by decimal part (dot and digits).\n- `i` textobject selects consecutive digits.\n\nReturn ~\n`(function)` Function implementing |MiniAi-textobject-specification|.\n\n------------------------------------------------------------------------------\n                                                     *MiniExtra.gen_highlighter*\n                          `MiniExtra.gen_highlighter`\n|mini.hipatterns| highlighter generators\n\nThis is a table with function elements. Call to actually get specification.\n\nAssumed to be used as part of |MiniHipatterns.setup()|. Example: >lua\n\n  local hi_words = require('mini.extra').gen_highlighter.words\n  require('mini.hipatterns').setup({\n    highlighters = {\n      todo = hi_words({ 'TODO', 'Todo', 'todo' }, 'MiniHipatternsTodo'),\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                             *MiniExtra.gen_highlighter.words()*\n      `MiniExtra.gen_highlighter.words`({words}, {group}, {extmark_opts})\nHighlight words\n\nNotes:\n- Words should start and end with alphanumeric symbol (latin letter or digit).\n- Words will be highlighted only in full and not if part bigger word, i.e.\n  there should not be alphanumeric symbol before and after it.\n\nParameters ~\n{words} `(table)` Array of words to highlight. Will be matched as is, not\n  as Lua pattern.\n{group} `(string|function)` Proper `group` field for `highlighter`.\n  See |MiniHipatterns.config|.\n{extmark_opts} `(any)` Proper `extmark_opts` field for `highlighter`.\n  See |MiniHipatterns.config|.\n\n------------------------------------------------------------------------------\n                                                             *MiniExtra.pickers*\n                              `MiniExtra.pickers`\n|mini.pick| pickers\n\nA table with 'mini.pick' pickers (which is a hard dependency).\nNotes:\n- All have the same signature:\n    - <local_opts> - optional table with options local to picker.\n    - <opts> - optional table with options forwarded to |MiniPick.start()|.\n- All of them are automatically registered in |MiniPick.registry| inside\n  both |MiniExtra.setup()| or |MiniPick.setup()| (only one is enough).\n- All use default versions of |MiniPick-source.preview|, |MiniPick-source.choose|,\n  and |MiniPick-source.choose_marked| if not stated otherwise.\n  Shown text and |MiniPick-source.show| are targeted to the picked items.\n\nExamples of usage:\n- As Lua code: `MiniExtra.pickers.buf_lines()`.\n- With |:Pick| command: `:Pick buf_lines scope='current'`\n  Note: this requires calling |MiniExtra.setup()|.\n\n------------------------------------------------------------------------------\n                                                 *MiniExtra.pickers.buf_lines()*\n              `MiniExtra.pickers.buf_lines`({local_opts}, {opts})\nBuffer lines picker\n\nPick from buffer lines. Notes:\n- Loads all target buffers which are currently unloaded.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - one of \"all\" (normal listed buffers) or \"current\".\n    Default: \"all\".\n  - <preserve_order> `(boolean)` - whether to preserve original order\n    during query. Default: `false`.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                              *MiniExtra.pickers.colorschemes()*\n             `MiniExtra.pickers.colorschemes`({local_opts}, {opts})\nColor scheme picker\n\nPick and apply color scheme. Preview temporarily applies item's color scheme\nand shows how selected highlight groups look.\nCanceling reverts to color scheme before picker start:\n- With |MiniColors-colorscheme:apply()| if |mini.colors| was available.\n- With |:colorscheme| if |g:colors_name| was available.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <names> `(table)` - array of color scheme names to pick from.\n    Default: all available color schemes.\n  - <preview_hl_groups> `(table)` - array of highlight groups to show in preview\n    window. Default: all defined highlight groups in alphabetical order.\n\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                  *MiniExtra.pickers.commands()*\n               `MiniExtra.pickers.commands`({local_opts}, {opts})\nNeovim commands picker\n\nPick from Neovim built-in (|Ex-commands|) and |user-commands|.\nNotes:\n- Preview shows information about the command (if available).\n- Choosing either executes command (if reliably known that it doesn't need\n  arguments) or populates Command line with the command.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Not used at the moment.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                *MiniExtra.pickers.diagnostic()*\n              `MiniExtra.pickers.diagnostic`({local_opts}, {opts})\nBuilt-in diagnostic picker\n\nPick from |vim.diagnostic| using |vim.diagnostic.get()|.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <get_opts> `(table)` - options for |vim.diagnostic.get()|. Can be used\n    to limit severity or namespace. Default: `{}`.\n  - <scope> `(string)` - one of \"all\" (available) or \"current\" (buffer).\n    Default: \"all\".\n  - <sort_by> `(string)` - sort priority. One of \"severity\", \"path\", \"none\".\n    Default: \"severity\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                  *MiniExtra.pickers.explorer()*\n               `MiniExtra.pickers.explorer`({local_opts}, {opts})\nFile explorer picker\n\nExplore file system and open file.\nNotes:\n- Choosing a directory navigates inside it, changing picker's items and\n  current working directory.\n- Query and preview work as usual (not only `move_next`/`move_prev` can be used).\n- Preview works for any item.\n\nExamples:\n\n- `MiniExtra.pickers.explorer()`\n- `:Pick explorer cwd='..'` - open explorer in parent directory.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <cwd> `(string)` - initial directory to explore. Should be a valid\n    directory path. Default: `nil` for |current-directory|.\n  - <filter> `(function)` - callable predicate to filter items to show.\n    Will be called for every item and should return `true` if it should be\n    shown. Each item is a table with the following fields:\n      - <fs_type> `(string)` - path type. One of \"directory\" or \"file\".\n      - <path> `(string)` - item path.\n      - <text> `(string)` - shown text (path's basename).\n  - <sort> `(function)` - callable item sorter. Will be called with array\n    of items (each element with structure as described above) and should\n    return sorted array of items.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                              *MiniExtra.pickers.git_branches()*\n             `MiniExtra.pickers.git_branches`({local_opts}, {opts})\nGit branches picker\n\nPick from Git branches using `git branch`.\nNotes:\n- Requires executable `git`.\n- Requires target path to be part of git repository.\n- Present for exploration and navigation purposes. Doing any Git operations\n  is suggested to be done in a dedicated Git client and is not planned.\n- On choose opens scratch buffer with branch's history.\n\nExamples:\n\n- `MiniExtra.pickers.git_branches({ scope = 'local' })` - local branches of\n  the |current-directory| parent Git repository.\n- `:Pick git_branches path='%'` - all branches of the current file parent\n  Git repository.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <path> `(string|nil)` - target path for Git operation (if required). Also\n    used to find Git repository inside which to construct items.\n    Default: `nil` for root of Git repository containing |current-directory|.\n  - <scope> `(string)` - branch scope to show. One of \"all\", \"local\", \"remotes\".\n    Default: \"all\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                               *MiniExtra.pickers.git_commits()*\n             `MiniExtra.pickers.git_commits`({local_opts}, {opts})\nGit commits picker\n\nPick from Git commits using `git log`.\nNotes:\n- Requires executable `git`.\n- Requires target path to be part of git repository.\n- Present for exploration and navigation purposes. Doing any Git operations\n  is suggested to be done in a dedicated Git client and is not planned.\n- On choose opens scratch buffer with commit's diff.\n\nExamples:\n\n- `MiniExtra.pickers.git_commits()` - all commits from parent Git\n  repository of |current-directory|.\n- `MiniExtra.pickers.git_commits({ path = 'subdir' })` - commits affecting\n  files from 'subdir' subdirectory.\n- `:Pick git_commits path='%'` commits affecting current file.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <path> `(string|nil)` - target path for Git operation (if required). Also\n    used to find Git repository inside which to construct items.\n    Default: `nil` for root of Git repository containing |current-directory|.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                 *MiniExtra.pickers.git_files()*\n              `MiniExtra.pickers.git_files`({local_opts}, {opts})\nGit files picker\n\nPick from Git files using `git ls-files`.\nNotes:\n- Requires executable `git`.\n- Requires target path to be part of git repository.\n- Present for exploration and navigation purposes. Doing any Git operations\n  is suggested to be done in a dedicated Git client and is not planned.\n\nExamples:\n\n- `MiniExtra.pickers.git_files({ scope = 'ignored' })` - ignored files from\n  parent Git repository of |current-directory|.\n- `:Pick git_files path='subdir' scope='modified'` - files from 'subdir'\n  subdirectory which are ignored by Git.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <path> `(string|nil)` - target path for Git operation (if required). Also\n    used to find Git repository inside which to construct items.\n    Default: `nil` for root of Git repository containing |current-directory|.\n  - <scope> `(string)` - files scope to show. One of\n      - \"tracked\"   (`--cached`   Git flag).\n      - \"modified\"  (`--modified` Git flag).\n      - \"untracked\" (`--others`   Git flag).\n      - \"ignored\"   (`--ignored`  Git flag).\n      - \"deleted\"   (`--deleted`  Git flag).\n    Default: \"tracked\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                 *MiniExtra.pickers.git_hunks()*\n              `MiniExtra.pickers.git_hunks`({local_opts}, {opts})\nGit hunks picker\n\nPick from Git hunks using `git diff`.\nNotes:\n- Requires executable `git`.\n- Requires target path to be part of git repository.\n- Present for exploration and navigation purposes. Doing any Git operations\n  is suggested to be done in a dedicated Git client and is not planned.\n- On choose navigates to hunk's first change.\n\nExamples:\n\n- `MiniExtra.pickers.git_hunks({ scope = 'staged' })` - staged hunks from\n  parent Git repository of |current-directory|.\n- `:Pick git_hunks path='%' n_context=0` - hunks from current file computed\n  with no context.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <n_context> `(number)` - number of context lines to show in hunk's preview.\n    Default: 3.\n  - <path> `(string|nil)` - target path for Git operation (if required). Also\n    used to find Git repository inside which to construct items.\n    Default: `nil` for root of Git repository containing |current-directory|.\n  - <scope> `(string)` - hunks scope to show. One of \"unstaged\" or \"staged\".\n    Default: \"unstaged\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                *MiniExtra.pickers.hipatterns()*\n              `MiniExtra.pickers.hipatterns`({local_opts}, {opts})\nMatches from 'mini.hipatterns' picker\n\nPick from |mini.hipatterns| matches using |MiniHipatterns.get_matches()|.\nNotes:\n- Requires 'mini.hipatterns'.\n- Highlighter identifier is highlighted with its highlight group.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - one of \"all\" (buffers with enabled 'mini.hipatterns')\n    or \"current\" (buffer). Default: \"all\".\n  - <highlighters> `(table|nil)` - highlighters for which to find matches.\n    Forwarded to |MiniHipatterns.get_matches()|. Default: `nil`.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                   *MiniExtra.pickers.history()*\n               `MiniExtra.pickers.history`({local_opts}, {opts})\nNeovim history picker\n\nPick from output of |:history|. Use `<C-e>` to edit current match in\nCommand line.\n\nNotes:\n- Has no preview.\n- Choosing action depends on scope:\n    - For \"cmd\" / \":\" scopes, the command is executed.\n    - For \"search\" / \"/\" / \"?\" scopes, search is redone.\n    - For other scopes nothing is done (but chosen item is still returned).\n- `<C-e>` only works for \"cmd\" / \":\" / \"search\" / \"/\" / \"?\" scopes.\n\nExamples:\n\n- Command history: `MiniExtra.pickers.history({ scope = ':' })`\n- Search history: `:Pick history scope='/'`\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - any allowed {name} flag of |:history| command.\n    Note: word abbreviations are not allowed. Default: \"all\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                 *MiniExtra.pickers.hl_groups()*\n              `MiniExtra.pickers.hl_groups`({local_opts}, {opts})\nHighlight groups picker\n\nPick and preview highlight groups.\nNotes:\n- Item line is colored with same highlight group it represents.\n- Preview shows highlight's definition (as in |:highlight| with {group-name}).\n- Choosing places highlight definition in Command line to update and apply.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Not used at the moment.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                   *MiniExtra.pickers.keymaps()*\n               `MiniExtra.pickers.keymaps`({local_opts}, {opts})\nNeovim keymaps picker\n\nPick and preview data about Neovim keymaps.\nNotes:\n- Item line contains data about keymap mode, whether it is buffer local, its\n  left hand side, and inferred description.\n- Preview shows keymap data or callback source (if present and reachable).\n- Choosing emulates pressing the left hand side of the keymap.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <mode> `(string)` - modes to show. One of \"all\" or appropriate mode\n    for |nvim_set_keymap()|. Default: \"all\".\n  - <scope> `(string)` - scope to show. One of \"all\", \"global\", \"buf\".\n    Default: \"all\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                      *MiniExtra.pickers.list()*\n                 `MiniExtra.pickers.list`({local_opts}, {opts})\nNeovim lists picker\n\nPick and navigate to elements of the following Neovim lists:\n- |quickfix| list.\n- |location-list| of current window.\n- |jumplist|.\n- |changelist|.\n\nNote: it requires explicit `scope`.\n\nExamples:\n\n- `MiniExtra.pickers.list({ scope = 'quickfix' })` - quickfix list.\n- `:Pick list scope='jump'` - jump list.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - type of list to show. One of \"quickfix\", \"location\",\n    \"jump\", \"change\". Default: `nil` which means explicit scope is needed.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                       *MiniExtra.pickers.lsp()*\n                 `MiniExtra.pickers.lsp`({local_opts}, {opts})\nLSP picker\n\nPick and navigate with LSP methods.\nNotes:\n- Needs an explicit scope from a list of supported ones:\n    - \"declaration\".\n    - \"definition\".\n    - \"document_symbol\".\n    - \"implementation\".\n    - \"references\".\n    - \"type_definition\".\n    - \"workspace_symbol\".\n    - \"workspace_symbol_live\" - same as \"workspace_symbol\", but with live\n      feedback treating picker's prompt as LSP server query. Similar to\n      how |MiniPick.builtin.grep_live()| and |MiniPick.builtin.grep()| are\n      related. To use regular matching, activate |MiniPick-actions-refine|.\n- Relies on `vim.lsp.buf` methods supporting |vim.lsp.LocationOpts.OnList|.\n  In particular, it means that picker is started only if LSP server returns\n  list of locations and not a single location.\n- Doesn't return anything due to async nature of `vim.lsp.buf` methods.\n- Requires set up |mini.icons| to show extra icons and highlighting in\n  \"document_symbol\", \"workspace_symbol\", \"workspace_symbol_live\" scopes.\n\nExamples:\n\n- `MiniExtra.pickers.lsp({ scope = 'references' })` - references of the symbol\n  under cursor.\n- `:Pick lsp scope='document_symbol'` - symbols in current file.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - LSP method to use. One of the supported ones (see\n    list above). Default: `nil` which means explicit scope is needed.\n  - <symbol_query> `(string)` - query for `\"workspace_symbol\"` scope.\n    Default: empty string for all symbols (according to LSP specification).\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(nil)` Nothing is returned.\n\n------------------------------------------------------------------------------\n                                                  *MiniExtra.pickers.manpages()*\n               `MiniExtra.pickers.manpages`({local_opts}, {opts})\nManual pages\n\nPick manual page (like described in |ft-man-plugin|).\nNotes:\n- Depends on |:Man| command to preview and choose items.\n- Shows page in the target window. Use |MiniPick-actions-choose| to split.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Not used at the moment.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                     *MiniExtra.pickers.marks()*\n                `MiniExtra.pickers.marks`({local_opts}, {opts})\nNeovim marks picker\n\nPick and preview position of Neovim |mark|s.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - scope to show. One of \"all\", \"global\", \"buf\".\n    Default: \"all\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                  *MiniExtra.pickers.oldfiles()*\n               `MiniExtra.pickers.oldfiles`({local_opts}, {opts})\nOld files picker\n\nPick from |v:oldfiles| entries representing readable files.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <current_dir> `(boolean)` - whether to return files only from current\n    working directory and its subdirectories. Default: `false`.\n  - <preserve_order> `(boolean)` - whether to preserve original order\n    during query. Default: `false`.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                   *MiniExtra.pickers.options()*\n               `MiniExtra.pickers.options`({local_opts}, {opts})\nNeovim options picker\n\nPick and preview data about Neovim options.\nNotes:\n- Item line is colored based on whether it was set (dimmed if wasn't).\n- Preview shows option value in target window and its general information.\n- Choosing places option name in Command line to update and apply.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <scope> `(string)` - options to show. One of \"all\", \"global\", \"win\", \"buf\".\n    Default: \"all\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                 *MiniExtra.pickers.registers()*\n              `MiniExtra.pickers.registers`({local_opts}, {opts})\nNeovim registers picker\n\nPick from Neovim |registers|.\nNotes:\n- There is no preview (all information is in the item's text).\n- Choosing pastes content of a register: with |i_CTRL-R| in Insert mode,\n  |c_CTRL-R| in Command-line mode, and |P| otherwise.\n  Expression register |quote=| is reevaluated (if present) and pasted.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Not used at the moment.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                              *MiniExtra.pickers.spellsuggest()*\n             `MiniExtra.pickers.spellsuggest`({local_opts}, {opts})\nNeovim spell suggestions picker\n\nPick and apply spell suggestions.\nNotes:\n- No preview is available.\n- Choosing replaces current word (|<cword>|) with suggestion.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <n_suggestions> `(number)` - number of spell suggestions. Default: 25.\n\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                                *MiniExtra.pickers.treesitter()*\n              `MiniExtra.pickers.treesitter`({local_opts}, {opts})\nTree-sitter nodes picker\n\nPick and navigate to |treesitter| nodes of current buffer.\nNotes:\n- Requires active tree-sitter parser in the current buffer.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Not used at the moment.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                               *MiniExtra.pickers.visit_paths()*\n             `MiniExtra.pickers.visit_paths`({local_opts}, {opts})\nVisit paths from 'mini.visits' picker\n\nPick paths from |mini.visits| using |MiniVisits.list_paths()|.\nNotes:\n- Requires 'mini.visits'.\n\nExamples:\n\n- `MiniExtra.pickers.visit_paths()` - visits registered for |current-directory|\n  and ordered by \"robust frecency\".\n- `:Pick visit_paths cwd='' recency_weight=1 filter='core'` - all visits with\n  \"core\" label ordered from most to least recent.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <cwd> `(string)` - forwarded to |MiniVisits.list_paths()|.\n    Default: `nil` to get paths registered for |current-directory|.\n  - <filter> `(function|string)` - forwarded to |MiniVisits.list_paths()|.\n    Default: `nil` to use all paths.\n  - <preserve_order> `(boolean)` - whether to preserve original order\n    during query. Default: `false`.\n  - <recency_weight> `(number)` - forwarded to |MiniVisits.gen_sort.default()|.\n    Default: 0.5 to use \"robust frecency\" sorting.\n  - <sort> `(function)` - forwarded to |MiniVisits.list_paths()|.\n    Default: `nil` to use \"robust frecency\".\n    Note: if supplied, has precedence over `recency_weight`.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(any)` Output of the called picker.\n\n------------------------------------------------------------------------------\n                                              *MiniExtra.pickers.visit_labels()*\n             `MiniExtra.pickers.visit_labels`({local_opts}, {opts})\nVisit labels from 'mini.visits' picker\n\nPick labels from |mini.visits| using |MiniVisits.list_labels()|\nand |MiniVisits.list_paths()|.\nNotes:\n- Requires 'mini.visits'.\n- Preview shows target visit paths filtered to those having previewed label.\n- Choosing essentially starts |MiniExtra.pickers.visit_paths()| for paths\n  with the chosen label.\n\nExamples:\n\n- `MiniExtra.pickers.visit_labels()` - labels from visits registered\n  for |current-directory|.\n- `:Pick visit_labels cwd=''` - labels from all visits.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <cwd> `(string)` - forwarded to |MiniVisits.list_labels()|.\n    Default: `nil` to get labels from visits registered for |current-directory|.\n  - <filter> `(function|string)` - forwarded to |MiniVisits.list_labels()|.\n    Default: `nil` to use all visits.\n  - <path> `(string)` - forwarded to |MiniVisits.list_labels()|.\n    Default: `\"\"` to get labels from all visits for target `cwd`.\n  - <sort> `(function)` - forwarded to |MiniVisits.list_paths()| for\n    preview and choose. Default: `nil` to use \"robust frecency\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\nReturn ~\n`(...)` Chosen path.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-files.txt",
    "content": "*mini.files* Navigate and manipulate file system\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                     *MiniFiles*\nFeatures:\n- Navigate file system using column view (Miller columns) to display nested\n  directories. See |MiniFiles-navigation| for overview.\n\n- Opt-in preview of file or directory under cursor.\n\n- Manipulate files and directories by editing text buffers: create, delete,\n  copy, rename, move. See |MiniFiles-manipulation| for overview.\n\n- Use as default file explorer instead of `netrw`.\n\n- Configurable:\n    - Filter/prefix/sort of file system entries.\n    - Mappings used for common explorer actions.\n    - UI options: whether to show preview of file/directory under cursor, etc.\n    - Bookmarks for quicker navigation.\n\nWhat it doesn't do:\n- Try to be replacement of system file explorer. It is mostly designed to\n  be used within Neovim to quickly explore file system structure, open\n  files, and perform some quick file system edits.\n\n- Work on remote locations. Only local file system is supported.\n\n- Provide built-in interactive toggle of content `filter` and `sort`.\n  See |MiniFiles-examples| for some common examples.\n\n- Provide out of the box extra information like git or diagnostic status.\n  This can be achieved by setting |extmarks| on appropriate event(s)\n  (see |MiniFiles-events|)\n\nNotes:\n- This module is written and thoroughly tested on Linux. Support for other\n  platform/OS (like Windows or MacOS) is a goal, but there is no guarantee.\n\n- This module silently reacts to not enough permissions:\n    - In case of missing file, check its or its parent read permissions.\n    - In case of no manipulation result, check write permissions.\n\n# Dependencies ~\n\nSuggested dependencies (provide extra functionality, will work without them):\n\n- Enabled |mini.icons| module to show icons near file/directory names.\n  Falls back to [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n  plugin or uses default icons.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.files').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniFiles`\nwhich you can use for scripting or manually (with `:lua MiniFiles.*`).\n\nSee |MiniFiles.config| for available config settings.\n\nYou can override runtime config settings (like mappings or window options)\nlocally to buffer inside `vim.b.minifiles_config` which should have same\nstructure as `MiniFiles.config`. See |mini.nvim-buffer-local-config| for\nmore details.\n\n# Comparisons ~\n\n- [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua):\n    - Provides tree view of file system, while this module uses column view.\n    - File system manipulation is done with custom set of mappings for each\n      action, while this module is designed to do that by editing text.\n    - Has more out of the box functionality with extra configuration, while\n      this module has not (by design).\n\n- [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim):\n    - Uses single window to show information only about currently explored\n      directory, while this module uses column view to show whole currently\n      explored branch.\n    - Also uses text editing to manipulate file system entries.\n    - Can work for remote file systems, while this module can not (by design).\n\n- [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim):\n    - Compares to this module mostly the same as 'nvim-tree/nvim-tree.lua'.\n\n# Highlight groups ~\n\n- `MiniFilesBorder` - border of regular windows.\n- `MiniFilesBorderModified` - border of windows showing modified buffer.\n- `MiniFilesCursorLine` - cursor line in explorer windows.\n- `MiniFilesDirectory` - text and icon representing directory.\n- `MiniFilesFile` - text representing file.\n- `MiniFilesNormal` - basic foreground/background highlighting.\n- `MiniFilesTitle` - title of regular windows.\n- `MiniFilesTitleFocused` - title of focused window.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nThis plugin provides only manually started functionality, so no disabling\nis available.\n\n------------------------------------------------------------------------------\n                                                          *MiniFiles-navigation*\nEvery navigation starts by calling |MiniFiles.open()|, either directly or via\nmapping (see its help for examples of some common scenarios). It will show\nan explorer consisting of side-by-side floating windows with the following\nprinciples:\n\n- Explorer shows one branch of nested directories at a time.\n\n- Explorer consists from several windows:\n\n    - Each window displays entries of a single directory in a modifiable\n      scratch buffer.\n\n    - Windows are organized left to right: for any particular window the left\n      neighbor is its parent directory and right neighbor - its child.\n\n- Explorer windows are the viewport to some part of current branch, meaning\n  that their opening/closing does not affect the branch. This matters, for\n  example, if there are more elements in the branch than can be shown windows.\n\n- Every buffer line represents separate file system entry following certain\n  format (not visible for users by default; set |'conceallevel'| to 0 to see it)\n\n- Once directory is shown, its buffer is not updated automatically following\n  external file system changes. Manually use |MiniFiles.synchronize()| for that.\n\nAfter opening explorer, in-buffer navigation is done the same way as any\nregular buffer, except without some keys reserved for built-in actions.\n\nMost common ways to navigate are:\n\n- Press `j` to move cursor onto next (lower) entry in current directory.\n- Press `k` to move cursor onto previous (higher) entry in current directory.\n- Press `l` to expand entry under cursor (see \"Go in\" action).\n- Press `h` to focus on parent directory (see \"Go out\" action).\n\nCursor positions in each directory buffer are tracked and saved during\nnavigation. This allows for more convenient repeated navigation to some\npreviously visited branch.\n\nAvailable built-in actions (see \"Details\" for more information): >\n\n | Action      | Keys | Description                                    |\n |-------------|------|------------------------------------------------|\n | Close       |  q   | Close explorer                                 |\n |-------------|------|------------------------------------------------|\n | Go in       |  l   | Expand entry (show directory or open file)     |\n |-------------|------|------------------------------------------------|\n | Go in plus  |  L   | Expand entry plus extra action                 |\n |-------------|------|------------------------------------------------|\n | Go out      |  h   | Focus on parent directory                      |\n |-------------|------|------------------------------------------------|\n | Go out plus |  H   | Focus on parent directory plus extra action    |\n |-------------|------|------------------------------------------------|\n | Go to mark  |  '   | Jump to bookmark (waits for single key id)     |\n |-------------|------|------------------------------------------------|\n | Set mark    |  m   | Set bookmark (waits for single key id)         |\n |-------------|------|------------------------------------------------|\n | Reset       | <BS> | Reset current explorer                         |\n |-------------|------|------------------------------------------------|\n | Reveal cwd  |  @   | Reset current current working directory        |\n |-------------|------|------------------------------------------------|\n | Show help   |  g?  | Show help window                               |\n |-------------|------|------------------------------------------------|\n | Synchronize |  =   | Synchronize user edits and/or external changes |\n |-------------|------|------------------------------------------------|\n | Trim left   |  <   | Trim left part of branch                       |\n |-------------|------|------------------------------------------------|\n | Trim right  |  >   | Trim right part of branch                      |\n |-------------|------|------------------------------------------------|\n<\nDetails:\n\n- \"Go in\":\n    - Always opens file in the latest window before `MiniFiles.open()` call.\n    - Never closes explorer.\n    - Works in linewise Visual mode to expand multiple entries.\n\n- \"Go in plus\" is regular \"Go in\" but closes explorer after opening a file.\n\n- \"Go out plus\" is regular \"Go out\" but trims right part of branch.\n\n- \"Set mark\" and \"Go to mark\" both wait for user to press a single character\n  of a bookmark id. Example: `ma` sets directory path of focused window as\n  bookmark \"a\"; `'a` jumps (sets as whole branch) to bookmark \"a\".\n  Special bookmark \"'\" always points to path before the latest bookmark jump.\n\n- \"Reset\" focuses only on \"anchor\" directory (the one used to open current\n  explorer) and resets all stored directory cursor positions.\n\n- \"Reveal cwd\" extends branch to include |current-directory|.\n  If it is not an ancestor of the current branch, nothing is done.\n\n- \"Show help\" results into new window with helpful information about current\n  explorer (like buffer mappings and bookmarks). Press `q` to close it.\n\n- \"Synchronize\" parses user edits in directory buffers, applies them (after\n  confirmation), and updates all directory buffers with the most relevant\n  file system information. Can also be used without user edits to show up\n  to date file system entries.\n  See |MiniFiles-manipulation| for more info about file system manipulation.\n\n- \"Trim left\" and \"Trim right\" trim parts of the whole branch, not only its\n  currently visible parts.\n\nNotes:\n\n- Each action has exported function with more details about it.\n\n- Keys can be configured with `mappings` table of |MiniFiles.config|.\n\n------------------------------------------------------------------------------\n                                                        *MiniFiles-manipulation*\nFile system manipulation is done by editing text inside directory buffers,\nwhich are shown inside dedicated window(s). See |MiniFiles-navigation| for\nmore information about navigating to a particular directory.\n\nGeneral workflow:\n\n- Navigate to the directory in which manipulation should be done.\n\n- Edit buffer in the way representing file system action.\n\n- Repeat previous steps until all necessary file system actions are recorded.\n  Note: even if directory buffer is hidden, its modifications are preserved,\n  so you can navigate in and out of directory with modified buffer.\n\n- Execute |MiniFiles.synchronize()| (default key is `=`). This will prompt\n  confirmation dialog listing all file system actions (per directory) it is\n  about to perform. READ IT CAREFULLY.\n\n- Confirm by pressing `y` / `<CR>` (apply edits and update buffers) or\n  don't confirm by pressing `n` / `<Esc>` (update buffers without applying edits).\n\nNote: prefer small and not related steps with more frequent synchronization\nover single complex manipulation. There are (known) cases which won't work.\n\n# How does it work ~\n\nAll manipulation functionality is powered by creating and keeping track of\npath indexes: text of the form `/xxx` (`xxx` is the number path index) placed\nat the start of every line representing file system entry.\n\nBy default they are hidden as concealed text (along with prefix separators)\nfor more convenience but you can see them by setting |'conceallevel'| to 0.\nDO NOT modify text to the left of entry name.\n\nDuring synchronization, actual text for entry name is compared to path index\nat that line (if present) to deduce which file system action to perform.\nNote that order of text manipulation steps does not affect performed actions.\n\n# Supported file system actions ~\n\n## Create ~\n\n- Create file by creating new line with file name (including extension).\n\n- Create directory by creating new line with directory name followed by `/`.\n\n- Create file or directory inside nested directories by creating new line\n  with text like 'dir/nested-dir/' or 'dir/nested-dir/file'.\n  Always use `/` on any OS.\n\n## Delete ~\n\n- Delete file or directory by deleting **whole line** describing it.\n\n- If `options.permanent_delete` is `true`, delete is permanent. Otherwise\n  file system entry is moved to a module-specific trash directory\n  (see |MiniFiles.config| for more details).\n\n## Rename ~\n\n- Rename file or directory by editing its name (not icon or path index to\n  the left of it).\n\n- With default mappings for `h` / `l` it might be not convenient to rename\n  only part of an entry. You can adopt any of the following approaches:\n    - Use different motions, like |$|, |e|, |f|, etc.\n    - Go into Insert mode and navigate inside it.\n    - Change mappings to be more suited for manipulation and not navigation.\n      See \"Mappings\" section in |MiniFiles.config|.\n\n- It is not needed to end directory name with `/`.\n\n- Appending `/` to a file name will delete it and create empty directory\n  with the same name.\n\n- Cyclic renames (\"a\" to \"b\" and \"b\" to \"a\") are not supported.\n\n## Copy ~\n\n- Copy file or directory by copying **whole line** describing it and pasting\n  it inside buffer of target directory.\n\n- Change of target path is allowed. Edit only entry name in target location\n  (not icon or path index to the left of it).\n\n- Copying inside same parent directory is supported only if target path has\n  different name.\n\n- Copying inside child directory is supported.\n\n## Move ~\n\n- Move file or directory by cutting **whole line** describing it and then\n  pasting it inside target directory.\n\n- Change of target path is allowed. Edit only entry name in target location\n  (not icon or path index to the left of it).\n\n- Moving directory inside itself is not supported.\n\n------------------------------------------------------------------------------\n                                                              *MiniFiles-events*\nTo allow user customization and integration of external tools, certain |User|\nautocommand events are triggered under common circumstances.\n\n# UI events ~\n\n- `MiniFilesExplorerOpen` - just after explorer finishes opening.\n\n- `MiniFilesExplorerClose` - just before explorer starts closing.\n\n- `MiniFilesBufferCreate` - when buffer is created to show a particular\n  directory/file. Triggered once per path during explorer session.\n  Can be used to create buffer-local mappings.\n\n- `MiniFilesBufferUpdate` - when path buffer is updated with new content.\n  Can be used for integrations to set useful |extmarks|.\n\n- `MiniFilesWindowOpen` - when new window is opened. Can be used to set\n  window-local settings (like border, 'winblend', etc.)\n\n- `MiniFilesWindowUpdate` - when a window is updated. Triggers VERY frequently.\n  At least after every cursor movement and \"go in\" / \"go out\" action.\n\nCallback for each buffer/window UI event will receive <data> field\n(see |nvim_create_autocmd()|) with the following information:\n\n- <buf_id> - index of target buffer.\n- <win_id> - index of target window. Can be `nil`, like in\n  `MiniFilesBufferCreate` and buffer's first `MiniFilesBufferUpdate` as\n  they are triggered before window is created.\n\n# File action events ~\n\n- `MiniFilesActionCreate` - after entry is successfully created.\n\n- `MiniFilesActionDelete` - after entry is successfully deleted.\n\n- `MiniFilesActionRename` - after entry is successfully renamed.\n\n- `MiniFilesActionCopy` - after entry is successfully copied.\n\n- `MiniFilesActionMove` - after entry is successfully moved.\n\nCallback for each file action event will receive `data` field\n(see |nvim_create_autocmd()|) with the following information:\n\n- <action> - string with action name.\n- <from> - full path of entry before action (`nil` for \"create\" action).\n- <to> - full path of entry after action (`nil` for permanent \"delete\" action).\n\n------------------------------------------------------------------------------\n                                                            *MiniFiles-examples*\n# Toggle explorer ~\n\nUse a combination of |MiniFiles.open()| and |MiniFiles.close()|: >lua\n\n  local minifiles_toggle = function(...)\n    if not MiniFiles.close() then MiniFiles.open(...) end\n  end\n<\n# Customize windows ~\n\nFor most of the common customizations using `MiniFilesWindowOpen` event\nautocommand is the suggested approach: >lua\n\n  vim.api.nvim_create_autocmd('User', {\n    pattern = 'MiniFilesWindowOpen',\n    callback = function(args)\n      local win_id = args.data.win_id\n\n      -- Customize window-local settings\n      vim.wo[win_id].winblend = 50\n      local config = vim.api.nvim_win_get_config(win_id)\n      config.border, config.title_pos = 'double', 'right'\n      vim.api.nvim_win_set_config(win_id, config)\n    end,\n  })\n<\nHowever, some parts (like window title and height) of window config are later\nupdated internally. Use `MiniFilesWindowUpdate` event for them: >lua\n\n  vim.api.nvim_create_autocmd('User', {\n    pattern = 'MiniFilesWindowUpdate',\n    callback = function(args)\n      local config = vim.api.nvim_win_get_config(args.data.win_id)\n\n      -- Ensure fixed height\n      config.height = 10\n\n      -- Ensure no title padding\n      local n = #config.title\n      config.title[1][1] = config.title[1][1]:gsub('^ ', '')\n      config.title[n][1] = config.title[n][1]:gsub(' $', '')\n\n      vim.api.nvim_win_set_config(args.data.win_id, config)\n    end,\n  })\n<\n# Customize icons ~\n\nUse different directory icon (if you don't use |mini.icons|): >lua\n\n  local my_prefix = function(fs_entry)\n    if fs_entry.fs_type == 'directory' then\n      -- NOTE: it is usually a good idea to use icon followed by space\n      return ' ', 'MiniFilesDirectory'\n    end\n    return MiniFiles.default_prefix(fs_entry)\n  end\n\n  require('mini.files').setup({ content = { prefix = my_prefix } })\n<\nShow no icons: >lua\n\n  require('mini.files').setup({ content = { prefix = function() end } })\n<\n# Create mapping to show/hide dot-files ~\n\nCreate an autocommand for `MiniFilesBufferCreate` event which calls\n|MiniFiles.refresh()| with explicit `content.filter` functions: >lua\n\n  local show_dotfiles = true\n\n  local filter_show = function(fs_entry) return true end\n\n  local filter_hide = function(fs_entry)\n    return not vim.startswith(fs_entry.name, '.')\n  end\n\n  local toggle_dotfiles = function()\n    show_dotfiles = not show_dotfiles\n    local new_filter = show_dotfiles and filter_show or filter_hide\n    MiniFiles.refresh({ content = { filter = new_filter } })\n  end\n\n  vim.api.nvim_create_autocmd('User', {\n    pattern = 'MiniFilesBufferCreate',\n    callback = function(args)\n      local buf_id = args.data.buf_id\n      -- Tweak left-hand side of mapping to your liking\n      vim.keymap.set('n', 'g.', toggle_dotfiles, { buffer = buf_id })\n    end,\n  })\n<\n# Create mappings to modify target window via split ~\n\nCombine |MiniFiles.get_explorer_state()| and |MiniFiles.set_target_window()|: >lua\n\n  local map_split = function(buf_id, lhs, direction)\n    local rhs = function()\n      -- Make new window and set it as target\n      local cur_target = MiniFiles.get_explorer_state().target_window\n      local new_target = vim.api.nvim_win_call(cur_target, function()\n        vim.cmd(direction .. ' split')\n        return vim.api.nvim_get_current_win()\n      end)\n\n      MiniFiles.set_target_window(new_target)\n\n      -- This intentionally doesn't act on file under cursor in favor of\n      -- explicit \"go in\" action (`l` / `L`). To immediately open file,\n      -- add appropriate `MiniFiles.go_in()` call instead of this comment.\n    end\n\n    -- Adding `desc` will result into `show_help` entries\n    local desc = 'Split ' .. direction\n    vim.keymap.set('n', lhs, rhs, { buffer = buf_id, desc = desc })\n  end\n\n  vim.api.nvim_create_autocmd('User', {\n    pattern = 'MiniFilesBufferCreate',\n    callback = function(args)\n      local buf_id = args.data.buf_id\n      -- Tweak keys to your liking\n      map_split(buf_id, '<C-s>', 'belowright horizontal')\n      map_split(buf_id, '<C-v>', 'belowright vertical')\n      map_split(buf_id, '<C-t>', 'tab')\n    end,\n  })\n<\n# Create mappings which use data from entry under cursor ~\n\nUse |MiniFiles.get_fs_entry()|: >lua\n\n  -- Set focused directory as current working directory\n  local set_cwd = function()\n    local path = (MiniFiles.get_fs_entry() or {}).path\n    if path == nil then return vim.notify('Cursor is not on valid entry') end\n    vim.fn.chdir(vim.fs.dirname(path))\n  end\n\n  -- Yank in register full path of entry under cursor\n  local yank_path = function()\n    local path = (MiniFiles.get_fs_entry() or {}).path\n    if path == nil then return vim.notify('Cursor is not on valid entry') end\n    vim.fn.setreg(vim.v.register, path)\n  end\n\n  -- Open path with system default handler (useful for non-text files)\n  local ui_open = function() vim.ui.open(MiniFiles.get_fs_entry().path) end\n\n  vim.api.nvim_create_autocmd('User', {\n    pattern = 'MiniFilesBufferCreate',\n    callback = function(args)\n      local b = args.data.buf_id\n      vim.keymap.set('n', 'g~', set_cwd,   { buffer = b, desc = 'Set cwd' })\n      vim.keymap.set('n', 'gX', ui_open,   { buffer = b, desc = 'OS open' })\n      vim.keymap.set('n', 'gy', yank_path, { buffer = b, desc = 'Yank path' })\n    end,\n  })\n<\n# Set custom bookmarks ~\n\nUse |MiniFiles.set_bookmark()| inside `MiniFilesExplorerOpen` event: >lua\n\n  local set_mark = function(id, path, desc)\n    MiniFiles.set_bookmark(id, path, { desc = desc })\n  end\n  vim.api.nvim_create_autocmd('User', {\n    pattern = 'MiniFilesExplorerOpen',\n    callback = function()\n      set_mark('c', vim.fn.stdpath('config'), 'Config') -- path\n      set_mark('w', vim.fn.getcwd, 'Working directory') -- callable\n      set_mark('~', '~', 'Home directory')\n    end,\n  })\n<\n------------------------------------------------------------------------------\n                                                             *MiniFiles.setup()*\n                          `MiniFiles.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniFiles.config|.\n\nUsage ~\n>lua\n  require('mini.files').setup() -- use default config\n  -- OR\n  require('mini.files').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                              *MiniFiles.config*\n                               `MiniFiles.config`\nDefaults ~\n>lua\n  MiniFiles.config = {\n    -- Customization of shown content\n    content = {\n      -- Predicate for which file system entries to show\n      filter = nil,\n      -- Highlight group to use for a file system entry\n      highlight = nil,\n      -- Prefix text and highlight to show to the left of file system entry\n      prefix = nil,\n      -- Order in which to show file system entries\n      sort = nil,\n    },\n\n    -- Module mappings created only inside explorer.\n    -- Use `''` (empty string) to not create one.\n    mappings = {\n      close       = 'q',\n      go_in       = 'l',\n      go_in_plus  = 'L',\n      go_out      = 'h',\n      go_out_plus = 'H',\n      mark_goto   = \"'\",\n      mark_set    = 'm',\n      reset       = '<BS>',\n      reveal_cwd  = '@',\n      show_help   = 'g?',\n      synchronize = '=',\n      trim_left   = '<',\n      trim_right  = '>',\n    },\n\n    -- General options\n    options = {\n      -- Whether to delete permanently or move into module-specific trash\n      permanent_delete = true,\n      -- Whether to use for editing directories\n      use_as_default_explorer = true,\n    },\n\n    -- Customization of explorer windows\n    windows = {\n      -- Maximum number of windows to show side by side\n      max_number = math.huge,\n      -- Whether to show preview of file/directory under cursor\n      preview = false,\n      -- Width of focused window\n      width_focus = 50,\n      -- Width of non-focused window\n      width_nofocus = 15,\n      -- Width of preview window\n      width_preview = 25,\n    },\n  }\n<\n# Content ~\n\n`content.filter` is a predicate which takes file system entry data as input\nand returns `true`-ish value if it should be shown.\nUses |MiniFiles.default_filter()| by default.\n\nA file system entry data is a table with the following fields:\n  - <fs_type> `(string)` - one of \"file\" or \"directory\".\n  - <name> `(string)` - basename of an entry (including extension).\n  - <path> `(string)` - full path of an entry.\n\n`content.highlight` describes how file system entry name should be highlighted.\nTakes file system entry data as input and returns a highlight group name.\nUses |MiniFiles.default_highlight()| by default.\n\n`content.prefix` describes what text (prefix) to show to the left of file\nsystem entry name (if any) and how to highlight it. It also takes file\nsystem entry data as input and returns tuple of text and highlight group\nname to be used to highlight prefix. See |MiniFiles-examples| for common\nexamples of how to use it.\nNote: due to how lines are parsed to detect user edits for file system\nmanipulation, output of `content.prefix` should not contain `/` character.\nUses |MiniFiles.default_prefix()| by default.\n\n`content.sort` describes in which order directory entries should be shown\nin directory buffer. Takes as input and returns as output an array of file\nsystem entry data. Note: technically, it can be used to filter and modify\nits elements as well.\nUses |MiniFiles.default_sort()| by default.\n\n# Mappings ~\n\n`mappings` table can be used to customize buffer-local mappings created in each\ndirectory buffer for built-in actions. Entry name corresponds to the function\nname of the action, value - right hand side of the mapping. Supply empty\nstring to not create a particular mapping.\n\nDefault mappings are mostly designed for consistent navigation experience.\nHere are some alternatives: >lua\n\n  -- Close explorer after opening file with `l`\n  mappings = {\n    go_in = 'L',\n    go_in_plus = 'l',\n  }\n\n  -- Don't use `h`/`l` for easier cursor navigation during text edit\n  mappings = {\n    go_in = 'L',\n    go_in_plus = '',\n    go_out = 'H',\n    go_out_plus = '',\n  }\n<\n# Options ~\n\n`options.use_as_default_explorer` is a boolean indicating whether this module\nwill be used as a default file explorer to edit directory (instead of `netrw`).\nNote: to work with directory in |arglist|, do not lazy load this module.\n\n`options.permanent_delete` is a boolean indicating whether to perform\npermanent delete or move into special trash directory.\nThis is a module-specific variant of \"remove to trash\".\nTarget directory is 'mini.files/trash' inside standard path of Neovim data\ndirectory (execute `:echo stdpath('data')` to see its path in your case).\n\n# Windows ~\n\n`windows.max_number` is a maximum number of windows allowed to be open\nsimultaneously. For example, use value 1 to always show single window.\nThere is no constraint by default.\n\n`windows.preview` is a boolean indicating whether to show preview of\nfile/directory under cursor. Notes:\n- It is always shown, even if current line is for not yet existing path.\n- File preview is highlighted if its size is small enough (less than 1K\n  bytes per line or 1M bytes in total).\n\n`windows.width_focus` and `windows.width_nofocus` are number of columns used\nas `width` for focused and non-focused windows respectively.\n\n------------------------------------------------------------------------------\n                                                              *MiniFiles.open()*\n                 `MiniFiles.open`({path}, {use_latest}, {opts})\nOpen file explorer\n\nCommon ways to use this function: >lua\n\n  -- Open current working directory in a last used state\n  MiniFiles.open()\n\n  -- Fresh explorer in current working directory\n  MiniFiles.open(nil, false)\n\n  -- Open directory of current file (in last used state) focused on the file\n  MiniFiles.open(vim.api.nvim_buf_get_name(0))\n\n  -- Fresh explorer in directory of current file\n  MiniFiles.open(vim.api.nvim_buf_get_name(0), false)\n\n  -- Open last used `path` (per tabpage)\n  -- Current working directory for the first time\n  MiniFiles.open(MiniFiles.get_latest_path())\n<\nParameters ~\n{path} `(string|nil)` A valid file system path used as anchor.\n  If it is a path to directory, used directly.\n  If it is a path to file, its parent directory is used as anchor while\n  explorer will focus on the supplied file.\n  Default: path of |current-directory|.\n{use_latest} `(boolean|nil)` Whether to load explorer state from history\n  (based on the supplied anchor path). Default: `true`.\n{opts} `(table|nil)` Table of options overriding |MiniFiles.config| and\n  `vim.b.minifiles_config` for this particular explorer session.\n\n------------------------------------------------------------------------------\n                                                           *MiniFiles.refresh()*\n                          `MiniFiles.refresh`({opts})\nRefresh explorer\n\nNotes:\n- If in `opts` at least one of `content` entry is not `nil`, all directory\n  buffers are forced to update.\n\nParameters ~\n{opts} `(table|nil)` Table of options to update.\n\n------------------------------------------------------------------------------\n                                                       *MiniFiles.synchronize()*\n                           `MiniFiles.synchronize`()\nSynchronize explorer\n\n- Parse user edits in directory buffers.\n- Convert edits to file system actions and apply them after confirmation.\n  Choosing \"No\" skips application while \"Cancel\" stops synchronization.\n- Update all directory buffers with the most relevant file system information.\n  Can be used without user edits to account for external file system changes.\n\nReturn ~\n`(boolean)` Whether synchronization was done.\n\n------------------------------------------------------------------------------\n                                                             *MiniFiles.reset()*\n                              `MiniFiles.reset`()\nReset explorer\n\n- Show single window focused on anchor directory (which was used as first\n  argument for |MiniFiles.open()|).\n- Reset all tracked directory cursors to point at first entry.\n\n------------------------------------------------------------------------------\n                                                             *MiniFiles.close()*\n                              `MiniFiles.close`()\nClose explorer\n\nReturn ~\n`(boolean|nil)` Whether closing was done or `nil` if there was nothing to close.\n\n------------------------------------------------------------------------------\n                                                             *MiniFiles.go_in()*\n                           `MiniFiles.go_in`({opts})\nGo in entry under cursor\n\nDepends on entry under cursor:\n- If directory, focus on it in the window to the right.\n- If file, open it in the window which was current during |MiniFiles.open()|.\n  Explorer is not closed after that.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <close_on_file> `(boolean)` - whether to close explorer after going\n    inside a file. Powers the `go_in_plus` mapping.\n    Default: `false`.\n\n------------------------------------------------------------------------------\n                                                            *MiniFiles.go_out()*\n                              `MiniFiles.go_out`()\nGo out to parent directory\n\n- Focus on window to the left showing parent of current directory.\n\n------------------------------------------------------------------------------\n                                                         *MiniFiles.trim_left()*\n                            `MiniFiles.trim_left`()\nTrim left part of branch\n\n- Remove all branch paths to the left of currently focused one. This also\n  results into current window becoming the most left one.\n\n------------------------------------------------------------------------------\n                                                        *MiniFiles.trim_right()*\n                            `MiniFiles.trim_right`()\nTrim right part of branch\n\n- Remove all branch paths to the right of currently focused one. This also\n  results into current window becoming the most right one.\n\n------------------------------------------------------------------------------\n                                                        *MiniFiles.reveal_cwd()*\n                            `MiniFiles.reveal_cwd`()\nReveal current working directory\n\n- Prepend branch with parent paths until current working directory is reached.\n  Do nothing if not inside it.\n\n------------------------------------------------------------------------------\n                                                         *MiniFiles.show_help()*\n                            `MiniFiles.show_help`()\nShow help window\n\n- Open window with helpful information about currently shown explorer and\n  focus on it. To close it, press `q`.\n\n------------------------------------------------------------------------------\n                                                      *MiniFiles.get_fs_entry()*\n                   `MiniFiles.get_fs_entry`({buf_id}, {line})\nGet file system entry data\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier of valid directory buffer.\n  Default: current buffer.\n{line} `(number|nil)` Line number of entry for which to return information.\n  Default: cursor line.\n\nReturn ~\n`(table|nil)` Table of file system entry data with the following fields:\n  - <fs_type> `(string)` - one of \"file\" or \"directory\".\n  - <name> `(string)` - basename of an entry (including extension).\n  - <path> `(string)` - full path of an entry.\n\nReturns `nil` if there is no proper file system entry path at the line.\n\n------------------------------------------------------------------------------\n                                                *MiniFiles.get_explorer_state()*\n                        `MiniFiles.get_explorer_state`()\nGet state of active explorer\n\nReturn ~\n`(table|nil)` Table with explorer state data or `nil` if no active explorer.\n  State data is a table with the following fields:\n  - <anchor> `(string)` - anchor directory path (see |MiniFiles.open()|).\n  - <bookmarks> `(table)` - map from bookmark id (single character) to its data:\n    table with <path> and <desc> fields (see |MiniFiles.set_bookmark()|).\n  - <branch> `(table)` - array of nested paths for currently opened branch.\n  - <depth_focus> `(number)` - an index in <branch> for currently focused path.\n  - <target_window> `(number)` - identifier of target window.\n  - <windows> `(table)` - array with data about currently opened windows.\n    Each element is a table with <win_id> (window identifier) and <path> (path\n    shown in the window) fields.\n\nSee also ~\n- |MiniFiles.set_bookmark()|\n- |MiniFiles.set_branch()|\n- |MiniFiles.set_target_window()|\n\n------------------------------------------------------------------------------\n                                                 *MiniFiles.set_target_window()*\n                    `MiniFiles.set_target_window`({win_id})\nSet target window\n\nParameters ~\n{win_id} `(number)` Window identifier inside which file will be opened.\n\n------------------------------------------------------------------------------\n                                                        *MiniFiles.set_branch()*\n                    `MiniFiles.set_branch`({branch}, {opts})\nSet branch\n\nSet which paths to display. Preview (if enabled) is applied afterwards.\n\nParameters ~\n{branch} `(table)` Array of strings representing actually present on disk paths.\n  Each consecutive pair should represent direct parent-child paths.\n  Should contain at least one directory path.\n  May end with file path (will be previwed).\n  Relative paths are resolved using |current-directory|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <depth_focus> `(number)` - an index in `branch` for path to focus. Will\n    be normalized to fit inside `branch`. Default: index of deepest directory.\n\nSee also ~\n|MiniFiles.get_explorer_state()|\n\n------------------------------------------------------------------------------\n                                                      *MiniFiles.set_bookmark()*\n                 `MiniFiles.set_bookmark`({id}, {path}, {opts})\nSet bookmark\n\nParameters ~\n{id} `(string)` Single character bookmark id.\n{path} `(string|function)` Path of a present on disk directory to set as\n  a bookmark's path. If callable, should return such path.\n{opts} `(table|nil)` Options. Possible fields:\n  - <desc> `(string)` - bookmark description (used in help window).\n\n------------------------------------------------------------------------------\n                                                   *MiniFiles.get_latest_path()*\n                         `MiniFiles.get_latest_path`()\nGet latest used anchor path\n\nNote: if latest used `path` argument for |MiniFiles.open()| was for file,\nthis will return its parent (as it was used as anchor path).\n\n------------------------------------------------------------------------------\n                                                    *MiniFiles.default_filter()*\n                     `MiniFiles.default_filter`({fs_entry})\nDefault filter of file system entries\n\nCurrently does not filter anything out.\n\nParameters ~\n{fs_entry} `(table)` Table with the following fields:\n  - <fs_type> `(string)` - one of \"file\" or \"directory\".\n  - <name> `(string)` - basename of an entry (including extension).\n  - <path> `(string)` - full path of an entry.\n\nReturn ~\n`(boolean)` Always `true`.\n\n------------------------------------------------------------------------------\n                                                    *MiniFiles.default_prefix()*\n                     `MiniFiles.default_prefix`({fs_entry})\nDefault prefix of file system entries\n\n- If set up |mini.icons|, use |MiniIcons.get()| for \"directory\"/\"file\" category.\n- Otherwise:\n    - For directory return fixed icon and \"MiniFilesDirectory\" group name.\n    - For file try to use `get_icon()` from 'nvim-tree/nvim-web-devicons'.\n      If missing, return fixed icon and 'MiniFilesFile' group name.\n\nParameters ~\n{fs_entry} `(table)` Table with the following fields:\n  - <fs_type> `(string)` - one of \"file\" or \"directory\".\n  - <name> `(string)` - basename of an entry (including extension).\n  - <path> `(string)` - full path of an entry.\n\nReturn ~\n`(...)` Icon and highlight group name. For more details, see |MiniFiles.config|\n  and |MiniFiles-examples|.\n\n------------------------------------------------------------------------------\n                                                      *MiniFiles.default_sort()*\n                     `MiniFiles.default_sort`({fs_entries})\nDefault sort of file system entries\n\nSort directories and files separately (alphabetically ignoring case) and\nput directories first.\n\nParameters ~\n{fs_entries} `(table)` Array of file system entry data.\n  Each one is a table with the following fields:\n  - <fs_type> `(string)` - one of \"file\" or \"directory\".\n  - <name> `(string)` - basename of an entry (including extension).\n  - <path> `(string)` - full path of an entry.\n\nReturn ~\n`(table)` Sorted array of file system entries.\n\n------------------------------------------------------------------------------\n                                                 *MiniFiles.default_highlight()*\n                   `MiniFiles.default_highlight`({fs_entry})\nDefault file system entry highlight\n\nReturns `'MiniFilesDirectory'` for directory and `'MiniFilesFile'` otherwise.\n\nParameters ~\n{fs_entry} `(table)` Table with the following fields:\n  - <fs_type> `(string)` - one of \"file\" or \"directory\".\n  - <name> `(string)` - basename of an entry (including extension).\n  - <path> `(string)` - full path of an entry.\n\nReturn ~\n`(string)` Highlight group name.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-fuzzy.txt",
    "content": "*mini.fuzzy* Fuzzy matching\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                     *MiniFuzzy*\nFeatures:\n- Minimal and fast fuzzy matching algorithm which prioritizes match width.\n\n- Functions to for common fuzzy matching operations:\n    - |MiniFuzzy.match()|.\n    - |MiniFuzzy.filtersort()|.\n    - |MiniFuzzy.process_lsp_items()|.\n\n- Generator of sorter (|MiniFuzzy.get_telescope_sorter()|) for\n  [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n\n# Setup ~\n\nThis module doesn't need setup, but it can be done to improve usability.\nSetup with `require('mini.fuzzy').setup({})` (replace `{}` with your\n`config` table). It will create global Lua table `MiniFuzzy` which you can\nuse for scripting or manually (with `:lua MiniFuzzy.*`).\n\nSee |MiniFuzzy.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minifuzzy_config` which should have same structure as\n`MiniFuzzy.config`.\nSee |mini.nvim-buffer-local-config| for more details.\n\n# Notes ~\n\n1. Currently there is no explicit design to work with multibyte symbols,\n   but simple examples should work.\n2. Smart case is used: case insensitive if input word (which is usually a\n   user input) is all lower case. Case sensitive otherwise.\n\n------------------------------------------------------------------------------\n                                                           *MiniFuzzy-algorithm*\nGeneral design uses only width of found match and index of first letter\nmatch. No special characters or positions (like in fzy and fzf) are used.\n\nGiven non-empty input `word` and target `candidate`:\n- The goal is to find matching between `word`'s letters and letters in\n  `candidate` which minimizes certain score. It is assumed that order of\n  letters in `word` and those matched in `candidate` should be the same.\n\n- Matching is represented by matched positions: an array `positions` of\n  integers with length equal to number of letters in `word`. The following\n  should be always true in case of a match: `candidate`'s letter at index\n  `positions[i]` is letters[i]` for all valid `i`.\n\n- Matched positions are evaluated based only on two features: their width\n  (number of indexes between first and last positions) and first match\n  (index of first letter match). There is a global setting `cutoff` for\n  which all feature values greater than it can be considered \"equally bad\".\n\n- Score of matched positions is computed with following explicit formula:\n  `cutoff * min(width, cutoff) + min(first, cutoff)`. It is designed to be\n  equivalent to first comparing widths (lower is better) and then comparing\n  first match (lower is better). For example, if `word = 'time'`:\n    - '_time' (width 4) will have a better match than 't_ime' (width 5).\n    - 'time_a' (width 4, first 1) will have a better match than 'a_time'\n      (width 4, first 3).\n\n- Final matched positions are those which minimize score among all possible\n  matched positions of `word` and `candidate`.\n\n------------------------------------------------------------------------------\n                                                             *MiniFuzzy.setup()*\n                          `MiniFuzzy.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniFuzzy.config|.\n\nUsage ~\n>lua\n  require('mini.fuzzy').setup() -- use default config\n  -- OR\n  require('mini.fuzzy').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                              *MiniFuzzy.config*\n                               `MiniFuzzy.config`\nDefaults ~\n>lua\n  MiniFuzzy.config = {\n    -- Maximum allowed value of match features (width and first match). All\n    -- feature values greater than cutoff can be considered \"equally bad\".\n    cutoff = 100,\n  }\n<\n------------------------------------------------------------------------------\n                                                             *MiniFuzzy.match()*\n                     `MiniFuzzy.match`({word}, {candidate})\nCompute match data\n\nParameters ~\n{word} `(string)` Input word (usually user input).\n{candidate} `(string)` Target word (usually with which matching is done).\n\nReturn ~\n`(table)` Matching information:\n  - <positions> `(table|nil)` - array with letter indexes inside `candidate`\n    which matched to corresponding letters in `word`. It is empty array if\n    `word` is empty string and `nil` if no match.\n  - <score> `number` - positive number representing how good the match is\n    (lower is better). It is `-1` if no match or word is empty string.\n\n------------------------------------------------------------------------------\n                                                        *MiniFuzzy.filtersort()*\n               `MiniFuzzy.filtersort`({word}, {candidate_array})\nFilter string array\n\n- Keep only input elements which match `word`.\n- Sort from best to worst matches (based on score and index in original\n  array, both lower is better).\n\nParameters ~\n{word} `(string)` String which will be searched.\n{candidate_array} `(table)` Lua array of strings inside which word will be\n  searched.\n\nReturn ~\n`(...)` Arrays of matched candidates and their indexes in original input.\n\n------------------------------------------------------------------------------\n                                                 *MiniFuzzy.process_lsp_items()*\n                 `MiniFuzzy.process_lsp_items`({items}, {base})\nFuzzy matching for `lsp_completion.process_items` of |MiniCompletion.config|\n\nParameters ~\n{items} `(table)` Array with LSP 'textDocument/completion' response items.\n{base} `(string)` Word to complete.\n\nReturn ~\n`(table)` Array of items with text (`filterText` or `label`) fuzzy matching `base`.\n\n------------------------------------------------------------------------------\n                                              *MiniFuzzy.get_telescope_sorter()*\n                    `MiniFuzzy.get_telescope_sorter`({opts})\nCustom getter for `telescope.nvim` sorter\n\nDesigned as a value for file and generic sorter of 'telescope.nvim'.\n\nParameters ~\n{opts} `(table|nil)` Options (currently not used).\n\nUsage ~\n>lua\n  require('telescope').setup({\n    defaults = {\n      generic_sorter = require('mini.fuzzy').get_telescope_sorter\n    }\n  })\n<\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-git.txt",
    "content": "*mini.git* Git integration\n\nMIT License Copyright (c) 2024 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                       *MiniGit*\nFeatures:\n\n- Automated tracking of Git related data: root path, status, HEAD, etc.\n  Exposes buffer-local variables for convenient use in statusline.\n  See |MiniGit.enable()| and |MiniGit.get_buf_data()| for more information.\n\n- |:Git| command for executing any `git` call inside file's repository root with\n  deeper current instance integration (show output as notification/buffer,\n  use to edit commit messages, etc.).\n\n- Helper functions to inspect Git history:\n    - |MiniGit.show_range_history()| shows how certain line range evolved.\n    - |MiniGit.show_diff_source()| shows file state as it was at diff entry.\n    - |MiniGit.show_at_cursor()| shows Git related data depending on context.\n\nWhat it doesn't do:\n\n- Replace fully featured Git client. Rule of thumb: if feature does not rely\n  on a state of current Neovim (opened buffers, etc.), it is out of scope.\n  For more functionality, use either |mini.diff| or fully featured Git client.\n\nSources with more details:\n- |:Git|\n- |MiniGit-examples|\n- |MiniGit.enable()|\n- |MiniGit.get_buf_data()|\n\n# Setup ~\n\nThis module needs a setup with `require('mini.git').setup({})` (replace `{}` with\nyour `config` table). It will create global Lua table `MiniGit` which you can use\nfor scripting or manually (with `:lua MiniGit.*`).\n\nSee |MiniGit.config| for `config` structure and default values.\n\n# Comparisons ~\n\n- [tpope/vim-fugitive](https://github.com/tpope/vim-fugitive):\n    - Mostly a dedicated Git client, while this module is not (by design).\n    - Provides buffer-local Git data only through fixed statusline component,\n      while this module has richer data in the form of a Lua table.\n    - Both provide |:Git| command with 'vim-fugitive' treating some cases\n      extra specially (like `:Git blame`, etc.), while this module mostly\n      treats all cases the same. See |MiniGit-examples| for how they can be\n      manually customized.\n      Also this module provides slightly different (usually richer)\n      completion suggestions.\n\n- [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit):\n    - Similar to 'tpope/vim-fugitive', but without `:Git` command.\n\n- [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim):\n    - Provides buffer-local Git data with emphasis on granular diff status,\n      while this module is more oriented towards repository and file level\n      data (root, HEAD, file status, etc.). Use |mini.diff| for diff tracking.\n\n# Disabling ~\n\nTo prevent buffer(s) from being tracked, set `vim.g.minigit_disable` (globally)\nor `vim.b.minigit_disable` (for a buffer) to `true`. Considering high number of\ndifferent scenarios and customization intentions, writing exact rules for\ndisabling module's functionality is left to user.\nSee |mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                              *MiniGit-examples*\n# Statusline component ~\n\nTracked buffer data can be used in statusline via `vim.b.minigit_summary_string`\nbuffer-local variable. It is expected to be used as is. To show another info,\ntweak buffer-local variable directly inside `MiniGitUpdated` `User` event: >lua\n\n  -- Use only HEAD name as summary string\n  local format_summary = function(data)\n    -- Utilize buffer-local table summary\n    local summary = vim.b[data.buf].minigit_summary\n    vim.b[data.buf].minigit_summary_string = summary.head_name or ''\n  end\n\n  local au_opts = { pattern = 'MiniGitUpdated', callback = format_summary }\n  vim.api.nvim_create_autocmd('User', au_opts)\n<\n# Tweaking command output ~\n\nBuffer output of |:Git| command can be tweaked inside autocommand for\n`MiniGitCommandSplit` `User` event (see |MiniGit-command-events|).\nFor example, to make `:vertical Git blame -- %` align blame output with the\ncurrent window state, use the following code: >lua\n\n  local align_blame = function(au_data)\n    if au_data.data.git_subcommand ~= 'blame' then return end\n\n    -- Align blame output with source\n    local win_src = au_data.data.win_source\n    vim.wo.wrap = false\n    vim.fn.winrestview({ topline = vim.fn.line('w0', win_src) })\n    vim.api.nvim_win_set_cursor(0, { vim.fn.line('.', win_src), 0 })\n\n    -- Bind both windows so that they scroll together\n    vim.wo[win_src].scrollbind, vim.wo.scrollbind = true, true\n  end\n\n  local au_opts = { pattern = 'MiniGitCommandSplit', callback = align_blame }\n  vim.api.nvim_create_autocmd('User', au_opts)\n<\n# History navigation ~\n\nFunction |MiniGit.show_at_cursor()| is specifically exported to make Git\nhistory navigation easier. Here are some different ways it can be used:\n\n- Call inside buffer for already committed file to show the evolution of\n  the current line (or visually selected range) through history.\n  It is essentially a `:Git log HEAD` with proper `-L` flag.\n  This also works inside output of |MiniGit.show_diff_source()|.\n\n- Call with cursor on commit hash to inspect that commit in full.\n  This is usually helpful in the output of `:Git log`.\n\n- Call with cursor inside diff entry to inspect its file in the state how it\n  was at certain commit. By default it shows state after commit, unless cursor\n  is on the \"deleted\" line (i.e. line starting with \"-\") in which case\n  state before commit is shown.\n\nThis workflow can be made more interactive when used with mapping, like this: >lua\n\n  local rhs = '<Cmd>lua MiniGit.show_at_cursor()<CR>'\n  vim.keymap.set({ 'n', 'x' }, '<Leader>gs', rhs, { desc = 'Show at cursor' })\n<\n------------------------------------------------------------------------------\n                                                                          *:Git*\nThe `:Git` user command runs `git` CLI call with extra integration for currently\nopened Neovim process:\n- Command is executed inside repository root of the currently active file\n  (or |current-directory| if file is not tracked by this module).\n\n- Command output is shown either in dedicated buffer in window split or as\n  notification via |vim.notify()|. Which method is used depends on whether\n  particular Git subcommand is supposed to show data for user to inspect\n  (like `log`, `status`, etc.) or not (like `commit`, `push`, etc.). This is\n  determined automatically based on the data Git itself provides.\n  Split window is made current after command execution.\n\n  Use split-related |:command-modifiers| (|:vertical|, |:horizontal|, or |:tab|)\n  to force output in a particular type of split. Default split direction is\n  controlled by `command.split` in |MiniGit.config|.\n\n  Use |:silent| command modifier to not show any output.\n\n  Errors and warnings are always shown as notifications.\n\n  See |MiniGit-examples| for the example of tweaking command output.\n\n- Editor for tasks that require interactive user input (like `:Git commit` or\n  `:Git rebase --interactive`) is opened inside current session in a separate\n  split. Make modifications as in regular buffer, |:write| changes followed by\n  |:close| / |:quit| for Git CLI command to resume.\n\nExamples of usage:\n- `:Git log --oneline` - show compact log of current repository.\n- `:vert Git blame -- %` - show latest commits per line in vertical split.\n- `:Git help rebase` - show help page for `rebase` subcommand.\n- `:Git -C <cwd> status` - execute `git status` inside |current-directory|.\n\nThere is also a context aware completion which can be invoked with `<Tab>`:\n- If completed word starts with \"-\", options for the current Git subcommand\n  are shown. Like completion at `:Git log -` will suggest `-L`, `--oneline`, etc.\n- If there is an explicit \" -- \" to the cursor's left, incremental path\n  suggestions will be shown.\n- If there is no recognized Git subcommand yet, show list of subcommands.\n  Otherwise for some common subcommands list of its targets will be suggested:\n  like for `:Git branch` it will be list of branches, etc.\n\nNotes:\n- Paths are always treated as relative to command's execution directory\n  (file's repository root or |current-directory| if absent).\n- Don't use quotes for entries containing space, escape it with `\\` directly.\n  Like `:Git commit -m Hello\\ world` and not `:Git commit -m 'Hello world'`\n  (which treats `'Hello` and `world'` as separate arguments).\n\n# Events ~\n*MiniGit-command-events*\n\nThere are several `User` events triggered during command execution:\n\n- `MiniGitCommandDone` - after command is done executing. For Lua callbacks it\n  provides a special `data` table with the following fields:\n    - <cmd_input> `(table)` - structured data about executed command.\n      Has same structure as Lua function input in |nvim_create_user_command()|.\n    - <cwd> `(string)` - directory path inside which Git command was executed.\n    - <exit_code> `(number)` - exit code of CLI process.\n    - <git_command> `(table)` - array with arguments of full executed command.\n    - <git_subcommand> `(string)` - detected Git subcommand (like \"log\", etc.).\n    - <stderr> `(string)` - `stderr` process output.\n    - <stdout> `(string)` - `stdout` process output.\n\n- `MiniGitCommandSplit` - after command showed its output in a split. Triggered\n  after `MiniGitCommandDone` and provides similar `data` table with extra fields:\n    - <win_source> `(number)` - window identifier of \"source\" window (current at\n      the moment before command execution).\n    - <win_stdout> `(number)` - window identifier of command output.\n\n------------------------------------------------------------------------------\n                                                               *MiniGit.setup()*\n                           `MiniGit.setup`({config})\nModule setup\n\nBesides general side effects (see |mini.nvim|), it also:\n- Sets up auto enabling in every normal buffer for an actual file on disk.\n- Creates |:Git| command.\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniGit.config|.\n\nUsage ~\n>lua\n  require('mini.git').setup() -- use default config\n  -- OR\n  require('mini.git').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                                *MiniGit.config*\n                                `MiniGit.config`\nDefaults ~\n>lua\n  MiniGit.config = {\n    -- General CLI execution\n    job = {\n      -- Path to Git executable\n      git_executable = 'git',\n\n      -- Timeout (in ms) for each job before force quit\n      timeout = 30000,\n    },\n\n    -- Options for `:Git` command\n    command = {\n      -- Default split direction\n      split = 'auto',\n    },\n  }\n<\n# Job ~\n\n`config.job` contains options for customizing CLI executions.\n\n`job.git_executable` defines a full path to Git executable. Default: \"git\".\n\n`job.timeout` is a duration (in ms) from job start until it is forced to stop.\nDefault: 30000.\n\n# Command ~\n\n`config.command` contains options for customizing |:Git| command.\n\n`command.split` defines default split direction for |:Git| command output. Can be\none of \"horizontal\", \"vertical\", \"tab\", or \"auto\". Value \"auto\" uses |:vertical|\nif only 'mini.git' buffers are shown in the tabpage and |:tab| otherwise.\nDefault: \"auto\".\n\n------------------------------------------------------------------------------\n                                                      *MiniGit.show_at_cursor()*\n                        `MiniGit.show_at_cursor`({opts})\nShow Git related data at cursor\n\n- If inside |mini.deps| confirmation buffer, show in split relevant commit data.\n- If there is a commit-like |<cword>|, show it in split.\n- If possible, show diff source via |MiniGit.show_diff_source()|.\n- If possible, show range history via |MiniGit.show_range_history()|.\n- Otherwise throw an error.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible values:\n  - <split> `(string)` - split direction. One of \"horizontal\", \"vertical\",\n    \"tab\", or \"auto\" (default). Value \"auto\" uses |:vertical| if only 'mini.git'\n    buffers are shown in the tabpage and |:tab| otherwise.\n  - Fields appropriate for forwarding to other functions.\n\n------------------------------------------------------------------------------\n                                                    *MiniGit.show_diff_source()*\n                       `MiniGit.show_diff_source`({opts})\nShow diff source\n\nWhen buffer contains text formatted as unified patch (like after\n`:Git log --patch`, `:Git diff`, or |MiniGit.show_range_history()|),\nshow state of the file at the particular state. Target commit/state, path,\nand line number are deduced from cursor position.\n\nNotes:\n- Needs |current-directory| to be the Git root for relative paths to work.\n- Needs cursor to be inside hunk lines or on \"---\" / \"+++\" lines with paths.\n- Only basic forms of `:Git diff` output is supported: `:Git diff`,\n  `:Git diff --cached`, and `:Git diff <commit>`.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible values:\n  - <split> `(string)` - split direction. One of \"horizontal\", \"vertical\",\n    \"tab\", or \"auto\" (default). Value \"auto\" uses |:vertical| if only 'mini.git'\n    buffers are shown in the tabpage and |:tab| otherwise.\n  - <target> `(string)` - which file state to show. One of \"before\", \"after\",\n    \"both\" (both states in vertical split), \"auto\" (default). Value \"auto\"\n    shows \"before\" state if cursor line starts with \"-\", otherwise - \"after\".\n\n------------------------------------------------------------------------------\n                                                  *MiniGit.show_range_history()*\n                      `MiniGit.show_range_history`({opts})\nShow range history\n\nCompute and show in split data about how particular line range in current\nbuffer evolved through Git history. Essentially a `git log` with `-L` flag.\n\nNotes:\n- Works well with |MiniGit.diff_foldexpr()|.\n- Does not work if there are uncommited changes, as there is no easy way to\n  compute effective range line numbers.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <line_start> `(number)` - range start line.\n  - <line_end> `(number)` - range end line.\n    If both <line_start> and <line_end> are not supplied, they default to\n    current line in Normal mode and visual selection in Visual mode.\n  - <log_args> `(table)` - array of options to append to `git log` call.\n  - <split> `(string)` - split direction. One of \"horizontal\", \"vertical\",\n    \"tab\", or \"auto\" (default). Value \"auto\" uses |:vertical| if only 'mini.git'\n    buffers are shown in the tabpage and |:tab| otherwise.\n\n------------------------------------------------------------------------------\n                                                       *MiniGit.diff_foldexpr()*\n                        `MiniGit.diff_foldexpr`({lnum})\nFold expression for Git logs\n\nFolds contents of hunks, file patches, and log entries in unified diff.\nUseful for filetypes \"diff\" (like after `:Git diff`) and \"git\" (like after\n`:Git log --patch` or `:Git show` for commit).\nWorks well with |MiniGit.show_range_history()|.\n\nGeneral idea of folding levels (use |zr| and |zm| to adjust interactively):\n- At level 0 there is one line per whole patch or log entry.\n- At level 1 there is one line per patched file.\n- At level 2 there is one line per hunk.\n- At level 3 there is no folds.\n\nFor automated setup, set the following for \"git\" and \"diff\" filetypes (either\ninside |FileType| autocommand or |ftplugin|): >vim\n\n  setlocal foldmethod=expr foldexpr=v:lua.MiniGit.diff_foldexpr()\n<\nParameters ~\n{lnum} `(number|nil)` Line number for which fold level is computed.\n  Default: |v:lnum|.\n\nReturn ~\n`(number|string)` Line fold level. See |fold-expr|.\n\n------------------------------------------------------------------------------\n                                                              *MiniGit.enable()*\n                           `MiniGit.enable`({buf_id})\nEnable Git tracking in a file buffer\n\nTracking is done by reacting to changes in file content or file's repository\nin the form of keeping buffer data up to date. The data can be used via:\n- |MiniGit.get_buf_data()|. See its help for a list of actually tracked data.\n- `vim.b.minigit_summary` (table) and `vim.b.minigit_summary_string` (string)\n  buffer-local variables which are more suitable for statusline.\n  `vim.b.minigit_summary_string` contains information about HEAD, file status,\n  and in progress action (see |MiniGit.get_buf_data()| for more details).\n  See |MiniGit-examples| for how it can be tweaked and used in statusline.\n\nNote: this function is called automatically for all new normal buffers.\nUse it explicitly if buffer was disabled.\n\n`User` event `MiniGitUpdated` is triggered whenever tracking data is updated.\nNote that not all data listed in |MiniGit.get_buf_data()| can be present (yet)\nat the point of event being triggered.\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                             *MiniGit.disable()*\n                          `MiniGit.disable`({buf_id})\nDisable Git tracking in buffer\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                              *MiniGit.toggle()*\n                           `MiniGit.toggle`({buf_id})\nToggle Git tracking in buffer\n\nEnable if disabled, disable if enabled.\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                        *MiniGit.get_buf_data()*\n                        `MiniGit.get_buf_data`({buf_id})\nGet buffer data\n\nParameters ~\n{buf_id} `(number)` Target buffer identifier. Default: 0 for current buffer.\n\nReturn ~\n`(table|nil)` Table with buffer Git data or `nil` if buffer is not enabled.\n  If the file is not part of Git repo, table will be empty.\n  Table has the following fields:\n  - <repo> `(string)` - full path to '.git' directory.\n  - <root> `(string)` - full path to worktree root.\n  - <head> `(string)` - full commit of current HEAD.\n  - <head_name> `(string)` - short name of current HEAD (like \"master\").\n    For detached HEAD it is \"HEAD\".\n  - <status> `(string)` - two character file status as returned by `git status`.\n  - <in_progress> `(string)` - name of action(s) currently in progress\n    (bisect, merge, etc.). Can be a combination of those separated by \",\".\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-hipatterns.txt",
    "content": "*mini.hipatterns* Highlight patterns in text\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                *MiniHipatterns*\nFeatures:\n- Highlight text with configurable patterns and highlight groups (can be\n  string or callable).\n\n- Highlighting is updated asynchronously with configurable debounce delay.\n\n- Function to get matches in a buffer (see |MiniHipatterns.get_matches()|).\n\nSee |MiniHipatterns-examples| for common configuration examples.\n\nNotes:\n- It does not define any highlighters by default. Add to `config.highlighters`\n  to have a visible effect.\n\n- Sometimes (especially during frequent buffer updates on same line numbers)\n  highlighting can be outdated or not applied when it should be. This is due\n  to asynchronous nature of updates reacting to text changes (via\n  `on_lines` of |nvim_buf_attach()|).\n  To make them up to date, use one of the following:\n    - Scroll window (for example, with |CTRL-E| / |CTRL-Y|). This will ensure\n      up to date highlighting inside window view.\n    - Hide and show buffer.\n    - Execute `:edit` (if you enabled highlighting with |MiniHipatterns.setup()|).\n    - Manually call |MiniHipatterns.update()|.\n\n- If you experience flicker when typing near highlighted pattern in Insert\n  mode, it might be due to `delay` configuration of |mini.completion| or\n  using built-in completion.\n  For better experience with 'mini.completion', make sure that its\n  `delay.completion` is less than this module's `delay.text_change` (which\n  it is by default).\n  The reason for this is (currently unresolvable) limitations of Neovim's\n  built-in completion implementation.\n\n# Setup ~\n\nSetting up highlights can be done in two ways:\n- Manually for every buffer with `require('mini.hipatterns').enable()`.\n  This will enable highlighting only in one particular buffer until it is\n  unloaded (which also includes calling `:edit` on current file).\n\n- Globally with `require('mini.hipatterns').setup({})` (replace `{}` with\n  your `config` table). This will auto-enable highlighting in \"normal\"\n  buffers (see 'buftype'). Use |MiniHipatterns.enable()| to manually enable\n  in other buffers.\n  It will also create global Lua table `MiniHipatterns` which you can use\n  for scripting or manually (with `:lua MiniHipatterns.*`).\n\nSee |MiniHipatterns.config| for `config` structure and default values.\n\nYou can override runtime config settings (like highlighters and delays)\nlocally to buffer inside `vim.b.minihipatterns_config` which should have\nsame structure as `MiniHipatterns.config`.\nSee |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [folke/todo-comments](https://github.com/folke/todo-comments):\n    - Oriented for \"TODO\", \"NOTE\", \"FIXME\" like patterns, while this module\n      can work with any Lua patterns and computable highlight groups.\n    - Has functionality beyond text highlighting (sign placing,\n      \"telescope.nvim\" extension, etc.), while this module only focuses on\n      highlighting text.\n- [folke/paint.nvim](https://github.com/folke/paint.nvim):\n    - Mostly similar to this module, but with slightly less functionality,\n      such as computed pattern and highlight group, asynchronous delay, etc.\n- [NvChad/nvim-colorizer.lua](https://github.com/NvChad/nvim-colorizer.lua):\n    - Oriented for color highlighting, while this module can work with any\n      Lua patterns and computable highlight groups.\n    - Has more built-in color spaces to highlight, while this module out of\n      the box provides only hex color highlighting\n      (see |MiniHipatterns.gen_highlighter.hex_color()|). Other types are\n      also possible to implement.\n- [uga-rosa/ccc.nvim](https://github.com/uga-rosa/ccc.nvim):\n    - Has more than color highlighting functionality, which is compared to\n      this module in the same way as 'NvChad/nvim-colorizer.lua'.\n\n# Highlight groups ~\n\n- `MiniHipatternsFixme` - suggested group to use for `FIXME`-like patterns.\n- `MiniHipatternsHack` - suggested group to use for `HACK`-like patterns.\n- `MiniHipatternsTodo` - suggested group to use for `TODO`-like patterns.\n- `MiniHipatternsNote` - suggested group to use for `NOTE`-like patterns.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nThis module can be disabled in three ways:\n- Globally: set `vim.g.minihipatterns_disable` to `true`.\n- Locally for buffer permanently: set `vim.b.minihipatterns_disable` to `true`.\n- Locally for buffer temporarily (until next auto-enabling event if set up\n  with |MiniHipatterns.setup()|): call |MiniHipatterns.disable()|.\n\nConsidering high number of different scenarios and customization\nintentions, writing exact rules for disabling module's functionality is\nleft to user. See |mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                       *MiniHipatterns-examples*\n# Common configuration examples ~\n\n- Special words used to convey different level of attention: >lua\n\n  require('mini.hipatterns').setup({\n    highlighters = {\n      fixme = { pattern = 'FIXME', group = 'MiniHipatternsFixme' },\n      hack  = { pattern = 'HACK',  group = 'MiniHipatternsHack'  },\n      todo  = { pattern = 'TODO',  group = 'MiniHipatternsTodo'  },\n      note  = { pattern = 'NOTE',  group = 'MiniHipatternsNote'  },\n    }\n  })\n<\n- To match only when pattern appears as a standalone word, use frontier\n  patterns `%f`. For example, instead of `'TODO'` pattern use\n  `'%f[%w]()TODO()%f[%W]'`. In this case, for example, 'TODOING' or 'MYTODO'\n  won't match, but 'TODO' and 'TODO:' will.\n\n- Color hex (like `#rrggbb`) highlighting: >lua\n\n  local hipatterns = require('mini.hipatterns')\n  hipatterns.setup({\n    highlighters = {\n      hex_color = hipatterns.gen_highlighter.hex_color(),\n    }\n  })\n<\n  You can customize which part of hex color is highlighted by using `style`\n  field of input options. See |MiniHipatterns.gen_highlighter.hex_color()|.\n\n- Colored words: >lua\n\n  local words = { red = '#ff0000', green = '#00ff00', blue = '#0000ff' }\n  local word_color_group = function(_, match)\n    local hex = words[match]\n    if hex == nil then return nil end\n    return MiniHipatterns.compute_hex_color_group(hex, 'bg')\n  end\n\n  local hipatterns = require('mini.hipatterns')\n  hipatterns.setup({\n    highlighters = {\n      word_color = { pattern = '%S+', group = word_color_group },\n    },\n  })\n<\n- Trailing whitespace (if don't want to use more specific |mini.trailspace|): >lua\n\n  { pattern = '%f[%s]%s*$', group = 'Error' }\n<\n- Censor certain sensitive information: >lua\n\n  local censor_extmark_opts = function(_, match, _)\n    local mask = string.rep('x', vim.fn.strchars(match))\n    return {\n      virt_text = { { mask, 'Comment' } }, virt_text_pos = 'overlay',\n      priority = 200, right_gravity = false,\n    }\n  end\n\n  require('mini.hipatterns').setup({\n    highlighters = {\n      censor = {\n        pattern = 'password: ()%S+()',\n        group = '',\n        extmark_opts = censor_extmark_opts,\n      },\n    },\n  })\n<\n- Enable only in certain filetypes. There are at least these ways to do it:\n    - (Suggested) With `vim.b.minihipatterns_config` in |filetype-plugin|.\n      Basically, create \"after/ftplugin/<filetype>.lua\" file in your config\n      directory (see |$XDG_CONFIG_HOME|) and define `vim.b.minihipatterns_config`\n      there with filetype specific highlighters.\n\n      This assumes `require('mini.hipatterns').setup()` call.\n\n      For example, to highlight keywords in EmmyLua comments in Lua files,\n      create \"after/ftplugin/lua.lua\" with the following content: >lua\n\n        vim.b.minihipatterns_config = {\n          highlighters = {\n            emmylua = { pattern = '^%s*%-%-%-()@%w+()', group = 'Special' }\n          }\n        }\n<\n    - Use callable `pattern` with condition. For example: >lua\n\n      require('mini.hipatterns').setup({\n        highlighters = {\n          emmylua = {\n            pattern = function(buf_id)\n              if vim.bo[buf_id].filetype ~= 'lua' then return nil end\n              return '^%s*%-%-%-()@%w+()'\n            end,\n            group = 'Special',\n          },\n        },\n      })\n<\n- Disable only in certain filetypes. Enable with |MiniHipatterns.setup()|\n  and set `vim.b.minihipatterns_disable` buffer-local variable to `true` for\n  buffer you want disabled. See |mini.nvim-disabling-recipes| for more examples.\n\n------------------------------------------------------------------------------\n                                                        *MiniHipatterns.setup()*\n                        `MiniHipatterns.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniHipatterns.config|.\n\nUsage ~\n>lua\n  require('mini.hipatterns').setup({}) -- replace {} with your config table\n                                       -- needs `highlighters` field present\n<\n------------------------------------------------------------------------------\n                                                         *MiniHipatterns.config*\n                            `MiniHipatterns.config`\nDefaults ~\n>lua\n  MiniHipatterns.config = {\n    -- Table with highlighters (see |MiniHipatterns.config| for more details).\n    -- Nothing is defined by default. Add manually for visible effect.\n    highlighters = {},\n\n    -- Delays (in ms) defining asynchronous highlighting process\n    delay = {\n      -- How much to wait for update after every text change\n      text_change = 200,\n\n      -- How much to wait for update after window scroll\n      scroll = 50,\n    },\n  }\n<\n# Highlighters ~\n\n`highlighters` table defines which patterns will be highlighted by placing\n|extmark| at the match start. It might or might not have explicitly named\nfields, but having them is recommended and is required for proper use of\n`vim.b.minihipatterns_config` as buffer-local config. By default it is\nempty expecting user definition.\n\nEach entry defines single highlighter as a table with the following fields:\n- <pattern> `(string|function|table)` - Lua pattern to highlight. Can be\n  either string, callable returning the string, or an array of those.\n  If string:\n    - It can have submatch delimited by placing `()` on start and end, NOT\n      by surrounding it with parenthesis (results in an error containing\n      `number expected, got string`). Example: `xx()abcd()xx` will match\n      `abcd` only if `xx` is placed before and after it.\n\n  If callable:\n    - It will be called for every enabled buffer with its identifier as input.\n      Should return single string pattern or `nil` (meaning this particular\n      highlighter will not work in this particular buffer).\n\n  If array:\n    - Each element is matched and highlighted with the same highlight group.\n\n    Note: matching does not result in overlapping (sub)matches (similarly\n    to how |cpo-c| works). For example, with line `xxxxxxx`:\n    - Pattern `xxx` matches columns 1-3, 4-6.\n    - Pattern `()xx()x` matches columns 1-2, 3-4, 5-6.\n    - Pattern `x()xx()` matches columns 2-3, 5-6.\n    - Pattern `x()x()x` matches columns 2-2, 4-4, 6-6.\n\n- <group> `(string|function)` - name of highlight group to use. Can be either\n  string or callable returning the string.\n  If callable:\n    - It will be called for every pattern match with the following arguments:\n        - `buf_id` - buffer identifier.\n        - `match` - string pattern match to be highlighted.\n        - `data` - extra table with information about the match.\n          It has at least these fields:\n            - <full_match> - string with full pattern match.\n            - <line> - match line number (1-indexed).\n            - <from_col> - match starting byte column (1-indexed).\n            - <to_col> - match ending byte column (1-indexed, inclusive).\n\n    - It can return `nil` meaning this particular match will not be highlighted.\n\n- <extmark_opts> `(table|function|nil)` - optional extra options\n  for |nvim_buf_set_extmark()|. If callable, will be called in the same way\n  as callable <group> (`data` will also contain `hl_group` key with <group>\n  value) and should return a table with all options for extmark (including\n  `end_row`, `end_col`, `hl_group`, and `priority`).\n\nSee \"Common use cases\" section for the examples.\n\n# Delay ~\n\n`delay` is a table defining delays in milliseconds used for asynchronous\nhighlighting process.\n\n`delay.text_change` is used to delay highlighting updates by accumulating\nthem (in debounce fashion). Smaller values will lead to faster response but\nmore frequent updates. Bigger - slower response but less frequent updates.\n\n`delay.scroll` is used to delay updating highlights in current window view\nduring scrolling (see |WinScrolled| event). These updates are present to\nensure up to date highlighting after scroll.\n\n------------------------------------------------------------------------------\n                                                       *MiniHipatterns.enable()*\n                  `MiniHipatterns.enable`({buf_id}, {config})\nEnable highlighting in buffer\n\nNotes:\n- With default config it will highlight nothing, as there are no default\n  highlighters.\n\n- Buffer highlighting is enabled until buffer is unloaded from memory\n  or |MiniHipatterns.disable()| on this buffer is called.\n\n- `:edit` disables this, as it is mostly equivalent to closing and opening\n  buffer. In order for highlighting to persist after `:edit`, call\n  |MiniHipatterns.setup()|.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier in which to enable highlighting.\n  Default: 0 for current buffer.\n{config} `(table|nil)` Optional buffer-local config. Should have the same\n  structure as |MiniHipatterns.config|. Values will be taken in this order:\n  - From this `config` argument (if supplied).\n  - From buffer-local config in `vim.b.minihipatterns_config` (if present).\n  - From global config (if |MiniHipatterns.setup()| was called).\n  - From default values.\n\n------------------------------------------------------------------------------\n                                                      *MiniHipatterns.disable()*\n                       `MiniHipatterns.disable`({buf_id})\nDisable highlighting in buffer\n\nNote that if |MiniHipatterns.setup()| was called, the effect is present\nuntil the next auto-enabling event. To permanently disable highlighting in\nbuffer, set `vim.b.minihipatterns_disable` to `true`\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier in which to enable highlighting.\n  Default: 0 for current buffer.\n\n------------------------------------------------------------------------------\n                                                       *MiniHipatterns.toggle()*\n                  `MiniHipatterns.toggle`({buf_id}, {config})\nToggle highlighting in buffer\n\nCall |MiniHipatterns.disable()| if enabled; |MiniHipatterns.enable()| otherwise.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier in which to enable highlighting.\n  Default: 0 for current buffer.\n{config} `(table|nil)` Forwarded to |MiniHipatterns.enable()|.\n\n------------------------------------------------------------------------------\n                                                       *MiniHipatterns.update()*\n           `MiniHipatterns.update`({buf_id}, {from_line}, {to_line})\nUpdate highlighting in range\n\nWorks only in buffer with enabled highlighting. Effect takes immediately\nwithout delay.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier in which to enable highlighting.\n  Default: 0 for current buffer.\n{from_line} `(number|nil)` Start line from which to update (1-indexed).\n{to_line} `(number|nil)` End line from which to update (1-indexed, inclusive).\n\n------------------------------------------------------------------------------\n                                          *MiniHipatterns.get_enabled_buffers()*\n                     `MiniHipatterns.get_enabled_buffers`()\nGet an array of enabled buffers\n\nReturn ~\n`(table)` Array of buffer identifiers with enabled highlighting.\n\n------------------------------------------------------------------------------\n                                                  *MiniHipatterns.get_matches()*\n             `MiniHipatterns.get_matches`({buf_id}, {highlighters})\nGet buffer matches\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier for which to return matches.\n  Default: `nil` for current buffer.\n{highlighters} `(table|nil)` Array of highlighter identifiers (as in\n  `highlighters` field of |MiniHipatterns.config|) for which to return matches.\n  Default: all available highlighters (ordered by string representation).\n\nReturn ~\n`(table)` Array of buffer matches which are tables with following fields:\n  - <bufnr> `(number)` - buffer identifier of a match.\n  - <highlighter> `(any)` - highlighter identifier which produced the match.\n  - <lnum> `(number)` - line number of the match start (starts with 1).\n  - <col> `(number)` - column number of the match start (starts with 1).\n  - <end_lnum> `(number|nil)` - line number of the match end (starts with 1).\n  - <end_col> `(number|nil)` - column number next to the match end\n    (implements end-exclusive region; starts with 1).\n  - <hl_group> `(string|nil)` - name of match's highlight group.\n\n  Matches are ordered first by supplied `highlighters`, then by line and\n  column of match start.\n\n------------------------------------------------------------------------------\n                                                *MiniHipatterns.gen_highlighter*\n                        `MiniHipatterns.gen_highlighter`\nGenerate builtin highlighters\n\nThis is a table with function elements. Call to actually get highlighter.\n\n------------------------------------------------------------------------------\n                                    *MiniHipatterns.gen_highlighter.hex_color()*\n               `MiniHipatterns.gen_highlighter.hex_color`({opts})\nHighlight hex color string\n\nThis will match color hex string in format `#rrggbb` and highlight it\naccording to `opts.style` displaying matched color.\n\nHighlight group is computed using |MiniHipatterns.compute_hex_color_group()|,\nso all its usage notes apply here.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <style> `(string)` - one of:\n      - `'full'` -  highlight background of whole hex string with it. Default.\n      - `'#'` - highlight background of only `#`.\n      - `'line'` - highlight underline with that color.\n      - `'inline'` - highlight text of <inline_text>.\n        Note: requires Neovim>=0.10.\n  - <priority> `(number)` - priority of highlighting. Default: 200.\n  - <filter> `(function)` - callable object used to filter buffers in which\n    highlighting will take place. It should take buffer identifier as input\n    and return `false` or `nil` to not highlight inside this buffer.\n  - <inline_text> `(string)` - string to be placed and highlighted with color\n    to the right of match in case <style> is \"inline\". Default: \"█\".\n\nReturn ~\n`(table)` Highlighter table ready to be used as part of `config.highlighters`.\n  Both `pattern` and `group` are callable.\n\nUsage ~\n>lua\n  local hipatterns = require('mini.hipatterns')\n  hipatterns.setup({\n    highlighters = {\n      hex_color = hipatterns.gen_highlighter.hex_color(),\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                      *MiniHipatterns.compute_hex_color_group()*\n         `MiniHipatterns.compute_hex_color_group`({hex_color}, {style})\nCompute and create group to highlight hex color string\n\nNotes:\n- This works properly only with enabled |'termguicolors'|.\n\n- To increase performance, it caches highlight groups per `hex_color` and\n  `style` combination. Needs a call to |MiniHipatterns.setup()| to have\n  these groups be persistent across color scheme changes.\n\nParameters ~\n{hex_color} `(string)` Hex color string in format `#rrggbb`.\n{style|nil} `(string)` One of:\n  - `'bg'` - highlight background with `hex_color` and foreground with black or\n    white (whichever is more visible). Default.\n  - `'fg'` - highlight foreground with `hex_color`.\n  - `'line'` - highlight underline with `hex_color`.\n\nReturn ~\n`(string)` Name of created highlight group appropriate to show `hex_color`.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-hues.txt",
    "content": "*mini.hues* Generate configurable color scheme\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniHues*\nFeatures:\n- Required to set two base colors: background and foreground.\n  Their shades and other non-base colors are computed to be as much\n  perceptually different as reasonably possible.\n  See |MiniHues.config| for setup inspiration.\n\n- Configurable:\n    - Number of hues used for non-base colors (from 0 to 8).\n    - Saturation level (\"low\", \"lowmedium\", \"medium\", \"mediumhigh\", \"high\").\n    - Accent color used for some selected UI elements.\n    - Plugin integration (can be selectively enabled for faster startup).\n\n- Random generator for base colors. See |MiniHues.gen_random_base_colors()|.\n  Powers |randomhue| color scheme.\n\n- Lua function to compute palette used in color scheme.\n  See |MiniHues.make_palette()|.\n\n- Bundled color schemes. See |MiniHues-color-schemes|.\n\nSupported highlight groups:\n- All built-in UI and syntax groups.\n\n- Built-in Neovim LSP and diagnostic.\n\n- Tree-sitter (|treesitter-highlight-groups|).\n\n- LSP semantic tokens (|lsp-semantic-highlight|).\n\n- Plugins (either with explicit definition or by verification that default\n  highlighting works appropriately):\n    - [nvim-mini/mini.nvim](https://nvim-mini.org/mini.nvim)\n    - [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n    - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n    - [DanilaMihailov/beacon.nvim](https://github.com/DanilaMihailov/beacon.nvim)\n    - [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n    - [folke/noice.nvim](https://github.com/folke/noice.nvim)\n    - [folke/snacks.nvim](https://github.com/folke/snacks.nvim)\n    - [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n    - [folke/trouble.nvim](https://github.com/folke/trouble.nvim)\n    - [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n    - [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n    - [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n    - [glepnir/lspsaga.nvim](https://github.com/glepnir/lspsaga.nvim)\n    - [HiPhish/rainbow-delimiters.nvim](https://github.com/HiPhish/rainbow-delimiters.nvim)\n    - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n    - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n    - [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n    - [kevinhwang91/nvim-bqf](https://github.com/kevinhwang91/nvim-bqf)\n    - [kevinhwang91/nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n    - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n    - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n    - [MeanderingProgrammer/render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)\n    - [neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)\n    - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n    - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n    - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n    - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n    - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n    - [OXY2DEV/helpview.nvim](https://github.com/OXY2DEV/helpview.nvim)\n    - [OXY2DEV/markview.nvim](https://github.com/OXY2DEV/markview.nvim)\n    - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim)\n    - [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)\n    - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n    - [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n    - [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n    - [stevearc/aerial.nvim](https://github.com/stevearc/aerial.nvim)\n    - [williamboman/mason.nvim](https://github.com/williamboman/mason.nvim)\n\n# Setup ~\n\nThis module needs a setup with `require('mini.hues').setup({})` and\n**mandatory `background` and `foreground` fields** (add more fields to fit\nyour taste). It will create global Lua table `MiniHues` which you can use\nfor scripting or manually (with `:lua MiniHues.*`).\n\nSee |MiniHues.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minihues_config`\nwill have no effect here.\n\nExample:\n>\n  require('mini.hues').setup({\n    background = '#11262d',\n    foreground = '#c0c8cc',\n    plugins = {\n      default = false,\n      ['nvim-mini/mini.nvim'] = true,\n    },\n  })\n<\n# Notes ~\n\n- This is used to create some of plugin's color schemes\n  (see |MiniHues-color-schemes|).\n\n- Using `setup()` doesn't actually create a colorscheme. It basically\n  creates a coordinated set of |highlight-groups|. To create your own scheme:\n    - Put \"myscheme.lua\" file (name after your chosen theme name) inside\n      any \"colors\" directory reachable from 'runtimepath' (\"colors\" inside\n      your Neovim config directory is usually enough).\n    - Inside \"myscheme.lua\" call `require('mini.hues').setup()` with your\n      palette and only after that set |g:colors_name| to \"myscheme\".\n\n- This module doesn't define |cterm-colors| for implementation simplicity.\n  Use |mini.colors| module, |MiniColors-colorscheme:add_cterm_attributes()|\n  in particular.\n\n------------------------------------------------------------------------------\n                                                        *MiniHues-color-schemes*\nBundled color schemes\n\n- *miniwinter* : \"icy winter\" palette with azure background.\n- *minispring* : \"blooming spring\" palette with green background.\n- *minisummer* : \"hot summer\" palette with brown/yellow background.\n- *miniautumn* : \"cooling autumn\" palette with purple background.\n\n- *randomhue* : uses randomly generated same hue background and foreground.\n  Every `:colorscheme randomhue` call results in a different (randomly yet\n  carefully selected) colors.\n\n  It is essentially a combination of calls to |MiniHues.setup()| and\n  |MiniHues.gen_random_base_colors()| with a slight adjustments for\n  'background' value.\n\n  Activate it as regular |:colorscheme|. Get currently active config with\n  `:lua print(vim.inspect(MiniHues.config))`.\n\n------------------------------------------------------------------------------\n                                                              *MiniHues.setup()*\n                           `MiniHues.setup`({config})\nModule setup\n\nMain side effect is to create palette and apply it. Essentially, a combination\nof |MiniHues.make_palette()| and |MiniHues.apply_palette()|.\n\nUsage ~\n>lua\n  require('mini.hues').setup({\n    -- Use config table as you like\n    -- Needs both `background` and `foreground` fields present\n    background = '#11262d',\n    foreground = '#c0c8cc',\n  })\n<\n------------------------------------------------------------------------------\n                                                               *MiniHues.config*\n                               `MiniHues.config`\nDefaults ~\n>lua\n  MiniHues.config = {\n    -- **Required** base colors as '#rrggbb' hex strings\n    background = nil,\n    foreground = nil,\n\n    -- Number of hues used for non-base colors\n    n_hues = 8,\n\n    -- Saturation. One of 'low', 'lowmedium', 'medium', 'mediumhigh', 'high'.\n    saturation = 'medium',\n\n    -- Accent color. One of: 'bg', 'fg', 'red', 'orange', 'yellow', 'green',\n    -- 'cyan', 'azure', 'blue', 'purple'\n    accent = 'bg',\n\n    -- Plugin integrations. Use `default = false` to disable all integrations.\n    -- Also can be set per plugin (see |MiniHues.config|).\n    plugins = { default = true },\n\n    -- Whether to auto adjust highlight groups based on certain events\n    autoadjust = true,\n  }\n<\nSee |MiniHues.make_palette()| for more information about how certain settings\naffect output color scheme.\n\n# Plugin integrations ~\n\n`config.plugins` defines for which supported plugins highlight groups will\nbe created. Limiting number of integrations slightly decreases startup time.\nIt is a table with boolean (`true`/`false`) values which are applied as follows:\n- If plugin name (as listed in |mini.hues|) has entry, it is used.\n- Otherwise `config.plugins.default` is used.\n\nExample which will load only \"mini.nvim\" integration: >lua\n\n  require('mini.hues').setup({\n    background = '#11262d',\n    foreground = '#c0c8cc',\n    plugins = {\n      default = false,\n      ['nvim-mini/mini.nvim'] = true,\n    },\n  })\n<\n# Auto adjust ~\n\n`config.autoadjust` defines whether to adjust some highlight groups based on\nevents relevant to them. Currently adjusted groups:\n\n- |hl-MsgSeparator| is adjusted based on `msgsep` flag in |'fillchars'|.\n  If it is whitespace - highlight background, otherwise - foreground.\n\n- |hl-Pmenu| is adjusted based on |'pumborder'| value (on Neovim>=0.12).\n  If it results in a border - same as floating window (but with no accent\n  foreground in border), otherwise - same as |hl-CursorLine|. This design\n  makes |ins-completion-menu| stand out from regular floating windows.\n\n# Examples ~\n*MiniHues-examples*\n\nHere are some possible setup configurations (copy first line and then use\nonly one `setup` call): >lua\n\n  local setup = require('mini.hues').setup\n\n  -- Choose background and foreground\n  setup({ background = '#2f1c22', foreground = '#cdc4c6' }) -- red\n  setup({ background = '#2f1e16', foreground = '#cdc5c1' }) -- orange\n  setup({ background = '#282211', foreground = '#c9c6c0' }) -- yellow\n  setup({ background = '#1c2617', foreground = '#c4c8c2' }) -- green\n  setup({ background = '#112723', foreground = '#c0c9c7' }) -- cyan\n  setup({ background = '#11262d', foreground = '#c0c8cc' }) -- azure\n  setup({ background = '#1d2231', foreground = '#c4c6cd' }) -- blue\n  setup({ background = '#281e2c', foreground = '#c9c5cb' }) -- purple\n\n  -- Choose number of accent colors\n  setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 6 })\n  setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 4 })\n  setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 2 })\n  setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 0 })\n\n  -- Choose saturation of colored text\n  setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'low' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'lowmedium' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'medium' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'mediumhigh' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'high' })\n\n  -- Choose accent color\n  setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'bg' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'red' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'yellow' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'cyan' })\n  setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'blue' })\n<\n------------------------------------------------------------------------------\n                                                       *MiniHues.make_palette()*\n                       `MiniHues.make_palette`({config})\n# Make palette ~\n\nGeneral idea of palette generation is that it is mostly based on color channel\ninformation extracted from base colors (background and foreground).\n\nAll operations are done inside `Oklch` color space, meaning that each color\nis defined by three numbers:\n- Lightness (`l`) - number between 0 (black) and 100 (white) describing how\n  light is a color.\n- Chroma (`c`) - positive number describing how colorful is a color (bigger\n  values - more colorful; 0 is gray).\n- Hue (`h`) - periodic number in [0, 360) describing a value of \"true color\"\n  on color circle/wheel.\n\nFor more details about `Oklch` see |MiniColors-color-spaces| or\nhttps://bottosson.github.io/posts/oklab/.\n\n## Algorithm overview ~\n\n- Extract lightness, chroma, and hue of base colors.\n\n- Generate reference lightness values:\n    - Background edge: 0 or 100, whichever is closest to background lightness.\n    - Foreground edge: 0 or 100, different from background edge.\n    - Middle: arithmetic mean of background and foreground lightness values.\n\n- Compute background and foreground tints and shades by changing lightness\n  of background color: two colors closer to background lightness edge and\n  two closer to middle.\n\n- Pick chroma value for non-base colors based on `config.saturation`.\n\n- Generate hues for non-base colors:\n    - Fit an equidistant circular grid with `config.n_hues` points to be as\n      far from both background and foreground hues. This will ensure that\n      non-base colors are as different as possible from base ones (for\n      better visual perception).\n      Example: for background hue 0, foreground hue 180, and `config.n_hues` 2\n      the output grid will be `{ 90, 270 }`.\n\n    - For each hue of reference color (which itself is an equidistant grid\n      of 8 hues) compute the closest value from the grid. This allows\n      operating in same terms (like \"red\", \"green\") despite maybe actually\n      having less different hues.\n\n- Compute for each hue two variants of non-base colors: with background and\n  foreground lightness values.\n\n- Compute two variants of accent color (with background and foreground\n  lightness) based on `config.accent`.\n\nNotes:\n- Some output colors can have not exact values of generated Oklch channels.\n  This is due to actually computed colors being impossible to represent via\n  '#rrggbb' hex string. In this case a process called gamut clipping is done\n  to reduce lightness and chroma in optimal way while maintaining same hue.\n  For more information see |MiniColors-gamut-clip|.\n\n- Not all colors are actually used in highlight groups and are present for the\n  sake of completeness.\n\nParameters ~\n{config} `(table)` Configuration for palette. Same structure as |MiniHues.config|.\n  Needs to have <background> and <foreground> fields.\n\nReturn ~\n`(table)` Palette with the following fields:\n  - <bg> and <fg> with supplied `background` and `foreground` colors.\n  - Fields like <bg_xxx> and <fg_xxx> are essentially <bg> and <fg> but with\n    different lightness values: `_edge`/`_edge2` - closer to edge lightness,\n    `_mid`/`_mid2` - closer to middle lightness.\n  - Fields for non-base colors (<red>, <orange>, <yellow>, <green>, <cyan>,\n    <azure>, <blue>, <purple>) have the same lightness as foreground.\n  - Fields for non-base colors with <_bg> suffix have the same lightness as\n    background.\n  - <accent> and <accent_bg> represent accent colors with foreground and\n    background lightness values.\n\nSee also ~\n|MiniHues.get_palette()|\n\n------------------------------------------------------------------------------\n                                                      *MiniHues.apply_palette()*\n             `MiniHues.apply_palette`({palette}, {plugins}, {opts})\nApply palette\n\nCreate color scheme highlight groups and terminal colors based on supplied\npalette. This is useful if you want to tweak palette colors.\nFor regular usage prefer |MiniHues.setup()|.\n\nParameters ~\n{palette} `(table)` Table with structure as |MiniHues.make_palette()| output.\n{plugins} `(table|nil)` Table with boolean values indicating whether to create\n  highlight groups for specific plugins. See |MiniHues.config| for more details.\n  Default: the value from |MiniHues.config|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <autoadjust> - whether to auto adjust some highlight groups when needed.\n    Default: value of `autoadjust` in |MiniHues.config|.\n\nUsage ~\n>lua\n  local palette = require('mini.hues').make_palette({\n    background = '#11262d',\n    foreground = '#c0c8cc',\n  })\n  palette.cyan = '#76e0a6'\n  palette.cyan_bg = '#004629'\n  require('mini.hues').apply_palette(palette)\n<\nSee also ~\n|MiniHues.get_palette()|\n\n------------------------------------------------------------------------------\n                                                        *MiniHues.get_palette()*\n                            `MiniHues.get_palette`()\nGet latest applied palette\n\nReturn ~\n`(table)` Table with structure as |MiniHues.make_palette()| output that was\n  the latest applied (via |MiniHues.apply_palette()|) palette.\n\n------------------------------------------------------------------------------\n                                             *MiniHues.gen_random_base_colors()*\n                   `MiniHues.gen_random_base_colors`({opts})\nGenerate random base colors\n\nCompute background and foreground colors based on randomly generated hue\nand heuristically picked lightness-chroma values.\n\nYou can recreate a similar functionality but tweaked to your taste\nusing |mini.colors|: >\n\n  local convert = require('mini.colors').convert\n  local hue = math.random(0, 359)\n  return {\n    background = convert({ l = 15, c = 3, h = hue }, 'hex'),\n    foreground = convert({ l = 80, c = 1, h = hue }, 'hex'),\n  }\n\nNotes:\n- Respects 'background' (uses different lightness and chroma values for\n  \"dark\" and \"light\" backgrounds).\n\n- When used during startup, might require usage of `math.randomseed()` for\n  proper random generation. For example: >\n\n  local hues = require('mini.hues')\n  math.randomseed(vim.loop.hrtime())\n  hues.setup(hues.gen_random_base_colors())\n\nParameters ~\n{opts} `(table|nil)` Options. Possible values:\n  - <gen_hue> `(function)` - callable which will return single number for\n    output hue. Can be used to limit which hues will be generated.\n    Default: random integer between 0 and 359.\n\nReturn ~\n`(table)` Table with <background> and <foreground> fields containing\n  color hex strings.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-icons.txt",
    "content": "*mini.icons* Icon provider\n\nMIT License Copyright (c) 2024 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                     *MiniIcons*\nFeatures:\n\n- Provide icons with their highlighting via a single |MiniIcons.get()| for\n  various categories: filetype, file/directory path, extension, operating\n  system, LSP kind values. Icons and category defaults can be overridden.\n\n- Configurable styles: \"glyph\" (icon glyphs) or \"ascii\" (non-glyph fallback).\n\n- Fixed set of highlight groups (linked to built-in groups by default) for\n  better blend with color scheme.\n\n- Caching for maximum performance.\n\n- Integration with |vim.filetype.add()| and |vim.filetype.match()|.\n\n- Mocking methods of 'nvim-tree/nvim-web-devicons' for better integrations\n  with plugins outside 'mini.nvim'. See |MiniIcons.mock_nvim_web_devicons()|.\n\n- Tweaking built-in maps for \"LSP kind\" to include icons. In particular, this\n  makes |mini.completion| use icons in LSP step. See |MiniIcons.tweak_lsp_kind()|.\n\nNotes:\n\n- It is not a goal to become a collection of icons for as much use cases as\n  possible. There are specific criteria for icon data to be included as\n  built-in in each category (see |MiniIcons.get()|).\n  The main supported category is \"filetype\".\n\nRecommendations for plugin authors using 'mini.icons' as a dependency:\n\n- Check if `_G.MiniIcons` table is present (which means that user explicitly\n  enabled 'mini.icons') and provide icons only if it is.\n\n- Use |MiniIcons.get()| function to get icon string and more data about it.\n\n- For file icons prefer using full path instead of relative or only basename.\n  It makes a difference if path matches pattern that uses parent directories.\n  The |MiniIcons.config| has an example of that.\n\n# Dependencies ~\n\nSuggested dependencies:\n\n- Terminal emulator that supports showing special utf8 glyphs, possibly with\n  \"overflow\" view (displaying is done not in one but two visual cells).\n  Most modern feature-rich terminal emulators support this out of the box:\n  WezTerm, Kitty, Alacritty, iTerm2, Ghostty.\n  Not having \"overflow\" feature only results into smaller icons.\n  Not having support for special utf8 glyphs will result into seemingly\n  random symbols (or question mark squares) instead of icon glyphs.\n\n- Font that supports Nerd Fonts (https://www.nerdfonts.com) icons from\n  version 3.0.0+ (in particular `nf-md-*` class).\n  This should be configured on terminal emulator level either by using font\n  patched with Nerd Fonts icons or using `NerdFontsSymbolsOnly` font as\n  a fallback for glyphs that are not supported in main font.\n\nIf using terminal emulator and/or font with icon support is impossible, use\n`config.style = 'ascii'`. It will use a (less visually appealing) set of\nnon-glyph icons.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.icons').setup({})` (replace `{}`\nwith your `config` table). It will create global Lua table `MiniIcons` which you\ncan use for scripting or manually (with `:lua MiniIcons.*`).\n\nSee |MiniIcons.config| for `config` structure and default values.\n\n# Comparisons ~\n\n- [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) (for users):\n    - Sets individual colors to each icon with separate specific highlight\n      groups, while this modules uses fixed set of highlight groups.\n      This makes it easier to customize in bulk and actually blend with any\n      color scheme.\n\n    - This module prefers richer set of `nf-md-*` (from \"Material design\" set)\n      Nerd Fonts icons while 'nvim-web-devicons' mostly prefers `nf-dev-*`\n      (from \"devicons\" set).\n\n    - Supported categories are slightly different (with much overlap).\n\n    - Both support customization of any icon. Only this module supports\n      customization of default ones per supported category.\n\n    - Using this module can occasionally result in small delays when used\n      synchronously for many times to get icons for not typical files (like\n      in |mini.files|). This is due to using |vim.filetype.match()| fallback and\n      is present only during first call, as value is cached for later uses.\n\n    - This module supports different icon styles (like \"ascii\" for when using\n      glyphs is not possible), while 'nvim-web-devicons' does not.\n\n    - This module provides |MiniIcons.mock_nvim_web_devicons()| function which\n      when called imitates installed 'nvim-web-devicons' plugin to support\n      other plugins which do not provide 'mini.icons' yet.\n\n- [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) (for plugin developers):\n    - Both have main \"get icon\" type of function:\n        - Both return tuple of icon and highlight group strings.\n\n        - This module always returns icon data possibly falling back to\n          user's configured default, while 'nvim-web-devicons' is able to\n          return `nil`. This module's approach is more aligned with the most\n          common use case of always showing an icon instead or near some data.\n          There is a third returned value indicating if output is a result of\n          a fallback (see |MiniIcons.get()|).\n\n        - This module uses |vim.filetype.match()| as a fallback for \"file\"\n          and \"extension\" categories, while 'nvim-web-devicons' completely\n          relies on the manually maintained tables of supported filenames\n          and extensions.\n          Using fallback results in a wider support and deeper integration\n          with Neovim's filetype detection at the cost of occasional slower\n          first call. The difference is reduced as much as is reasonable by\n          preferring faster file extension resolution over filetype matching.\n\n        - This module caches all its return values resulting in really fast\n          next same argument calls, while 'nvim-web-devicons' doesn't do that.\n\n        - This module works with full file/directory paths as input.\n\n    - Different sets of supported categories (see |MiniIcons.config|):\n        - Both support \"file\", \"extension\", \"filetype\", \"operating system\".\n          Albeit in different volumes: 'nvim-web-devicons' covers more\n          cases for \"operating system\", while this module has better eventual\n          coverage for other cases.\n\n        - This module supports \"directory\" and \"lsp\" categories.\n\n        - 'nvim-web-devicons' covers \"desktop environment\" and \"window\n          management\" categories. This modules does not include them due to\n          relatively low demand.\n\n- [onsails/lspkind.nvim](https://github.com/onsails/lspkind.nvim):\n    - Provides icons only for `CompletionItemKind`, while this module also has\n      icons for `SymbolKind` and other non-LSP categories.\n    - Provides dedicated formatting function for 'hrsh7th/nvim-cmp' while this\n      module intentionally does not (adding icons should be straightforward\n      to manually implement while anything else is out of scope).\n\n# Highlight groups ~\n\nOnly the following set of highlight groups is used as icon highlight.\nIt is recommended that they all only define colored foreground:\n\n- `MiniIconsAzure`  - azure.\n- `MiniIconsBlue`   - blue.\n- `MiniIconsCyan`   - cyan.\n- `MiniIconsGreen`  - green.\n- `MiniIconsGrey`   - grey.\n- `MiniIconsOrange` - orange.\n- `MiniIconsPurple` - purple.\n- `MiniIconsRed`    - red.\n- `MiniIconsYellow` - yellow.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n------------------------------------------------------------------------------\n                                                             *MiniIcons.setup()*\n                          `MiniIcons.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniIcons.config|.\n\nUsage ~\n>lua\n  require('mini.icons').setup() -- use default config\n  -- OR\n  require('mini.icons').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                              *MiniIcons.config*\n                               `MiniIcons.config`\nDefaults ~\n>lua\n  MiniIcons.config = {\n    -- Icon style: 'glyph' or 'ascii'\n    style = 'glyph',\n\n    -- Customize per category. See `:h MiniIcons.config` for details.\n    default   = {},\n    directory = {},\n    extension = {},\n    file      = {},\n    filetype  = {},\n    lsp       = {},\n    os        = {},\n\n    -- Control which extensions will be considered during \"file\" resolution\n    use_file_extension = function(ext, file) return true end,\n  }\n<\n# Style ~\n\n`config.style` is a string defining which icon style to use. It can be:\n- `'glyph'` (default) - use glyph icons (like 󰈔 and 󰉋 ).\n- `'ascii'` - use fallback ASCII-compatible icons. Those are computed as\n  an upper first character of the icon's resolved name inside its category.\n  Examples: >lua\n\n    MiniIcons.get('file', 'Makefile') -- Has `'M'` as icon\n    MiniIcons.get('extension', 'lua') -- Has `'L'` as icon\n    MiniIcons.get('file', 'file.lua') -- Has `'L'` as icon; it is resolved to\n                                      -- come from 'lua' 'extension' category\n    MiniIcons.get('file', 'myfile')   -- Has `'F'` as icon; it is resolved to\n                                      -- come from 'file' 'default' category\n<\n# Customization per category ~\n\nThe following entries can be used to customize icons for supported categories:\n- `config.default`\n- `config.directory`\n- `config.extension`\n- `config.file`\n- `config.filetype`\n- `config.lsp`\n- `config.os`\n\nCustomization should be done by supplying a table with <glyph> (icon glyph)\nand/or <hl> (name of highlight group) string fields as a value for an icon\nname entry. Example: >lua\n\n  require('mini.icons').setup({\n    default = {\n      -- Override default glyph for \"file\" category (reuse highlight group)\n      file = { glyph = '󰈤' },\n    },\n    extension = {\n      -- Override highlight group (not necessary from 'mini.icons')\n      lua = { hl = 'Special' },\n\n      -- Add icons for custom extension. This will also be used in\n      -- 'file' category for input like 'file.my.ext'.\n      ['my.ext'] = { glyph = '󰻲', hl = 'MiniIconsRed' },\n    },\n  })\n<\nNotes:\n- These customizations only take effect inside |MiniIcons.setup()| call.\n  Changing interactively via `:lua MiniIcons.config.xxx = { ... }` does not work\n  for performance reasons.\n- Use lower case names for categories which are matched ignoring case.\n  See |MiniIcons.get()| for more details.\n\n# Using extension during file resolution ~\n\n`config.use_file_extension` is a function which can be used to control which\nextensions will be considered as a source of icon data during \"file\" category\nresolution (see |MiniIcons.get()| for more details).\nDefault: function which always returns `true` (i.e. consider all extensions).\n\nWill be called once for the biggest suffix after dot found in the file name.\nThe arguments will be `ext` (found extension; lowercase) and `file` (input for\nwhich icon is computed; as is). Should explicitly return `true` if `ext` is to\nbe considered (i.e. call `MiniIcons.get('extension', ext)` and use its\noutput if it is not default). Otherwise extension won't be even considered.\n\nThe primary use case for this setting is to ensure that some extensions are\nignored in order for resolution to reach |vim.filetype.match()| stage. This\nis needed if there is a set up filetype detection for files with recognizable\nextension and conflicting icons (which you want to use). Note: if problematic\nfiletype detection involves only known in advance file names, prefer using\n`config.file` customization.\n\nExample: >lua\n\n  -- Built-in filetype detection recognizes files like \"queries/.*%.scm\"\n  -- as \"query\" filetype. However, without special setup, 'mini.icons' will\n  -- use \"scm\" extension to resolve as Scheme file. Here is a setup to ignore\n  -- \"scm\" extension and completely rely on `vim.filetype.match()` fallback.\n  require('mini.icons').setup({\n    -- Check last letters explicitly to account for dots in file name\n    use_file_extension = function(ext) return ext:sub(-3) ~= 'scm' end\n  })\n\n  -- Another common choices for extensions to ignore: \"yml\", \"json\", \"txt\".\n<\n------------------------------------------------------------------------------\n                                                               *MiniIcons.get()*\n                      `MiniIcons.get`({category}, {name})\nGet icon data\n\nUsage example: >lua\n\n  -- Results into `icon='󰢱'`, `hl='MiniIconsAzure'`, `is_default=false`\n  local icon, hl, is_default = MiniIcons.get('file', 'file.lua')\n<\nNotes:\n- Always returns some data, even if icon name is not explicitly supported\n  within target category. Category \"default\" is used as a fallback. Use third\n  output value to check if this particular case is a result of a fallback.\n\n- Glyphs are explicitly preferred (when reasonable) from a richer set of\n  `nf-md-*` class  (\"Material design\" set) of Nerd Fonts icons.\n\n- Output is cached after the first call to increase performance of next calls\n  with same arguments. To reset cache, call |MiniIcons.setup()|.\n\n- To increase first call performance for \"extension\" and \"file\" categories,\n  add frequently used values in |MiniIcons.config|. They will be preferred\n  over executing |vim.filetype.match()|.\n\n- Matching icon name for \"file\" and \"directory\" categories is done exactly\n  and respecting case. Others are done ignoring case.\n\nParameters ~\n{category} `(string)` Category name. Supported categories:\n  - `'default'` - icon data used as fallback for any category.\n    Icon names:\n      - <Input>: any supported category name.\n      - <Built-in>: only supported category names.\n\n    Examples: >lua\n\n      MiniIcons.get('default', 'file')\n<\n  - `'directory'` - icon data for directory path.\n    Icon names:\n      - <Input>: any string, but only basename is used. Works with not present\n        paths (no check is done).\n      - <Built-in>: popular directory names not tied to language/software\n        (with few notable exceptions like Neovim, Git, etc.).\n\n    Examples: >lua\n\n      -- All of these will result in the same output\n      MiniIcons.get('directory', '.config')\n      MiniIcons.get('directory', '~/.config')\n      MiniIcons.get('directory', '/home/user/.config')\n\n      -- Results in different output\n      MiniIcons.get('directory', '.Config')\n<\n  - `'extension'` - icon data for extension.\n    Icon names:\n      - <Input>: any string (without extra dot prefix).\n      - <Built-in>: popular extensions without associated filetype plus a set\n        for which filetype detection gives not good enough result.\n\n    Icon data is attempted to be resolved in the following order:\n      - List of user configured and built-in extensions (for better results).\n        Run `:=MiniIcons.list('extension')` to see them.\n        Used also if present as suffix after the dot (widest one preferred).\n      - Filetype as a result of |vim.filetype.match()| with placeholder\n        file name. Uses icon data from \"filetype\" category.\n\n    Examples: >lua\n\n      -- All of these will result in the same output\n      MiniIcons.get('extension', 'lua')\n      MiniIcons.get('extension', 'LUA')\n      MiniIcons.get('extension', 'my.lua')\n<\n  - `'file'` - icon data for file path.\n    Icon names:\n      - <Input>: any string. Works with not present paths (no check is done).\n      - <Built-in>: popular file names not tied to language/software\n        (with few notable exceptions like Neovim, Git, etc.) plus a set which\n        has recognizable extension but has special detectable filetype.\n\n    Icon data is attempted to be resolved in the following order:\n      - List of user configured and built-in file names (matched to basename\n        of the input exactly). Run `:=MiniIcons.list('file')` to see them.\n      - Basename extension:\n          - Matched directly as `get('extension', ext)`, where `ext` is the\n            widest suffix after the dot.\n          - Considered only if `config.use_file_extension` returned `true`.\n          - Only recognizable extensions (i.e. not default fallback) are used.\n      - Filetype as a result of |vim.filetype.match()| with full input (not\n        basename) as `filename`. Uses icon data from \"filetype\" category.\n\n    Examples: >lua\n\n      -- All of these will result in the same output\n      MiniIcons.get('file', 'init.lua')\n      MiniIcons.get('file', '~/.config/nvim/init.lua')\n      MiniIcons.get('file', '/home/user/.config/nvim/init.lua')\n\n      -- Results in different output\n      MiniIcons.get('file', 'Init.lua')\n      MiniIcons.get('file', 'init.LUA')\n\n      -- Respects full path input in `vim.filetype.match()`\n      MiniIcons.get('file', '.git/info/attributes')\n<\n  - `'filetype'` - icon data for 'filetype' values.\n    Icon names:\n      - <Input>: any string.\n      - <Built-in>: any filetype that is reasonably used in Neovim ecosystem.\n        This category is intended as a widest net for supporting use cases.\n        Users are encouraged to have a specific filetype detection set up.\n\n    Examples: >lua\n\n      MiniIcons.get('filetype', 'lua')\n      MiniIcons.get('filetype', 'help')\n      MiniIcons.get('filetype', 'minifiles')\n<\n  - `'lsp'` - icon data for various \"LSP kind\" values.\n    Icon names:\n      - <Input>: any string.\n      - <Built-in>: only namesspace entries from LSP specification that are\n        can be displayed to user. Like `CompletionItemKind`, `SymbolKind`, etc.\n\n    Examples: >lua\n\n      MiniIcons.get('lsp', 'array')\n      MiniIcons.get('lsp', 'keyword')\n<\n  - `'os'` - icon data for popular operating systems.\n    Icon names:\n      - <Input>: any string.\n      - <Built-in>: only operating systems which have `nf-md-*` class icon.\n\n    Examples: >lua\n\n      MiniIcons.get('os', 'linux')\n      MiniIcons.get('os', 'arch')\n      MiniIcons.get('os', 'macos')\n<\n{name} `(string)` Icon name within category. Use |MiniIcons.list()| to get icon\n  names which are explicitly supported for specific category.\n\nReturn ~\n`(...)` Tuple of icon string, highlight group name it is suggested to be\n  highlighted with, and boolean indicating whether this icon was returned\n  as a result of fallback to default. Example: >lua\n\n  -- Results into `icon='󰢱'`, `hl='MiniIconsAzure'`, `is_default=false`\n  local icon, hl, is_default = MiniIcons.get('file', 'file.lua')\n\n  -- Results into `icon='󰈔'`, `hl='MiniIconsGrey'`, `is_default=true`\n  local icon, hl, is_default = MiniIcons.get('file', 'not-supported')\n<\n------------------------------------------------------------------------------\n                                                              *MiniIcons.list()*\n                          `MiniIcons.list`({category})\nList explicitly supported icon names\n\nParameters ~\n{category} `(string)` Category name supported by |MiniIcons.get()|.\n\nReturn ~\n`(table)` Array of icon names which are explicitly supported for category.\n  Note, that `'file'` and `'extension'` categories support much more icon names\n  via their fallback to using |vim.filetype.match()| with `'filetype'` category.\n\n------------------------------------------------------------------------------\n                                            *MiniIcons.mock_nvim_web_devicons()*\n                      `MiniIcons.mock_nvim_web_devicons`()\nMock 'nvim-web-devicons' module\n\nCall this function to mock exported functions of 'nvim-tree/nvim-web-devicons'\nplugin. It will mock all its functions which return icon data by\nusing |MiniIcons.get()| equivalent.\n\nThis function is useful if any plugins relevant to you depend solely on\n'nvim-web-devicons' and have not yet added an integration with 'mini.icons'.\n\nFull example of usage: >lua\n\n  require('mini.icons').setup()\n  MiniIcons.mock_nvim_web_devicons()\n<\nWorks without installed 'nvim-web-devicons' and even with it installed (needs\nto be called after 'nvim-web-devicons' is set up).\n\n------------------------------------------------------------------------------\n                                                    *MiniIcons.tweak_lsp_kind()*\n                       `MiniIcons.tweak_lsp_kind`({mode})\nTweak built-in LSP kind names\n\nUpdate in place appropriate maps in |vim.lsp.protocol| (`CompletionItemKind`\nand `SymbolKind`) by using icon strings from \"lsp\" category. Only \"numeric\nid to kind name\" part is updated (to preserve data from original map).\n\nUpdating is done in one of these modes:\n- Append:  add icon after text.\n- Prepend: add icon before text (default).\n- Replace: use icon instead of text.\n\nNotes:\n- Makes |mini.completion| show icons, as it uses built-in protocol map.\n- Results in loading whole `vim.lsp` module, so might add significant amount\n  of time on startup. Call it lazily. For example, with |MiniDeps.later()|: >lua\n\n    require('mini.icons').setup()\n    MiniDeps.later(MiniIcons.tweak_lsp_kind)\n<\nParameters ~\n{mode} `(string|nil)` One of \"prepend\" (default), \"append\", \"replace\".\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-indentscope.txt",
    "content": "*mini.indentscope* Visualize and work with indent scope\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                               *MiniIndentscope*\nIndent scope (or just \"scope\") is a maximum set of consecutive lines which\ncontains certain reference line (cursor line by default) and every member\nhas indent not less than certain reference indent (\"indent at cursor\" by\ndefault: minimum between cursor column and indent of cursor line).\n\nFeatures:\n- Visualize scope with animated vertical line. It is very fast and done\n  automatically in a non-blocking way (other operations can be performed,\n  like moving cursor). You can customize debounce delay and animation rule.\n\n- Customization of scope computation options can be done on global level\n  (in |MiniIndentscope.config|), for a certain buffer (using\n  `vim.b.miniindentscope_config` buffer variable), or within a call (using\n  `opts` variable in |MiniIndentscope.get_scope()|).\n\n- Customizable notion of a border: which adjacent lines with strictly lower\n  indent are recognized as such. This is useful for a certain filetypes\n  (for example, Python or plain text).\n\n- Customizable way of line to be considered \"border first\". This is useful\n  if you want to place cursor on function header and get scope of its body.\n\n- There are textobjects and motions to operate on scope. Support |count|\n  and dot-repeat (in operator pending mode).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.indentscope').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniIndentscope` which you can use for scripting or manually (with `:lua\nMiniIndentscope.*`).\n\nSee |MiniIndentscope.config| for available config settings.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.miniindentscope_config` which should have same structure as\n`MiniIndentscope.config`. See |mini.nvim-buffer-local-config| for more\ndetails.\n\n# Comparisons ~\n\n- [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim):\n    - Its main functionality is about showing static guides of indent levels.\n    - Implementation of 'mini.indentscope' is similar to\n      'indent-blankline.nvim' (using |extmarks| on first column to be shown\n      even on blank lines). They can be used simultaneously, but it will\n      lead to one of the visualizations being on top (hiding) of another.\n\n# Highlight groups ~\n\n- `MiniIndentscopeSymbol` - symbol showing on every line of scope if its\n  indent is multiple of 'shiftwidth'.\n- `MiniIndentscopeSymbolOff` - symbol showing on every line of scope if its\n  indent is not multiple of 'shiftwidth'.\n  Default: links to `MiniIndentscopeSymbol`.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable autodrawing, set `vim.g.miniindentscope_disable` (globally) or\n`vim.b.miniindentscope_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                       *MiniIndentscope-drawing*\nDraw of scope indicator is done as iterative animation. It has the\nfollowing design:\n- Draw indicator on origin line (where cursor is at) immediately. Indicator\n  is visualized as `MiniIndentscope.config.symbol` placed to the right of\n  scope's border indent. This creates a line from top to bottom scope edges.\n- Draw upward and downward concurrently per one line. Progression by one\n  line in both direction is considered to be one step of animation.\n- Before each step wait certain amount of time, which is decided by\n  \"animation function\". It takes next and total step numbers (both are one\n  or bigger) and returns number of milliseconds to wait before drawing next\n  step. Comparing to a more popular \"easing functions\" in animation (input:\n  duration since animation start; output: percent of animation done), it is\n  a discrete inverse version of its derivative. Such interface proved to be\n  more appropriate for kind of task at hand.\n\n# Special cases ~\n\n- When scope to be drawn intersects (same indent, ranges overlap) currently\n  visible one (at process or finished drawing), drawing is done immediately\n  without animation. With most common example being typing new text, this\n  feels more natural.\n- Scope for the whole buffer is not drawn as it is isually redundant.\n  Technically, it can be thought as drawn at column 0 (because border\n  indent is -1) which is not visible.\n\n------------------------------------------------------------------------------\n                                                       *MiniIndentscope.setup()*\n                       `MiniIndentscope.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniIndentscope.config|.\n\nUsage ~\n>lua\n  require('mini.indentscope').setup() -- use default config\n  -- OR\n  require('mini.indentscope').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                        *MiniIndentscope.config*\n                            `MiniIndentscope.config`\nDefaults ~\n>lua\n  MiniIndentscope.config = {\n    -- Draw options\n    draw = {\n      -- Delay (in ms) between event and start of drawing scope indicator\n      delay = 100,\n\n      -- Animation rule for scope's first drawing. A function which, given\n      -- next and total step numbers, returns wait time (in ms). See\n      -- |MiniIndentscope.gen_animation| for builtin options. To disable\n      -- animation, use `require('mini.indentscope').gen_animation.none()`.\n      animation = --<function: implements constant 20ms between steps>,\n\n      -- Whether to auto draw scope: return `true` to draw, `false` otherwise.\n      -- Default draws only fully computed scope (see `options.n_lines`).\n      predicate = function(scope) return not scope.body.is_incomplete end,\n\n      -- Symbol priority. Increase to display on top of more symbols.\n      priority = 2,\n    },\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      -- Textobjects\n      object_scope = 'ii',\n      object_scope_with_border = 'ai',\n\n      -- Motions (jump to respective border line; if not present - body line)\n      goto_top = '[i',\n      goto_bottom = ']i',\n    },\n\n    -- Options which control scope computation\n    options = {\n      -- Type of scope's border: which line(s) with smaller indent to\n      -- categorize as border. Can be one of: 'both', 'top', 'bottom', 'none'.\n      border = 'both',\n\n      -- Whether to use cursor column when computing reference indent.\n      -- Useful to see incremental scopes with horizontal cursor movements.\n      indent_at_cursor = true,\n\n      -- Maximum number of lines above or below within which scope is computed\n      n_lines = 10000,\n\n      -- Whether to first check input line to be a border of adjacent scope.\n      -- Use it if you want to place cursor on function header to get scope of\n      -- its body.\n      try_as_border = false,\n    },\n\n    -- Which character to use for drawing scope indicator\n    symbol = '╎',\n  }\n<\n# Options ~\n\n## Border ~\n\nField `border` controls which line(s) with smaller indent to categorize\nas border. This matters for textobjects and motions.\nIt also controls how empty lines are treated: they are included in scope\nonly if followed by a border. Another way of looking at it is that indent\nof blank line is computed based on value of `border` option.\nHere is an illustration of how `border` works in presence of empty lines: >\n\n                             |both|bottom|top|none|\n  1|function foo()           | 0  |  0   | 0 | 0  |\n  2|                         | 4  |  0   | 4 | 0  |\n  3|    print('Hello world') | 4  |  4   | 4 | 4  |\n  4|                         | 4  |  4   | 2 | 2  |\n  5|  end                    | 2  |  2   | 2 | 2  |\n<\nNumbers inside a table are indent values of a line computed with certain\nvalue of `border`. So, for example, a scope with reference line 3 and\nright-most column has body range depending on value of `border` option:\n- `border` is \"both\":   range is 2-4, border is 1 and 5 with indent 2.\n- `border` is \"top\":    range is 2-3, border is 1 with indent 0.\n- `border` is \"bottom\": range is 3-4, border is 5 with indent 0.\n- `border` is \"none\":   range is 3-3, border is empty with indent `nil`.\n\n## Indent at cursor ~\n\nField `indent_at_cursor` controls if cursor position should affect computation\nof scope. If `true`, reference indent is a minimum of reference line's indent\nand cursor column. In main example, here how scope's body range differs\ndepending on cursor column and `indent_at_cursor` value (assuming cursor is\non line 3 and it is whole buffer): >\n\n  Column\\Option true|false\n     1 and 2    2-5 | 2-4\n   3 and more   2-4 | 2-4\n<\n## Number of lines ~\n\nField `n_lines` defines |MiniIndentscope.get_scope()| behavior for how many\nlines above/below to check before iteration is stopped. Scope that reached\ncomputation limit has <is_incomplete> field set to `true`. It will also not\nbe auto drawn with default `config.draw.predicate`.\n\nLower values will result in better overall performance in exchange for more\nfrequent incomplete scope computation. Set to `math.huge` for no restriction.\n\n## Try as border ~\n\nField `try_as_border` controls how to act when input line can be recognized\nas a border of some neighbor indent scope. In main example, when input line\nis 1 and can be recognized as border for inner scope, value `try_as_border=true`\nmeans that inner scope will be returned. Similar, for input line 5 inner scope\nwill be returned if it is recognized as border.\n\n------------------------------------------------------------------------------\n                                                   *MiniIndentscope.get_scope()*\n               `MiniIndentscope.get_scope`({line}, {col}, {opts})\nCompute indent scope\n\nIndent scope (or just \"scope\") is a maximum set of consecutive lines which\ncontains certain reference line (cursor line by default) and every member\nhas indent not less than certain reference indent (\"indent at column\" by\ndefault). Here \"indent at column\" means minimum between input column value\nand indent of reference line. When using cursor column, this allows for a\nuseful interactive view of nested indent scopes by making horizontal\nmovements within line.\n\nOptions controlling actual computation is taken from these places in order:\n- Argument `opts`. Use it to ensure independence from other sources.\n- Buffer local variable `vim.b.miniindentscope_config` (`options` field).\n  Useful to define local behavior (for example, for a certain filetype).\n- Global options from |MiniIndentscope.config|.\n\n# Algorithm overview ~\n\n- Compute reference \"indent at column\". Reference line is an input `line`\n  which might be modified to one of its neighbors if `try_as_border` option\n  is `true`: if it can be viewed as border of some neighbor scope, it will.\n- Process upwards and downwards from reference line searching for line with\n  indent strictly less than reference one. This is like casting rays up and\n  down from reference line and reference indent until meeting \"a wall\"\n  (character to the right of indent or buffer edge). Latest line before\n  meeting a wall is a respective end of scope body. It always exists because\n  reference line is a such one.\n  Casting ray is forced to stop if it goes over `opts.n_lines` lines.\n- Based on top and bottom lines with strictly lower indent, construct\n  scopes's border. The way it is computed is decided based on `border`\n  option (see |MiniIndentscope.config| for more information).\n- Compute border indent as maximum indent of border lines (or reference\n  indent minus one in case of no border). This is used during drawing\n  visual indicator.\n\n# Indent computation ~\n\nFor every line indent is intended to be computed unambiguously:\n- For \"normal\" lines indent is an output of |indent()|.\n- Indent is `-1` for imaginary lines 0 and past last line.\n- For blank and empty lines indent is computed based on previous\n  (|prevnonblank()|) and next (|nextnonblank()|) non-blank lines. The way\n  it is computed is decided based on `border` in order to not include blank\n  lines at edge of scope's body if there is no border there. See\n  |MiniIndentscope.config| for a details example.\n\nParameters ~\n{line} `(number|nil)` Input line number (starts from 1). Can be modified to a\n  neighbor if `try_as_border` is `true`. Default: cursor line.\n{col} `(number|nil)` Column number (starts from 1). Default: if\n  `indent_at_cursor` option is `true` - cursor column from `curswant` of\n  |getcurpos()| (allows for more natural behavior on empty lines);\n  `math.huge` otherwise in order to not incorporate cursor in computation.\n{opts} `(table|nil)` Options to override global or buffer local ones (see\n  |MiniIndentscope.config|).\n\nReturn ~\n`(table)` Table with scope information:\n  - <body> - table with <top> (top line of scope, inclusive), <bottom>\n    (bottom line of scope, inclusive), and <indent> (minimum indent within\n    scope) keys. Line numbers start at 1. Can also have <is_incomplete> key\n    set to `true` if computation was stopped due to `opts.n_lines` restriction.\n  - <border> - table with <top> (line of top border, might be `nil`),\n    <bottom> (line of bottom border, might be `nil`), and <indent> (indent\n    of border) keys. Line numbers start at 1.\n  - <buf_id> - identifier of current buffer.\n  - <reference> - table with <line> (reference line), <column> (reference\n    column), and <indent> (\"indent at column\") keys.\n\n------------------------------------------------------------------------------\n                                                        *MiniIndentscope.draw()*\n                    `MiniIndentscope.draw`({scope}, {opts})\nDraw scope manually\n\nScope is visualized as a vertical line within scope's body range at column\nequal to border indent plus one (or body indent if border is absent).\nNumbering starts from one.\n\nParameters ~\n{scope} `(table|nil)` Scope. Default: output of |MiniIndentscope.get_scope()|\n  with default arguments.\n{opts} `(table|nil)` Options. Currently supported:\n   - <animation_fun> - animation function for drawing. See\n     |MiniIndentscope-drawing| and |MiniIndentscope.gen_animation|.\n   - <priority> - priority number for visualization. See `priority` option\n     for |nvim_buf_set_extmark()|.\n\n------------------------------------------------------------------------------\n                                                      *MiniIndentscope.undraw()*\n                           `MiniIndentscope.undraw`()\nUndraw currently visible scope manually\n\n------------------------------------------------------------------------------\n                                                 *MiniIndentscope.gen_animation*\n                        `MiniIndentscope.gen_animation`\nGenerate builtin animation function\n\nThis is a builtin source to generate animation function for usage in\n`MiniIndentscope.config.draw.animation`. Most of them are variations of\ncommon easing functions, which provide certain type of progression for\nrevealing scope visual indicator.\n\nEach field corresponds to one family of progression which can be customized\nfurther by supplying appropriate arguments.\n\nExamples:\n- Don't use animation: `MiniIndentscope.gen_animation.none()`\n- Use quadratic \"out\" easing with total duration of 1000 ms: >lua\n\n  gen_animation.quadratic({ easing = 'out', duration = 1000, unit = 'total' })\n<\nSee also ~\n|MiniIndentscope-drawing| for more information about how drawing is done.\n\n------------------------------------------------------------------------------\n                                          *MiniIndentscope.gen_animation.none()*\n                     `MiniIndentscope.gen_animation.none`()\nGenerate no animation\n\nShow indicator immediately. Same as animation function always returning 0.\n\n------------------------------------------------------------------------------\n                                        *MiniIndentscope.gen_animation.linear()*\n                 `MiniIndentscope.gen_animation.linear`({opts})\nGenerate linear progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Animation function (see |MiniIndentscope-drawing|).\n\n------------------------------------------------------------------------------\n                                     *MiniIndentscope.gen_animation.quadratic()*\n               `MiniIndentscope.gen_animation.quadratic`({opts})\nGenerate quadratic progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Animation function (see |MiniIndentscope-drawing|).\n\n------------------------------------------------------------------------------\n                                         *MiniIndentscope.gen_animation.cubic()*\n                 `MiniIndentscope.gen_animation.cubic`({opts})\nGenerate cubic progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Animation function (see |MiniIndentscope-drawing|).\n\n------------------------------------------------------------------------------\n                                       *MiniIndentscope.gen_animation.quartic()*\n                `MiniIndentscope.gen_animation.quartic`({opts})\nGenerate quartic progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Animation function (see |MiniIndentscope-drawing|).\n\n------------------------------------------------------------------------------\n                                   *MiniIndentscope.gen_animation.exponential()*\n              `MiniIndentscope.gen_animation.exponential`({opts})\nGenerate exponential progression\n\nParameters ~\n{opts} `(table|nil)` Options that control progression. Possible keys:\n  - <easing> `(string)` - a subtype of progression. One of \"in\"\n    (accelerating from zero speed), \"out\" (decelerating to zero speed),\n    \"in-out\" (default; accelerating halfway, decelerating after).\n  - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n  - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n    of \"step\" (default; ensures average duration of step to be `opts.duration`)\n    or \"total\" (ensures fixed total duration regardless of scope's range).\n\nReturn ~\n`(function)` Animation function (see |MiniIndentscope-drawing|).\n\n------------------------------------------------------------------------------\n                                                 *MiniIndentscope.move_cursor()*\n          `MiniIndentscope.move_cursor`({side}, {use_border}, {scope})\nMove cursor within scope\n\nCursor is placed on a first non-blank character of target line.\n\nParameters ~\n{side} `(string)` One of \"top\" or \"bottom\".\n{use_border} `(boolean|nil)` Whether to move to border or within scope's body.\n  If particular border is absent, body is used.\n{scope} `(table|nil)` Scope to use. Default: output of |MiniIndentscope.get_scope()|.\n\n------------------------------------------------------------------------------\n                                                    *MiniIndentscope.operator()*\n             `MiniIndentscope.operator`({side}, {add_to_jumplist})\nFunction for motion mappings\n\nMove to a certain side of border. Respects |count| and dot-repeat (in\noperator-pending mode). Doesn't move cursor for scope that is not shown\n(drawing indent less that zero).\n\nParameters ~\n{side} `(string)` One of \"top\" or \"bottom\".\n{add_to_jumplist} `(boolean|nil)` Whether to add movement to jump list. It is\n  `true` only for Normal mode mappings.\n\n------------------------------------------------------------------------------\n                                                  *MiniIndentscope.textobject()*\n                   `MiniIndentscope.textobject`({use_border})\nFunction for textobject mappings\n\nRespects |count| and dot-repeat (in operator-pending mode). Doesn't work\nfor scope that is not shown (drawing indent less that zero).\n\nParameters ~\n{use_border} `(boolean|nil)` Whether to include border in textobject. When\n  `true` and `try_as_border` option is `false`, allows \"chaining\" calls for\n  incremental selection.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-jump.txt",
    "content": "*mini.jump* Jump to next/previous single character\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski, Adam Blažek\n\n------------------------------------------------------------------------------\n                                                                      *MiniJump*\nFeatures:\n- Extend f, F, t, T to work on multiple lines.\n\n- Repeat jump by pressing f, F, t, T again. It is reset when cursor moved\n  as a result of not jumping or timeout after idle time (duration\n  customizable).\n\n- Highlight (after customizable delay) all possible target characters and\n  stop it after some (customizable) idle time.\n\n- Normal, Visual, and Operator-pending (with dot-repeat as in clean Neovim)\n  modes are supported.\n\nThis module follows vim's 'ignorecase' and 'smartcase' options. When\n'ignorecase' is set, f, F, t, T will match case-insensitively. When\n'smartcase' is also set, f, F, t, T will only match lowercase\ncharacters case-insensitively.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.jump').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniJump` which you can use for scripting or manually (with\n`:lua MiniJump.*`).\n\nSee |MiniJump.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minijump_config` which should have same structure as\n`MiniJump.config`. See |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Highlight groups ~\n\n- `MiniJump` - all possible cursor positions.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.minijump_disable` (globally) or\n`vim.b.minijump_disable` (for a buffer) to `true`. Considering high number of\ndifferent scenarios and customization intentions, writing exact rules for\ndisabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                               *MiniJump-events*\nTo allow user customization and integration of external tools, certain |User|\nautocommand events are triggered under common circumstances:\n\n- `MiniJumpGetTarget` - before asking user for the target. Use |MiniJump.state|\n  for more information about the upcoming jump.\n- `MiniJumpStart` - after jumping has started.\n- `MiniJumpJump` - after performing a jump.\n- `MiniJumpStop` - after jumping is stopped.\n\n------------------------------------------------------------------------------\n                                                              *MiniJump.setup()*\n                           `MiniJump.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniJump.config|.\n\nUsage ~\n>lua\n  require('mini.jump').setup() -- use default config\n  -- OR\n  require('mini.jump').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniJump.config*\n                               `MiniJump.config`\nDefaults ~\n>lua\n  MiniJump.config = {\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      forward = 'f',\n      backward = 'F',\n      forward_till = 't',\n      backward_till = 'T',\n      repeat_jump = ';',\n    },\n\n    -- Delay values (in ms) for different functionalities. Set any of them to\n    -- a very big number (like 10^7) to virtually disable.\n    delay = {\n      -- Delay between jump and highlighting all possible jumps\n      highlight = 250,\n\n      -- Delay between jump and automatic stop if idle (no jump is done)\n      idle_stop = 10000000,\n    },\n\n    -- Whether to disable showing non-error feedback\n    -- This also affects (purely informational) helper messages shown after\n    -- idle time if user input is required.\n    silent = false,\n  }\n<\n------------------------------------------------------------------------------\n                                                                *MiniJump.state*\n                                `MiniJump.state`\nData about jumping state\n\nIt stores various information used in this module. All elements, except\n`jumping`, is about the latest jump. They are used as default values for\nsimilar arguments.\n\nUsage ~\nThis can be used to define mappings which depend on state; either as\na standalone mapping or part of |MiniKeymap.map_multistep()|. For example: >lua\n\n  -- Stop jumping after pressing `<Esc>`\n  local jump_stop = function()\n    if not MiniJump.state.jumping then return '<Esc>' end\n    MiniJump.stop_jumping()\n  end\n  local opts = { expr = true, desc = 'Stop jumping' }\n  vim.keymap.set({ 'n', 'x', 'o' }, '<Esc>', jump_stop, opts)\n<\nClass ~\n{JumpingState}\n\nFields ~\n{target} `(string|nil)` The string to jump to.\n{backward} `(boolean|nil)` Whether to jump backward.\n{till} `(boolean|nil)` Whether to jump just before/after the match instead of\n  exactly on target. This includes positioning cursor past the end of\n  previous/current line. Note that with backward jump this might lead to\n  cursor being on target if can't be put past the line.\n{n_times} `(number|nil)` Number of times to perform consecutive jumps.\n{mode} `(string)` Mode of latest jump (output of |mode()| with non-zero argument).\n{jumping} `(boolean)` Whether module is currently in \"jumping mode\": usage of\n  |MiniJump.smart_jump()| and all mappings won't require target.\n\nInitial values:\n>lua\n  MiniJump.state = {\n    target = nil,\n    backward = false,\n    till = false,\n    n_times = 1,\n    mode = nil,\n    jumping = false,\n  }\n<\n------------------------------------------------------------------------------\n                                                               *MiniJump.jump()*\n            `MiniJump.jump`({target}, {backward}, {till}, {n_times})\nJump to target\n\nTakes a string and jumps to its first occurrence in desired direction.\n\nAll default values are taken from |MiniJump.state| to emulate latest jump.\n\nParameters ~\n{target} `(string|nil)` The string to jump to.\n{backward} `(boolean|nil)` Whether to jump backward.\n{till} `(boolean|nil)` Whether to jump just before/after the match instead of\n  exactly on target. This includes positioning cursor past the end of\n  previous/current line. Note that with backward jump this might lead to\n  cursor being on target if can't be put past the line.\n{n_times} `(number|nil)` Number of times to perform consecutive jumps.\n\n------------------------------------------------------------------------------\n                                                         *MiniJump.smart_jump()*\n                   `MiniJump.smart_jump`({backward}, {till})\nMake smart jump\n\nIf the last movement was a jump, perform another jump with the same target.\nOtherwise, wait for a target input (via |getcharstr()|). Respects |v:count|.\n\nAll default values are taken from |MiniJump.state| to emulate latest jump.\n\nParameters ~\n{backward} `(boolean|nil)` Whether to jump backward.\n{till} `(boolean|nil)` Whether to jump just before/after the match instead of\n  exactly on target. This includes positioning cursor past the end of\n  previous/current line. Note that with backward jump this might lead to\n  cursor being on target if can't be put past the line.\n\n------------------------------------------------------------------------------\n                                                       *MiniJump.stop_jumping()*\n                           `MiniJump.stop_jumping`()\nStop jumping\n\nRemoves highlights (if any) and forces the next smart jump to prompt for\nthe target. Automatically called on appropriate Neovim |events|.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-jump2d.txt",
    "content": "*mini.jump2d* Jump within visible lines\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniJump2d*\nJump within visible lines via iterative label filtering.\n\nFeatures:\n- Make jump by iterative filtering of possible, equally considered jump\n  spots until there is only one. Filtering is done by typing a label\n  character that is visualized at jump spot.\n\n- Customizable (see |MiniJump2d.config|):\n    - Way of computing possible jump spots with opinionated default.\n    - Characters used to label jump spots during iterative filtering.\n    - Visual effects: how many steps ahead to show; dim lines with spots.\n    - Action hooks to be executed at certain events during jump.\n    - Allowed windows: current and/or not current.\n    - Allowed lines: whether to process blank or folded lines, lines\n      before/at/after cursor line, etc. Example: user can configure to look\n      for spots only inside current window at or after cursor line.\n    Example: user can configure to look for word starts only inside current\n    window at or after cursor line with 'j' and 'k' labels performing some\n    action after jump.\n\n- Works in Visual and Operator-pending (with dot-repeat) modes.\n\n- Preconfigured ways of computing jump spots (see |MiniJump2d.builtin_opts|):\n    - Starts of lines.\n    - Starts of words.\n    - Single character from user input.\n    - Variable length query from user input.\n\n- Works with multibyte characters.\n\nGeneral overview of how jump is intended to be performed:\n- Lock eyes on desired location (\"spot\") recognizable by future jump.\n  Should be within visible lines at place where cursor can be placed.\n\n- Initiate jump. Either by custom keybinding or with a call to\n  |MiniJump2d.start()| (allows customization options). This will highlight\n  all possible jump spots with their labels (letters from \"a\" to \"z\" by\n  default). For more details, read |MiniJump2d.start()| and |MiniJump2d.config|.\n\n- Type character that appeared over desired location. If its label was\n  unique, jump is performed. If it wasn't unique, possible jump spots are\n  filtered to those having the same label character.\n\n- Repeat previous step until there is only one possible jump spot or type <CR>\n  to jump to first available jump spot. Typing anything else stops jumping\n   without moving cursor.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.jump2d').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table\n`MiniJump2d` which you can use for scripting or manually (with\n`:lua MiniJump2d.*`).\n\nSee |MiniJump2d.config| for available config settings.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minijump2d_config` which should have same structure as\n`MiniJump2d.config`. See |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Example usage ~\n\n- Modify default jumping to use only current window at or after cursor line: >lua\n\n  require('mini.jump2d').setup({\n    allowed_lines = { cursor_before = false },\n    allowed_windows = { not_current = false },\n  })\n<\n- Jump to line start using combination of options supplied in\n  |MiniJump2d.config| and |MiniJump2d.builtin_opts.line_start|: >vim\n\n  :lua MiniJump2d.start(MiniJump2d.builtin_opts.line_start)\n<\n- Jump to a single character typed after executing this command: >vim\n\n  :lua MiniJump2d.start(MiniJump2d.builtin_opts.single_character)\n<\n- See more examples in |MiniJump2d.start()| and |MiniJump2d.builtin_opts|.\n\n# Comparisons ~\n\n- [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim):\n    - Both are fast, customizable, and extensible (user can write their own\n      ways to define jump spots).\n    - 'hop.nvim' visualizes all steps at once. While this module can show\n      configurable number of steps ahead.\n    - Both have several builtin ways to specify type of jump (word start,\n      line start, one character or query based on user input). 'hop.nvim'\n      does that by exporting many targeted Neovim commands, while this\n      module has preconfigured basic options leaving others to\n      customization with Lua code (see |MiniJump2d.builtin_opts|).\n    - 'hop.nvim' computes labels (called \"hints\") differently. Contrary to\n      this module deliberately not having preference of one jump spot over\n      another, 'hop.nvim' uses specialized algorithm that produces sequence\n      of keys in a slightly biased manner: some sequences are intentionally\n      shorter than the others (leading to fewer average keystrokes). They\n      are put near cursor (by default) and highlighted differently. Final\n      order of sequences is based on distance to the cursor.\n    - 'mini.jump2d' has opinionated default algorithm of computing jump\n      spots. See |MiniJump2d.default_spotter()|.\n\n# Highlight groups ~\n\n- `MiniJump2dSpot` - highlighting of jump spot's next step. By default it\n  uses label with highest contrast while not being too visually demanding:\n  white on black for dark 'background', black on white for light. If it\n  doesn't suit your liking, try couple of these alternatives (or choose\n  your own, of course): >lua\n\n    -- Reverse underlying colors (mostly *very* visible in any colorscheme)\n    vim.api.nvim_set_hl(0, 'MiniJump2dSpot', { reverse = true })\n\n    -- Bold italic\n    vim.api.nvim_set_hl(0, 'MiniJump2dSpot', { bold = true, italic = true })\n\n    -- Red undercurl\n    vim.api.nvim_set_hl(0, 'MiniJump2dSpot', { sp = 'Red', undercurl = true })\n<\n- `MiniJump2dSpotUnique` - highlighting of jump spot's next step if it has\n  unique label. By default links to `MiniJump2dSpot`.\n\n- `MiniJump2dSpotAhead` - highlighting of jump spot's future steps. By default\n  similar to `MiniJump2dSpot` but with less contrast and visibility.\n\n- `MiniJump2dDim` - highlighting of lines with at least one jump spot.\n  Make it non-bright in order for jump spot labels to be more visible.\n  By default linked to `Comment` highlight group.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minijump2d_disable` (globally) or\n`vim.b.minijump2d_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                            *MiniJump2d.setup()*\n                          `MiniJump2d.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniJump2d.config|.\n\nUsage ~\n>lua\n  require('mini.jump2d').setup() -- use default config\n  -- OR\n  require('mini.jump2d').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                             *MiniJump2d.config*\n                              `MiniJump2d.config`\nDefaults ~\n>lua\n  MiniJump2d.config = {\n    -- Function producing jump spots (byte indexed) for a particular line.\n    -- For more information see |MiniJump2d.start()|.\n    -- If `nil` (default) - use |MiniJump2d.default_spotter()|\n    spotter = nil,\n\n    -- Characters used for labels of jump spots (in supplied order)\n    labels = 'abcdefghijklmnopqrstuvwxyz',\n\n    -- Options for visual effects\n    view = {\n      -- Whether to dim lines with at least one jump spot\n      dim = false,\n\n      -- How many steps ahead to show. Set to big number to show all steps.\n      n_steps_ahead = 0,\n    },\n\n    -- Which lines are used for computing spots\n    allowed_lines = {\n      blank = true, -- Blank line (not sent to spotter even if `true`)\n      cursor_before = true, -- Lines before cursor line\n      cursor_at = true, -- Cursor line\n      cursor_after = true, -- Lines after cursor line\n      fold = true, -- Start of fold (not sent to spotter even if `true`)\n    },\n\n    -- Which windows from current tabpage are used for visible lines\n    allowed_windows = {\n      current = true,\n      not_current = true,\n    },\n\n    -- Functions to be executed at certain events\n    hooks = {\n      before_start = nil, -- Before jump start\n      after_jump = nil, -- After jump was actually done\n    },\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      start_jumping = '<CR>',\n    },\n\n    -- Whether to disable showing non-error feedback\n    -- This also affects (purely informational) helper messages shown after\n    -- idle time if user input is required.\n    silent = false,\n  }\n<\n# Spotter function ~\n\nActual computation of possible jump spots is done through spotter function.\nIt should have the following arguments:\n- `line_num` is a line number inside buffer.\n- `args` - table with additional arguments:\n    - {win_id} - identifier of a window where input line number is from.\n    - {win_id_init} - identifier of a window which was current when\n      `MiniJump2d.start()` was called.\n\nIts output is a list of byte-indexed positions that should be considered as\npossible jump spots for this particular line in this particular window.\nNote: for a more aligned visualization this list should be (but not\nstrictly necessary) sorted increasingly.\n\nNote: spotter function is always called with `win_id` window being\n\"temporary current\" (see |nvim_win_call()|). This allows using builtin\nVimscript functions that operate only inside current window.\n\n# View ~\n\nOption `view.n_steps_ahead` controls how many steps ahead to show along\nwith the currently required label. Those future steps are shown with\ndifferent (less visible) highlight group (\"MiniJump2dSpotAhead\"). Usually\nit is a good idea to use this with a spotter which doesn't result into many\njump spots (like, for example, |MiniJump2d.builtin_opts.word_start|).\nDefault is 0 to not show anything ahead as it reduces visual noise.\n\nOption `view.dim` controls whether to dim lines with at least one jump spot.\nDimming is done by applying \"MiniJump2dDim\" highlight group to the whole line.\n\n# Allowed lines ~\n\nOption `allowed_lines` controls which lines will be used for computing\npossible jump spots:\n- If `blank` or `fold` is `true`, it is possible to jump to first column of blank\n  line (determined by |prevnonblank()|) or first folded one (determined by\n  |foldclosed()|) respectively. Otherwise they are skipped. These lines are\n  not processed by spotter function even if the option is `true`.\n- If `cursor_before`, (`cursor_at`, `cursor_after`) is `true`, lines before\n  (at, after) cursor line of all processed windows are forwarded to spotter\n  function. Otherwise, they don't. This allows control of jump \"direction\".\n\n# Hooks ~\n\nFollowing hook functions can be used to further tweak jumping experience:\n- `before_start` - called without arguments first thing when jump starts.\n  One of the possible use cases is to ask for user input and update spotter\n  function with it.\n- `after_jump` - called after jump was actually done. Useful to make\n  post-adjustments (like move cursor to first non-whitespace character).\n\n------------------------------------------------------------------------------\n                                                            *MiniJump2d.start()*\n                           `MiniJump2d.start`({opts})\nStart jumping\n\nCompute possible jump spots, visualize them and wait for iterative filtering.\n\n# First computation of possible jump spots ~\n\n- Process allowed windows (current and/or not current; controlled by\n  `allowed_windows` option) by visible lines from top to bottom. For each\n  one see if it is allowed (controlled by `allowed_lines` option). If not\n  allowed, then do nothing. If allowed and should be processed by\n  `spotter`, process it.\n- Apply spotter function from `spotter` option for each appropriate line\n  and concatenate outputs. This means that eventual order of jump spots\n  aligns with lexicographical order within \"window id\" - \"line number\" -\n  \"position in `spotter` output\" tuples.\n- For each possible jump compute its label: a single character from\n  `labels` option used to filter jump spots. Each possible label character\n  might be used more than once to label several \"consecutive\" jump spots.\n  It is done in an optimal way under assumption of no preference of one\n  spot over another. Basically, it means \"use all labels at each step of\n  iterative filtering as equally as possible\".\n\n# Visualization ~\n\nCurrent label for each possible jump spot is shown at that position\noverriding everything underneath it.\n\n# Iterative filtering ~\n\nLabels of possible jump spots are computed in order to use them as equally\nas possible.\n\nExample:\n- With `abc` as `labels` option, initial labels for 10 possible jumps\n  are \"aaaabbbccc\". As there are 10 spots which should be \"coded\" with 3\n  symbols, at least 2 symbols need 3 steps to filter them out. With current\n  implementation those are always the \"first ones\".\n- After typing `a`, it filters first four jump spots and recomputes its\n  labels to be \"aabc\".\n- After typing `a` again, it filters first two spots and recomputes its\n  labels to be \"ab\".\n- After typing either `a` or `b` it filters single spot and makes jump.\n\nWith default 26 labels for most real-world cases 2 steps is enough for\ndefault spotter function. Rarely 3 steps are needed with several windows.\n\nParameters ~\n{opts} `(table|nil)` Configuration of jumping, overriding global and buffer\n  local values. Has the same structure as |MiniJump2d.config|\n  without <mappings> field. Extra allowed fields:\n  - <hl_group> - highlight group for first step.\n    Default: `\"MiniJump2dSpot\"`.\n  - <hl_group_ahead> - highlight group for second and later steps.\n    Default: `\"MiniJump2dSpotAhead\"`.\n  - <hl_group_dim> - highlight group for dimming used lines.\n    Default: `\"MiniJump2dDim\"`.\n  - <hl_group_unique> - highlight group for unique next step.\n    Default: `\"MiniJump2dSpotUnique\"`.\n\nUsage ~\n>lua\n  -- Start default jumping\n  MiniJump2d.start()\n\n  -- Jump to word start\n  MiniJump2d.start(MiniJump2d.builtin_opts.word_start)\n\n  -- Jump to single character from user input (follow by typing one character)\n  MiniJump2d.start(MiniJump2d.builtin_opts.single_character)\n\n  -- Jump to first character of punctuation group only inside current window\n  -- which is placed at cursor line; visualize with `Search`\n  MiniJump2d.start({\n    spotter = MiniJump2d.gen_spotter.pattern('%p+'),\n    allowed_lines = { cursor_before = false, cursor_after = false },\n    allowed_windows = { not_current = false },\n    hl_group = 'Search'\n  })\n<\nSee also ~\n|MiniJump2d.config|\n\n------------------------------------------------------------------------------\n                                                             *MiniJump2d.stop()*\n                              `MiniJump2d.stop`()\nStop jumping\n\n------------------------------------------------------------------------------\n                                                        *MiniJump2d.gen_spotter*\n                            `MiniJump2d.gen_spotter`\nGenerate spotter\n\nThis is a table with function elements. Call to actually get a spotter.\n\n------------------------------------------------------------------------------\n                                              *MiniJump2d.gen_spotter.pattern()*\n              `MiniJump2d.gen_spotter.pattern`({pattern}, {side})\nGenerate spotter for Lua pattern\n\nParameters ~\n{pattern} `(string|nil)` Lua pattern. Default: `'[^%s%p]+'` which matches group\n  of \"non-whitespace non-punctuation characters\" (basically a way of saying\n  \"group of alphanumeric characters\" that works with multibyte characters).\n{side} `(string|nil)` Which side of pattern match should be considered as\n  jumping spot. Should be one of 'start' (start of match, default), 'end'\n  (inclusive end of match), or 'none' (match for spot is done manually\n  inside pattern with plain `()` matching group).\n\nReturn ~\n`(function)` Spotter function.\n\nUsage ~\n>lua\n  -- Match any punctuation\n  MiniJump2d.gen_spotter.pattern('%p')\n\n  -- Match first from line start non-whitespace character\n  MiniJump2d.gen_spotter.pattern('^%s*%S', 'end')\n\n  -- Match start of last word\n  MiniJump2d.gen_spotter.pattern('[^%s%p]+[%s%p]-$', 'start')\n\n  -- Match letter followed by another letter (example of manual matching\n  -- inside pattern)\n  MiniJump2d.gen_spotter.pattern('%a()%a', 'none')\n<\n------------------------------------------------------------------------------\n                                           *MiniJump2d.gen_spotter.vimpattern()*\n                 `MiniJump2d.gen_spotter.vimpattern`({pattern})\nGenerate spotter for Vimscript pattern\n\nParameters ~\n{pattern} `(string|nil)` Vimscript |pattern|. Default: `\\k\\+` to match group\n  of \"keyword characters\" (see 'iskeyword').\n\nReturn ~\n`(function)` Spotter function.\n\nUsage ~\n>lua\n  -- Match start of a keyword\n  MiniJump2d.gen_spotter.vimpattern('\\\\k\\\\+')\n\n  -- Match end of a keyword\n  MiniJump2d.gen_spotter.vimpattern('\\\\k*\\\\zs\\\\k')\n<\n------------------------------------------------------------------------------\n                                                *MiniJump2d.gen_spotter.union()*\n                     `MiniJump2d.gen_spotter.union`({...})\nGenerate union of spotters\n\nParameters ~\n{...} `(any)` Each argument should be a valid spotter.\n  See |MiniJump2d.config| for more details.\n\nReturn ~\n`(function)` Spotter producing union of spots.\n\nUsage ~\n>lua\n  -- Match start and end of non-blank character groups:\n  local nonblank_start = MiniJump2d.gen_spotter.pattern('%S+', 'start')\n  local nonblank_end = MiniJump2d.gen_spotter.pattern('%S+', 'end')\n  local spotter = MiniJump2d.gen_spotter.union(nonblank_start, nonblank_end)\n<\n------------------------------------------------------------------------------\n                                                  *MiniJump2d.default_spotter()*\n                          `MiniJump2d.default_spotter`\nDefault spotter function\n\nSpot is possible for jump if it is one of the following:\n- Start or end of non-whitespace character group.\n- Alphanumeric character followed or preceded by punctuation (useful for\n  snake case names).\n- Start of uppercase character group (useful for camel case names). Usually\n  only Latin alphabet is recognized due to Lua patterns shortcomings.\n\nThese rules are derived in an attempt to balance between two intentions:\n- Allow as much useful jumping spots as possible.\n- Make labeled jump spots easily distinguishable.\n\nUsually takes from 2 to 3 keystrokes to get to destination.\n\n------------------------------------------------------------------------------\n                                                       *MiniJump2d.builtin_opts*\n                           `MiniJump2d.builtin_opts`\nTable with builtin `opts` values for |MiniJump2d.start()|\n\nEach element of table is itself a table defining one or several options for\n`MiniJump2d.start()`. Read help description to see which options it defines\n(like in |MiniJump2d.builtin_opts.line_start|).\n\nUsage ~\n>lua\n  -- Using `MiniJump2d.builtin_opts.line_start` as example:\n  -- Command\n  :lua MiniJump2d.start(MiniJump2d.builtin_opts.line_start)\n\n  -- Custom mapping\n  vim.keymap.set(\n    'n', '<CR>',\n    '<Cmd>lua MiniJump2d.start(MiniJump2d.builtin_opts.line_start)<CR>'\n  )\n\n  -- Inside `MiniJump2d.setup()` (make sure to use all defined options)\n  local jump2d = require('mini.jump2d')\n  local jump_line_start = jump2d.builtin_opts.line_start\n  jump2d.setup({\n    spotter = jump_line_start.spotter,\n    hooks = { after_jump = jump_line_start.hooks.after_jump }\n  })\n<\n------------------------------------------------------------------------------\n                                               *MiniJump2d.builtin_opts.default*\n                       `MiniJump2d.builtin_opts.default`\nJump with |MiniJump2d.default_spotter()|\n\nDefines `spotter`.\n\n------------------------------------------------------------------------------\n                                            *MiniJump2d.builtin_opts.line_start*\n                      `MiniJump2d.builtin_opts.line_start`\nJump to line start\n\nDefines `spotter` and `hooks.after_jump`.\n\n------------------------------------------------------------------------------\n                                            *MiniJump2d.builtin_opts.word_start*\n                      `MiniJump2d.builtin_opts.word_start`\nJump to word start\n\nRespects 'iskeyword' when computing word start.\n\nDefines `spotter`.\n\n------------------------------------------------------------------------------\n                                      *MiniJump2d.builtin_opts.single_character*\n                   `MiniJump2d.builtin_opts.single_character`\nJump to single character taken from user input\n\nDefines `spotter`, `allowed_lines.blank`, `allowed_lines.fold`, and\n`hooks.before_start`.\n\n------------------------------------------------------------------------------\n                                                 *MiniJump2d.builtin_opts.query*\n                        `MiniJump2d.builtin_opts.query`\nJump to query taken from user input\n\nDefines `spotter`, `allowed_lines.blank`, `allowed_lines.fold`, and\n`hooks.before_start`.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-keymap.txt",
    "content": "*mini.keymap* Special key mappings\n\nMIT License Copyright (c) 2025 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniKeymap*\nFeatures:\n\n- Map keys to perform configurable multi-step actions: if condition for step\n  one is true - execute step one action, else check step two, and so on until\n  falling back to executing original keys. This is usually referred to as\n  \"smart\" keys (like \"smart tab\"). See |MiniKeymap.map_multistep()|.\n\n  There are many built-in steps targeted for Insert mode mappings of special\n  keys like <Tab>, <S-Tab>, <CR>, and <BS>:\n  - Navigate and accept |popupmenu-completion|. Useful for |mini.completion|.\n  - Navigate and expand |mini.snippets|.\n  - Execute <CR> and <BS> respecting |mini.pairs|.\n  - Jump before/after current tree-sitter node.\n  - Jump before opening and after closing characters (brackets and quotes).\n  - Increase/decrease indent when cursor is inside of it.\n  - Delete all whitespace to the left (\"hungry backspace\").\n  - Navigate |vim.snippet|.\n  - Navigate and accept in [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) completion.\n  - Navigate and accept in [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp) completion.\n  - Navigate and expand [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip) snippets.\n  - Execute <CR> and <BS> respecting [windwp/nvim-autopairs](https://github.com/windwp/nvim-autopairs).\n\n- Map keys as \"combo\": each key acts immediately plus execute extra action if\n  all are typed within configurable delay between each other.\n  See |MiniKeymap.map_combo()|. Some of the common use cases include:\n    - Map insertable keys (like \"jk\", \"kj\") in Insert and Command-line mode\n      to exit into Normal mode.\n    - Fight against bad habits of pressing the same navigation key by showing\n      a notification if there are too many of them pressed in a row.\n\nSources with more details:\n- |MiniKeymap-examples|\n\n# Setup ~\n\nThis module doesn't need setup, but it can be done to improve usability.\nSetup with `require('mini.keymap').setup({})` (replace `{}` with your `config`\ntable). It will create global Lua table `MiniKeymap` which you can use for\nscripting or manually (with `:lua MiniKeymap.*`).\n\nSee |MiniKeymap.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minikeymap_config`\nwill have no effect here.\n\n# Comparisons ~\n\n- [max397574/better-escape.nvim](https://github.com/max397574/better-escape.nvim):\n    - Mostly similar to |MiniKeymap.map_combo()| with a different approach\n      to creating mappings.\n    - Mostly targeted for Insert mode mappings as pressed keys get removed\n      automatically after typed. This module allows more general cases while\n      requiring explicit removal of keys (usually via explicit `<BS><BS>`).\n\n- [abecodes/tabout.nvim](https://github.com/abecodes/tabout.nvim):\n    - Similar general idea as in `'jump_{after,before}_tsnode'` steps\n      of |MiniKeymap.map_multistep()|.\n    - Works only with enabled tree-sitter parser. This module provides\n      fallback via 'jump_after_close' and 'jump_before_open' that work\n      without tree-sitter parser.\n    - 'tabout.nvim' has finer control of how the tree-sitter node movement\n      is done, while this module has \"jump outside of current node\" behavior.\n\n# Disabling ~\n\nTo disable acting in mappings, set `vim.g.minikeymap_disable` (globally) or\n`vim.b.minikeymap_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user.\nSee |mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                           *MiniKeymap-examples*\n# Multi-step ~\n\nSee |MiniKeymap.map_multistep()| for a general description of how multi-step\nmappings work and what built-in steps are available.\n\nSetup that works well with |mini.completion| and |mini.pairs|: >lua\n\n  local map_multistep = require('mini.keymap').map_multistep\n  map_multistep('i', '<Tab>',   { 'pmenu_next' })\n  map_multistep('i', '<S-Tab>', { 'pmenu_prev' })\n  map_multistep('i', '<CR>',    { 'pmenu_accept', 'minipairs_cr' })\n  map_multistep('i', '<BS>',    { 'minipairs_bs' })\n<\nUse <Tab> / <S-Tab> to also navigate and expand |mini.snippets|: >lua\n\n  local map_multistep = require('mini.keymap').map_multistep\n\n  local tab_steps = { 'minisnippets_next','minisnippets_expand','pmenu_next' }\n  map_multistep('i', '<Tab>', tab_steps)\n\n  local shifttab_steps = { 'minisnippets_prev', 'pmenu_prev' }\n  map_multistep('i', '<S-Tab>', shifttab_steps)\n<\nAn extra smart <Tab> and <S-Tab>: >lua\n\n  local map_multistep = require('mini.keymap').map_multistep\n\n  -- NOTE: this will never insert tab, press <C-v><Tab> for that\n  local tab_steps = {\n    'minisnippets_next', 'minisnippets_expand', 'pmenu_next',\n    'jump_after_tsnode', 'jump_after_close',\n  }\n  map_multistep('i', '<Tab>', tab_steps)\n\n  local shifttab_steps = {\n    'minisnippets_prev',  'pmenu_prev',\n    'jump_before_tsnode', 'jump_before_open',\n  }\n  map_multistep('i', '<S-Tab>', shifttab_steps)\n<\nNavigation in active |vim.snippet| session also requires mapping in |Select-mode|: >lua\n\n  local map_multistep = require('mini.keymap').map_multistep\n  map_multistep({ 'i', 's' }, '<Tab>',   { 'vimsnippet_next', 'pmenu_next' })\n  map_multistep({ 'i', 's' }, '<S-Tab>', { 'vimsnippet_prev', 'pmenu_prev' })\n<\n# Combos ~\n\nSee |MiniKeymap.map_combo()| for a general description of what is a combo and\nmore caveats about its usage.\n\nAll combos require their left hand side keys to be typed relatively quickly.\nTo adjust the delay between keys, add `{ delay = 500 }` (use custom value) as\nfourth argument.\n\n## \"Better escape\" to Normal mode ~\n\nLeave into |Normal-mode| without having to reach for <Esc> key: >lua\n\n  -- Support most common modes. This can also contain 't', but would\n  -- only mean to press `<Esc>` inside terminal.\n  local mode = { 'i', 'c', 'x', 's' }\n  require('mini.keymap').map_combo(mode, 'jk', '<BS><BS><Esc>')\n\n  -- To not have to worry about the order of keys, also map \"kj\"\n  require('mini.keymap').map_combo(mode, 'kj', '<BS><BS><Esc>')\n\n  -- Escape into Normal mode from Terminal mode\n  require('mini.keymap').map_combo('t', 'jk', '<BS><BS><C-\\\\><C-n>')\n  require('mini.keymap').map_combo('t', 'kj', '<BS><BS><C-\\\\><C-n>')\n<\n## Show bad navigation habits ~\n\nShow notification if there is too much movement by repeating same key: >lua\n\n  local notify_many_keys = function(key)\n    local lhs = string.rep(key, 5)\n    local action = function() vim.notify('Too many ' .. key) end\n    require('mini.keymap').map_combo({ 'n', 'x' }, lhs, action)\n  end\n  notify_many_keys('h')\n  notify_many_keys('j')\n  notify_many_keys('k')\n  notify_many_keys('l')\n<\n## Fix previous spelling mistake ~\n\nFix previous spelling mistake (see |[s| and |z=|) without manually leaving\nInsert mode: >lua\n\n  local action = '<BS><BS><Esc>[s1z=gi<Right>'\n  require('mini.keymap').map_combo('i', 'kk', action)\n<\n## Hide search highlighting ~\n\nUse double <Esc><Esc> to execute |:nohlsearch|. Although this can also be done\nwith `nmap <Esc> <Cmd>nohl<CR>`, the combo approach also exists and can be used\nto free <Esc> mapping in Normal mode for something else. >lua\n\n  local action = function() vim.cmd('nohlsearch') end\n  require('mini.keymap').map_combo({ 'n','i','x','c' }, '<Esc><Esc>', action)\n<\n## Buffer navigation ~\n\nReplace some movements with easier to type alternatives: >lua\n\n  local map_combo = require('mini.keymap').map_combo\n  map_combo({ 'n', 'x' }, 'll', 'g$')\n  map_combo({ 'n', 'x' }, 'hh', 'g^')\n  map_combo({ 'n', 'x' }, 'jj', '}')\n  map_combo({ 'n', 'x' }, 'kk', '{')\n<\n------------------------------------------------------------------------------\n                                                            *MiniKeymap.setup()*\n                          `MiniKeymap.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniKeymap.config|.\n\nUsage ~\n>lua\n  require('mini.keymap').setup({}) -- replace {} with your config table\n                                   -- needs `keymap` field present\n<\n------------------------------------------------------------------------------\n                                                             *MiniKeymap.config*\n                              `MiniKeymap.config`\nDefaults ~\n>lua\n  MiniKeymap.config = {}\n<\n------------------------------------------------------------------------------\n                                                    *MiniKeymap.map_multistep()*\n           `MiniKeymap.map_multistep`({mode}, {lhs}, {steps}, {opts})\nMap multi-step action\n\nMapping of a multi-step action is an expression mapping (|:map-expression|).\nExecuting a multi-step action is essentially:\n- Check condition for step one. If `true` - execute step one action and stop.\n- Check condition for step two, and so on.\n- If there is no more steps, fall back to returning mapped key.\n\nFor better user experience there are many built-in steps mostly designed\nto create Insert mode \"smart\" mappings of <Tab>, <S-Tab>, <CR>, and <BS>.\nAvailable built-in steps (\"For key\" is a suggestion, any can be used):\n>\n ┌─────────────────────┬────────────────┬──────────────────────────┬─────────┐\n │      Step name      │   Condition    │          Action          │ For key │\n ├─────────────────────┴────────────────┴──────────────────────────┴─────────┤\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |ins-completion-menu| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ pmenu_next          │ Pmenu visible  │ Select next (as <C-n>)   │ <Tab>   │\n │ pmenu_prev          │ Pmenu visible  │ Select prev (as <C-p>)   │ <S-Tab> │\n │ pmenu_accept        │ Item selected  │ Accept (as <C-y>)        │ <CR>    │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.snippets| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ minisnippets_next   │ Session active │ Jump to next tabstop     │ <Tab>   │\n │ minisnippets_prev   │ Session active │ Jump to prev tabstop     │ <S-Tab> │\n │ minisnippets_expand │ Can expand     │ Expand snippet at cursor │ <Tab>   │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.pairs| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ minipairs_cr        │ Module set up  │ <CR> respecting pairs    │ <CR>    │\n │ minipairs_bs        │ Module set up  │ <BS> respecting pairs    │ <BS>    │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Jump around in Insert mode ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ jump_after_tsnode   │ TS parser      │ Jump after node end      │ <Tab>   │\n │ jump_before_tsnode  │ TS parser      │ Jump before node start   │ <S-Tab> │\n │ jump_after_close    │ Insert mode    │ Jump after  )]}\"'`       │ <Tab>   │\n │ jump_before_open    │ Insert mode    │ Jump before ([{\"'`       │ <S-Tab> │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Work with whitespace ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ increase_indent     │ Is on indent   │ Increase indent          │ <Tab>   │\n │ decrease_indent     │ Is on indent   │ Decrease indent          │ <S-Tab> │\n │ hungry_bs           │ Space to left  │ Delete all space to left │ <BS>    │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |vim.snippet| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ vimsnippet_next     │ Session active │ Jump to next tabstop     │ <Tab>   │\n │ vimsnippet_prev     │ Session active │ Jump to prev tabstop     │ <S-Tab> │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'hrsh7th/nvim-cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ cmp_next            │ Menu visible   │ Select next item         │ <Tab>   │\n │ cmp_prev            │ Menu visible   │ Select prev item         │ <S-Tab> │\n │ cmp_accept          │ Item selected  │ Accept selected item     │ <CR>    │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'Saghen/blink.cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ blink_next          │ Menu visible   │ Select next item         │ <Tab>   │\n │ blink_prev          │ Menu visible   │ Select prev item         │ <S-Tab> │\n │ blink_accept        │ Item selected  │ Accept selected item     │ <CR>    │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'L3MON4D3/LuaSnip' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ luasnip_next        │ Session active │ Jump to next tabstop     │ <Tab>   │\n │ luasnip_prev        │ Session active │ Jump to prev tabstop     │ <S-Tab> │\n │ luasnip_expand      │ Can expand     │ Expand snippet at cursor │ <Tab>   │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'windwp/nvim-autopairs' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ nvimautopairs_cr    │ Module present │ <CR> respecting pairs    │ <CR>    │\n │ nvimautopairs_bs    │ Module present │ <BS> respecting pairs    │ <BS>    │\n └─────────────────────┴────────────────┴──────────────────────────┴─────────┘\n<\nNotes:\n- Executing action has limitations of |:map-expression| (like not allowed text\n  or buffer changes, etc.). To execute complex lua code, use |vim.schedule()|\n  inside action, return the code as string in |:map-cmd| format, or return\n  a function to be later executed. See usage examples.\n\n- Some mapped keys (like <Tab>, <CR>) might require disabling smart presets\n  in plugins (like 'nvim-cmp', 'blink-cmp', 'nvim-autopairs').\n\nParameters ~\n{mode} `(string|table)` Same as for |vim.keymap.set()|.\n{lhs} `(string)` Same as for |vim.keymap.set()|.\n{steps} `(table)` Array of steps. Each step can be a string with the name\n  of built-in step or a table with two callable methods (will be called\n  without arguments):\n  - <condition> - return `true` if the action should be executed.\n  - <action> - action to be executed if <condition> returns `true`.\n    For more flexibility, it can also return a value which can be:\n      - String - will be returned as expression output. Can be something like\n        `\"<Tab>\"` (treat as <Tab> key) or `\"<Cmd>lua vim.notify('Hello')<CR>\"`.\n        Should not escape keycodes (i.e. return \"<Tab>\" and not \"\\t\").\n        To undo already done escape, use |keytrans()|.\n      - Function - will be executed as if `\"<Cmd>lua f()<CR>\"`, but does not\n        need to create a global function for that.\n      - `false` - do not stop going through steps.\n{opts} `(table|nil)` Same as for |vim.keymap.set()|.\n\nUsage ~\nSee |MiniKeymap-examples| for practical examples.\n\nSome illustrative examples: >lua\n\n  _G.log = {}\n  local steps = {}\n  steps[1] = {\n    condition = function() table.insert(_G.log, 'C1'); return _G.cond1 end,\n    -- Compute and return keys. Will be emulated as pressed.\n    action = function() table.insert(_G.log, 'A1'); return 'hello' end,\n  }\n\n  steps[2] = {\n    condition = function() table.insert(_G.log, 'C2'); return _G.cond2 end,\n    -- Perform action immediately, return `false` to keep asking other steps\n    action = function() table.insert(_G.log, 'A2'); return false end,\n  }\n\n  steps[3] = {\n    condition = function() table.insert(_G.log, 'C3'); return _G.cond3 end,\n    -- Perform action later (to overcom expression mapping limitations)\n    action = function()\n      table.insert(_G.log, 'A3_1')\n      return function() table.insert(_G.log, 'A3_2') end\n    end,\n  }\n\n  -- Make Insert mode <Tab> mapping\n  require('mini.keymap').map_multistep('i', '<Tab>', steps)\n\n  -- Pressing <Tab> inserts fallback `\\t`; logs C1+C2+C3\n  _G.cond1, _G.cond2, _G.cond3 = false, false, false\n\n  -- Pressing <Tab> inserts `hello`; logs C1+A1\n  _G.cond1, _G.cond2, _G.cond3 = true, false, false\n\n  -- Pressing <Tab> inserts nothing; logs C1+C2+A2+C3+A3_1+A3_2\n  _G.cond1, _G.cond2, _G.cond3 = false, true, true\n<\n------------------------------------------------------------------------------\n                                                           *MiniKeymap.gen_step*\n                             `MiniKeymap.gen_step`\nGenerate step for multi-step mappings\n\nThis is a table with function elements. Call to actually get a step.\n\n------------------------------------------------------------------------------\n                                          *MiniKeymap.gen_step.search_pattern()*\n        `MiniKeymap.gen_step.search_pattern`({pattern}, {flags}, {opts})\nSearch pattern step\n\nUse |search()| to jump to pattern match. Possibly adjust final position to\nbe just to the right of the match (useful in Insert mode).\n\nParameters ~\n{pattern} `(string)` Same as for |search()|.\n{flags} `(string|nil)` Same as for |search()|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <side> `(string)` - one of `\"before\"` (default) or `\"after\"`.\n  - <stopline> `(number|function)` - forwarded to |search()| (as number or\n    as function's output after calling it before every search).\n  - <timeout> `(number)` - forwarded to |search()|.\n  - <skip> `(string|function)` - forwarded to |search()|.\n\nReturn ~\n`(table)` Step which searches pattern.\n\nUsage ~\nBuilt-in |MiniKeymap.map_multistep()| steps \"jump_after_close\" and\n\"jump_before_open\" use this, but only in Insert mode.\n\nSteps that jump before/after all consecutive brackets in several modes: >lua\n\n  local keymap = require('mini.keymap')\n  local tab_step_insert = keymap.gen_step.search_pattern(\n    -- Need to use 'c' flag and 'after' side for robust \"chaining\"\n    [=[[)\\]}]\\+]=], 'ceW', { side = 'after' }\n  )\n  keymap.map_multistep('i', '<Tab>', { tab_step_insert })\n  local tab_step = keymap.gen_step.search_pattern([=[[)\\]}]\\+]=], 'eW')\n  keymap.map_multistep({ 'n', 'x' }, '<Tab>', { tab_step })\n\n  local stab_step = keymap.gen_step.search_pattern([=[[(\\[{]\\+]=], 'bW')\n  keymap.map_multistep({ 'i', 'n', 'x' }, '<S-Tab>', { stab_step })\n<\n------------------------------------------------------------------------------\n                                                        *MiniKeymap.map_combo()*\n            `MiniKeymap.map_combo`({mode}, {lhs}, {action}, {opts})\nMap combo post action\n\nCreate a combo: sequence of keys where each acts immediately plus execute\nan extra action if all are typed within configurable delay between each other.\n\nExample for Insert mode \"better escape\" `jk` combo with `<BS><BS><Esc>` action:\n- Press `j`. It is visible immediately without any side effects.\n- Quickly (no more than default 200 ms after) press `k`. This triggers the\n  action which is equivalent to typing <BS><BS> (delete already present `jk`)\n  and <Esc> to exit into Normal mode.\n\nNotes:\n- IMPORTANT! Combo is not a regular mapping but a separate key tracking\n  with |vim.on_key()|. This is important as combos will not be visible and\n  can not be managed as regular mappings. Instead each combo is associated\n  with a dedicated |namespace| (named for human readability). However, it is not\n  really expected to manage them on the fly after they are created.\n\n- String action is executed with |nvim_input()|, i.e. emulated keys will\n  respect custom mappings.\n\n- Different combos are tracked and act independent of each other. For example,\n  if there are combos for `jjk` and `jk` keys, fast typing `jjk` will execute both.\n\n- Neovim>=0.11 is recommended due to |vim.on_key()| improvement to allow\n  watching for keys as they are typed and not as if coming from mappings.\n  For example, this matters when creating a `jk` combo for Visual mode while\n  also having `xnoremap j gj` style of remaps. On Neovim<0.11 the fix is to\n  use `gjgk` as combo's left hand side.\n\n- Each combo adds very small but non-zero overhead on each keystroke.\n  Usually about 1-3 microseconds (i.e. 0.001-0.003 ms), which should be\n  fast enough for most setups. For a \"normal, real world\" coding session\n  with a total of ~20000 keystrokes it results in extra ~40ms of overhead\n  for a single created combo. Create many combos with caution.\n\nParameters ~\n{mode} `(string|table)` String or array of string mode id (like \"n\", \"i\", etc.).\n  Array of several modes is more performant than several single mode combos.\n{lhs} `(string|table)` String with tracked key sequence or an array of\n  tracked keys (one element - one key).\n{action} `(string|function)` Action to perform after key sequence is detected.\n  If string, treated as keys and emulated with |nvim_input()|.\n  If function, executed in |vim.schedule()|. Can return string keys which will\n  be emulated.\n{opts} `(table|nil)` Options. Possible fields:\n  - <delay> `(number)` - delay in milliseconds within which keys should be\n    pressed to detect a key sequence. Default: 200.\n\nUsage ~\nSee |MiniKeymap-examples| for practical examples.\n\nSome illustrative examples: >lua\n\n  local map_combo = require('mini.keymap').map_combo\n\n  -- In Insert mode pressing `x` followed by `x` within 1 second logs 'A'\n  -- and emulates extra pressing of `yy`\n  _G.log = {}\n  local action = function() table.insert(_G.log, 'A'); return 'yy' end\n  map_combo('i', 'xx', action, { delay = 1000 })\n<\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-map.txt",
    "content": "*mini.map* Window with buffer text overview\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                       *MiniMap*\nFeatures:\n- Show and manage special floating window displaying automatically updated\n  overview of current buffer text. Window takes up whole height of Neovim\n  instance and is fixed to a left/right side. Map content is computed by\n  taking all current lines, converting it to binary whitespace/non-whitespace\n  mask, rescaling to appropriate dimensions, and converting back to strings\n  consisting from special encoding symbols. All this is done **very fast** and\n  **asynchronously**. See |MiniMap.open()|, |MiniMap.refresh()|, |MiniMap.close()|,\n  |MiniMap.toggle()|, |MiniMap.toggle_side()|.\n  For a general overview and tips, see |mini.map-usage|.\n\n- Show scrollbar next to map content. It represents current line and view\n  (top and bottom visible lines). Can be the only thing shown, making map\n  window a \"pure scrollbar\". See \"Pure scrollbar config\" section in\n  |MiniMap.config|.\n\n- Highlight map lines representing certain data in current buffer. This is\n  done via extensible set of callables, called integrations (see\n  \"Integrations\" section in |MiniMap.config|). There are pre-built generators\n  for common integrations:\n    - Builtin search (as result of |/| and similar).\n    - Builtin diagnostic (taken from |vim.diagnostic.get()|).\n    - General diff hunks provided by |mini.diff|.\n    - Hunks computed provided by 'lewis6991/gitsigns.nvim'.\n  For more details see |MiniMap.gen_integration|.\n\n- Focus on map window to quickly browse current (source) buffer. Moving inside\n  map window updates cursor position in source window enabling fast and\n  targeted buffer exploration. To focus back, hit `<CR>` to accept current\n  explored position or `<Esc>` to go back to original position. See\n  |MiniMap.toggle_focus()|.\n\n- Customizable via |MiniMap.config| and/or `opts` argument of |MiniMap.open()|\n  or |MiniMap.refresh()|:\n    - Encoding symbols used to display binary information of different\n      resolution (default is 3x2). There are pre-built generators for\n      different basic character families and resolutions. See\n      |MiniMap.gen_encode_symbols|.\n    - Scrollbar symbols, separate for line and view. Can have any width\n      (even zero, which virtually disables scrollbar).\n    - Integrations producing map line highlights.\n    - Window options: side (left/right), width, 'winblend', and more.\n\nWhat it doesn't do:\n- Automatically refresh when typing in Insert mode. Although it can be done in\n  non-blocking way, it still might introduce considerable computation overhead\n  (especially in very large files).\n- Has more flexible window configuration. In case a full height floating\n  window obstructs vision of underlying buffers, use |MiniMap.toggle()| or\n  |MiniMap.toggle_side()|. Works best with global statusline.\n- Provide autoopen functionality. Due to vast differences in user preference\n  of when map window should be shown, set up of automatic opening is left to\n  user. A common approach would be to call `MiniMap.open()` on |VimEnter| event.\n  If you use |mini.starter|, you can modify `<CR>` buffer mapping: >lua\n\n    local set_map_keymap = function()\n      local rhs = function()\n        MiniStarter.eval_current_item()\n        MiniMap.open()\n      end\n      vim.keymap.set('n', '<CR>', rhs, { buffer = true })\n    end\n    local opts = { pattern = 'MiniStarterOpened', callback = set_map_keymap }\n    vim.api.nvim_create_autocmd('User', opts)\n<\n# Setup ~\n\nThis module needs a setup with `require('mini.map').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniMap`\nwhich you can use for scripting or manually (with `:lua MiniMap.*`).\n\nSee |MiniMap.config| for available config settings.\n\nYou can override runtime config settings (like `config.modifiers`) locally\nto buffer inside `vim.b.minimap_config` which should have same structure\nas `MiniMap.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Dependencies ~\n\nSuggested dependencies (provide extra functionality for integrations):\n- Enabled |mini.diff| module for general diff highlighting via\n  |MiniMap.gen_integration.diff()|. If missing, no highlighting is added.\n- Plugin [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n  for Git status highlighting via |MiniMap.gen_integration.gitsigns()|.\n  If missing, no highlighting is added.\n\n# Comparisons ~\n\n- [wfxr/minimap.vim](https://github.com/wfxr/minimap.vim):\n    - 'mini.map' doesn't have dependencies while being as fast as written\n      in Rust dependency of 'minimap.vim'.\n    - 'mini.map' uses floating window, while 'minimap.vim' uses regular one.\n    - 'mini.map' provides slightly different visual interface with\n      scrollbar and integration counts.\n    - 'mini.map' allows encode symbols customization, 'minimap.vim' does not.\n    - 'mini.map' allows extending highlight integrations, while only\n      builtin search and git status are supported in 'minimap.vim'.\n    - 'mini.map' updates in asynchronous (non-blocking) fashion, 'minimap.vim'\n      does not.\n    - 'mini.map' can be used as a pure scrollbar, 'minimap.vim' can not.\n- [dstein64/nvim-scrollview](https://github.com/dstein64/nvim-scrollview):\n    - 'mini.map' has two-part scrollbar showing current line and view (with\n      variable height), while 'nvim-scrollview' shows only current view\n      (with fixed height).\n    - 'nvim-scrollview' respects folds, i.e. shows view of visible lines,\n      while 'mini.map' by design always shows view based on actual lines.\n    - 'nvim-scrollview' creates scrollbar which can be dragged with mouse,\n      while 'mini.nvim' does not, by design (use |MiniMap.toggle_focus()|).\n    - 'mini.map' can show buffer outline, while 'nvim-scrollview' can not.\n    - 'mini.map' can show highlight integrations, while 'nvim-scrollview'\n      can not.\n- [petertriho/nvim-scrollbar](https://github.com/petertriho/nvim-scrollbar):\n    - 'mini.map' has two-part scrollbar showing current line and view (with\n      variable height), while 'nvim-scrollbar' shows only current view.\n    - 'mini.map' can show buffer outline, while 'nvim-scrollbar' can not.\n    - 'mini.map' has fully extendable highlight integrations, while\n      'nvim-scrollbar' only supports diagnostic and search (with dependency).\n- [lewis6991/satellite.nvim](https://github.com/lewis6991/satellite.nvim):\n    - Almost the same differences as with 'dstein64/nvim-scrollview', except\n      'satellite.nvim' can display some set of integration highlights.\n\n# Highlight groups ~\n\n- `MiniMapNormal` - basic highlight of whole window.\n- `MiniMapSymbolCount` - counts of per-line integration items.\n- `MiniMapSymbolLine` - scrollbar part representing current line.\n- `MiniMapSymbolView` - scrollbar part representing current view.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minimap_disable` (globally) or `vim.b.minimap_disable`\n(for a buffer) to `true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                                *mini.map-usage*\n# Mappings ~\n\nThis module doesn't make mappings, only provides functions for users to map\nmanually. Here is how one |<Leader>| set of mappings can be constructed: >lua\n\n  vim.keymap.set('n', '<Leader>mc', MiniMap.close)\n  vim.keymap.set('n', '<Leader>mf', MiniMap.toggle_focus)\n  vim.keymap.set('n', '<Leader>mo', MiniMap.open)\n  vim.keymap.set('n', '<Leader>mr', MiniMap.refresh)\n  vim.keymap.set('n', '<Leader>ms', MiniMap.toggle_side)\n  vim.keymap.set('n', '<Leader>mt', MiniMap.toggle)\n<\n# How automatic refresh works ~\n\nAutomatic refresh is done by calling |MiniMap.refresh()| when appropriate\n|events| occur. It is done with specially chosen `parts` argument value (to\navoid unnecessary computations). For example, when only cursor has moved\n(|CursorMoved|), only scrollbar is updated; so no recomputation of integrations\nor line encoding is done.\n\nTo avoid visual clutter, automatic refresh is done only in normal buffers\nand help pages (i.e. with |'buftype'| being empty or \"help\")\n\nWhen you think content is not up to date, try one of these:\n- Call |MiniMap.refresh()| manually. Make mapping to make it easier.\n- Save current buffer, for example with |:write|.\n- Exit and enter Normal mode (if your Neovim version supports |ModeChanged|).\n\n------------------------------------------------------------------------------\n                                                               *MiniMap.setup()*\n                           `MiniMap.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniMap.config|.\n\nUsage ~\n>lua\n  require('mini.map').setup() -- use default config\n  -- OR\n  require('mini.map').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                                *MiniMap.config*\n                                `MiniMap.config`\nDefaults ~\n>lua\n  MiniMap.config = {\n    -- Highlight integrations (none by default)\n    integrations = nil,\n\n    -- Symbols used to display data\n    symbols = {\n      -- Encode symbols. See `:h MiniMap.config` for specification and\n      -- `:h MiniMap.gen_encode_symbols` for pre-built ones.\n      -- Default: solid blocks with 3x2 resolution.\n      encode = nil,\n\n      -- Scrollbar parts for view and line. Use empty string to disable any.\n      scroll_line = '█',\n      scroll_view = '┃',\n    },\n\n    -- Window options\n    window = {\n      -- Whether window is focusable in normal way (with `wincmd` or mouse)\n      focusable = false,\n\n      -- Side to stick ('left' or 'right')\n      side = 'right',\n\n      -- Whether to show count of multiple integration highlights\n      show_integration_count = true,\n\n      -- Total width\n      width = 10,\n\n      -- Value of 'winblend' option\n      winblend = 25,\n\n      -- Z-index\n      zindex = 10,\n    },\n  }\n<\n# Symbols ~\n\nOptions in `config.symbols` define characters used to display various\ninformation in map window.\n\n## Encode symbols ~\n\nThe `config.symbols.encode` option defines which characters are used to\nencode source buffer lines. For details of encode algorithm, see\n|MiniMap.encode_strings()|.\n\nThis option should be a table with the following structure:\n- <resolution> field - table containing <row> and <col> elements with row\n  and column resolution of each symbol. This defines encoding structure and\n  number of needed encode symbols.\n- Numerical fields 1, 2, ..., 2^(row_resolution * col_resolution). Each symbol\n  represents a `(row_resolution, col_resolution)` boolean mask (`true` for\n  non-whitespace, `false` for whitespace), created as (reversed) binary digit:\n  `true` as 1; `false` as 0. Traversing left-right, top-bottom (top-left is\n  lowest bit, bottom-right - highest). So first symbol encodes a complete\n  whitespace, last - complete non-whitespace.\n\nIf `nil` (default), output of |MiniMap.gen_encode_symbols.block()| with `'3x2'`\nidentifier is used.\n\nExample: { '1', '2', '3', '4', resolution = { row = 1, col = 2 } }. This\nwill encode two characters in each input row. So a string `'  a  aaa'` will\nbe encoded as `'1234'`.\n\nThere are pre-built generators of encode symbols:\n- |MiniMap.gen_encode_symbols.block()|\n- |MiniMap.gen_encode_symbols.dot()|\n- |MiniMap.gen_encode_symbols.shade()|\n\n## Scrollbar symbols ~\n\nOptions `config.symbols.scroll_line` and `config.symbols.scroll_view` define\nstrings used to represent current line and current view inside map window.\nCan have any length, map window content will adjust.\n\nIf supplied window width is small enough so that only (part of) of\nscrollbar can be shown, it is called a \"pure scrollbar\". The behavior differs\nslightly from normal map window. See \"Pure scrollbar config\" later section.\n\nSome suggestions for scrollbar symbols:\n- View-line pairs: '▒' and '█'.\n- Line - '🮚', '▶'.\n- View - '╎', '┋', '┋'.\n\n# Integrations ~\n\nOption `config.integrations` is an array of integrations. Each one is used\nto define map line highlights representing some important lines in source\nbuffer. If `nil` (default), no integrations are used.\n\nEach integration should be a callable returning an array with data about\n**source buffer** lines it wants to highlight. Each array element should be\na table with <line> (source buffer line number) and <hl_group> (string with\nhighlight group name) keys. Note: line number outside of source buffer\ncount will be converted to a nearest appropriate one.\n\nExample output of single integration: >lua\n\n  {\n    { line = 1, hl_group = 'Search' },\n    { line = 2, hl_group = 'Operator' },\n    { line = 9, hl_group = 'Search'}\n  }\n<\nConversion to map highlights is done on a \"first seen\" basis: actual\nhighlight group applied to a map line is taken from the first integration\noutput convertible to that map line. Other outputs with same map line\n(after conversion) contribute to integration count shown between scrollbar\nand encoded lines (if `config.window.show_integration_count` is `true`).\n\nPrevious example output with default `'3x2'` resolution will add |hl-Search|\nhighlight on map lines 1 and 3, and show integration count 2 on first line.\n\nEvery element of integrations array is called one by one from start to end\nwith their outputs appended to end of single array. This means that more\nimportant integrations should be placed in the beginning of an array, as\nthis will make them have higher priority in case other integrations will\nhighlight same map line.\n\nExample of using `config.integrations`: >lua\n\n  local map = require('mini.map')\n  map.setup({\n    integrations = {\n      map.gen_integration.builtin_search(),\n      map.gen_integration.diff(),\n      map.gen_integration.diagnostic(),\n    },\n  })\n<\n# Window config ~\n\nOption `config.window` defines some properties of map window.\n\n`window.focusable` - whether to allow focusing on map window with other\nmethods beside |MiniMap.toggle_focus()| (like |:wincmd|, |CTRL-W|, or mouse).\nDefault: `false`.\n\n`window.side` - which side to stick map window: `'left'` or `'right'` (default).\n\n`window.show_integration_count` - whether to show integration count between\nscrollbar and encoded lines. Integration count is a number of integration\noutputs which were converted to same map line. When `true`, adds single\ncell column with numbers from 2 to 9 and character '+' indicating count\ngreater than 9. Count 1 is not shown, because it is redundant to highlighted\nmap line. Default: `true`.\n\n`window.width` - width of floating window, including scrollbar and\nintegration count column. Default: 10.\n\n`window.winblend` - value of 'winblend' of floating window. Value 0 makes it\ncompletely non-transparent, 100 - completely transparent (content is still\nvisible, but with slightly different highlights).\n\n`window.zindex` - z-index of floating window. Default: 10.\n\n# Pure scrollbar config ~\n\n\"Pure scrollbar\" is a configuration when window width is not enough to show\nencoded content. It has following differences from default \"map\" approach:\n- It doesn't perform line encoding with |MiniMap.encode_strings()|\n  but instead uses encoding with fixed number of lines (equal to window\n  height).\n- Integration highlights are not computed.\n\nConfig: >lua\n\n  require('mini.map').setup({\n    -- Customize `symbols` to your liking\n\n    window = {\n      -- Set this to the maximum width of your scroll symbols\n      width = 1,\n\n      -- Set this to your liking. Try values 0, 25, 50, 75, 100\n      winblend = 100,\n\n      -- Don't need extra column\n      show_integration_count = false,\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                                               *MiniMap.current*\n                               `MiniMap.current`\nTable with information about current state of map\n\nAt least these keys are supported:\n- <buf_data> - table with buffer identifiers. Field <map> contains\n  identifier of a buffer used to display map. Field <source> - buffer\n  identifier which content map is displaying (i.e. source buffer).\n- <win_data> - table of window identifiers used to display map in certain\n  tabpage. Keys: tabpage identifier. Values: window identifier.\n- <opts> - current options used to control map display. Same structure\n  as |MiniMap.config|. Takes precedence over global and buffer-local configs.\n  Is reset when last map window is closed with |MiniMap.close()|.\n\n------------------------------------------------------------------------------\n                                                      *MiniMap.encode_strings()*\n                  `MiniMap.encode_strings`({strings}, {opts})\nEncode strings\n\nThis takes arbitrary array of strings and computes its non-whitespace\noutline. Output is an array of strings with configurable array length, string\nwidth, and symbols representing encoding.\n\nEach encode symbol is assumed to have resolution within which it can convey\nbinary information. For example, resolution `3x2` (row resolution 3,\ncolumn - 2) means that each symbol can encode 3 rows and 2 columns of\nbinary data. Here it is used to encode non-whitespace mask. See more in\n\"Encode symbols\" section of |MiniMap.config|.\n\nEncoding has the following steps:\n- Convert strings to boolean mask: 2d boolean array with each row\n  representing a string. Element in every row subarray is `true` if\n  respective (possibly multibyte) character in a string is not a whitespace,\n  `false` otherwise. Note: tabs are expanded into 'tabstop' spaces.\n- Rescale to appropriate dimensions:\n    - Each output dimension is just enough to encode all input strings, but\n      not more than supplied dimensions (`opts.n_rows * resolution.row` and\n      `opts.n_cols * resolution.col` respectively).\n    - If input dimensions are too big to fit inside output, perform grid\n      downscaling with loss of information. Input boolean mask is divided\n      into 2d-bins with as equal as possible dimensions. Each bin then\n      converted into single boolean value: `true` if bin contains at least\n      one `true` element, `false` otherwise. This leads to a whitespace\n      output meaning that **all** entries in a bin are whitespace, while\n      non-whitespace output means that **some** entry is non-whitespace.\n- Convert boolean mask to symbol strings:\n    - Input rescaled boolean mask is divided into bins with dimensions of\n      symbol resolution (assuming `false` outer padding).\n    - Each bin with resolution dimensions is transformed into encode symbol.\n      Single convertible `(resolution.row, resolution.col)` boolean\n      mask is treated as (reversed) binary digit: `true` as 1; `false` as 0.\n      Traversing left-right, top-bottom (top-left is lowest bit,\n      bottom-right - highest).\n\nExample:\n\nAssume the output should have 3 rows of symbols each with width 2. Encode\nsymbols are ' ', '▌', '▐', '█' with `1x2` resolution.\n\nAssume input strings: >\n  aaaaa\n   b b\n\n   d d\n  e e\n<\nSteps:\n- Convert to boolean mask (each row is a boolean array, \"t\"/\"f\" ~ `true`/`false`,\n  empty spots are equivalent to being `false`): >\n  ttttt\n  ftft\n\n  ftft\n  tft\n<\n- Rescale. Output dimensions are `n_rows * resolution.row = 3 * 1 = 3` rows and\n  `n_cols * resolution.col = 2 * 2 = 4`. It creates as equal as possible grid\n  with 3 rows and 4 columns and converts bins to single booleans. Result: >\n  tttt\n  tftf\n  ttff\n<\n- Convert to symbols. It makes `1x2` bins, treats their input as (reversed)\n  binary digits (`ff=00=0`, `tf=10=1`, `ft=01=2`, `tt=11=3`) and takes\n  corresponding symbols from supplied options (value plus 1). Result: >\n  ██\n  ▌▌\n  █\n<\nParameters ~\n{strings} `(table)` Array of arbitrary strings.\n{opts} `(table|nil)` Options. Possible fields:\n  - <n_rows> - number of rows in output encoding. If too big, will be\n    truncated to be maximum needed to encode all input strings (taking into\n    account symbols row resolution). Default: `math.huge`.\n  - <n_cols> - width of every encoding string. If too big, will be truncated\n    to be maximum needed to encode all input strings (taking into account\n    symbols column resolution). Default: `math.huge`.\n  - <symbols> - array of symbols with extra `resolution` field. See \"Encode\n    symbols\" section of |MiniMap.config| for more details. Default: output\n    of |MiniMap.gen_encode_symbols.block()| with `'3x2'` identifier.\n\nReturn ~\n`(table)` Array of encoded strings.\n\n------------------------------------------------------------------------------\n                                                                *MiniMap.open()*\n                             `MiniMap.open`({opts})\nOpen map window\n\nThis creates and shows map window in current tabpage. It basically has\ntwo steps:\n- If not already done, create map buffer (used to set lines and other\n  visual indicators) and map window.\n- Call |MiniMap.refresh()|.\n\nParameters ~\n{opts} `(table|nil)` Options used to define map configuration. Same structure\n  as |MiniMap.config|. Will have effect until at least one tabpage has opened\n  map window. Default values are taken in the following order:\n  - From `opts` field of |MiniMap.current|.\n  - From `vim.b.minimap_config`.\n  - From |MiniMap.config|.\n\n------------------------------------------------------------------------------\n                                                             *MiniMap.refresh()*\n                       `MiniMap.refresh`({opts}, {parts})\nRefresh map window\n\nThis function serves two purposes:\n- Update current map configuration via `opts`.\n- Update parts of displayed content via `parts`.\n\nParameters ~\n{opts} `(table|nil)` Options used to define map configuration. Same structure\n  as |MiniMap.config|. Will have effect until at least one tabpage has opened\n  map window. Default values are taken in the following order:\n  - From `opts` field of |MiniMap.current|.\n  - From `vim.b.minimap_config`.\n  - From |MiniMap.config|.\n{parts} `(table|nil)` Which parts to update. Recognised keys with boolean\n  values (all `true` by default):\n  - <integrations> - whether to update integration highlights.\n  - <lines> - whether to update map lines.\n  - <scrollbar> - whether to update scrollbar.\n\n------------------------------------------------------------------------------\n                                                               *MiniMap.close()*\n                               `MiniMap.close`()\nClose map window\n\nAlso resets `opts` field of |MiniMap.current| after closing last map window\n(among possibly several tabpages).\n\n------------------------------------------------------------------------------\n                                                              *MiniMap.toggle()*\n                            `MiniMap.toggle`({opts})\nToggle map window\n\nOpen if not shown in current tabpage, close otherwise.\n\nParameters ~\n{opts} `(table|nil)` Input for |MiniMap.open()|.\n\n------------------------------------------------------------------------------\n                                                        *MiniMap.toggle_focus()*\n                 `MiniMap.toggle_focus`({use_previous_cursor})\nToggle focus to/from map window\n\nWhen not inside map window, put cursor inside map window; otherwise put\ncursor in previous window with source buffer.\n\nWhen cursor is moving inside map window (but not just after focusing), view of\nsource window is updated to show first line convertible to current map line.\nThis allows quick targeted source buffer exploration.\n\nThere are at least these extra methods to focus back from map window:\n- Press `<CR>` to accept current explored position in source buffer.\n  Equivalent to calling this function with `false` argument.\n- Press `<Esc>` to go back to original position prior focusing on map window.\n  Equivalent to calling this function with `true` argument.\n\nParameters ~\n{use_previous_cursor} `(boolean|nil)` Whether to focus on source window at\n  original cursor position (the one prior focusing on map window).\n\n------------------------------------------------------------------------------\n                                                         *MiniMap.toggle_side()*\n                            `MiniMap.toggle_side`()\nToggle side of map window\n\nA small convenience wrapper for calling |MiniMap.refresh()| to change the\nside of map window.\n\n------------------------------------------------------------------------------\n                                                    *MiniMap.gen_encode_symbols*\n                          `MiniMap.gen_encode_symbols`\nGenerate encode symbols\n\nThis is a table with function elements. Call to actually get encode symbols.\n\nEach element takes a string resolution identifier of a form `'rxc'` (like `'3x2'`)\nwhere `r` is a row resolution of each symbol (how many rows of binary data it\ncan encode) and `c` is a column resolution (how many columns it can encode).\n\n------------------------------------------------------------------------------\n                                            *MiniMap.gen_encode_symbols.block()*\n                    `MiniMap.gen_encode_symbols.block`({id})\nGenerate block encode symbols\n\nOutputs use solid block to encode binary data. Example: '🬗', '▟', '█'.\n\nParameters ~\n{id} `(string)` Resolution identifier.\n  Available values: `'1x2'`, `'2x1'`, `'2x2'`, `'3x2'` (default in 'mini.map').\n\n------------------------------------------------------------------------------\n                                              *MiniMap.gen_encode_symbols.dot()*\n                     `MiniMap.gen_encode_symbols.dot`({id})\nGenerate dot encode symbols\n\nOutputs use dots to encode binary data. Example: '⡪', '⣼', '⣿'.\n\nParameters ~\n{id} `(string)` Resolution identifier. Available values: `'4x2'`, `'3x2'`.\n\n------------------------------------------------------------------------------\n                                            *MiniMap.gen_encode_symbols.shade()*\n                    `MiniMap.gen_encode_symbols.shade`({id})\nGenerate shade encode symbols\n\nOutputs use whole cell shades to encode binary data. They use same set of\ncharacters ('░', '▒', '▒', '▓), but with different resolution.\n\nParameters ~\n{id} `(string)` Resolution identifier. Available values: `'1x2'`, `'2x1'`.\n\n------------------------------------------------------------------------------\n                                                       *MiniMap.gen_integration*\n                           `MiniMap.gen_integration`\nGenerate integrations\n\nThis is a table with function elements. Call to actually get encode symbols.\n\nEach element takes a table defining highlight groups used for to highlight\nmap lines.\n\n------------------------------------------------------------------------------\n                                      *MiniMap.gen_integration.builtin_search()*\n             `MiniMap.gen_integration.builtin_search`({hl_groups})\nBuiltin search\n\nHighlight lines with matches of current builtin search (like with |/|, |?|, etc.).\nIntegration count reflects number of actual matches.\n\nIt prompts integration highlighting update on every change of |'hlsearch'|\n(see |OptionSet|) or |v:hlsearch|. Note that it is not happening for some keys:\n- After starting search with |n|, |N|, |star|, or |#|.\n  To enable highlight update on this keys, make custom mappings. Like this: >lua\n\n  for _, key in ipairs({ 'n', 'N', '*', '#' }) do\n    local rhs = key ..\n      '<Cmd>lua MiniMap.refresh({}, {lines = false, scrollbar = false})<CR>'\n    vim.keymap.set('n', key, rhs)\n  end\n<\nParameters ~\n{hl_groups} `(table|nil)` Table defining highlight groups. Can have the\n  following fields:\n  - <search> - highlight group for search matches. Default: |hl-Search|.\n\n------------------------------------------------------------------------------\n                                          *MiniMap.gen_integration.diagnostic()*\n               `MiniMap.gen_integration.diagnostic`({hl_groups})\nBuiltin diagnostic\n\nHighlight lines with matches of current diagnostic items. Items are computed\nwith |vim.diagnostic.get()| for current (source) buffer.\n\nIt prompts integration highlighting update on every |DiagnosticChanged| event.\nDiagnostic items with higher severity (see |vim.diagnostic.severity|) have\nhigher highlight priority (errors will be shown over all others, etc.).\n\nParameters ~\n{hl_groups} `(table|nil)` Table defining highlight groups. Supplied fields\n  also define which diagnostic severity to highlight.\n  Can have the following fields:\n  - <error> - highlight group for error items.\n    Default: |hl-DiagnosticFloatingError|.\n  - <warn> - highlight group for warning items. Default: `nil` (not shown).\n  - <info> - highlight group for info items. Default: `nil` (not shown).\n  - <hint> - highlight group for hint items. Default: `nil` (not shown).\n\nUsage ~\n>lua\n  -- Show all diagnostic levels\n  local map = require('mini.map')\n  local diagnostic_integration = map.gen_integration.diagnostic({\n    error = 'DiagnosticFloatingError',\n    warn  = 'DiagnosticFloatingWarn',\n    info  = 'DiagnosticFloatingInfo',\n    hint  = 'DiagnosticFloatingHint',\n  })\n  map.setup({ integrations = { diagnostic_integration } })\n<\n------------------------------------------------------------------------------\n                                                *MiniMap.gen_integration.diff()*\n                  `MiniMap.gen_integration.diff`({hl_groups})\nGeneral diff hunks from |mini.diff|\n\nHighlight lines which are part of current diff.\nRequires 'mini.diff' as dependency.\n\nParameters ~\n{hl_groups} `(table|nil)` Table defining highlight groups. If `nil` (not\n  supplied), this status is not highlighted. Can have the following fields:\n  - <add> - group name for \"add\" hunks. Default: \"MiniDiffSignAdd\".\n  - <change> - group name for \"change\" hunks. Default: \"MiniDiffSignChange\".\n  - <delete> - group name for \"delete\" hunks. Default: \"MiniDiffSignDelete\".\n\n------------------------------------------------------------------------------\n                                            *MiniMap.gen_integration.gitsigns()*\n                `MiniMap.gen_integration.gitsigns`({hl_groups})\nHunks from 'lewis6991/gitsigns.nvim'\n\nHighlight lines which have non-trivial Git status.\nRequires [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim).\n\nParameters ~\n{hl_groups} `(table|nil)` Table defining highlight groups. If `nil` (not\n  supplied), this status is not highlighted. Can have the following fields:\n  - <add> - group name for added lines. Default: \"GitSignsAdd\".\n  - <change> - group name for changed lines. Default: \"GitSignsChange\".\n  - <delete> - group name for deleted lines. Default: \"GitSignsDelete\".\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-misc.txt",
    "content": "*mini.misc* Miscellaneous functions\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniMisc*\nFeatures the following functions:\n- |MiniMisc.bench_time()| to benchmark function execution time.\n  Useful in combination with `stat_summary()`.\n\n- |MiniMisc.log_add()|, |MiniMisc.log_show()| and other helper functions to work\n  with a special in-memory log array. Useful when debugging Lua code.\n\n- |MiniMisc.put()| and |MiniMisc.put_text()| to pretty print its arguments\n  into command line and current buffer respectively.\n\n- |MiniMisc.resize_window()| to resize current window to its editable width.\n\n- |MiniMisc.safely()| to execute a function on a condition and warn on error.\n  Useful to organize |init.lua| in fail-safe sections with simple lazy loading.\n\n- |MiniMisc.setup_auto_root()| to set up automated change of current directory.\n\n- |MiniMisc.setup_termbg_sync()| to set up terminal background synchronization\n  (removes possible \"frame\" around current Neovim instance).\n\n- |MiniMisc.setup_restore_cursor()| to set up automated restoration of\n  cursor position on file reopen.\n\n- |MiniMisc.stat_summary()| to compute summary statistics of numerical array.\n  Useful in combination with `bench_time()`.\n\n- |MiniMisc.tbl_head()| and |MiniMisc.tbl_tail()| to return \"first\" and \"last\"\n  elements of table.\n\n- |MiniMisc.zoom()| to zoom in and out of a buffer, making it full screen\n  in a floating window.\n\n- And more.\n\n# Setup ~\n\nThis module doesn't need setup, but it can be done to improve usability.\nSetup with `require('mini.misc').setup({})` (replace `{}` with your\n`config` table). It will create global Lua table `MiniMisc` which you can\nuse for scripting or manually (with `:lua MiniMisc.*`).\n\nSee |MiniMisc.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minimisc_config`\nwill have no effect here.\n\n------------------------------------------------------------------------------\n                                                              *MiniMisc.setup()*\n                           `MiniMisc.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniMisc.config|.\n\nUsage ~\n>lua\n  require('mini.misc').setup() -- use default config\n  -- OR\n  require('mini.misc').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniMisc.config*\n                               `MiniMisc.config`\nDefaults ~\n>lua\n  MiniMisc.config = {\n    -- Array of fields to make global (to be used as independent variables)\n    make_global = { 'put', 'put_text' },\n  }\n<\n------------------------------------------------------------------------------\n                                                         *MiniMisc.bench_time()*\n                     `MiniMisc.bench_time`({f}, {n}, {...})\nExecute `f` several times and time how long it took\n\nParameters ~\n{f} `(function)` Function which execution to benchmark.\n{n} `(number|nil)` Number of times to execute `f(...)`. Default: 1.\n{...} `(any)` Arguments when calling `f`.\n\nReturn ~\n`(...)` Table with durations (in seconds; up to nanoseconds) and\n  output of (last) function execution.\n\n------------------------------------------------------------------------------\n                                                   *MiniMisc.get_gutter_width()*\n                     `MiniMisc.get_gutter_width`({win_id})\nCompute width of gutter (info column on the left of the window)\n\nParameters ~\n{win_id} `(number|nil)` Window identifier (see |win_getid()|) for which gutter\n  width is computed. Default: 0 for current.\n\n------------------------------------------------------------------------------\n                                                            *MiniMisc.log_add()*\n                  `MiniMisc.log_add`({desc}, {state}, {opts})\nAdd an entry to the in-memory log array\n\nUseful when trying to debug a Lua code (like Neovim config or plugin).\nUse this instead of ad-hoc `print()` statements.\n\nEach entry is a table with the following fields:\n- <desc> `(any)` - entry description. Usually a string describing a place\n  in the code.\n- <state> `(any)` - data about current state. Usually a table.\n- <timestamp> `(number)` - a timestamp of when the entry was added. A number of\n  milliseconds since the in-memory log was initiated (after |MiniMisc.setup()|\n  or |MiniMisc.log_clear()|). Useful during profiling.\n\nParameters ~\n{desc} `(any)` Entry description.\n{state} `(any)` Data about current state.\n{opts} `(table|nil)` Options. Possible fields:\n  - <deepcopy> - (boolean) Whether to apply |vim.deepcopy| to the {state}.\n    Usually helpful to record the exact state during code execution and avoid\n    side effects of tables being changed in-place. Default `true`.\n\nUsage ~\n>lua\n  local t = { a = 1 }\n  MiniMisc.log_add('before', { t = t }) -- Will show `t = { a = 1 }` state\n  t.a = t.a + 1\n  MiniMisc.log_add('after', { t = t })  -- Will show `t = { a = 2 }` state\n\n  -- Use `:lua MiniMisc.log_show()` or `:=MiniMisc.log_get()` to see the log\n<\nSee also ~\n- |MiniMisc.log_get()| to get log array\n- |MiniMisc.log_show()| to show log array in the dedicated buffer\n- |MiniMisc.log_clear()| to clear the log array\n\n------------------------------------------------------------------------------\n                                                            *MiniMisc.log_get()*\n                              `MiniMisc.log_get`()\nGet log array\n\nReturn ~\n`(table[])` Log array. Returned as is, without |vim.deepcopy()|.\n\nSee also ~\n- |MiniMisc.log_add()| to add to the log array\n\n------------------------------------------------------------------------------\n                                                           *MiniMisc.log_show()*\n                             `MiniMisc.log_show`()\nShow log array in a scratch buffer\n\nSee also ~\n- |MiniMisc.log_add()| to add to the log array\n\n------------------------------------------------------------------------------\n                                                          *MiniMisc.log_clear()*\n                             `MiniMisc.log_clear`()\nClear log array\n\nThis also sets a new starting point for entry timestamps.\n\nSee also ~\n- |MiniMisc.log_add()| to add to the log array\n\n------------------------------------------------------------------------------\n                                                                *MiniMisc.put()*\n                             `MiniMisc.put`({...})\nPrint Lua objects in command line\n\nParameters ~\n{...} `(any)` Any number of objects to be printed each on separate line.\n\n------------------------------------------------------------------------------\n                                                           *MiniMisc.put_text()*\n                           `MiniMisc.put_text`({...})\nPrint Lua objects in current buffer\n\nParameters ~\n{...} `(any)` Any number of objects to be printed each on separate line.\n\n------------------------------------------------------------------------------\n                                                      *MiniMisc.resize_window()*\n                `MiniMisc.resize_window`({win_id}, {text_width})\nResize window to have exact number of editable columns\n\nParameters ~\n{win_id} `(number|nil)` Window identifier (see |win_getid()|) to be resized.\n  Default: 0 for current.\n{text_width} `(number|nil)` Number of editable columns resized window will\n  display. Default: first element of 'colorcolumn' or otherwise 'textwidth'\n  (using screen width as its default but not more than 79).\n\n------------------------------------------------------------------------------\n                                                             *MiniMisc.safely()*\n                         `MiniMisc.safely`({when}, {f})\nExecute a function on a condition and warn on error\n\nInput function is executed exactly once. Its possible error is captured and is\nshown as a |vim.notify()| warning.\n\nUseful to organize |init.lua| in fail-safe sections with simple lazy loading.\n\nParameters ~\n{when} `(string)` When to execute a function. One of:\n  - `'now'` - immediately.\n  - `'later'` - queue to be executed soon without blocking the execution of next\n    code in file. Queued functions are executed in order they are added.\n  - `'delay:<number>'` - after a specified delay with |vim.defer_fn()|.\n  - `'event:<events>'` - on whichever specified event is triggered first.\n  - `'event:<events>~<patterns>` - same as above, but events must match\n    specified |autocmd-pattern|.\n  - `'filetype:<filetypes>'` - same as `'event:FileType~<filetypes>'`, but follow\n    successful function execution with |filetype-detect| for all normal buffers\n    (if new |ftdetect| scripts were added) and sourcing |ftplugin| (for buffers\n    matching `<filetypes>`). Intended to be used for loading \"language plugins\".\n{f} `(function)` Function to execute (without arguments).\n\nUsage ~\n>lua\n  MiniMisc.safely('later', function()\n    vim.notify('This will be executed after the next \"now\" call')\n  end)\n  MiniMisc.safely('now', function() error('This will be a warning') end)\n\n  MiniMisc.safely('event:InsertEnter', function()\n    require('mini.completion').setup()\n  end)\n  MiniMisc.safely('event:CmdlineEnter~/', function()\n    vim.notify('Start searching for the first time')\n  end)\n\n  MiniMisc.safely('filetype:tex,plaintex', function()\n    -- Load plugin to improve writing LaTeX\n  end)\n<\n------------------------------------------------------------------------------\n                                                    *MiniMisc.setup_auto_root()*\n                `MiniMisc.setup_auto_root`({names}, {fallback})\nSet up automated change of current directory\n\nWhat it does:\n- Creates autocommand which on every |BufEnter| event with |MiniMisc.find_root()|\n  finds root directory for current buffer file and sets |current-directory|\n  to it (using |chdir()|).\n- Resets |'autochdir'| to `false`.\n\nParameters ~\n{names} `(table|function|nil)` Forwarded to |MiniMisc.find_root()|.\n{fallback} `(function|nil)` Forwarded to |MiniMisc.find_root()|.\n\nUsage ~\n>lua\n  require('mini.misc').setup()\n  MiniMisc.setup_auto_root()\n<\n------------------------------------------------------------------------------\n                                                          *MiniMisc.find_root()*\n              `MiniMisc.find_root`({buf_id}, {names}, {fallback})\nFind root directory\n\nBased on a buffer name (full path to file opened in a buffer) find a root\ndirectory. If buffer is not associated with file, returns `nil`.\n\nRoot directory is a directory containing at least one of pre-defined files.\nIt is searched using |vim.fs.find()| with `upward = true` starting from\ndirectory of current buffer file until first occurrence of root file(s).\n\nNotes:\n- Uses directory path caching to speed up computations. This means that no\n  changes in root directory will be detected after directory path was already\n  used in this function. Reload Neovim to account for that.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier (see |bufnr()|) to use.\n  Default: 0 for current.\n{names} `(table|function|nil)` Array of file names or a callable used to\n  identify a root directory. Forwarded to |vim.fs.find()|.\n  Default: `{ '.git', 'Makefile' }`.\n{fallback} `(function|nil)` Callable fallback to use if no root is found\n  with |vim.fs.find()|. Will be called with a buffer path and should return\n  a valid directory path.\n\n------------------------------------------------------------------------------\n                                                  *MiniMisc.setup_termbg_sync()*\n                      `MiniMisc.setup_termbg_sync`({opts})\nSet up terminal background synchronization\n\nWhat it does:\n- Checks if terminal emulator supports OSC 11 control sequence through\n  appropriate `stdout`. Stops if not.\n- Creates autocommands for |ColorScheme| and |VimResume| events, which\n  change terminal background to have same color as |guibg| of |hl-Normal|.\n- Creates autocommands for |VimLeavePre| and |VimSuspend| events which set\n  terminal background back to its original color.\n- Synchronizes background immediately to allow not depend on loading order.\n\nPrimary use case is to remove possible \"frame\" around current Neovim instance\nwhich appears if Neovim's |hl-Normal| background color differs from what is\nused by terminal emulator itself.\n\nWorks only on Neovim>=0.10.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <explicit_reset> `(boolean)` - whether to reset terminal background by\n    explicitly setting it to the color it had when this function was called.\n    Set to `true` if terminal emulator doesn't support OSC 111 control sequence.\n    Default: `false`.\n\n------------------------------------------------------------------------------\n                                               *MiniMisc.setup_restore_cursor()*\n                    `MiniMisc.setup_restore_cursor`({opts})\nRestore cursor position on file open\n\nWhen reopening a file this will make sure the cursor is placed back to the\nposition where you left before. This implements |restore-cursor| in a nicer way.\nFile should have a recognized file type (see 'filetype') and be opened in\na normal buffer (see 'buftype').\n\nNote: it relies on file mark data stored in 'shadafile' (see |shada-f|).\nBe sure to enable it.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <center> - (boolean) Center the window after we restored the cursor.\n    Default: `true`.\n  - <ignore_filetype> - Array with file types to be ignored (see 'filetype').\n    Default: `{ \"gitcommit\", \"gitrebase\" }`.\n\nUsage ~\n>lua\n  require('mini.misc').setup_restore_cursor()\n<\n------------------------------------------------------------------------------\n                                                       *MiniMisc.stat_summary()*\n                          `MiniMisc.stat_summary`({t})\nCompute summary statistics of numerical array\n\nThis might be useful to compute summary of time benchmarking with\n|MiniMisc.bench_time()|.\n\nParameters ~\n{t} `(table)` Array (table suitable for `ipairs`) of numbers.\n\nReturn ~\n`(table)` Table with summary values under following keys (may be\n  extended in the future): <maximum>, <mean>, <median>, <minimum>, <n>\n  (number of elements), <sd> (sample standard deviation).\n\n------------------------------------------------------------------------------\n                                                           *MiniMisc.tbl_head()*\n                         `MiniMisc.tbl_head`({t}, {n})\nReturn \"first\" elements of table as decided by `pairs`\n\nNote: order of elements might vary.\n\nParameters ~\n{t} `(table)` Input table.\n{n} `(number|nil)` Maximum number of first elements. Default: 5.\n\nReturn ~\n`(table)` Table with at most `n` first elements of `t` (with same keys).\n\n------------------------------------------------------------------------------\n                                                           *MiniMisc.tbl_tail()*\n                         `MiniMisc.tbl_tail`({t}, {n})\nReturn \"last\" elements of table as decided by `pairs`\n\nThis function makes two passes through elements of `t`:\n- First to count number of elements.\n- Second to construct result.\n\nNote: order of elements might vary.\n\nParameters ~\n{t} `(table)` Input table.\n{n} `(number|nil)` Maximum number of last elements. Default: 5.\n\nReturn ~\n`(table)` Table with at most `n` last elements of `t` (with same keys).\n\n------------------------------------------------------------------------------\n                                                *MiniMisc.use_nested_comments()*\n                    `MiniMisc.use_nested_comments`({buf_id})\nAdd possibility of nested comment leader\n\nThis works by parsing 'commentstring' buffer option, extracting\nnon-whitespace comment leader (symbols on the left of commented line), and\nlocally modifying 'comments' option (by prepending `n:<leader>`). Does\nnothing if 'commentstring' is empty or has comment symbols both in front\nand back (like \"/*%s*/\").\n\nNested comment leader added with this function is useful for formatting\nnested comments. For example, have in Lua \"first-level\" comments with '--'\nand \"second-level\" comments with '----'. With nested comment leader second\ntype can be formatted with `gq` in the same way as first one.\n\nRecommended usage is with |autocmd|: >lua\n\n  local use_nested_comments = function() MiniMisc.use_nested_comments() end\n  vim.api.nvim_create_autocmd('BufEnter', { callback = use_nested_comments })\n<\nNote: for most filetypes 'commentstring' option is added only when buffer\nwith this filetype is entered, so using non-current `buf_id` can not lead\nto desired effect.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier (see |bufnr()|) in which function\n  will operate. Default: 0 for current.\n\n------------------------------------------------------------------------------\n                                                               *MiniMisc.zoom()*\n                      `MiniMisc.zoom`({buf_id}, {config})\nZoom in and out of a buffer, making it full screen in a floating window\n\nThis function is useful when working with multiple windows but temporarily\nneeding to zoom into one to see more of the code from that buffer. Call it\nagain (without arguments) to zoom out.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier (see |bufnr()|) to be zoomed.\n  Default: 0 for current.\n{config} `(table|nil)` Optional config for window (as for |nvim_open_win()|).\n\nReturn ~\n`(boolean)` Whether current buffer is zoomed in.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-move.txt",
    "content": "*mini.move* Move any selection in any direction\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniMove*\nFeatures:\n- Works in two modes:\n    - Visual mode. Select text (charwise with |v|, linewise with |V|, and\n      blockwise with |CTRL-V|) and press customizable mapping to move in\n      all four directions (left, right, down, up). It keeps Visual mode.\n    - Normal mode. Press customizable mapping to move current line in all\n      four directions (left, right, down, up).\n    - Special handling of linewise movement:\n        - Vertical movement gets reindented with |=|.\n        - Horizontal movement is improved indent/dedent with |>| / |<|.\n        - Cursor moves along with selection.\n\n- Provides both mappings and Lua functions for motions. See\n  |MiniMove.move_selection()| and |MiniMove.move_line()|.\n\n- Respects |v:count|. Movement mappings can be preceded by a number which\n  multiplies command effect.\n\n- All consecutive moves (regardless of direction) can be undone by a single |u|.\n\n- Respects preferred column for vertical movement. It will vertically move\n  selection as how cursor is moving (not strictly vertically if target\n  column is not present in target line).\n\nNotes:\n- Doesn't allow moving selection outside of current lines (by design).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.move').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniMove`\nwhich you can use for scripting or manually (with `:lua MiniMove.*`).\n\nSee |MiniMove.config| for available config settings.\n\nYou can override runtime config settings (but not `config.mappings`) locally\nto buffer inside `vim.b.minimove_config` which should have same structure\nas `MiniMove.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [matze/vim-move](https://github.com/matze/vim-move):\n    - Doesn't support vertical movement of charwise and blockwise selections.\n      While 'mini.move' does.\n    - Doesn't support horizontal movement of current line in favor of\n      horizontal movement of current character. While 'mini.move' supports\n      horizontal movement of current line and doesn't support such movement\n      of current character.\n    - Has extra functionality for certain moves (like move by half page).\n      While 'mini.move' does not (by design).\n- [booperlv/nvim-gomove](https://github.com/booperlv/nvim-gomove):\n    - Doesn't support movement in charwise visual selection.\n      While 'mini.move' does.\n    - Has extra functionality beyond moving text, like duplication.\n      While 'mini.move' concentrates only on moving functionality.\n\n# Disabling ~\n\nTo disable, set `vim.g.minimove_disable` (globally) or `vim.b.minimove_disable`\n(for a buffer) to `true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                              *MiniMove.setup()*\n                           `MiniMove.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniMove.config|.\n\nUsage ~\n>lua\n  require('mini.move').setup() -- use default config\n  -- OR\n  require('mini.move').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniMove.config*\n                               `MiniMove.config`\nDefaults ~\n>lua\n  MiniMove.config = {\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      -- Move visual selection in Visual mode. Defaults are Alt (Meta) + hjkl.\n      left = '<M-h>',\n      right = '<M-l>',\n      down = '<M-j>',\n      up = '<M-k>',\n\n      -- Move current line in Normal mode\n      line_left = '<M-h>',\n      line_right = '<M-l>',\n      line_down = '<M-j>',\n      line_up = '<M-k>',\n    },\n\n    -- Options which control moving behavior\n    options = {\n      -- Automatically reindent selection during linewise vertical move\n      reindent_linewise = true,\n    },\n  }\n<\n# Mappings ~\n\nOther possible choices of mappings: >lua\n\n  -- `HJKL` for moving visual selection (overrides H, L, J in Visual mode)\n  require('mini.move').setup({\n    mappings = {\n      left  = 'H',\n      right = 'L',\n      down  = 'J',\n      up    = 'K',\n    }\n  })\n\n  -- Shift + arrows\n  require('mini.move').setup({\n    mappings = {\n      left  = '<S-left>',\n      right = '<S-right>',\n      down  = '<S-down>',\n      up    = '<S-up>',\n\n      line_left  = '<S-left>',\n      line_right = '<S-right>',\n      line_down  = '<S-down>',\n      line_up    = '<S-up>',\n    }\n  })\n<\n------------------------------------------------------------------------------\n                                                     *MiniMove.move_selection()*\n                 `MiniMove.move_selection`({direction}, {opts})\nMove visually selected region in any direction within present lines\n\nMain function powering visual selection move in Visual mode.\n\nNotes:\n- Vertical movement in linewise mode is followed up by reindent with |v_=|.\n- Horizontal movement in linewise mode is same as |v_<| and |v_>|.\n\nParameters ~\n{direction} `(string)` One of \"left\", \"down\", \"up\", \"right\".\n{opts} `(table|nil)` Options. Same structure as `options` in |MiniMove.config|\n  (with its values as defaults) plus these allowed extra fields:\n  - <n_times> (number) - number of times to try to make a move.\n    Default: |v:count1|.\n\n------------------------------------------------------------------------------\n                                                          *MiniMove.move_line()*\n                   `MiniMove.move_line`({direction}, {opts})\nMove current line in any direction\n\nMain function powering current line move in Normal mode.\n\nNotes:\n- Vertical movement is followed up by reindent with |v_=|.\n- Horizontal movement is almost the same as |<<| and |>>| with a different\n  handling of |v:count| (multiplies shift effect instead of modifying that\n  number of lines).\n\nParameters ~\n{direction} `(string)` One of \"left\", \"down\", \"up\", \"right\".\n{opts} `(table|nil)` Options. Same structure as `options` in |MiniMove.config|\n  (with its values as defaults) plus these allowed extra fields:\n  - <n_times> (number) - number of times to try to make a move.\n    Default: |v:count1|.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-notify.txt",
    "content": "*mini.notify* Show notifications\n\nMIT License Copyright (c) 2024 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniNotify*\nFeatures:\n\n- Show one or more highlighted notifications in a single floating window.\n\n- Manage notifications (add, update, remove, clear).\n\n- Custom |vim.notify()| implementation. To adjust, use |MiniNotify.make_notify()|\n  or save-restore `vim.notify` manually after calling |MiniNotify.setup()|.\n\n- Automated show of LSP progress report.\n\n- Track history which can be accessed with |MiniNotify.get_all()|\n  and shown with |MiniNotify.show_history()|.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.notify').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniNotify`\nwhich you can use for scripting or manually (with `:lua MiniNotify.*`).\n\nSee |MiniNotify.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.mininotify_config` which should have same structure as\n`MiniNotify.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [j-hui/fidget.nvim](https://github.com/j-hui/fidget.nvim):\n    - Basic goals of providing interface for notifications are similar.\n    - Has more configuration options and visual effects, while this module\n      does not (by design).\n\n- [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify):\n    - Similar to 'j-hui/fidget.nvim'.\n\n# Highlight groups ~\n\n- `MiniNotifyBorder` - window border.\n- `MiniNotifyLspProgress` - notifications from built-in LSP progress report.\n- `MiniNotifyNormal` - basic foreground/background highlighting.\n- `MiniNotifyTitle` - window title.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\nNOTE: |vim.notify()| override after |MiniNotify.make_notify()| uses own\nhighlight groups per notification level.\n\n# Disabling ~\n\nTo disable showing notifications, set `vim.g.mininotify_disable` (globally) or\n`vim.b.mininotify_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                      *MiniNotify-specification*\n# Notification specification ~\n\nNotification is a table with the following keys:\n\n- <msg> `(string)` - single string with notification message.\n  Use `\\n` to delimit several lines.\n- <level> `(string)` - notification level as key of |vim.log.levels|.\n  Like \"ERROR\", \"WARN\", \"INFO\", etc.\n- <hl_group> `(string)` - highlight group with which notification is shown.\n- <data> `(table)` - extra data to store in notification (like `source`, etc.).\n- <ts_add> `(number)` - timestamp of when notification is added.\n- <ts_update> `(number)` - timestamp of the latest notification update.\n- <ts_remove> `(number|nil)` - timestamp of when notification is removed.\n  It is `nil` if notification was never removed and thus considered \"active\".\n\nNotes:\n- Timestamps are compatible with |strftime()| and have fractional part.\n\n------------------------------------------------------------------------------\n                                                            *MiniNotify.setup()*\n                          `MiniNotify.setup`({config})\nModule setup\n\nThis will also:\n- Set |vim.notify()| custom implementation (see |MiniNotify.make_notify()|).\n- Clean the history. Use `MiniNotify.setup(MiniNotify.config)` to force\n  clean history while preserving the config.\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniNotify.config|.\n\nUsage ~\n>lua\n  require('mini.notify').setup() -- use default config\n  -- OR\n  require('mini.notify').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                             *MiniNotify.config*\n                              `MiniNotify.config`\nDefaults ~\n>lua\n  MiniNotify.config = {\n    -- Content management\n    content = {\n      -- Function which formats the notification message\n      -- By default prepends message with notification time\n      format = nil,\n\n      -- Function which orders notification array from most to least important\n      -- By default orders first by level and then by update timestamp\n      sort = nil,\n    },\n\n    -- Notifications about LSP progress\n    lsp_progress = {\n      -- Whether to enable showing\n      enable = true,\n\n      -- Notification level\n      level = 'INFO',\n\n      -- Duration (in ms) of how long last message should be shown\n      duration_last = 1000,\n    },\n\n    -- Window options\n    window = {\n      -- Floating window config\n      config = {},\n\n      -- Maximum window width as share (between 0 and 1) of available columns\n      max_width_share = 0.382,\n\n      -- Value of 'winblend' option\n      winblend = 25,\n    },\n  }\n<\n# Content ~\n\n`config.content` defines how notifications are shown.\n\n`content.format` is a function which takes single notification object\n(see |MiniNotify-specification|) and returns a string to be used directly\nwhen showing notification.\nDefault: `nil` for |MiniNotify.default_format()|.\n\n`content.sort` is a function which takes array of notification objects\n(see |MiniNotify-specification|) and returns an array of such objects.\nIt can be used to define custom order and/or filter for notifications which\nare shown simultaneously.\nNote: Input contains notifications before applying `content.format`.\nDefault: `nil` for |MiniNotify.default_sort()|.\n\nExample: >lua\n\n  require('mini.notify').setup({\n    content = {\n      -- Use notification message as is for LSP progress\n      format = function(notif)\n        if notif.data.source == 'lsp_progress' then return notif.msg end\n        return MiniNotify.default_format(notif)\n      end,\n\n      -- Show more recent notifications first\n      sort = function(notif_arr)\n        table.sort(\n          notif_arr,\n          function(a, b) return a.ts_update > b.ts_update end\n        )\n        return notif_arr\n      end,\n    },\n  })\n<\n# LSP progress ~\n\n`config.lsp_progress` defines automated notifications for LSP progress.\nIt is implemented as a single updating notification per progress with all\ninformation about it.\nSetting up is done inside |MiniNotify.setup()| via |vim.schedule()|'ed setting\nof |lsp-handler| for \"$/progress\" method.\n\n`lsp_progress.enable` is a boolean indicating whether LSP progress should\nbe shown in notifications. Can be disabled in current session.\nDefault: `true`. Note: Should be `true` during |MiniNotify.setup()| call to be able\nto enable it in current session.\n\n`lsp_progress.level` is a level to be used in |MiniNotify.add()|.\nDefault: `'INFO'`.\n\n`lsp_progress.duration_last` is a number of milliseconds for the last progress\nreport to be shown on screen before removing it.\nDefault: 1000.\n\nNotes:\n- This respects previously set handler by saving and calling it.\n- Overriding \"$/progress\" method of `vim.lsp.handlers` disables notifications.\n- All LSP progress notifications set the following fields in `data`:\n    - <source> is `\"lsp_progress\"`.\n    - <client_name> is set to client's name (provided by client or inferred).\n    - <context> is the latest LSP request context (`ctx` arg of |lsp-handler|).\n    - <response> is the latest LSP response (`result` arg of |lsp-handler|).\n\n# Window ~\n\n`config.window` defines behavior of notification window.\n\n`window.config` is a table defining floating window characteristics\nor a callable returning such table (will be called with identifier of\nwindow's buffer already showing notifications). It should have the same\nstructure as in |nvim_open_win()|. It has the following default values\nwhich show notifications in the upper right corner with upper limit on width:\n- `width` is chosen to fit buffer content but at most `window.max_width_share`\n  share of 'columns'.\n  To have higher maximum width, use function in `config.window` which computes\n  dimensions inside of it (based on buffer content).\n- `height` is chosen to fit buffer content with enabled 'wrap' (assuming\n  default value of `width`).\n- `anchor`, `col`, and `row` are \"NE\", 'columns', and 0 or 1 (depending on tabline).\n- `border` is \"single\".\n- `zindex` is 999 to be as much on top as reasonably possible.\n\n`window.max_width_share` defines maximum window width as a share of 'columns'.\nShould be a number between 0 (not included) and 1.\nDefault: 0.382.\n\nExample for showing notifications in bottom right corner: >lua\n\n  local win_config = function()\n    local has_statusline = vim.o.laststatus > 0\n    local pad = vim.o.cmdheight + (has_statusline and 1 or 0)\n    return { anchor = 'SE', col = vim.o.columns, row = vim.o.lines - pad }\n  end\n  require('mini.notify').setup({ window = { config = win_config } })\n<\n`window.winblend` defines 'winblend' value for notification window.\nDefault: 25.\n\n------------------------------------------------------------------------------\n                                                      *MiniNotify.make_notify()*\n                        `MiniNotify.make_notify`({opts})\nMake vim.notify wrapper\n\nCalling this function creates an implementation of |vim.notify()| powered by\nthis module. General idea is to show notification as soon as safely possible\n(see |vim.schedule_wrap()|) and remove it after a configurable amount of time.\n\nAll notifications set `source = \"vim.notify\"` in their `data` field.\n\nThis is used with default options inside |MiniNotify.setup()|. To adjust,\ncall manually after `setup()`. For example, to show errors longer: >lua\n\n  require('mini.notify').setup()\n  vim.notify = MiniNotify.make_notify({ ERROR = { duration = 10000 } })\n<\nTo preserve original `vim.notify`: >lua\n\n  local notify_orig = vim.notify\n  require('mini.notify').setup()\n  vim.notify = notify_orig\n<\nParameters ~\n{opts} `(table|nil)` Options to configure behavior of notification `level`\n  (as in |MiniNotify.add()|). Fields are the same as names of `vim.log.levels`\n  with values being tables with possible fields:\n  - <duration> `(number)` - duration (in ms) of how much a notification\n    should be shown. If 0 or negative, notification is not shown at all.\n  - <hl_group> `(string)` - highlight group of notification.\n  Only data different to default can be supplied.\n\n  Default: >lua\n\n  {\n    ERROR = { duration = 5000, hl_group = 'DiagnosticError'  },\n    WARN  = { duration = 5000, hl_group = 'DiagnosticWarn'   },\n    INFO  = { duration = 5000, hl_group = 'DiagnosticInfo'   },\n    DEBUG = { duration = 0,    hl_group = 'DiagnosticHint'   },\n    TRACE = { duration = 0,    hl_group = 'DiagnosticOk'     },\n    OFF   = { duration = 0,    hl_group = 'MiniNotifyNormal' },\n  }\n<\n------------------------------------------------------------------------------\n                                                              *MiniNotify.add()*\n              `MiniNotify.add`({msg}, {level}, {hl_group}, {data})\nAdd notification\n\nAdd notification to history. It is considered \"active\" and is shown.\nTo hide, call |MiniNotify.remove()| with identifier this function returns.\n\nExample: >lua\n\n  local id = MiniNotify.add('Hello', 'WARN', 'Comment')\n  vim.defer_fn(function() MiniNotify.remove(id) end, 1000)\n<\nParameters ~\n{msg} `(string)` Notification message.\n{level} `(string|nil)` Notification level as key of |vim.log.levels|.\n  Default: `'INFO'`.\n{hl_group} `(string|nil)` Notification highlight group.\n  Default: `'MiniNotifyNormal'`.\n{data} `(table|nil)` Extra data to store in the notification.\n  Default: `{}`.\n\nReturn ~\n`(number)` Notification identifier.\n\n------------------------------------------------------------------------------\n                                                           *MiniNotify.update()*\n                        `MiniNotify.update`({id}, {new})\nUpdate active notification\n\nModify contents of active notification.\n\nParameters ~\n{id} `(number)` Identifier of currently active notification as returned\n  by |MiniNotify.add()|.\n{new} `(table)` Table with contents to update. Keys should be as non-timestamp\n  fields of |MiniNotify-specification| and values - new content values.\n  If present, field `data` is updated as is. Use |MiniNotify.get()| together\n  with |vim.tbl_deep_extend()| to change only part of it.\n\n------------------------------------------------------------------------------\n                                                           *MiniNotify.remove()*\n                           `MiniNotify.remove`({id})\nRemove notification\n\nIf notification is active, make it not active (by setting `ts_remove` field).\nIf not active, do nothing.\n\nParameters ~\n{id} `(number|nil)` Identifier of previously added notification.\n  If it is not, nothing is done (silently).\n\n------------------------------------------------------------------------------\n                                                            *MiniNotify.clear()*\n                              `MiniNotify.clear`()\nRemove all active notifications\n\nHide all active notifications and stop showing window (if shown).\n\n------------------------------------------------------------------------------\n                                                          *MiniNotify.refresh()*\n                             `MiniNotify.refresh`()\nRefresh notification window\n\nMake notification window show relevant information:\n- Create an array of active notifications (see |MiniNotify-specification|).\n- Apply `config.content.sort` to an array. If output has zero notifications,\n  make notification window to not show.\n- Apply `config.content.format` to each element of notification array and\n  update its message.\n- Construct content from notifications and show them in a window.\n\nNote: effects are delayed if inside fast event (|vim.in_fast_event()|).\n\n------------------------------------------------------------------------------\n                                                              *MiniNotify.get()*\n                             `MiniNotify.get`({id})\nGet previously added notification by id\n\nParameters ~\n{id} `(number)` Identifier of notification.\n\nReturn ~\n`(table)` Notification object (see |MiniNotify-specification|).\n\n------------------------------------------------------------------------------\n                                                          *MiniNotify.get_all()*\n                             `MiniNotify.get_all`()\nGet all previously added notifications\n\nGet map of used notifications with keys being notification identifiers.\n\nCan be used to get only active notification objects. Example: >lua\n\n  -- Get active notifications\n  vim.tbl_filter(\n    function(notif) return notif.ts_remove == nil end,\n    MiniNotify.get_all()\n  )\n<\nReturn ~\n`(table)` Map with notification object values (see |MiniNotify-specification|).\n  Note: messages are taken from last valid update.\n\n------------------------------------------------------------------------------\n                                                     *MiniNotify.show_history()*\n                          `MiniNotify.show_history`()\nShow history\n\nOpen or reuse a scratch buffer with all previously shown notifications.\n\nNotes:\n- Content is ordered from oldest to newest based on latest update time.\n- Message is formatted with `config.content.format`.\n\n------------------------------------------------------------------------------\n                                                   *MiniNotify.default_format()*\n                      `MiniNotify.default_format`({notif})\nDefault content format\n\nUsed by default as `config.content.format`. Prepends notification message\nwith the human readable update time and a separator.\n\nParameters ~\n{notif} `(table)` Notification object (see |MiniNotify-specification|).\n\nReturn ~\n`(string)` Formatted notification message.\n\n------------------------------------------------------------------------------\n                                                     *MiniNotify.default_sort()*\n                     `MiniNotify.default_sort`({notif_arr})\nDefault content sort\n\nUsed by default as `config.content.sort`. First sorts by notification's `level`\n(\"ERROR\" > \"WARN\" > \"INFO\" > \"DEBUG\" > \"TRACE\" > \"OFF\"; the bigger the more\nimportant); if draw - by latest update time (the later the more important).\n\nParameters ~\n{notif_arr} `(table)` Array of notifications (see |MiniNotify-specification|).\n\nReturn ~\n`(table)` Sorted array of notifications.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-nvim.txt",
    "content": "*mini.nvim* Collection of minimal, independent and fast Lua modules\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                   *mini.nvim-table-of-contents*\n|mini.nvim| is a collection of minimal, independent, and fast Lua modules\ndedicated to improve Neovim (version 0.9 and higher) experience. Each\nmodule can be considered as a separate sub-plugin.\n\nTable of contents:\n\n  General principles .......................... |mini.nvim-general-principles|\n  Module list ........................................ |mini.nvim-module-list|\n  Disabling recipes ............................ |mini.nvim-disabling-recipes|\n  Buffer-local config ........................ |mini.nvim-buffer-local-config|\n  Plugin color schemes ............................. |mini.nvim-color-schemes|\n  Extend and create a/i textobjects ................................ |mini.ai|\n  Align text interactively ...................................... |mini.align|\n  Animate common Neovim actions ............................... |mini.animate|\n  Base16 colorscheme creation .................................. |mini.base16|\n  Common configuration presets ................................. |mini.basics|\n  Go forward/backward with square brackets .................. |mini.bracketed|\n  Remove buffers ............................................ |mini.bufremove|\n  Show next key clues ............................................ |mini.clue|\n  Command line tweaks ......................................... |mini.cmdline|\n  Tweak and save any color scheme .............................. |mini.colors|\n  Comment lines ............................................... |mini.comment|\n  Completion and signature help ............................ |mini.completion|\n  Autohighlight word under cursor .......................... |mini.cursorword|\n  Plugin manager ................................................. |mini.deps|\n  Work with diff hunks ........................................... |mini.diff|\n  Generate Neovim help files ...................................... |mini.doc|\n  Extra 'mini.nvim' functionality ............................... |mini.extra|\n  Navigate and manipulate file system ........................... |mini.files|\n  Fuzzy matching ................................................ |mini.fuzzy|\n  Git integration ................................................. |mini.git|\n  Highlight patterns in text ............................... |mini.hipatterns|\n  Generate configurable color scheme ............................. |mini.hues|\n  Icon provider ................................................. |mini.icons|\n  Visualize and work with indent scope .................... |mini.indentscope|\n  Jump to next/previous single character ......................... |mini.jump|\n  Jump within visible lines .................................... |mini.jump2d|\n  Special key mappings ......................................... |mini.keymap|\n  Window with buffer text overview ................................ |mini.map|\n  Miscellaneous functions ........................................ |mini.misc|\n  Move any selection in any direction ............................ |mini.move|\n  Show notifications ........................................... |mini.notify|\n  Text edit operators ....................................... |mini.operators|\n  Autopairs ..................................................... |mini.pairs|\n  Pick anything .................................................. |mini.pick|\n  Session management ......................................... |mini.sessions|\n  Manage and expand snippets ................................. |mini.snippets|\n  Split and join arguments .................................. |mini.splitjoin|\n  Start screen ................................................ |mini.starter|\n  Statusline ............................................... |mini.statusline|\n  Surround actions ........................................... |mini.surround|\n  Tabline ..................................................... |mini.tabline|\n  Test Neovim plugins ............................................ |mini.test|\n  Trailspace (highlight and remove) ........................ |mini.trailspace|\n  Track and reuse file system visits ........................... |mini.visits|\n\n------------------------------------------------------------------------------\n                                                  *mini.nvim-general-principles*\nDesign ~\nEach module is designed to solve a particular problem targeting balance\nbetween feature-richness (handling as many edge-cases as possible) and\nsimplicity of implementation/support. Granted, not all of them ended up\nwith the same balance, but it is the goal nevertheless.\n\nIndependence ~\nModules are independent of each other and can be run without external\ndependencies. Although some of them may need dependencies for full experience.\n\nStructure ~\nEach module is a submodule for a placeholder \"mini\" module. For example,\n\"surround\" module should be referred to as \"mini.surround\". As later will\nbe explained, this plugin can also be referred to as \"MiniSurround\".\n\nSetup ~\n- Each module you want to use should be enabled separately with\n  `require(<name of module>).setup({})`. Possibly replace `{}` with your\n  config table or omit altogether to use defaults. You can supply only\n  parts of config, the rest will be inferred from defaults.\n\n- Call to module's `setup()` always creates a global Lua object with\n  coherent camel-case name: `require('mini.surround').setup()` creates\n  `_G.MiniSurround`. This allows for a simpler usage of plugin available\n  from `v:lua` like `v:lua.MiniSurround`. Considering this, \"module\" and\n  \"Lua object\" names can be used interchangeably:\n  'mini.surround' and 'MiniSurround' will mean the same thing.\n\n- Each supplied `config` table (after extending with default values) is\n  stored in `config` field of global object. Like `MiniSurround.config`.\n\n- Values of `config`, which affect runtime activity, can be changed on the\n  fly to have effect. For example, `MiniSurround.config.n_lines` can be\n  changed during runtime; but changing `MiniSurround.config.mappings` won't\n  have any effect (as mappings are created once during `setup()`).\n\n- If module works best with some specific non-default option value, it is\n  set during `setup()`. If the value is not essential to module's functionality,\n  it is done only if user or another plugin hasn't set it beforehand (no\n  matter the value).\n\nBuffer local configuration ~\nEach module can be additionally configured to use certain runtime config\nsettings locally to buffer. See |mini.nvim-buffer-local-config| for more\ninformation.\n\nBuffer names ~\nAll module-related buffers are named according to the following format:\n`mini<module-name>://<buffer-number>/<useful-info>` (forward slashes are\nused on any platform; `<useful-info>` may be empty). This structure allows\ncreating identifiable, reasonably unique, and useful buffer names.\nFor example, |mini.files| buffers are created per displayed directory/file with\nnames like `minifiles://10/path/to/displayed/directory`.\n\nDisabling ~\nEach module's core functionality can be disabled globally or locally to\nbuffer. See \"Disabling\" section in module's help page for more details.\nSee |mini.nvim-disabling-recipes| for common recipes.\n\nSilencing ~\nEach module can be configured to not show non-error feedback globally or\nlocally to buffer. See \"Silencing\" section in module's help for more details.\n\nHighlighting ~\nAppearance of module's output is controlled by certain set of highlight\ngroups (see |highlight-groups|). By default they usually link to some\nsemantically close built-in highlight group. Use |:highlight| command or\n|nvim_set_hl()| Lua function to customize highlighting. To see a more\ncalibrated look, use |mini.hues|, |mini.base16|, or plugin's colorschemes.\n\nStability ~\nEach module upon release is considered to be relatively stable: both in\nterms of setup and functionality. Any non-bugfix backward-incompatible\nchange will be released gradually as much as possible.\n\nNot filetype and language specific ~\nIncluding functionality which needs several filetype/language specific\nimplementations is an explicit no-goal of this project. This is mostly due\nto the potential increase in maintenance to keep implementation up to date.\nHowever, any part which might need filetype/language specific tuning should\nbe designed to allow it by letting user set proper buffer options and/or\nlocal configuration.\n\n------------------------------------------------------------------------------\n                                                         *mini.nvim-module-list*\n- |mini.ai| - extend and create `a`/`i` textobjects (like in `di(` or\n  `va\"`). It enhances some builtin |text-objects| (like |a(|, |a)|, |a'|,\n  and more), creates new ones (like `a*`, `a<Space>`, `af`, `a?`, and\n  more), and allows user to create their own (like based on treesitter, and\n  more). Supports dot-repeat, `v:count`, different search methods,\n  consecutive application, and customization via Lua patterns or functions.\n  Has builtins for brackets, quotes, function call, argument, tag, user\n  prompt, and any punctuation/digit/whitespace character.\n\n- |mini.align| - align text interactively (with or without instant preview).\n  Allows rich and flexible customization of both alignment rules and user\n  interaction. Works with charwise, linewise, and blockwise selections in\n  both Normal mode (on textobject/motion; with dot-repeat) and Visual mode.\n\n- |mini.animate| - animate common Neovim actions. Has \"works out of the box\"\n  builtin animations for cursor movement, scroll, resize, window open and\n  close. All of them can be customized and enabled/disabled independently.\n\n- |mini.base16| - fast implementation of base16 theme for manually supplied\n  palette. Supports 30+ plugin integrations. Has unique palette generator\n  which needs only background and foreground colors.\n\n- |mini.basics| - common configuration presets. Has configurable presets for\n  options, mappings, and autocommands. It doesn't change option or mapping\n  if it was manually created.\n\n- |mini.bracketed| - go forward/backward with square brackets. Among others,\n  supports variety of non-trivial targets: comments, files on disk, indent\n  changes, tree-sitter nodes, linear undo states, yank history entries.\n\n- |mini.bufremove| - buffer removing (unshow, delete, wipeout) while saving\n  window layout.\n\n- |mini.clue| - show next key clues. Implements custom key query process with\n  customizable opt-in triggers, next key descriptions (clues), hydra-like\n  submodes, window delay/config. Provides clue sets for some built-in\n  concepts: `g`/`z` keys, window commands, etc.\n\n- |mini.cmdline| - command line tweaks. Adds autocompletion with customizable\n  delay, autocorrection for words with fixed candidates, and autopeek command\n  range in a floating window with customizable context size.\n\n- |mini.colors| - tweak and save any color scheme. Can create colorscheme\n  object with methods to invert/set/modify/etc.\n  lightness/saturation/hue/temperature/etc. of foreground/background/all\n  colors, infer cterm attributes, add transparency, save to a file and more.\n  Has functionality for interactive experiments and animation of\n  transition between color schemes.\n\n- |mini.comment| - fast and familiar per-line code commenting.\n\n- |mini.completion| - async (with customizable 'debounce' delay) 'two-stage\n  chain completion': first builtin LSP, then configurable fallback. Also\n  has functionality for completion item info and function signature (both\n  in floating window appearing after customizable delay).\n\n- |mini.cursorword| - automatic highlighting of word under cursor (displayed\n  after customizable delay). Current word under cursor can be highlighted\n  differently.\n\n- |mini.deps| - plugin manager for plugins outside of 'mini.nvim'. Uses Git and\n  built-in packages to install, update, clean, and snapshot plugins.\n\n- |mini.diff| - visualize difference between buffer text and its reference\n  interactively (with colored signs or line numbers). Uses Git index as\n  default reference. Provides toggleable overview in text area, built-in\n  apply/reset/textobject/goto mappings.\n\n- |mini.doc| - generation of help files from EmmyLua-like annotations.\n  Allows flexible customization of output via hook functions. Used for\n  documenting this plugin.\n\n- |mini.extra| - extra 'mini.nvim' functionality. Contains 'mini.pick' pickers,\n  'mini.ai' textobjects, and more.\n\n- |mini.files| - navigate and manipulate file system. A file explorer with\n  column view capable of manipulating file system by editing text. Can\n  create/delete/rename/copy/move files/directories inside and across\n  directories. For full experience needs enabled |mini.icons| module (but works\n  without it).\n\n- |mini.fuzzy| - functions for fast and simple fuzzy matching. It has\n  not only functions to perform fuzzy matching of one string to others, but\n  also a sorter for 'nvim-telescope/telescope.nvim'.\n\n- |mini.git| - Git integration (https://git-scm.com/). Implements tracking of\n  Git related data (root, branch, etc.), |:Git| command for better integration\n  with running Neovim instance, and various helpers to explore Git history.\n\n- |mini.hipatterns| - highlight patterns in text with configurable highlighters\n  (pattern and/or highlight group can be string or callable).\n  Works asynchronously with configurable debounce delay.\n\n- |mini.hues| - generate configurable color scheme. Takes only background\n  and foreground colors as required arguments. Can adjust number of hues\n  for non-base colors, saturation, accent color, plugin integration.\n\n- |mini.icons| - icon provider with fixed set of highlight groups.\n  Supports various categories, icon and style customizations, caching for\n  performance. Integrates with Neovim's filetype matching.\n\n- |mini.indentscope| - visualize and operate on indent scope. Supports\n  customization of debounce delay, animation style, and different\n  granularity of options for scope computing algorithm.\n\n- |mini.jump| - minimal and fast module for smarter jumping to a single\n  character.\n\n- |mini.jump2d| - minimal and fast Lua plugin for jumping (moving cursor)\n  within visible lines via iterative label filtering. Supports custom jump\n  targets (spots), labels, hooks, allowed windows and lines, and more.\n\n- |mini.keymap| - utilities to make special key mappings: multi-step actions\n  (with built-in steps for \"smart\" <Tab>, <S-Tab>, <CR>, <BS>),\n  combos (more general version of \"better escape\" like behavior).\n\n- |mini.map| - window with buffer text overview, scrollbar, and highlights.\n  Allows configurable symbols for line encode and scrollbar, extensible\n  highlight integration (with pre-built ones for builtin search, diagnostic,\n  git line status), window properties, and more.\n\n- |mini.misc| - collection of miscellaneous useful functions. Like `put()`\n  and `put_text()` which print Lua objects to command line and current\n  buffer respectively.\n\n- |mini.move| - move any selection in any direction. Supports any Visual\n  mode (charwise, linewise, blockwise) and Normal mode (current line) for\n  all four directions (left, right, down, up). Respects `count` and undo.\n\n- |mini.notify| - show one or more highlighted notifications in a single window.\n  Provides both low-level functions (add, update, remove, clear) and maker\n  of |vim.notify()| implementation. Sets up automated LSP progress updates.\n\n- |mini.operators| - various text edit operators: replace, exchange,\n  multiply, sort, evaluate. Creates mappings to operate on textobject,\n  line, and visual selection. Supports |[count]| and dot-repeat.\n\n- |mini.pairs| - autopairs plugin which has minimal defaults and\n  functionality to do per-key expression mappings.\n\n- |mini.pick| - general purpose interactive non-blocking picker with\n  toggleable preview. Has fast default matching with fuzzy/exact/grouped\n  modes. Provides most used built-in pickers for files, pattern matches,\n  buffers, etc. For full experience needs enabled |mini.icons| module (but\n  works without it).\n\n- |mini.sessions| - session management (read, write, delete) which works\n  using |:mksession|. Implements both global (from configured directory) and\n  local (from current directory) sessions.\n\n- |mini.snippets| - manage and expand snippets. Supports only syntax from LSP\n  specification. Provides flexible loaders to manage snippet files, exact and\n  fuzzy prefix matching, interactive selection, and rich interactive snippet\n  session experience with dynamic tabstop visualization.\n\n- |mini.splitjoin| - split and join arguments (regions inside brackets\n  between allowed separators). Has customizable pre and post hooks.\n  Works inside comments.\n\n- |mini.starter| - minimal, fast, and flexible start screen. Displayed items\n  are fully customizable both in terms of what they do and how they look\n  (with reasonable defaults). Item selection can be done using prefix query\n  with instant visual feedback.\n\n- |mini.statusline| - minimal and fast statusline. Has ability to use custom\n  content supplied with concise function (using module's provided section\n  functions) along with builtin default. For full experience needs\n  enabled |mini.diff|, |mini.git|, and |mini.icons| modules (but works without\n  any of them).\n\n- |mini.surround| - fast and feature-rich surround plugin. Add, delete,\n  replace, find, highlight surrounding (like pair of parenthesis, quotes,\n  etc.). Supports dot-repeat, `v:count`, different search methods,\n  \"last\"/\"next\" extended mappings, customization via Lua patterns or\n  functions, and more. Has builtins for brackets, function call, tag, user\n  prompt, and any alphanumeric/punctuation/whitespace character.\n\n- |mini.test| - framework for writing extensive Neovim plugin tests.\n  Supports hierarchical tests, hooks, parametrization, filtering (like from\n  current file or cursor position), screen tests, \"busted-style\" emulation,\n  customizable reporters, and more. Designed to be used with provided\n  wrapper for managing child Neovim processes.\n\n- |mini.tabline| - minimal tabline which always shows listed (see 'buflisted')\n  buffers. Allows showing extra information section in case of multiple vim\n  tabpages. For full experience needs enabled |mini.icons| module (but works\n  without it).\n\n- |mini.trailspace| - automatic highlighting of trailing whitespace with\n  functionality to remove it.\n\n- |mini.visits| - track and reuse file system visits. Tracks data about each\n  file/directory visit (after delay) and stores it (only) locally. This can be\n  used to get a list of \"recent\"/\"frequent\"/\"frecent\" visits.\n  Allows persistently adding labels to visits enabling flexible workflow.\n\n------------------------------------------------------------------------------\n                                                   *mini.nvim-disabling-recipes*\nEach module's core functionality can be disabled globally or buffer-locally\nby creating appropriate global or buffer-scoped variables equal to |v:true|.\nFunctionality is disabled if at least one of |g:| or |b:| variables is `v:true`.\n\nVariable names have the same structure: `{g,b}:mini*_disable` where `*` is\nmodule's lowercase name. For example, `g:minianimate_disable` disables\n|mini.animate| globally and `b:minianimate_disable` - for current buffer.\nNote: in this section disabling 'mini.animate' is used as example;\neverything holds for other module variables.\n\nConsidering high number of different scenarios and customization intentions,\nwriting exact rules for disabling module's functionality is left to user.\n\n# Manual disabling ~\n>lua\n  -- Disable globally\n  vim.g.minianimate_disable = true\n\n  -- Disable for current buffer\n  vim.b.minianimate_disable = true\n\n  -- Toggle (disable if enabled, enable if disabled)\n  vim.g.minianimate_disable = not vim.g.minianimate_disable -- globally\n  vim.b.minianimate_disable = not vim.b.minianimate_disable -- for buffer\n<\n# Automated disabling ~\n\nAutomated disabling is suggested to be done inside autocommands: >lua\n\n  -- Disable for a certain filetype (for example, \"lua\")\n  local f = function(args) vim.b[args.buf].minianimate_disable = true end\n  vim.api.nvim_create_autocmd('Filetype', { pattern = 'lua', callback = f })\n\n  -- Enable only for certain filetypes (for example, \"lua\" and \"help\")\n  local f = function(args)\n    local ft = vim.bo[args.buf].filetype\n    if ft == 'lua' or ft == 'help' then return end\n    vim.b[args.buf].minianimate_disable = true\n  end\n  vim.api.nvim_create_autocmd('Filetype', { callback = f })\n\n  -- Disable in Visual mode\n  local f_en = function(args) vim.b[args.buf].minianimate_disable = false end\n  local enable_opts = { pattern = '[vV\\x16]*:*', callback = f_en }\n  vim.api.nvim_create_autocmd('ModeChanged', enable_opts)\n\n  local f_dis = function(args) vim.b[args.buf].minianimate_disable = true end\n  local disable_opts = { pattern = '*:[vV\\x16]*', callback = f_dis }\n  vim.api.nvim_create_autocmd('ModeChanged', disable_opts)\n\n  -- Disable in Terminal buffer\n  local f = function(args) vim.b[args.buf].minianimate_disable = true end\n  vim.api.nvim_create_autocmd('TermOpen', { callback = f })\n<\n------------------------------------------------------------------------------\n                                                 *mini.nvim-buffer-local-config*\nEach module can be additionally configured locally to buffer by creating\nappropriate buffer-scoped variable with values to override. It affects only\nruntime options and not those used once during setup (like most `mappings`).\n\nVariable names have the same structure: `b:mini*_config` where `*` is\nmodule's lowercase name. For example, `b:minianimate_config` can store\ninformation about how |mini.animate| will act inside current buffer. Its\nvalue should be a table with same structure as module's `config`. Example: >lua\n\n  -- Disable scroll animation in current buffer\n  vim.b.minianimate_config = { scroll = { enable = false } }\n<\nConsidering high number of different scenarios and customization intentions,\nwriting exact rules for module's buffer local configuration is left to\nuser. It is done in similar fashion to |mini.nvim-disabling-recipes|.\n\n------------------------------------------------------------------------------\n                                                       *mini.nvim-color-schemes*\n- Color schemes based on |mini.hues|: |MiniHues-color-schemes|.\n- Color schemes based on |mini.base16|: |MiniBase16-color-schemes|.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-operators.txt",
    "content": "*mini.operators* Text edit operators\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                 *MiniOperators*\nFeatures:\n- Operators:\n    - Evaluate text and replace with output.\n    - Exchange text regions.\n    - Multiply (duplicate) text.\n    - Replace text with register.\n    - Sort text.\n\n- Automated configurable mappings to operate on textobject, line, selection.\n  Can be disabled in favor of more control with |MiniOperators.make_mappings()|.\n\n- All operators support |[count]| and dot-repeat.\n\nSee |MiniOperators-overview| and |MiniOperators.config| for more details.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.operators').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniOperators`\nwhich you can use for scripting or manually (with `:lua MiniOperators.*`).\n\nSee |MiniOperators.config| for available config settings.\n\nYou can override runtime config settings (but not `config.mappings`) locally\nto buffer inside `vim.b.minioperators_config` which should have same structure\nas `MiniOperators.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [gbprod/substitute.nvim](https://github.com/gbprod/substitute.nvim):\n    - Has \"replace\" and \"exchange\" variants, but not others from this module.\n    - Has \"replace/substitute\" over range functionality, while this module\n      does not by design (it is similar to |:s| functionality while not\n      offering significantly lower mental complexity).\n    - \"Replace\" highlights pasted text, while in this module it doesn't.\n    - \"Exchange\" doesn't work across buffers, while in this module it does.\n\n- [svermeulen/vim-subversive](https://github.com/svermeulen/vim-subversive):\n    - Main inspiration for \"replace\" functionality, so they are mostly similar\n      for this operator.\n    - Has \"replace/substitute\" over range functionality, while this module\n      does not by design.\n\n- [tommcdo/vim-exchange](https://github.com/tommcdo/vim-exchange):\n    - Main inspiration for \"exchange\" functionality, so they are mostly\n      similar for this operator.\n    - Doesn't work across buffers, while this module does.\n\n- [christoomey/vim-sort-motion](https://github.com/christoomey/vim-sort-motion):\n    - Uses |:sort| for linewise sorting, while this module uses consistent\n      sorting algorithm (by default, see |MiniOperators.default_sort_func()|).\n    - Sorting algorithm can't be customized, while this module allows this\n      (see `sort.func` in |MiniOperators.config|).\n    - For charwise region uses only commas as separators, while this module\n      can also separate by semicolon or whitespace (by default,\n      see |MiniOperators.default_sort_func()|).\n\n# Highlight groups ~\n\n- `MiniOperatorsExchangeFrom` - first region to exchange.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable main functionality, set `vim.g.minioperators_disable` (globally) or\n`vim.b.minioperators_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                        *MiniOperators-overview*\nOperator defines an action that will be performed on a textobject, motion,\nor visual selection (similar to |d|, |c|, etc.). When makes sense, it can also\nrespect supplied register (like \"replace\" operator).\n\nThis module implements each operator in a separate dedicated function\n(like |MiniOperators.replace()| for \"replace\" operator). Each such function\ntakes `mode` as argument and acts depending on it:\n\n- If `mode` is `nil` (or not explicitly supplied), it sets |'operatorfunc'|\n  to this dedicated function and returns `g@` assuming being called from\n  expression mapping. See |:map-operator| and |:map-expression| for more details.\n\n- If `mode` is \"char\", \"line\", or \"block\", it acts as `operatorfunc` and performs\n  action for region between |`[| and |`]| marks.\n\n- If `mode` is \"visual\", it performs action for region between |`<| and |`>| marks.\n\nFor more details about specific operator, see help for its function:\n\n- Evaluate: |MiniOperators.evaluate()|\n- Exchange: |MiniOperators.exchange()|\n- Multiply: |MiniOperators.multiply()|\n- Replace:  |MiniOperators.replace()|\n- Sort:     |MiniOperators.sort()|\n\n# Mappings ~\n*MiniOperators-mappings*\n\nAll operators are automatically mapped during |MiniOperators.setup()| execution.\nMappings keys are deduced from `prefix` field of corresponding `config` entry.\nAll built-in conflicting mappings are removed (like |gra|, |grn| in Neovim>=0.11).\nBoth |gx| and |v_gx| are remapped to `gX` (if that is not already taken).\n\nFor each operator the following mappings are created:\n\n- In Normal mode to operate on textobject. Uses `prefix` directly.\n- In Normal mode to operate on line. Appends to `prefix` the last character.\n  This aligns with |operator-doubled| and established patterns for operators\n  with more than two characters, like |guu|, |gUU|, etc.\n- In Visual mode to operate on visual selection. Uses `prefix` directly.\n\nExample of default mappings for \"replace\":\n- `gr` in Normal mode for operating on textobject.\n  Example of usage: `griw` replaces \"inner word\" with default register.\n- `grr` in Normal mode for operating on line.\n  Example of usage: `grr` replaces current line.\n- `gr` in Visual mode for operating on visual selection.\n  Example of usage: `viw` selects \"inner word\" and `gr` replaces it.\n\nThere are two suggested ways to customize mappings:\n\n- Change `prefix` in |MiniOperators.setup()| call. For example, doing >lua\n\n    require('mini.operators').setup({ replace = { prefix = 'cr' } })\n<\n  will make mappings for `cr` / `crr` / `cr` instead of `gr` / `grr` / `gr`.\n\n- Disable automated mapping creation by supplying empty string as prefix and\n  use |MiniOperators.make_mappings()| directly. For example: >lua\n\n    -- Disable automated creation of \"replace\"\n    local operators = require('mini.operators')\n    operators.setup({ replace = { prefix = '' } })\n\n    -- Make custom mappings\n    operators.make_mappings(\n      'replace',\n      { textobject = 'cr', line = 'crr', selection = 'cr' }\n    )\n<\n------------------------------------------------------------------------------\n                                                         *MiniOperators.setup()*\n                        `MiniOperators.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniOperators.config|.\n\nUsage ~\n>lua\n  require('mini.operators').setup() -- use default config\n  -- OR\n  require('mini.operators').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                          *MiniOperators.config*\n                             `MiniOperators.config`\nDefaults ~\n>lua\n  MiniOperators.config = {\n    -- Each entry configures one operator.\n    -- `prefix` defines keys mapped during `setup()`: in Normal mode\n    -- to operate on textobject and line, in Visual - on selection.\n\n    -- Evaluate text and replace with output\n    evaluate = {\n      prefix = 'g=',\n\n      -- Function which does the evaluation\n      func = nil,\n    },\n\n    -- Exchange text regions\n    exchange = {\n      -- NOTE: Default `gx` is remapped to `gX`\n      prefix = 'gx',\n\n      -- Whether to reindent new text to match previous indent\n      reindent_linewise = true,\n    },\n\n    -- Multiply (duplicate) text\n    multiply = {\n      prefix = 'gm',\n\n      -- Function which can modify text before multiplying\n      func = nil,\n    },\n\n    -- Replace text with register\n    replace = {\n      -- NOTE: Default `gr*` LSP mappings are removed\n      prefix = 'gr',\n\n      -- Whether to reindent new text to match previous indent\n      reindent_linewise = true,\n    },\n\n    -- Sort text\n    sort = {\n      prefix = 'gs',\n\n      -- Function which does the sort\n      func = nil,\n    }\n  }\n<\n# Evaluate ~\n\n`evaluate.prefix` is a string used to automatically infer operator mappings keys\nduring |MiniOperators.setup()|. See |MiniOperators-mappings|.\n\n`evaluate.func` is a function used to actually evaluate text region.\nIf `nil` (default), |MiniOperators.default_evaluate_func()| is used.\n\nThis function will take content table representing selected text as input\nand should return array of lines as output (each item per line).\nContent table has fields `lines`, array of region lines, and `submode`,\none of `v`, `V`, `\\22` (escaped `<C-v>`) for charwise, linewise, and blockwise.\n\nTo customize evaluation per language, set `evaluate.func` in buffer-local\nconfig (`vim.b.minioperators_config`; see |mini.nvim-buffer-local-config|).\n\n# Exchange ~\n\n`exchange.prefix` is a string used to automatically infer operator mappings keys\nduring |MiniOperators.setup()|. See |MiniOperators-mappings|.\n\nNote: default value \"gx\" overrides |gx| / |v_gx|. Instead they are remapped\nto `gX` (if that is not already taken). To keep using `gx` with built-in\nfeature (open URL at cursor) choose different `config.prefix`.\n\n`exchange.reindent_linewise` is a boolean indicating whether newly put linewise\ntext should preserve indent of replaced text. In other words, if `false`,\nregions are exchanged preserving their indents; if `true` - without them.\n\n# Multiply ~\n\n`multiply.prefix` is a string used to automatically infer operator mappings keys\nduring |MiniOperators.setup()|. See |MiniOperators-mappings|.\n\n`multiply.func` is a function used to optionally update multiplied text.\nIf `nil` (default), text used as is.\n\nTakes content table as input (see \"Evaluate\" section) and should return\narray of lines as output.\n\n# Replace ~\n\n`replace.prefix` is a string used to automatically infer operator mappings keys\nduring |MiniOperators.setup()|. See |MiniOperators-mappings|.\n\n`replace.reindent_linewise` is a boolean indicating whether newly put linewise\ntext should preserve indent of replaced text.\n\n# Sort ~\n\n`sort.prefix` is a string used to automatically infer operator mappings keys\nduring |MiniOperators.setup()|. See |MiniOperators-mappings|.\n\n`sort.func` is a function used to actually sort text region.\nIf `nil` (default), |MiniOperators.default_sort_func()| is used.\n\nTakes content table as input (see \"Evaluate\" section) and should return\narray of lines as output.\n\nExample of `sort.func` which asks user for custom delimiter for charwise region: >lua\n\n  local sort_func = function(content)\n    local opts = {}\n    if content.submode == 'v' then\n      -- Ask for delimiter to be treated as is (not as Lua pattern)\n      local delimiter = vim.fn.input('Sort delimiter: ')\n      -- Treat surrounding whitespace as part of split\n      opts.split_patterns = { '%s*' .. vim.pesc(delimiter) .. '%s*' }\n    end\n    return MiniOperators.default_sort_func(content, opts)\n  end\n\n  require('mini.operators').setup({ sort = { func = sort_func } })\n<\n------------------------------------------------------------------------------\n                                                      *MiniOperators.evaluate()*\n                        `MiniOperators.evaluate`({mode})\nEvaluate text and replace with output\n\nIt replaces the region with the output of `config.evaluate.func`.\nBy default it is |MiniOperators.default_evaluate_func()| which evaluates\ntext as Lua code depending on the region submode.\n\nParameters ~\n{mode} `(string|nil)` One of `nil`, `'char'`, `'line'`, `'block'`, `'visual'`.\n\n------------------------------------------------------------------------------\n                                                      *MiniOperators.exchange()*\n                        `MiniOperators.exchange`({mode})\nExchange text regions\n\nHas two-step logic:\n- First call remembers the region as the one to be exchanged and highlights it\n  with `MiniOperatorsExchangeFrom` highlight group.\n- Second call performs the exchange. Basically, a two substeps action:\n  \"yank both regions\" and replace each one with another.\n\nNotes:\n- Use `<C-c>` to stop exchanging after the first step.\n\n- Exchanged regions can have different (char,line,block)-wise submodes.\n\n- Works with most cases of intersecting regions, but not officially supported.\n\nParameters ~\n{mode} `(string|nil)` One of `nil`, `'char'`, `'line'`, `'block'`, `'visual'`.\n\n------------------------------------------------------------------------------\n                                                      *MiniOperators.multiply()*\n                        `MiniOperators.multiply`({mode})\nMultiply (duplicate) text\n\nCopies a region (without affecting registers) and puts it directly after.\n\nNotes:\n- Supports two types of |[count]|: `[count1]gm[count2][textobject]` with default\n  `config.multiply.prefix` makes `[count1]` copies of region defined by\n  `[count2][textobject]`. Example: `2gm3aw` - 2 copies of `3aw`.\n\n- |[count]| for \"line\" mapping (`gmm` by default) is treated as `[count1]` from\n  previous note.\n\n- Advantages of using this instead of \"yank\" + \"paste\":\n   - Doesn't modify any register, while separate steps need some register to\n     hold multiplied text.\n   - In most cases separate steps would be \"yank\" + \"move cursor\" + \"paste\",\n     while \"multiply\" makes it at once.\n\nParameters ~\n{mode} `(string|nil)` One of `nil`, `'char'`, `'line'`, `'block'`, `'visual'`.\n\n------------------------------------------------------------------------------\n                                                       *MiniOperators.replace()*\n                        `MiniOperators.replace`({mode})\nReplace text with register\n\nNotes:\n- Supports two types of |[count]|: `[count1]gr[count2][textobject]` with default\n  `config.replace.prefix` puts `[count1]` contents of register over region defined\n  by `[count2][textobject]`. Example: `2gr3aw` - 2 register contents over `3aw`.\n\n- |[count]| for \"line\" mapping (`grr` by default) is treated as `[count1]` from\n  previous note.\n\n- Advantages of using this instead of \"visually select\" + \"paste with |v_P|\":\n   - As operator it is dot-repeatable which has cumulative gain in case of\n     multiple replacing is needed.\n   - Can automatically reindent.\n\nParameters ~\n{mode} `(string|nil)` One of `nil`, `'char'`, `'line'`, `'block'`, `'visual'`.\n\n------------------------------------------------------------------------------\n                                                          *MiniOperators.sort()*\n                          `MiniOperators.sort`({mode})\nSort text\n\nIt replaces the region with the output of `config.sort.func`.\nBy default it is |MiniOperators.default_sort_func()| which sorts the text\ndepending on submode.\n\nNotes:\n- \"line\" mapping is charwise (as there is not much sense in sorting\n  linewise a single line). This also results into no |[count]| support.\n\nParameters ~\n{mode} `(string|nil)` One of `nil`, `'char'`, `'line'`, `'block'`, `'visual'`.\n\n------------------------------------------------------------------------------\n                                                 *MiniOperators.make_mappings()*\n           `MiniOperators.make_mappings`({operator_name}, {lhs_tbl})\nMake operator mappings\n\nParameters ~\n{operator_name} `(string)` Name of existing operator from this module.\n{lhs_tbl} `(table)` Table with mappings keys. Should have these fields:\n  - <textobject> `(string)` - Normal mode mapping to operate on textobject.\n  - <line> `(string)` - Normal mode mapping to operate on line.\n    Usually an alias for textobject mapping followed by |_|.\n    For \"sort\" it operates charwise on whole line without left and right\n    whitespace (as there is not much sense in sorting linewise a single line).\n  - <selection> `(string)` - Visual mode mapping to operate on selection.\n\n  Supply empty string to not create particular mapping. Note: creating `line`\n  mapping needs `textobject` mapping to be set.\n\nUsage ~\n>lua\n  require('mini.operators').make_mappings(\n    'replace',\n    { textobject = 'cr', line = 'crr', selection = 'cr' }\n  )\n<\n------------------------------------------------------------------------------\n                                         *MiniOperators.default_evaluate_func()*\n                `MiniOperators.default_evaluate_func`({content})\nDefault evaluate function\n\nEvaluate text as Lua code and return object from last line (like if last\nline is prepended with `return` if it is not already).\n\nBehavior depends on region submode:\n\n- For charwise and linewise regions, text evaluated as is.\n\n- For blockwise region, lines are evaluated per line using only first lines\n  of outputs. This allows separate execution of lines in order to provide\n  something different compared to linewise region.\n\nParameters ~\n{content} `(table)` Table with the following fields:\n  - <lines> `(table)` - array with content lines.\n  - <submode> `(string)` - region submode. One of `'v'`, `'V'`, `'<C-v>'` (escaped).\n\n------------------------------------------------------------------------------\n                                             *MiniOperators.default_sort_func()*\n              `MiniOperators.default_sort_func`({content}, {opts})\nDefault sort function\n\nSort text based on region submode:\n\n- For charwise region, split by separator pattern, sort parts, merge back\n  with separators. Actual pattern is inferred based on the array of patterns\n  from `opts.split_patterns`: whichever element is present in the text is\n  used, preferring the earlier one if several are present.\n  Example: sorting \"c, b; a\" line with default `opts.split_patterns` results\n  into \"b; a, c\" as it is split only by comma.\n\n- For linewise and blockwise regions sort lines as is.\n\nNotes:\n- Sort is done with |table.sort()| on an array of lines, which doesn't treat\n  whitespace or digits specially. Use |:sort| for more complicated tasks.\n\n- Pattern is allowed to be an empty string in which case split results into\n  all characters as parts.\n\n- Pad pattern in `split_patterns` with `%s*` to include whitespace into separator.\n  Example: line \"b _ a\" with \"_\" pattern will be sorted as \" a_b \" (because\n  it is split as \"b \", \"_\", \" a\" ) while with \"%s*_%s*\" pattern it results\n  into \"a _ b\" (split as \"b\", \" _ \", \"a\").\n\nParameters ~\n{content} `(table)` Table with the following fields:\n  - <lines> `(table)` - array with content lines.\n  - <submode> `(string)` - region submode. One of `'v'`, `'V'`, `'<C-v>'` (escaped).\n{opts} `(table|nil)` Options. Possible fields:\n  - <compare_fun> `(function)` - compare function compatible with |table.sort()|.\n    Default: direct compare with `<`.\n  - <split_patterns> `(table)` - array of split Lua patterns to be used for\n    charwise submode. Order is important.\n    Default: `{ '%s*,%s*', '%s*;%s*', '%s+', '' }`.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-pairs.txt",
    "content": "*mini.pairs* Autopairs\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                     *MiniPairs*\nFeatures:\n- Functionality to work with two \"paired\" characters conditional on cursor's\n  neighborhood (character to its left and character to its right).\n\n- Usage should be through making appropriate mappings using |MiniPairs.map()|\n  or in |MiniPairs.setup()| (for global mapping), |MiniPairs.map_buf()| (for\n  buffer mapping).\n\n- Pairs get automatically registered for special <BS> (all configured modes)\n  and <CR> (only Insert mode) mappings. Pressing the key inside pair will\n  delete whole pair and insert extra blank line inside pair respectively.\n  Note: these mappings are autocreated if they do not override existing ones.\n\nWhat it doesn't do:\n- Provide smart behavior, like based on bracket balance. The default behavior\n  is to almost always perform an action (insert pair, jump over). Manually\n  press |i_CTRL-V| before a character to explicitly insert it (and only it).\n\n- It doesn't support multiple characters as \"open\" and \"close\" symbols. Use\n  snippets for that.\n\n- It doesn't support dependency on filetype. Use |i_CTRL-V| to insert\n  single symbol or `autocmd` command or 'after/ftplugin' approach to:\n    - `:lua MiniPairs.map_buf(0, 'i', <*>, <pair_info>)` - make new mapping\n      for '<*>' in current buffer.\n    - `:lua MiniPairs.unmap_buf(0, 'i', <*>, <pair>)` - unmap key `<*>` while\n      unregistering `<pair>` pair in current buffer. Note: this reverts\n      mapping done by |MiniPairs.map_buf()|. If mapping was done with\n      |MiniPairs.map()|, unmap for buffer in usual Neovim manner:\n      `inoremap <buffer> <*> <*>` (this maps `<*>` key to do the same it\n      does by default).\n    - Disable module for buffer (see 'Disabling' section).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.pairs').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniPairs` which you can use for scripting or manually (with\n`:lua MiniPairs.*`).\n\nSee |MiniPairs.config| for `config` structure and default values.\n\nThis module doesn't have runtime options, so using `vim.b.minipairs_config`\nwill have no effect here.\n\n# Example mappings ~\n>lua\n  -- Register quotes inside `config` of `MiniPairs.setup()`\n  mappings = {\n    ['\"'] = { register = { cr = true } },\n    [\"'\"] = { register = { cr = true } },\n  }\n\n  -- Insert `<>` pair if `<` is typed at line start, don't register for <CR>\n  local lt_opts = {\n    action = 'open',\n    pair = '<>',\n    neigh_pattern = '\\r.',\n    register = { cr = false },\n  }\n  MiniPairs.map('i', '<', lt_opts)\n\n  local gt_opts = { action = 'close', pair = '<>', register = { cr = false } }\n  MiniPairs.map('i', '>', gt_opts)\n\n  -- Create symmetrical `$$` pair only in Tex files\n  local map_tex = function()\n    MiniPairs.map_buf(0, 'i', '$', { action = 'closeopen', pair = '$$' })\n  end\n  vim.api.nvim_create_autocmd(\n    'FileType',\n    { pattern = 'tex', callback = map_tex }\n  )\n<\n# Notes ~\n\n- Make sure to make proper mapping of <CR> in order to support completion\n  plugin of your choice:\n    - For |mini.completion| see 'Helpful key mappings' section.\n    - For current implementation of \"hrsh7th/nvim-cmp\" there is no need to\n      make custom mapping. You can use default setup, which will confirm\n      completion selection if popup is visible and expand pair otherwise.\n- Having mapping in terminal mode can conflict with:\n    - Autopairing capabilities of interpretators (`ipython`, `radian`).\n    - Vim mode of terminal itself.\n\n# Disabling ~\n\nTo disable, set `vim.g.minipairs_disable` (globally) or `vim.b.minipairs_disable`\n(for a buffer) to `true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                             *MiniPairs.setup()*\n                          `MiniPairs.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniPairs.config|.\n\nUsage ~\n>lua\n  require('mini.pairs').setup() -- use default config\n  -- OR\n  require('mini.pairs').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                              *MiniPairs.config*\n                               `MiniPairs.config`\nDefaults ~\n>lua\n  MiniPairs.config = {\n    -- In which modes mappings from this `config` should be created\n    modes = { insert = true, command = false, terminal = false },\n\n    -- Global mappings. Each right hand side should be a pair information, a\n    -- table with at least these fields (see more in |MiniPairs.map()|):\n    -- - <action> - one of \"open\", \"close\", \"closeopen\".\n    -- - <pair> - two character string for pair to be used.\n    -- By default pair is not inserted after `\\`, quotes are not recognized by\n    -- <CR>, `'` does not insert the pair after a letter.\n    -- Only parts of tables can be tweaked (others will use these defaults).\n    -- Supply `false` instead of table to not map particular key.\n    mappings = {\n      ['('] = { action = 'open', pair = '()', neigh_pattern = '^[^\\\\]' },\n      ['['] = { action = 'open', pair = '[]', neigh_pattern = '^[^\\\\]' },\n      ['{'] = { action = 'open', pair = '{}', neigh_pattern = '^[^\\\\]' },\n\n      [')'] = { action = 'close', pair = '()', neigh_pattern = '^[^\\\\]' },\n      [']'] = { action = 'close', pair = '[]', neigh_pattern = '^[^\\\\]' },\n      ['}'] = { action = 'close', pair = '{}', neigh_pattern = '^[^\\\\]' },\n\n      ['\"'] = { action = 'closeopen', pair = '\"\"', neigh_pattern = '^[^\\\\]',   register = { cr = false } },\n      [\"'\"] = { action = 'closeopen', pair = \"''\", neigh_pattern = '^[^%a\\\\]', register = { cr = false } },\n      ['`'] = { action = 'closeopen', pair = '``', neigh_pattern = '^[^\\\\]',   register = { cr = false } },\n    },\n  }\n<\n------------------------------------------------------------------------------\n                                                               *MiniPairs.map()*\n              `MiniPairs.map`({mode}, {lhs}, {pair_info}, {opts})\nMake global mapping\n\nThis is a wrapper for |nvim_set_keymap()| but instead of right hand side of\nmapping (as string) it expects table with pair information.\n\nUsing this function instead of |nvim_set_keymap()| allows automatic\nregistration of pairs which will be recognized by <BS> and <CR>.\nIt also infers mapping description from `pair_info`.\n\nParameters ~\n{mode} `(string)` `mode` for |nvim_set_keymap()|.\n{lhs} `(string)` `lhs` for |nvim_set_keymap()|.\n{pair_info} `(table)` Table with pair information. Fields:\n  - <action> - one of \"open\" for |MiniPairs.open()|,\n    \"close\" for |MiniPairs.close()|, or \"closeopen\" for |MiniPairs.closeopen()|.\n  - <pair> - two character string to be passed to an action function.\n    Can contain multibyte characters.\n  - <neigh_pattern> - optional neighborhood pattern to be passed to an action\n    function. Will be matched against two character neighborhood (might\n    contain multibyte characters).\n    Default: `'..'` (no restriction from neighborhood).\n  - <register> - optional table with information about whether this pair will\n    be recognized by <BS> (in |MiniPairs.bs()|) and/or <CR> (in |MiniPairs.cr()|).\n    Should have boolean fields <bs> and <cr> (both `true` by default).\n{opts} `(table|nil)` Optional table `opts` for |nvim_set_keymap()|. Elements\n  `expr` and `noremap` won't be recognized (`true` by default).\n\n------------------------------------------------------------------------------\n                                                           *MiniPairs.map_buf()*\n       `MiniPairs.map_buf`({buffer}, {mode}, {lhs}, {pair_info}, {opts})\nMake buffer mapping\n\nThis is a wrapper for |nvim_buf_set_keymap()| but instead of string right\nhand side of mapping it expects table with pair information similar to one\nin |MiniPairs.map()|.\n\nUsing this function instead of |nvim_buf_set_keymap()| allows automatic\nregistration of pairs which will be recognized by <BS> and <CR>.\nIt also infers mapping description from `pair_info`.\n\nParameters ~\n{buffer} `(number)` `buffer` for |nvim_buf_set_keymap()|.\n{mode} `(string)` `mode` for |nvim_buf_set_keymap()|.\n{lhs} `(string)` `lhs` for |nvim_buf_set_keymap()|.\n{pair_info} `(table)` Table with pair information.\n{opts} `(table|nil)` Optional table `opts` for |nvim_buf_set_keymap()|.\n  Elements `expr` and `noremap` won't be recognized (`true` by default).\n\n------------------------------------------------------------------------------\n                                                             *MiniPairs.unmap()*\n                    `MiniPairs.unmap`({mode}, {lhs}, {pair})\nRemove global mapping\n\nA wrapper for |nvim_del_keymap()| which registers supplied `pair`.\n\nParameters ~\n{mode} `(string)` `mode` for |nvim_del_keymap()|.\n{lhs} `(string)` `lhs` for |nvim_del_keymap()|.\n{pair} `(string)` Pair which should be unregistered from both <BS> and <CR>.\n  Should be explicitly supplied to avoid confusion.\n  Supply `''` to not unregister pair.\n\n------------------------------------------------------------------------------\n                                                         *MiniPairs.unmap_buf()*\n             `MiniPairs.unmap_buf`({buffer}, {mode}, {lhs}, {pair})\nRemove buffer mapping\n\nWrapper for |nvim_buf_del_keymap()| which also unregisters supplied `pair`.\n\nNote: this only reverts mapping done by |MiniPairs.map_buf()|. If mapping was\ndone with |MiniPairs.map()|, revert to default behavior for buffer: >lua\n\n  -- Map `X` key to do the same it does by default\n  vim.keymap.set('i', 'X', 'X', { buffer = true })\n<\nParameters ~\n{buffer} `(number)` `buffer` for |nvim_buf_del_keymap()|.\n{mode} `(string)` `mode` for |nvim_buf_del_keymap()|.\n{lhs} `(string)` `lhs` for |nvim_buf_del_keymap()|.\n{pair} `(string)` Pair which should be unregistered from both <BS> and <CR>.\n  Should be explicitly supplied to avoid confusion.\n  Supply `''` to not unregister pair.\n\n------------------------------------------------------------------------------\n                                                              *MiniPairs.open()*\n                   `MiniPairs.open`({pair}, {neigh_pattern})\nProcess \"open\" symbols\n\nUsed as |:map-<expr>| mapping for \"open\" symbols in asymmetric pair ('(', '[',\netc.). If neighborhood doesn't match supplied pattern, function results\ninto \"open\" symbol. Otherwise, it pastes whole pair and moves inside pair\nwith |<Left>|.\n\nUsed inside |MiniPairs.map()| and |MiniPairs.map_buf()| for an actual mapping.\n\nParameters ~\n{pair} `(string)` String with two characters representing pair.\n{neigh_pattern} `(string|nil)` Pattern for two neighborhood characters.\n  Character \"\\r\" indicates line start, \"\\n\" - line end.\n\nReturn ~\n`(string)` Keys performing \"open\" action.\n\n------------------------------------------------------------------------------\n                                                             *MiniPairs.close()*\n                   `MiniPairs.close`({pair}, {neigh_pattern})\nProcess \"close\" symbols\n\nUsed as |:map-<expr>| mapping for \"close\" symbols in asymmetric pair (')',\n']', etc.). If neighborhood doesn't match supplied pattern, function\nresults into \"close\" symbol. Otherwise it jumps over symbol to the right of\ncursor (with |<Right>|) if it is equal to \"close\" one and inserts it\notherwise.\n\nUsed inside |MiniPairs.map()| and |MiniPairs.map_buf()| for an actual mapping.\n\nParameters ~\n{pair} `(string)` String with two characters representing pair.\n{neigh_pattern} `(string|nil)` Pattern for two neighborhood characters.\n  Character \"\\r\" indicates line start, \"\\n\" - line end.\n\nReturn ~\n`(string)` Keys performing \"close\" action.\n\n------------------------------------------------------------------------------\n                                                         *MiniPairs.closeopen()*\n                 `MiniPairs.closeopen`({pair}, {neigh_pattern})\nProcess \"closeopen\" symbols\n\nUsed as |:map-<expr>| mapping for 'symmetrical' symbols (like \" and ')\nIt tries to perform 'closeopen action': move over right character\n(with |<Right>|) if it is equal to second character from pair or\nconditionally paste pair otherwise (with |MiniPairs.open()|).\n\nUsed inside |MiniPairs.map()| and |MiniPairs.map_buf()| for an actual mapping.\n\nParameters ~\n{pair} `(string)` String with two characters representing pair.\n{neigh_pattern} `(string|nil)` Pattern for two neighborhood characters.\n  Character \"\\r\" indicates line start, \"\\n\" - line end.\n\nReturn ~\n`(string)` Keys performing \"closeopen\" action.\n\n------------------------------------------------------------------------------\n                                                                *MiniPairs.bs()*\n                             `MiniPairs.bs`({key})\nProcess |<BS>|\n\nUsed as |:map-<expr>| mapping for <BS> in Insert mode. It removes whole pair\n(via executing <Del> after input key) if neighborhood is equal to a whole\npair recognized for current buffer. Pair is recognized for current buffer\nif it is registered for global or current buffer mapping. Pair is\nregistered as a result of calling |MiniPairs.map()| or |MiniPairs.map_buf()|.\n\nMapped by default inside |MiniPairs.setup()|.\n\nThis can be used to modify other Insert mode keys to respect neighborhood\npair. Examples: >lua\n\n  local map_bs = function(lhs, rhs)\n    vim.keymap.set('i', lhs, rhs, { expr = true, replace_keycodes = false })\n  end\n\n  map_bs('<C-h>', 'v:lua.MiniPairs.bs()')\n  map_bs('<C-w>', 'v:lua.MiniPairs.bs(\"\\23\")')\n  map_bs('<C-u>', 'v:lua.MiniPairs.bs(\"\\21\")')\n<\nParameters ~\n{key} `(string|nil)` Key to use. Default: `'<BS>'`.\n\nReturn ~\n`(string)` Keys performing \"backspace\" action.\n\n------------------------------------------------------------------------------\n                                                                *MiniPairs.cr()*\n                             `MiniPairs.cr`({key})\nProcess |i_<CR>|\n\nUsed as |:map-<expr>| mapping for <CR> in insert mode. It puts \"close\"\nsymbol on next line (via `<CR><C-o>O`) if neighborhood is equal to a whole\npair recognized for current buffer. Pair is recognized for current buffer\nif it is registered for global or current buffer mapping. Pair is\nregistered as a result of calling |MiniPairs.map()| or |MiniPairs.map_buf()|.\n\nNote: some relevant mode changing events are temporarily ignored\n(with |'eventignore'|) to counter effect of using |i_CTRL-O|.\n\nMapped by default inside |MiniPairs.setup()|.\n\nParameters ~\n{key} `(string|nil)` Key to use. Default: `'<CR>'`.\n\nReturn ~\n`(string)` Keys performing \"new line\" action.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-pick.txt",
    "content": "*mini.pick* Pick anything\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniPick*\nFeatures:\n\n- Single window general purpose interface for picking element from any array.\n\n- On demand toggleable preview and info views.\n\n- Interactive query matching (filter+sort) with fast non-blocking default\n  which does fuzzy matching and allows other modes (|MiniPick.default_match()|).\n\n- Built-in pickers (see |MiniPick.builtin|):\n    - Files.\n    - Pattern match (for fixed pattern or with live feedback; both allow\n      file filtering via glob patterns).\n    - Buffers.\n    - Help tags.\n    - CLI output.\n    - Resume latest picker.\n\n- |:Pick| command to work with extensible |MiniPick.registry|.\n\n- |vim.ui.select()| implementation. To adjust, use |MiniPick.ui_select()|\n  or save-restore `vim.ui.select` manually after calling |MiniPick.setup()|.\n\n- Rich and customizable built-in |MiniPick-actions| when picker is active:\n    - Manually change currently focused item.\n    - Scroll vertically and horizontally.\n    - Toggle preview or info view.\n    - Mark/unmark items to choose later.\n    - Refine current matches (make them part of a new picker).\n    - And many more.\n\n- Minimal yet flexible |MiniPick-source| specification with:\n    - Items (array, callable, or manually set later).\n    - Source name.\n    - Working directory.\n    - Matching algorithm.\n    - Way matches are shown in main window.\n    - Item preview.\n    - \"On choice\" action for current and marked items.\n\n- Custom actions/keys can be configured globally, per buffer, or per picker.\n\n- Out of the box support for 'ignorecase' and 'smartcase'.\n\n- Match caching to increase responsiveness on repeated prompts.\n\nNotes:\n- Works on all supported versions but Neovim>=0.10 will give more visual\n  feedback in floating window footer.\n\n- For more pickers see |MiniExtra.pickers|.\n\nSources with more details:\n- |MiniPick-overview|\n- |MiniPick-source|\n- |MiniPick-actions|\n- |MiniPick-examples|\n- |MiniPick.builtin|\n\n# Dependencies ~\n\nSuggested dependencies (provide extra functionality, will work without them):\n\n- Enabled |mini.icons| module to show icons near the items for actual paths.\n  Falls back to 'nvim-tree/nvim-web-devicons' plugin or no icons will be used.\n\n- *MiniPick-cli-tools* CLI tool(s) to power |MiniPick.builtin.files()|,\n  |MiniPick.builtin.grep()|, and |MiniPick.builtin.grep_live()| built-in pickers:\n    - `rg` (github.com/BurntSushi/ripgrep; enough for all three; recommended).\n    - `fd` (github.com/sharkdp/fd; for `files` only).\n    - `git` (github.com/git/git; enough for all three).\n\n  Note: CLI tools are called only with basic arguments needed to get items.\n  To customize the output, use their respective configuration approaches.\n  Here are some examples of where to start:\n    - github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#configuration-file\n    - github.com/sharkdp/fd#excluding-specific-files-or-directories\n    - git-scm.com/docs/gitignore\n\n# Setup ~\n\nThis module needs a setup with `require('mini.pick').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniPick`\nwhich you can use for scripting or manually (with `:lua MiniPick.*`).\n\nSee |MiniPick.config| for available config settings.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minipick_config` which should have same structure as `MiniPick.config`.\nSee |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim):\n    - The main inspiration for this module, so there is significant overlap.\n    - Has three (or two) window UI (prompt, matches, preview), while this\n      module combines everything in one window. It allows more straightforward\n      customization for unusual scenarios.\n    - Default match algorithm is somewhat slow, while this module should\n      match relatively lag-free for at least 100K+ items.\n    - Has many built-in pickers, while this module has handful at its core\n      relying on other 'mini.nvim' modules to provide more (see |mini.extra|).\n\n- [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua):\n    - Mostly same comparison as with 'nvim-telescope/telescope.nvim'.\n    - Requires [junegunn/fzf](https://github.com/junegunn/fzf) installed to\n      power fuzzy matching, while this module provides built-in Lua matching.\n\n# Highlight groups ~\n\n- `MiniPickBorder` - window border.\n- `MiniPickBorderBusy` - window border while picker is busy processing.\n- `MiniPickBorderText` - non-prompt on border.\n- `MiniPickCursor` - cursor during active picker (hidden by default).\n- `MiniPickIconDirectory` - default icon for directory.\n- `MiniPickIconFile` - default icon for file.\n- `MiniPickHeader` - headers in info buffer and previews.\n- `MiniPickMatchCurrent` - current matched item.\n- `MiniPickMatchMarked` - marked matched items.\n- `MiniPickMatchRanges` - ranges matching query elements.\n- `MiniPickNormal` - basic foreground/background highlighting.\n- `MiniPickPreviewLine` - target line in preview.\n- `MiniPickPreviewRegion` - target region in preview.\n- `MiniPickPrompt` - prompt.\n- `MiniPickPromptCaret` - caret in prompt.\n- `MiniPickPromptPrefix` - prefix of the prompt.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n------------------------------------------------------------------------------\n                                                               *MiniPick-events*\nTo allow user customization and integration of external tools, certain |User|\nautocommand events are triggered under common circumstances:\n\n- `MiniPickMatch` - just after updating query matches or setting items.\n- `MiniPickStart` - just after picker has started.\n- `MiniPickStop` - just before picker is stopped.\n\n------------------------------------------------------------------------------\n                                                             *MiniPick-overview*\nGeneral idea is to take array of objects, display them with interactive\nfilter/sort/navigate/preview, and allow to choose one or more items.\n\n# How to start a picker ~\n\n- Use |MiniPick.start()| with `opts.source` defining |MiniPick-source|.\n  Example: `MiniPick.start({ source = { items = vim.fn.readdir('.') } })`\n\n- Use any of |MiniPick.builtin| pickers directly.\n  Example: `MiniPick.builtin.files({ tool = 'git' })`\n\n- Use |:Pick| command which uses customizable pickers from |MiniPick.registry|.\n  Example: `:Pick files tool='git'`\n\n# User interface ~\n\nUI consists from a single window capable of displaying three different views:\n- \"Main\" - where current query matches are shown.\n- \"Preview\" - preview of current item (toggle with `<Tab>`).\n- \"Info\" - general info about picker and its state (toggle with `<S-Tab>`).\n\nCurrent prompt is displayed at the top left of the window border with vertical\nline indicating caret (current input position).\n\nBottom part of window border displays (in Neovim>=0.10) extra visual feedback:\n- Left part is a picker name.\n- Right part contains information in the format >\n\n  <current index in matches> | <match count> | <marked count> / <total count>\n<\nWhen picker is busy (like if there are no items yet set or matching is active)\nwindow border changes color to be `MiniPickBorderBusy` after `config.delay.busy`\nmilliseconds of idle time.\n\n# Life cycle ~\n\n- Type characters to filter and sort matches. It uses |MiniPick.default_match()|\n  with `query` being an array of pressed characters.\n  Overview of how it matches:\n    - If query starts with `'`, the match is exact.\n    - If query starts with `^`, the match is exact at start.\n    - If query ends with `$`, the match is exact at end.\n    - If query starts with `*`, the match is forced to be fuzzy.\n    - Otherwise match is fuzzy.\n    - Sorting is done to first minimize match width and then match start.\n      Nothing more: no favoring certain places in string, etc.\n\n- Type special keys to perform |MiniPick-actions|. Here are some basic ones:\n    - `<C-n>` / `<Down>` moves down; `<C-p>` / `<Up>` moves up.\n    - `<Left>` / `<Right>` moves prompt caret left / right.\n    - `<S-Tab>` toggles information window with all available mappings.\n    - `<Tab>` toggles preview.\n    - `<C-x>` / `<C-a>` toggles current / all item(s) as (un)marked.\n    - `<C-Space>` / `<M-Space>` makes all matches or marked items as new picker.\n    - `<CR>` / `<M-CR>` chooses current/marked item(s).\n    - `<Esc>` / `<C-c>` stops picker.\n\n# Implementation details ~\n\n- Processing key typing is done via a dedicated key query process for more\n  control over their side effects. As a result, regular mappings don't work\n  here and picker's window needs to be current as long as it is shown.\n  Changing window focus leads to automatic picker stop (after small delay).\n  Not picker related screen changes require explicit |:redraw|.\n- Any picker is non-blocking but waits to return the chosen item. Example:\n  `file = MiniPick.builtin.files()` allows other actions to be executed when\n  picker is shown while still assigning `file` with value of the chosen item.\n\n------------------------------------------------------------------------------\n                                                               *MiniPick-source*\nSource is defined as a `source` field inside one of (in increasing priority):\n- |MiniPick.config| - has global effect.\n- `vim.b.minipick_config` - has buffer-local effect.\n- `opts.source` in picker call - has effect for that particular call.\n\nExample of source to choose from |arglist|: >lua\n\n  { items = vim.fn.argv, name = 'Arglist' }\n<\nNote: this is mostly useful for writing pickers. Can safely skip if you\nwant to just use provided pickers.\n\n# Items ~\n*MiniPick-source.items*\n\n`source.items` defines items to choose from. It should be one of the following:\n- Array of objects which can have different types. Any type is allowed.\n- `nil`. Picker waits for explicit |MiniPick.set_picker_items()| call.\n- Callable returning any of the previous types. Will be called once on start\n  with source's `cwd` set as |current-directory|.\n\n*MiniPick-source.items-stritems*\nMatching is done for items array based on the string representation of its\nelements (here called \"stritems\"). For single item it is computed as follows:\n- Callable is called once with output used in next steps.\n- String item is used as is.\n- String <text> field of table item is used (if present).\n- Use output of |vim.inspect()|.\n\nExample: >lua\n\n  items = { 'aaa.txt', { text = 'bbb' }, function() return 'ccc' end }\n  -- corresponding stritems are { 'aaa.txt', 'bbb', 'ccc' }\n<\nDefault value is `nil`, assuming it always be supplied by the caller.\n\n*MiniPick-source.items-common*\nThere are some recommendations for common item types in order for them to work\nout of the box with |MiniPick.default_show()|, |MiniPick.default_preview()|,\n|MiniPick.default_choose()|, |MiniPick.default_choose_marked()|:\n\n- Path (file or directory). Use string or `path` field of a table. Path can\n  be either absolute, relative to the `source.cwd`, or have a general URI format\n  (only if supplied as table field).\n  Examples: `'aaa.txt'`, `{ path = 'aaa.txt' }`\n\n- Buffer. Use buffer id as number, string, or `bufnr` / `buf_id` / `buf`\n  field of a table (any name is allowed).\n  Examples: `1`, `'1'`, `{ bufnr = 1 }`, `{ buf_id = 1 }`, `{ buf = 1 }`\n\n- Line in file or buffer. Use table representation with `lnum` field with line\n  number (starting from 1) or string in \"<path>\\0<line>\" format (`\\0` is\n  an actual null character; don't escape the slash; may need to be `\\000`).\n  Examples: >lua\n\n    { path = 'aaa.txt', lnum = 2 }, 'aaa.txt\\0002', { bufnr = 1, lnum = 3 }\n<\n- Position in file or buffer. Use table representation with `lnum` and `col`\n  fields with line and column numbers (starting from 1) or string in\n  \"<path>\\0<line>\\0<col>\" format (`\\0` is an actual null character, don't\n  escape the slash; may need to be `\\000`).\n  Examples: >lua\n\n    { path = 'aaa.txt', lnum = 2, col = 3 }, 'aaa.txt\\0' .. '2\\0003',\n    { bufnr = 1, lnum = 3, col = 4 }\n<\n- Region in file or buffer. Use table representation with `lnum`, `col`,\n  `end_lnum`, `end_col` fields for start and end line/column. All numbers\n  start from 1, end line is inclusive, end column is exclusive.\n  This naming is similar to |getqflist()| and |diagnostic-structure|.\n  Examples: >lua\n\n    { path = 'aaa.txt', lnum = 2, col = 3, end_lnum = 4, end_col = 5 },\n    { bufnr = 1, lnum = 3, col = 4, end_lnum = 5, end_col = 6 }\n<\nNote: all table items will benefit from having `text` field for better matching.\n\n# Name ~\n*MiniPick-source.name*\n\n`source.name` defines the name of the picker to be used for visual feedback.\n\nDefault value is \"<No name>\".\n\n# Current working directory ~\n*MiniPick-source.cwd*\n\n`source.cwd` is a string defining the current working directory in which\npicker operates. It should point to a valid actually present directory path.\nThis is a part of source to allow persistent way to use relative paths,\ni.e. not depend on current directory being constant after picker start.\nIt also makes the |MiniPick.builtin.resume()| picker more robust.\n\nIt will be set as local |current-directory| (|:lcd|) of picker's main window\nto allow simpler code for \"in window\" functions (choose/preview/custom/etc.).\n\nDefault value is |current-directory|.\n\n# Match ~\n*MiniPick-source.match*\n\n`source.match` is a callable defining how stritems\n(see |MiniPick-source.items-stritems|) are matched (filtered and sorted) based\non the query.\n\nIt will be called with the following arguments:\n- `stritems` - all available stritems for current picker.\n- `inds` - array of `stritems` indexes usually pointing at current matches.\n  It does point to current matches in the case of interactively appending\n  character at the end of the query. It assumes that matches for such bigger\n  query is a subset of previous matches (implementation can ignore it).\n  This can be utilized to increase performance by checking fewer stritems.\n- `query` - array of strings. Usually (like is common case of user interactively\n  typing query) each string represents one character. However, any strings are\n  allowed, as query can be set with |MiniPick.set_picker_query()|.\n\nIt should either return array of match indexes for stritems elements matching\nthe query (synchronous) or explicitly use |MiniPick.set_picker_match_inds()|\nto set them (may be asynchronous).\n\nNotes:\n- The result can be any array of `stritems` indexes, i.e. not necessarily\n  a subset of input `inds`.\n\n- Both `stritems` and `query` depend on values of 'ignorecase' and 'smartcase'.\n  If query shows \"ignore case\" properties (only 'ignorecase' is set or both\n  'ignorecase' / 'smartcase' are set and query has only lowercase characters),\n  then `stritems` and `query` will have only lowercase characters.\n  This allows automatic support for case insensitive matching while being\n  faster and having simpler match function implementation.\n\n- Writing custom `source.match` usually means also changing |MiniPick-source.show|\n  because it is used to highlight stritems parts actually matching the query.\n\nExample of simple \"exact\" `match()` preserving initial order: >lua\n\n  local match_exact = function(stritems, inds, query)\n    local prompt_pattern = vim.pesc(table.concat(query))\n    local f = function(i) return stritems[i]:find(prompt_pattern) ~= nil end\n    return vim.tbl_filter(f, inds)\n  end\n  -- For non-blocking version see `:h MiniPick.poke_is_picker_active()`\n<\nDefault value is |MiniPick.default_match()|.\n\n# Show ~\n*MiniPick-source.show*\n\n`source.show` is a callable defining how matched items are shown in the window.\n\nIt will be called with the following arguments:\n- `buf_id` - identifier of the target buffer.\n- `items_to_show` - array of actual items to be shown in `buf_id`. This is\n  a subset of currently matched items computed to fit in current window view.\n- `query` - array of strings. Same as in `source.match`.\n\nIt should update buffer `buf_id` to visually represent `items_to_show`\n__one item per line starting from line one__ (it shouldn't depend on\n`options.content_from_bottom`). This also includes possible visualization\nof which parts of stritem actually matched query.\n\nExample (assuming string items; without highlighting): >lua\n\n  local show_prepend = function(buf_id, items_arr, query)\n    local lines = vim.tbl_map(function(x) return 'Item: ' .. x end, items_arr)\n    vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n  end\n<\nDefault value is |MiniPick.default_show()|.\n\n# Preview ~\n*MiniPick-source.preview*\n\n`source.preview` is a callable defining how item preview is done.\n\nIt will be called with the following arguments:\n- `buf_id` - identifier of the target buffer. Note: for every separate instance\n  of item previewing new scratch buffer is be created.\n- `item` - item to preview.\n\nIt should update buffer `buf_id` to visually represent `item`. It can also\ndirectly set another buffer in picker's main window, but usually it is more\nrobust to update given `buf_id` directly.\n\nExample: >lua\n\n  local preview_inspect = function(buf_id, item)\n    local lines = vim.split(vim.inspect(item), '\\n')\n    vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n  end\n<\nDefault value is |MiniPick.default_preview()|.\n\n# Choose an item ~\n*MiniPick-source.choose*\n\n`source.choose` is a callable defining what to do when an item is chosen.\n\nIt will be called with the following arguments:\n- `item` - chosen item. Always non-`nil`.\n\nIt should perform any intended \"choose\" action for an item and return\na value indicating whether picker should continue (i.e. not stop):\n`nil` and `false` will stop picker, other values will continue.\n\nNotes:\n- It is called when picker window is still current. Use `windows.target` value\n  from |MiniPick.get_picker_state()| output to do something with target window.\n\nExample: >lua\n\n  local choose_file_continue = function(item)\n    if vim.fn.filereadable(item) == 0 then return end\n    vim.api.nvim_win_call(\n      MiniPick.get_picker_state().windows.target,\n      function() vim.cmd('edit ' .. item) end\n    )\n    return true\n  end\n<\nDefault value is |MiniPick.default_choose()|.\n\n# Choose marked items ~\n*MiniPick-source.choose_marked*\n\n`source.choose_marked` is a callable defining what to do when marked items\n(see |MiniPick-actions-mark|) are chosen. Serves as a companion to\n`source.choose` which can choose several items.\n\nIt will be called with the following arguments:\n- `items_marked` - array of marked items. Can be empty.\n\nIt should perform any intended \"choose\" action for several items and return\na value indicating whether picker should continue (i.e. not stop):\n`nil` and `false` will stop picker, other values will continue.\n\nNotes:\n- It is called when picker window is still current. Use `windows.target` value\n  from |MiniPick.get_picker_state()| output to do something with target window.\n\nExample: >lua\n\n  local choose_marked_print = function(items) print(vim.inspect(items)) end\n<\nDefault value is |MiniPick.default_choose_marked()|.\n\n------------------------------------------------------------------------------\n                                                              *MiniPick-actions*\nWhen picker is active, `mappings` table defines a set of special keys which when\npressed will execute certain actions. Those can be of two types:\n- Built-in: actions present in default `config.mappings`. Can be only overridden\n  with a different key.\n- Custom: user defined actions. Should be a table with `char` and `func` fields.\n\n\n# Built-in ~\n\n## Caret ~\n*MiniPick-actions-caret*\n\nUser can add character not only at query end, but more generally at caret.\n\n- `mappings.caret_left` - move caret to left.\n- `mappings.caret_right` - move caret to right.\n\n## Choose ~\n*MiniPick-actions-choose*\n\nChoose is a fundamental action that actually implements the intent of\ncalling a picker, i.e. pick an item.\n\n- `mappings.choose` - choose as is, i.e. apply `source.choose` for current item.\n- `mappings.choose_in_split` - make horizontal split at target window, update\n  target window to the new split, and choose.\n- `mappings.choose_in_tabpage` - same as `choose_in_split`, but create tabpage.\n- `mappings.choose_in_vsplit` - same as `choose_in_split`, but split vertically.\n- `mappings.choose_marked` - choose marked items as is, i.e.\n  apply `source.choose_marked` at current marked items.\n\n## Delete ~\n*MiniPick-actions-delete*\n\nDelete actions are for deleting elements from query.\n\n- `mappings.delete_char` - delete one character to the left.\n- `mappings.delete_char_right` - delete one character to the right.\n- `mappings.delete_left` - delete everything to the left (like |i_CTRL-U|).\n- `mappings.delete_word` - delete word to the left (like |i_CTRL-W|).\n\n## Mark ~\n*MiniPick-actions-mark*\n\nMarking is an action of adding certain items to a separate list which then can\nbe chosen with `mappings.choose_marked` (for example, sent to quickfix list).\nThis is a companion to a regular choosing which can pick only one item.\n\n- `mappings.mark` - toggle marked/unmarked state of current item.\n- `mappings.mark_all` - toggle marked/unmarked state (mark all if not all\n  marked; unmark all otherwise) of all currently matched items.\n\nNotes:\n- Marks persist across queries and matches. For example, user can make a query\n  with marking all matches several times and marked items from all queries\n  will be preserved.\n\n## Move ~\n*MiniPick-actions-move*\n\nMove is a fundamental action of changing which item is current.\n\n- `mappings.move_down` - change focus to the item below.\n- `mappings.move_start` change focus to the first currently matched item\n- `mappings.move_up` - change focus to the item above.\n\nNotes:\n- Up and down wrap around edges: `move_down` on last item moves to first,\n  `move_up` on first moves to last.\n- Moving when preview or info view is shown updates the view with new item.\n- These also work with non-overridable alternatives:\n    - `<Down>` moves down.\n    - `<Home>` moves to first matched.\n    - `<Up>` moves up.\n\n## Paste ~\n*MiniPick-actions-paste*\n\nPaste is an action to paste content of |registers| at caret.\n\n- `mappings.paste` - paste from register defined by the next key press.\n\nNotes:\n- Does not support expression register `=`.\n- Supports special cases of register: <C-f> (as |c_CTRL-R_CTRL-F|),\n  <C-w> (as |c_CTRL-R_CTRL-W|), <C-a> (as |c_CTRL-R_CTRL-A|),\n  <C-l> (as |c_CTRL-R_CTRL-L|).\n\n## Refine ~\n*MiniPick-actions-refine*\n\nRefine is an action that primarily executes the following:\n- Takes certain items and makes them be all items (in order they are present).\n- Resets query.\n- Updates `source.match` to be the one from config.\n\n- `mappings.refine` - refine currently matched items.\n- `mappings.refine_marked` - refine currently marked items.\n\nThis action is useful in at least two cases:\n- Perform consecutive \"narrowing\" queries. Example: to get items that contain\n  both \"hello\" and \"world\" exact matches (in no particular order) with default\n  matching, type \"'hello\" (notice \"'\" at the start) followed by `<C-Space>` and\n  another \"'world\".\n- Reset `match` to default. Particularly useful in |MiniPick.builtin.grep_live()|\n  and |MiniExtra.pickers.lsp()| with \"workspace_symbol_live\" scope.\n\n## Scroll ~\n*MiniPick-actions-scroll*\n\nScroll is an action to either move current item focus further than to the\nneighbor item or adjust window view to see more information.\n\n- `mappings.scroll_down` - when matches are shown, go down by the amount of\n  visible matches. In preview and info view - scroll down as with |CTRL-F|.\n- `mappings.scroll_left` - scroll left as with |zH|.\n- `mappings.scroll_right` - scroll right as with |zL|.\n- `mappings.scroll_up` - when matches are shown, go up by the amount of\n  visible matches. In preview and info view - scroll up as with |CTRL-B|.\n\n## Stop ~\n*MiniPick-actions-stop*\n\n`mappings.stop` stops the picker. <C-c> also always stops the picker.\n\n\n## Toggle ~\n*MiniPick-actions-toggle*\n\nToggle action is a way to change view: show if target is not shown, reset to\nmain view otherwise.\n\n- `mappings.toggle_info` - toggle info view.\n- `mappings.toggle_preview` - toggle preview.\n\nNote:\n- Updating query in any way resets window view to show matches.\n- Moving current item focus keeps preview or info view with updated item.\n\n# Custom ~\n*MiniPick-actions-custom*\n\nAlong with built-in actions, users can define custom actions. This can be\ndone by supplying custom elements to `mappings` table. The field defines action\nname (used to infer an action description in info view). The value is a table\nwith the following fields:\n- <char> `(string)` - single character acting as action trigger.\n- <func> `(function)` - callable to be executed without arguments after\n  user presses <char>. Its return value is treated as \"should stop picker\n  after execution\", i.e. returning nothing, `nil`, or `false` continues\n  picker while everything else (prefer `true`) stops it.\n\nExample of `execute` custom mapping: >lua\n\n  execute = {\n    char = '<C-e>',\n    func = function() vim.cmd(vim.fn.input('Execute: ')) end,\n  }\n<\n------------------------------------------------------------------------------\n                                                             *MiniPick-examples*\n# Disable icons ~\n\nDisable icons in |MiniPick.builtin| pickers related to paths: >lua\n\n  local pick = require('mini.pick')\n  pick.setup({ source = { show = pick.default_show } })\n<\n# Switch toggle and move keys ~\n>lua\n  require('mini.pick').setup({\n    mappings = {\n      toggle_info    = '<C-k>',\n      toggle_preview = '<C-p>',\n      move_down      = '<Tab>',\n      move_up        = '<S-Tab>',\n    }\n  })\n<\n# Different window styles ~\n>lua\n  -- Different border\n  { window = { config = { border = 'double' } } }\n\n  -- \"Cursor tooltip\"\n  {\n    window = {\n      config = {\n        relative = 'cursor', anchor = 'NW',\n        row = 0, col = 0, width = 40, height = 20,\n      },\n    },\n  }\n\n  -- Centered on screen\n  local win_config = function()\n    local height = math.floor(0.618 * vim.o.lines)\n    local width = math.floor(0.618 * vim.o.columns)\n    return {\n      anchor = 'NW', height = height, width = width,\n      row = math.floor(0.5 * (vim.o.lines - height)),\n      col = math.floor(0.5 * (vim.o.columns - width)),\n    }\n  end\n  { window = { config = win_config } }\n<\n------------------------------------------------------------------------------\n                                                              *MiniPick.setup()*\n                           `MiniPick.setup`({config})\nModule setup\n\n# :Pick ~\n*:Pick*\n\nCalling this function creates a `:Pick` user command. It takes picker name\nfrom |MiniPick.registry| as mandatory first argument and executes it with\nfollowing (expanded, |expandcmd()|) |<f-args>| combined in a single table.\nTo add custom pickers, update |MiniPick.registry|.\n\nExample: >vim\n\n  :Pick files tool='git'\n  :Pick grep pattern='<cword>'\n<\n\nIt also sets custom |vim.ui.select()| implementation to use the module.\nSee |MiniPick.ui_select()|.\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniPick.config|.\n\nUsage ~\n>lua\n  require('mini.pick').setup() -- use default config\n  -- OR\n  require('mini.pick').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniPick.config*\n                               `MiniPick.config`\nDefaults ~\n>lua\n  MiniPick.config = {\n    -- Delays (in ms; should be at least 1)\n    delay = {\n      -- Delay between forcing asynchronous behavior\n      async = 10,\n\n      -- Delay between computation start and visual feedback about it\n      busy = 50,\n    },\n\n    -- Keys for performing actions. See `:h MiniPick-actions`.\n    mappings = {\n      caret_left  = '<Left>',\n      caret_right = '<Right>',\n\n      choose            = '<CR>',\n      choose_in_split   = '<C-s>',\n      choose_in_tabpage = '<C-t>',\n      choose_in_vsplit  = '<C-v>',\n      choose_marked     = '<M-CR>',\n\n      delete_char       = '<BS>',\n      delete_char_right = '<Del>',\n      delete_left       = '<C-u>',\n      delete_word       = '<C-w>',\n\n      mark     = '<C-x>',\n      mark_all = '<C-a>',\n\n      move_down  = '<C-n>',\n      move_start = '<C-g>',\n      move_up    = '<C-p>',\n\n      paste = '<C-r>',\n\n      refine        = '<C-Space>',\n      refine_marked = '<M-Space>',\n\n      scroll_down  = '<C-f>',\n      scroll_left  = '<C-h>',\n      scroll_right = '<C-l>',\n      scroll_up    = '<C-b>',\n\n      stop = '<Esc>',\n\n      toggle_info    = '<S-Tab>',\n      toggle_preview = '<Tab>',\n    },\n\n    -- General options\n    options = {\n      -- Whether to show content from bottom to top\n      content_from_bottom = false,\n\n      -- Whether to cache matches (more speed and memory on repeated prompts)\n      use_cache = false,\n    },\n\n    -- Source definition. See `:h MiniPick-source`.\n    source = {\n      items = nil,\n      name  = nil,\n      cwd   = nil,\n\n      match   = nil,\n      show    = nil,\n      preview = nil,\n\n      choose        = nil,\n      choose_marked = nil,\n    },\n\n    -- Window related options\n    window = {\n      -- Float window config (table or callable returning it)\n      config = nil,\n\n      -- String to use as caret in prompt\n      prompt_caret = '▏',\n\n      -- String to use as prefix in prompt\n      prompt_prefix = '> ',\n    },\n  }\n<\n# Delays ~\n\n`config.delay` defines plugin delays (in ms). All should be strictly positive.\n\n`delay.async` is a delay between forcing asynchronous behavior. This usually\nmeans forcing |:redraw| in preview (several but limited number of times to\nensure visible async highlighting) and using |MiniPick.poke_is_picker_active()|\n(for example, to stop current matching if query has updated).\nSmaller values give smoother user experience at the cost of more computations.\n\n`delay.busy` is a delay between when some computation starts and showing\nvisual feedback about it by making window border to have `MiniPickBorderBusy`\nhighlight group.\nSmaller values will give feedback faster at the cost of feeling like flicker.\n\n# Mappings ~\n\n`config.mappings` defines keys for special actions to be triggered after certain\nkeys. See |MiniPick-actions| for more information.\n\n# Options ~\n\n`config.options` contains some general purpose options.\n\n`options.content_from_bottom` is a boolean indicating whether content should be\nshown from bottom to top. That means that best matches will be shown at\nthe bottom. Note: for better experience use Neovim>=0.10, which has floating\nwindow footer capability. Default: `false`.\n\n`options.use_cache` is a boolean indicating whether match results should be\ncached per prompt (i.e. concatenated query). This results into faster response\non repeated prompts (like when deleting query entries) at the cost of using\nmore memory. Default: `false`.\n\n# Source ~\n\n`config.source` defines fallbacks for source specification. For example, this\ncan be used to change default `match` to use different implementation or `show`\nto not show icons for some |MiniPick.builtin| pickers (see |MiniPick-examples|).\nSee |MiniPick-source| for more information.\n\n# Window ~\n\n`config.window` contains window specific configurations.\n\n`window.config` defines a (parts of) default floating window config for the main\npicker window. This can be either a table overriding some parts or a callable\nreturning such table. See |MiniPick-examples| for some examples.\n\n`window.prompt_caret` defines how caret is displayed in window's prompt.\nDefault: '▏'.\n\n`window.prompt_prefix` defines what prefix is used in window's prompt.\nDefault: '> '.\n\n------------------------------------------------------------------------------\n                                                              *MiniPick.start()*\n                            `MiniPick.start`({opts})\nStart picker\n\nNotes:\n- If there is currently an active picker, it is properly stopped and new one\n  is started \"soon\" in the main event-loop (see |vim.schedule()|).\n- Current window at the moment of this function call is treated as \"target\".\n  It will be set back as current after |MiniPick.stop()|.\n  See |MiniPick.get_picker_state()| and |MiniPick.set_picker_target_window()|.\n\nParameters ~\n{opts} `(table|nil)` Options. Should have same structure as |MiniPick.config|.\n  Default values are inferred from there.\n  Usually should have proper |MiniPick-source.items| defined.\n\nReturn ~\n`(any)` Item which was current when picker is stopped; `nil` if aborted.\n\n------------------------------------------------------------------------------\n                                                               *MiniPick.stop()*\n                               `MiniPick.stop`()\nStop active picker\n\n------------------------------------------------------------------------------\n                                                            *MiniPick.refresh()*\n                              `MiniPick.refresh`()\nRefresh active picker\n\n------------------------------------------------------------------------------\n                                                      *MiniPick.default_match()*\n         `MiniPick.default_match`({stritems}, {inds}, {query}, {opts})\nDefault match\n\nFilter target stritems to contain query and sort from best to worst matches.\n\nImplements default value for |MiniPick-source.match|.\n\nBy default (if no special modes apply) it does the following fuzzy matching:\n\n- Stritem contains query if it contains all its elements verbatim in the same\n  order (possibly with gaps, i.e. not strictly one after another).\n  Note: empty query and empty string element is contained in any string.\n\n- Sorting is done with the following ordering (same as in |mini.fuzzy|):\n    - The smaller the match width (end column minus start column) the better.\n    - Among same match width, the smaller start column the better.\n    - Among same match width and start column, preserve original order.\n\nNotes:\n- Most common interactive usage results into `query` containing one typed\n  character per element.\n\n# Special modes ~\n\n- Forced modes:\n    - Query starts with \"*\": match the rest fuzzy (without other modes).\n    - Query starts with \"'\": match the rest exactly (without gaps).\n\n- Place modes:\n    - Query starts with '^': match the rest exactly at start.\n    - Query ends with '$': match the rest exactly at end.\n    - Both modes can be used simultaneously.\n\n- Grouped: query contains at least one whitespace element. Output is computed\n  as if query is split at whitespace indexes with concatenation between them.\n\nPrecedence of modes:\n  \"forced exact\" = \"forced fuzzy\" > \"place start/end\" > \"grouped\" > \"default\"\n\n# Examples ~\n\nAssuming `stritems` are `{ '_abc', 'a_bc', 'ab_c', 'abc_' }`, here are some\nexample matches based on prompt (concatenated query): >\n\n  | Prompt | Matches                |\n  |--------|------------------------|\n  | abc    | All                    |\n  | *abc   | All                    |\n  |        |                        |\n  | 'abc   | abc_, _abc             |\n  | *'abc  | None (no \"'\" in items) |\n  |        |                        |\n  | ^abc   | abc_                   |\n  | *^abc  | None (no \"^\" in items) |\n  |        |                        |\n  | abc$   | _abc                   |\n  | *abc$  | None (no \"$\" in items) |\n  |        |                        |\n  | ab c   | abc_, _abc, ab_c       |\n  | *ab c  | None (no \" \" in items) |\n<\nHaving query `{ 'ab', 'c' }` is the same as \"ab c\" prompt.\n\nYou can have a feel of how this works with this command: >lua\n\n  MiniPick.start({ source = { items = { '_abc', 'a_bc', 'ab_c', 'abc_' } } })\n<\nParameters ~\n{stritems} `(table)` Array of all stritems.\n{inds} `(table)` Array of `stritems` indexes to match. All of them should point\n  at string elements of `stritems`. No check is done for performance reasons.\n{query} `(table)` Array of strings.\n{opts} `(table|nil)` Options. Possible fields:\n  - <sync> `(boolean)` - Whether to match synchronously. Default: `false`.\n  - <preserve_order> `(boolean)` - Whether to skip sort step. Default: `false`.\n\nReturn ~\n`(table|nil)` Depending on whether computation is synchronous (either `opts.sync`\n  is `true` or there is an active picker):\n  - If yes, array of `stritems` indexes matching the `query` (from best to worst).\n  - If no, `nil` is returned with |MiniPick.set_picker_match_inds()| used later.\n\n------------------------------------------------------------------------------\n                                                       *MiniPick.default_show()*\n          `MiniPick.default_show`({buf_id}, {items}, {query}, {opts})\nDefault show\n\nShow items in a buffer and highlight parts that actually match query (assuming\nmatch is done with |MiniPick.default_match()|). Lines are computed based on\nthe |MiniPick-source.items-stritems|.\n\nImplements default value for |MiniPick-source.show|.\n\nUses the following highlight groups (see |mini.pick| for their description):\n\n- `MiniPickIconDirectory`\n- `MiniPickIconFile`\n- `MiniPickMatchCurrent`\n- `MiniPickMatchMarked`\n- `MiniPickMatchRanges`\n\nParameters ~\n{buf_id} `(number)` Identifier of target buffer.\n{items} `(table)` Array of items to show.\n{query} `(table)` Array of strings representing query.\n{opts} `(table|nil)` Options. Possible fields:\n  - <show_icons> `(boolean)` - whether to show icons for entries recognized as\n    valid actually present paths on disk (see |MiniPick-source.items-common|),\n    empty space otherwise. Tries to use `text` field as fallback for path.\n    Default: `false`. Note: |MiniPick.builtin| pickers showing file/directory\n    paths use `true` by default.\n  - <icons> `(table)` - table with fallback icons used if icon provider\n    does not itself supply default icons for category. Can have fields:\n      - <directory> `(string)` - icon for directory. Default: \" \".\n      - <file> `(string)` - icon for file. Default: \" \".\n      - <none> `(string)` - icon for non-valid path. Default: \"  \".\n\n------------------------------------------------------------------------------\n                                                    *MiniPick.default_preview()*\n              `MiniPick.default_preview`({buf_id}, {item}, {opts})\nDefault preview\n\nPreview item. Logic follows the rules in |MiniPick-source.items-common|:\n- File and buffer are shown at the start.\n- Directory has its content listed.\n- Line/position/region in file or buffer is shown at start.\n- Others are shown directly with |vim.inspect()|.\n\nImplements default value for |MiniPick-source.preview|.\n\nUses the following highlight groups (see |mini.pick| for their description):\n\n- `MiniPickPreviewLine`\n- `MiniPickPreviewRegion`\n\nParameters ~\n{buf_id} `(number)` Identifier of target buffer.\n{item} `(any)` Item to preview.\n{opts} `(table|nil)` Options. Possible values:\n  - <n_context_lines> `(number)` - number of lines to load past target position\n    when reading from disk. Useful to explore context. Default: 'lines' twice.\n  - <line_position> `(string)` - where in the window to show item position.\n    One of \"top\", \"center\", \"bottom\". Default: \"top\".\n\n------------------------------------------------------------------------------\n                                                     *MiniPick.default_choose()*\n                       `MiniPick.default_choose`({item})\nDefault choose\n\nChoose item. Logic follows the rules in |MiniPick-source.items-common|:\n- File uses |bufadd()| and sets cursor at the start of line/position/region.\n- Buffer is set as current in target window and sets cursor similarly.\n- Directory is called with |:edit| in the target window.\n- Others have the output of |vim.inspect()| printed in Command line.\n\nImplements default value for |MiniPick-source.choose|.\n\nParameters ~\n{item} `(any)` Item to choose.\n\n------------------------------------------------------------------------------\n                                              *MiniPick.default_choose_marked()*\n               `MiniPick.default_choose_marked`({items}, {opts})\nDefault choose marked items\n\nChoose marked items. Logic follows the rules in |MiniPick-source.items-common|:\n- If among items there is at least one file or buffer, quickfix list is opened\n  with all file or buffer lines/positions/regions.\n- Otherwise, picker's `source.choose` is called on the first item.\n\nImplements default value for |MiniPick-source.choose_marked|.\n\nParameters ~\n{items} `(table)` Array of items to choose.\n{opts} `(table|nil)` Options. Possible fields:\n  - <list_type> `(string)` - which type of list to open. One of \"quickfix\"\n    or \"location\". Default: \"quickfix\".\n\n------------------------------------------------------------------------------\n                                                          *MiniPick.ui_select()*\n        `MiniPick.ui_select`({items}, {opts}, {on_choice}, {start_opts})\nSelect rewrite\n\nFunction which can be used to directly override |vim.ui.select()| to use\n'mini.pick' for any \"select\" type of tasks.\nSet automatically in |MiniPick.setup()|.\n\nImplements required by `vim.ui.select()` signature, with some differencies:\n- Allows `opts.preview_item` that returns an array of lines for item preview.\n- Allows fourth `start_opts` argument to customize |MiniPick.start()| call.\n\nNotes:\n- `on_choice` is called when target window is current.\n\nUsage ~\n>lua\n  -- Customize with fourth argument inside a function wrapper\n  vim.ui.select = function(items, opts, on_choice)\n    local start_opts = { window = { config = { width = vim.o.columns } } }\n    return MiniPick.ui_select(items, opts, on_choice, start_opts)\n  end\n<\nTo preserve original `vim.ui.select()`: >lua\n\n  local ui_select_orig = vim.ui.select\n  require('mini.pick').setup()\n  vim.ui.select = ui_select_orig\n<\n------------------------------------------------------------------------------\n                                                              *MiniPick.builtin*\n                               `MiniPick.builtin`\nTable with built-in pickers\n\n------------------------------------------------------------------------------\n                                                      *MiniPick.builtin.files()*\n                 `MiniPick.builtin.files`({local_opts}, {opts})\nPick from files\n\nLists all files recursively in all subdirectories. Tries to use one of the\nCLI tools to create items (see |MiniPick-cli-tools|): `rg`, `fd`, `git`.\nIf none is present, uses fallback which utilizes |vim.fs.dir()|.\n\nTo customize CLI tool search, either use tool's global configuration approach\nor directly |MiniPick.builtin.cli()| with specific command.\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <tool> `(string)` - which tool to use. One of \"rg\", \"fd\", \"git\", \"fallback\".\n    Default: whichever tool is present, trying in that same order.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\n------------------------------------------------------------------------------\n                                                       *MiniPick.builtin.grep()*\n                 `MiniPick.builtin.grep`({local_opts}, {opts})\nPick from pattern matches\n\nLists all pattern matches recursively in all subdirectories.\nTries to use one of the CLI tools to create items (see |MiniPick-cli-tools|):\n`rg`, `git`. If none is present, uses fallback which utilizes |vim.fs.dir()| and\nLua pattern matches (NOT recommended in large directories).\n\nTo customize CLI tool search, either use tool's global configuration approach\nor directly |MiniPick.builtin.cli()| with specific command.\nOptions 'ignorecase' and 'smartcase' are respected via forcing appropriate\nflags to CLI tool (i.e. overriding tool's global config).\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <tool> `(string)` - which tool to use. One of \"rg\", \"git\", \"fallback\".\n    Default: whichever tool is present, trying in that same order.\n  - <pattern> `(string)` - string pattern to search. If not given, asks user\n    interactively with |input()|.\n  - <globs> `(table)` - array of string glob patterns to restrict search to\n    matching files. Supported only by \"rg\" and \"git\" tools, respects their\n    specific glob syntax and effects. Default: `{}` (no restriction).\n    Example: `{ '*.lua', 'lua/**' }` for Lua files and files in \"lua\" directory.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\n------------------------------------------------------------------------------\n                                                  *MiniPick.builtin.grep_live()*\n               `MiniPick.builtin.grep_live`({local_opts}, {opts})\nPick from pattern matches with live feedback\n\nPerform pattern matching treating prompt as pattern. Gives live feedback on\nwhich matches are found. Use |MiniPick-actions-refine| to revert to regular\nmatching. Use `<C-o>` to restrict search to files matching glob patterns.\nTries to use one of the CLI tools to create items (see |MiniPick-cli-tools|):\n`rg`, `git`. If none is present, error is thrown (for performance reasons).\n\nTo customize search, use tool's global configuration approach.\nOptions 'ignorecase' and 'smartcase' are respected via forcing appropriate\nflags to CLI tool (i.e. overriding tool's global config).\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <tool> `(string)` - which tool to use. One of \"rg\", \"git\".\n    Default: whichever tool is present, trying in that same order.\n  - <globs> `(table)` - array of string glob patterns to restrict search to\n    matching files. Supported only by \"rg\" and \"git\" tools, respects their\n    specific glob syntax and effects. Default: `{}` (no restriction).\n    Example: `{ '*.lua', 'lua/**' }` for Lua files and files in \"lua\" directory.\n    Use `<C-o>` custom mapping to add glob to the array.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\n------------------------------------------------------------------------------\n                                                       *MiniPick.builtin.help()*\n                 `MiniPick.builtin.help`({local_opts}, {opts})\nPick from help tags\n\nNotes:\n- On choose directly executes |:help| command with appropriate modifier\n  (none, |:vertical|, |:tab|). This is done through custom mappings named\n  `show_help_in_{split,vsplit,tab}`. Not `choose_in_{split,vsplit,tab}` because\n  there is no split guarantee (like if there is already help window opened).\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <default_split> `(string)` - direction of a split for `choose` action.\n    One of \"horizontal\", \"vertical\", \"tab\". Default: \"horizontal\".\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\n------------------------------------------------------------------------------\n                                                    *MiniPick.builtin.buffers()*\n                `MiniPick.builtin.buffers`({local_opts}, {opts})\nPick from buffers\n\nNotes:\n- There are not built-in mappings for buffer manipulation. Here is an example\n  of how to call this function with mapping to wipeout the current item: >lua\n\n  local wipeout_cur = function()\n    vim.api.nvim_buf_delete(MiniPick.get_picker_matches().current.bufnr, {})\n  end\n  local buffer_mappings = { wipeout = { char = '<C-d>', func = wipeout_cur } }\n  MiniPick.builtin.buffers(local_opts, { mappings = buffer_mappings })\n<\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <include_current> `(boolean)` - whether to include current buffer in\n    the output. Default: `true`.\n  - <include_unlisted> `(boolean)` - whether to include |unlisted-buffer|s in\n    the output. Default: `false`.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\n------------------------------------------------------------------------------\n                                                        *MiniPick.builtin.cli()*\n                  `MiniPick.builtin.cli`({local_opts}, {opts})\nPick from CLI output\n\nExecutes command line tool and constructs items based on its output.\nUses |MiniPick.set_picker_items_from_cli()|.\n\nExample: `MiniPick.builtin.cli({ command = { 'echo', 'a\\nb\\nc' } })`\n\nParameters ~\n{local_opts} `(table|nil)` Options defining behavior of this particular picker.\n  Possible fields:\n  - <command> `(table)` - forwarded to `set_picker_items_from_cli()`.\n  - <postprocess> `(function)` - forwarded to `set_picker_items_from_cli()`.\n  - <spawn_opts> `(table)` - forwarded to `set_picker_items_from_cli()`.\n    Note: if `cwd` field is absent, it is inferred from |MiniPick-source.cwd|.\n{opts} `(table|nil)` Options forwarded to |MiniPick.start()|.\n\n------------------------------------------------------------------------------\n                                                     *MiniPick.builtin.resume()*\n                          `MiniPick.builtin.resume`()\nResume latest picker\n\n------------------------------------------------------------------------------\n                                                             *MiniPick.registry*\n                              `MiniPick.registry`\nPicker registry\n\nPlace for users and extensions to manage pickers with their commonly used\nlocal options. By default contains all |MiniPick.builtin| pickers.\nAll entries should accept only a single `local_opts` table argument.\n\nServes as a source for |:Pick| command.\n\nCustomization examples: >lua\n\n  -- Adding custom picker to pick `register` entries\n  MiniPick.registry.registry = function()\n    local items = vim.tbl_keys(MiniPick.registry)\n    table.sort(items)\n    local source = {items = items, name = 'Registry', choose = function() end}\n    local chosen_picker_name = MiniPick.start({ source = source })\n    if chosen_picker_name == nil then return end\n    return MiniPick.registry[chosen_picker_name]()\n  end\n\n  -- Make `:Pick files` accept `cwd`\n  MiniPick.registry.files = function(local_opts)\n    local opts = { source = { cwd = local_opts.cwd } }\n    local_opts.cwd = nil\n    return MiniPick.builtin.files(local_opts, opts)\n  end\n<\n------------------------------------------------------------------------------\n                                                   *MiniPick.get_picker_items()*\n                         `MiniPick.get_picker_items`()\nGet items of active picker\n\nReturn ~\n`(table|nil)` Picker items or `nil` if no active picker.\n\nSee also ~\n|MiniPick.set_picker_items()| and |MiniPick.set_picker_items_from_cli()|\n\n------------------------------------------------------------------------------\n                                                *MiniPick.get_picker_stritems()*\n                        `MiniPick.get_picker_stritems`()\nGet stritems of active picker\n\nReturn ~\n`(table|nil)` Picker stritems (|MiniPick-source.items-stritems|) or `nil` if\n  no active picker.\n\nSee also ~\n|MiniPick.set_picker_items()| and |MiniPick.set_picker_items_from_cli()|\n\n------------------------------------------------------------------------------\n                                                 *MiniPick.get_picker_matches()*\n                        `MiniPick.get_picker_matches`()\nGet matches of active picker\n\nReturn ~\n`(table|nil)` Picker matches or `nil` if no active picker. Matches is a table\n  with the following fields:\n  - <all> `(table|nil)` - all currently matched items.\n  - <all_inds> `(table|nil)` - indexes of all currently matched items.\n  - <current> `(any)` - current matched item.\n  - <current_ind> `(number|nil)` - index of current matched item.\n  - <marked> `(table|nil)` - marked items.\n  - <marked_inds> `(table|nil)` - indexes of marked items.\n  - <shown> `(table|nil)` - shown items (from top to bottom).\n  - <shown_inds> `(table|nil)` - indexes of shown items (from top to bottom).\n\nSee also ~\n|MiniPick.set_picker_match_inds()|\n\n------------------------------------------------------------------------------\n                                                    *MiniPick.get_picker_opts()*\n                          `MiniPick.get_picker_opts`()\nGet config of active picker\n\nReturn ~\n`(table|nil)` Picker config (`start()`'s input `opts` table) or `nil` if\n  no active picker.\n\nSee also ~\n|MiniPick.set_picker_opts()|\n\n------------------------------------------------------------------------------\n                                                   *MiniPick.get_picker_state()*\n                         `MiniPick.get_picker_state`()\nGet state data of active picker\n\nReturn ~\n`(table|nil)` Table with picker state data or `nil` if no active picker.\n  State data is a table with the following fields:\n  - <buffers> `(table)` - table with `main`, `preview`, `info` fields representing\n    buffer identifier (or `nil`) for corresponding view.\n  - <windows> `(table)` - table with `main` and `target` fields representing\n    window identifiers for main and target windows.\n  - <caret> `(number)` - caret column.\n  - <is_busy> `(boolean)` - whether picker is busy with computations.\n\nSee also ~\n|MiniPick.set_picker_target_window()|\n\n------------------------------------------------------------------------------\n                                                   *MiniPick.get_picker_query()*\n                         `MiniPick.get_picker_query`()\nGet query of active picker\n\nReturn ~\n`(table|nil)` Array of picker query or `nil` if no active picker.\n\nSee also ~\n|MiniPick.set_picker_query()|\n\n------------------------------------------------------------------------------\n                                                   *MiniPick.set_picker_items()*\n                  `MiniPick.set_picker_items`({items}, {opts})\nSet items for active picker\n\nNote: sets items asynchronously in non-blocking fashion.\n\nParameters ~\n{items} `(table)` Array of items.\n{opts} `(table|nil)` Options. Possible fields:\n  - <do_match> `(boolean)` - whether to perform match after setting items.\n    Default: `true`.\n  - <querytick> `(number|nil)` - value of querytick (|MiniPick.get_querytick()|)\n    to periodically check against when setting items. If checked querytick\n    differs from supplied, no items are set.\n\nSee also ~\n|MiniPick.get_picker_items()| and |MiniPick.get_picker_stritems()|\n\n------------------------------------------------------------------------------\n                                          *MiniPick.set_picker_items_from_cli()*\n            `MiniPick.set_picker_items_from_cli`({command}, {opts})\nSet items for active picker based on CLI output\n\nAsynchronously executes `command` and sets items to its postprocessed output.\n\nExample: >lua\n\n  local items = vim.schedule_wrap(function()\n    MiniPick.set_picker_items_from_cli({ 'echo', 'a\\nb\\nc' })\n  end)\n  MiniPick.start({ source = { items = items, name = 'Echo abc' } })\n<\nParameters ~\n{command} `(table)` Array with (at least one) string command parts.\n{opts} `(table|nil)` Options. Possible fields:\n  - <postprocess> `(function)` - callable performing postprocessing of output.\n    Will be called with array of lines as input, should return array of items.\n    Default: removes trailing empty lines and uses rest as string items.\n  - <spawn_opts> `(table)` - `options` for |uv.spawn()|, except `args` and `stdio`.\n    Note: relative `cwd` path is resolved against active picker's `cwd`.\n  - <set_items_opts> `(table)` - table forwarded to |MiniPick.set_picker_items()|.\n\nSee also ~\n|MiniPick.get_picker_items()| and |MiniPick.get_picker_stritems()|\n\n------------------------------------------------------------------------------\n                                              *MiniPick.set_picker_match_inds()*\n          `MiniPick.set_picker_match_inds`({match_inds}, {match_type})\nSet match indexes for active picker\n\nThere are two intended use cases:\n- Inside custom asynchronous |MiniPick-source.match| function to set which of\n  picker's stritems match the query. See |MiniPick.poke_is_picker_active()|.\n- To programmatically set current match and marked items.\n  See |MiniPick.get_picker_matches()|.\n\nParameters ~\n{match_inds} `(table)` Array of numbers with picker's items indexes.\n{match_type} `(string|nil)` Type of match indexes to set. One of:\n  - `\"all\"` (default) - indexes of items that match query.\n  - `\"current\"` - index of current match. Only first element is used and should\n    also be present among query matches.\n  - `\"marked\"` - indexes of marked items. Values can be not among query matches.\n    Will make only input indexes be marked, i.e. current marks are reset.\n  Note: no `\"shown\"` match type as those indexes are computed automatically.\n\nSee also ~\n|MiniPick.get_picker_matches()|\n\n------------------------------------------------------------------------------\n                                                    *MiniPick.set_picker_opts()*\n                       `MiniPick.set_picker_opts`({opts})\nSet config for active picker\n\nParameters ~\n{opts} `(table)` Table overriding initial `opts` input of |MiniPick.start()|.\n\nSee also ~\n|MiniPick.get_picker_opts()|\n\n------------------------------------------------------------------------------\n                                           *MiniPick.set_picker_target_window()*\n                 `MiniPick.set_picker_target_window`({win_id})\nSet target window for active picker\n\nParameters ~\n{win_id} `(number)` Valid window identifier to be used as the new target window.\n\nSee also ~\n|MiniPick.get_picker_state()|\n\n------------------------------------------------------------------------------\n                                                   *MiniPick.set_picker_query()*\n                      `MiniPick.set_picker_query`({query})\nSet query for active picker\n\nParameters ~\n{query} `(table)` Array of strings to be set as the new picker query.\n\nSee also ~\n|MiniPick.get_picker_query()|\n\n------------------------------------------------------------------------------\n                                                      *MiniPick.get_querytick()*\n                           `MiniPick.get_querytick`()\nGet query tick\n\nQuery tick is a unique query identifier. Intended to be used to detect user\nactivity during and between |MiniPick.start()| calls for efficient non-blocking\nfunctionality. Updates after any query change, picker start and stop.\n\nSee |MiniPick.poke_is_picker_active()| for usage example.\n\nReturn ~\n`(number)` Query tick.\n\n------------------------------------------------------------------------------\n                                                   *MiniPick.is_picker_active()*\n                         `MiniPick.is_picker_active`()\nCheck if there is an active picker\n\nReturn ~\n`(boolean)` Whether there is currently an active picker.\n\nSee also ~\n|MiniPick.poke_is_picker_active()|\n\n------------------------------------------------------------------------------\n                                              *MiniPick.poke_is_picker_active()*\n                       `MiniPick.poke_is_picker_active`()\nPoke if picker is active\n\nIntended to be used for non-blocking implementation of source methods.\nReturns an output of |MiniPick.is_picker_active()|, but depending on\nwhether there is a coroutine running:\n- If no, return it immediately.\n- If yes, return it after `coroutine.yield()` with `coroutine.resume()`\n  called \"soon\" by the main event-loop (see |vim.schedule()|).\n\nExample of non-blocking exact `match` (as demo; can be optimized further): >lua\n\n  local match_nonblock = function(match_inds, stritems, query)\n    local prompt, querytick = table.concat(query), MiniPick.get_querytick()\n    local f = function()\n      local res = {}\n      for _, ind in ipairs(match_inds) do\n        local should_stop = not MiniPick.poke_is_picker_active() or\n          MiniPick.get_querytick() ~= querytick\n        if should_stop then return end\n\n        if stritems[ind]:find(prompt) ~= nil then table.insert(res, ind) end\n      end\n\n      MiniPick.set_picker_match_inds(res)\n    end\n\n    coroutine.resume(coroutine.create(f))\n  end\n<\nReturn ~\n`(boolean)` Whether there is an active picker.\n\nSee also ~\n|MiniPick.is_picker_active()|\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-sessions.txt",
    "content": "*mini.sessions* Session management\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                  *MiniSessions*\nRead, write, and delete sessions. Uses |:mksession| (meaning 'sessionoptions'\nis fully respected). This is intended as a drop-in Lua replacement for\n[mhinz/vim-startify](https://github.com/mhinz/vim-startify) session management\n(works out of the box with sessions created by it). Implements both global\n(from configured directory) and local (from current directory) sessions.\n\nKey design ideas:\n- Sessions are represented by readable files (results of applying |:mksession|).\n  There are two kinds of sessions:\n    - Global: any file inside a configurable directory.\n    - Local: configurable file inside current working directory (|getcwd()|).\n\n- All session files are detected during `MiniSessions.setup()` and during\n  relevant actions (`read`, `delete`, `select`) with file names as session\n  names (including possible extension).\n\n- No automated new session creation. Use |MiniSessions.write()| manually.\n\n- Store information about detected sessions in separate table\n  (|MiniSessions.detected|) and operate only on it. Meaning if this information\n  changes, there will be no effect until next detection. To avoid confusion,\n  don't directly use |:mksession| / |:source| for writing / reading session files.\n\nFeatures:\n- Autoread default session (local if detected, else latest written global) if\n  Neovim was called without intention to show something else.\n\n- Autowrite currently read session before leaving it (quit Neovim or read\n  another session).\n\n- Configurable severity level of all actions.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.sessions').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniSessions` which you can use for scripting or manually (with\n`:lua MiniSessions.*`).\n\nSee |MiniSessions.config| for `config` structure and default values.\n\nThis module doesn't benefit from buffer local configuration, so using\n`vim.b.minisessions_config` will have no effect here.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.minisessions_disable` (globally) or\n`vim.b.minisessions_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                          *MiniSessions.setup()*\n                         `MiniSessions.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniSessions.config|.\n\nUsage ~\n>lua\n  require('mini.sessions').setup() -- use default config\n  -- OR\n  require('mini.sessions').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                           *MiniSessions.config*\n                             `MiniSessions.config`\nDefaults ~\n>lua\n  MiniSessions.config = {\n    -- Whether to read default session if Neovim opened without file arguments\n    autoread = false,\n\n    -- Whether to write currently read session before leaving it\n    autowrite = true,\n\n    -- Directory where global sessions are stored (use `''` to disable)\n    directory = --<\"session\" subdir of user data directory from |stdpath()|>,\n\n    -- File for local session (use `''` to disable)\n    file = 'Session.vim',\n\n    -- Whether to force possibly harmful actions (meaning depends on function)\n    force = { read = false, write = true, delete = false },\n\n    -- Hook functions for actions. Default `nil` means 'do nothing'.\n    -- Takes table with active session data as argument.\n    hooks = {\n      -- Before successful action\n      pre = { read = nil, write = nil, delete = nil },\n      -- After successful action\n      post = { read = nil, write = nil, delete = nil },\n    },\n\n    -- Whether to print session path after action\n    verbose = { read = false, write = true, delete = true },\n  }\n<\n------------------------------------------------------------------------------\n                                                         *MiniSessions.detected*\n                            `MiniSessions.detected`\nTable of detected sessions. Keys represent session name. Values are tables\nwith session information that currently has these fields (but subject to\nchange):\n- <modify_time> `(number)` modification time (see |getftime()|) of session file.\n- <name> `(string)` name of session (should be equal to table key).\n- <path> `(string)` full path to session file.\n- <type> `(string)` type of session ('global' or 'local').\n\n------------------------------------------------------------------------------\n                                                           *MiniSessions.read()*\n                  `MiniSessions.read`({session_name}, {opts})\nRead detected session\n\nWhat it does:\n- If there is an active session and `autowrite` is `true` in |MiniSessions.config|,\n  write it with |MiniSessions.write()|.\n- Delete all current buffers with |:bwipeout|. This is needed to correctly\n  restore buffers from target session. If `force` is not `true`, checks\n  beforehand for unsaved listed buffers and stops if there are any.\n- Source session with supplied name.\n\nParameters ~\n{session_name} `(string|nil)` Name of detected session file to read. Default:\n  `nil` for default session: local (if detected) or latest session (see\n  |MiniSessions.get_latest()|).\n{opts} `(table|nil)` Table with options. Current allowed keys:\n  - <force> (whether to delete unsaved buffers; default:\n    `MiniSessions.config.force.read`).\n  - <verbose> (whether to print session path after action; default\n    `MiniSessions.config.verbose.read`).\n  - <hooks> (a table with <pre> and <post> function hooks to be executed\n    with session data argument before and after successful read; overrides\n    `MiniSessions.config.hooks.pre.read` and\n    `MiniSessions.config.hooks.post.read`).\n\n------------------------------------------------------------------------------\n                                                          *MiniSessions.write()*\n                  `MiniSessions.write`({session_name}, {opts})\nWrite session\n\nWhat it does:\n- Check if file for supplied session name already exists. If it does and\n  `force` is not `true`, then stop.\n- Write session with |:mksession| to a file named `session_name`. Its\n  directory is determined based on type of session:\n    - It is at location |v:this_session| if `session_name` is `nil` and\n      there is currently read session.\n    - It is current working directory (|getcwd()|) if `session_name` is equal\n      to `MiniSessions.config.file` (represents local session).\n    - It is `MiniSessions.config.directory` otherwise (represents global\n      session).\n- Update |MiniSessions.detected|.\n\nParameters ~\n{session_name} `(string|nil)` Name of session file to write. Default: `nil` for\n  currently read session (|v:this_session|).\n{opts} `(table|nil)` Table with options. Current allowed keys:\n  - <force> (whether to ignore existence of session file; default:\n    `MiniSessions.config.force.write`).\n  - <verbose> (whether to print session path after action; default\n    `MiniSessions.config.verbose.write`).\n  - <hooks> (a table with <pre> and <post> function hooks to be executed\n    with session data argument before and after successful write; overrides\n    `MiniSessions.config.hooks.pre.write` and\n    `MiniSessions.config.hooks.post.write`).\n\n------------------------------------------------------------------------------\n                                                         *MiniSessions.delete()*\n                 `MiniSessions.delete`({session_name}, {opts})\nDelete detected session\n\nWhat it does:\n- Check if session name is a current one. If yes and `force` is not `true`,\n  then stop.\n- Delete session.\n- Update |MiniSessions.detected|.\n\nParameters ~\n{session_name} `(string|nil)` Name of detected session file to delete. Default:\n  `nil` for name of currently read session (taken from |v:this_session|).\n{opts} `(table|nil)` Table with options. Current allowed keys:\n  - <force> (whether to allow deletion of current session; default:\n    `MiniSessions.config.force.delete`).\n  - <verbose> (whether to print session path after action; default\n    `MiniSessions.config.verbose.delete`).\n  - <hooks> (a table with <pre> and <post> function hooks to be executed\n    with session data argument before and after successful delete; overrides\n    `MiniSessions.config.hooks.pre.delete` and\n    `MiniSessions.config.hooks.post.delete`).\n\n------------------------------------------------------------------------------\n                                                         *MiniSessions.select()*\n                    `MiniSessions.select`({action}, {opts})\nSelect session interactively and perform action\n\nNote: this uses |vim.ui.select()| function. For more user-friendly\nexperience, override it (for example, see |MiniPick.ui_select()|).\n\nParameters ~\n{action} `(string|nil)` Action to perform. Should be one of \"read\" (default),\n  \"write\", or \"delete\".\n{opts} `(table|nil)` Options for specified action.\n\n------------------------------------------------------------------------------\n                                                     *MiniSessions.get_latest()*\n                          `MiniSessions.get_latest`()\nGet name of latest detected session\n\nLatest session is the session with the latest modification time determined\nby |getftime()|.\n\nReturn ~\n`(string|nil)` Name of latest session or `nil` if there is no sessions.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-snippets.txt",
    "content": "*mini.snippets* Manage and expand snippets\n\nMIT License Copyright (c) 2024 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                  *MiniSnippets*\nSnippet is a template for a frequently used text. Typical workflow is to type\nsnippet's (configurable) prefix and expand it into a snippet session.\n\nThe template usually contains both pre-defined text and places (called\n\"tabstops\") for user to interactively change/add text during snippet session.\n\nThis module supports (only) snippet syntax defined in LSP specification (with\nsmall deviations). See |MiniSnippets-syntax-specification|.\n\nFeatures:\n- Manage snippet collection by adding it explicitly or with a flexible set of\n  performant built-in loaders. See |MiniSnippets.gen_loader|.\n\n- Configured snippets are efficiently resolved before every expand based on\n  current local context. This, for example, allows using different snippets\n  in different local tree-sitter languages (like in markdown code blocks).\n  See |MiniSnippets.default_prepare()|.\n\n- Match which snippet to insert based on the currently typed text.\n  Supports both exact and fuzzy matching. See |MiniSnippets.default_match()|.\n\n- Select from several matched snippets via `vim.ui.select()`.\n  See |MiniSnippets.default_select()|.\n\n- Start specialized in-process LSP server to show loaded snippets inside\n  (auto)completion engines (like |mini.completion|).\n  See |MiniSnippets.start_lsp_server()|.\n\n- Insert, jump, and edit during snippet session in a configurable manner:\n    - Configurable mappings for jumping and stopping.\n    - Jumping wraps around the tabstops for easier navigation.\n    - Easy to reason rules for when session automatically stops.\n    - Text synchronization of linked tabstops preserving relative indent.\n    - Dynamic tabstop state visualization (current/visited/unvisited, etc.)\n    - Inline visualization of empty tabstops (requires Neovim>=0.10).\n    - Works inside comments by preserving comment leader on new lines.\n    - Supports nested sessions (expand snippet while there is an active one).\n  See |MiniSnippets.default_insert()|.\n\n- Exported function to parse snippet body into easy-to-reason data structure.\n  See |MiniSnippets.parse()|.\n\nNotes:\n- It does not set up any snippet collection by default. Explicitly populate\n  `config.snippets` to have snippets to match from.\n- It does not come with a built-in snippet collection. It is expected from\n  users to add their own snippets, manually or with dedicated plugin(s).\n- It does not support variable/tabstop transformations in default snippet\n  session. This requires ECMAScript Regular Expression parser which can not\n  be implemented concisely.\n\nSources with more details:\n- |MiniSnippets-glossary|\n- |MiniSnippets-overview|\n- |MiniSnippets-examples|\n- |MiniSnippets-in-other-plugins| (for plugin authors)\n\n# Dependencies ~\n\nThis module doesn't come with snippet collection. Either create it manually\nor install a dedicated plugin. For example,\n[rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.snippets').setup({})` (replace `{}`\nwith your `config` table). It will create global Lua table `MiniSnippets` which\nyou can use for scripting or manually (with `:lua MiniSnippets.*`).\n\nSee |MiniSnippets.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minisnippets_config` which should have same structure as\n`MiniSnippets.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip):\n    - Both contain functionality to load snippets from file system.\n      This module provides several common loader generators while 'LuaSnip'\n      contains a more elaborate loading setup.\n      Also both require explicit opt-in for which snippets to load.\n    - Both support LSP snippet format. 'LuaSnip' also provides own more\n      elaborate snippet format which is out of scope for this module.\n    - 'LuaSnip' can autoexpand snippets, while this module always requires\n      an explicit user action to expand (by design).\n    - Both contain snippet expand functionality which differs in some aspects:\n        - 'LuaSnip' has an elaborate dynamic tabstop visualization config.\n          This module provides a handful of dedicated highlight groups.\n        - This module provides configurable visualization of empty tabstops.\n        - 'LusSnip' implements nested sessions by essentially merging them\n          into one. This module treats each nested session separately (to not\n          visually overload) while storing them in stack (first in last out).\n        - 'LuaSnip' uses |Select-mode| to power replacing current tabstop,\n          while this module always stays in |Insert-mode|. This enables easier\n          mapping understanding and more targeted highlighting.\n        - This module implements jumping which wraps after final tabstop\n          for more flexible navigation (enhanced with by a more flexible\n          autostopping rules), while 'LuaSnip' autostops session once\n          jumping reached the final tabstop.\n\n- Built-in |vim.snippet| (on Neovim>=0.10):\n    - Does not contain functionality to load or match snippets (by design),\n      while this module does.\n    - Both contain expand functionality based on LSP snippet format.\n      Differences in how snippet sessions are handled are similar to\n      comparison with 'LuaSnip'.\n\n- [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets):\n    - A snippet collection plugin without features to manage or expand them.\n      This module is designed with 'friendly-snippets' compatibility in mind.\n\n- [abeldekat/cmp-mini-snippets](https://github.com/abeldekat/cmp-mini-snippets):\n    - A source for [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n      that integrates 'mini.snippets'.\n\n# Highlight groups ~\n\n- `MiniSnippetsCurrent` - current tabstop.\n- `MiniSnippetsCurrentReplace` - current tabstop, placeholder is to be replaced.\n- `MiniSnippetsFinal` - special `$0` tabstop.\n- `MiniSnippetsUnvisited` - not yet visited tabstop(s).\n- `MiniSnippetsVisited` - visited tabstop(s).\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.minisnippets_disable` (globally) or\n`vim.b.minisnippets_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                         *MiniSnippets-glossary*\nPOSITION ~\nTable representing position in a buffer. Fields:\n- <line> `(number)` - line number (starts at 1).\n- <col> `(number)` - column number (starts at 1).\n\nREGION ~\nTable representing region in a buffer.\nFields: <from> and <to> for inclusive start/end POSITIONs.\n\nSNIPPET ~\nData about template to insert. Should contain fields:\n- <prefix> - string snippet identifier.\n- <body> - string snippet content with appropriate syntax.\n- <desc> - string snippet description in human readable form.\n\nCan also be used to mean snippet body if distinction is clear.\n\nSNIPPET SESSION ~\nInteractive state for user to adjust inserted snippet.\n\nMATCHED SNIPPET ~\nSnippet which contains <region> field with region that matched it.\nUsually region needs to be removed.\n\nSNIPPET NODE ~\nUnit of parsed snippet body. See |MiniSnippets.parse()|.\n\nTABSTOP ~\nDedicated places in snippet body for users to interactively adjust.\nSpecified in snippet body with `$` followed by digit(s).\n\nLINKED TABSTOPS ~\nDifferent nodes assigned the same tabstop. Updated in sync.\n\nREFERENCE NODE ~\nFirst (from left to right) node of linked tabstops. Used to determine\nsynced text and cursor placement after jump.\n\nEXPAND ~\nAction to start snippet session based on currently typed text.\nAlways done in current buffer at cursor. Executed steps:\n- `PREPARE` - resolve raw config snippets at context.\n- `MATCH` - match resolved snippets at cursor position.\n- `SELECT` - possibly choose among matched snippets.\n- `INSERT` - insert selected snippet and start snippet session.\n\n------------------------------------------------------------------------------\n                                                         *MiniSnippets-overview*\nSnippet is a template for a frequently used text. Typical workflow is to type\nsnippet's (configurable) prefix and expand it into a snippet session: add some\npre-defined text and allow user to interactively change/add at certain places.\n\nThis overview assumes default config for mappings and expand.\nSee |MiniSnippets.config| and |MiniSnippets-examples| for more details.\n\n# Snippet structure ~\n\nSnippet consists from three parts:\n- `Prefix` - identifier used to match against current text.\n- `Body` - actually inserted content with appropriate syntax.\n- `Desc` - description in human readable form.\n\nExample: `{ prefix = 'tis', body = 'This is snippet', desc = 'Snip' }`\nTyping `tis` and pressing \"expand\" mapping (<C-j> by default) will remove \"tis\",\nadd \"This is snippet\", and place cursor at the end in Insert mode.\n\n# Syntax ~\n*MiniSnippets-syntax-specification*\n\nInserting just text after typing smaller prefix is already powerful enough.\nFor more flexibility, snippet body can be formatted in a special way to\nprovide extra features. This module implements support for syntax defined\nin LSP specification (with small deviations). See this link for reference:\nhttps://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#snippet_syntax\n\nA quick overview of basic syntax features:\n\n- Tabstops are snippet parts meant for interactive editing at their location.\n  They are denoted as `$1`, `$2`, etc.\n  Navigating between them is called \"jumping\" and is done in numerical order\n  of tabstop identifiers by pressing special keys: <C-l> and <C-h> to jump\n  to next and previous tabstop respectively.\n  Special tabstop `$0` is called \"final tabstop\": it is used to decide when\n  snippet session is automatically stopped and is visited last during jumping.\n\n  Example: `T1=$1 T2=$2 T0=$0` is expanded as `T1= T2= T0=` with three tabstops.\n\n- Tabstop can have placeholder: a text used if tabstop is not yet edited.\n  Text is preserved if no editing is done. It follows this same syntax, which\n  means it can itself contain tabstops with placeholders (i.e. be nested).\n  Tabstop with placeholder is denoted as `${1:placeholder}` (`$1` is `${1:}`).\n\n  Example: `T1=${1:text} T2=${2:<$1>}` is expanded as `T1=text T2=<text>`;\n           typing `x` at first placeholder results in `T1=x T2=<x>`;\n           jumping once and typing `y` results in `T1=x T2=y`.\n\n- There can be several tabstops with same identifier. They are linked and\n  updated in sync during text editing. Can also have different placeholders;\n  they are forced to be the same as in the first (from left to right) tabstop.\n\n  Example: `T1=${1:text} T1=$1` is expanded as `T1=text T1=text`;\n           typing `x` at first placeholder results in `T1=x T1=x`.\n\n- Tabstop can also have choices: suggestions about tabstop text. It is denoted\n  as `${1|a,b,c|}`. First choice is used as placeholder.\n\n  Example: `T1=${1|left,right|}` is expanded as `T1=left`.\n\n- Variables can be used to automatically insert text without user interaction.\n  As tabstops, each one can have a placeholder which is used if variable is\n  not defined. There is a special set of variables describing editor state.\n\n  Example: `V1=$TM_FILENAME V2=${NOTDEFINED:placeholder}` is expanded as\n           `V1=current-file-basename V2=placeholder`.\n\nWhat's different from LSP specification:\n- Special set of variables is wider and is taken from VSCode specification:\n  https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables\n  Exceptions are `BLOCK_COMMENT_START` and `BLOCK_COMMENT_END` as Neovim doesn't\n  provide this information.\n- Variable `TM_SELECTED_TEXT` is resolved as contents of |quote_quote| register.\n  It assumes that text is put there prior to expanding. For example, visually\n  select, press |c|, type prefix, and expand.\n  See |MiniSnippets-examples| for how to adjust this.\n- Environment variables are recognized and supported: `V1=$VIMRUNTIME` will\n  use an actual value of |$VIMRUNTIME|.\n- Variable transformations are not supported during snippet session. It would\n  require interacting with ECMAScript-like regular expressions for which there\n  is no easy way in Neovim. It may change in the future.\n  Transformations are recognized during parsing, though, with some exceptions:\n    - The `}` inside `if` of `${1:?if:else}` needs escaping (for technical reasons).\n\nThere is a |MiniSnippets.parse()| function for programmatically parsing\nsnippet body into a comprehensible data structure.\n\n# Expand ~\n\nUsing snippets is done via what is called \"expanding\". It goes like this:\n- Type snippet prefix or its recognizable part.\n- Press <C-j> to expand. It will perform the following steps:\n    - Prepare available snippets in current context (buffer + local language).\n      This allows snippet setup to have general function loaders which return\n      different snippets in different contexts.\n    - Match text to the left of cursor with available prefixes. It first tries\n      to do exact match and falls back to fuzzy matching.\n    - If there are several matches, use `vim.ui.select()` to choose one.\n    - Insert single matching snippet. If snippet contains tabstops, start\n      snippet session.\n\nFor more details about each step see:\n- |MiniSnippets.default_prepare()|\n- |MiniSnippets.default_match()|\n- |MiniSnippets.default_select()|\n- |MiniSnippets.default_insert()|\n\nSnippet session allows interactive editing at tabstop locations:\n\n- All tabstop locations are visualized depending on tabstop \"state\" (whether\n  it is current/visited/unvisited/final and whether it was already edited).\n  Empty tabstops are visualized with inline virtual text (\"•\"/\"∎\" for\n  regular/final tabstops). It is removed after session is stopped.\n\n- Start session at first tabstop. Type text to replace placeholder.\n  When finished with current tabstop, jump to next with <C-l>. Repeat.\n  If changed mind about some previous tabstop, jump back with <C-h>.\n  Jumping also wraps around the edge (first tabstop is next after final).\n\n- If tabstop has choices, use <C-n> / <C-p> to select next / previous item.\n\n- Starting another snippet session while there is an active one is allowed.\n  This creates nested sessions: suspend current, start the new one.\n  After newly created is stopped, resume the suspended one.\n\n- Stop session manually by pressing <C-c> or make it stop automatically:\n  if final tabstop is current either make a text edit or exit to Normal mode.\n  If snippet doesn't explicitly define final tabstop, it is added at the end\n  of the snippet.\n\nFor more details about snippet session see |MiniSnippets-session|.\n\nTo select and insert snippets via completion engine (that supports LSP\ncompletion; like |mini.completion| or |lsp-autocompletion|),\ncall |MiniSnippets.start_lsp_server()| after |MiniSnippets.setup()|. This sets up\nan LSP server that matches and provides snippets loaded with 'mini.snippets'.\nTo match with completion engine, use `start_lsp_server({ match = false })`.\n\n# Management ~\n\nOut of the box 'mini.snippets' doesn't load any snippets, it should be done\nexplicitly inside |MiniSnippets.setup()| following |MiniSnippets.config|.\n\nThe suggested approach to snippet management is to create dedicated files with\nsnippet data and load them through function loaders in `config.snippets`.\nSee |MiniSnippets-examples| for basic (yet capable) snippet management config.\n\n## File specification ~\n*MiniSnippets-file-specification*\n\nGeneral idea of supported files is to have at least out of the box experience\nwith common snippet collections. Namely \"rafamadriz/friendly-snippets\".\nThe following files are supported:\n\n- Extensions:\n    - Read/decoded as JSON object (|vim.json.decode()|): `*.json`, `*.code-snippets`\n    - Executed as Lua file (|dofile()|) and uses returned value: `*.lua`\n\n- Content:\n    - Dict-like: object in JSON; returned table in Lua; no order guarantees.\n    - Array-like: array in JSON; returned array table in Lua; preserves order.\n\nExample of file content with a single snippet:\n- Lua dict-like:   `return { name = { prefix = 't', body = 'Text' } }`\n- Lua array-like:  `return { { prefix = 't', body = 'Text', desc = 'name' } }`\n- JSON dict-like:  `{ \"name\": { \"prefix\": \"t\", \"body\": \"Text\" } }`\n- JSON array-like: `[ { \"prefix\": \"t\", \"body\": \"Text\", \"desc\": \"name\" } ]`\n\nNotes:\n- There is no built-in support for VSCode-like \"package.json\" files. Define\n  structure manually in |MiniSnippets.setup()| via built-in or custom loaders.\n- There is no built-in support for `scope` field of snippet data. Snippets are\n  expected to be manually separated into smaller files and loaded on demand.\n\nFor supported snippet syntax see |MiniSnippets-syntax-specification|.\n\n## General advice ~\n\n- Put files in \"snippets\" subdirectory of any path in 'runtimepath' (like\n  '`$XDG_CONFIG_HOME`/nvim/snippets/global.json').\n  This is compatible with |MiniSnippets.gen_loader.from_runtime()| and\n  example from |MiniSnippets-examples|.\n- Prefer `*.json` files with dict-like content if you want more cross platfrom\n  setup. Otherwise use `*.lua` files with array-like content.\n- To implement \"dynamic snippet\" that changes data (usually <body>) depending\n  on the context, use `*.lua` file with function returning snippet data.\n  It should be an element in the output table (dict or array like).\n\n# Demo ~\n\nThe best way to grasp the design of snippet management and expansion is to\ntry them out yourself. Here are steps for a basic demo:\n- Create 'snippets/global.json' file in the config directory with the content: >json\n\n  {\n    \"Basic\":        { \"prefix\": \"ba\", \"body\": \"T1=$1 T2=$2 T0=$0\"         },\n    \"Placeholders\": { \"prefix\": \"pl\", \"body\": \"T1=${1:aa}\\nT2=${2:<$1>}\"  },\n    \"Choices\":      { \"prefix\": \"ch\", \"body\": \"T1=${1|a,b|} T2=${2|c,d|}\" },\n    \"Linked\":       { \"prefix\": \"li\", \"body\": \"T1=$1\\n\\tT1=$1\"            },\n    \"Variables\":    { \"prefix\": \"va\", \"body\": \"Runtime: $VIMRUNTIME\\n\"    },\n    \"Complex\":      {\n      \"prefix\": \"co\",\n      \"body\": [ \"T1=${1:$RANDOM}\", \"T3=${3:$1_${2:$1}}\", \"T2=$2\" ]\n    }\n  }\n<\n- Set up 'mini.snippets' as recommended in |MiniSnippets-examples|.\n- Open Neovim. Type each snippet prefix and press <C-j> (even if there is\n  still active session). Explore from there.\n\n------------------------------------------------------------------------------\n                                                         *MiniSnippets-examples*\n# Basic snippet management config ~\n\nExample of snippet management setup that should cover most cases: >lua\n\n  -- Setup\n  local gen_loader = require('mini.snippets').gen_loader\n  require('mini.snippets').setup({\n    snippets = {\n      -- Load custom file with global snippets first\n      gen_loader.from_file('~/.config/nvim/snippets/global.json'),\n\n      -- Load snippets based on current language by reading files from\n      -- \"snippets/\" subdirectories from 'runtimepath' directories.\n      gen_loader.from_lang(),\n    },\n  })\n<\nThis setup allows having single file with custom \"global\" snippets (will be\npresent in every buffer) and snippets which will be loaded based on the local\nlanguage (see |MiniSnippets.gen_loader.from_lang()|).\n\nCreate language snippets manually (by creating and populating\n'`$XDG_CONFIG_HOME`/nvim/snippets/lua.json' file) or by installing dedicated\nsnippet collection plugin (like 'rafamadriz/friendly-snippets').\n\nNote: all built-in loaders and |MiniSnippets.read_file()| cache their output\nby default. It means that after a file is first read, changing it won't have\neffect during current Neovim session. See |MiniSnippets.gen_loader| about how\nto reset cache if necessary.\n\n# Select from all available snippets in current context ~\n\nWith |MiniSnippets.default_match()|, expand snippets (<C-j> by default) at line\nstart or after whitespace. To be able to always select from all current\ncontext snippets, make mapping similar to the following: >lua\n\n  local rhs = function() MiniSnippets.expand({ match = false }) end\n  vim.keymap.set('i', '<C-g><C-j>', rhs, { desc = 'Expand all' })\n<\n# \"Supertab\"-like <Tab> / <S-Tab> mappings ~\n\nThis module intentionally by default uses separate keys to expand and jump as\nit enables cleaner use of nested sessions. Here is an example of setting up\ncustom <Tab> to \"expand or jump\" and <S-Tab> to \"jump to previous\": >lua\n\n  local snippets = require('mini.snippets')\n  local match_strict = function(snips)\n    -- Do not match with whitespace to cursor's left\n    return snippets.default_match(snips, { pattern_fuzzy = '%S+' })\n  end\n  snippets.setup({\n    -- ... Set up snippets ...\n    mappings = { expand = '', jump_next = '', jump_prev = '' },\n    expand   = { match = match_strict },\n  })\n  local expand_or_jump = function()\n    local can_expand = #MiniSnippets.expand({ insert = false }) > 0\n    if can_expand then vim.schedule(MiniSnippets.expand); return '' end\n    local is_active = MiniSnippets.session.get() ~= nil\n    if is_active then MiniSnippets.session.jump('next'); return '' end\n    return '\\t'\n  end\n  local jump_prev = function() MiniSnippets.session.jump('prev') end\n  vim.keymap.set('i', '<Tab>', expand_or_jump, { expr = true })\n  vim.keymap.set('i', '<S-Tab>', jump_prev)\n<\n# Stop session immediately after jumping to final tabstop ~\n\nUtilize a dedicated |MiniSnippets-events|: >lua\n\n  local fin_stop = function(args)\n    if args.data.tabstop_to == '0' then MiniSnippets.session.stop() end\n  end\n  local au_opts = { pattern = 'MiniSnippetsSessionJump', callback = fin_stop }\n  vim.api.nvim_create_autocmd('User', au_opts)\n<\n# Stop all sessions on Normal mode exit ~\n\nUse |ModeChanged| and |MiniSnippets-events| events: >lua\n\n  local make_stop = function()\n    local au_opts = { pattern = '*:n', once = true }\n    au_opts.callback = function()\n      while MiniSnippets.session.get() do\n        MiniSnippets.session.stop()\n      end\n    end\n    vim.api.nvim_create_autocmd('ModeChanged', au_opts)\n  end\n  local opts = { pattern = 'MiniSnippetsSessionStart', callback = make_stop }\n  vim.api.nvim_create_autocmd('User', opts)\n<\n# Customize variable evaluation ~\n\nCreate environment variables and `config.expand.insert` wrapper: >lua\n\n  -- Use evnironment variables with value is same for all snippet sessions\n  vim.loop.os_setenv('USERNAME', 'user')\n\n  -- Compute custom lookup for variables with dynamic values\n  local insert_with_lookup = function(snippet)\n    local lookup = {\n      TM_SELECTED_TEXT = table.concat(vim.fn.getreg('a', true, true), '\\n'),\n    }\n    return MiniSnippets.default_insert(snippet, { lookup = lookup })\n  end\n\n  require('mini.snippets').setup({\n    -- ... Set up snippets ...\n    expand = { insert = insert_with_lookup },\n  })\n<\n# Using Neovim's built-ins to insert snippet ~\n\nDefine custom `expand.insert` in |MiniSnippets.config| and mappings: >lua\n\n  require('mini.snippets').setup({\n    -- ... Set up snippets ...\n    expand = {\n      insert = function(snippet, _) vim.snippet.expand(snippet.body) end\n    }\n  })\n  -- Make jump mappings or skip to use built-in <Tab>/<S-Tab> in Neovim>=0.11\n  local jump_next = function()\n    if vim.snippet.active({direction = 1}) then return vim.snippet.jump(1) end\n  end\n  local jump_prev = function()\n    if vim.snippet.active({direction = -1}) then vim.snippet.jump(-1) end\n  end\n  vim.keymap.set({ 'i', 's' }, '<C-l>', jump_next)\n  vim.keymap.set({ 'i', 's' }, '<C-h>', jump_prev)\n<\n# Using 'mini.snippets' in other plugins ~\n*MiniSnippets-in-other-plugins*\n\n- Perform a `_G.MiniSnippets ~= nil` check before using any feature. This\n  ensures that user explicitly set up 'mini.snippets'.\n\n- To insert snippet given its body (like |vim.snippet.expand()|), use: >lua\n\n     -- Use configured `insert` method with falling back to default\n     local insert = MiniSnippets.config.expand.insert\n       or MiniSnippets.default_insert\n     -- Insert at cursor\n     insert({ body = snippet })\n<\n- To get available snippets, use: >lua\n\n  -- Get snippets matched at cursor\n  MiniSnippets.expand({ insert = false })\n\n  -- Get all snippets available at cursor context\n  MiniSnippets.expand({ match = false, insert = false })\n<\n------------------------------------------------------------------------------\n                                                          *MiniSnippets.setup()*\n                         `MiniSnippets.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniSnippets.config|.\n\nUsage ~\n>lua\n  require('mini.snippets').setup({}) -- replace {} with your config table\n                                     -- needs `snippets` field present\n<\n------------------------------------------------------------------------------\n                                                           *MiniSnippets.config*\n                             `MiniSnippets.config`\nDefaults ~\n>lua\n  MiniSnippets.config = {\n    -- Array of snippets and loaders (see |MiniSnippets.config| for details).\n    -- Nothing is defined by default. Add manually to have snippets to match.\n    snippets = {},\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      -- Expand snippet at cursor position. Created globally in Insert mode.\n      expand = '<C-j>',\n\n      -- Interact with default `expand.insert` session.\n      -- Created for the duration of active session(s)\n      jump_next = '<C-l>',\n      jump_prev = '<C-h>',\n      stop = '<C-c>',\n    },\n\n    -- Functions describing snippet expansion. If `nil`, default values\n    -- are `MiniSnippets.default_<field>()`.\n    expand = {\n      -- Resolve raw config snippets at context\n      prepare = nil,\n      -- Match resolved snippets at cursor position\n      match = nil,\n      -- Possibly choose among matched snippets\n      select = nil,\n      -- Insert selected snippet\n      insert = nil,\n    },\n  }\n<\n# Loaded snippets ~\n\n`config.snippets` is an array containing snippet data which can be: snippet\ntable, function loader, or (however deeply nested) array of snippet data.\n\nSnippet is a table with the following fields:\n\n- <prefix> `(string|table|nil)` - string used to match against current text.\n   If array, all strings should be used as separate prefixes.\n- <body> `(string|table|nil)` - content of a snippet which should follow\n   the |MiniSnippets-syntax-specification|. Array is concatenated with `\"\\n\"`.\n- <desc> `(string|table|nil)` - description of snippet. Can be used to display\n  snippets in a more human readable form. Array is concatenated with `\"\\n\"`.\n\nFunction loaders are expected to be called with single `context` table argument\n(containing any data about current context) and return same as `config.snippets`\ndata structure.\n\n`config.snippets` is resolved with `config.prepare` on every expand.\nSee |MiniSnippets.default_prepare()| for how it is done by default.\n\nFor a practical example see |MiniSnippets-examples|.\nHere is an illustration of `config.snippets` customization capabilities: >lua\n\n  local gen_loader = require('mini.snippets').gen_loader\n  require('mini.snippets').setup({\n    snippets = {\n      -- Load custom file with global snippets first (order matters)\n      gen_loader.from_file('~/.config/nvim/snippets/global.json'),\n\n      -- Or add them here explicitly\n      { prefix='cdate', body='$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE' },\n\n      -- Load snippets based on current language by reading files from\n      -- \"snippets/\" subdirectories from 'runtimepath' directories.\n      gen_loader.from_lang(),\n\n      -- Load project-local snippets with `gen_loader.from_file()`\n      -- and relative path (file doesn't have to be present)\n      gen_loader.from_file('.vscode/project.code-snippets'),\n\n      -- Custom loader for language-specific project-local snippets\n      function(context)\n        local rel_path = '.vscode/' .. context.lang .. '.code-snippets'\n        if vim.fn.filereadable(rel_path) == 0 then return end\n        return MiniSnippets.read_file(rel_path)\n      end,\n\n      -- Ensure that some prefixes are not used (as there is no `body`)\n      { prefix = { 'bad', 'prefix' } },\n    }\n  })\n<\n# Mappings ~\n\n`config.mappings` describes which mappings are automatically created.\n\n`mappings.expand` is created globally in Insert mode and is used to expand\nsnippet at cursor. Use |MiniSnippets.expand()| for custom mappings.\n\n`mappings.jump_next`, `mappings.jump_prev`, and `mappings.stop` are created for\nthe duration of active snippet session(s) from |MiniSnippets.default_insert()|.\nUsed to jump to next/previous tabstop and stop active session respectively.\nUse |MiniSnippets.session.jump()| and |MiniSnippets.session.stop()| for custom\nInsert mode mappings.\nNote: do not use `\"<C-n>\"` or `\"<C-p>\"` for any action as they conflict with\nbuilt-in completion: it forces them to mean \"change focus to next/previous\ncompletion item\". This matters more frequently than when there is a tabstop\nwith choices due to how this module handles built-in completion during jumps.\n\n# Expand ~\n\n`config.expand` defines expand steps (see |MiniSnippets-glossary|), either after\npressing `mappings.expand` or starting manually via |MiniSnippets.expand()|.\n\n`expand.prepare` is a function that takes `raw_snippets` in the form of\n`config.snippets` and should return a plain array of snippets (as described\nin |MiniSnippets-glossary|). Will be called on every |MiniSnippets.expand()| call.\nIf returns second value, it will be used as context for warning messages.\nDefault: |MiniSnippets.default_prepare()|.\n\n`expand.match` is a function that takes `expand.prepare` output and returns\nan array of matched snippets: one or several snippets user might intend to\neventually insert. Should sort matches in output from best to worst.\nEntries can contain `region` field with current buffer region used to do\nthe match; usually it needs to be removed (similar to how |ins-completion|\nand |abbreviations| work).\nDefault: |MiniSnippets.default_match()|\n\n`expand.select` is a function that takes output of `expand.match` and function\nthat inserts snippet (and also ensures Insert mode and removes snippet's match\nregion). Should allow user to perform interactive snippet selection and\ninsert the chosen one. Designed to be compatible with |vim.ui.select()|.\nCalled for any non-empty `expand.match` output (even with single entry).\nDefault: |MiniSnippets.default_select()|\n\n`expand.insert` is a function that takes single snippet table as input and\ninserts snippet at cursor position. This is a main entry point for adding\ntext template to buffer and starting a snippet session.\nIf called inside |MiniSnippets.expand()| (which is a usual interactive case),\nall it has to do is insert snippet at cursor position. Ensuring Insert mode\nand removing matched snippet region is done beforehand.\nDefault: |MiniSnippets.default_insert()|\n\nIllustration of `config.expand` customization: >lua\n\n  -- Supply extra data as context\n  local my_p = function(raw_snippets)\n    local _, cont = MiniSnippets.default_prepare({})\n    cont.cursor = vim.api.nvim_win_get_cursor()\n    return MiniSnippets.default_prepare(raw_snippets, { context = cont })\n  end\n  -- Perform fuzzy match based only on alphanumeric characters\n  local my_m = function(snippets)\n    return MiniSnippets.default_match(snippets, { pattern_fuzzy = '%w*' })\n  end\n  -- Always insert the best matched snippet\n  local my_s = function(snippets, insert) return insert(snippets[1]) end\n  -- Use different string to show empty tabstop as inline virtual text\n  local my_i = function(snippet)\n    return MiniSnippets.default_insert(snippet, { empty_tabstop = '$' })\n  end\n\n  require('mini.snippets').setup({\n    -- ... Set up snippets ...\n    expand = { prepare = my_p, match = my_m, select = my_s, insert = my_i }\n  })\n<\n------------------------------------------------------------------------------\n                                                         *MiniSnippets.expand()*\n                         `MiniSnippets.expand`({opts})\nExpand snippet at cursor position\n\nPerform expand steps (see |MiniSnippets-glossary|).\nInitial raw snippets are taken from `config.snippets` in current buffer.\nSnippets from `vim.b.minisnippets_config` are appended to global snippet array.\n\nParameters ~\n{opts} `(table|nil)` Options. Same structure as `expand` in |MiniSnippets.config|\n  and uses its values as default. There are differences in allowed values:\n  - Use `match = false` to have all buffer snippets as matches.\n  - Use `select = false` to always expand the best match (if any).\n  - Use `insert = false` to return all matches without inserting.\n\n  Note: `opts.insert` is called after ensuring Insert mode, removing snippet's\n  match region, and positioning cursor.\n\nReturn ~\n`(table|nil)` If `insert` is `false`, an array of matched snippets (`expand.match`\n  output). Otherwise `nil`.\n\nUsage ~\n>lua\n  -- Match, maybe select, and insert\n  MiniSnippets.expand()\n\n  -- Match and force expand the best match (if any)\n  MiniSnippets.expand({ select = false })\n\n  -- Use all current context snippets as matches\n  MiniSnippets.expand({ match = false })\n\n  -- Get all matched snippets\n  local matches = MiniSnippets.expand({ insert = false })\n\n  -- Get all current context snippets\n  local all = MiniSnippets.expand({ match = false, insert = false })\n<\n\nSee also ~\n|MiniSnippets.start_lsp_server()| to instead show loaded snippets\n  in (auto)completion engines (like |mini.completion|).\n\n------------------------------------------------------------------------------\n                                                       *MiniSnippets.gen_loader*\n                           `MiniSnippets.gen_loader`\nGenerate snippet loader\n\nThis is a table with function elements. Call to actually get a loader.\n\nCommon features for all produced loaders:\n- Designed to work with |MiniSnippets-file-specification|.\n- Cache output by default, i.e. second and later calls with same input value\n  don't read file system. Different loaders from same generator share cache.\n  Disable by setting `opts.cache` to `false`.\n  To clear all cache, call |MiniSnippets.setup()|. For example:\n  `MiniSnippets.setup(MiniSnippets.config)`\n- Use |vim.notify()| to show problems during loading while trying to load as\n  much correctly defined snippet data as possible.\n  Disable by setting `opts.silent` to `true`.\n\n------------------------------------------------------------------------------\n                                           *MiniSnippets.gen_loader.from_lang()*\n                  `MiniSnippets.gen_loader.from_lang`({opts})\nGenerate language loader\n\nOutput loads files from \"snippets/\" subdirectories of 'runtimepath' matching\nconfigured language patterns.\nSee |MiniSnippets.gen_loader.from_runtime()| for runtime loading details.\n\nLanguage is taken from <lang> field (if present with string value) of `context`\nargument used in loader calls during \"prepare\" stage.\nThis is compatible with |MiniSnippets.default_prepare()| and most snippet\ncollection plugins.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible values:\n  - <lang_patterns> `(table)` - map from language to array of runtime patterns\n    used to find snippet files, as in |MiniSnippets.gen_loader.from_runtime()|.\n    Patterns will be processed in order. With |MiniSnippets.default_prepare()|\n    it means if snippets have same prefix, data from later patterns is used.\n    To interactively check the current language with default context, execute\n    `:=MiniSnippets.default_prepare({})` and see data in the second table.\n\n    Default pattern array (for non-empty language) is constructed as to read\n    `*.json` and `*.lua` files that are:\n    - Inside \"snippets/\" subdirectory named as language (files can be however\n      deeply nested).\n    - Named as language and is in \"snippets/\" directory (however deep).\n    Example for \"lua\" language: >lua\n        { 'lua/**/*.json', 'lua/**/*.lua', '**/lua.json', '**/lua.lua' }\n<\n    Add entry for `\"\"` (empty string) as language to be sourced when `lang`\n    context is empty string (which is usually temporary scratch buffers).\n\n  - <cache> `(boolean)` - whether to use cached output. Default: `true`.\n    Note: caching is done per used runtime pattern, not `lang` value to allow\n    different `from_lang()` loaders to share cache.\n  - <silent> `(boolean)` - whether to hide non-error messages. Default: `false`.\n\nReturn ~\n`(function)` Snippet loader.\n\nUsage ~\n>lua\n  -- Adjust language patterns\n  local latex_patterns = { 'latex/**/*.json', '**/latex.json' }\n  local lang_patterns = {\n    tex = latex_patterns, plaintex = latex_patterns,\n    -- Recognize special injected language of markdown tree-sitter parser\n    markdown_inline = { 'markdown.json' },\n  }\n  local gen_loader = require('mini.snippets').gen_loader\n  require('mini.snippets').setup({\n    snippets = {\n      gen_loader.from_lang({ lang_patterns = lang_patterns }),\n    },\n  })\n<\n------------------------------------------------------------------------------\n                                        *MiniSnippets.gen_loader.from_runtime()*\n           `MiniSnippets.gen_loader.from_runtime`({pattern}, {opts})\nGenerate runtime loader\n\nOutput loads files which match `pattern` inside \"snippets/\" directories from\n'runtimepath'. This is useful to simultaneously read several similarly\nnamed files from different sources. Order from 'runtimepath' is preserved.\n\nTypical case is loading snippets for a language from files like `xxx.{json,lua}`\nbut located in different \"snippets/\" directories inside 'runtimepath'.\n- `<config>`/snippets/lua.json - manually curated snippets in user config.\n- `<path/to/installed/plugin>`/snippets/lua.json - from installed plugin.\n- `<config>`/after/snippets/lua.json - used to adjust snippets from plugins.\n  For example, remove some snippets by using prefixes and no body.\n\nParameters ~\n{pattern} `(string)` Pattern of files to read. Can have wildcards as described\n  in |nvim_get_runtime_file()|. Example for \"lua\" language: `'lua.{json,lua}'`.\n{opts} `(table|nil)` Options. Possible fields:\n  - <all> `(boolean)` - whether to load from all matching runtime files.\n    Default: `true`.\n  - <cache> `(boolean)` - whether to use cached output. Default: `true`.\n    Note: caching is done per `pattern` value, which assumes that both\n    'runtimepath' value and snippet files do not change during Neovim session.\n    Caching this way gives significant speed improvement by reducing the need\n    to traverse file system on every snippet expand.\n  - <silent> `(boolean)` - whether to hide non-error messages. Default: `false`.\n\nReturn ~\n`(function)` Snippet loader.\n\n------------------------------------------------------------------------------\n                                           *MiniSnippets.gen_loader.from_file()*\n              `MiniSnippets.gen_loader.from_file`({path}, {opts})\nGenerate single file loader\n\nOutput is a thin wrapper around |MiniSnippets.read_file()| which will skip\nwarning if file is absent (other messages are still shown). Use it to load\nfile which is not guaranteed to exist (like project-local snippets).\n\nParameters ~\n{path} `(string)` Same as in |MiniSnippets.read_file()|.\n{opts} `(table|nil)` Same as in |MiniSnippets.read_file()|.\n\nReturn ~\n`(function)` Snippet loader.\n\n------------------------------------------------------------------------------\n                                                      *MiniSnippets.read_file()*\n                    `MiniSnippets.read_file`({path}, {opts})\nRead file with snippet data\n\nParameters ~\n{path} `(string)` Path to file with snippets. Can be relative.\n  See |MiniSnippets-file-specification| for supported file formats.\n{opts} `(table|nil)` Options. Possible fields:\n  - <cache> `(boolean)` - whether to use cached output. Default: `true`.\n    Note: Caching is done per full path only after successful reading.\n  - <silent> `(boolean)` - whether to hide non-error messages. Default: `false`.\n\nReturn ~\n`(table|nil)` Array of snippets or `nil` if failed (also warn with |vim.notify()|\n  about the reason).\n\n------------------------------------------------------------------------------\n                                                *MiniSnippets.default_prepare()*\n             `MiniSnippets.default_prepare`({raw_snippets}, {opts})\nDefault prepare\n\nNormalize raw snippets (as in `snippets` from |MiniSnippets.config|) based on\nsupplied context:\n- Traverse and flatten nested arrays. Function loaders are executed with\n  `opts.context` as argument and output is processed recursively.\n- Ensure unique non-empty prefixes: later ones completely override earlier\n  ones (similar to how |ftplugin| and similar runtime design behave).\n  Empty string prefixes are all added (to allow inserting without matching).\n- Transform and infer fields:\n    - Multiply array `prefix` into several snippets with same body/description.\n      Infer absent `prefix` as empty string.\n    - Concatenate array `body` with `\"\\n\"`. Do not infer absent `body` to have\n      it remove previously added snippet with the same prefix.\n    - Concatenate array `desc` with `\"\\n\"`. Infer `desc` field from `description`\n      (for compatibility) or `body` fields, in that order.\n- Sort output by prefix.\n\nUnlike |MiniSnippets.gen_loader| entries, there is no output caching. This\navoids duplicating data from `gen_loader` cache and reduces memory usage.\nIt also means that every |MiniSnippets.expand()| call prepares snippets, which\nis usually fast enough. If not, consider manual caching: >lua\n\n  local cache = {}\n  local prepare_cached = function(raw_snippets)\n    local _, cont = MiniSnippets.default_prepare({})\n    local id = 'buf=' .. cont.buf_id .. ',lang=' .. cont.lang\n    if cache[id] then return unpack(vim.deepcopy(cache[id])) end\n    local snippets = MiniSnippets.default_prepare(raw_snippets)\n    cache[id] = vim.deepcopy({ snippets, cont })\n    return snippets, cont\n  end\n<\nParameters ~\n{raw_snippets} `(table)` Array of snippet data as from |MiniSnippets.config|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <context> `(any)` - Context used as an argument for callable snippet data.\n    Default: table with <buf_id> (current buffer identifier) and <lang> (local\n    language) fields. Language is computed from tree-sitter parser at cursor\n    (allows different snippets in injected languages), 'filetype' otherwise.\n\nReturn ~\n`(...)` Array of snippets and supplied context (default if none was supplied).\n\n------------------------------------------------------------------------------\n                                                  *MiniSnippets.default_match()*\n                `MiniSnippets.default_match`({snippets}, {opts})\nDefault match\n\nMatch snippets based on the line before cursor.\n\nTries two matching approaches consecutively:\n- Find exact snippet prefix (if present and non-empty) to the left of cursor.\n  It should also be preceded with a byte that matches `pattern_exact_boundary`.\n  In case of any match, return the one with the longest prefix.\n- Match fuzzily snippet prefixes against the base (text to the left of cursor\n  extracted via `opts.pattern_fuzzy`). Matching is done via |matchfuzzy()|.\n  Empty base results in all snippets being matched. Return all fuzzy matches.\n\nParameters ~\n{snippets} `(table)` Array of snippets which can be matched.\n{opts} `(table|nil)` Options. Possible fields:\n  - <pattern_exact_boundary> `(string)` - Lua pattern for the byte to the left\n    of exact match to accept it. Line start is matched against empty string;\n    use `?` quantifier to allow it as boundary.\n    Default: `[%s%p]?` (accept only whitespace and punctuation as boundary,\n    allow match at line start).\n    Example: prefix \"l\" matches in lines `l`, `_l`, `x l`; but not `1l`, `ll`.\n  - <pattern_fuzzy> `(string)` - Lua pattern to extract base to the left of\n    cursor for fuzzy matching. Supply empty string to skip this step.\n    Default: `'%S*'` (as many as possible non-whitespace; allow empty string).\n\nReturn ~\n`(table)` Array of matched snippets ordered from best to worst match.\n\nUsage ~\n>lua\n  -- Accept any exact match\n  MiniSnippets.default_match(snippets, { pattern_exact_boundary = '.?' })\n\n  -- Perform fuzzy match based only on alphanumeric characters\n  MiniSnippets.default_match(snippets, { pattern_fuzzy = '%w*' })\n<\n------------------------------------------------------------------------------\n                                                 *MiniSnippets.default_select()*\n          `MiniSnippets.default_select`({snippets}, {insert}, {opts})\nDefault select\n\nShow snippets as |vim.ui.select()| items and insert the chosen one.\nFor best interactive experience requires `vim.ui.select()` to work from Insert\nmode (be properly called and restore Insert mode after choice).\nThis is the case for at least |MiniPick.ui_select()| and Neovim's default.\n\nParameters ~\n{snippets} `(table)` Array of snippets (as an output of `config.expand.match`).\n{insert} `(function|nil)` Function to insert chosen snippet (passed as the only\n  argument). Expected to remove snippet's match region (if present as a field)\n  and ensure proper cursor position in Insert mode.\n  Default: |MiniSnippets.default_insert()|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <insert_single> `(boolean)` - whether to skip |vim.ui.select()| for `snippets`\n    with a single entry and insert it directly. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                 *MiniSnippets.default_insert()*\n                `MiniSnippets.default_insert`({snippet}, {opts})\nDefault insert\n\nPrepare for snippet insert and do it:\n- Ensure Insert mode.\n- Delete snippet's match region (if present as <region> field). Ensure cursor.\n- Parse snippet body with |MiniSnippets.parse()| and enabled `normalize`.\n  In particular, evaluate variables, ensure final node presence and same\n  text for nodes with same tabstops. Stop if not able to.\n- Insert snippet at cursor:\n    - Add snippet's text. Lines are split at \"\\n\".\n      Indent and left comment leaders (inferred from 'commentstring' and\n      'comments') of current line are repeated on the next.\n      Tabs (\"\\t\") are expanded according to 'expandtab' and 'shiftwidth'.\n    - If there is an actionable tabstop (not final), start snippet session.\n\n# Session life cycle ~\n*MiniSnippets-session*\n\n- Start with cursor at first tabstop. If there are linked tabstops, cursor\n  is placed at start of reference node (see |MiniSnippets-glossary|).\n  All tabstops are visualized with dedicated highlight groups (see \"Highlight\n  groups\" section in |mini.snippets|).\n  Empty tabstops are visualized with inline virtual text (\"•\"/\"∎\" for\n  regular/final tabstops) meaning that it is not an actual text in the\n  buffer and will be removed after session is stopped.\n\n- Decide whether you want to replace the placeholder. If not, jump to next or\n  previous tabstop. If yes, edit it: add new and/or delete already added text.\n  While doing so, several things happen in all linked tabstops (if any):\n\n    - After first typed character the placeholder is removed and highlighting\n      changes from `MiniSnippetsCurrentReplace` to `MiniSnippetsCurrent`.\n    - Text in all tabstop nodes is synchronized with the reference one.\n      Relative indent of reference tabstop's text is preserved: all but first\n      lines in linked tabstops are reindented based on the first line indent.\n      Note: text sync is forced only for current tabstop (for performance).\n\n- Jump with <C-l> / <C-h> to next / previous tabstop. Exact keys can be\n  adjusted in |MiniSnippets.config| `mappings`.\n  See |MiniSnippets.session.jump()| for jumping details.\n\n- If tabstop has choices, all of them are shown after each jump and deleting\n  tabstop text. It is done with |complete()|, so use <C-n> / <C-p> to select\n  next / previous choice. Type text to narrow down the list.\n  Works best when 'completeopt' option contains `menuone` and `noselect` flags.\n  Note: deleting character hides the list due to how |complete()| works;\n  delete whole tabstop text (for example with one or more |i_CTRL-W|) for\n  full list to reappear.\n\n- Nest another session by expanding snippet in the same way as without\n  active session (can be even done in another buffer). If snippet has no\n  actionable tabstop, text is just inserted. Otherwise start nested session:\n\n    - Suspend current session: hide highlights, keep text change tracking.\n    - Start new session and act as if it is the only one (edit/jump/nest).\n    - When ready (possibly after even more nested sessions), stop the session.\n      This will resume previous one: sync text for its current tabstop and\n      show highlighting.\n      The experience of text synchronization only after resuming session is\n      similar to how editing in |visual-block| mode works.\n      Nothing else (like cursor/mode/buffer) is changed for a smoother\n      automated session stop.\n\n  Notes about the choice of the \"session stack\" approach to nesting over more\n  common \"merge into single session\" approach:\n  - Does not overload with highlighting.\n  - Allows nested sessions in different buffers.\n  - Doesn't need a complex logic of injecting one session into another.\n\n- Repeat edit/jump/nest steps any number of times.\n\n- Stop. It can be done in two ways:\n\n    - Manually by pressing <C-c> or calling |MiniSnippets.session.stop()|.\n      Exact key can be adjusted in |MiniSnippets.config| `mappings`.\n    - Automatically: any text edit or switching to Normal mode stops session\n      if final tabstop (`$0`) is current. Its presence is ensured after insert.\n      Not stopping session right away after jumping to final mode (as most\n      other snippet plugins do) allows going back to other tabstops in case\n      of a late missed typo. Wrapping around the edge during jumping also\n      helps with that.\n      If current tabstop is not final, exiting into Normal mode for quick edit\n      outside of snippets range (or carefully inside) is fine. Later get back\n      into Insert mode and jump to next tabstop or manually stop session.\n  See |MiniSnippets-examples| for how to set up custom stopping rules.\n\nUse |MiniSnippets.session.get()| to get data about active/nested session(s).\nUse |MiniSnippets.session.jump()| / |MiniSnippets.session.stop()| in mappings.\n\nWhat is allowed but not officially supported/recommended:\n\n- Editing text within snippet range but outside of session life cycle. Mostly\n  behaves as expected, but may harm tracking metadata (|extmarks|).\n  In general anything but deleting tabstop range should be OK.\n  Text synchronization of current tabstop would still be active.\n\n# Events ~\n*MiniSnippets-events*\n\nGeneral session activity (autocommand data contains <session> field):\n- `MiniSnippetsSessionStart` - after a session is started.\n- `MiniSnippetsSessionStop` - before a session is stopped.\n\nNesting session activity (autocommand data contains <session> field):\n- `MiniSnippetsSessionSuspend` - before a session is suspended.\n- `MiniSnippetsSessionResume` - after a session is resumed.\n\nJumping between tabstops (autocommand data contains <tabstop_from> and\n<tabstop_new> fields):\n- `MiniSnippetsSessionJumpPre` - before jumping to a new tabstop.\n- `MiniSnippetsSessionJump` - after jumping to a new tabstop.\n\nParameters ~\n{snippet} `(table)` Snippet table. Field <body> is mandatory.\n{opts} `(table|nil)` Options. Possible fields:\n  - <empty_tabstop> `(string)` - used to visualize empty regular tabstops.\n    Default: \"•\".\n  - <empty_tabstop_final> `(string)` - used to visualize empty final tabstop(s).\n    Default: \"∎\".\n  - <lookup> `(table)` - passed to |MiniSnippets.parse()|. Use it to adjust\n    how variables are evaluated. Default: `{}`.\n\n------------------------------------------------------------------------------\n                                                          *MiniSnippets.session*\n                             `MiniSnippets.session`\nWork with snippet session from |MiniSnippets.default_insert()|\n\n------------------------------------------------------------------------------\n                                                    *MiniSnippets.session.get()*\n                       `MiniSnippets.session.get`({all})\nGet data about active session\n\nParameters ~\n{all} `(boolean|nil)` Whether to return array with the whole session stack.\n  Default: `false`.\n\nReturn ~\n`(table)` Single table with session data (if `all` is `false`) or array of them.\n  Session data contains the following fields:\n   - <buf_id> `(number)` - identifier of session's buffer.\n   - <cur_tabstop> `(string)` - identifier of session's current tabstop.\n   - <extmark_id> `(number)` - |extmark| identifier which track session range.\n   - <insert_args> `(table)` - |MiniSnippets.default_insert()| arguments used to\n     create the session. A table with <snippet> and <opts> fields.\n   - <nodes> `(table)` - parsed array of snippet nodes which is kept up to date\n     during session. Has the structure of a normalized |MiniSnippets.parse()|\n     output, plus every node contains `extmark_id` field with |extmark| identifier\n     which can be used to get data about the current node state.\n   - <ns_id> `(number)` - |namespace| identifier for all session's extmarks.\n   - <tabstops> `(table)` - data about session's tabstops. Fields are string\n     tabstop identifiers and values are tables with the following fields:\n       - <is_visited> `(boolean)` - whether tabstop was visited.\n       - <next> `(string)` - identifier of the next tabstop.\n       - <prev> `(string)` - identifier of the previous tabstop.\n\n------------------------------------------------------------------------------\n                                                   *MiniSnippets.session.jump()*\n                    `MiniSnippets.session.jump`({direction})\nJump to next/previous tabstop\n\nMake next/previous tabstop be current. Executes the following steps:\n- Mark current tabstop as visited.\n- Find the next/previous tabstop id assuming they are sorted as numbers.\n  Tabstop \"0\" is always last. Search is wrapped around the edges: first and\n  final tabstops are next/previous for one another.\n- Focus on target tabstop:\n    - Ensure session's buffer is current.\n    - Adjust highlighting of affected nodes.\n    - Set cursor at tabstop's reference node (first node among linked).\n      Cursor is placed on left edge if tabstop has not been edited yet (so\n      typing text replaces placeholder), on right edge otherwise (to update\n      already edited text).\n    - Show all choices for tabstop with choices. Navigating through choices\n      will update tabstop's text.\n\nParameters ~\n{direction} `(string)` One of \"next\" or \"prev\".\n\n------------------------------------------------------------------------------\n                                                   *MiniSnippets.session.stop()*\n                         `MiniSnippets.session.stop`()\nStop (only) active session\n\nTo stop all nested sessions use the following code: >lua\n\n  while MiniSnippets.session.get() do\n    MiniSnippets.session.stop()\n  end\n<\n------------------------------------------------------------------------------\n                                                          *MiniSnippets.parse()*\n                  `MiniSnippets.parse`({snippet_body}, {opts})\nParse snippet\n\nParameters ~\n{snippet_body} `(string|table)` Snippet body as string or array of strings.\n  Should follow |MiniSnippets-syntax-specification|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <normalize> `(boolean)` - whether to normalize nodes:\n    - Evaluate variable nodes and add output as a `text` field.\n      If variable is not set, `text` field is `nil`.\n      Values from `opts.lookup` are preferred over evaluation output.\n      See |MiniSnippets-syntax-specification| for more info about variables.\n    - Add `text` field for tabstops present in `opts.lookup`.\n    - Ensure every node contains exactly one of `text` or `placeholder` fields.\n      If there are none, add default `placeholder` (one text node with first\n      choice or empty string). If there are both, remove `placeholder` field.\n    - Ensure present final tabstop: append to end if absent.\n    - Ensure that nodes for same tabstop have same placeholder. Use the one\n      from the first node.\n    Default: `false`.\n  - <lookup> `(table)` - map from variable/tabstop (string) name to its value.\n    Default: `{}`.\n\nReturn ~\n`(table)` Array of nodes. Node is a table with fields depending on node type:\n  - Text node:\n    - <text> `(string)` - node's text.\n  - Tabstop node:\n    - <tabstop> `(string)` - tabstop identifier.\n    - <text> `(string|nil)` - tabstop value (if present in <lookup>).\n    - <placeholder> `(table|nil)` - array of nodes to be used as placeholder.\n    - <choices> `(table|nil)` - array of string choices.\n    - <transform> `(table|nil)` - array of transformation string parts.\n  - Variable node:\n    - <var> `(string)` - variable name.\n    - <text> `(string|nil)` - variable value.\n    - <placeholder> `(table|nil)` - array of nodes to be used as placeholder.\n    - <transform> `(table|nil)` - array of transformation string parts.\n\n------------------------------------------------------------------------------\n                                               *MiniSnippets.start_lsp_server()*\n                    `MiniSnippets.start_lsp_server`({opts})\nStart completion LSP server\n\nThis starts (|vim.lsp.start()|) an LSP server with the purpose of displaying\nsnippets in (auto)completion engines (|mini.completion| in particular).\nThe server:\n- Only implements `textDocument/completion` method which prepares and matches\n  snippets at cursor (via |MiniSnippets.expand()|).\n- Auto-attaches to all loaded buffers by default.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <before_attach> `(function)` - function executed before every attach to\n    the buffer. Takes buffer id as input and can return `false` (not `nil`) to\n    cancel attaching to the buffer. Default: attach to loaded normal buffers.\n  - <match> `(false|function)` - value of `opts.match` forwarded to\n    the |MiniSnippets.expand()| when computing completion candidates.\n    Supply `false` to not do matching at cursor, return all available snippets\n    in cursor context, and rely on completion engine to match and sort items.\n    Default: `nil` (equivalent to |MiniSnippets.default_match()|).\n  - <server_config> `(table)` - server config to be used as basis for first\n    argument to |vim.lsp.start()| (`cmd` will be overridden). Default: `{}`.\n  - <triggers> `(table)` - array of trigger characters to be used as\n    `completionProvider.triggerCharacters` server capability. Default: `{}`.\n\nReturn ~\n`(integer|nil)` Identifier of started LSP server.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-splitjoin.txt",
    "content": "*mini.splitjoin* Split and join arguments\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                 *MiniSplitjoin*\nFeatures:\n- Mappings and Lua functions that modify arguments (regions inside brackets\n  between allowed separators) under cursor.\n\n  Supported actions:\n    - Toggle - split if arguments are on single line, join otherwise.\n      Main supported function of the module. See |MiniSplitjoin.toggle()|.\n    - Split - make every argument separator be on end of separate line.\n      See |MiniSplitjoin.split()|.\n    - Join - make all arguments be on single line.\n      See |MiniSplitjoin.join()|.\n\n- Mappings are dot-repeatable in Normal mode and work in Visual mode.\n\n- Customizable argument detection (see |MiniSplitjoin.config.detect|):\n    - Which brackets can contain arguments.\n    - Which strings can separate arguments.\n    - Which regions are excluded when looking for separators (like inside\n      nested brackets or quotes).\n\n- Customizable pre and post hooks for both split and join. See `split` and\n  `join` in |MiniSplitjoin.config|. There are several built-in ones\n  in |MiniSplitjoin.gen_hook|.\n\n- Works inside comments by using modified notion of indent.\n  See |MiniSplitjoin.get_indent_part()|.\n\n- Provides low-level Lua functions for split and join at positions.\n  See |MiniSplitjoin.split_at()| and |MiniSplitjoin.join_at()|.\n\nNotes:\n- Search for arguments is done using Lua patterns (regex-like approach).\n  Certain amount of false positives is to be expected.\n\n- This module is mostly designed around |MiniSplitjoin.toggle()|. If target\n  split positions are on different lines, join first and then split.\n\n- Actions can be done on Visual mode selection, which mostly present as\n  a safety route in case of incorrect detection of initial region.\n  It uses |MiniSplitjoin.get_visual_region()| which treats selection as full\n  brackets (include brackets in selection).\n\n# Setup ~\n\nThis module needs a setup with `require('mini.splitjoin').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniSplitjoin`\nwhich you can use for scripting or manually (with `:lua MiniSplitjoin.*`).\n\nSee |MiniSplitjoin.config| for available config settings.\n\nYou can override runtime config settings (like action hooks) locally to\nbuffer inside `vim.b.minisplitjoin_config` which should have same structure\nas `MiniSplitjoin.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [FooSoft/vim-argwrap](https://github.com/FooSoft/vim-argwrap):\n    - Mostly has the same design as this module.\n    - Doesn't work inside comments, while this module does.\n    - Has more built-in ways to control split and join, while this module\n      intentionally provides only handful.\n- [AndrewRadev/splitjoin.vim](https://github.com/AndrewRadev/splitjoin.vim):\n    - More oriented towards language-depended transformations, while this\n      module intntionally deals with more generic text-related functionality.\n- [Wansmer/treesj](https://github.com/Wansmer/treesj):\n    - Operates based on tree-sitter nodes. This is more accurate in\n      some edge cases, but **requires** tree-sitter parser.\n    - Doesn't work inside comments or strings.\n\n# Disabling ~\n\nTo disable, set `g:minisplitjoin_disable` (globally) or `b:minisplitjoin_disable`\n(for a buffer) to `v:true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                        *MiniSplitjoin-glossary*\nPOSITION ~\nTable with fields <line> and <col> containing line and column numbers\nrespectively. Both are 1-indexed. Example: `{ line = 2, col = 1 }`.\n\nREGION ~\nTable representing region in a buffer. Fields: <from> and <to> for\ninclusive start and end positions. Example: >lua\n\n  { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }\n<\n------------------------------------------------------------------------------\n                                                         *MiniSplitjoin.setup()*\n                        `MiniSplitjoin.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniSplitjoin.config|.\n\nUsage ~\n>lua\n  require('mini.splitjoin').setup() -- use default config\n  -- OR\n  require('mini.splitjoin').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                          *MiniSplitjoin.config*\n                             `MiniSplitjoin.config`\nDefaults ~\n>lua\n  MiniSplitjoin.config = {\n    -- Module mappings. Use `''` (empty string) to disable one.\n    -- Created for both Normal and Visual modes.\n    mappings = {\n      toggle = 'gS',\n      split = '',\n      join = '',\n    },\n\n    -- Detection options: where split/join should be done\n    detect = {\n      -- Array of Lua patterns to detect region with arguments.\n      -- Default: { '%b()', '%b[]', '%b{}' }\n      brackets = nil,\n\n      -- String Lua pattern defining argument separator\n      separator = ',',\n\n      -- Array of Lua patterns for sub-regions to exclude separators from.\n      -- Enables correct detection in presence of nested brackets and quotes.\n      -- Default: { '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" }\n      exclude_regions = nil,\n    },\n\n    -- Split options\n    split = {\n      hooks_pre = {},\n      hooks_post = {},\n    },\n\n    -- Join options\n    join = {\n      hooks_pre = {},\n      hooks_post = {},\n    },\n  }\n<\n# Detection ~\n*MiniSplitjoin.config.detect*\n\nThe table at `config.detect` controls how arguments are detected using Lua\npatterns. General idea is to convert whole buffer into a single line,\nperform string search, and convert results back into 2d positions.\n\nExample configuration: >lua\n\n  require('mini.splitjoin').setup({\n    detect = {\n      -- Detect only inside balanced parenthesis\n      brackets = { '%b()' },\n\n      -- Allow both `,` and `;` to separate arguments\n      separator = '[,;]',\n\n      -- Make any separator define an argument\n      exclude_regions = {},\n    },\n  })\n<\n## Outer brackets ~\n\n`detect.brackets` is an array of Lua patterns used to find enclosing region.\nIt is done by traversing whole buffer to find the smallest region matching\nany supplied pattern.\n\nDefault: `nil`, inferred as `{ '%b()', '%b[]', '%b{}' }`.\nSo an argument can be inside a balanced `()`, `[]`, or `{}`.\n\nExample: `brackets = { '%b()' }` will search for arguments only inside\nbalanced `()`.\n\n## Separator ~\n\n`detect.separator` is a single Lua pattern defining which strings should be\ntreated as argument separators.\n\nEmpty string in `detect.separator` will result in only surrounding brackets\nused as separators.\n\nOnly end of pattern match will be used as split/join positions.\n\nDefault: `','`. So an argument can be separated only with comma.\n\nExample: `separator = { '[,;]' }` will treat both `,` and `;` as separators.\n\n## Excluded regions ~\n\n`detect.exclude_regions` is an array of Lua patterns for sub-regions from which\nto exclude separators. Enables correct detection in case of nested brackets\nand quotes.\n\nDefault: `nil`; inferred as `{ '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" }`.\nSo a separator **can not** be inside a balanced `()`, `[]`, `{}` (representing\nnested argument regions) or `\"\"`, `''` (representing strings).\n\nExample: `exclude_regions = {}` will not exclude any regions. So in case of\n`f(a, { b, c })` it will detect both commas as argument separators.\n\n# Hooks ~\n\n`split.hooks_pre`, `split.hooks_post`, `join.hooks_pre`, and `join.hooks_post`\nare arrays of hook functions. If empty (default) no hook is applied.\n\nHooks should take and return array of positions. See |MiniSplitjoin-glossary|.\n\nThey can be used to tweak actions:\n\n- Pre-hooks are called before action. Each is applied on the output of\n  previous one. Input of first hook are detected split/join positions.\n  Output of last one is actually used to perform split/join.\n\n- Post-hooks are called after action. Each is applied on the output of\n  previous one. Input of first hook are split/join positions from actual\n  action plus its region's right end as last position (for easier hook code).\n  Output of last one is used as action return value.\n\nFor more specific details see |MiniSplitjoin.split()| and |MiniSplitjoin.join()|.\n\nSee |MiniSplitjoin.gen_hook| for generating common hooks with examples.\n\n------------------------------------------------------------------------------\n                                                        *MiniSplitjoin.toggle()*\n                         `MiniSplitjoin.toggle`({opts})\nToggle arguments\n\nOverview:\n- Detect region at input position: either by using supplied `opts.region` or\n  by finding smallest bracketed region surrounding position.\n  See |MiniSplitjoin.config.detect| for more details.\n- If region spans single line, use |MiniSplitjoin.split()| with found region.\n  Otherwise use |MiniSplitjoin.join()|.\n\nParameters ~\n{opts} `(table|nil)` Options. Has structure from |MiniSplitjoin.config|\n  inheriting its default values.\n\n  Following extra optional fields are allowed:\n  - <position> `(table)` - position at which to find smallest bracket region.\n    See |MiniSplitjoin-glossary| for the structure.\n    Default: cursor position.\n  - <region> `(table)` - region at which to perform action. Assumes inclusive\n    both start at left bracket and end at right bracket.\n    See |MiniSplitjoin-glossary| for the structure.\n    Default: `nil` to automatically detect region.\n\nReturn ~\n`(any)` Output of chosen `split()` or `join()` action.\n\n------------------------------------------------------------------------------\n                                                         *MiniSplitjoin.split()*\n                         `MiniSplitjoin.split`({opts})\nSplit arguments\n\nOverview:\n- Detect region: either by using supplied `opts.region` or by finding smallest\n  bracketed region surrounding input position (cursor position by default).\n  See |MiniSplitjoin.config.detect| for more details.\n\n- Find separator positions using `separator` and `exclude_regions` from `opts`.\n  Both brackets are treated as separators.\n  See |MiniSplitjoin.config.detect| for more details.\n  Note: stop if no separator positions are found.\n\n- Modify separator positions to represent split positions. Last split position\n  (which is inferred from right bracket) is moved one column to left so that\n  right bracket would move on new line.\n\n- Apply all hooks from `opts.split.hooks_pre`. Each is applied on the output of\n  previous one. Input of first hook is split positions from previous step.\n  Output of last one is used as split positions in next step.\n\n- Split and update split positions with |MiniSplitjoin.split_at()|.\n\n- Apply all hooks from `opts.split.hooks_post`. Each is applied on the output of\n  previous one. Input of first hook is split positions from previous step plus\n  region's right end (for easier hook code).\n  Output of last one is used as function return value.\n\nNote:\n- By design, it doesn't detect if argument **should** be split, so application\n  on arguments spanning multiple lines can lead to undesirable result.\n\nParameters ~\n{opts} `(table|nil)` Options. Has structure from |MiniSplitjoin.config|\n  inheriting its default values.\n\n  Following extra optional fields are allowed:\n  - <position> `(table)` - position at which to find smallest bracket region.\n    See |MiniSplitjoin-glossary| for the structure.\n    Default: cursor position.\n  - <region> `(table)` - region at which to perform action. Assumes inclusive\n    both start at left bracket and end at right bracket.\n    See |MiniSplitjoin-glossary| for the structure.\n    Default: `nil` to automatically detect region.\n\nReturn ~\n`(any)` Output of last `opts.split.hooks_post` or `nil` if no split positions\n  found. Default: return value of |MiniSplitjoin.split_at()| application.\n\n------------------------------------------------------------------------------\n                                                          *MiniSplitjoin.join()*\n                          `MiniSplitjoin.join`({opts})\nJoin arguments\n\nOverview:\n- Detect region: either by using supplied `opts.region` or by finding smallest\n  bracketed region surrounding input position (cursor position by default).\n  See |MiniSplitjoin.config.detect| for more details.\n\n- Compute join positions to be line ends of all but last region lines.\n  Note: stop if no join positions are found.\n\n- Apply all hooks from `opts.join.hooks_pre`. Each is applied on the output\n  of previous one. Input of first hook is join positions from previous step.\n  Output of last one is used as join positions in next step.\n\n- Join and update join positions with |MiniSplitjoin.join_at()|.\n\n- Apply all hooks from `opts.join.hooks_post`. Each is applied on the output\n  of previous one. Input of first hook is join positions from previous step\n  plus region's right end for easier hook code.\n  Output of last one is used as function return value.\n\nParameters ~\n{opts} `(table|nil)` Options. Has structure from |MiniSplitjoin.config|\n  inheriting its default values.\n\n  Following extra optional fields are allowed:\n  - <position> `(table)` - position at which to find smallest bracket region.\n    See |MiniSplitjoin-glossary| for the structure.\n    Default: cursor position.\n  - <region> `(table)` - region at which to perform action. Assumes inclusive\n    both start at left bracket and end at right bracket.\n    See |MiniSplitjoin-glossary| for the structure.\n    Default: `nil` to automatically detect region.\n\nReturn ~\n`(any)` Output of last `opts.split.hooks_post` or `nil` of no join positions\n  found. Default: return value of |MiniSplitjoin.join_at()| application.\n\n------------------------------------------------------------------------------\n                                                        *MiniSplitjoin.gen_hook*\n                            `MiniSplitjoin.gen_hook`\nGenerate common hooks\n\nThis is a table with function elements. Call to actually get hook.\n\nAll generated post-hooks return updated versions of their input reflecting\nchanges done inside hook.\n\nExample for `lua` filetype (place it in 'lua.lua' filetype plugin, |ftplugin|): >lua\n\n  local gen_hook = MiniSplitjoin.gen_hook\n  local curly = { brackets = { '%b{}' } }\n\n  -- Add trailing comma when splitting inside curly brackets\n  local add_comma_curly = gen_hook.add_trailing_separator(curly)\n\n  -- Delete trailing comma when joining inside curly brackets\n  local del_comma_curly = gen_hook.del_trailing_separator(curly)\n\n  -- Pad curly brackets with single space after join\n  local pad_curly = gen_hook.pad_brackets(curly)\n\n  -- Create buffer-local config\n  vim.b.minisplitjoin_config = {\n    split = { hooks_post = { add_comma_curly } },\n    join  = { hooks_post = { del_comma_curly, pad_curly } },\n  }\n<\n------------------------------------------------------------------------------\n                                         *MiniSplitjoin.gen_hook.pad_brackets()*\n                 `MiniSplitjoin.gen_hook.pad_brackets`({opts})\nGenerate hook to pad brackets\n\nThis is a join post-hook. Use in `join.hooks_post` of |MiniSplitjoin.config|.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n   - <pad> `(string)` - pad to add after first and before last join positions.\n     Default: `' '` (single space).\n   - <brackets> `(table)` - array of bracket patterns indicating on which\n     brackets action should be made. Has same structure as `brackets`\n     in |MiniSplitjoin.config.detect|.\n     Default: `MiniSplitjoin.config.detect.brackets`.\n\nReturn ~\n`(function)` A hook which adds inner pad to first and last join positions and\n  returns updated input join positions.\n\n------------------------------------------------------------------------------\n                               *MiniSplitjoin.gen_hook.add_trailing_separator()*\n            `MiniSplitjoin.gen_hook.add_trailing_separator`({opts})\nGenerate hook to add trailing separator\n\nThis is a split post-hook. Use in `split.hooks_post` of |MiniSplitjoin.config|.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n   - <sep> `(string)` - separator to add before last split position.\n     Default: `','`.\n   - <brackets> `(table)` - array of bracket patterns indicating on which\n     brackets action should be made. Has same structure as `brackets`\n     in |MiniSplitjoin.config.detect|.\n     Default: `MiniSplitjoin.config.detect.brackets`.\n\nReturn ~\n`(function)` A hook which adds separator before last split position and\n  returns updated input split positions.\n\n------------------------------------------------------------------------------\n                               *MiniSplitjoin.gen_hook.del_trailing_separator()*\n            `MiniSplitjoin.gen_hook.del_trailing_separator`({opts})\nGenerate hook to delete trailing separator\n\nThis is a join post-hook. Use in `join.hooks_post` of |MiniSplitjoin.config|.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n   - <sep> `(string)` - separator to remove before last join position.\n     Default: `','`.\n   - <brackets> `(table)` - array of bracket patterns indicating on which\n     brackets action should be made. Has same structure as `brackets`\n     in |MiniSplitjoin.config.detect|.\n     Default: `MiniSplitjoin.config.detect.brackets`.\n\nReturn ~\n`(function)` A hook which adds separator before last split position and\n  returns updated input split positions.\n\n------------------------------------------------------------------------------\n                                                      *MiniSplitjoin.split_at()*\n                     `MiniSplitjoin.split_at`({positions})\nSplit at positions\n\nOverview:\n- For each position move all characters after it to next line and make it have\n  same indent as current one (see |MiniSplitjoin.get_indent_part()|).\n  Also remove trailing whitespace at position line.\n\n- Increase indent of inner lines by a single pad: tab in case of |'noexpandtab'|\n  or |shiftwidth()| number of spaces otherwise.\n\nNotes:\n- Cursor is adjusted to follow text updates.\n- Use output of this function to keep track of input positions.\n\nParameters ~\n{positions} `(table)` Array of positions at which to perform split.\n  See |MiniSplitjoin-glossary| for their structure. Note: they don't have\n  to be ordered, but first and last ones will be used to infer lines for\n  which indent will be increased.\n\nReturn ~\n`(table)` Array of new positions to where input `positions` were moved.\n\n------------------------------------------------------------------------------\n                                                       *MiniSplitjoin.join_at()*\n                      `MiniSplitjoin.join_at`({positions})\nJoin at positions\n\nOverview:\n- For each position join its line with the next line. Joining is done by\n  replacing trailing whitespace of the line and indent of its next line\n  (see |MiniSplitjoin.get_indent_part()|) with a pad string (single space except\n  empty string for first and last positions). To adjust this, use hooks\n  (for example, see |MiniSplitjoin.gen_hook.pad_brackets()|).\n\nNotes:\n- Cursor is adjusted to follow text updates.\n- Use output of this function to keep track of input positions.\n\nParameters ~\n{positions} `(table)` Array of positions at which to perform join.\n  See |MiniSplitjoin-glossary| for their structure. Note: they don't have\n  to be ordered, but first and last ones will have different pad string.\n\nReturn ~\n`(table)` Array of new positions to where input `positions` were moved.\n\n------------------------------------------------------------------------------\n                                             *MiniSplitjoin.get_visual_region()*\n                      `MiniSplitjoin.get_visual_region`()\nGet previous visual region\n\nGet previous visual selection using |'<| and |'>| marks in the format of\nregion (see |MiniSplitjoin-glossary|). Used in Visual mode mappings.\n\nNote:\n- Both marks are included in region.\n- In linewise mode start is at column 1 and end is at line's last character.\n\nReturn ~\n`(table)` A region. See |MiniSplitjoin-glossary| for exact structure.\n\n------------------------------------------------------------------------------\n                                               *MiniSplitjoin.get_indent_part()*\n          `MiniSplitjoin.get_indent_part`({line}, {respect_comments})\nGet string's indent part\n\nParameters ~\n{line} `(string)` String for which to compute indent.\n{respect_comments} `(boolean|nil)` Whether to respect comments as indent part.\n  Default: `true`.\n\nReturn ~\n`(string)` Part of input representing line's indent. Can be empty string.\n  Use `string.len()` to compute indent in bytes.\n\n------------------------------------------------------------------------------\n                                                      *MiniSplitjoin.operator()*\n                        `MiniSplitjoin.operator`({task})\nOperator for Normal mode mappings\n\nMain function to be used in expression mappings. No need to use it\ndirectly, everything is setup in |MiniSplitjoin.setup()|.\n\nParameters ~\n{task} `(string)` Name of task.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-starter.txt",
    "content": "*mini.starter* Start screen\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                   *MiniStarter*\nDisplayed items are fully customizable both in terms of what they do and\nhow they look (with reasonable defaults). Item selection can be done using\nprefix query with instant visual feedback.\n\nKey design ideas:\n- All available actions are defined inside items. Each item should have the\n  following info:\n    - <action> - function or string for |vim.cmd()| which is executed when\n      item is chosen. Empty string result in placeholder \"inactive\" item.\n    - <name> - string which will be displayed and used for choosing.\n    - <section> - string representing to which section item belongs.\n  There are pre-configured whole sections in |MiniStarter.sections|.\n\n- Configure what items are displayed by supplying an array which can be\n  normalized to an array of items. Read about how supplied items are\n  normalized in |MiniStarter.refresh()|.\n\n- Modify the final look by supplying content hooks: functions which take\n  buffer content (see |MiniStarter.get_content()|) and identifier as input\n  while returning buffer content as output. There are pre-configured\n  content hook generators in |MiniStarter.gen_hook|.\n\n- Choosing an item can be done in two ways:\n    - Type prefix query to filter item by matching its name (ignoring\n      case). Displayed information is updated after every typed character.\n      For every item its unique prefix is highlighted.\n    - Use Up/Down arrows and hit Enter.\n\n- Allow multiple simultaneously open Starter buffers.\n\nWhat is doesn't do:\n- It doesn't support fuzzy query for items. And probably will never do.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.starter').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniStarter` which you can use for scripting or manually (with\n`:lua MiniStarter.*`).\n\nSee |MiniStarter.config| for `config` structure and default values. For\nsome configuration examples (including one similar to 'vim-startify' and\n'dashboard-nvim'), see |MiniStarter-example-config|.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.ministarter_config` which should have same structure as\n`MiniStarter.config`. See |mini.nvim-buffer-local-config| for more details.\nNote: `vim.b.ministarter_config` is copied to Starter buffer from current\nbuffer allowing full customization.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Highlight groups ~\n\n- `MiniStarterCurrent` - current item.\n- `MiniStarterFooter` - footer units.\n- `MiniStarterHeader` - header units.\n- `MiniStarterInactive` - inactive item.\n- `MiniStarterItem` - item name.\n- `MiniStarterItemBullet` - units from |MiniStarter.gen_hook.adding_bullet()|.\n- `MiniStarterItemPrefix` - unique query for item.\n- `MiniStarterSection` - section units.\n- `MiniStarterQuery` - current query in active items.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable core functionality, set `vim.g.ministarter_disable` (globally) or\n`vim.b.ministarter_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                    *MiniStarter-example-config*\n# Similar to 'mhinz/vim-startify' ~\n>lua\n  local starter = require('mini.starter')\n  starter.setup({\n    evaluate_single = true,\n    items = {\n      starter.sections.builtin_actions(),\n      starter.sections.recent_files(10, false),\n      starter.sections.recent_files(10, true),\n      -- Use this if you set up 'mini.sessions'\n      starter.sections.sessions(5, true)\n    },\n    content_hooks = {\n      starter.gen_hook.adding_bullet(),\n      starter.gen_hook.indexing('all', { 'Builtin actions' }),\n      starter.gen_hook.padding(3, 2),\n    },\n  })\n<\n# Similar to 'glepnir/dashboard-nvim' ~\n>lua\n  local starter = require('mini.starter')\n  starter.setup({\n    items = {\n      starter.sections.telescope(),\n    },\n    content_hooks = {\n      starter.gen_hook.adding_bullet(),\n      starter.gen_hook.aligning('center', 'center'),\n    },\n  })\n<\n# Demo of capabilities ~\n>lua\n  local my_items = {\n    { name = 'Echo random number', action = 'lua print(math.random())', section = 'Section 1' },\n    function()\n      return {\n        { name = 'Item #1 from function', action = [[echo 'Item #1']], section = 'From function' },\n        { name = 'Placeholder (always inactive) item', action = '', section = 'From function' },\n        function()\n          return {\n            name = 'Item #1 from double function',\n            action = [[echo 'Double function']],\n            section = 'From double function',\n          }\n        end,\n      }\n    end,\n    { name = [[Another item in 'Section 1']], action = 'lua print(math.random() + 10)', section = 'Section 1' },\n  }\n\n  local footer_n_seconds = (function()\n    local timer = vim.loop.new_timer()\n    local n_seconds = 0\n    timer:start(0, 1000, vim.schedule_wrap(function()\n      if vim.bo.filetype ~= 'ministarter' then\n        timer:stop()\n        return\n      end\n      n_seconds = n_seconds + 1\n      MiniStarter.refresh()\n    end))\n\n    return function()\n      return 'Number of seconds since opening: ' .. n_seconds\n    end\n  end)()\n\n  local hook_top_pad_10 = function(content)\n    -- Pad from top\n    for _ = 1, 10 do\n      -- Insert at start a line with single content unit\n      table.insert(content, 1, { { type = 'empty', string = '' } })\n    end\n    return content\n  end\n\n  local starter = require('mini.starter')\n  starter.setup({\n    items = my_items,\n    footer = footer_n_seconds,\n    content_hooks = { hook_top_pad_10 },\n  })\n<\n------------------------------------------------------------------------------\n                                                         *MiniStarter-lifecycle*\n- Open with |MiniStarter.open()|. It includes creating buffer with\n  appropriate options, mappings, behavior; call to |MiniStarter.refresh()|;\n  issue `MiniStarterOpened` |User| event.\n- Wait for user to choose an item. This is done using following logic:\n    - Typing any character from `MiniStarter.config.query_updaters` leads\n      to updating query. Read more in |MiniStarter.add_to_query()|.\n    - <BS> deletes latest character from query.\n    - <Down>/<Up>, <C-n>/<C-p>, <M-j>/<M-k> move current item.\n    - <CR> executes action of current item.\n    - <C-c> closes Starter buffer.\n- Evaluate current item when appropriate (after `<CR>` or when there is a\n  single item and `MiniStarter.config.evaluate_single` is `true`). This\n  executes item's `action`.\n\n------------------------------------------------------------------------------\n                                                           *MiniStarter.setup()*\n                         `MiniStarter.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniStarter.config|.\n\nUsage ~\n>lua\n  require('mini.starter').setup() -- use default config\n  -- OR\n  require('mini.starter').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                            *MiniStarter.config*\n                              `MiniStarter.config`\nDefaults ~\n>lua\n  MiniStarter.config = {\n    -- Whether to open Starter buffer on VimEnter. Not opened if Neovim was\n    -- started with intent to show something else.\n    autoopen = true,\n\n    -- Whether to evaluate action of single active item\n    evaluate_single = false,\n\n    -- Items to be displayed. Should be an array with the following elements:\n    -- - Item: table with <action>, <name>, and <section> keys.\n    -- - Function: should return one of these three categories.\n    -- - Array: elements of these three types (i.e. item, array, function).\n    -- If `nil` (default), default items will be used (see |mini.starter|).\n    items = nil,\n\n    -- Header to be displayed before items. Converted to single string via\n    -- `tostring` (use `\\n` to display several lines). If function, it is\n    -- evaluated first. If `nil` (default), polite greeting will be used.\n    header = nil,\n\n    -- Footer to be displayed after items. Converted to single string via\n    -- `tostring` (use `\\n` to display several lines). If function, it is\n    -- evaluated first. If `nil` (default), default usage help will be shown.\n    footer = nil,\n\n    -- Array  of functions to be applied consecutively to initial content.\n    -- Each function should take and return content for Starter buffer (see\n    -- |mini.starter| and |MiniStarter.get_content()| for more details).\n    content_hooks = nil,\n\n    -- Characters to update query. Each character will have special buffer\n    -- mapping overriding your global ones. Be careful to not add `:` as it\n    -- allows you to go into command mode.\n    query_updaters = 'abcdefghijklmnopqrstuvwxyz0123456789_-.',\n\n    -- Whether to disable showing non-error feedback\n    silent = false,\n  }\n<\n------------------------------------------------------------------------------\n                                                            *MiniStarter.open()*\n                          `MiniStarter.open`({buf_id})\nOpen Starter buffer\n\n- Create buffer if necessary and move into it.\n- Set buffer options. Note that settings are done with |:noautocmd| to\n  achieve a massive speedup.\n- Set buffer mappings. Besides basic mappings (described inside \"Lifecycle\n  of Starter buffer\" of |mini.starter|), map every character from\n  `MiniStarter.config.query_updaters` to add itself to query with\n  |MiniStarter.add_to_query()|.\n- Populate buffer with |MiniStarter.refresh()|.\n- Issue custom `MiniStarterOpened` event to allow acting upon opening\n  Starter buffer. Use it with\n  `autocmd User MiniStarterOpened <your command>`.\n\nNote: to fully use it in autocommand, use |autocmd-nested|. Example: >lua\n\n  local starter_open = function() MiniStarter.open() end\n  local au_opts = { nested = true, callback = starter_open }\n  vim.api.nvim_create_autocmd('TabNewEntered', au_opts)\n<\nParameters ~\n{buf_id} `(number|nil)` Identifier of existing valid buffer (see |bufnr()|) to\n  open inside. Default: create a new one.\n\n------------------------------------------------------------------------------\n                                                         *MiniStarter.refresh()*\n                        `MiniStarter.refresh`({buf_id})\nRefresh Starter buffer\n\n- Normalize `MiniStarter.config.items`:\n    - Flatten: recursively (in depth-first fashion) parse its elements. If\n      function is found, execute it and continue with parsing its output\n      (this allows deferring item collection up until it is actually\n      needed).  If proper item is found (table with fields `action`,\n      `name`, `section`), add it to output.\n    - Sort: order first by section and then by item id (both in order of\n      appearance).\n- Normalize `MiniStarter.config.header` and `MiniStarter.config.footer` to\n  be multiple lines by splitting at `\\n`. If function - evaluate it first.\n- Make initial buffer content (see |MiniStarter.get_content()| for a\n  description of what a buffer content is). It consist from content lines\n  with single content unit:\n    - First lines contain strings of normalized header.\n    - Body is for normalized items. Section names have own lines preceded\n      by empty line.\n    - Last lines contain separate strings of normalized footer.\n- Sequentially apply hooks from `MiniStarter.config.content_hooks` to\n  content. All hooks are applied with `(content, buf_id)` signature. Output\n  of one hook serves as first argument to the next.\n- Gather final items from content with |MiniStarter.content_to_items()|.\n- Convert content to buffer lines with |MiniStarter.content_to_lines()| and\n  add them to buffer.\n- Add highlighting of content units.\n- Position cursor.\n- Make current query. This results into some items being marked as\n  \"inactive\" and updating highlighting of current query on \"active\" items.\n\nNote: this function is executed on every |VimResized| to allow more\nresponsive behavior.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                           *MiniStarter.close()*\n                         `MiniStarter.close`({buf_id})\nClose Starter buffer\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                          *MiniStarter.sections*\n                             `MiniStarter.sections`\nTable of pre-configured sections\n\n------------------------------------------------------------------------------\n                                        *MiniStarter.sections.builtin_actions()*\n                    `MiniStarter.sections.builtin_actions`()\nSection with builtin actions\n\nReturn ~\n`(table)` Array of items.\n\n------------------------------------------------------------------------------\n                                               *MiniStarter.sections.sessions()*\n                 `MiniStarter.sections.sessions`({n}, {recent})\nSection with |mini.sessions| sessions\n\nSessions are taken from |MiniSessions.detected|. Notes:\n- If it shows \"'mini.sessions' is not set up\", it means that you didn't\n  call `require('mini.sessions').setup()`.\n- If it shows \"There are no detected sessions in 'mini.sessions'\", it means\n  that there are no sessions at the current sessions directory. Either\n  create session or supply different directory where session files are\n  stored (see |MiniSessions.setup()|).\n- Local session (if detected) is always displayed first.\n\nParameters ~\n{n} `(number|nil)` Number of returned items. Default: 5.\n{recent} `(boolean|nil)` Whether to use recent sessions (instead of\n  alphabetically by name). Default: true.\n\nReturn ~\n`(function)` Function which returns array of items.\n\n------------------------------------------------------------------------------\n                                           *MiniStarter.sections.recent_files()*\n      `MiniStarter.sections.recent_files`({n}, {current_dir}, {show_path})\nSection with most recently used files\n\nFiles are taken from |v:oldfiles|.\n\nParameters ~\n{n} `(number|nil)` Number of returned items. Default: 5.\n{current_dir} `(boolean|nil)` Whether to return files only from current working\n  directory and its subdirectories. Default: `false`.\n{show_path} `(boolean|function|nil)` Whether to append file name with its path.\n  If callable, will be called with full path and should return string to be\n  directly appended to file name. Default: `true`.\n\nReturn ~\n`(function)` Function which returns array of items.\n\n------------------------------------------------------------------------------\n                                                   *MiniStarter.sections.pick()*\n                         `MiniStarter.sections.pick`()\nSection with |mini.pick| pickers\n\nNotes:\n- All actions require 'mini.pick' module of 'mini.nvim'.\n- \"Command history\", \"Explorer\", and \"Visited paths\" items\n  require |mini.extra| module of 'mini.nvim'.\n- \"Visited paths\" items requires |mini.visits| module of 'mini.nvim'.\n\nReturn ~\n`(function)` Function which returns array of items.\n\n------------------------------------------------------------------------------\n                                              *MiniStarter.sections.telescope()*\n                       `MiniStarter.sections.telescope`()\nSection with basic Telescope pickers relevant to start screen\n\nNotes:\n- All actions require\n  [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim).\n- \"Browser\" item requires\n  [nvim-telescope/telescope-file-browser.nvim](https://github.com/nvim-telescope/telescope-file-browser.nvim).\n\nReturn ~\n`(function)` Function which returns array of items.\n\n------------------------------------------------------------------------------\n                                                          *MiniStarter.gen_hook*\n                             `MiniStarter.gen_hook`\nTable with pre-configured content hook generators\n\nEach element is a function which returns content hook. So to use them\ninside |MiniStarter.setup()|, call them.\n\n------------------------------------------------------------------------------\n                                                *MiniStarter.gen_hook.padding()*\n                 `MiniStarter.gen_hook.padding`({left}, {top})\nHook generator for padding\n\nOutput is a content hook which adds constant padding from left and top.\nThis allows tweaking the screen position of buffer content.\n\nParameters ~\n{left} `(number|nil)` Number of empty spaces to add to start of each content\n  line. Default: 0.\n{top} `(number|nil)` Number of empty lines to add to start of content.\n  Default: 0.\n\nReturn ~\n`(function)` Content hook.\n\n------------------------------------------------------------------------------\n                                          *MiniStarter.gen_hook.adding_bullet()*\n         `MiniStarter.gen_hook.adding_bullet`({bullet}, {place_cursor})\nHook generator for adding bullet to items\n\nOutput is a content hook which adds supplied string to be displayed to the\nleft of item.\n\nParameters ~\n{bullet} `(string|nil)` String to be placed to the left of item name.\n  Default: \"░ \".\n{place_cursor} `(boolean|nil)` Whether to place cursor on the first character\n  of bullet when corresponding item becomes current. Default: true.\n\nReturn ~\n`(function)` Content hook.\n\n------------------------------------------------------------------------------\n                                               *MiniStarter.gen_hook.indexing()*\n        `MiniStarter.gen_hook.indexing`({grouping}, {exclude_sections})\nHook generator for indexing items\n\nOutput is a content hook which adds unique index to the start of item's\nname. It results into shortening queries required to choose an item (at\nexpense of clarity).\n\nParameters ~\n{grouping} `(string|nil)` One of \"all\" (number indexing across all sections) or\n  \"section\" (letter-number indexing within each section). Default: \"all\".\n{exclude_sections} `(table|nil)` Array of section names (values of `section`\n  element of item) for which index won't be added. Default: `{}`.\n\nReturn ~\n`(function)` Content hook.\n\n------------------------------------------------------------------------------\n                                               *MiniStarter.gen_hook.aligning()*\n           `MiniStarter.gen_hook.aligning`({horizontal}, {vertical})\nHook generator for aligning content\n\nOutput is a content hook which independently aligns content horizontally\nand vertically. Window width and height are taken from first window in current\ntabpage displaying the Starter buffer.\n\nBasically, this computes left and top pads for |MiniStarter.gen_hook.padding()|\nsuch that output lines would appear aligned in certain way.\n\nParameters ~\n{horizontal} `(string|nil)` One of \"left\", \"center\", \"right\". Default: \"left\".\n{vertical} `(string|nil)` One of \"top\", \"center\", \"bottom\". Default: \"top\".\n\nReturn ~\n`(function)` Content hook.\n\n------------------------------------------------------------------------------\n                                                     *MiniStarter.get_content()*\n                      `MiniStarter.get_content`({buf_id})\nGet content of Starter buffer\n\nGenerally, buffer content is a table in the form of \"2d array\" (or rather\n\"2d list\" because number of elements can differ):\n- Each element represents content line: an array with content units to be\n  displayed in one buffer line.\n- Each content unit is a table with at least the following elements:\n    - \"type\" - string with type of content. Something like \"item\",\n      \"section\", \"header\", \"footer\", \"empty\", etc.\n    - \"string\" - which string should be displayed. May be an empty string.\n    - \"hl\" - which highlighting should be applied to content string. May be\n      `nil` for no highlighting.\n\nSee |MiniStarter.content_to_lines()| for converting content to buffer lines\nand |MiniStarter.content_to_items()| - to list of parsed items.\n\nNotes:\n- Content units with type \"item\" also have `item` element with all\n  information about an item it represents. Those elements are used directly\n  to create an array of items used for query.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                  *MiniStarter.content_coords()*\n              `MiniStarter.content_coords`({content}, {predicate})\nHelper to iterate through content\n\nBasically, this traverses content \"2d array\" (in depth-first fashion; top\nto bottom, left to right) and returns \"coordinates\" of units for which\n`predicate` is true-ish.\n\nParameters ~\n{content} `(table|nil)` Content \"2d array\". Default: content of current buffer.\n{predicate} `(function|string|nil)` Predictate to filter units. If it is:\n   - Function, then it is evaluated with unit as input.\n   - String, then it checks unit to have this type (allows easy getting of\n     units with some type).\n   - `nil`, all units are kept.\n\nReturn ~\n`(table)` Array of resulting units' coordinates. Each coordinate is a\n  table with <line> and <unit> keys. To retrieve actual unit from coordinate\n  `c`, use `content[c.line][c.unit]`.\n\n------------------------------------------------------------------------------\n                                                *MiniStarter.content_to_lines()*\n                   `MiniStarter.content_to_lines`({content})\nConvert content to buffer lines\n\nOne buffer line is made by concatenating `string` element of units within\nsame content line.\n\nParameters ~\n{content} `(table|nil)` Content \"2d array\". Default: content of current buffer.\n\nReturn ~\n`(table)` Array of strings for each buffer line.\n\n------------------------------------------------------------------------------\n                                                *MiniStarter.content_to_items()*\n                   `MiniStarter.content_to_items`({content})\nConvert content to items\n\nParse content (in depth-first fashion) and retrieve each item from `item`\nelement of content units with type \"item\". This also:\n- Computes some helper information about how item will be actually\n  displayed (after |MiniStarter.content_to_lines()|) and minimum number of\n  prefix characters needed for a particular item to be queried single.\n- Modifies item's `name` element taking it from corresponding `string`\n  element of content unit. This allows modifying item's `name` at the stage\n  of content hooks (like, for example, in |MiniStarter.gen_hook.indexing()|).\n\nParameters ~\n{content} `(table|nil)` Content \"2d array\". Default: content of current buffer.\n\nReturn ~\n`(table)` Array of items.\n\n------------------------------------------------------------------------------\n                                               *MiniStarter.eval_current_item()*\n                   `MiniStarter.eval_current_item`({buf_id})\nEvaluate current item\n\nNote that it resets current query before evaluation, as it is rarely needed\nany more.\n\nParameters ~\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n------------------------------------------------------------------------------\n                                             *MiniStarter.update_current_item()*\n            `MiniStarter.update_current_item`({direction}, {buf_id})\nUpdate current item\n\nThis makes next (with respect to `direction`) active item to be current.\n\nParameters ~\n{direction} `(string)` One of \"next\" or \"previous\".\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                    *MiniStarter.add_to_query()*\n                  `MiniStarter.add_to_query`({char}, {buf_id})\nAdd character to current query\n\n- Update current query by appending `char` to its end (only if it results\n  into at least one active item) or delete latest character if `char` is `nil`.\n- Recompute status of items: \"active\" if its name starts with new query,\n  \"inactive\" otherwise.\n- Update highlighting: whole strings for \"inactive\" items, current query\n  for \"active\" items.\n\nParameters ~\n{char} `(string|nil)` Single character to be added to query. If `nil`, deletes\n  latest character from query.\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n------------------------------------------------------------------------------\n                                                       *MiniStarter.set_query()*\n                   `MiniStarter.set_query`({query}, {buf_id})\nSet current query\n\nParameters ~\n{query} `(string|nil)` Query to be set (only if it results into at least one\n  active item). Default: `nil` for setting query to empty string, which\n  essentially resets query.\n{buf_id} `(number|nil)` Buffer identifier of a valid Starter buffer.\n  Default: current buffer.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-statusline.txt",
    "content": "*mini.statusline* Statusline\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                *MiniStatusline*\nFeatures:\n- Define own custom statusline structure for active and inactive windows.\n  This is done with a function which should return string appropriate for\n  |'statusline'|. Its code should be similar to default one with structure:\n    - Compute string data for every section you want to be displayed.\n    - Combine them in groups with |MiniStatusline.combine_groups()|.\n\n- Built-in active mode indicator with colors.\n\n- Sections can hide information when window is too narrow (specific window\n  width is configurable per section).\n\n# Dependencies ~\n\nSuggested dependencies (provide extra functionality, will work without them):\n\n- Nerd font (to support extra icons).\n\n- Enabled |mini.icons| module for |MiniStatusline.section_fileinfo()|.\n  Falls back to using 'nvim-tree/nvim-web-devicons' plugin or shows nothing.\n\n- Enabled |mini.git| module for |MiniStatusline.section_git()|.\n  Falls back to using 'lewis6991/gitsigns.nvim' plugin or shows nothing.\n\n- Enabled |mini.diff| module for |MiniStatusline.section_diff()|.\n  Falls back to using 'lewis6991/gitsigns.nvim' plugin or shows nothing.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.statusline').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniStatusline` which you can use for scripting or manually (with\n`:lua MiniStatusline.*`).\n\nSee |MiniStatusline.config| for `config` structure and default values. For\nsome content examples, see |MiniStatusline-example-content|.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.ministatusline_config` which should have same structure as\n`MiniStatusline.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Highlight groups ~\n\nHighlight depending on mode (second |MiniStatusline.section_mode()| output):\n- `MiniStatuslineModeNormal` - Normal mode.\n- `MiniStatuslineModeInsert` - Insert mode.\n- `MiniStatuslineModeVisual` - Visual mode.\n- `MiniStatuslineModeReplace` - Replace mode.\n- `MiniStatuslineModeCommand` - Command mode.\n- `MiniStatuslineModeOther` - other modes (like Terminal, etc.).\n\nHighlight used in default statusline:\n- `MiniStatuslineDevinfo` - for \"dev info\" group\n  (|MiniStatusline.section_git()| and |MiniStatusline.section_diagnostics()|).\n- `MiniStatuslineFilename` - for |MiniStatusline.section_filename()| section.\n- `MiniStatuslineFileinfo` - for |MiniStatusline.section_fileinfo()| section.\n\nOther groups:\n- `MiniStatuslineInactive` - highlighting in not focused window.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable (show empty statusline), set `vim.g.ministatusline_disable`\n(globally) or `vim.b.ministatusline_disable` (for a buffer) to `true`.\nConsidering high number of different scenarios and customization\nintentions, writing exact rules for disabling module's functionality is\nleft to user. See |mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                *MiniStatusline-example-content*\nExample content\n\n# Default content ~\n\nThis function is used as default value for active content: >lua\n\n  function()\n    local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 })\n    local git           = MiniStatusline.section_git({ trunc_width = 40 })\n    local diff          = MiniStatusline.section_diff({ trunc_width = 75 })\n    local diagnostics   = MiniStatusline.section_diagnostics({ trunc_width = 75 })\n    local lsp           = MiniStatusline.section_lsp({ trunc_width = 75 })\n    local filename      = MiniStatusline.section_filename({ trunc_width = 140 })\n    local fileinfo      = MiniStatusline.section_fileinfo({ trunc_width = 120 })\n    local location      = MiniStatusline.section_location({ trunc_width = 75 })\n    local search        = MiniStatusline.section_searchcount({ trunc_width = 75 })\n\n    return MiniStatusline.combine_groups({\n      { hl = mode_hl,                  strings = { mode } },\n      { hl = 'MiniStatuslineDevinfo',  strings = { git, diff, diagnostics, lsp } },\n      '%<', -- Mark general truncate point\n      { hl = 'MiniStatuslineFilename', strings = { filename } },\n      '%=', -- End left alignment\n      { hl = 'MiniStatuslineFileinfo', strings = { fileinfo } },\n      { hl = mode_hl,                  strings = { search, location } },\n    })\n  end\n<\n# Show boolean options ~\n\nTo compute section string for boolean option use variation of this code\nsnippet inside content function (you can modify option itself, truncation\nwidth, short and long displayed names): >lua\n\n  local spell = vim.wo.spell and (MiniStatusline.is_truncated(120) and 'S' or 'SPELL') or ''\n<\nHere `x and y or z` is a common Lua way of doing ternary operator: if `x`\nis `true`-ish then return `y`, if not - return `z`.\n\n------------------------------------------------------------------------------\n                                                        *MiniStatusline.setup()*\n                        `MiniStatusline.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniStatusline.config|.\n\nUsage ~\n>lua\n  require('mini.statusline').setup() -- use default config\n  -- OR\n  require('mini.statusline').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                         *MiniStatusline.config*\n                            `MiniStatusline.config`\nDefaults ~\n>lua\n  MiniStatusline.config = {\n    -- Content of statusline as functions which return statusline string. See\n    -- `:h statusline` and code of default contents (used instead of `nil`).\n    content = {\n      -- Content for active window\n      active = nil,\n      -- Content for inactive window(s)\n      inactive = nil,\n    },\n\n    -- Whether to use icons by default\n    use_icons = true,\n  }\n<\n------------------------------------------------------------------------------\n                                                       *MiniStatusline.active()*\n                           `MiniStatusline.active`()\nCompute content for active window\n\n------------------------------------------------------------------------------\n                                                     *MiniStatusline.inactive()*\n                          `MiniStatusline.inactive`()\nCompute content for inactive window\n\n------------------------------------------------------------------------------\n                                               *MiniStatusline.combine_groups()*\n                   `MiniStatusline.combine_groups`({groups})\nCombine groups of sections\n\nEach group can be either a string or a table with fields `hl` (group's\nhighlight group) and `strings` (strings representing sections).\n\nGeneral idea of this function is as follows;\n- String group is used as is (useful for special strings like `%<` or `%=`).\n- Each table group has own highlighting in `hl` field (if missing, the\n  previous one is used) and string parts in `strings` field. Non-empty\n  strings from `strings` are separated by one space. Non-empty groups are\n  separated by two spaces (one for each highlighting).\n\nParameters ~\n{groups} `(table)` Array of groups.\n\nReturn ~\n`(string)` String suitable for 'statusline'.\n\n------------------------------------------------------------------------------\n                                                 *MiniStatusline.is_truncated()*\n                  `MiniStatusline.is_truncated`({trunc_width})\nDecide whether to truncate\n\nThis basically computes window width and compares it to `trunc_width`: if\nwindow is smaller then truncate; otherwise don't. Don't truncate by\ndefault.\n\nUse this to manually decide if section needs truncation or not.\n\nParameters ~\n{trunc_width} `(number|nil)` Truncation width. If `nil`, output is `false`.\n\nReturn ~\n`(boolean)` Whether to truncate.\n\n------------------------------------------------------------------------------\n                                                 *MiniStatusline.section_mode()*\n                     `MiniStatusline.section_mode`({args})\nSection for Vim |mode()|\n\nShort output is returned if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments.\n\nReturn ~\n`(...)` Section string and mode's highlight group.\n\n------------------------------------------------------------------------------\n                                                  *MiniStatusline.section_git()*\n                      `MiniStatusline.section_git`({args})\nSection for Git information\n\nShows Git summary from |mini.git| (should be set up; recommended). To tweak\nformatting of what data is shown, modify buffer-local summary string directly\nas described in |MiniGit-examples|.\n\nIf 'mini.git' is not set up, section falls back on 'lewis6991/gitsigns' data\nor showing empty string.\n\nEmpty string is returned if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments. Use `args.icon` to supply your own icon.\n\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                                 *MiniStatusline.section_diff()*\n                     `MiniStatusline.section_diff`({args})\nSection for diff information\n\nShows diff summary from |mini.diff| (should be set up; recommended). To tweak\nformatting of what data is shown, modify buffer-local summary string directly\nas described in |MiniDiff-diff-summary|.\n\nIf 'mini.diff' is not set up, section falls back on 'lewis6991/gitsigns' data\nor showing empty string.\n\nEmpty string is returned if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments. Use `args.icon` to supply your own icon.\n\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                          *MiniStatusline.section_diagnostics()*\n                  `MiniStatusline.section_diagnostics`({args})\nSection for Neovim's builtin diagnostics\n\nShows nothing if diagnostics is disabled, no diagnostic is set, or for short\noutput. Otherwise uses |vim.diagnostic.get()| to compute and show number of\nerrors ('E'), warnings ('W'), information ('I'), and hints ('H').\n\nShort output is returned if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments. Use `args.icon` to supply your own icon.\n  Use `args.signs` to use custom signs per severity level name. For example: >lua\n\n  { ERROR = '!', WARN = '?', INFO = '@', HINT = '*' }\n<\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                                  *MiniStatusline.section_lsp()*\n                      `MiniStatusline.section_lsp`({args})\nSection for attached LSP servers\n\nShows number of LSP servers (each as separate \"+\" character) attached to\ncurrent buffer or nothing if none is attached.\nNothing is shown if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments. Use `args.icon` to supply your own icon.\n\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                             *MiniStatusline.section_filename()*\n                   `MiniStatusline.section_filename`({args})\nSection for file name\n\nShow full file name or relative in short output.\n\nShort output is returned if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments.\n\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                             *MiniStatusline.section_fileinfo()*\n                   `MiniStatusline.section_fileinfo`({args})\nSection for file information\n\nShows 'filetype', 'fileencoding' / 'encoding', 'fileformat', and buffer size.\nShort output has only non-empty 'filetype' and is returned if window width is\nlower than `args.trunc_width` or buffer is not normal (as per 'buftype').\n\nBuffer size is computed based on current text, not file's saved version.\n\nIf `config.use_icons` is true and icon provider is present (see\n\"Dependencies\" section in |mini.statusline|), shows icon near the filetype.\n\nParameters ~\n{args} `(table)` Section arguments.\n\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                             *MiniStatusline.section_location()*\n                   `MiniStatusline.section_location`({args})\nSection for location inside buffer\n\nShow location inside buffer in the form:\n- Normal: `'<cursor line>|<total lines>│<cursor column>|<total columns>'`\n- Short: `'<cursor line>│<cursor column>'`\n\nShort output is returned if window width is lower than `args.trunc_width`.\n\nParameters ~\n{args} `(table)` Section arguments.\n\nReturn ~\n`(string)` Section string.\n\n------------------------------------------------------------------------------\n                                          *MiniStatusline.section_searchcount()*\n                  `MiniStatusline.section_searchcount`({args})\nSection for current search count\n\nShow the current status of |searchcount()|. Empty output is returned if\nwindow width is lower than `args.trunc_width`, search highlighting is not\non (see |v:hlsearch|), or if number of search result is 0.\n\n`args.options` is forwarded to |searchcount()|. By default it recomputes\ndata on every call which can be computationally expensive (although still\nusually on 0.1 ms order of magnitude). To prevent this, supply\n`args.options = { recompute = false }`.\n\nParameters ~\n{args} `(table)` Section arguments.\n\nReturn ~\n`(string)` Section string.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-surround.txt",
    "content": "*mini.surround* Surround actions\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                  *MiniSurround*\nFast and feature-rich surrounding. Can be configured to have experience\nsimilar to [tpope/vim-surround](https://github.com/tpope/vim-surround)\n(see |MiniSurround-vim-surround-config|).\n\nFeatures:\n- Actions (text editing actions are dot-repeatable out of the box and\n  respect |[count]|) with configurable mappings:\n    - Add surrounding with `sa` (in visual mode or on motion).\n    - Delete surrounding with `sd`.\n    - Replace surrounding with `sr`.\n    - Find surrounding with `sf` or `sF` (move cursor right or left).\n    - Highlight surrounding with `sh`.\n\n- Surrounding is identified by a single character as both \"input\" (in\n  `delete` and `replace` start, `find`, and `highlight`) and \"output\" (in\n  `add` and `replace` end):\n    - 'f' - function call (string of alphanumeric symbols or '_' or '.'\n      followed by balanced '()'). In \"input\" finds function call, in\n      \"output\" prompts user to enter function name.\n    - 't' - tag. In \"input\" finds tag with same identifier, in \"output\"\n      prompts user to enter tag name with possible attributes.\n    - All symbols in brackets '()', '[]', '{}', '<>\". In \"input' represents\n      balanced brackets (open - with whitespace pad, close - without), in\n      \"output\" - left and right parts of brackets.\n    - '?' - interactive. Prompts user to enter left and right parts.\n    - All other single character identifiers (supported by |getcharstr()|)\n      represent surrounding with identical left and right parts.\n\n- Configurable search methods to find not only covering but possibly next,\n  previous, or nearest surrounding. See more in |MiniSurround.config|.\n\n- All actions involving finding surrounding (delete, replace, find,\n  highlight) can be used with suffix that changes search method to find\n  previous/last. See more in |MiniSurround.config|.\n\nKnown issues which won't be resolved:\n- Search for surrounding is done using Lua patterns (regex-like approach).\n  So certain amount of false positives should be expected.\n\n- When searching for \"input\" surrounding, there is no distinction if it is\n  inside string or comment. So in this case there will be not proper match\n  for a function call: 'f(a = \")\", b = 1)'.\n\n- Tags are searched using regex-like methods, so issues are inevitable.\n  Overall it is pretty good, but certain cases won't work. Like self-nested\n  tags won't match correctly on both ends: '<a><a></a></a>'.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.surround').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniSurround` which you can use for scripting or manually (with\n`:lua MiniSurround.*`).\n\nSee |MiniSurround.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minisurround_config` which should have same structure as\n`MiniSurround.config`. See |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Example usage ~\n\nRegular mappings:\n- `saiw)` - add (`sa`) for inner word (`iw`) parenthesis (`)`).\n- `saiw?[[<CR>]]<CR>` - add (`sa`) for inner word (`iw`) interactive\n  surrounding (`?`): `[[` for left and `]]` for right.\n- `2sdf` - delete (`sd`) second (`2`) surrounding function call (`f`).\n- `sr)tdiv<CR>` - replace (`sr`) surrounding parenthesis (`)`) with tag\n  (`t`) with identifier 'div' (`div<CR>` in command line prompt).\n- `sff` - find right (`sf`) part of surrounding function call (`f`).\n- `sh}` - highlight (`sh`) for a brief period of time surrounding curly\n  brackets (`}`).\n\nExtended mappings (temporary force \"prev\"/\"next\" search methods):\n- `sdnf` - delete (`sd`) next (`n`) function call (`f`).\n- `srlf(` - replace (`sr`) last (`l`) function call (`f`) with padded\n  bracket (`(`).\n- `2sfnt` - find (`sf`) second (`2`) next (`n`) tag (`t`).\n- `2shl}` - highlight (`sh`) last (`l`) second (`2`) curly bracket (`}`).\n\n# Comparisons ~\n\n- [tpope/vim-surround](https://github.com/tpope/vim-surround):\n    - 'vim-surround' has completely different, with other focus set of\n      default mappings, while 'mini.surround' has a more coherent set.\n    - 'mini.surround' supports dot-repeat, customized search path (see\n      |MiniSurround.config|), customized specifications (see\n      |MiniSurround-surrounding-specification|) allowing usage of tree-sitter\n      queries (see |MiniSurround.gen_spec.input.treesitter()|),\n      highlighting and finding surrounding, \"last\"/\"next\" extended\n      mappings. While 'vim-surround' does not.\n- [machakann/vim-sandwich](https://github.com/machakann/vim-sandwich):\n    - Both have same keybindings for common actions (add, delete, replace).\n    - Otherwise same differences as with 'tpope/vim-surround' (except\n      dot-repeat because 'vim-sandwich' supports it).\n- [kylechui/nvim-surround](https://github.com/kylechui/nvim-surround):\n    - 'nvim-surround' is designed after 'tpope/vim-surround' with same\n      default mappings and logic, while 'mini.surround' has mappings\n      similar to 'machakann/vim-sandwich'.\n    - 'mini.surround' has more flexible customization of input surrounding\n      (with composed patterns, region pair(s), search methods).\n    - 'mini.surround' supports |[count]| in both input and output\n      surrounding (see |MiniSurround-count-with-actions|) while\n      'nvim-surround' doesn't.\n    - 'mini.surround' supports \"last\"/\"next\" extended mappings.\n- |mini.ai|:\n    - Both use similar logic for finding target: textobject in 'mini.ai'\n      and surrounding pair in 'mini.surround'. While 'mini.ai' uses\n      extraction pattern for separate `a` and `i` textobjects,\n      'mini.surround' uses it to select left and right surroundings\n      (basically a difference between `a` and `i` textobjects).\n    - Some builtin specifications are slightly different:\n        - Quotes in 'mini.ai' are balanced, in 'mini.surround' they are not.\n        - The 'mini.surround' doesn't have argument surrounding.\n        - Default behavior in 'mini.ai' selects one of the edges into `a`\n          textobject, while 'mini.surround' - both.\n\n# Highlight groups ~\n\n- `MiniSurround` - highlighting of requested surrounding.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minisurround_disable` (globally) or\n`vim.b.minisurround_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                             *MiniSurround-builtin-surroundings*\nThis table describes all builtin surroundings along with what they\nrepresent. Explanation:\n- `Key` represents the surrounding identifier: single character which should\n  be typed after action mappings (see \"Mappings\" in |MiniSurround.config|).\n- `Name` is a description of surrounding.\n- `Example line` contains a string for which examples are constructed. The\n  `*` denotes the cursor position over `a` character.\n- `Delete` shows the result of typing `sd` followed by surrounding identifier.\n  It aims to demonstrate \"input\" surrounding which is also used in replace\n  with `sr` (surrounding id is typed first), highlight with `sh`, find with\n  `sf` and `sF`.\n- `Replace` shows the result of typing `sr!` followed by surrounding\n  identifier (with possible follow up from user). It aims to demonstrate\n  \"output\" surrounding which is also used in adding with `sa` (followed by\n  textobject/motion or in Visual mode).\n\nExample: typing `sd)` with cursor on `*` (covers `a` character) changes line\n`!( *a (bb) )!` into `! aa (bb) !`. Typing `sr!)` changes same initial line\ninto `(( aa (bb) ))`.\n>\n ┌───┬───────────────┬───────────────┬─────────────┬─────────────────┐\n │Key│     Name      │  Example line │    Delete   │     Replace     │\n ├───┴───────────────┴───────────────┴─────────────┴─────────────────┤\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ ( │  Balanced ()  │ !( *a (bb) )! │  !aa (bb)!  │ ( ( aa (bb) ) ) │\n │ [ │  Balanced []  │ ![ *a [bb] ]! │  !aa [bb]!  │ [ [ aa [bb] ] ] │\n │ { │  Balanced {}  │ !{ *a {bb} }! │  !aa {bb}!  │ { { aa {bb} } } │\n │ < │  Balanced <>  │ !< *a <bb> >! │  !aa <bb>!  │ < < aa <bb> > > │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ ) │  Balanced ()  │ !( *a (bb) )! │ ! aa (bb) ! │ (( aa (bb) ))   │\n │ ] │  Balanced []  │ ![ *a [bb] ]! │ ! aa [bb] ! │ [[ aa [bb] ]]   │\n │ } │  Balanced {}  │ !{ *a {bb} }! │ ! aa {bb} ! │ {{ aa {bb} }}   │\n │ > │  Balanced <>  │ !< *a <bb> >! │ ! aa <bb> ! │ << aa <bb> >>   │\n │ b │  Alias for    │ !( *a {bb} )! │ ! aa {bb} ! │ (( aa {bb} ))   │\n │   │  ), ], or }   │               │             │                 │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ q │  Alias for    │ !'aa'*a'aa'!  │ !'aaaaaa'!  │ \"'aa'aa'aa'\"    │\n │   │  \", ', or `   │               │             │                 │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ ? │  User prompt  │ !e * o!       │ ! a !       │ ee a oo         │\n │   │(typed e and o)│               │             │                 │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ t │      Tag      │ !<x>*</x>!    │ !a!         │ <y><x>a</x></y> │\n │   │               │               │             │ (typed y)       │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │ f │ Function call │ !f(*a, bb)!   │ !aa, bb!    │ g(f(*a, bb))    │\n │   │               │               │             │ (typed g)       │\n ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n │   │    Default    │ !_a*a_!       │ !aaa!       │ __aaa__         │\n │   │   (typed _)   │               │             │                 │\n └┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘\n<\nNotes:\n- All examples assume default `config.search_method`.\n- Open brackets differ from close brackets by how they treat inner edge\n  whitespace: open includes it left and right parts, close does not.\n- Output value of `b` alias is same as `)`. For `q` alias - same as `\"`.\n- Default surrounding is activated for all characters which are not\n  configured surrounding identifiers. Notes:\n    - Due to special handling of underlying `x.-x` Lua pattern\n      (see |MiniSurround-search-algorithm|), it doesn't really support\n      non-trivial `[count]` for \"cover\" search method.\n    - When cursor is exactly on the identifier character while there are\n      two matching candidates on both left and right, the one resulting in\n      region with smaller width is preferred.\n\n------------------------------------------------------------------------------\n                                                         *MiniSurround-glossary*\nNote: this is similar to |MiniAi-glossary|.\n\nREGION ~\nTable representing region in a buffer. Fields: <from> and <to> for\ninclusive start and end positions (<to> might be `nil` to describe empty\nregion). Each position is also a table with line <line> and column <col>\n(both start at 1). Examples: >lua\n\n  { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }\n\n  -- Empty region\n  { from = { line = 10, col = 10 } }\n<\nREGION PAIR ~\nTable representing regions for left and right surroundings. Fields: <left>\nand <right> with regions. Example: >lua\n\n  {\n    left  = { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } },\n    right = { from = { line = 1, col = 3 } },\n  }\n<\nPATTERN ~\nString describing Lua pattern.\n\nSPAN ~\nInterval inside a string (end-exclusive). Like [1, 5). Equal `from` and `to` edges\ndescribe empty span at that point.\n\nSpan `A = [a1, a2)` covers `B = [b1, b2)` if every element of `B` is within\n`A` (`a1 <= b < a2`). It also is described as \"B is nested inside A\".\n\nNESTED PATTERN ~\nArray of patterns aimed to describe nested spans.\n\nSPAN MATCHES NESTED PATTERN ~\nIf there is a sequence of consecutively nested spans each matching\ncorresponding pattern within substring of previous span (or input string\nfor first span). Example: >lua\n\n  -- Nested patterns for balanced `()` with inner space\n  { '%b()', '^. .* .$' }\n\n  -- Example input string (with columns underneath for easier reading):\n     \"( ( () ( ) ) )\"\n  --  12345678901234\n<\nHere are all matching spans [1, 15) and [3, 13). Both [5, 7) and [8, 10)\nmatch first pattern but not second. All other combinations of `(` and `)`\ndon't match first pattern (not balanced).\n\nCOMPOSED PATTERN ~\nArray with each element describing possible pattern (or array of them) at\nthat place. Composed pattern basically defines all possible combinations of\nnested pattern (their cartesian product). Examples:\n\n1. Either balanced `()` or balanced `[]` but both with inner edge space: >lua\n\n    -- Composed pattern\n    { { '%b()', '%b[]' }, '^. .* .$' }\n\n    -- Composed pattern expanded into equivalent array of nested patterns\n    { '%b()', '^. .* .$' } -- and\n    { '%b[]', '^. .* .$' }\n<\n2. Either \"balanced `()` with inner edge space\" or \"balanced `[]` with no\n   inner edge space\", both with 5 or more characters: >lua\n\n    -- Composed pattern\n    { { { '%b()', '^. .* .$' }, { '%b[]', '^.[^ ].*[^ ].$' } }, '.....' }\n\n    -- Composed pattern expanded into equivalent array of nested patterns\n    { '%b()', '^. .* .$', '.....' } -- and\n    { '%b[]', '^.[^ ].*[^ ].$', '.....' }\n<\nSPAN MATCHES COMPOSED PATTERN ~\nIf it matches at least one nested pattern from expanded composed pattern.\n\n------------------------------------------------------------------------------\n                                        *MiniSurround-surrounding-specification*\nSurround specification is a table with keys:\n- <input> - defines how to find and extract surrounding for \"input\"\n  operations (like `delete`). See more in \"Input surrounding\" section.\n- <output> - defines what to add on left and right for \"output\" operations\n  (like `add`). See more in \"Output surrounding\" section.\n\nExample of surround info for builtin `)` identifier: >lua\n\n  {\n    input = { '%b()', '^.().*().$' },\n    output = { left = '(', right = ')' }\n  }\n<\n# Input surrounding ~\n\nSpecification for input surrounding has a structure of composed pattern\n(see |MiniSurround-glossary|) with two differences:\n- Last pattern(s) should have two or four empty capture groups denoting\n  how the last string should be processed to extract surrounding parts:\n    - Two captures represent left part from start of string to first\n      capture and right part - from second capture to end of string.\n      Example: `a()b()c` defines left surrounding as 'a', right - 'c'.\n    - Four captures define left part inside captures 1 and 2, right part -\n      inside captures 3 and 4. Example: `a()()b()c()` defines left part as\n      empty, right part as 'c'.\n- Allows callable objects (see |vim.is_callable()|) in certain places\n  (enables more complex surroundings in exchange of increase in configuration\n  complexity and computations):\n    - If specification itself is a callable, it will be called without\n      arguments and should return one of:\n        - Composed pattern. Useful for implementing user input. Example of\n          simplified variant of input surrounding for function call with\n          name taken from user prompt: >lua\n\n            function()\n              local left_edge = vim.pesc(vim.fn.input('Function name: '))\n              return { left_edge .. '%b()', '^.-%(().*()%)$' }\n            end\n<\n        - Single region pair (see |MiniSurround-glossary|). Useful to allow\n          full control over surrounding. Will be taken as is. Example of\n          returning first and last lines of a buffer: >lua\n\n            function()\n              local n_lines = vim.fn.line('$')\n              return {\n                left = {\n                  from = { line = 1, col = 1 },\n                  to = { line = 1, col = vim.fn.getline(1):len() }\n                },\n                right = {\n                  from = { line = n_lines, col = 1 },\n                  to = { line = n_lines, col = vim.fn.getline(n_lines):len() }\n                },\n              }\n            end\n<\n        - Array of region pairs. Useful for incorporating other instruments,\n          like treesitter (see |MiniSurround.gen_spec.input.treesitter()|). The\n          best region pair will be picked in the same manner as with composed\n          pattern (respecting options `n_lines`, `search_method`, etc.) using\n          output region (from start of left region to end of right region).\n          Example using edges of \"best\" line with display width more than 80: >lua\n\n            function()\n              local make_line_region_pair = function(n)\n                local left = { line = n, col = 1 }\n                local right = { line = n, col = vim.fn.getline(n):len() }\n                return {\n                  left = { from = left, to = left },\n                  right = { from = right, to = right },\n                }\n              end\n\n              local res = {}\n              for i = 1, vim.fn.line('$') do\n                if vim.fn.getline(i):len() > 80 then\n                  table.insert(res, make_line_region_pair(i))\n                end\n              end\n              return res\n            end\n<\n    - If there is a callable instead of assumed string pattern, it is expected\n      to have signature `(line, init)` and behave like `pattern:find()`.\n      It should return two numbers representing span in `line` next after\n      or at `init` (`nil` if there is no such span).\n      !IMPORTANT NOTE!: it means that output's `from` shouldn't be strictly\n      to the left of `init` (it will lead to infinite loop). Not allowed as\n      last item (as it should be pattern with captures).\n      Example of matching only balanced parenthesis with big enough width: >lua\n\n        {\n          '%b()',\n          function(s, init)\n            if init > 1 or s:len() < 5 then return end\n            return 1, s:len()\n          end,\n          '^.().*().$'\n        }\n<\nMore examples: >lua\n\n  -- Pair of balanced brackets from set (used for builtin `b` identifier)\n  { { '%b()', '%b[]', '%b{}' }, '^.().*().$' }\n\n  -- Lua block string\n  { '%[%[().-()%]%]' }\n<\nSee |MiniSurround.gen_spec| for function wrappers to create commonly used\nsurrounding specifications.\n\n# Output surrounding ~\n\nSpecification for output can be either a table with <left> and <right> fields,\nor a callable returning such table (will be called with no arguments).\nStrings can contain new lines character \"\\n\" to add multiline parts.\n\nExamples: >lua\n\n  -- Lua block string\n  { left = '[[', right = ']]' }\n\n  -- Brackets on separate lines (indentation is not preserved)\n  { left = '(\\n', right = '\\n)' }\n\n  -- Function call\n  function()\n    local function_name = MiniSurround.user_input('Function name')\n    return { left = function_name .. '(', right = ')' }\n  end\n<\n------------------------------------------------------------------------------\n                                               *MiniSurround-count-with-actions*\n|[count]| is supported by all actions in the following ways:\n\n- In add, two types of `[count]` is supported in Normal mode:\n  `[count1]sa[count2][textobject]`. The `[count1]` defines how many times\n  left and right parts of output surrounding will be repeated and `[count2]` is\n  used for textobject.\n  In Visual mode `[count]` is treated as `[count1]`.\n  Example: `2sa3aw)` and `v3aw2sa)` will result into textobject `3aw` being\n  surrounded by `((` and `))`.\n\n- In delete/replace/find/highlight `[count]` means \"find n-th surrounding\n  and execute operator on it\".\n  Example: `2sd)` on line `(a(b(c)b)a)` with cursor on `c` will result into\n  `(ab(c)ba)` (and not in `(abcba)` if it would have meant \"delete n times\").\n\n------------------------------------------------------------------------------\n                                                 *MiniSurround-search-algorithm*\nSearch for the input surrounding relies on these principles:\n- Input surrounding specification is constructed based on surrounding\n  identifier (see |MiniSurround-surrounding-specification|).\n- General search is done by converting some 2d buffer region (neighborhood\n  of reference region) into 1d string (each line is appended with `\\n`).\n  Then search for a best span matching specification is done inside string\n  (see |MiniSurround-glossary|). After that, span is converted back into 2d\n  region. Note: first search is done inside reference region lines, and\n  only after that - inside its neighborhood within `config.n_lines` (see\n  |MiniSurround.config|).\n- The best matching span is chosen by iterating over all spans matching\n  surrounding specification and comparing them with \"current best\".\n  Comparison also depends on reference region (tighter covering is better,\n  otherwise closer is better) and search method (if span is even considered).\n- Extract pair of spans (for left and right regions in region pair) based\n  on extraction pattern (last item in nested pattern).\n- For |[count]| greater than 1, steps are repeated with current best match\n  becoming reference region. One such additional step is also done if final\n  region is equal to reference region.\n\nNotes:\n- Iteration over all matched spans is done in depth-first fashion with\n  respect to nested pattern.\n- It is guaranteed that span is compared only once.\n- For the sake of increasing functionality, during iteration over all\n  matching spans, some Lua patterns in composed pattern are handled\n  specially.\n    - `%bxx` (`xx` is two identical characters). It denotes balanced pair\n      of identical characters and results into \"paired\" matches. For\n      example, `%b\"\"` for `\"aa\" \"bb\"` would match `\"aa\"` and `\"bb\"`, but\n      not middle `\" \"`.\n    - `x.-y` (`x` and `y` are different strings). It results only in matches with\n      smallest width. For example, `e.-o` for `e e o o` will result only in\n      middle `e o`. Note: it has some implications for when parts have\n      quantifiers (like `+`, etc.), which usually can be resolved with\n      frontier pattern `%f[]`.\n\n------------------------------------------------------------------------------\n                                                          *MiniSurround.setup()*\n                         `MiniSurround.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniSurround.config|.\n\nUsage ~\n>lua\n  require('mini.surround').setup() -- use default config\n  -- OR\n  require('mini.surround').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                           *MiniSurround.config*\n                             `MiniSurround.config`\nDefaults ~\n>lua\n  MiniSurround.config = {\n    -- Add custom surroundings to be used on top of builtin ones. For more\n    -- information with examples, see `:h MiniSurround.config`.\n    custom_surroundings = nil,\n\n    -- Duration (in ms) of highlight when calling `MiniSurround.highlight()`\n    highlight_duration = 500,\n\n    -- Module mappings. Use `''` (empty string) to disable one.\n    mappings = {\n      add = 'sa', -- Add surrounding in Normal and Visual modes\n      delete = 'sd', -- Delete surrounding\n      find = 'sf', -- Find surrounding (to the right)\n      find_left = 'sF', -- Find surrounding (to the left)\n      highlight = 'sh', -- Highlight surrounding\n      replace = 'sr', -- Replace surrounding\n\n      suffix_last = 'l', -- Suffix to search with \"prev\" method\n      suffix_next = 'n', -- Suffix to search with \"next\" method\n    },\n\n    -- Number of lines within which surrounding is searched\n    n_lines = 20,\n\n    -- Whether to respect selection type:\n    -- - Place surroundings on separate lines in linewise mode.\n    -- - Place surroundings on each line in blockwise mode.\n    respect_selection_type = false,\n\n    -- How to search for surrounding (first inside current line, then inside\n    -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev',\n    -- 'cover_or_nearest', 'next', 'prev', 'nearest'. For more details,\n    -- see `:h MiniSurround.config`.\n    search_method = 'cover',\n\n    -- Whether to disable showing non-error feedback\n    -- This also affects (purely informational) helper messages shown after\n    -- idle time if user input is required.\n    silent = false,\n  }\n<\n# Mappings ~\n\n`config.mappings` defines what mappings are set up for particular actions.\nBy default it uses \"prefix style\" left hand side starting with \"s\" (for\n\"surround\"): `sa` - \"surround add\", `sd` - \"surround delete\", etc.\n\nNote: if any of the mappings start with \"s\" (as is by default), it is mapped\nto |<Nop>| to prevent accidental trigger of built-in |s| (can happen if there\nis a long enough delay between pressing \"s\" and the next key). Use `cl` instead.\n\n# Custom surroundings ~\n\nUser can define own surroundings by supplying `config.custom_surroundings`.\nIt should be a **table** with keys being single character surrounding\nidentifier (supported by |getcharstr()|) and values - surround specification\n(see |MiniSurround-surrounding-specification|).\n\nGeneral recommendations:\n- In `config.custom_surroundings` only some data can be defined (like only\n  `output`). Other fields will be taken from builtin surroundings.\n- Function returning surround info at <input> or <output> fields of\n  specification is helpful when user input is needed (like asking for\n  function name). Use |input()| or |MiniSurround.user_input()|. Return\n  `nil` to stop any current surround operation.\n- Keys should use character representation which can be |getcharstr()| output.\n  For example, `'\\r'` and not `'<CR>'`.\n\nExamples of using `config.custom_surroundings` (see more examples at\n|MiniSurround.gen_spec|): >lua\n\n  local surround = require('mini.surround')\n  surround.setup({\n    custom_surroundings = {\n      -- Make `)` insert parts with spaces. `input` pattern stays the same.\n      [')'] = { output = { left = '( ', right = ' )' } },\n\n      -- Use function to compute surrounding info\n      ['*'] = {\n        input = function()\n          local n_star = MiniSurround.user_input('Number of * to find')\n          local many_star = string.rep('%*', tonumber(n_star) or 1)\n          return { many_star .. '().-()' .. many_star }\n        end,\n        output = function()\n          local n_star = MiniSurround.user_input('Number of * to output')\n          local many_star = string.rep('*', tonumber(n_star) or 1)\n          return { left = many_star, right = many_star }\n        end,\n      },\n    },\n  })\n\n  -- Create custom surrounding for Lua's block string `[[...]]`\n  -- Use this inside autocommand or 'after/ftplugin/lua.lua' file\n  vim.b.minisurround_config = {\n    custom_surroundings = {\n      s = {\n        input = { '%[%[().-()%]%]' },\n        output = { left = '[[', right = ']]' },\n      },\n    },\n  }\n<\n# Respect selection type ~\n\nBoolean option `config.respect_selection_type` controls whether to respect\nselection type when adding and deleting surrounding. When enabled:\n- Linewise adding places surroundings on separate lines while indenting\n  surrounded lines ones.\n- Deleting surroundings which look like they were the result of linewise\n  adding will act to revert it: delete lines with surroundings and dedent\n  surrounded lines ones.\n- Blockwise adding places surroundings on whole edges, not only start and\n  end of selection. Note: it doesn't really work outside of text and in\n  presence of multibyte characters; and probably won't due to\n  implementation difficulties.\n\n# Search method ~\n\nValue of `config.search_method` defines how best match search is done.\nBased on its value, one of the following matches will be selected:\n- Covering match. Left/right edge is before/after left/right edge of\n  reference region.\n- Previous match. Left/right edge is before left/right edge of reference\n  region.\n- Next match. Left/right edge is after left/right edge of reference region.\n- Nearest match. Whichever is closest among previous and next matches.\n\nPossible values are:\n- `'cover'` (default) - use only covering match. Don't use either previous or\n  next; report that there is no surrounding found.\n- `'cover_or_next'` - use covering match. If not found, use next.\n- `'cover_or_prev'` - use covering match. If not found, use previous.\n- `'cover_or_nearest'` - use covering match. If not found, use nearest.\n- `'next'` - use next match.\n- `'previous'` - use previous match.\n- `'nearest'` - use nearest match.\n\nNote: search is first performed on the reference region lines and only\nafter failure - on the whole neighborhood defined by `config.n_lines`. This\nmeans that with `config.search_method` not equal to `'cover'`, \"previous\"\nor \"next\" surrounding will end up as search result if they are found on\nfirst stage although covering match might be found in bigger, whole\nneighborhood. This design is based on observation that most of the time\noperation is done within reference region lines (usually cursor line).\n\nHere is an example of how replacing `)` with `]` surrounding is done based\non a value of `'config.search_method'` when cursor is inside `bbb` word:\n- `'cover'`:         `(a) bbb (c)` -> `(a) bbb (c)` (with message)\n- `'cover_or_next'`: `(a) bbb (c)` -> `(a) bbb [c]`\n- `'cover_or_prev'`: `(a) bbb (c)` -> `[a] bbb (c)`\n- `'cover_or_nearest'`: depends on cursor position.\n  For first and second `b` - as in `cover_or_prev` (as previous match is\n  nearer), for third - as in `cover_or_next` (as next match is nearer).\n- `'next'`:          `(a) bbb (c)` -> `(a) bbb [c]`. Same outcome for `(bbb)`.\n- `'prev'`:          `(a) bbb (c)` -> `[a] bbb (c)`. Same outcome for `(bbb)`.\n- `'nearest'`: depends on cursor position (same as in `'cover_or_nearest'`).\n\n# Search suffixes ~\n\nTo provide more searching possibilities, 'mini.surround' creates extended\nmappings force \"prev\" and \"next\" methods for particular search. It does so\nby appending mapping with certain suffix: `config.mappings.suffix_last` for\nmappings which will use \"prev\" search method, `config.mappings.suffix_next`\n- \"next\" search method.\n\nNotes:\n- It creates new mappings only for actions involving surrounding search:\n  delete, replace, find (right and left), highlight.\n- All new mappings behave the same way as if `config.search_method` is set\n  to certain search method. They preserve dot-repeat support, respect |[count]|.\n- Supply empty string to disable creation of corresponding set of mappings.\n\nExample with default values (`n` for `suffix_next`, `l` for `suffix_last`)\nand initial line `(aa) (bb) (cc)`.\n- Typing `sdn)` with cursor inside `(aa)` results into `(aa) bb (cc)`.\n- Typing `sdl)` with cursor inside `(cc)` results into `(aa) bb (cc)`.\n- Typing `2srn)]` with cursor inside `(aa)` results into `(aa) (bb) [cc]`.\n\n# Setup similar to 'tpope/vim-surround' ~\n*MiniSurround-vim-surround-config*\n\nThis module is primarily designed after 'machakann/vim-sandwich'. To get\nbehavior closest to 'tpope/vim-surround' (but not identical), use this setup: >lua\n\n  require('mini.surround').setup({\n    mappings = {\n      add = 'ys',\n      delete = 'ds',\n      find = '',\n      find_left = '',\n      highlight = '',\n      replace = 'cs',\n\n      -- Add this only if you don't want to use extended mappings\n      suffix_last = '',\n      suffix_next = '',\n    },\n    search_method = 'cover_or_next',\n  })\n\n  -- Remap adding surrounding to Visual mode selection\n  vim.keymap.del('x', 'ys')\n  vim.keymap.set('x', 'S', [[:<C-u>lua MiniSurround.add('visual')<CR>]], { silent = true })\n\n  -- Make special mapping for \"add surrounding for line\"\n  vim.keymap.set('n', 'yss', 'ys_', { remap = true })\n<\n------------------------------------------------------------------------------\n                                                            *MiniSurround.add()*\n                           `MiniSurround.add`({mode})\nAdd surrounding\n\nNo need to use it directly, everything is setup in |MiniSurround.setup()|.\n\nParameters ~\n{mode} `(string)` Mapping mode (normal by default).\n\n------------------------------------------------------------------------------\n                                                         *MiniSurround.delete()*\n                            `MiniSurround.delete`()\nDelete surrounding\n\nNo need to use it directly, everything is setup in |MiniSurround.setup()|.\n\n------------------------------------------------------------------------------\n                                                        *MiniSurround.replace()*\n                            `MiniSurround.replace`()\nReplace surrounding\n\nNo need to use it directly, everything is setup in |MiniSurround.setup()|.\n\n------------------------------------------------------------------------------\n                                                           *MiniSurround.find()*\n                             `MiniSurround.find`()\nFind surrounding\n\nNo need to use it directly, everything is setup in |MiniSurround.setup()|.\n\n------------------------------------------------------------------------------\n                                                      *MiniSurround.highlight()*\n                           `MiniSurround.highlight`()\nHighlight surrounding\n\nNo need to use it directly, everything is setup in |MiniSurround.setup()|.\n\n------------------------------------------------------------------------------\n                                                 *MiniSurround.update_n_lines()*\n                        `MiniSurround.update_n_lines`()\nUpdate `MiniSurround.config.n_lines` from user input\n\nMapping example: >lua\n\n  vim.keymap.set('n', 'sn', '<Cmd>lua MiniSurround.update_n_lines()<CR>')\n<\n------------------------------------------------------------------------------\n                                                     *MiniSurround.user_input()*\n                  `MiniSurround.user_input`({prompt}, {text})\nAsk user for input\n\nThis is mainly a wrapper for |input()| which allows empty string as input,\ncancelling with `<Esc>` and `<C-c>`, and slightly modifies prompt. Use it\nto ask for input inside function custom surrounding (see |MiniSurround.config|).\n\n------------------------------------------------------------------------------\n                                                         *MiniSurround.gen_spec*\n                            `MiniSurround.gen_spec`\nGenerate common surrounding specifications\n\nThis is a table with two sets of generator functions: <input> and <output>\n(currently empty). Each is a table with function values generating\ncorresponding surrounding specification.\n\nSee also ~\n|MiniAi.gen_spec|\n\n------------------------------------------------------------------------------\n                                      *MiniSurround.gen_spec.input.treesitter()*\n          `MiniSurround.gen_spec.input.treesitter`({captures}, {opts})\nTreesitter specification for input surrounding\n\nThis is a specification in function form. When called with a pair of\ntreesitter captures, it returns a specification function outputting an\narray of region pairs derived from <outer> and <inner> captures. It first\nsearches for all matched nodes of outer capture and then completes each one\nwith the biggest match of inner capture inside that node (if any). The result\nregion pair is a difference between regions of outer and inner captures.\n\nIn order for this to work, apart from working treesitter parser for desired\nlanguage, user should have a reachable language-specific 'textobjects'\nquery (see |vim.treesitter.query.get()|).\nThe most straightforward way for this is to have 'textobjects.scm' query\nfile with treesitter captures stored in some recognized path. This is\nprimarily designed to be compatible with plugin\n'nvim-treesitter/nvim-treesitter-textobjects', but can be used without it.\n\nTwo most common approaches for having a query file:\n- Install 'nvim-treesitter/nvim-treesitter-textobjects'. It has curated and\n  well maintained builtin query files for many languages with a standardized\n  capture names, like `call.outer`, `call.inner`, etc.\n- Manually create file 'after/queries/<language name>/textobjects.scm' in\n  your |$XDG_CONFIG_HOME| directory. It should contain queries with\n  captures (later used to define surrounding parts). See |lua-treesitter-query|.\nTo verify that query file is reachable, run (example for \"lua\" language,\noutput should have at least an intended file): >vim\n\n  :lua print(vim.inspect(vim.treesitter.query.get_files('lua','textobjects')))\n<\nExample configuration for function definition textobject with\n'nvim-treesitter/nvim-treesitter-textobjects' captures: >lua\n\n  local ts_input = require('mini.surround').gen_spec.input.treesitter\n  require('mini.surround').setup({\n    custom_surroundings = {\n      -- Use tree-sitter to search for function call\n      f = {\n        input = ts_input({ outer = '@call.outer', inner = '@call.inner' })\n      },\n    }\n  })\n<\nNotes:\n- Be sure that query files don't contain unknown |treesitter-directives|\n  (like `#make-range!`, for example). Otherwise surrounding with such captures\n  might not be found as |lua-treesitter-core| won't treat them as captures.\n  Verify with `:=vim.treesitter.query.get('lang', 'textobjects')` and see\n  if the target capture is recognized as one.\n- It uses buffer's |filetype| to determine query language.\n- On large files it is slower than pattern-based textobjects. Still very\n  fast though (one search should be magnitude of milliseconds or tens of\n  milliseconds on really large file).\n\nParameters ~\n{captures} `(table)` Captures for outer and inner parts of region pair:\n  table with <outer> and <inner> fields with captures for outer\n  (`[left.form; right.to]`) and inner (`(left.to; right.from)` both edges\n  exclusive, i.e. they won't be a part of surrounding) regions. Each value\n  should be a string capture starting with `'@'`.\n{opts} `(table|nil)` Options. Possible values:\n  - <use_nvim_treesitter> - whether to try to use 'nvim-treesitter' plugin\n    (if present) to do the query. It used to implement more advanced behavior\n    and more coherent experience if 'nvim-treesitter-textobjects' queries are\n    used. However, as |lua-treesitter-core| methods are more capable now,\n    the option will soon be removed. Only present for backward compatibility.\n    Default: `false`.\n\nReturn ~\n`(function)` Function which returns array of current buffer region pairs\n  representing differences between outer and inner captures.\n\nSee also ~\n- |MiniSurround-surrounding-specification| for how this type of\n  surrounding specification is processed.\n- |vim.treesitter.query.get()| for how query is fetched.\n- |Query:iter_captures()| for how all query captures are iterated in case of\n  no 'nvim-treesitter'.\n- |MiniAi.gen_spec.treesitter()| for similar 'mini.ai' generator.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-tabline.txt",
    "content": "*mini.tabline* Tabline\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                   *MiniTabline*\nKey idea: show all listed buffers in readable way with minimal total width.\n\nFeatures:\n- Buffers are listed in the order of their identifier (see |bufnr()|).\n\n- Different highlight groups for \"states\" of buffer affecting 'buffer tabs'.\n\n- Buffer names are made unique by extending paths to files or appending\n  unique identifier to buffers without name.\n\n- Current buffer is displayed \"optimally centered\" (in center of screen\n  while maximizing the total number of buffers shown) when there are many\n  buffers open.\n\n- 'Buffer tabs' are clickable if Neovim allows it.\n\n- Extra information section in case of multiple Neovim tabpages.\n\n- Truncation symbols which show if there are tabs to the left and/or right.\n  Exact characters are taken from 'listchars' global value (`precedes` and\n  `extends` fields) and are shown only if 'list' option is enabled.\n\nWhat it doesn't do:\n- Custom buffer order is not supported.\n\n# Dependencies ~\n\nSuggested dependencies (provide extra functionality, will work without them):\n\n- Enabled |mini.icons| module to show icons near file names.\n  Falls back to [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n  or shows nothing.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.tabline').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniTabline` which you can use for scripting or manually (with\n`:lua MiniTabline.*`).\n\nSee |MiniTabline.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minitabline_config` which should have same structure as\n`MiniTabline.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Suggested option values ~\n\nSome options are set automatically by |MiniTabline.setup()|:\n- 'showtabline' is set to 2 to always show tabline.\n\n# Highlight groups ~\n\n- `MiniTablineCurrent` - buffer is current (has cursor in it).\n- `MiniTablineVisible` - buffer is visible (displayed in some window).\n- `MiniTablineHidden` - buffer is hidden (not displayed).\n- `MiniTablineModifiedCurrent` - buffer is modified and current.\n- `MiniTablineModifiedVisible` - buffer is modified and visible.\n- `MiniTablineModifiedHidden` - buffer is modified and hidden.\n- `MiniTablineFill` - unused right space of tabline.\n- `MiniTablineTabpagesection` - section with tabpage information.\n- `MiniTablineTrunc` - truncation symbols indicating more left/right tabs.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable (show empty tabline), set `vim.g.minitabline_disable` (globally) or\n`vim.b.minitabline_disable` (for a buffer) to `true`. Considering high number\nof different scenarios and customization intentions, writing exact rules\nfor disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                           *MiniTabline.setup()*\n                         `MiniTabline.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniTabline.config|.\n\nUsage ~\n>lua\n  require('mini.tabline').setup() -- use default config\n  -- OR\n  require('mini.tabline').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                            *MiniTabline.config*\n                              `MiniTabline.config`\nDefaults ~\n>lua\n  MiniTabline.config = {\n    -- Whether to show file icons (requires 'mini.icons')\n    show_icons = true,\n\n    -- Function which formats the tab label\n    -- By default surrounds with space and possibly prepends with icon\n    format = nil,\n\n    -- Where to show tabpage section in case of multiple vim tabpages.\n    -- One of 'left', 'right', 'none'.\n    tabpage_section = 'left',\n  }\n<\n# Format ~\n\n`config.format` is a callable that takes buffer identifier and pre-computed\nlabel as arguments and returns a string with formatted label. Output will be\ntreated strictly as text (i.e. no 'statusline' like constructs is allowed).\nThis function will be called for all displayable in tabline buffers.\nDefault: |MiniTabline.default_format()|.\n\nExample of adding \"+\" suffix for modified buffers: >lua\n\n  function(buf_id, label)\n    local suffix = vim.bo[buf_id].modified and '+ ' or ''\n    return MiniTabline.default_format(buf_id, label) .. suffix\n  end\n<\n------------------------------------------------------------------------------\n                                             *MiniTabline.make_tabline_string()*\n                      `MiniTabline.make_tabline_string`()\nMake string for |'tabline'|\n\n------------------------------------------------------------------------------\n                                                  *MiniTabline.default_format()*\n                `MiniTabline.default_format`({buf_id}, {label})\nDefault tab format\n\nUsed by default as `config.format`.\nPrepends label with padded icon based on buffer's name (if `show_icon`\nin |MiniTabline.config| is `true`) and surrounds label with single space.\nNote: it is meant to be used only as part of `format` in |MiniTabline.config|.\n\nParameters ~\n{buf_id} `(number)` Buffer identifier.\n{label} `(string)` Pre-computed label.\n\nReturn ~\n`(string)` Formatted label.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-test.txt",
    "content": "*mini.test* Test Neovim plugins\n\nMIT License Copyright (c) 2022 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                      *MiniTest*\nFeatures:\n- Test action is defined as a named callable entry of a table.\n\n- Helper for creating child Neovim process which is designed to be used in\n  tests (including taking and verifying screenshots). See\n  |MiniTest.new_child_neovim()| and |MiniTest.expect.reference_screenshot()|.\n\n- Hierarchical organization of tests with custom hooks, parametrization,\n  and user data. See |MiniTest.new_set()|.\n\n- Emulation of [lunarmodules/busted](https://github.com/lunarmodules/busted)\n  interface (`describe`, `it`, etc.).\n\n- Predefined small yet usable set of expectations (`assert`-like functions).\n  See |MiniTest.expect|.\n\n- Customizable definition of what files should be tested.\n\n- Test case filtering. There are predefined wrappers for testing a file\n  (|MiniTest.run_file()|) and case at a location like current cursor position\n  (|MiniTest.run_at_location()|).\n\n- Customizable reporter of output results. There are two predefined ones:\n    - |MiniTest.gen_reporter.buffer()| for interactive usage.\n    - |MiniTest.gen_reporter.stdout()| for headless Neovim.\n\n- Customizable project specific testing script.\n\n- Works on Unix (Linux, MacOS, etc.) and Windows.\n\nWhat it doesn't support:\n- Parallel execution. Due to idea of limiting implementation complexity.\n\n- Mocks, stubs, etc. Use child Neovim process and manually override what is\n  needed. Reset child process it afterwards.\n\n- \"Overly specific\" expectations. Tests for (no) equality and (absence of)\n  errors usually cover most of the needs. Adding new expectations is a\n  subject to weighing its usefulness against additional implementation\n  complexity. Use |MiniTest.new_expectation()| to create custom ones.\n\nFor more information see:\n- 'TESTING.md' file for a hands-on introduction based on examples.\n\n- Code of this plugin's tests. Consider it to be an example of intended\n  way to use 'mini.test' for test organization and creation.\n\n# Workflow ~\n\n- Organize tests in separate files. Each test file should return a test set\n  (explicitly or implicitly by using \"busted\" style functions).\n\n- Write test actions as callable entries of test set. Use child process\n  inside test actions (see |MiniTest.new_child_neovim()|) and builtin\n  expectations (see |MiniTest.expect|).\n\n- Run tests. This does two steps:\n    - *Collect*. This creates single hierarchical test set, flattens into\n      array of test cases (see |MiniTest-test-case|) while expanding with\n      parametrization, and possibly filters them.\n    - *Execute*. This safely calls hooks and main test actions in specified\n      order while allowing reporting progress in asynchronous fashion.\n      Detected errors means test case fail; otherwise - pass.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.test').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniTest`\nwhich you can use for scripting or manually (with `:lua MiniTest.*`).\n\nSee |MiniTest.config| for available config settings.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minitest_config` which should have same structure as `MiniTest.config`.\nSee |mini.nvim-buffer-local-config| for more details.\n\nTo stop module from showing non-error feedback, set `config.silent = true`.\n\n# Comparisons ~\n\n- Testing infrastructure from\n  [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim):\n    - Executes each file in separate headless Neovim process with customizable\n      'init.vim' file. While 'mini.test' executes everything in current\n      Neovim process encouraging writing tests with help of manually\n      managed child Neovim process (see |MiniTest.new_child_neovim()|).\n    - Tests are expected to be written with embedded simplified versions of\n      'lunarmodules/busted' and 'lunarmodules/luassert'. While 'mini.test'\n      uses concepts of test set (see |MiniTest.new_set()|) and test case\n      (see |MiniTest-test-case|). It also can emulate bigger part of\n      \"busted\" framework.\n    - Has single way of reporting progress (shows result after every case\n      without summary). While 'mini.test' can have customized reporters\n      with defaults for interactive and headless usage (provide more\n      compact and user-friendly summaries).\n    - Allows parallel execution, while 'mini.test' does not.\n    - Allows making mocks, stubs, and spies, while 'mini.test' does not in\n      favor of manually overwriting functionality in child Neovim process.\n\nAlthough 'mini.test' supports emulation of \"busted style\" testing, it will\nbe more stable to use its designed approach of defining tests (with\n`MiniTest.new_set()` and explicit table fields). Couple of reasons:\n- \"Busted\" syntax doesn't support full capabilities offered by 'mini.test'.\n  Mainly it is about parametrization and supplying user data to test sets.\n- It is an emulation, not full support. So some subtle things might not\n  work the way you expect.\n\nSome hints for converting from 'plenary.nvim' tests to 'mini.test':\n- Rename files from \"***_spec.lua\" to \"test_***.lua\" and put them in\n  \"tests\" directory.\n- Replace `assert` calls with 'mini.test' expectations. See |MiniTest.expect|.\n- Create main test set `T = MiniTest.new_set()` and eventually return it.\n- Make new sets (|MiniTest.new_set()|) from `describe` blocks. Convert\n  `before_each()` and `after_each` to `pre_case` and `post_case` hooks.\n- Make test cases from `it` blocks.\n\n# Highlight groups ~\n\n- `MiniTestEmphasis` - emphasis highlighting. By default it is a bold text.\n- `MiniTestFail` - highlighting of failed cases. By default it is a bold\n  text with `vim.g.terminal_color_1` color (red).\n- `MiniTestPass` - highlighting of passed cases. By default it is a bold\n  text with `vim.g.terminal_color_2` color (green).\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minitest_disable` (globally) or `vim.b.minitest_disable`\n(for a buffer) to `true`. Considering high number of different scenarios\nand customization intentions, writing exact rules for disabling module's\nfunctionality is left to user. See |mini.nvim-disabling-recipes| for common\nrecipes.\n\n------------------------------------------------------------------------------\n                                                              *MiniTest.setup()*\n                           `MiniTest.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniTest.config|.\n\nUsage ~\n>lua\n  require('mini.test').setup() -- use default config\n  -- OR\n  require('mini.test').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                               *MiniTest.config*\n                               `MiniTest.config`\nDefaults ~\n>lua\n  MiniTest.config = {\n    -- Options for collection of test cases. See `:h MiniTest.collect()`.\n    collect = {\n      -- Temporarily emulate functions from 'busted' testing framework\n      -- (`describe`, `it`, `before_each`, `after_each`, and more)\n      emulate_busted = true,\n\n      -- Function returning array of file paths to be collected.\n      -- Default: all Lua files in 'tests' directory starting with 'test_'.\n      find_files = function()\n        return vim.fn.globpath('tests', '**/test_*.lua', true, true)\n      end,\n\n      -- Predicate function indicating if test case should be executed\n      filter_cases = function(case) return true end,\n    },\n\n    -- Options for execution of test cases. See `:h MiniTest.execute()`.\n    execute = {\n      -- Table with callable fields `start()`, `update()`, and `finish()`\n      reporter = nil,\n\n      -- Whether to stop execution after first error\n      stop_on_error = false,\n    },\n\n    -- Path (relative to current directory) to script which handles project\n    -- specific test running\n    script_path = 'scripts/minitest.lua',\n\n    -- Whether to disable showing non-error feedback\n    silent = false,\n  }\n<\n------------------------------------------------------------------------------\n                                                              *MiniTest.current*\n                               `MiniTest.current`\nTable with information about current state of test execution\n\nUse it to examine result of |MiniTest.execute()|. It is reset at the\nbeginning of every call.\n\nAt least these keys are supported:\n- <all_cases> - array with all cases being currently executed. Basically,\n  an input of `MiniTest.execute()`.\n- <case> - currently executed test case. See |MiniTest-test-case|. Use it\n  to customize execution output (like adding custom notes, etc).\n\n------------------------------------------------------------------------------\n                                                            *MiniTest.new_set()*\n                       `MiniTest.new_set`({opts}, {tbl})\nCreate test set\n\nTest set is one of the two fundamental data structures. It is a table that\ndefines hierarchical test organization as opposed to sequential\norganization with |MiniTest-test-case|.\n\nAll its elements are one of three categories:\n- A callable (object that can be called; function or table with `__call`\n  metatble entry) is considered to define a test action. It will be called\n  with \"current arguments\" (result of all nested `parametrize` values, read\n  further). If it throws error, test has failed.\n- A test set (output of this function) defines nested structure. Its\n  options during collection (see |MiniTest.collect()|) will be extended\n  with options of this (parent) test set.\n- Any other elements are considered helpers and don't directly participate\n  in test structure.\n\nSet options allow customization of test collection and execution (more\ndetails in `opts` description):\n- `hooks` - table with elements that will be called without arguments at\n  predefined stages of test execution.\n- `parametrize` - array defining different arguments with which main test\n  actions will be called. Any non-trivial parametrization will lead to\n  every element (even nested) be \"multiplied\" and processed with every\n  element of `parametrize`. This allows handling many different combination\n  of tests with little effort.\n- `data` - table with user data that will be forwarded to cases. Primary\n  objective is to be used for customized case filtering.\n\nNotes:\n- Preferred way of adding elements is by using syntax `T[name] = element`.\n  This way order of added elements will be preserved. Any other way won't\n  guarantee any order.\n- Supplied options `opts` are stored in `opts` field of metatable\n  (`getmetatable(set).opts`).\n\nParameters ~\n{opts} `(table|nil)` Allowed options:\n  - <hooks> - table with fields:\n      - <pre_once> - executed before first filtered node.\n      - <pre_case> - executed before each case (even nested).\n      - <post_case> - executed after each case (even nested).\n      - <post_once> - executed after last filtered node.\n  - <parametrize> - array where each element is itself an array of\n    parameters to be appended to \"current parameters\" of callable fields.\n    Note: don't use plain `{}` as it is equivalent to \"parametrization into\n    zero cases\", so no cases will be collected from this set. Calling test\n    actions with no parameters is equivalent to `{{}}` or not supplying\n    `parametrize` option at all.\n  - <data> - user data to be forwarded to cases. Can be used for a more\n    granular filtering.\n  - <n_retry> - number of times to retry each case until success.\n    Default: 1.\n{tbl} `(table|nil)` Initial test items (possibly nested). Will be executed\n  without any guarantees on order.\n\nReturn ~\n`(table)` A single test set.\n\nUsage ~\n>lua\n  -- Use with defaults\n  T = MiniTest.new_set()\n  T['works'] = function() MiniTest.expect.equality(1, 1) end\n\n  -- Use with custom options. This will result into two actual cases: first\n  -- will pass, second - fail after two attempts.\n  T['nested'] = MiniTest.new_set({\n    hooks = { pre_case = function() _G.x = 1 end },\n    parametrize = { { 1 }, { 2 } },\n    n_retry = 2,\n  })\n\n  T['nested']['works'] = function(x) MiniTest.expect.equality(_G.x, x) end\n<\n------------------------------------------------------------------------------\n                                                            *MiniTest-test-case*\nTest case\n\nAn item of sequential test organization, as opposed to hierarchical with\ntest set (see |MiniTest.new_set()|). It is created as result of test\ncollection with |MiniTest.collect()| to represent all necessary information\nof test execution.\n\nExecution of test case goes by the following rules:\n- Call functions in order:\n    - All elements of `hooks.pre` from first to last without arguments.\n    - Field `test` with arguments unpacked from `args`. If execution fails,\n      retry it (along with hooks that come from `pre_case` and `post_case`)\n      at most `n_retry` times until first success (if any).\n    - All elements of `hooks.post` from first to last without arguments.\n- Error in any call gets appended to `exec.fails`, meaning error in any\n  hook will lead to test fail.\n- State (`exec.state`) is changed before every call and after last call.\n\nClass ~\n{Test-case}\n\nFields ~\n{args} `(table)` Array of arguments with which `test` will be called.\n{data} `(table)` User data: all fields of `opts.data` from nested test sets.\n{desc} `(table)` Description: array of fields from nested test sets.\n{exec} `(table|nil)` Information about test case execution. Value of `nil` means\n  that this particular case was not (yet) executed. Has following fields:\n  - <fails> - array of strings with failing information.\n  - <notes> - array of strings with non-failing information.\n  - <state> - state of test execution. One of:\n      - 'Executing <name of what is being executed>' (during execution).\n      - 'Pass' (no fails, no notes).\n      - 'Pass with notes' (no fails, some notes).\n      - 'Fail' (some fails, no notes).\n      - 'Fail with notes' (some fails, some notes).\n{hooks} `(table)` Hooks to be executed as part of test case. Has fields:\n  - <pre> and <post> - arrays of functions to be consecutively executed\n    before and after every execution of `test`.\n  - <pre_source> and <post_source> - arrays of strings with sources of\n    corresponding elements in <pre> and <post> arrays. Source is one of\n    `\"once\"` (for `pre_once` and `post_once` hooks) and\n    `\"case\"` (for `pre_case` and `post_case` hooks).\n{test} `(function|table)` Main callable object representing test action.\n\n------------------------------------------------------------------------------\n                                                               *MiniTest.skip()*\n                             `MiniTest.skip`({msg})\nSkip the rest of current case\n\nNotes:\n- When called inside test case, stops execution while adding message to notes.\n- When called inside `pre_case` hook, registers skip at the start of its\n  test case. Calling in other hooks has no effect.\n- Currently implemented as a specially handled type of error.\n\nParameters ~\n{msg} `(string|nil)` Message to be added to current case notes.\n\n------------------------------------------------------------------------------\n                                                           *MiniTest.add_note()*\n                           `MiniTest.add_note`({msg})\nAdd note to currently executed test case\n\nAppends `msg` to `exec.notes` field of `case` in |MiniTest.current|.\n\nParameters ~\n{msg} `(string)` Note to add.\n\n------------------------------------------------------------------------------\n                                                            *MiniTest.finally()*\n                            `MiniTest.finally`({f})\nRegister callable execution after current callable\n\nCan be used several times inside hooks and main test callable of test case.\n\nParameters ~\n{f} `(function|table)` Callable to be executed after current callable is\n  finished executing (regardless of whether it ended with error or not).\n\n------------------------------------------------------------------------------\n                                                                *MiniTest.run()*\n                             `MiniTest.run`({opts})\nRun tests\n\n- Try executing project specific script at path `opts.script_path`. If\n  successful (no errors), then stop.\n- Collect cases with |MiniTest.collect()| and `opts.collect`.\n- Execute collected cases with |MiniTest.execute()| and `opts.execute`.\n\nParameters ~\n{opts} `(table|nil)` Options with structure similar to |MiniTest.config|.\n  Absent values are inferred from there.\n\n------------------------------------------------------------------------------\n                                                           *MiniTest.run_file()*\n                      `MiniTest.run_file`({file}, {opts})\nRun specific test file\n\nBasically a |MiniTest.run()| wrapper with custom `collect.find_files` option.\n\nParameters ~\n{file} `(string|nil)` Path to test file. By default a path of current buffer.\n{opts} `(table|nil)` Options for |MiniTest.run()|.\n\n------------------------------------------------------------------------------\n                                                    *MiniTest.run_at_location()*\n                 `MiniTest.run_at_location`({location}, {opts})\nRun case(s) covering location\n\nTry filtering case(s) covering location, meaning that definition of its\nmain `test` action (as taken from builtin `debug.getinfo`) is located in\nspecified file and covers specified line. Note that it can result in\nmultiple cases if they come from parametrized test set (see `parametrize`\noption in |MiniTest.new_set()|).\n\nBasically a |MiniTest.run()| wrapper with custom `collect.find_files` option.\n\nParameters ~\n{location} `(table|nil)` Table with fields <file> (path to file) and <line>\n  (line number in that file). Default is taken from current cursor position.\n\n------------------------------------------------------------------------------\n                                                            *MiniTest.collect()*\n                           `MiniTest.collect`({opts})\nCollect test cases\n\nOverview of collection process:\n- If `opts.emulate_busted` is `true`, temporary make special global\n  functions (removed at the end of collection). They can be used inside\n  test files to create hierarchical structure of test cases.\n- Source each file from array output of `opts.find_files`. It should output\n  a test set (see |MiniTest.new_set()|) or `nil` (if \"busted\" style is used;\n  test set is created implicitly).\n- Combine all test sets into single set with fields equal to its file path.\n- Convert from hierarchical test configuration to sequential: from single\n  test set to array of test cases (see |MiniTest-test-case|). Conversion is\n  done in the form of \"for every table element do: for every `parametrize`\n  element do: ...\". Details:\n    - If element is a callable, construct test case with it being main\n      `test` action. Description is appended with key of element in current\n      test set table. Hooks, arguments, and data are taken from \"current\n      nested\" ones. Add case to output array.\n    - If element is a test set, process it in similar, recursive fashion.\n      The \"current nested\" information is expanded:\n        - `args` is extended with \"current element\" from `parametrize`.\n        - `desc` is appended with element key.\n        - `hooks` are appended to their appropriate places. `*_case` hooks\n          will be inserted closer to all child cases than hooks from parent\n          test sets: `pre_case` at end, `post_case` at start.\n        - `data` is extended via |vim.tbl_deep_extend()|.\n    - Any other element is not processed.\n- Filter array with `opts.filter_cases`. Note that input case doesn't contain\n  all hooks, as `*_once` hooks will be added after filtration.\n- Add `*_once` hooks to appropriate cases.\n\nParameters ~\n{opts} `(table|nil)` Options controlling case collection. Possible fields:\n  - <emulate_busted> - whether to emulate 'lunarmodules/busted' interface.\n    It emulates these global functions: `describe`, `it`, `setup`, `teardown`,\n    `before_each`, `after_each`. Use |MiniTest.skip()| instead of `pending()`\n    and |MiniTest.finally()| instead of `finally`.\n  - <find_files> - function which when called without arguments returns\n    array with file paths. Each file should be a Lua file returning single\n    test set or `nil`.\n  - <filter_cases> - function which when called with single test case\n    (see |MiniTest-test-case|) returns `false` if this case should be filtered\n    out; `true` otherwise.\n\nReturn ~\n`(table)` Array of test cases ready to be used by |MiniTest.execute()|.\n\n------------------------------------------------------------------------------\n                                                            *MiniTest.execute()*\n                      `MiniTest.execute`({cases}, {opts})\nExecute array of test cases\n\nOverview of execution process:\n- Reset `all_cases` in |MiniTest.current| with `cases` input.\n- Call `reporter.start(cases)` (if present).\n- Execute each case in natural array order (aligned with their integer\n  keys). Set `MiniTest.current.case` to currently executed case. Detailed\n  test case execution is described in |MiniTest-test-case|. After any state\n  change (including case retry attempts), call `reporter.update(case_num)`\n  (if present), where `case_num` is an integer key of current test case.\n- Call `reporter.finish()` (if present).\n\nNotes:\n- Execution is done in asynchronous fashion with scheduling. This allows\n  making meaningful progress report during execution.\n- This function doesn't return anything. Instead, it updates `cases` in\n  place with proper `exec` field. Use `all_cases` at |MiniTest.current| to\n  look at execution result.\n\nParameters ~\n{cases} `(table)` Array of test cases (see |MiniTest-test-case|).\n{opts} `(table|nil)` Options controlling case collection. Possible fields:\n  - <reporter> - table with possible callable fields `start`, `update`,\n    `finish`. Default: |MiniTest.gen_reporter.buffer()| in interactive\n    usage and |MiniTest.gen_reporter.stdout()| in headless usage.\n  - <stop_on_error> - whether to stop execution (see |MiniTest.stop()|)\n    after first error. Default: `false`.\n\n------------------------------------------------------------------------------\n                                                               *MiniTest.stop()*\n                            `MiniTest.stop`({opts})\nStop test execution\n\nParameters ~\n{opts} `(table|nil)` Options with fields:\n  - <close_all_child_neovim> - whether to close all child neovim processes\n    created with |MiniTest.new_child_neovim()|. Default: `true`.\n\n------------------------------------------------------------------------------\n                                                       *MiniTest.is_executing()*\n                           `MiniTest.is_executing`()\nCheck if tests are being executed\n\nReturn ~\n`(boolean)`\n\n------------------------------------------------------------------------------\n                                                               *MiniTest.expect*\n                               `MiniTest.expect`\nTable with expectation functions\n\nEach function has the following behavior:\n- Silently returns `true` if expectation is fulfilled.\n- Throws an informative error with information helpful for debugging.\n  Allows customizable fail reason to provide more context.\n\nMostly designed to be used within 'mini.test' framework.\n\nUsage ~\n>lua\n  local x = 1 + 1\n  MiniTest.expect.equality(x, 2) -- passes\n  MiniTest.expect.equality(x, 1, { fail_reason = 'Not equal' }) -- fails\n<\n------------------------------------------------------------------------------\n                                                    *MiniTest.expect.equality()*\n              `MiniTest.expect.equality`({left}, {right}, {opts})\nExpect equality of two objects\n\nEquality is tested via |vim.deep_equal()|. It also tries to compute more\ndetailed cause for equality (for easier spotting the difference):\n- If they have different types.\n- For strings if they have different length or if some character is different.\n- For tables it shows a \"key branch\" at which values are different along with\n  the actual values. A single difference is shown, there might be more.\n  For not nested tables key branch is just a key. If the difference is inside\n  nested tables, the key branch shows a \"path through nested tables\" to\n  a different value. Examples: >lua\n\n    local eq = MiniTest.expect.equality\n    eq({ 1, 2 }, { 1, 3 })         -- Key branch is `2`\n    eq({ 1, { 2 } }, { 1, 'c' })   -- Key branch is `2` ('c' is not a table)\n    eq({ 1, { 2 } }, { 1, { 3 } }) -- Key branch is `2->1`\n\n    -- Key branch is either `1->1->\"a\"` or `1->1->\"b\"`\n    eq({ { { a = 1 } } }, { { { b = 2 } } })\n<\nParameters ~\n{left} `(any)` First object.\n{right} `(any)` Second object.\n{opts} `(table|nil)` Options. Possible fields:\n  - <fail_reason> `(string|function)` - reason for failing expectation.\n    a function is called with expectation input and should return a string.\n    Default: `nil` for default reason like \"Failed expectation for ...\".\n\n------------------------------------------------------------------------------\n                                                 *MiniTest.expect.no_equality()*\n             `MiniTest.expect.no_equality`({left}, {right}, {opts})\nExpect no equality of two objects\n\nEquality is tested via |vim.deep_equal()|.\n\nParameters ~\n{left} `(any)` First object.\n{right} `(any)` Second object.\n{opts} `(table|nil)` Options. Possible fields:\n  - <fail_reason> `(string|function)` - reason for failing expectation.\n    a function is called with expectation input and should return a string.\n    Default: `nil` for default reason like \"Failed expectation for ...\".\n\n------------------------------------------------------------------------------\n                                                       *MiniTest.expect.error()*\n             `MiniTest.expect.error`({f}, {pattern}, {opts}, {...})\nExpect function call to raise error\n\nParameters ~\n{f} `(function)` Function to be tested for raising error.\n{pattern} `(string|nil)` Pattern which error message should match.\n  Use `nil` or empty string to not test for pattern matching.\n{opts} `(table|nil)` Options. Possible fields:\n  - <fail_reason> `(string|function)` - reason for failing expectation.\n    a function is called with expectation input and should return a string.\n    Default: `nil` for default reason like \"Failed expectation for ...\".\n\n------------------------------------------------------------------------------\n                                                    *MiniTest.expect.no_error()*\n                 `MiniTest.expect.no_error`({f}, {opts}, {...})\nExpect function call to not raise error\n\nParameters ~\n{f} `(function)` Function to be tested for not raising error.\n{opts} `(table|nil)` Options. Possible fields:\n  - <fail_reason> `(string|function)` - reason for failing expectation.\n    a function is called with expectation input and should return a string.\n    Default: `nil` for default reason like \"Failed expectation for ...\".\n\n------------------------------------------------------------------------------\n                                        *MiniTest.expect.reference_screenshot()*\n      `MiniTest.expect.reference_screenshot`({screenshot}, {path}, {opts})\nExpect equality to reference screenshot\n\nParameters ~\n{screenshot} `(table|nil)` Array with screenshot information. Usually an output\n  of `child.get_screenshot()` (see |MiniTest-child-neovim-get_screenshot()|).\n  If `nil`, expectation passed.\n{path} `(string|nil)` Path to reference screenshot. If `nil`, constructed\n  automatically in directory `opts.directory` from current case info and\n  total number of times it was called inside current case. If there is no\n  file at `path`, it is created with content of `screenshot`.\n{opts} `(table|nil)` Options:\n  - <force> `(boolean)` - whether to forcefully create reference screenshot.\n    Temporary useful during test writing. Default: `false`.\n  - <ignore_text> `(boolean|table)` - whether to ignore all or some text lines.\n    If `true` - ignore all, if number array - ignore text of those lines,\n    if `false` - do not ignore any. Default: `false`.\n  - <ignore_attr> `(boolean|table)` - whether to ignore all or some attr lines.\n    If `true` - ignore all, if number array - ignore attr of those lines,\n    if `false` - do not ignore any. Default: `false`.\n  - <directory> `(string)` - directory where automatically constructed `path`\n    is located. Default: \"tests/screenshots\".\n  - <fail_reason> `(string|function)` - reason for failing expectation.\n    a function is called with expectation input and should return a string.\n    Default: `nil` for default reason like \"Failed expectation for ...\".\n\n------------------------------------------------------------------------------\n                                                    *MiniTest.new_expectation()*\n       `MiniTest.new_expectation`({subject}, {predicate}, {fail_context})\nCreate new expectation function\n\nHelper for writing custom functions with behavior similar to other methods\nof |MiniTest.expect|.\n\nParameters ~\n{subject} `(string|function|table)` Subject of expectation. If callable,\n  called with expectation input arguments to produce string value.\n{predicate} `(function|table)` Predicate callable. Called with expectation\n  input arguments. Output `false` or `nil` means failed expectation.\n{fail_context} `(string|function|table)` Information about fail. If callable,\n  called with expectation input arguments to produce string value.\n\nReturn ~\n`(function)` Expectation function.\n\nUsage ~\n>lua\n  local expect_truthy = MiniTest.new_expectation(\n    'truthy',\n    function(x) return x end,\n    function(x) return 'Object: ' .. vim.inspect(x) end\n  )\n<\n------------------------------------------------------------------------------\n                                                         *MiniTest.gen_reporter*\n                            `MiniTest.gen_reporter`\nTable with pre-configured report generators\n\nEach element is a function which returns reporter - table with callable\n`start`, `update`, and `finish` fields.\n\n------------------------------------------------------------------------------\n                                                *MiniTest.gen_reporter.buffer()*\n                     `MiniTest.gen_reporter.buffer`({opts})\nGenerate buffer reporter\n\nThis is a default choice for interactive (not headless) usage. Opens a window\nwith dedicated non-terminal buffer and updates it with throttled redraws.\n\nOpened buffer has the following helpful Normal mode mappings:\n- `<Esc>` - stop test execution if executing (see |MiniTest.is_executing()|\n  and |MiniTest.stop()|). Close window otherwise.\n- `q` - same as `<Esc>` for convenience and compatibility.\n\nGeneral idea:\n- Group cases by concatenating first `opts.group_depth` elements of case\n  description (`desc` field). Groups by collected files if using default values.\n- In `start()` show some stats to know how much is scheduled to be executed.\n- In `update()` show symbolic overview of current group and state of current\n  case. Each symbol represents one case and its state:\n    - `?` - case didn't finish executing.\n    - `o` - pass.\n    - `O` - pass with notes.\n    - `x` - fail.\n    - `X` - fail with notes.\n- In `finish()` show all fails and notes ordered by case.\n\nParameters ~\n{opts} `(table|nil)` Table with options. Used fields:\n  - <group_depth> - number of first elements of case description (can be zero)\n    used for grouping. Higher values mean higher granularity of output.\n    Default: 1.\n  - <throttle_delay> - minimum number of milliseconds to wait between\n    redrawing. Reduces screen flickering but not amount of computations.\n    Default: 10.\n  - <window> - definition of window to open. Can take one of the forms:\n      - Callable. It is called expecting output to be target window id\n        (current window is used if output is `nil`). Use this to open in\n        \"normal\" window (like `function() vim.cmd('vsplit') end`).\n      - Table. Used as `config` argument in |nvim_open_win()|.\n    Default: table for centered floating window.\n\n------------------------------------------------------------------------------\n                                                *MiniTest.gen_reporter.stdout()*\n                     `MiniTest.gen_reporter.stdout`({opts})\nGenerate stdout reporter\n\nThis is a default choice for headless usage. Writes to `stdout`. Uses\ncoloring ANSI escape sequences to make pretty and informative output\n(should work in most modern terminals and continuous integration providers).\n\nIt has same general idea as |MiniTest.gen_reporter.buffer()| with slightly\nless output (it doesn't overwrite previous text) to overcome typical\nterminal limitations.\n\nParameters ~\n{opts} `(table|nil)` Table with options. Used fields:\n  - <group_depth> - number of first elements of case description (can be zero)\n    used for grouping. Higher values mean higher granularity of output.\n    Default: 1.\n  - <quit_on_finish> - whether to quit after finishing test execution.\n    Default: `true`.\n\n------------------------------------------------------------------------------\n                                                   *MiniTest.new_child_neovim()*\n                         `MiniTest.new_child_neovim`()\nCreate child Neovim process\n\nThis creates an object designed to be a fundamental piece of 'mini.test'\nmethodology. It can start/stop/restart a separate (child) Neovim process\n(headless, but fully functioning) together with convenience helpers to\ninteract with it through |RPC| messages.\n\nFor more information see |MiniTest-child-neovim|.\n\nReturn ~\n`(MiniTest.child)` Object of |MiniTest-child-neovim|.\n\nUsage ~\n>lua\n  -- Initiate\n  local child = MiniTest.new_child_neovim()\n  child.start()\n\n  -- Use API functions\n  child.api.nvim_buf_set_lines(0, 0, -1, true, { 'Line inside child Neovim' })\n\n  -- Execute Lua code, Vimscript commands, etc.\n  child.lua('_G.n = 0')\n  child.cmd('au CursorMoved * lua _G.n = _G.n + 1')\n  child.type_keys('l')\n  print(child.lua_get('_G.n')) -- Should be 1\n\n  -- Use other `vim.xxx` Lua wrappers (executed inside child process)\n  vim.b.aaa = 'current process'\n  child.b.aaa = 'child process'\n  print(child.lua_get('vim.b.aaa')) -- Should be 'child process'\n\n  -- Always stop process after it is not needed\n  child.stop()\n<\n------------------------------------------------------------------------------\n                                                         *MiniTest-child-neovim*\nChild class\n\nIt offers a great set of tools to write reliable and reproducible tests by\nallowing to use fresh process in any test action. Interaction with it is done\nthrough |RPC| protocol.\n\nAlthough quite flexible, at the moment it has certain limitations:\n- Doesn't allow using functions or userdata for child's both inputs and\n  outputs. Usual solution is to move computations from current Neovim process\n  to child process. Use `child.lua()` and `child.lua_get()` for that.\n- When writing tests, it is common to end up with \"hanging\" process: it\n  stops executing without any output. Most of the time it is because Neovim\n  process is \"blocked\", i.e. it waits for user input and won't return from\n  other call (like `child.api.nvim_exec_lua()`). Common causes are active\n  |hit-enter-prompt| (increase prompt height to a bigger value) or\n  Operator-pending mode (exit it). To mitigate this experience, most helpers\n  will throw an error if its immediate execution will lead to hanging state.\n  Also in case of hanging state try `child.api_notify` instead of `child.api`.\n\nNotes:\n- An important type of field is a \"redirection table\". It acts as a\n  convenience wrapper for corresponding `vim.*` table. Can be used both to\n  return and set values. Examples:\n    - `child.api.nvim_buf_line_count(0)` will execute\n      `vim.api.nvim_buf_line_count(0)` inside child process and return its\n      output to current process.\n    - `child.bo.filetype = 'lua'` will execute `vim.bo.filetype = 'lua'`\n      inside child process.\n  They still have same limitations listed above, so are not perfect. In\n  case of a doubt, use `child.lua()`.\n- Almost all methods use |vim.rpcrequest()| (i.e. wait for call to finish and\n  then return value). See for `*_notify` variant to use |vim.rpcnotify()|.\n- All fields and methods should be called with `.`, not `:`.\n\nClass ~\n{MiniTest.child}\n\nFields ~\n{start} `(function)` Start child process. See |MiniTest-child-neovim-start()|.\n{stop} `(function)` Stop current child process.\n{restart} `(function)` Restart child process: stop if running and then\n  start a new one. Takes same arguments as `child.start()` but uses values\n  from most recent `start()` call as defaults.\n\n{type_keys} `(function)` Emulate typing keys.\n  See |MiniTest-child-neovim-type_keys()|. Doesn't check for blocked state.\n\n{cmd} `(function)` Execute Vimscript code from a string.\n  A wrapper for |nvim_exec()| without capturing output.\n{cmd_capture} `(function)` Execute Vimscript code from a string and\n  capture output. A wrapper for |nvim_exec()| with capturing output.\n\n{lua} `(function)` Execute Lua code. A wrapper for |nvim_exec_lua()|.\n{lua_notify} `(function)` Execute Lua code without waiting for output.\n{lua_get} `(function)` Execute Lua code and return result. A wrapper\n  for |nvim_exec_lua()| but prepends string code with `return`.\n{lua_func} `(function)` Execute Lua function and return it's result.\n  Function will be called with all extra parameters (second one and later).\n  Note: usage of upvalues (data from outside function scope) is not allowed.\n\n{is_blocked} `(function)` Check whether child process is blocked.\n{is_running} `(function)` Check whether child process is currently running.\n\n{ensure_normal_mode} `(function)` Ensure normal mode.\n{get_screenshot} `(function)` Returns table with two \"2d arrays\" of single\n  characters representing what is displayed on screen and how it looks.\n  Has `opts` table argument for optional configuratnion.\n\n{job} `(table|nil)` Information about current job. If `nil`, child is not running.\n\n{api} `(table)` Redirection table for `vim.api`. Doesn't check for blocked state.\n{api_notify} `(table)` Same as `api`, but uses |vim.rpcnotify()|.\n\n{diagnostic} `(table)` Redirection table for |vim.diagnostic|.\n{fn} `(table)` Redirection table for |vim.fn|.\n{highlight} `(table)` Redirection table for |vim.highlight|.\n{hl} `(table)` Redirection table for |vim.hl|.\n{json} `(table)` Redirection table for `vim.json`.\n{loop} `(table)` Redirection table for |vim.loop|.\n{lsp} `(table)` Redirection table for `vim.lsp` (|lsp-core|).\n{mpack} `(table)` Redirection table for |vim.mpack|.\n{spell} `(table)` Redirection table for |vim.spell|.\n{treesitter} `(table)` Redirection table for `vim.treesitter` (|lua-treesitter-core|).\n{ui} `(table)` Redirection table for |vim.ui|. Currently of no\n  use because it requires sending function through RPC, which is impossible\n  at the moment.\n{fs} `(table)` Redirection table for |vim.fs|.\n\n{g} `(table)` Redirection table for |vim.g|.\n{b} `(table)` Redirection table for |vim.b|.\n{w} `(table)` Redirection table for |vim.w|.\n{t} `(table)` Redirection table for |vim.t|.\n{v} `(table)` Redirection table for |vim.v|.\n{env} `(table)` Redirection table for |vim.env|.\n\n{o} `(table)` Redirection table for |vim.o|.\n{go} `(table)` Redirection table for |vim.go|.\n{bo} `(table)` Redirection table for |vim.bo|.\n{wo} `(table)` Redirection table for |vim.wo|.\n\n------------------------------------------------------------------------------\n                                                 *MiniTest-child-neovim-start()*\n                          `child.start`({args}, {opts})\n\nStart child process and connect to it. Won't work if child is already running.\n\nParameters ~\n{args} `(table)` Array with arguments for executable. Will be prepended with\n  the following default arguments (see |startup-options|): >lua\n  { '--clean', '-n', '--listen', <some address>,\n    '--headless', '--cmd', 'set lines=24 columns=80' }\n<\n{opts} `(table|nil)` Options:\n  - <nvim_executable> - name of Neovim executable. Default: |v:progpath|.\n  - <connection_timeout> - stop trying to connect after this amount of\n    milliseconds. Default: 5000.\n\nUsage ~\n>lua\n  child = MiniTest.new_child_neovim()\n\n  -- Start default clean Neovim instance\n  child.start()\n\n  -- Start with custom 'init.lua' file\n  child.start({ '-u', 'scripts/minimal_init.lua' })\n<\n------------------------------------------------------------------------------\n                                             *MiniTest-child-neovim-type_keys()*\n                       `child.type_keys`({wait}, {...})\n\nBasically a wrapper for |nvim_input()| applied inside child process.\nDifferences:\n- Can wait after each group of characters.\n- Raises error if typing keys resulted into error in child process (i.e. its\n  |v:errmsg| was updated).\n- Key '<' as separate entry may not be escaped as '<LT>'.\n\nParameters ~\n{wait} `(number|nil)` Number of milliseconds to wait after each entry. May be\n  omitted, in which case no waiting is done.\n{...} `(string|table<number,string>)` Separate entries for |nvim_input()|,\n  after which `wait` will be applied. Can be either string or array of strings.\n\nUsage ~\n>lua\n  -- All of these type keys 'c', 'a', 'w'\n  child.type_keys('caw')\n  child.type_keys('c', 'a', 'w')\n  child.type_keys('c', { 'a', 'w' })\n\n  -- Waits 5 ms after `c` and after 'w'\n  child.type_keys(5, 'c', { 'a', 'w' })\n\n  -- Special keys can also be used\n  child.type_keys('i', 'Hello world', '<Esc>')\n<\n------------------------------------------------------------------------------\n                                        *MiniTest-child-neovim-get_screenshot()*\n                        `child.get_screenshot`({opts})\n\nCompute what is displayed on (default TUI) screen and how it is displayed.\nThis basically calls |screenstring()| and |screenattr()| for every visible\ncell (row from 1 to 'lines', column from 1 to 'columns').\n\nNotes:\n- To make output more portable and visually useful, outputs of\n  `screenattr()` are coded with single character symbols. Those are taken from\n  94 characters (ASCII codes between 33 and 126), so there will be duplicates\n  in case of more than 94 different ways text is displayed on screen.\n\nParameters ~\n{opts} `(table|nil)` Options. Possieble fields:\n  - <redraw> `(boolean)` - whether to call |:redraw| prior to computing\n    screenshot. Default: `true`.\n\nReturn ~\n`(table|nil)` Screenshot table with the following fields:\n  - <text> - \"2d array\" (row-column) of single characters displayed at\n    particular cells.\n  - <attr> - \"2d array\" (row-column) of symbols representing how text is\n    displayed (basically, \"coded\" appearance/highlighting). They should be\n    used only in relation to each other: same/different symbols for two\n    cells mean same/different visual appearance. Note: there will be false\n    positives if there are more than 94 different attribute values.\n  It also can be used with `tostring()` to convert to single string (used\n  for writing to reference file). It results into two visual parts\n  (separated by empty line), for `text` and `attr`. Each part has \"ruler\"\n  above content and line numbers for each line.\n  Returns `nil` if couldn't get a reasonable screenshot.\n\nUsage ~\n>lua\n  local screenshot = child.get_screenshot()\n\n  -- Show character displayed row=3 and column=4\n  print(screenshot.text[3][4])\n\n  -- Convert to string\n  tostring(screenshot)\n<\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-trailspace.txt",
    "content": "*mini.trailspace* Trailspace (highlight and remove)\n\nMIT License Copyright (c) 2021 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                *MiniTrailspace*\nFeatures:\n- Highlighting is done only in modifiable buffer by default, only in Normal\n  mode, and stops in Insert mode and when leaving window.\n\n- Trim all trailing whitespace with |MiniTrailspace.trim()|.\n\n- Trim all trailing empty lines with |MiniTrailspace.trim_last_lines()|.\n\n# Setup ~\n\nThis module needs a setup with `require('mini.trailspace').setup({})`\n(replace `{}` with your `config` table). It will create global Lua table\n`MiniTrailspace` which you can use for scripting or manually (with\n`:lua MiniTrailspace.*`).\n\nSee |MiniTrailspace.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minitrailspace_config` which should have same structure as\n`MiniTrailspace.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Highlight groups ~\n\n- `MiniTrailspace` - highlight group for trailing space.\n\nTo change any highlight group, set it directly with |nvim_set_hl()|.\n\n# Disabling ~\n\nTo disable, set `vim.g.minitrailspace_disable` (globally) or\n`vim.b.minitrailspace_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes. Note: after disabling\nthere might be highlighting left; it will be removed after next\nhighlighting update (see |events| and `MiniTrailspace` |:augroup|).\n\n------------------------------------------------------------------------------\n                                                        *MiniTrailspace.setup()*\n                        `MiniTrailspace.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniTrailspace.config|.\n\nUsage ~\n>lua\n  require('mini.trailspace').setup() -- use default config\n  -- OR\n  require('mini.trailspace').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                         *MiniTrailspace.config*\n                            `MiniTrailspace.config`\nDefaults ~\n>lua\n  MiniTrailspace.config = {\n    -- Highlight only in normal buffers (ones with empty 'buftype'). This is\n    -- useful to not show trailing whitespace where it usually doesn't matter.\n    only_in_normal_buffers = true,\n  }\n<\n------------------------------------------------------------------------------\n                                                    *MiniTrailspace.highlight()*\n                          `MiniTrailspace.highlight`()\nHighlight trailing whitespace in current window\n\n------------------------------------------------------------------------------\n                                                  *MiniTrailspace.unhighlight()*\n                         `MiniTrailspace.unhighlight`()\nUnhighlight trailing whitespace in current window\n\n------------------------------------------------------------------------------\n                                                         *MiniTrailspace.trim()*\n                            `MiniTrailspace.trim`()\nTrim trailing whitespace\n\n------------------------------------------------------------------------------\n                                              *MiniTrailspace.trim_last_lines()*\n                       `MiniTrailspace.trim_last_lines`()\nTrim last blank lines\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "doc/mini-visits.txt",
    "content": "*mini.visits* Track and reuse file system visits\n\nMIT License Copyright (c) 2023 Evgeni Chasnovski\n\n------------------------------------------------------------------------------\n                                                                    *MiniVisits*\nFeatures:\n\n- Persistently track file system visits (both files and directories)\n  per project directory. Store visit index is human readable and editable.\n\n- Visit index is normalized on every write to contain relevant information.\n  Exact details can be customized. See |MiniVisits.normalize_index()|.\n\n- Built-in ability to persistently add labels to path for later use.\n  See |MiniVisits.add_label()| and |MiniVisits.remove_label()|.\n\n- Exported functions to reuse visit data:\n    - List visited paths/labels with custom filter and sort (uses \"robust\n      frecency\" by default). Can be used as source for pickers.\n      See |MiniVisits.list_paths()| and |MiniVisits.list_labels()|.\n      See |MiniVisits.gen_filter| and |MiniVisits.gen_sort|.\n\n    - Select visited paths/labels using |vim.ui.select()|.\n      See |MiniVisits.select_path()| and |MiniVisits.select_label()|.\n\n    - Iterate through visit paths in target direction (\"forward\", \"backward\",\n      \"first\", \"last\"). See |MiniVisits.iterate_paths()|.\n\n- Exported functions to manually update visit index allowing persistent\n  track of any user information. See `*_index()` functions.\n\nNotes:\n- All data is stored _only_ in in-session Lua variable (for quick operation)\n  and at `config.store.path` on disk (for persistent usage).\n- Most of functions affect an in-session data which gets written to disk only\n  before Neovim is closing or when users asks to.\n- It doesn't account for paths being renamed or moved (because there is no\n  general way to detect that). Usually a manual intervention to the visit\n  index is required after the change but _before_ the next writing to disk\n  (usually before closing current session) because it will treat previous\n  path as deleted and remove it from index.\n  There is a |MiniVisits.rename_in_index()| helper for that.\n  If rename/move is done with |mini.files|, index is autoupdated.\n\nSources with more details:\n- |MiniVisits-overview|\n- |MiniVisits-index-specification|\n- |MiniVisits-examples|\n\n# Setup ~\n\nThis module needs a setup with `require('mini.visits').setup({})` (replace\n`{}` with your `config` table). It will create global Lua table `MiniVisits`\nwhich you can use for scripting or manually (with `:lua MiniVisits.*`).\n\nSee |MiniVisits.config| for `config` structure and default values.\n\nYou can override runtime config settings locally to buffer inside\n`vim.b.minivisits_config` which should have same structure as\n`MiniVisits.config`. See |mini.nvim-buffer-local-config| for more details.\n\n# Comparisons ~\n\n- [nvim-telescope/telescope-frecency.nvim](https://github.com/nvim-telescope/telescope-frecency.nvim):\n    - It stores array of actual visit timestamps, while this module tracks\n      only total number and latest timestamp of visits. This is by design\n      as a different trade-off between how much data is being used/stored\n      and complexity of underlying \"frecency\" sorting.\n    - By default tracks a buffer only once per session, while this module\n      tracks on every meaningful buffer enter. This leads to a more relevant\n      in-session sorting.\n    - Implements an original frecency algorithm of Firefox's address bar,\n      while this module uses own \"robust frecency\" approach.\n    - Mostly designed to work with 'nvim-telescope/telescope.nvim', while\n      this module provides general function to list paths and select\n      with |vim.ui.select()|.\n    - Does not allow use of custom data (like labels), while this module does.\n\n- [ThePrimeagen/harpoon](https://github.com/ThePrimeagen/harpoon):\n    - Has slightly different concept than general labeling, which more\n      resembles adding paths to an ordered stack. This module implements\n      a more common labeling which does not imply order with ability to\n      make it automated depending on the task and/or preference.\n    - Implements marks as positions in a path, while this module labels paths.\n    - Writes data on disk after every meaning change, while this module is\n      more conservative and read only when Neovim closes or when asked to.\n    - Has support for labeling terminals, while this modules is oriented\n      only towards paths.\n    - Has dedicated UI to manage marks, while this module does not by design.\n      There are functions for adding and removing label from the path.\n    - Does not provide functionality to track and reuse any visited path,\n      while this module does.\n\n# Disabling ~\n\nTo disable automated tracking, set `vim.g.minivisits_disable` (globally) or\n`vim.b.minivisits_disable` (for a buffer) to `true`. Considering high\nnumber of different scenarios and customization intentions, writing exact\nrules for disabling module's functionality is left to user. See\n|mini.nvim-disabling-recipes| for common recipes.\n\n------------------------------------------------------------------------------\n                                                           *MiniVisits-overview*\n# Tracking visits ~\n\nFile system visits (both directory and files) tracking is done in two steps:\n- On every dedicated event (`config.track.event`, |BufEnter| by default) timer\n  is (re)started to actually register visit after certain amount of time\n  (`config.track.delay` milliseconds, 1000 by default). It is not registered\n  immediately to allow navigation to target buffer in several steps\n  (for example, with series of |:bnext| / |:bprevious|).\n\n- When delay time passes without any dedicated events being triggered\n  (meaning user is \"settled\" on certain buffer), |MiniVisits.register_visit()|\n  is called if all of the following conditions are met:\n    - Module is not disabled (see \"Disabling\" section in |mini.visits|).\n    - Buffer is normal with non-empty name (used as visit path).\n    - Visit path does not equal to the latest tracked one. This is to allow\n      temporary enter of non-normal buffers (like help, terminal, etc.)\n      without artificial increase of visit count.\n\nVisit is autoregistered for |current-directory| and leads to increase of count\nand latest time of visit. See |MiniVisits-index-specification| for more details.\n\nNotes:\n- All data is stored _only_ in in-session Lua variable (for quick operation)\n  and at `config.store.path` on disk (for persistent usage). It is automatically\n  written to disk before every Neovim exit (if `config.store.autowrite` is set).\n\n- Tracking can be disabled by supplying empty string as `track.event`.\n  Then it is up to the user to properly call |MiniVisits.register_visit()|.\n\n# Reusing visits ~\n\nVisit data can be reused in at least these ways:\n\n- Get a list of visited paths (see |MiniVisits.list_paths()|) and use it\n  to visualize/pick/navigate visit history.\n\n- Select one of the visited paths to open it (see |MiniVisits.select_path()|).\n\n- Move along visit history (see |MiniVisits.iterate_paths()|).\n\n- Utilize labels. Any visit can be added one or more labels (like \"core\",\n  \"tmp\", etc.). They are bound to the visit (path registered for certain\n  directory) and are stored persistently.\n  Labels can be used to manually create groups of files and/or directories\n  that have particular interest to the user.\n  There is no one right way to use them, though. See |MiniVisits-examples|\n  for some inspiration.\n\n- Utilizing custom data. Visit index can be manipulated manually using\n  `_index()` set of functions. All \"storable\" (i.e. not functions or\n  metatables) user data inside index is then stored on disk, so it can be\n  used to create any kind of workflow user wants.\n\nSee |MiniVisits-examples| for some actual configuration and workflow examples.\n\n------------------------------------------------------------------------------\n                                                *MiniVisits-index-specification*\n# Structure ~\n\nVisit index is a table containing actual data in two level deep nested tables.\n\nFirst level keys are paths of project directory (a.k.a \"cwd\") for which\nvisits are registered.\n\nSecond level keys are actual visit paths. Their values are tables with visit\ndata which should follow these requirements:\n- Field <count> should be present and be a number. It represents the number\n  of times this path was visited under particular cwd.\n- Field <latest> should be present and be a number. It represents the time\n  of latest path visit under particular cwd.\n  By default computed with |os.time()| (up to a second).\n- Field <labels> might not be present. If present, it should be a table\n  with string labels as keys and `true` as values. It represents labels of\n  the path under particular cwd.\n\nNotes:\n- All paths are absolute.\n- Visit path should not necessarily be a part of corresponding cwd.\n- Both `count` and `latest` can be any number: whole, fractional, negative, etc.\n\nExample of an index data: >lua\n\n  {\n    ['/home/user/project_1'] = {\n      ['home/user/project_1/file'] = { count = 3, latest = 1699796000 },\n      ['home/user/project_1/subdir'] = {\n        count = 10, latest = 1699797000, labels = { core = true },\n      },\n    },\n    ['/home/user/project_2'] = {\n      ['home/user/project_1/file'] = {\n        count = 0, latest = 0, labels = { other = true },\n      },\n      ['home/user/project_2/README'] = { count = 1, latest = 1699798000 },\n    },\n  }\n<\n# Storage ~\n\nWhen stored on disk, visit index is a file containing Lua code returning\nvisit index table. It can be edited by hand as long as it contains a valid\nLua code (to be executed with |dofile()|).\n\nNotes:\n- Storage is implemented in such a way that it doesn't really support more\n  than one parallel Neovim processes. Meaning that if there are two or more\n  simultaneous Neovim processes with same visit index storage path, the last\n  one writing to it will preserve its visit history while others - won't.\n\n# Normalization ~\n\nTo ensure that visit index contains mostly relevant data, it gets normalized:\nautomatically inside |MiniVisits.write_index()| or\nvia |MiniVisits.normalize_index()|.\n\nWhat normalization actually does can be configured in `config.store.normalize`.\n\nSee |MiniVisits.gen_normalize.default()| for default normalization approach.\n\n------------------------------------------------------------------------------\n                                                           *MiniVisits-examples*\nThis module provides a flexible framework for working with file system visits.\nExact choice of how to organize workflow is left to the user.\nHere are some examples for inspiration which can be combined together.\n\n# Use different sorting ~\n\nDefault sorting in |MiniVisits.gen_sort.default()| allows flexible adjustment\nof which feature to prefer more: recency or frequency. Here is an example of\nhow to make set of keymaps for three types of sorting combined with two types\nof scopes (all visits and only for current cwd): >lua\n\n  local make_select_path = function(select_global, recency_weight)\n    local visits = require('mini.visits')\n    local sort = visits.gen_sort.default({ recency_weight = recency_weight })\n    local select_opts = { sort = sort }\n    return function()\n      local cwd = select_global and '' or vim.fn.getcwd()\n      visits.select_path(cwd, select_opts)\n    end\n  end\n\n  local map = function(lhs, desc, ...)\n    vim.keymap.set('n', lhs, make_select_path(...), { desc = desc })\n  end\n\n  -- Adjust LHS and description to your liking\n  map('<Leader>vr', 'Select recent (all)',   true,  1)\n  map('<Leader>vR', 'Select recent (cwd)',   false, 1)\n  map('<Leader>vy', 'Select frecent (all)',  true,  0.5)\n  map('<Leader>vY', 'Select frecent (cwd)',  false, 0.5)\n  map('<Leader>vf', 'Select frequent (all)', true,  0)\n  map('<Leader>vF', 'Select frequent (cwd)', false, 0)\n<\nNote: If using |mini.pick|, consider |MiniExtra.pickers.visit_paths()|.\n\n# Use manual labels ~\n\nLabels is a powerful tool to create groups of associated paths.\nUsual workflow consists of:\n- Add label with |MiniVisits.add_label()| (prompts for actual label).\n- Remove label with |MiniVisits.remove_label()| (prompts for actual label).\n- When need to use labeled groups, call |MiniVisits.select_label()| which\n  will then call |MiniVisits.select_path()| to select path among those\n  having selected label.\n  Note: If using |mini.pick|, consider |MiniExtra.pickers.visit_labels()|.\n\nTo make this workflow smoother, here is an example of keymaps: >lua\n\n  local map_vis = function(keys, call, desc)\n    local rhs = '<Cmd>lua MiniVisits.' .. call .. '<CR>'\n    vim.keymap.set('n', '<Leader>' .. keys, rhs, { desc = desc })\n  end\n\n  map_vis('vv', 'add_label()',          'Add label')\n  map_vis('vV', 'remove_label()',       'Remove label')\n  map_vis('vl', 'select_label(\"\", \"\")', 'Select label (all)')\n  map_vis('vL', 'select_label()',       'Select label (cwd)')\n<\n# Use fixed labels ~\n\nDuring work on every project there is usually a handful of files where core\nactivity is concentrated. This can be made easier by creating mappings\nwhich add/remove special fixed label (for example, \"core\") and select paths\nwith that label for both all and current cwd. Example: >lua\n\n  -- Create and select\n  local map_vis = function(keys, call, desc)\n    local rhs = '<Cmd>lua MiniVisits.' .. call .. '<CR>'\n    vim.keymap.set('n', '<Leader>' .. keys, rhs, { desc = desc })\n  end\n\n  map_vis('vv', 'add_label(\"core\")',                     'Add to core')\n  map_vis('vV', 'remove_label(\"core\")',                  'Remove from core')\n  map_vis('vc', 'select_path(\"\", { filter = \"core\" })',  'Select core (all)')\n  map_vis('vC', 'select_path(nil, { filter = \"core\" })', 'Select core (cwd)')\n\n  -- Iterate based on recency\n  local sort_latest = MiniVisits.gen_sort.default({ recency_weight = 1 })\n  local map_iterate_core = function(lhs, direction, desc)\n    local opts = { filter = 'core', sort = sort_latest, wrap = true }\n    local rhs = function()\n      MiniVisits.iterate_paths(direction, vim.fn.getcwd(), opts)\n    end\n    vim.keymap.set('n', lhs, rhs, { desc = desc })\n  end\n\n  map_iterate_core('[{', 'last',     'Core label (earliest)')\n  map_iterate_core('[[', 'forward',  'Core label (earlier)')\n  map_iterate_core(']]', 'backward', 'Core label (later)')\n  map_iterate_core(']}', 'first',    'Core label (latest)')\n<\n# Use automated labels ~\n\nWhen using version control system (such as Git), usually there is already\nan identifier that groups files you are working with - branch name.\nHere is an example of keymaps to add/remove label equal to branch name: >lua\n\n  local map_branch = function(keys, action, desc)\n    local rhs = function()\n      local branch = vim.fn.system('git rev-parse --abbrev-ref HEAD')\n      if vim.v.shell_error ~= 0 then return nil end\n      branch = vim.trim(branch)\n      require('mini.visits')[action](branch)\n    end\n    vim.keymap.set('n', '<Leader>' .. keys, rhs, { desc = desc })\n  end\n\n  map_branch('vb', 'add_label',    'Add branch label')\n  map_branch('vB', 'remove_label', 'Remove branch label')\n<\n------------------------------------------------------------------------------\n                                                            *MiniVisits.setup()*\n                          `MiniVisits.setup`({config})\nModule setup\n\nParameters ~\n{config} `(table|nil)` Module config table. See |MiniVisits.config|.\n\nUsage ~\n>lua\n  require('mini.visits').setup() -- use default config\n  -- OR\n  require('mini.visits').setup({}) -- replace {} with your config table\n<\n------------------------------------------------------------------------------\n                                                             *MiniVisits.config*\n                              `MiniVisits.config`\nDefaults ~\n>lua\n  MiniVisits.config = {\n    -- How visit index is converted to list of paths\n    list = {\n      -- Predicate for which paths to include (all by default)\n      filter = nil,\n\n      -- Sort paths based on the visit data (robust frecency by default)\n      sort = nil,\n    },\n\n    -- Whether to disable showing non-error feedback\n    silent = false,\n\n    -- How visit index is stored\n    store = {\n      -- Whether to write all visits before Neovim is closed\n      autowrite = true,\n\n      -- Function to ensure that written index is relevant\n      normalize = nil,\n\n      -- Path to store visit index\n      path = vim.fn.stdpath('data') .. '/mini-visits-index',\n    },\n\n    -- How visit tracking is done\n    track = {\n      -- Start visit register timer at this event\n      -- Supply empty string (`''`) to not do this automatically\n      event = 'BufEnter',\n\n      -- Debounce delay after event to register a visit\n      delay = 1000,\n    },\n  }\n<\n# List ~\n*MiniVisits.config.list*\n\n`config.list` defines how visit index is converted to a path list by default.\n\n`list.filter` is a callable which should take a path data and return `true` if\nthis path should be present in the list.\nDefault: output of |MiniVisits.gen_filter.default()|.\n\nPath data is a table with at least these fields:\n- <path> `(string)` - absolute path of visit.\n- <count> `(number)` - number of visits.\n- <latest> `(number)` - timestamp of latest visit.\n- <labels> `(table|nil)` - table of labels (has string keys with `true` values).\n\nNotes:\n- Both `count` and `latest` (in theory) can be any number. But built-in tracking\n  results into positive integer `count` and `latest` coming from |os.time()|.\n- There can be other entries if they are set by user as index entry.\n\n`list.sort` is a callable which should take an array of path data and return\na sorted array of path data (or at least tables each containing <path> field).\nDefault: output of |MiniVisits.gen_sort.default()|.\nSingle path data entry is a table with a same structure as for `list.filter`.\n\nNote, that `list.sort` can be used both to filter, sort, or even return paths\nunrelated to the input.\n\n# Silent ~\n\n`config.silent` is a boolean controlling whether to show non-error feedback\n(like adding/removing labels, etc.). Default: `false`.\n\n# Store ~\n\n`config.store` defines how visit index is stored on disk to enable persistent\ndata across several sessions.\n\n`store.autowrite` is a boolean controlling whether to write visit data to\ndisk on |VimLeavePre| event. Default: `true`.\n\n`store.normalize` is a callable which should take visit index\n(see |MiniVisits-index-specification|) as input and return \"normalized\" visit\nindex as output. This is used to ensure that visit index is up to date and\ncontains only relevant data. For example, it controls how old and\nirrelevant visits are \"forgotten\", and more.\nDefault: output of |MiniVisits.gen_normalize.default()|.\n\n`store.path` is a path to which visit index is written. See \"Storage\" section\nof |MiniVisits-index-specification| for more details.\nNote: set to empty string to disable any writing with not explicitly set\npath (including the one on |VimLeavePre|).\nDefault: \"mini-visits-index\" file inside |$XDG_DATA_HOME|.\n\n# Track ~\n\n`config.track` defines how visits are tracked (index entry is autoupdated).\nSee \"Tracking visits\" section in |MiniVisits-overview| for more details.\n\n`track.event` is a proper Neovim |{event}| on which track get triggered.\nNote: set to empty string to disable automated tracking.\nDefault: |BufEnter|.\n\n`track.delay` is a delay in milliseconds after event is triggered and visit\nis autoregistered.\nDefault: 1000 (to allow navigation between buffers without tracking\nintermediate ones).\n\n------------------------------------------------------------------------------\n                                                   *MiniVisits.register_visit()*\n                   `MiniVisits.register_visit`({path}, {cwd})\nRegister visit\n\nSteps:\n- Ensure that there is an entry for path-cwd pair.\n- Add 1 to visit `count`.\n- Set `latest` visit time to equal current time.\n\nParameters ~\n{path} `(string|nil)` Visit path. Default: path of current buffer if normal,\n  error otherwise.\n{cwd} `(string|nil)` Visit cwd (project directory). Default: |current-directory|.\n\n------------------------------------------------------------------------------\n                                                         *MiniVisits.add_path()*\n                      `MiniVisits.add_path`({path}, {cwd})\nAdd path to index\n\nEnsures that there is a (one or more) entry for path-cwd pair. If entry is\nalready present, does nothing. If not - creates it with both `count` and\n`latest` set to 0.\n\nParameters ~\n{path} `(string|nil)` Visit path. Can be empty string to mean \"all visited\n  paths for `cwd`\". Default: path of current buffer if normal, error otherwise.\n{cwd} `(string|nil)` Visit cwd (project directory). Can be empty string to mean\n  \"all visited cwd\". Default: |current-directory|.\n\n------------------------------------------------------------------------------\n                                                        *MiniVisits.add_label()*\n                 `MiniVisits.add_label`({label}, {path}, {cwd})\nAdd label to path\n\nSteps:\n- Ensure that there is an entry for path-cwd pair.\n- Add label to the entry.\n\nParameters ~\n{label} `(string|nil)` Label string. Default: `nil` to ask from user.\n{path} `(string|nil)` Visit path. Can be empty string to mean \"all visited\n  paths for `cwd`\". Default: path of current buffer if normal, error otherwise.\n{cwd} `(string|nil)` Visit cwd (project directory). Can be empty string to mean\n  \"all visited cwd\". Default: |current-directory|.\n\n------------------------------------------------------------------------------\n                                                      *MiniVisits.remove_path()*\n                    `MiniVisits.remove_path`({path}, {cwd})\nRemove path\n\nDeletes a (one or more) entry for path-cwd pair from an index. If entry is\nalready absent, does nothing.\n\nNotes:\n- Affects only in-session Lua variable. Call |MiniVisits.write_index()| to\n  make it persistent.\n\nParameters ~\n{path} `(string|nil)` Visit path. Can be empty string to mean \"all visited\n  paths for `cwd`\". Default: path of current buffer if normal, error otherwise.\n{cwd} `(string|nil)` Visit cwd (project directory). Can be empty string to mean\n  \"all visited cwd\". Default: |current-directory|.\n\n------------------------------------------------------------------------------\n                                                     *MiniVisits.remove_label()*\n               `MiniVisits.remove_label`({label}, {path}, {cwd})\nRemove label from path\n\nSteps:\n- Remove label from (one or more) index entry.\n- If it was last label in an entry, remove `labels` key.\n\nParameters ~\n{label} `(string|nil)` Label string. Default: `nil` to ask from user.\n{path} `(string|nil)` Visit path. Can be empty string to mean \"all visited\n  paths for `cwd`\". Default: path of current buffer if normal, error otherwise.\n{cwd} `(string|nil)` Visit cwd (project directory). Can be empty string to mean\n  \"all visited cwd\". Default: |current-directory|.\n\n------------------------------------------------------------------------------\n                                                       *MiniVisits.list_paths()*\n                     `MiniVisits.list_paths`({cwd}, {opts})\nList visit paths\n\nConvert visit index for certain cwd into an ordered list of visited paths.\nSupports custom filtering and sorting.\n\nExamples: >lua\n\n  -- Get paths sorted from most to least recent\n  local sort_recent = MiniVisits.gen_sort.default({ recency_weight = 1 })\n  MiniVisits.list_paths(nil, { sort = sort_recent })\n\n  -- Get paths from all cwd sorted from most to least frequent\n  local sort_frequent = MiniVisits.gen_sort.default({ recency_weight = 0 })\n  MiniVisits.list_paths('', { sort = sort_frequent })\n\n  -- Get paths not including hidden\n  local is_not_hidden = function(path_data)\n    return not vim.startswith(vim.fn.fnamemodify(path_data.path, ':t'), '.')\n  end\n  MiniVisits.list_paths(nil, { filter = is_not_hidden })\n<\nParameters ~\n{cwd} `(string|nil)` Visit cwd (project directory). Can be empty string to mean\n  \"all visited cwd\". Default: |current-directory|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function)` - predicate to filter paths. For more information\n    about how it is used, see |MiniVisits.config.list|.\n    Default: value of `config.list.filter` with |MiniVisits.gen_filter.default()|\n    as its default.\n  - <sort> `(function)` - path data sorter. For more information about how\n    it is used, see |MiniVisits.config.list|.\n    Default: value of `config.list.sort` or |MiniVisits.gen_sort.default()|\n    as its default.\n\nReturn ~\n`(table)` Array of visited paths.\n\n------------------------------------------------------------------------------\n                                                      *MiniVisits.list_labels()*\n                `MiniVisits.list_labels`({path}, {cwd}, {opts})\nList visit labels\n\nConvert visit index for certain path-cwd pair into an ordered list of labels.\nSupports custom filtering for paths. Result is ordered from most to least\nfrequent label.\n\nExamples: >lua\n\n  -- Get labels for current path-cwd pair\n  MiniVisits.list_labels()\n\n  -- Get labels for current path across all cwd\n  MiniVisits.list_labels(nil, '')\n\n  -- Get all available labels excluding ones from hidden files\n  local is_not_hidden = function(path_data)\n    return not vim.startswith(vim.fn.fnamemodify(path_data.path, ':t'), '.')\n  end\n  MiniVisits.list_labels('', '', { filter = is_not_hidden })\n<\nParameters ~\n{path} `(string|nil)` Visit path. Can be empty string to mean \"all visited\n  paths for `cwd`\". Default: path of current buffer if normal, error otherwise.\n{cwd} `(string|nil)` Visit cwd (project directory). Can be empty string to mean\n  \"all visited cwd\". Default: |current-directory|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function)` - predicate to filter paths. For more information\n    about how it is used, see |MiniVisits.config.list|.\n    Default: value of `config.list.filter` with |MiniVisits.gen_filter.default()|\n    as its default.\n  - <sort> `(function)` - path data sorter. For more information about how\n    it is used, see |MiniVisits.config.list|.\n    Default: value of `config.list.sort` or |MiniVisits.gen_sort.default()|\n    as its default.\n\nReturn ~\n`(table)` Array of available labels.\n\n------------------------------------------------------------------------------\n                                                      *MiniVisits.select_path()*\n                    `MiniVisits.select_path`({cwd}, {opts})\nSelect visit path\n\nUses |vim.ui.select()| with an output of |MiniVisits.list_paths()| and\ncalls |:edit| on the chosen item.\n\nNote: if you have |mini.pick|, consider using |MiniExtra.pickers.visit_labels()|\nand |MiniExtra.pickers.visit_paths()|.\n\nExamples:\n\n- Select from all visited paths: `MiniVisits.select_path('')`\n\n- Select from paths under current directory sorted from most to least recent: >lua\n\n    local sort_recent = MiniVisits.gen_sort.default({ recency_weight = 1 })\n    MiniVisits.select_path(nil, { sort = sort_recent })\n<\nParameters ~\n{cwd} `(string|nil)` Forwarded to |MiniVisits.list_paths()|.\n{opts} `(table|nil)` Forwarded to |MiniVisits.list_paths()|.\n\n------------------------------------------------------------------------------\n                                                     *MiniVisits.select_label()*\n                `MiniVisits.select_label`({path}, {cwd}, {opts})\nSelect visit label\n\nUses |vim.ui.select()| with an output of |MiniVisits.list_labels()| and\ncalls |MiniVisits.select_path()| to get target paths with selected label.\n\nNote: if you have |mini.pick|, consider using |MiniExtra.pickers.visit_labels()|.\n\nExamples:\n\n- Select from labels of current path: `MiniVisits.select_label()`\n\n- Select from all visited labels: `MiniVisits.select_label('', '')`\n\n- Select from current project labels and sort paths (after choosing) from most\n  to least recent: >lua\n\n    local sort_recent = MiniVisits.gen_sort.default({ recency_weight = 1 })\n    MiniVisits.select_label('', nil, { sort = sort_recent })\n<\nParameters ~\n{path} `(string|nil)` Forwarded to |MiniVisits.list_labels()|.\n{cwd} `(string|nil)` Forwarded to |MiniVisits.list_labels()|.\n{opts} `(table|nil)` Forwarded to both |MiniVisits.list_labels()|\n and |MiniVisits.select_path()| (after choosing a label).\n\n------------------------------------------------------------------------------\n                                                    *MiniVisits.iterate_paths()*\n             `MiniVisits.iterate_paths`({direction}, {cwd}, {opts})\nIterate visit paths\n\nSteps:\n- Compute a sorted array of target paths using |MiniVisits.list_paths()|.\n- Identify the current index inside the array based on path of current buffer.\n- Iterate through the array certain amount of times in a dedicated direction:\n    - For \"first\" direction - forward starting from index 0 (so that single\n      first iteration leads to first path).\n    - For \"backward\" direction - backward starting from current index.\n    - For \"forward\" direction - forward starting from current index.\n    - For \"last\" direction - backward starting from index after the last one\n      (so that single first iteration leads to the last path).\n\nNotes:\n- Mostly designed to be used as a mapping. See `MiniVisits-examples`.\n- If path from current buffer is not in the output of `MiniVisits.list_paths()`,\n  starting index is inferred such that first iteration lands on first item\n  (if iterating forward) or last item (if iterating backward).\n- Navigation with this function is not tracked (see |MiniVisits-overview|).\n  This is done to allow consecutive application without affecting\n  underlying list of paths.\n\nExamples assuming underlying array of files `{ \"file1\", \"file2\", \"file3\" }`:\n\n- `MiniVisits(\"first\")` results into focusing on \"file1\".\n- `MiniVisits(\"backward\", { n_times = 2 })` from \"file3\" results into \"file1\".\n- `MiniVisits(\"forward\", { n_times = 10 })` from \"file1\" results into \"file3\".\n- `MiniVisits(\"last\", { n_times = 4, wrap = true })` results into \"file3\".\n\nParameters ~\n{direction} `(string)` One of \"first\", \"backward\", \"forward\", \"last\".\n{cwd} `(string|nil)` Forwarded to |MiniVisits.list_paths()|.\n{opts} `(table|nil)` Options. Possible fields:\n  - <filter> `(function)` - forwarded to |MiniVisits.list_paths()|.\n  - <sort> `(function)` - forwarded to |MiniVisits.list_paths()|.\n  - <n_times> `(number)` - number of steps to go in certain direction.\n    Default: |v:count1|.\n  - <wrap> `(boolean)` - whether to wrap around list edges. Default: `false`.\n\n------------------------------------------------------------------------------\n                                                        *MiniVisits.get_index()*\n                            `MiniVisits.get_index`()\nGet active visit index\n\nReturn ~\n`(table)` Copy of currently active visit index table.\n\n------------------------------------------------------------------------------\n                                                        *MiniVisits.set_index()*\n                        `MiniVisits.set_index`({index})\nSet active visit index\n\nParameters ~\n{index} `(table)` Visit index table.\n\n------------------------------------------------------------------------------\n                                                      *MiniVisits.reset_index()*\n                           `MiniVisits.reset_index`()\nReset active visit index\n\nSet currently active visit index to the output of |MiniVisits.read_index()|.\nDoes nothing if reading the index failed.\n\n------------------------------------------------------------------------------\n                                                  *MiniVisits.normalize_index()*\n                     `MiniVisits.normalize_index`({index})\nNormalize visit index\n\nApplies `config.store.normalize` (|MiniVisits.gen_normalize.default()| by default)\nto the input index object and returns the output (if it fits in the definition\nof index object; see |MiniVisits-index-specification|).\n\nParameters ~\n{index} `(table|nil)` Index object. Default: copy of the current index.\n\nReturn ~\n`(table)` Normalized index object.\n\n------------------------------------------------------------------------------\n                                                       *MiniVisits.read_index()*\n                     `MiniVisits.read_index`({store_path})\nRead visit index from disk\n\nParameters ~\n{store_path} `(string|nil)` Path on the disk containing visit index data.\n  Default: `config.store.path`.\n  Notes:\n  - Can return `nil` if path is empty string or file is not readable.\n  - File is sourced with |dofile()| as a regular Lua file.\n\nReturn ~\n`(table|nil)` Output of the file source.\n\n------------------------------------------------------------------------------\n                                                      *MiniVisits.write_index()*\n                `MiniVisits.write_index`({store_path}, {index})\nWrite visit index to disk\n\nSteps:\n- Normalize index with |MiniVisits.normalize_index()|.\n- Ensure path is valid (all parent directories are created, etc.).\n- Write index object to the path so that it is readable\n  with |MiniVisits.read_index()|.\n\nParameters ~\n{store_path} `(string|nil)` Path on the disk where to write visit index data.\n  Default: `config.store.path`. Note: if empty string, nothing is written.\n{index} `(table|nil)` Index object to write to disk.\n  Default: current session index.\n\n------------------------------------------------------------------------------\n                                                  *MiniVisits.rename_in_index()*\n         `MiniVisits.rename_in_index`({path_from}, {path_to}, {index})\nRename path in index\n\nA helper to react for a path rename/move in order to preserve its visit data.\nIt works both for file and directory paths.\n\nNotes:\n- It does not update current index, but returns a modified index object.\n  Use |MiniVisits.set_index()| to make it current.\n- Use only full paths.\n- Do not append `/` to directory paths. Use same format as for files.\n\nAssuming `path_from` and `path_to` are variables containing full paths\nbefore and after rename/move, here is an example to update current index: >lua\n\n  local new_index = MiniVisits.rename_in_index(path_from, path_to)\n  MiniVisits.set_index(new_index)\n<\nParameters ~\n{path_from} `(string)` Full path to be renamed.\n{path_to} `(string)` Full path to be replaced with.\n{index} `(table|nil)` Index object inside which to perform renaming.\n  Default: current session index.\n\nReturn ~\n`(table)` Index object with renamed path.\n\n------------------------------------------------------------------------------\n                                                         *MiniVisits.gen_filter*\n                            `MiniVisits.gen_filter`\nGenerate filter function\n\nThis is a table with function elements. Call to actually get specification.\n\n------------------------------------------------------------------------------\n                                               *MiniVisits.gen_filter.default()*\n                       `MiniVisits.gen_filter.default`()\nDefault filter\n\nAlways returns `true` resulting in no actual filter.\n\nReturn ~\n`(function)` Visit filter function. See |MiniVisits.config.list| for more details.\n\n------------------------------------------------------------------------------\n                                          *MiniVisits.gen_filter.this_session()*\n                     `MiniVisits.gen_filter.this_session`()\nFilter visits from current session\n\nReturn ~\n`(function)` Visit filter function. See |MiniVisits.config.list| for more details.\n\n------------------------------------------------------------------------------\n                                                           *MiniVisits.gen_sort*\n                             `MiniVisits.gen_sort`\nGenerate sort function\n\nThis is a table with function elements. Call to actually get specification.\n\n------------------------------------------------------------------------------\n                                                 *MiniVisits.gen_sort.default()*\n                     `MiniVisits.gen_sort.default`({opts})\nDefault sort\n\nSort paths using \"robust frecency\" approach. It relies on the rank operation:\nbased on certain reference number for every item, assign it a number\nbetween 1 (best) and number of items (worst). Ties are dealt with \"average\nrank\" approach: each element with a same reference number is assigned\nan average rank among such elements. This way total rank sum depends only\non number of paths.\n\nHere is an algorithm outline:\n- Rank paths based on frequency (`count` value): from most to least frequent.\n- Rank paths based on recency (`latest` value): from most to least recent.\n- Combine ranks from previous steps with weights:\n  `score = (1 - w) * rank_frequency + w * rank_recency`, where `w` is\n  \"recency weight\". The smaller this weight the less recency affects outcome.\n\nExamples:\n- Default recency weight 0.5 results into \"robust frecency\" sorting: it\n  combines both frequency and recency.\n  This is called a \"robust frecency\" because actual values don't have direct\n  effect on the outcome, only ordering matters. For example, if there is\n  a very frequent file with `count = 100` while all others have `count = 5`,\n  it will not massively dominate the outcome as long as it is not very recent.\n\n- Having recency weight 1 results into \"from most to least recent\" sorting.\n\n- Having recency weight 0 results into \"from most to least frequent\" sorting.\n\nParameters ~\n{opts} `(table|nil)` Option. Possible fields:\n  - <recency_weight> `(number)` - a number between 0 and 1 for recency weight.\n    Default: 0.5.\n\nReturn ~\n`(function)` Visit sort function. See |MiniVisits.config.list| for more details.\n\n------------------------------------------------------------------------------\n                                                       *MiniVisits.gen_sort.z()*\n                           `MiniVisits.gen_sort.z`()\nZ sort\n\nSort as in https://github.com/rupa/z.\n\nReturn ~\n`(function)` Visit sort function. See |MiniVisits.config.list| for more details.\n\n------------------------------------------------------------------------------\n                                                      *MiniVisits.gen_normalize*\n                           `MiniVisits.gen_normalize`\nGenerate normalize function\n\nThis is a table with function elements. Call to actually get specification.\n\n------------------------------------------------------------------------------\n                                            *MiniVisits.gen_normalize.default()*\n                   `MiniVisits.gen_normalize.default`({opts})\nGenerate default normalize function\n\nSteps:\n- Prune visits, i.e. remove outdated visits:\n    - If `count` number of visits is below prune threshold, remove that visit\n      entry from particular cwd (it can still be present in others).\n    - If either first (cwd) or second (path) level key doesn't represent an\n      actual path on disk, remove the whole associated value.\n    - NOTE: if visit has any label, it is not automatically pruned.\n\n- Decay visits, i.e. possibly make visits more outdated. This is an important\n  part to the whole usability: together with pruning it results into automated\n  removing of paths which were visited long ago and are not relevant.\n\n  Decay is done per cwd if its total `count` values sum exceeds decay threshold.\n  It is performed through multiplying each `count` by same coefficient so that\n  the new total sum of `count` is equal to some smaller target value.\n  Note: only two decimal places are preserved, so the sum might not be exact.\n\n- Prune once more to ensure that there are no outdated paths after decay.\n\nParameters ~\n{opts} `(table|nil)` Options. Possible fields:\n  - <decay_threshold> `(number)` - decay threshold. Default: 1000.\n  - <decay_target> `(number)` - decay target. Default: 800.\n  - <prune_threshold> `(number)` - prune threshold. Default: 0.5.\n  - <prune_paths> `(boolean)` - whether to prune outdated paths. Default: `true`.\n\nReturn ~\n`(function)` Visit index normalize function. See \"Store\" in |MiniVisits.config|.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "lua/mini/ai.lua",
    "content": "--- *mini.ai* Extend and create a/i textobjects\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Enhance some builtin |text-objects| (like |a(|, |a)|, |a'|, and more),\n--- create new ones (like `a*`, `a<Space>`, `af`, `a?`, and more), and allow\n--- user to create their own.\n---\n--- Features:\n--- - Customizable creation of `a`/`i` textobjects using Lua patterns and functions.\n---   Supports:\n---     - Dot-repeat.\n---     - |v:count|.\n---     - Different search methods (see |MiniAi.config|).\n---     - Consecutive application (update selection without leaving Visual mode).\n---     - Aliases for multiple textobjects.\n---\n--- - Comprehensive builtin textobjects (see more in |MiniAi-builtin-textobjects|):\n---     - Balanced brackets (with and without whitespace) plus alias.\n---     - Balanced quotes plus alias.\n---     - Function call.\n---     - Argument.\n---     - Tag.\n---     - Derived from user prompt.\n---     - Default for anything but Latin letters (to fall back to |text-objects|).\n---\n---     For more textobjects see |MiniExtra.gen_ai_spec|.\n---\n--- - Motions for jumping to left/right edge of textobject.\n---\n--- - Set of specification generators to tweak some builtin textobjects (see\n---   |MiniAi.gen_spec|).\n---\n--- - Treesitter textobjects (through |MiniAi.gen_spec.treesitter()| helper).\n---\n--- This module works by defining mappings for both `a` and `i` in Visual and\n--- Operator-pending mode. After typing, they wait for single character user input\n--- treated as textobject identifier and apply resolved textobject specification\n--- (fall back to other mappings if can't find proper textobject id). For more\n--- information see |MiniAi-textobject-specification| and |MiniAi-algorithm|.\n---\n--- Known issues which won't be resolved:\n--- - Search for builtin textobjects is done mostly using Lua patterns\n---   (regex-like approach). Certain amount of false positives is to be expected.\n---\n--- - During search for builtin textobjects there is no distinction if it is\n---   inside string or comment. For example, in the following case there will\n---   be wrong match for a function call: `f(a = \")\", b = 1)`.\n---\n--- General rule of thumb: any instrument using available parser for document\n--- structure (like treesitter) will usually provide more precise results. This\n--- module has builtins mostly for plain text textobjects which are useful\n--- most of the times (like \"inside brackets\", \"around quotes/underscore\", etc.).\n--- For advanced use cases define function specification for custom textobjects.\n---\n--- What it doesn't (and probably won't) do:\n--- - Have special operators to specially handle whitespace (like `I` and `A`\n---   in 'targets.vim'). Whitespace handling is assumed to be done inside\n---   textobject specification (like `i(` and `i)` handle whitespace differently).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.ai').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniAi`\n--- which you can use for scripting or manually (with `:lua MiniAi.*`).\n---\n--- See |MiniAi.config| for available config settings.\n---\n--- You can override runtime config settings (like `config.custom_textobjects`)\n--- locally to buffer inside `vim.b.miniai_config` which should have same structure\n--- as `MiniAi.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Comparisons ~\n---\n--- - [wellle/targets.vim](https://github.com/wellle/targets.vim):\n---     - Has limited support for creating own textobjects: it is constrained\n---       to pre-defined detection rules. 'mini.ai' allows creating own rules\n---       via Lua patterns and functions (see |MiniAi-textobject-specification|).\n---     - Doesn't provide any programmatical API for getting information about\n---       textobjects. 'mini.ai' does it via |MiniAi.find_textobject()|.\n---     - Has no implementation of \"moving to edge of textobject\". 'mini.ai'\n---       does it via |MiniAi.move_cursor()| and `g[` and `g]` default mappings.\n---     - Both implement the notion of manual \"next\"/\"last\" search directions.\n---     - Implements `A`, `I` operators. 'mini.ai' does not by design: it is\n---       assumed to be a property of textobject, not operator.\n---     - Doesn't implement \"function call\" and \"user prompt\" textobjects.\n---       'mini.ai' does (with `f` and `?` identifiers).\n---     - Has limited support for \"argument\" textobject. Although it works in\n---       most situations, it often misdetects commas as argument separator\n---       (like if it is inside quotes or `{}`). 'mini.ai' deals with these cases.\n--- - [nvim-treesitter/nvim-treesitter-textobjects](https://github.com/nvim-treesitter/nvim-treesitter-textobjects):\n---     - Along with textobject functionality provides a curated and maintained\n---       set of popular textobject queries for many languages (which can power\n---       |MiniAi.gen_spec.treesitter()| functionality).\n---     - Both support working with |treesitter-directives| allowing more\n---       fine-tuned textobjects.\n---     - Implements only textobjects based on treesitter.\n---     - Doesn't support |v:count|.\n---     - Doesn't support multiple search method (basically, only 'cover').\n---     - Doesn't support consecutive application of target textobject.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.miniai_disable` (globally) or `vim.b.miniai_disable`\n--- (for a buffer) to `true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniAi\n\n--- This table describes all builtin textobjects along with what they\n--- represent. Explanation:\n--- - `Key` represents the textobject identifier: single character which should\n---   be typed after `a`/`i`.\n--- - `Name` is a description of textobject.\n--- - `Example line` contains a string for which examples are constructed. The\n---   `*` denotes the cursor position.\n--- - `a`/`i` describe inclusive region representing `a` and `i` textobjects.\n---   Use numbers in separators for easier navigation.\n--- - `2a`/`2i` describe either `2a`/`2i` (support for |v:count|) textobjects\n---   or `a`/`i` textobject followed by another `a`/`i` textobject (consecutive\n---   application leads to incremental selection).\n---\n--- Example: typing `va)` with cursor on `*` leads to selection from column 2\n--- to column 12. Another typing `a)` changes selection to [1; 13]. Also, besides\n--- visual selection, any |operator| can be used or `g[`/`g]` motions to move\n--- to left/right edge of `a` textobject.\n--- >\n---  ┌───┬───────────────┬──────────────────┬────────┬────────┬────────┬────────┐\n---  │Key│     Name      │   Example line   │   a    │   i    │   2a   │   2i   │\n---  ├───┴───────────────┴──────────────────┴────────┴────────┴────────┴────────┤\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ ( │  Balanced ()  │ (( *a (bb) ))    │        │        │        │        │\n---  │ [ │  Balanced []  │ [[ *a [bb] ]]    │ [2;12] │ [4;10] │ [1;13] │ [2;12] │\n---  │ { │  Balanced {}  │ {{ *a {bb} }}    │        │        │        │        │\n---  │ < │  Balanced <>  │ << *a <bb> >>    │        │        │        │        │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ ) │  Balanced ()  │ (( *a (bb) ))    │        │        │        │        │\n---  │ ] │  Balanced []  │ [[ *a [bb] ]]    │        │        │        │        │\n---  │ } │  Balanced {}  │ {{ *a {bb} }}    │ [2;12] │ [3;11] │ [1;13] │ [2;12] │\n---  │ > │  Balanced <>  │ << *a <bb> >>    │        │        │        │        │\n---  │ b │  Alias for    │ [( *a {bb} )]    │        │        │        │        │\n---  │   │  ), ], or }   │                  │        │        │        │        │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ \" │  Balanced \"   │ \"*a\" \" bb \"      │        │        │        │        │\n---  │ ' │  Balanced '   │ '*a' ' bb '      │        │        │        │        │\n---  │ ` │  Balanced `   │ `*a` ` bb `      │ [1;4]  │ [2;3]  │ [6;11] │ [7;10] │\n---  │ q │  Alias for    │ '*a' \" bb \"      │        │        │        │        │\n---  │   │  \", ', or `   │                  │        │        │        │        │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ ? │  User prompt  │ e*e o e o o      │ [3;5]  │ [4;4]  │ [7;9]  │ [8;8]  │\n---  │   │(typed e and o)│                  │        │        │        │        │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ t │      Tag      │ <x><y>*a</y></x> │ [4;12] │ [7;8]  │ [1;16] │ [4;12] │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ f │ Function call │ f(a, g(*b, c) )  │ [6;13] │ [8;12] │ [1;15] │ [3;14] │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ a │   Argument    │ f(*a, g(b, c) )  │ [3;5]  │ [3;4]  │ [5;14] │ [7;13] │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈1234567890123456┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │   │    Default    │ aa_*b__cc___     │ [4;7]  │ [4;5]  │ [8;12] │ [8;9]  │\n---  │   │   (typed _)   │                  │        │        │        │        │\n---  └───┴───────────────┴──────────────────┴────────┴────────┴────────┴────────┘\n--- <\n--- Notes:\n--- - All examples assume default `config.search_method`.\n--- - Open brackets differ from close brackets by how they treat inner edge\n---   whitespace for `i` textobject: open ignores it, close - includes.\n--- - Default textobject is activated for identifiers which are not Latin letters.\n---   They are designed to be treated as separators, so include only right edge\n---   in `a` textobject. To include both edges, use custom textobjects\n---   (see |MiniAi-textobject-specification| and |MiniAi.config|). Note:\n---     - When cursor is exactly on the identifier character while there are\n---       two matching candidates on both left and right, the resulting region\n---       with smaller width is preferred.\n---@tag MiniAi-builtin-textobjects\n\n--- Note: this is similar to |MiniSurround-glossary|.\n---\n--- REGION ~\n--- Table representing region in a buffer. Fields:\n--- - <from> and <to> for inclusive start and end positions (<to> might be\n---   `nil` to describe empty region). Each position is also a table with\n---   line <line> and column <col> (both start at 1).\n--- - <vis_mode> for which Visual mode will be used to select textobject.\n---   See `opts` argument of |MiniAi.select_textobject()|.\n---   One of `'v'`, `'V'`, `'\\22'` (escaped `'<C-v>'`).\n---\n--- Examples: >lua\n---\n---   { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }\n---\n---   -- Forced linewise mode\n---   {\n---     from = { line = 1, col = 1 }, to = { line = 2, col = 1 },\n---     vis_mode = 'V',\n---   }\n---\n---   -- Empty region\n---   { from = { line = 10, col = 10 } }\n--- <\n--- PATTERN ~\n--- String describing Lua pattern.\n---\n--- SPAN ~\n--- Interval inside a string (end-exclusive). Like [1, 5). Equal `from` and `to` edges\n--- describe empty span at that point.\n---\n--- Span `A = [a1, a2)` covers `B = [b1, b2)` if every element of `B` is within\n--- `A` (`a1 <= b < a2`). It also is described as \"B is nested inside A\".\n---\n--- NESTED PATTERN ~\n--- Array of patterns aimed to describe nested spans.\n---\n--- SPAN MATCHES NESTED PATTERN ~\n--- If there is a sequence of consecutively nested spans each matching\n--- corresponding pattern within substring of previous span (or input string\n--- for first span). Example: >lua\n---\n---   -- Nested patterns for balanced `()` with inner space\n---   { '%b()', '^. .* .$' }\n---\n---   -- Example input string (with columns underneath for easier reading):\n---      \"( ( () ( ) ) )\"\n---   --  12345678901234\n--- <\n--- Here are all matching spans [1, 15) and [3, 13). Both [5, 7) and [8, 10)\n--- match first pattern but not second. All other combinations of `(` and `)`\n--- don't match first pattern (not balanced).\n---\n--- COMPOSED PATTERN ~\n--- Array with each element describing possible pattern (or array of them) at\n--- that place. Composed pattern basically defines all possible combinations of\n--- nested pattern (their cartesian product). Examples:\n---\n--- 1. Either balanced `()` or balanced `[]` but both with inner edge space: >lua\n---\n---     -- Composed pattern\n---     { { '%b()', '%b[]' }, '^. .* .$' }\n---\n---     -- Composed pattern expanded into equivalent array of nested patterns\n---     { '%b()', '^. .* .$' } -- and\n---     { '%b[]', '^. .* .$' }\n--- <\n--- 2. Either \"balanced `()` with inner edge space\" or \"balanced `[]` with no\n---    inner edge space\", both with 5 or more characters: >lua\n---\n---     -- Composed pattern\n---     { { { '%b()', '^. .* .$' }, { '%b[]', '^.[^ ].*[^ ].$' } }, '.....' }\n---\n---     -- Composed pattern expanded into equivalent array of nested patterns\n---     { '%b()', '^. .* .$', '.....' } -- and\n---     { '%b[]', '^.[^ ].*[^ ].$', '.....' }\n--- <\n--- SPAN MATCHES COMPOSED PATTERN ~\n--- If it matches at least one nested pattern from expanded composed pattern.\n---@tag MiniAi-glossary\n\n--- Textobject specification has a structure of composed pattern (see\n--- |MiniAi-glossary|) with two differences:\n--- - Last pattern(s) should have even number of empty capture groups denoting\n---   how the last string should be processed to extract `a` or `i` textobject:\n---     - Zero captures mean that whole string represents both `a` and `i`.\n---       Example: `xxx` will define textobject matching string `xxx` literally.\n---     - Two captures represent `i` textobject inside of them. `a` - whole string.\n---       Example: `x()x()x` defines `a` textobject to be `xxx`, `i` - middle `x`.\n---     - Four captures define `a` textobject inside captures 1 and 4, `i` -\n---       inside captures 2 and 3. Example: `x()()x()x()` defines `a`\n---       textobject to be last `xx`, `i` - middle `x`.\n--- - Allows callable objects (see |vim.is_callable()|) in certain places\n---   (enables more complex textobjects in exchange of increase in configuration\n---   complexity and computations):\n---     - If specification itself is a callable, it will be called with the same\n---       arguments as |MiniAi.find_textobject()| and should return one of:\n---         - Composed pattern. Useful for implementing user input. Example of\n---           simplified variant of textobject for function call with name taken\n---           from user prompt: >lua\n---\n---             function()\n---               local left_edge = vim.pesc(vim.fn.input('Function name: '))\n---               return { left_edge .. '%b()', '^.-%(().*()%)$' }\n---             end\n--- <\n---         - Single output region. Useful to allow full control over\n---           textobject. Will be taken as is. Example of returning whole buffer: >lua\n---\n---             function()\n---               local from = { line = 1, col = 1 }\n---               local to = {\n---                 line = vim.fn.line('$'),\n---                 col = math.max(vim.fn.getline('$'):len(), 1)\n---               }\n---               return { from = from, to = to, vis_mode = 'V' }\n---             end\n--- <\n---         - Array of output region(s). Useful for incorporating other\n---           instruments, like treesitter (see |MiniAi.gen_spec.treesitter()|).\n---           The best region will be picked in the same manner as with composed\n---           pattern (respecting options `n_lines`, `search_method`, etc.).\n---           Example of selecting \"best\" line with display width more than 80: >lua\n---\n---             function(_, _, _)\n---               local res = {}\n---               for i = 1, vim.api.nvim_buf_line_count(0) do\n---                 local cur_line = vim.fn.getline(i)\n---                 if vim.fn.strdisplaywidth(cur_line) > 80 then\n---                   local region = {\n---                     from = { line = i, col = 1 },\n---                     to = { line = i, col = cur_line:len() },\n---                   }\n---                   table.insert(res, region)\n---                 end\n---               end\n---               return res\n---             end\n--- <\n---     - If there is a callable instead of assumed string pattern, it is expected\n---       to have signature `(line, init)` and behave like `pattern:find()`.\n---       It should return two numbers representing span in `line` next after\n---       or at `init` (`nil` if there is no such span).\n---       !IMPORTANT NOTE!: it means that output's `from` shouldn't be strictly\n---       to the left of `init` (it will lead to infinite loop). Not allowed as\n---       last item (as it should be pattern with captures).\n---       Example of matching only balanced parenthesis with big enough width: >lua\n---\n---         {\n---           '%b()',\n---           function(s, init)\n---             if init > 1 or s:len() < 5 then return end\n---             return 1, s:len()\n---           end,\n---           '^.().*().$'\n---         }\n--- <\n--- More examples: >lua\n---\n---   -- Pair of balanced brackets from set (used for builtin `b` identifier):\n---   { { '%b()', '%b[]', '%b{}' }, '^.().*().$' }\n---\n---   -- Imitate word ignoring digits and punctuation (only for Latin alphabet):\n---   { '()()%f[%w]%w+()[ \\t]*()' }\n---\n---   -- Word with camel case support (also supports only Latin alphabet):\n---   {\n---     {\n---       '%u[%l%d]+%f[^%l%d]',\n---       '%f[%S][%l%d]+%f[^%l%d]',\n---       '%f[%P][%l%d]+%f[^%l%d]',\n---       '^[%l%d]+%f[^%l%d]',\n---     },\n---     '^().*()$'\n---   }\n---\n---   -- Number:\n---   { '%f[%d]%d+' }\n---\n---   -- Date in 'YYYY-MM-DD' format:\n---   { '()%d%d%d%d%-%d%d%-%d%d()' }\n---\n---   -- Lua block string:\n---   { '%[%[().-()%]%]' }\n--- <\n--- See |MiniAi.gen_spec| for function wrappers to create commonly used\n--- textobject specifications.\n---@tag MiniAi-textobject-specification\n\n--- Search for the textobjects relies on these principles:\n--- - It uses same input data as described in |MiniAi.find_textobject()|,\n---   i.e. whether it is `a` or `i` textobject, its identifier, reference region, etc.\n--- - Textobject specification is constructed based on textobject identifier\n---   (see |MiniAi-textobject-specification|).\n--- - General search is done by converting some 2d buffer region (neighborhood\n---   of reference region) into 1d string (each line is appended with `\\n`).\n---   Then search for a best span matching textobject specification is done\n---   inside string (see |MiniAi-glossary|). After that, span is converted back\n---   into 2d region. Note: first search is done inside reference region lines,\n---   and only after that - inside its neighborhood within `config.n_lines`\n---   (see |MiniAi.config|).\n--- - The best matching span is chosen by iterating over all spans matching\n---   textobject specification and comparing them with \"current best\".\n---   Comparison also depends on reference region (tighter covering is better,\n---   otherwise closer is better) and search method (if span is even considered).\n--- - Extract span based on extraction pattern (last item in nested pattern).\n--- - If task is to perform a consecutive search (`opts.n_times` is greater than 1),\n---   steps are repeated with current best match becoming reference region.\n---   One such additional step is also done if final region is equal to\n---   reference region (this enables consecutive application).\n---\n--- Notes:\n--- - Iteration over all matched spans is done in depth-first fashion with\n---   respect to nested pattern.\n--- - It is guaranteed that span is compared only once.\n--- - For the sake of increasing functionality, during iteration over all\n---   matching spans, some Lua patterns in composed pattern are handled\n---   specially.\n---     - `%bxx` (`xx` is two identical characters). It denotes balanced pair\n---       of identical characters and results into \"paired\" matches. For\n---       example, `%b\"\"` for `\"aa\" \"bb\"` would match `\"aa\"` and `\"bb\"`, but\n---       not middle `\" \"`.\n---     - `x.-y` (`x` and `y` are different strings). It results only in matches with\n---       smallest width. For example, `e.-o` for `e e o o` will result only in\n---       middle `e o`. Note: it has some implications for when parts have\n---       quantifiers (like `+`, etc.), which usually can be resolved with\n---       frontier pattern `%f[]` (see examples in |MiniAi-textobject-specification|).\n---@tag MiniAi-algorithm\n\n-- Module definition ==========================================================\nlocal MiniAi = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniAi.config|.\n---\n---@usage >lua\n---   require('mini.ai').setup() -- use default config\n---   -- OR\n---   require('mini.ai').setup({}) -- replace {} with your config table\n--- <\nMiniAi.setup = function(config)\n  -- Export module\n  _G.MiniAi = MiniAi\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Custom textobjects ~\n---\n--- User can define own textobjects by supplying `config.custom_textobjects`.\n--- It should be a table with keys being single character textobject identifier\n--- (supported by |getcharstr()|) and values - textobject specification\n--- (see |MiniAi-textobject-specification|).\n---\n--- General recommendations:\n--- - This can be used to override builtin ones (|MiniAi-builtin-textobjects|).\n---   Supply non-valid input (not in specification format) to disable module's\n---   builtin textobject in favor of external or Neovim's builtin mapping.\n--- - Keys should use character representation which can be |getcharstr()| output.\n---   For example, `'\\r'` and not `'<CR>'`.\n---\n--- Examples:\n--- >lua\n---   require('mini.ai').setup({\n---     custom_textobjects = {\n---       -- Tweak argument textobject\n---       a = require('mini.ai').gen_spec.argument({ brackets = { '%b()' } }),\n---\n---       -- Disable brackets alias in favor of builtin block textobject\n---       b = false,\n---\n---       -- Now `vax` should select `xxx` and `vix` - middle `x`\n---       x = { 'x()x()x' },\n---\n---       -- Whole buffer\n---       g = function()\n---         local from = { line = 1, col = 1 }\n---         local to = {\n---           line = vim.fn.line('$'),\n---           col = math.max(vim.fn.getline('$'):len(), 1)\n---         }\n---         return { from = from, to = to }\n---       end\n---     }\n---   })\n---\n---   -- Use `vim.b.miniai_config` to customize per buffer\n---   -- Example of specification useful for Markdown files:\n---   local spec_pair = require('mini.ai').gen_spec.pair\n---   vim.b.miniai_config = {\n---     custom_textobjects = {\n---       ['*'] = spec_pair('*', '*', { type = 'greedy' }),\n---       ['_'] = spec_pair('_', '_', { type = 'greedy' }),\n---     },\n---   }\n--- <\n--- There are more example specifications in |MiniAi-textobject-specification|.\n---\n--- # Search method ~\n---\n--- Value of `config.search_method` defines how best match search is done.\n--- Based on its value, one of the following matches will be selected:\n--- - Covering match. Left/right edge is before/after left/right edge of\n---   reference region.\n--- - Previous match. Left/right edge is before left/right edge of reference\n---   region.\n--- - Next match. Left/right edge is after left/right edge of reference region.\n--- - Nearest match. Whichever is closest among previous and next matches.\n---\n--- Possible values are:\n--- - `'cover'` - use only covering match. Don't use either previous or\n---   next; report that there is no textobject found.\n--- - `'cover_or_next'` (default) - use covering match. If not found, use next.\n--- - `'cover_or_prev'` - use covering match. If not found, use previous.\n--- - `'cover_or_nearest'` - use covering match. If not found, use nearest.\n--- - `'next'` - use next match.\n--- - `'prev'` - use previous match.\n--- - `'nearest'` - use nearest match.\n---\n--- Note: search is first performed on the reference region lines and only\n--- after failure - on the whole neighborhood defined by `config.n_lines`. This\n--- means that with `config.search_method` not equal to `'cover'`, \"prev\" or\n--- \"next\" textobject will end up as search result if they are found on first\n--- stage although covering match might be found in bigger, whole neighborhood.\n--- This design is based on observation that most of the time operation is done\n--- within reference region lines (usually cursor line).\n---\n--- Here is an example of what `a)` textobject is based on a value of\n--- `'config.search_method'` when cursor is inside `bbb` word:\n--- - `'cover'`:         `(a) bbb (c)` -> none\n--- - `'cover_or_next'`: `(a) bbb (c)` -> `(c)`\n--- - `'cover_or_prev'`: `(a) bbb (c)` -> `(a)`\n--- - `'cover_or_nearest'`: depends on cursor position.\n---   For first and second `b` - as in `cover_or_prev` (as previous match is\n---   nearer), for third - as in `cover_or_next` (as next match is nearer).\n--- - `'next'`: `(a) bbb (c)` -> `(c)`. Same outcome for `(bbb)`.\n--- - `'prev'`: `(a) bbb (c)` -> `(a)`. Same outcome for `(bbb)`.\n--- - `'nearest'`: depends on cursor position (same as in `'cover_or_nearest'`).\n---\n--- # Mappings ~\n---\n--- Mappings `around_next` / `inside_next` and `around_last` / `inside_last` are\n--- essentially `around` / `inside` but using search method `'next'` and `'prev'`.\n---\n--- NOTE: with default config, built-in LSP mappings |v_an| and |v_in| on Neovim>=0.12\n--- are overridden. Either use different `around_next` / `inside_next` keys or\n--- map manually using |vim.lsp.buf.selection_range()|. For example: >lua\n---\n---   local map_lsp_selection = function(lhs, desc)\n---     local s = vim.startswith(desc, 'Increase') and 1 or -1\n---     local rhs = function() vim.lsp.buf.selection_range(s * vim.v.count1) end\n---     vim.keymap.set('x', lhs, rhs, { desc = desc })\n---   end\n---   map_lsp_selection('<Leader>ls', 'Increase selection')\n---   map_lsp_selection('<Leader>lS', 'Decrease selection')\n--- <\nMiniAi.config = {\n  -- Table with textobject id as fields, textobject specification as values.\n  -- Also use this to disable builtin textobjects. See |MiniAi.config|.\n  custom_textobjects = nil,\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Main textobject prefixes\n    around = 'a',\n    inside = 'i',\n\n    -- Next/last textobjects\n    -- NOTE: These override built-in LSP selection mappings on Neovim>=0.12\n    -- Map LSP selection manually to use it (see `:h MiniAi.config`)\n    around_next = 'an',\n    inside_next = 'in',\n    around_last = 'al',\n    inside_last = 'il',\n\n    -- Move cursor to corresponding edge of `a` textobject\n    goto_left = 'g[',\n    goto_right = 'g]',\n  },\n\n  -- Number of lines within which textobject is searched\n  n_lines = 50,\n\n  -- How to search for object (first inside current line, then inside\n  -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev',\n  -- 'cover_or_nearest', 'next', 'prev', 'nearest'.\n  search_method = 'cover_or_next',\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Find textobject region\n---\n---@param ai_type string One of `'a'` or `'i'`.\n---@param id string Single character string representing textobject id. It is\n---   used to get specification which is later used to compute textobject region.\n---   Note: if specification is a function, it is called with all present\n---   arguments (`opts` is populated with default arguments).\n---@param opts table|nil Options. Possible fields:\n---   - <n_lines> - Number of lines within which textobject is searched.\n---     Default: `config.n_lines` (see |MiniAi.config|).\n---   - <n_times> - Number of times to perform a consecutive search. Each one\n---     is done with reference region being previous found textobject region.\n---     Default: 1.\n---   - <reference_region> - region to try to cover (see |MiniAi-glossary|). It\n---     is guaranteed that output region will not be inside or equal to this one.\n---     Default: empty region at cursor position.\n---   - <search_method> - Search method. Default: `config.search_method`.\n---\n---@return table|nil Region of textobject or `nil` if no textobject different\n---   from `opts.reference_region` was consecutively found `opts.n_times` times.\nMiniAi.find_textobject = function(ai_type, id, opts)\n  if not (ai_type == 'a' or ai_type == 'i') then H.error([[`ai_type` should be one of 'a' or 'i'.]]) end\n  opts = vim.tbl_deep_extend('force', H.get_default_opts(), opts or {})\n  H.validate_search_method(opts.search_method)\n\n  -- Get textobject specification\n  local tobj_spec = H.get_textobject_spec(id, { ai_type, id, opts })\n  if tobj_spec == nil then return end\n  if H.is_region(tobj_spec) then return tobj_spec end\n\n  -- Find region\n  local res = H.find_textobject_region(tobj_spec, ai_type, opts)\n\n  if res == nil then\n    local msg = string.format(\n      [[No textobject %s found covering region%s within %d line%s and `search_method = '%s'`.]],\n      vim.inspect(ai_type .. id),\n      opts.n_times == 1 and '' or (' %s times'):format(opts.n_times),\n      opts.n_lines,\n      opts.n_lines == 1 and '' or 's',\n      opts.search_method\n    )\n    H.message(msg)\n  end\n\n  return res\nend\n\n--- Move cursor to edge of textobject\n---\n---@param side string One of `'left'` or `'right'`.\n---@param ai_type string One of `'a'` or `'i'`.\n---@param id string Single character string representing textobject id.\n---@param opts table|nil Same as in |MiniAi.find_textobject()|.\n---   `opts.n_times` means number of actual jumps (important when cursor\n---   already on the potential jump spot).\nMiniAi.move_cursor = function(side, ai_type, id, opts)\n  if not (side == 'left' or side == 'right') then H.error([[`side` should be one of 'left' or 'right'.]]) end\n  opts = opts or {}\n  local init_pos = vim.api.nvim_win_get_cursor(0)\n\n  -- Compute single textobject first to find out if it would move the cursor.\n  -- If not, then eventual `n_times` should be bigger by 1 to imitate `n_times`\n  -- *actual* jumps. This implements consecutive jumps and has logic of \"If\n  -- cursor is strictly inside region, move to its side first\".\n  local new_opts = vim.tbl_deep_extend('force', opts, { n_times = 1 })\n  local tobj_single = MiniAi.find_textobject(ai_type, id, new_opts)\n  if tobj_single == nil then return end\n  local tobj_side = side == 'left' and 'from' or 'to'\n\n  -- Allow empty region\n  tobj_single.to = tobj_single.to or tobj_single.from\n\n  new_opts.n_times = opts.n_times or 1\n  if (init_pos[1] == tobj_single[tobj_side].line) and (init_pos[2] == tobj_single[tobj_side].col - 1) then\n    new_opts.n_times = new_opts.n_times + 1\n  end\n\n  -- Compute actually needed textobject while avoiding unnecessary computation\n  -- in a most common usage (`v:count1 == 1`)\n  local pos = tobj_single[tobj_side]\n  if new_opts.n_times > 1 then\n    local tobj = MiniAi.find_textobject(ai_type, id, new_opts)\n    if tobj == nil then return end\n    tobj.to = tobj.to or tobj.from\n    pos = tobj[tobj_side]\n  end\n\n  -- Move cursor and open enough folds\n  vim.cmd(\"normal! m'\")\n  vim.api.nvim_win_set_cursor(0, { pos.line, pos.col - 1 })\n  vim.cmd('normal! zv')\nend\n\n--- Generate common textobject specifications\n---\n--- This is a table with function elements. Call to actually get specification.\n---\n--- Example: >lua\n---\n---   local gen_spec = require('mini.ai').gen_spec\n---   require('mini.ai').setup({\n---     custom_textobjects = {\n---       -- Tweak argument to be recognized only inside `()` between `;`\n---       a = gen_spec.argument({ brackets = { '%b()' }, separator = ';' }),\n---\n---       -- Tweak function call to not detect dot in function name\n---       f = gen_spec.function_call({ name_pattern = '[%w_]' }),\n---\n---       -- Function definition (needs treesitter queries with these captures)\n---       F = gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' }),\n---\n---       -- Make `|` select both edges in non-balanced way\n---       ['|'] = gen_spec.pair('|', '|', { type = 'non-balanced' }),\n---     }\n---   })\n--- <\nMiniAi.gen_spec = {}\n\n--- Argument specification\n---\n--- Argument textobject (has default `a` identifier) is a region inside\n--- balanced bracket between allowed not excluded separators. Use this function\n--- to tweak how it works.\n---\n--- Examples:\n--- - `argument({ brackets = { '%b()' } })` will search for an argument only\n---   inside balanced `()`.\n--- - `argument({ separator = '[,;]' })` will treat both `,` and `;` as separators.\n--- - `argument({ exclude_regions = { '%b()' } })` will exclude separators\n---   which are inside balanced `()` (inside outer brackets).\n---\n---@param opts table|nil Options. Allowed fields:\n---   - <brackets> - array of patterns for outer balanced brackets.\n---     Default: `{ '%b()', '%b[]', '%b{}' }` (any `()`, `[]`, or `{}` can\n---     enclose arguments).\n---   - <separator> - separator pattern. Default: `','`.\n---     One of the practical usages of this option is to include whitespace\n---     around character to be a part of separator. For example, `'%s*,%s*'`\n---     will treat as separator not only ',', but its possible surrounding\n---     whitespace. This has both positive and negative effects. On one hand,\n---     `daa` executed over the first argument will delete whitespace after\n---     first comma, leading to a more expected outcome. On the other hand it\n---     is ambiguous which argument is picked when cursor is over whitespace\n---     near the character separator.\n---   - <exclude_regions> - array with patterns for regions inside which\n---     separators will be ignored.\n---     Default: `{ '%b\"\"', \"%b''\", '%b()', '%b[]', '%b{}' }` (separators\n---     inside balanced quotes or brackets are ignored).\nMiniAi.gen_spec.argument = function(opts)\n  opts = vim.tbl_extend('force', {\n    brackets = { '%b()', '%b[]', '%b{}' },\n    separator = ',',\n    exclude_regions = { '%b\"\"', \"%b''\", '%b()', '%b[]', '%b{}' },\n  }, opts or {})\n\n  local brackets, separator, exclude_regions = opts.brackets, opts.separator, opts.exclude_regions\n\n  local res = {}\n  -- Match brackets\n  res[1] = brackets\n\n  -- Match argument with both left and right separators/brackets\n  res[2] = function(s, init)\n    -- Cache string separators per spec as they are used multiple times.\n    -- Storing per spec allows coexistence of several argument specifications.\n    H.cache.argument_sep_spans = H.cache.argument_sep_spans or {}\n    H.cache.argument_sep_spans[res] = H.cache.argument_sep_spans[res] or {}\n    local sep_spans = H.cache.argument_sep_spans[res][s] or H.arg_get_separator_spans(s, separator, exclude_regions)\n    H.cache.argument_sep_spans[res][s] = sep_spans\n\n    -- Return span fully on right of `init`, `nil` otherwise\n    -- For first argument returns left bracket; for last - right one.\n    for i = 1, #sep_spans - 1 do\n      if init <= sep_spans[i][1] then return sep_spans[i][1], sep_spans[i + 1][2] end\n    end\n\n    return nil\n  end\n\n  -- Make extraction part\n  --\n  -- Extraction of `a` type depends on argument number, `i` - as `a` but\n  -- without separators and inner whitespace. The reason for this complex\n  -- solution are the following requirements:\n  -- - Don't match argument region when cursor is on the outer bracket.\n  --   Example: `f(xxx)` should select argument only when cursor is on 'x'.\n  -- - Don't select edge whitespace for first and last argument BUT MATCH WHEN\n  --   CURSOR IS ON THEM which needs to match edge whitespace right until the\n  --   extraction part. This is useful when working with padded brackets.\n  --   Example for `f(  xx  ,  yy  )`:\n  --     - `a` object should select 'xx  ,' when cursor is on all '  xx  ';\n  --       should select ',  yy' when cursor is on all '  yy  '.\n  --     - `i` object should select 'xx' when cursor is on all '  xx  ';\n  --       should select 'yy' when cursor is on all '  yy  '.\n  --\n  -- At this stage whether argument is first, middle, last, or single is\n  -- determined by presence of matching separator at either left or right edge.\n  -- If edge matches separator pattern - it has separator. If not - a bracket.\n  local left_edge_separator = '^' .. separator\n  local find_after_left_separator = function(s)\n    local _, sep_end = s:find(left_edge_separator)\n    if sep_end == nil then return nil end\n    return sep_end + 1\n  end\n  local find_after_left_bracket = function(s)\n    local left_sep = find_after_left_separator(s)\n    if left_sep ~= nil then return nil end\n    return 2\n  end\n\n  local right_edge_sep = separator .. '$'\n  local find_before_right_separator = function(s)\n    local sep_start, _ = s:find(right_edge_sep)\n    if sep_start == nil then return nil end\n    return sep_start - 1\n  end\n  local find_before_right_bracket = function(s)\n    local right_sep = find_before_right_separator(s)\n    if right_sep ~= nil then return nil end\n    return s:len() - 1\n  end\n\n  local match_and_include = function(left_type, left_include, right_type, right_include)\n    local find_after_left = left_type == 'bracket' and find_after_left_bracket or find_after_left_separator\n    local find_before_right = right_type == 'bracket' and find_before_right_bracket or find_before_right_separator\n\n    return function(s, init)\n      -- Match only once\n      if init > 1 then return nil end\n\n      -- Make sure that string matches left and right targets\n      local left_after, right_before = find_after_left(s), find_before_right(s)\n      if left_after == nil or right_before == nil then return nil end\n\n      -- Possibly include matched edge targets\n      local left = left_include and 1 or left_after\n      local right = right_include and s:len() or right_before\n\n      return left, right\n    end\n  end\n\n  local extract_first_arg = '^%s*()().-()%s*' .. separator .. '()$'\n  local extract_nonfirst_arg = '^()' .. separator .. '%s*().-()()%s*$'\n  local extract_single_arg = '^%s*().-()%s*$'\n\n  res[3] = {\n    -- First argument. Include right separator, exclude left whitespace.\n    { match_and_include('bracket', false, 'separator', true), extract_first_arg },\n\n    -- Middle argument. Include only left separator.\n    { match_and_include('separator', true, 'separator', false), extract_nonfirst_arg },\n\n    -- Last argument. Include left separator, exclude right whitespace.\n    -- NOTE: it misbehaves for whitespace argument. It's OK because it's rare.\n    { match_and_include('separator', true, 'bracket', false), extract_nonfirst_arg },\n\n    -- Single argument. Include both whitespace (makes `aa` and `ia` differ).\n    { match_and_include('bracket', false, 'bracket', false), extract_single_arg },\n  }\n\n  return res\nend\n\n--- Function call specification\n---\n--- Function call textobject (has default `f` identifier) is a region with some\n--- characters followed by balanced `()`. Use this function to tweak how it works.\n---\n--- Example:\n--- - `function_call({ name_pattern = '[%w_]' })` will recognize function name with\n---   only alphanumeric or underscore (not dot).\n---\n---@param opts table|nil Options. Allowed fields:\n---   - <name_pattern> - string pattern of character set allowed in function name.\n---     Default: `'[%w_%.]'` (alphanumeric, underscore, or dot).\n---     Note: should be enclosed in `[]`.\nMiniAi.gen_spec.function_call = function(opts)\n  opts = vim.tbl_deep_extend('force', { name_pattern = '[%w_%.]' }, opts or {})\n  -- Use frontier pattern to select widest possible name\n  return { '%f' .. opts.name_pattern .. opts.name_pattern .. '+%b()', '^.-%(().*()%)$' }\nend\n\n--- Pair specification\n---\n--- Use it to define textobject for region surrounded with `left` from left and\n--- `right` from right. The `a` textobject includes both edges, `i` - excludes them.\n---\n--- Region can be one of several types (controlled with `opts.type`). All\n--- examples are for default search method, `a` textobject, and use `'_'` as\n--- both `left` and `right`:\n--- - Non-balanced (`{ type = 'non-balanced' }`), default. Equivalent to using\n---   `x.-y` as first pattern. Example: on line '_a_b_c_' it consecutively\n---   matches '_a_', '_b_', '_c_'.\n--- - Balanced (`{ type = 'balanced' }`). Equivalent to using `%bxy` as first\n---   pattern. Example: on line '_a_b_c_' it consecutively matches '_a_', '_c_'.\n---   Note: both `left` and `right` should be single character.\n--- - Greedy (`{ type = 'greedy' }`). Like non-balanced but will select maximum\n---   consecutive `left` and `right` edges. Example: on line '__a__b_' it\n---   consecutively selects '__a__' and '__b_'. Note: both `left` and `right`\n---   should be single character.\n---\n---@param left string Left edge.\n---@param right string Right edge.\n---@param opts table|nil Options. Possible fields:\n---   - <type> - Type of a pair. One of `'non-balanced'` (default), `'balanced'`,\n---   `'greedy'`.\nMiniAi.gen_spec.pair = function(left, right, opts)\n  if not (type(left) == 'string' and type(right) == 'string') then\n    H.error('Both `left` and `right` should be strings.')\n  end\n  opts = vim.tbl_deep_extend('force', { type = 'non-balanced' }, opts or {})\n\n  if (opts.type == 'balanced' or opts.type == 'greedy') and not (left:len() == 1 and right:len() == 1) then\n    local msg =\n      string.format([[Both `left` and `right` should be single character for `opts.type == '%s'`.]], opts.type)\n    H.error(msg)\n  end\n\n  local left_esc = vim.pesc(left)\n  local right_esc = vim.pesc(right)\n\n  if opts.type == 'balanced' then return { string.format('%%b%s%s', left, right), '^.().*().$' } end\n  if opts.type == 'non-balanced' then return { string.format('%s().-()%s', left_esc, right_esc) } end\n  if opts.type == 'greedy' then\n    return { string.format('%%f[%s]%s+()[^%s]-()%s+%%f[^%s]', left_esc, left_esc, left_esc, right_esc, right_esc) }\n  end\n\n  H.error([[`opts.type` should be one of 'balanced', 'non-balanced', 'greedy'.]])\nend\n\n--- Treesitter specification\n---\n--- This is a specification in function form. When called with a pair of\n--- treesitter captures, it returns a specification function outputting an\n--- array of regions that match corresponding (`a` or `i`) capture.\n---\n--- In order for this to work, apart from working treesitter parser for desired\n--- language, user should have a reachable language-specific 'textobjects'\n--- query (see |vim.treesitter.query.get()|).\n--- The most straightforward way for this is to have 'textobjects.scm' query\n--- file with treesitter captures stored in some recognized path. This is\n--- primarily designed to be compatible with plugin\n--- 'nvim-treesitter/nvim-treesitter-textobjects', but can be used without it.\n---\n--- Two most common approaches for having a query file:\n--- - Install 'nvim-treesitter/nvim-treesitter-textobjects'. It has curated and\n---   well maintained builtin query files for many languages with a standardized\n---   capture names, like `function.outer`, `function.inner`, etc.\n--- - Manually create file 'after/queries/<language name>/textobjects.scm' in\n---   your |$XDG_CONFIG_HOME| directory. It should contain queries with\n---   captures (later used to define textobjects). See |lua-treesitter-query|.\n--- To verify that query file is reachable, run (example for \"lua\" language,\n--- output should have at least an intended file): >vim\n---\n---   :lua print(vim.inspect(vim.treesitter.query.get_files('lua','textobjects')))\n--- <\n--- Example configuration for function definition textobject with\n--- 'nvim-treesitter/nvim-treesitter-textobjects' captures:\n--- >lua\n---   local spec_treesitter = require('mini.ai').gen_spec.treesitter\n---   require('mini.ai').setup({\n---     custom_textobjects = {\n---       F = spec_treesitter({ a = '@function.outer', i = '@function.inner' }),\n---       o = spec_treesitter({\n---         a = { '@conditional.outer', '@loop.outer' },\n---         i = { '@conditional.inner', '@loop.inner' },\n---       })\n---     }\n---   })\n--- <\n--- Notes:\n--- - Be sure that query files don't contain unknown |treesitter-directives|\n---   (like `#make-range!`, for example). Otherwise textobject for such capture\n---   might not be found as |lua-treesitter-core| won't treat them as captures.\n---   Verify with `:=vim.treesitter.query.get('lang', 'textobjects')` and see\n---   if the target capture is recognized as one.\n--- - It uses buffer's |filetype| to determine query language.\n--- - On large files it is slower than pattern-based textobjects. Still very\n---   fast though (one search should be magnitude of milliseconds or tens of\n---   milliseconds on really large file).\n---\n---@param ai_captures table Captures for `a` and `i` textobjects: table with\n---   <a> and <i> fields with captures for `a` and `i` textobjects respectively.\n---   Each value can be either a string capture (should start with `'@'`) or an\n---   array of such captures (best among all matches will be chosen).\n---@param opts table|nil Options. Possible values:\n---   - <use_nvim_treesitter> - whether to try to use 'nvim-treesitter' plugin\n---     (if present) to do the query. It used to implement more advanced behavior\n---     and more coherent experience if 'nvim-treesitter-textobjects' queries are\n---     used. However, as |lua-treesitter-core| methods are more capable now,\n---     the option will soon be removed. Only present for backward compatibility.\n---     Default: `false`.\n---\n---@return function Function with |MiniAi.find_textobject()| signature which\n---   returns array of current buffer regions representing matches for\n---   corresponding (`a` or `i`) treesitter capture.\n---\n---@seealso - |MiniAi-textobject-specification| for how this type of textobject\n---   specification is processed.\n--- - |vim.treesitter.query.get()| for how query is fetched.\n--- - |Query:iter_captures()| for how all query captures are iterated in case of\n---   no 'nvim-treesitter'.\nMiniAi.gen_spec.treesitter = function(ai_captures, opts)\n  -- TODO: Remove after releasing 'mini.nvim' 0.17.0\n  opts = vim.tbl_deep_extend('force', { use_nvim_treesitter = false }, opts or {})\n  ai_captures = H.prepare_ai_captures(ai_captures)\n\n  -- Tree-sitter ranges are 0-based, end-exclusive, and usually\n  -- `row1-col1-byte1-row2-col2-byte2` (i.e. \"range six\") format.\n  local ts_range_to_region = function(r)\n    -- The `master` branch of 'nvim-treesitter' can return \"range four\" format\n    -- if it uses custom directives, like `#make-range!`. Due to the fact that\n    -- it doesn't fully mock the `TSNode:range()` method to return \"range six\".\n    -- TODO: Remove after 'nvim-treesitter' `master` branch support is dropped.\n    local offset = #r == 4 and -1 or 0\n    local res = { from = { line = r[1] + 1, col = r[2] + 1 }, to = { line = r[4 + offset] + 1, col = r[5 + offset] } }\n\n    -- NOTE: Adjust \"row-exclusive, col-0\" range that means \"all previous row\n    -- including the newline character\"\n    if res.to.col == 0 then\n      res.to.line = res.to.line - 1\n      res.to.col = vim.fn.col({ res.to.line, '$' })\n    end\n\n    return res\n  end\n\n  return function(ai_type, _, _)\n    -- Get array of matched treesitter nodes\n    local target_captures = ai_captures[ai_type]\n    local has_nvim_treesitter = pcall(require, 'nvim-treesitter') and pcall(require, 'nvim-treesitter.query')\n    local range_querier = (has_nvim_treesitter and opts.use_nvim_treesitter) and H.get_matched_ranges_plugin\n      or H.get_matched_ranges_builtin\n    local matched_ranges = range_querier(target_captures)\n    return vim.tbl_map(ts_range_to_region, matched_ranges)\n  end\nend\n\n--- Specification from user prompt\n---\n--- - Ask user for left and right textobject edges as raw strings (no pattern).\n--- - Construct specification for a textobject that matches from left edge string\n---   to right edge string: `a` includes both strings, `i` only insides.\n---\n--- Used for |MiniAi-builtin-textobjects| with identifier `?`.\n---\n---@return function Textobject specification as function.\nMiniAi.gen_spec.user_prompt = function()\n  return function()\n    -- Using cache allows for a dot-repeat without another user input\n    if H.cache.prompted_textobject ~= nil then return H.cache.prompted_textobject end\n\n    local left = H.user_input('Left edge')\n    if left == nil or left == '' then return end\n    local right = H.user_input('Right edge')\n    if right == nil or right == '' then return end\n\n    -- Clean command line from prompt messages (does not work in Visual mode)\n    vim.cmd([[echo '' | redraw]])\n\n    local left_esc, right_esc = vim.pesc(left), vim.pesc(right)\n    local res = { string.format('%s().-()%s', left_esc, right_esc) }\n    H.cache.prompted_textobject = res\n    return res\n  end\nend\n\n--- Visually select textobject region\n---\n--- Does nothing if no region is found.\n---\n---@param ai_type string One of `'a'` or `'i'`.\n---@param id string Single character string representing textobject id.\n---@param opts table|nil Same as in |MiniAi.find_textobject()|. Extra fields:\n---   - <vis_mode> - One of `'v'`, `'V'`, or `'\\22'` (escaped version of `'<C-v>'`).\n---     Default: Latest visual mode.\n---   - <operator_pending> - Whether selection is for Operator-pending mode.\n---     Used in that mode's mappings, shouldn't be used directly. Default: `false`.\nMiniAi.select_textobject = function(ai_type, id, opts)\n  if H.is_disabled() then return end\n\n  opts = opts or {}\n  local operator_pending = opts.operator_pending\n\n  -- Exit to Normal before getting textobject id. This way invalid id doesn't\n  -- result into staying in current mode (which seems to be more convenient).\n  H.exit_to_normal_mode()\n\n  local tobj = MiniAi.find_textobject(ai_type, id, opts)\n  if tobj == nil then return end\n\n  local set_cursor = function(position) vim.api.nvim_win_set_cursor(0, { position.line, position.col - 1 }) end\n\n  -- Allow empty regions\n  local tobj_is_empty = tobj.to == nil\n  tobj.to = tobj.to or tobj.from\n\n  -- Compute selection type preferring the one coming from textobject\n  local vis_mode = tobj.vis_mode\n  if vis_mode == nil or not H.is_visual_mode(vis_mode) then\n    local prev_vis_mode = vim.fn.visualmode()\n    prev_vis_mode = prev_vis_mode == '' and 'v' or prev_vis_mode\n    vis_mode = opts.vis_mode and vim.api.nvim_replace_termcodes(opts.vis_mode, true, true, true) or prev_vis_mode\n  end\n\n  local cache_eventignore = vim.o.eventignore\n  -- Allow going past end of line in order to collapse multiline regions\n  local cache_virtualedit, cache_whichwrap = vim.o.virtualedit, vim.o.whichwrap\n\n  -- Cache window horizontal view data to possibly counter unwanted side scroll\n  local leftcol = vim.fn.winsaveview().leftcol\n\n  pcall(function()\n    -- Do nothing in Operator-pending mode for empty region (except `c`, `d`,\n    -- or selected \"replace\" operators). These are hand picked because they\n    -- completely remove selected text, which is necessary for currently only\n    -- possible empty region selection implementation.\n    local is_empty_opending = tobj_is_empty and opts.operator_pending\n    if is_empty_opending then\n      local is_allowed_empty_opending = vim.v.operator == 'c'\n        or vim.v.operator == 'd'\n        or (vim.v.operator == 'g@' and vim.o.operatorfunc:find('MiniOperators%.replace') ~= nil)\n        or (vim.v.operator == 'g@' and vim.o.operatorfunc:find('substitute') ~= nil)\n      if not is_allowed_empty_opending then return H.message('Textobject region is empty. Nothing is done.') end\n    end\n\n    -- Allow setting cursor past line end (allows collapsing multiline region)\n    -- NOTE: This doesn't work for 'virtualedit=all' and 'selection=inclusive'\n    -- (default). The reason is that later option restoring is done immediately\n    -- leading to a selection obey 'virtualedit=all' rules and thus won't treat\n    -- end-of-line as '\\n' and collapse multiline region. The solution is to\n    -- `vim.schedule()` option restore, but it feels too much for a niche case.\n    vim.o.virtualedit = 'onemore'\n\n    -- Select region:\n    -- - Go from start to end stay at range end in Visual mode (as done in\n    --   built-in visual selection).\n    -- - Open just enough folds to have both ends visible.\n    -- - Respect exclusive selection (including when selecting end of line)\n    set_cursor(tobj.from)\n    vim.cmd('normal! zv')\n    vim.cmd('normal! ' .. vis_mode)\n    set_cursor(tobj.to)\n    if vim.o.selection == 'exclusive' and not tobj_is_empty then vim.cmd('set whichwrap=l | normal! l') end\n    vim.cmd('normal! zv')\n\n    -- Restore horizontal view which was possibly affected by moving cursor\n    -- NOTE: It seems to not affect cursor if it is outside of restored view\n    vim.fn.winrestview({ leftcol = leftcol })\n\n    if is_empty_opending then\n      -- Add single space (without triggering events) and visually select it.\n      -- Seems like the only way to make `ci)` and `di)` move inside empty\n      -- brackets. Original idea is from 'wellle/targets.vim'.\n      vim.o.eventignore = 'all'\n\n      -- First escape from previously started Visual mode\n      vim.cmd([[silent! execute \"normal! \\<Esc>i \\<Esc>v\"]])\n    end\n  end)\n\n  -- Restore options\n  vim.o.eventignore = cache_eventignore\n  vim.o.virtualedit, vim.o.whichwrap = cache_virtualedit, cache_whichwrap\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniAi.config)\n\n-- Cache for various operations\nH.cache = {}\n\n-- Builtin textobjects\nH.builtin_textobjects = {\n  -- Use balanced pair for brackets. Use opening ones to possibly remove edge\n  -- whitespace from `i` textobject.\n  ['('] = { '%b()', '^.%s*().-()%s*.$' },\n  [')'] = { '%b()', '^.().*().$' },\n  ['['] = { '%b[]', '^.%s*().-()%s*.$' },\n  [']'] = { '%b[]', '^.().*().$' },\n  ['{'] = { '%b{}', '^.%s*().-()%s*.$' },\n  ['}'] = { '%b{}', '^.().*().$' },\n  ['<'] = { '%b<>', '^.%s*().-()%s*.$' },\n  ['>'] = { '%b<>', '^.().*().$' },\n  -- Use special \"same balanced\" pattern to select quotes in pairs\n  [\"'\"] = { \"%b''\", '^.().*().$' },\n  ['\"'] = { '%b\"\"', '^.().*().$' },\n  ['`'] = { '%b``', '^.().*().$' },\n  -- Derived from user prompt\n  ['?'] = MiniAi.gen_spec.user_prompt(),\n  -- Argument\n  ['a'] = MiniAi.gen_spec.argument(),\n  -- Brackets\n  ['b'] = { { '%b()', '%b[]', '%b{}' }, '^.().*().$' },\n  -- Function call\n  ['f'] = MiniAi.gen_spec.function_call(),\n  -- Tag\n  ['t'] = { '<(%w-)%f[^<%w][^<>]->.-</%1>', '^<.->().*()</[^/]->$' },\n  -- Quotes\n  ['q'] = { { \"%b''\", '%b\"\"', '%b``' }, '^.().*().$' },\n}\n\n-- Module's namespaces\nH.ns_id = {\n  -- Track user input\n  input = vim.api.nvim_create_namespace('MiniAiInput'),\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('custom_textobjects', config.custom_textobjects, 'table', true)\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.around', config.mappings.around, 'string')\n  H.check_type('mappings.inside', config.mappings.inside, 'string')\n  H.check_type('mappings.around_next', config.mappings.around_next, 'string')\n  H.check_type('mappings.inside_next', config.mappings.inside_next, 'string')\n  H.check_type('mappings.around_last', config.mappings.around_last, 'string')\n  H.check_type('mappings.inside_last', config.mappings.inside_last, 'string')\n  H.check_type('mappings.goto_left', config.mappings.goto_left, 'string')\n  H.check_type('mappings.goto_right', config.mappings.goto_right, 'string')\n\n  H.check_type('n_lines', config.n_lines, 'number')\n  H.validate_search_method(config.search_method, 'search_method')\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\n--stylua: ignore\nH.apply_config = function(config)\n  MiniAi.config = config\n\n  -- Make mappings\n  local maps = config.mappings\n  local m = function(mode, lhs, rhs, opts)\n    opts.expr = true\n    -- Allow recursive mapping to support falling back on user defined mapping\n    opts.remap = true\n    H.map(mode, lhs, rhs, opts)\n  end\n\n  m({ 'n', 'x', 'o' }, maps.goto_left,  function() return H.expr_motion('left') end,   { desc = 'Move to left \"around\"' })\n  m({ 'n', 'x', 'o' }, maps.goto_right, function() return H.expr_motion('right') end,  { desc = 'Move to right \"around\"' })\n\n  local make_tobj = function(mode, ai_type, search_method)\n    return function() return H.expr_textobject(mode, ai_type, { search_method = search_method }) end\n  end\n\n  m('x', maps.around, make_tobj('x', 'a'), { desc = 'Around textobject' })\n  m('x', maps.inside, make_tobj('x', 'i'), { desc = 'Inside textobject' })\n  m('o', maps.around, make_tobj('o', 'a'), { desc = 'Around textobject' })\n  m('o', maps.inside, make_tobj('o', 'i'), { desc = 'Inside textobject' })\n\n  m('x', maps.around_next, make_tobj('x', 'a', 'next'), { desc = 'Around next textobject' })\n  m('x', maps.around_last, make_tobj('x', 'a', 'prev'), { desc = 'Around last textobject' })\n  m('x', maps.inside_next, make_tobj('x', 'i', 'next'), { desc = 'Inside next textobject' })\n  m('x', maps.inside_last, make_tobj('x', 'i', 'prev'), { desc = 'Inside last textobject' })\n  m('o', maps.around_next, make_tobj('o', 'a', 'next'), { desc = 'Around next textobject' })\n  m('o', maps.around_last, make_tobj('o', 'a', 'prev'), { desc = 'Around last textobject' })\n  m('o', maps.inside_next, make_tobj('o', 'i', 'next'), { desc = 'Inside next textobject' })\n  m('o', maps.inside_last, make_tobj('o', 'i', 'prev'), { desc = 'Inside last textobject' })\nend\n\nH.is_disabled = function() return vim.g.miniai_disable == true or vim.b.miniai_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniAi.config, vim.b.miniai_config or {}, config or {})\nend\n\nH.is_search_method = function(x, x_name)\n  x = x or H.get_config().search_method\n  x_name = x_name or '`config.search_method`'\n\n  local allowed_methods = vim.tbl_keys(H.span_compare_methods)\n  if vim.tbl_contains(allowed_methods, x) then return true end\n\n  table.sort(allowed_methods)\n  local allowed_methods_string = table.concat(vim.tbl_map(vim.inspect, allowed_methods), ', ')\n  local msg = ([[%s should be one of %s.]]):format(x_name, allowed_methods_string)\n  return false, msg\nend\n\nH.validate_search_method = function(x, x_name)\n  local is_valid, msg = H.is_search_method(x, x_name)\n  if not is_valid then H.error(msg) end\nend\n\n-- Mappings -------------------------------------------------------------------\nH.expr_textobject = function(mode, ai_type, opts)\n  local tobj_id = H.user_textobject_id(ai_type)\n\n  if tobj_id == nil then return mode == 'o' and '<Esc>' or '' end\n\n  -- Possibly fall back to builtin `a`/`i` textobjects\n  if H.is_disabled() or not H.is_valid_textobject_id(tobj_id) then\n    local mappings = H.get_config().mappings\n    local main_key = mappings[ai_type == 'a' and 'around' or 'inside']\n    local res = main_key .. tobj_id\n    -- If fallback is an existing user mapping, prepend it with '<Ignore>'.\n    -- This deals with `:h recursive_mapping`. Shouldn't prepend if it is a\n    -- builtin textobject. Also see https://github.com/vim/vim/issues/10907 .\n    if vim.fn.maparg(res, mode) ~= '' then res = '<Ignore>' .. res end\n    return res\n  end\n  opts = vim.tbl_deep_extend('force', H.get_default_opts(), opts or {})\n\n  -- Clear cache\n  H.cache = {}\n\n  -- Construct call options based on mode\n  local reference_region_field, operator_pending_field, vis_mode_field = 'nil', 'nil', 'nil'\n\n  if mode == 'x' then\n    -- Use Visual selection as reference region for Visual mode mappings\n    reference_region_field = vim.inspect(H.get_visual_region(), { newline = '', indent = '' })\n  end\n\n  if mode == 'o' then\n    -- Supply `operator_pending` flag in Operator-pending mode\n    operator_pending_field = 'true'\n\n    -- Take into account forced Operator-pending modes ('nov', 'noV', 'no<C-V>')\n    vis_mode_field = vim.fn.mode(1):gsub('^no', '')\n    vis_mode_field = vim.inspect(vis_mode_field == '' and 'v' or vis_mode_field)\n  end\n\n  -- Make expression\n  return '<Cmd>lua '\n    .. string.format(\n      [[MiniAi.select_textobject('%s', %s, { search_method = %s, n_times = %d, reference_region = %s, operator_pending = %s, vis_mode = %s })]],\n      ai_type,\n      vim.inspect(tobj_id),\n      vim.inspect(opts.search_method),\n      vim.v.count1,\n      reference_region_field,\n      operator_pending_field,\n      vis_mode_field\n    )\n    .. '<CR>'\nend\n\nH.expr_motion = function(side)\n  if H.is_disabled() then return '' end\n\n  if not (side == 'left' or side == 'right') then H.error([[`side` should be one of 'left' or 'right'.]]) end\n\n  -- Get user input\n  local tobj_id = H.user_textobject_id('a')\n  if tobj_id == nil then return end\n\n  -- Clear cache\n  H.cache = {}\n\n  -- Make expression for moving cursor\n  return '<Cmd>lua '\n    .. string.format([[MiniAi.move_cursor('%s', 'a', %s, { n_times = %d })]], side, vim.inspect(tobj_id), vim.v.count1)\n    .. '<CR>'\nend\n\n-- Work with textobject info --------------------------------------------------\nH.make_textobject_table = function()\n  -- Extend builtins with data from `config`. Don't use `tbl_deep_extend()`\n  -- because only top level keys should be merged.\n  local textobjects = vim.tbl_extend('force', H.builtin_textobjects, H.get_config().custom_textobjects or {})\n\n  -- Use default textobject pattern for anything excluding Latin characters, as\n  -- they are needed to fall back to Neovim's built-in textobjects (like `aw`)\n  return setmetatable(textobjects, {\n    __index = function(_, key)\n      if type(key) == 'string' and string.find(key, '^%a$') ~= nil then return end\n      local key_esc = vim.pesc(key)\n      -- Use `%f[]` to ensure maximum stretch in both directions. Include only\n      -- right edge in `a` textobject.\n      -- Example output: '_()()[^_]-()_+%f[^_]()'\n      return { string.format('%s()()[^%s]-()%s+%%f[^%s]()', key_esc, key_esc, key_esc, key_esc) }\n    end,\n  })\nend\n\nH.get_textobject_spec = function(id, args)\n  local textobject_tbl = H.make_textobject_table()\n  local spec = textobject_tbl[id]\n\n  -- Allow function returning spec or region(s)\n  if vim.is_callable(spec) then spec = spec(unpack(args)) end\n\n  -- Wrap callable tables to be an actual functions. Otherwise they might be\n  -- confused with list of patterns.\n  if H.is_composed_pattern(spec) then return vim.tbl_map(H.wrap_callable_table, spec) end\n\n  if not (H.is_region(spec) or H.is_region_array(spec)) then return nil end\n  return spec\nend\n\nH.is_valid_textobject_id = function(id)\n  local spec = H.make_textobject_table()[id]\n  return type(spec) == 'table' or vim.is_callable(spec)\nend\n\nH.is_region = function(x)\n  if type(x) ~= 'table' then return false end\n  local from_is_valid = type(x.from) == 'table' and type(x.from.line) == 'number' and type(x.from.col) == 'number'\n  -- Allow `to` to be `nil` to describe empty regions\n  local to_is_valid = true\n  if x.to ~= nil then\n    to_is_valid = type(x.to) == 'table' and type(x.to.line) == 'number' and type(x.to.col) == 'number'\n  end\n  return from_is_valid and to_is_valid\nend\n\nH.is_region_array = function(x)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not H.is_region(v) then return false end\n  end\n  return true\nend\n\nH.is_composed_pattern = function(x)\n  if not (H.islist(x) and #x > 0) then return false end\n  for _, val in ipairs(x) do\n    local val_type = type(val)\n    if not (val_type == 'table' or val_type == 'string' or vim.is_callable(val)) then return false end\n  end\n  return true\nend\n\n-- Work with finding textobjects ----------------------------------------------\n---@param tobj_spec table Composed pattern. Last item(s) - extraction template.\n---@param ai_type string One of `'a'` or `'i'`.\n---@param opts table Textobject options with all fields present.\n---@private\nH.find_textobject_region = function(tobj_spec, ai_type, opts)\n  local reference_region, n_times, n_lines = opts.reference_region, opts.n_times, opts.n_lines\n\n  if n_times == 0 then return end\n\n  -- Find `n_times` matching spans evolving from reference region span\n  -- First try to find inside 0-neighborhood\n  local neigh = H.get_neighborhood(reference_region, 0)\n  local reference_span = neigh.region_to_span(reference_region)\n\n  local find_next = function(cur_reference_span)\n    local res = H.find_best_match(neigh, tobj_spec, cur_reference_span, opts)\n\n    -- If didn't find in 0-neighborhood, possibly try extend one\n    if res.span == nil then\n      -- Stop if no need to extend neighborhood\n      if n_lines == 0 or neigh.n_neighbors > 0 then return {} end\n\n      -- Update data with respect to new neighborhood\n      local cur_reference_region = neigh.span_to_region(cur_reference_span)\n      neigh = H.get_neighborhood(reference_region, n_lines)\n      reference_span = neigh.region_to_span(reference_region)\n      cur_reference_span = neigh.region_to_span(cur_reference_region)\n\n      -- Recompute based on new neighborhood\n      res = H.find_best_match(neigh, tobj_spec, cur_reference_span, opts)\n    end\n\n    return res\n  end\n\n  local find_res = { span = reference_span }\n  for _ = 1, n_times do\n    find_res = find_next(find_res.span)\n    if find_res.span == nil then return end\n  end\n\n  -- Extract final span\n  local extract = function(span, extract_pattern)\n    -- Use `nil` extract pattern to allow array of regions as textobject spec\n    if extract_pattern == nil then return span end\n\n    -- First extract local (with respect to best matched span) span\n    local s = neigh['1d']:sub(span.from, span.to - 1)\n    local local_span = H.extract_span(s, extract_pattern, ai_type)\n\n    -- Convert local span to global\n    local offset = span.from - 1\n    return { from = local_span.from + offset, to = local_span.to + offset }\n  end\n\n  local final_span = extract(find_res.span, find_res.extract_pattern)\n\n  -- Ensure that output region is different from reference. This is needed if\n  -- final span was shrunk during extraction and resulted into equal to input\n  -- reference. This powers consecutive application of most `i` textobjects.\n  if H.is_span_covering(reference_span, final_span) then\n    find_res = find_next(find_res.span)\n    if find_res.span == nil then return end\n    final_span = extract(find_res.span, find_res.extract_pattern)\n    if H.is_span_covering(reference_span, final_span) then return end\n  end\n\n  -- Convert to region\n  return neigh.span_to_region(final_span, find_res.vis_mode)\nend\n\nH.get_default_opts = function()\n  local config = H.get_config()\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  return {\n    n_lines = config.n_lines,\n    n_times = vim.v.count1,\n    -- Empty region at cursor position\n    reference_region = { from = { line = cur_pos[1], col = cur_pos[2] + 1 } },\n    search_method = config.search_method,\n  }\nend\n\n-- Work with argument textobject ----------------------------------------------\nH.arg_get_separator_spans = function(s, sep_pattern, exclude_regions)\n  if s:len() <= 2 then return {} end\n\n  -- Pre-compute edge separator spans (assumes edge characters are brackets)\n  local left_bracket_span = { 1, 1 }\n  local right_bracket_span = { s:len(), s:len() }\n\n  -- Get all separator spans (meaning separator is allowed to match more than\n  -- a single character)\n  local sep_spans = {}\n  s:gsub('()' .. sep_pattern .. '()', function(l, r) table.insert(sep_spans, { l, r - 1 }) end)\n  if #sep_spans == 0 then return { left_bracket_span, right_bracket_span } end\n\n  -- Remove separators that are in \"excluded regions\": by default, inside\n  -- brackets or quotes\n  local inner_s, forbidden = s:sub(2, -2), {}\n  local add_to_forbidden = function(l, r) table.insert(forbidden, { l + 1, r }) end\n\n  for _, pat in ipairs(exclude_regions) do\n    local capture_pat = string.format('()%s()', pat)\n    inner_s:gsub(capture_pat, add_to_forbidden)\n  end\n\n  local res = vim.tbl_filter(function(x) return not H.is_span_inside_spans(x, forbidden) end, sep_spans)\n\n  -- Append edge separators (assumes first and last characters are from\n  -- brackets). This allows single argument and ensures at least 2 elements.\n  table.insert(res, 1, left_bracket_span)\n  table.insert(res, right_bracket_span)\n  return res\nend\n\n-- Work with treesitter textobject --------------------------------------------\nH.prepare_ai_captures = function(ai_captures)\n  local is_capture = function(x)\n    if type(x) == 'string' then x = { x } end\n    if not H.islist(x) then return false end\n\n    for _, v in ipairs(x) do\n      if not (type(v) == 'string' and v:sub(1, 1) == '@') then return false end\n    end\n    return true\n  end\n\n  if not (type(ai_captures) == 'table' and is_capture(ai_captures.a) and is_capture(ai_captures.i)) then\n    H.error('Wrong format for `ai_captures`. See `MiniAi.gen_spec.treesitter()` for details.')\n  end\n\n  local prepare = function(x)\n    if type(x) == 'string' then return { x } end\n    return x\n  end\n\n  return { a = prepare(ai_captures.a), i = prepare(ai_captures.i) }\nend\n\nH.get_matched_ranges_plugin = function(captures)\n  local ts_queries = require('nvim-treesitter.query')\n  local buf_id = vim.api.nvim_get_current_buf()\n  local matches = ts_queries.get_capture_matches_recursively(buf_id, captures, 'textobjects')\n  local res = vim.tbl_map(function(m) return vim.treesitter.get_range(m.node, buf_id, m.metadata) end, matches)\n  return res\nend\n\nH.get_matched_ranges_builtin = function(captures)\n  -- Get buffer's parser (LanguageTree)\n  local buf_id = vim.api.nvim_get_current_buf()\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, nil, { error = false })\n  if not has_parser or parser == nil then H.error_treesitter('parser') end\n\n  -- Get parser (LanguageTree) at cursor (important for injected languages)\n  local pos = vim.api.nvim_win_get_cursor(0)\n  local lang_tree = parser:language_for_range({ pos[1] - 1, pos[2], pos[1] - 1, pos[2] })\n\n  local missing_query_langs = {}\n  local res = {}\n  -- Maybe go up parent trees to work with injected languages\n  while vim.tbl_isempty(res) and lang_tree ~= nil do\n    local lang = lang_tree:lang()\n    -- Get query file depending on the local language\n    local query = vim.treesitter.query.get(lang, 'textobjects')\n\n    if query ~= nil then H.append_ranges(res, buf_id, query, captures, lang_tree) end\n    if query == nil then missing_query_langs[lang] = true end\n\n    -- `LanguageTree:parent()` was added in Neovim<0.10\n    -- TODO: Drop extra check after compatibility with Neovim=0.9 is dropped\n    lang_tree = lang_tree.parent and lang_tree:parent() or nil\n  end\n\n  if vim.tbl_isempty(res) and not vim.tbl_isempty(missing_query_langs) then\n    H.error_treesitter('query', vim.tbl_keys(missing_query_langs))\n  end\n\n  return res\nend\n\nH.append_ranges = function(res, buf_id, query, captures, lang_tree)\n  -- Compute ranges of matched captures\n  local capture_is_requested = vim.tbl_map(function(c) return vim.tbl_contains(captures, '@' .. c) end, query.captures)\n\n  for _, tree in ipairs(lang_tree:trees()) do\n    -- TODO: Remove `opts.all`after compatibility with Neovim=0.10 is dropped\n    for _, match, metadata in query:iter_matches(tree:root(), buf_id, nil, nil, { all = true }) do\n      for capture_id, nodes in pairs(match) do\n        local mt = metadata[capture_id]\n        if capture_is_requested[capture_id] then table.insert(res, H.get_nodes_range_builtin(nodes, buf_id, mt)) end\n      end\n    end\n  end\nend\n\nH.get_nodes_range_builtin = function(nodes, buf_id, metadata)\n  -- In Neovim<0.10 `Query:iter_matches()` has `match` map to single node.\n  -- TODO: Remove `opts.all`after compatibility with Neovim=0.9 is dropped\n  nodes = type(nodes) == 'table' and nodes or { nodes }\n\n  -- Get matched range as spanning from left most node start to right most node\n  -- end. This accounts for several matched nodes that are intentionally there\n  -- to cover complex cases. Approach is named \"quantified captures\".\n  local left, right\n  for _, node in ipairs(nodes) do\n    local range = vim.treesitter.get_range(node, buf_id, metadata)\n    if left == nil or range[3] < left[3] then left = range end\n    if right == nil or range[6] > right[6] then right = range end\n  end\n  return { left[1], left[2], left[3], right[4], right[5], right[6] }\nend\n\nH.error_treesitter = function(failed_get, langs)\n  local buf_id, ft = vim.api.nvim_get_current_buf(), vim.bo.filetype\n  if langs == nil then\n    local has_lang, ft_lang = pcall(vim.treesitter.language.get_lang, ft)\n    -- `vim.treesitter.language.get_lang()` defaults to `ft` on Neovim>0.11\n    -- TODO: Drop check after compatibility with Neovim=0.10 is dropped\n    langs = (has_lang and ft_lang ~= nil) and { ft_lang } or { ft }\n  end\n  table.sort(langs)\n  local langs_str = table.concat(vim.tbl_map(vim.inspect, langs), ', ')\n  local langs_noun = #langs == 1 and 'language' or 'languages'\n  local msg = string.format('Can not get %s for buffer %d and %s %s.', failed_get, buf_id, langs_noun, langs_str)\n  H.error(msg)\nend\n\n-- Work with matching spans ---------------------------------------------------\n---@param neighborhood table Output of `get_neighborhood()`.\n---@param tobj_spec table Textobject specification.\n---@param reference_span table Span to cover.\n---@param opts table Fields: <search_method>.\n---@private\nH.find_best_match = function(neighborhood, tobj_spec, reference_span, opts)\n  local best_span, best_nested_pattern, best_vis_mode, current_nested_pattern\n  local f = function(span, vis_mode)\n    if H.is_better_span(span, best_span, reference_span, opts) then\n      best_span, best_nested_pattern, best_vis_mode = span, current_nested_pattern, vis_mode\n    end\n  end\n\n  if H.is_region_array(tobj_spec) then\n    -- Iterate over all spans representing regions in array\n    for _, region in ipairs(tobj_spec) do\n      -- Consider region only if it is completely within neighborhood\n      if neighborhood.is_region_inside(region) then f(neighborhood.region_to_span(region), region.vis_mode) end\n    end\n  else\n    -- Iterate over all matched spans\n    for _, nested_pattern in ipairs(H.cartesian_product(tobj_spec)) do\n      current_nested_pattern = nested_pattern\n      H.iterate_matched_spans(neighborhood['1d'], nested_pattern, f)\n    end\n  end\n\n  local extract_pattern\n  if best_nested_pattern ~= nil then extract_pattern = best_nested_pattern[#best_nested_pattern] end\n  return { span = best_span, vis_mode = best_vis_mode, extract_pattern = extract_pattern }\nend\n\nH.iterate_matched_spans = function(line, nested_pattern, f)\n  local max_level = #nested_pattern\n  -- Keep track of visited spans to ensure only one call of `f`.\n  -- Example: `((a) (b))`, `{'%b()', '%b()'}`\n  local visited = {}\n\n  local process\n  process = function(level, level_line, level_offset)\n    local pattern = nested_pattern[level]\n    local next_span = function(s, init) return H.string_find(s, pattern, init) end\n    if vim.is_callable(pattern) then next_span = pattern end\n\n    local is_same_balanced = type(pattern) == 'string' and pattern:match('^%%b(.)%1$') ~= nil\n    local init = 1\n    while init <= level_line:len() do\n      local from, to = next_span(level_line, init)\n      if from == nil then break end\n\n      if level == max_level then\n        local found_match = H.new_span(from + level_offset, to + level_offset)\n        local found_match_id = string.format('%s_%s', found_match.from, found_match.to)\n        if not visited[found_match_id] then\n          f(found_match)\n          visited[found_match_id] = true\n        end\n      else\n        local next_level_line = level_line:sub(from, to)\n        local next_level_offset = level_offset + from - 1\n        process(level + 1, next_level_line, next_level_offset)\n      end\n\n      -- Start searching from right end to implement \"balanced\" pair.\n      -- This doesn't work with regular balanced pattern because it doesn't\n      -- capture nested brackets.\n      init = (is_same_balanced and to or from) + 1\n    end\n  end\n\n  process(1, line, 0)\nend\n\n-- NOTE: spans are end-exclusive to allow empty spans via `from == to`\nH.new_span = function(from, to) return { from = from, to = to == nil and from or (to + 1) } end\n\n---@param candidate table Candidate span to test against `current`.\n---@param current table|nil Current best span.\n---@param reference table Reference span to cover.\n---@param opts table Fields: <search_method>.\n---@private\nH.is_better_span = function(candidate, current, reference, opts)\n  -- Candidate should be never equal or nested inside reference\n  if H.is_span_covering(reference, candidate) or H.is_span_equal(candidate, reference) then return false end\n\n  return H.span_compare_methods[opts.search_method](candidate, current, reference)\nend\n\nH.span_compare_methods = {\n  cover = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n    -- If both are not covering, `candidate` is not better (as it must cover)\n    return false\n  end,\n\n  cover_or_next = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n\n    -- If not covering, `candidate` must be \"next\" and closer to reference\n    if not H.is_span_on_left(reference, candidate) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.next\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  cover_or_prev = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n\n    -- If not covering, `candidate` must be \"previous\" and closer to reference\n    if not H.is_span_on_left(candidate, reference) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.prev\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  cover_or_nearest = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n\n    -- If not covering, `candidate` must be closer to reference\n    if current == nil then return true end\n\n    local dist = H.span_distance.near\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  next = function(candidate, current, reference)\n    if H.is_span_covering(candidate, reference) then return false end\n\n    -- `candidate` must be \"next\" and closer to reference\n    if not H.is_span_on_left(reference, candidate) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.next\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  prev = function(candidate, current, reference)\n    if H.is_span_covering(candidate, reference) then return false end\n\n    -- `candidate` must be \"previous\" and closer to reference\n    if not H.is_span_on_left(candidate, reference) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.prev\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  nearest = function(candidate, current, reference)\n    if H.is_span_covering(candidate, reference) then return false end\n\n    -- `candidate` must be closer to reference\n    if current == nil then return true end\n\n    local dist = H.span_distance.near\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n}\n\nH.span_distance = {\n  -- Other possible choices of distance between [a1, a2] and [b1, b2]:\n  -- - Hausdorff distance: max(|a1 - b1|, |a2 - b2|).\n  --   Source:\n  --   https://math.stackexchange.com/questions/41269/distance-between-two-ranges\n  -- - Minimum distance: min(|a1 - b1|, |a2 - b2|).\n\n  -- Distance is chosen so that \"next span\" in certain direction is the closest\n  next = function(span_1, span_2) return math.abs(span_1.from - span_2.from) end,\n  prev = function(span_1, span_2) return math.abs(span_1.to - span_2.to) end,\n  near = function(span_1, span_2) return math.min(math.abs(span_1.from - span_2.from), math.abs(span_1.to - span_2.to)) end,\n}\n\nH.is_better_covering_span = function(candidate, current, reference)\n  local candidate_is_covering = H.is_span_covering(candidate, reference)\n  local current_is_covering = H.is_span_covering(current, reference)\n\n  if candidate_is_covering and current_is_covering then\n    -- Covering candidate is better than covering current if it is narrower\n    return (candidate.to - candidate.from) < (current.to - current.from)\n  end\n  if candidate_is_covering and not current_is_covering then return true end\n  if not candidate_is_covering and current_is_covering then return false end\n\n  -- Return `nil` if neither span is covering\n  return nil\nend\n\n--stylua: ignore\nH.is_span_covering = function(span, span_to_cover)\n  if span == nil or span_to_cover == nil then return false end\n  if span.from == span.to then\n    return (span.from == span_to_cover.from) and (span_to_cover.to == span.to)\n  end\n  if span_to_cover.from == span_to_cover.to then\n    return (span.from <= span_to_cover.from) and (span_to_cover.to < span.to)\n  end\n\n  return (span.from <= span_to_cover.from) and (span_to_cover.to <= span.to)\nend\n\nH.is_span_equal = function(span_1, span_2)\n  if span_1 == nil or span_2 == nil then return false end\n  return (span_1.from == span_2.from) and (span_1.to == span_2.to)\nend\n\nH.is_span_on_left = function(span_1, span_2)\n  if span_1 == nil or span_2 == nil then return false end\n  return (span_1.from <= span_2.from) and (span_1.to <= span_2.to)\nend\n\nH.is_span_inside_spans = function(ref_span, spans)\n  for _, span in ipairs(spans) do\n    if span[1] <= ref_span[1] and ref_span[2] <= span[2] then return true end\n  end\n  return false\nend\n\n-- Work with Lua patterns -----------------------------------------------------\nH.extract_span = function(s, extract_pattern, ai_type)\n  local positions = { s:match(extract_pattern) }\n\n  if #positions == 1 and type(positions[1]) == 'string' then\n    if s:len() == 0 then return H.new_span(0, 0) end\n    return H.new_span(1, s:len())\n  end\n\n  local is_all_numbers = true\n  for _, pos in ipairs(positions) do\n    if type(pos) ~= 'number' then is_all_numbers = false end\n  end\n\n  local is_valid_positions = is_all_numbers and (#positions == 2 or #positions == 4)\n  if not is_valid_positions then\n    local msg = 'Could not extract proper positions (two or four empty captures) from '\n      .. string.format([[string '%s' with extraction pattern '%s'.]], s, extract_pattern)\n    H.error(msg)\n  end\n\n  local ai_spans\n  if #positions == 2 then\n    ai_spans = { a = H.new_span(1, s:len()), i = H.new_span(positions[1], positions[2] - 1) }\n  else\n    ai_spans = { a = H.new_span(positions[1], positions[4] - 1), i = H.new_span(positions[2], positions[3] - 1) }\n  end\n\n  return ai_spans[ai_type]\nend\n\n-- Work with cursor neighborhood ----------------------------------------------\n---@param reference_region table Reference region.\n---@param n_neighbors number Maximum number of neighbors to include before\n---   start line and after end line.\n---@private\nH.get_neighborhood = function(reference_region, n_neighbors)\n  -- Compute '2d neighborhood' of (possibly empty) region\n  local from_line, to_line = reference_region.from.line, (reference_region.to or reference_region.from).line\n  local line_start = math.max(1, from_line - n_neighbors)\n  local line_end = math.min(vim.api.nvim_buf_line_count(0), to_line + n_neighbors)\n  local neigh2d = vim.api.nvim_buf_get_lines(0, line_start - 1, line_end, false)\n  -- Append 'newline' character to distinguish between lines in 1d case\n  for k, v in pairs(neigh2d) do\n    neigh2d[k] = v .. '\\n'\n  end\n\n  -- '1d neighborhood': position is determined by offset from start\n  local neigh1d = table.concat(neigh2d, '')\n\n  -- Convert 2d buffer position to 1d offset\n  local pos_to_offset = function(pos)\n    if pos == nil then return nil end\n    local line_num = line_start\n    local offset = 0\n    while line_num < pos.line do\n      offset = offset + neigh2d[line_num - line_start + 1]:len()\n      line_num = line_num + 1\n    end\n\n    return offset + pos.col\n  end\n\n  -- Convert 1d offset to 2d buffer position\n  local offset_to_pos = function(offset)\n    if offset == nil then return nil end\n    local line_num = 1\n    local line_offset = 0\n    while line_num <= #neigh2d and line_offset + neigh2d[line_num]:len() < offset do\n      line_offset = line_offset + neigh2d[line_num]:len()\n      line_num = line_num + 1\n    end\n\n    return { line = line_start + line_num - 1, col = offset - line_offset }\n  end\n\n  -- Convert 2d region to 1d span\n  local region_to_span = function(region)\n    if region == nil then return nil end\n    local is_empty = region.to == nil\n    local to = region.to or region.from\n    return { from = pos_to_offset(region.from), to = pos_to_offset(to) + (is_empty and 0 or 1) }\n  end\n\n  -- Convert 1d span to 2d region\n  local span_to_region = function(span, vis_mode)\n    if span == nil then return nil end\n    -- NOTE: this might lead to outside of line positions due to added `\\n` at\n    -- the end of lines in 1d-neighborhood. However, this is crucial for\n    -- allowing `i` textobjects to collapse multiline selections.\n    local res = { from = offset_to_pos(span.from), vis_mode = vis_mode }\n\n    -- Convert empty span to empty region\n    if span.from < span.to then res.to = offset_to_pos(span.to - 1) end\n    return res\n  end\n\n  local is_region_inside = function(region)\n    local res = line_start <= region.from.line\n    if region.to ~= nil then res = res and (region.to.line <= line_end) end\n    return res\n  end\n\n  return {\n    n_neighbors = n_neighbors,\n    region = reference_region,\n    ['1d'] = neigh1d,\n    ['2d'] = neigh2d,\n    pos_to_offset = pos_to_offset,\n    offset_to_pos = offset_to_pos,\n    region_to_span = region_to_span,\n    span_to_region = span_to_region,\n    is_region_inside = is_region_inside,\n  }\nend\n\n-- Work with user input -------------------------------------------------------\nH.user_textobject_id = function(ai_type)\n  -- Get from user single character textobject identifier\n  local needs_reminder = true\n  vim.defer_fn(function()\n    if not needs_reminder then return end\n\n    local msg = string.format('Reminder to press `%s` textobject id ', ai_type)\n    H.echo(msg)\n    H.cache.msg_shown = true\n  end, 1000)\n  local ok, char = pcall(vim.fn.getcharstr)\n  needs_reminder = false\n  H.unecho()\n\n  -- Terminate if couldn't get input (like with <C-c>) or it is `<Esc>`\n  if not ok or char == '\\27' then return nil end\n  return char\nend\n\nH.user_input = function(prompt, text)\n  -- Use `on_key` to distinguish cancel with `<Esc>` and immediate `<CR>`\n  local was_cancelled = false\n  vim.on_key(function(key) was_cancelled = was_cancelled or key == '\\27' end, H.ns_id.input)\n\n  -- Ask for input. Use `pcall` to allow `<C-c>` to cancel user input\n  vim.cmd('echohl Question')\n  local ok, res = pcall(vim.fn.input, { prompt = '(mini.ai) ' .. prompt .. ': ', default = text or '' })\n  vim.cmd('echohl None | echo \"\" | redraw')\n\n  vim.on_key(nil, H.ns_id.input)\n  return (ok and not was_cancelled) and res or nil\nend\n\n-- Work with Visual mode ------------------------------------------------------\nH.is_visual_mode = function(mode)\n  mode = mode or vim.fn.mode()\n  -- '\\22' is an escaped `<C-v>`\n  return mode == 'v' or mode == 'V' or mode == '\\22', mode\nend\n\nH.exit_to_normal_mode = function()\n  -- Don't use `<C-\\><C-n>` in command-line window as they close it\n  if vim.fn.getcmdwintype() ~= '' then\n    local is_vis, cur_mode = H.is_visual_mode()\n    if is_vis then vim.cmd('normal! ' .. cur_mode) end\n  else\n    -- '\\28\\14' is an escaped version of `<C-\\><C-n>`\n    vim.cmd('normal! \\28\\14')\n  end\nend\n\nH.get_visual_region = function()\n  local is_vis, _ = H.is_visual_mode()\n  if not is_vis then return end\n  local res = {\n    from = { line = vim.fn.line('v'), col = vim.fn.col('v') },\n    to = { line = vim.fn.line('.'), col = vim.fn.col('.') },\n  }\n  if res.from.line > res.to.line or (res.from.line == res.to.line and res.from.col > res.to.col) then\n    res = { from = res.to, to = res.from }\n  end\n  return res\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.ai) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg, is_important)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.ai) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n  local chunks, tot_width = {}, 0\n  for _, ch in ipairs(msg) do\n    local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n    table.insert(chunks, new_ch)\n    tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n    if tot_width >= max_width then break end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, is_important, {})\nend\n\nH.unecho = function()\n  if H.cache.msg_shown then vim.cmd([[echo '' | redraw]]) end\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.string_find = function(s, pattern, init)\n  init = init or 1\n\n  -- Match only start of full string if pattern says so.\n  -- This is needed because `string.find()` doesn't do this.\n  -- Example: `string.find('(aaa)', '^.*$', 4)` returns `4, 5`\n  if pattern:sub(1, 1) == '^' then\n    if init > 1 then return nil end\n    return string.find(s, pattern)\n  end\n\n  -- Handle patterns `x.-y` differently: make match as small as possible. This\n  -- doesn't allow `x` be present inside `.-` match, just as with `yyy`. Which\n  -- also leads to a behavior similar to punctuation id (like with `va_`): no\n  -- covering is possible, only next, previous, or nearest.\n  local check_left, _, prev = string.find(pattern, '(.)%.%-')\n  local is_pattern_special = check_left ~= nil and prev ~= '%'\n  if not is_pattern_special then return string.find(s, pattern, init) end\n\n  -- Make match as small as possible\n  local from, to = string.find(s, pattern, init)\n  if from == nil then return end\n\n  local cur_from, cur_to = from, to\n  while cur_to == to do\n    from, to = cur_from, cur_to\n    cur_from, cur_to = string.find(s, pattern, cur_from + 1)\n  end\n\n  return from, to\nend\n\n---@param arr table List of items. If item is list, consider as set for\n---   product. Else - make it single item list.\n---@private\nH.cartesian_product = function(arr)\n  if not (type(arr) == 'table' and #arr > 0) then return {} end\n  arr = vim.tbl_map(function(x) return H.islist(x) and x or { x } end, arr)\n\n  local res, cur_item = {}, {}\n  local process\n  process = function(level)\n    for i = 1, #arr[level] do\n      table.insert(cur_item, arr[level][i])\n      if level == #arr then\n        -- Flatten array to allow tables as elements of step tables\n        table.insert(res, H.tbl_flatten(cur_item))\n      else\n        process(level + 1)\n      end\n      table.remove(cur_item, #cur_item)\n    end\n  end\n\n  process(1)\n  return res\nend\n\nH.wrap_callable_table = function(x)\n  if vim.is_callable(x) and type(x) == 'table' then\n    return function(...) return x(...) end\n  end\n  return x\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\nH.tbl_flatten = vim.fn.has('nvim-0.10') == 1 and function(x) return vim.iter(x):flatten(math.huge):totable() end\n  or vim.tbl_flatten\n\nreturn MiniAi\n"
  },
  {
    "path": "lua/mini/align.lua",
    "content": "--- *mini.align* Align text interactively\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Rich and flexible customization of both alignment rules and user interaction.\n--- Works with charwise, linewise, and blockwise selections in both Normal mode\n--- (on textobject/motion; with dot-repeat) and Visual mode.\n---\n--- Features:\n--- - Alignment is done in three main steps:\n---     - <Split> lines into parts based on Lua pattern(s) or user-supplied rule.\n---     - <Justify> parts for certain side(s) to be same width inside columns.\n---     - <Merge> parts to be lines, with customizable delimiter(s).\n---\n---     Each main step can be preceded by other steps (pre-steps) to achieve\n---     highly customizable outcome. See `steps` value in |MiniAlign.config|.\n---     For more details, see |MiniAlign-glossary| and |MiniAlign-algorithm|.\n---\n--- - User can control alignment interactively by pressing customizable modifiers\n---   (single keys representing how alignment steps and/or options should change).\n---   Some of default modifiers:\n---     - Press `s` to enter split Lua pattern.\n---     - Press `j` to choose justification side from available ones (\"left\",\n---       \"center\", \"right\", \"none\").\n---     - Press `m` to enter merge delimiter.\n---     - Press `f` to enter filter Lua expression to configure which parts\n---       will be affected (like \"align only first column\").\n---     - Press `i` to ignore some commonly unwanted split matches.\n---     - Press `p` to pair neighboring parts so they be aligned together.\n---     - Press `t` to trim whitespace from parts.\n---     - Press `<BS>` (backspace) to delete some last pre-step.\n---\n---     For more details, see |MiniAlign-modifiers-builtin| and |MiniAlign-examples|.\n---\n--- - Alignment can be done with instant preview (result is updated after each\n---   modifier) or without it (result is shown and accepted after non-default\n---   split pattern is set).\n---\n--- - Every user interaction is accompanied with helper status message showing\n---   relevant information about current alignment process.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.align').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniAlign`\n--- which you can use for scripting or manually (with `:lua MiniAlign.*`).\n---\n--- See |MiniAlign.config| for available config settings.\n---\n--- You can override runtime config settings (like `config.modifiers`) locally\n--- to buffer inside `vim.b.minialign_config` which should have same structure\n--- as `MiniAlign.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Comparisons ~\n---\n--- - [junegunn/vim-easy-align](https://github.com/junegunn/vim-easy-align):\n---     - 'mini.align' is mostly designed after 'junegunn/vim-easy-align', so\n---       there are a lot of similarities.\n---     - Both plugins allow users to change alignment options interactively by\n---       pressing modifier keys (albeit completely different default ones).\n---       'junegunn/vim-easy-align' has those modifiers fixed, while 'mini.align'\n---       allows their full customization. See |MiniAlign.config| for examples.\n---     - 'junegunn/vim-easy-align' is designed to treat delimiters differently\n---       than other parts of strings. 'mini.align' doesn't distinguish split\n---       parts from one another by design: splitting is allowed to be done\n---       based on some other logic than by splitting on delimiters.\n---     - 'junegunn/vim-easy-align' initially aligns by only first delimiter.\n---       'mini.align' initially aligns by all delimiter.\n---     - 'junegunn/vim-easy-align' implements special filtering by delimiter\n---       row number. 'mini.align' has builtin filtering based on Lua code\n---       supplied by user in modifier phase. See |MiniAlign.gen_step.filter()|\n---       and 'f' builtin modifier.\n---     - 'mini.align' treats any non-registered modifier as a plain delimiter\n---       pattern, while 'junegunn/vim-easy-align' does not.\n---     - 'mini.align' exports core Lua function used for aligning strings\n---       (|MiniAlign.align_strings()|).\n--- - [godlygeek/tabular](https://github.com/godlygeek/tabular):\n---     - 'godlygeek/tabular' is mostly designed around single command which is\n---       customized by printing its parameters. 'mini.align' implements\n---       different concept of interactive alignment through pressing\n---       customizable single character modifiers.\n---     - 'godlygeek/tabular' can detect region upon which alignment can be\n---       desirable. 'mini.align' does not by design: use Visual selection or\n---       textobject/motion to explicitly define region to align.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minialign_disable` (globally) or `vim.b.minialign_disable`\n--- (for a buffer) to `true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniAlign\n\n--- PARTS ~\n--- 2d array of strings (array of arrays of strings).\n--- See more in |MiniAlign.as_parts()|.\n---\n--- ROW ~\n--- First-level array of parts (like `parts[1]`).\n---\n--- COLUMN ~\n--- Array of strings, constructed from parts elements with the same\n--- second-level index (like `{ parts[1][1],` `parts[2][1], ... }`).\n---\n--- STEP ~\n--- A named callable. See |MiniAlign.new_step()|. When used in terms of alignment\n--- steps, callable takes two arguments: some object (parts or string array)\n--- and option table.\n---\n--- SPLIT ~\n--- Process of taking array of strings and converting it into parts.\n---\n--- JUSTIFY ~\n--- Process of taking parts and converting them to aligned parts (all elements\n--- have same widths inside columns).\n---\n--- MERGE ~\n--- Process of taking parts and converting it back to array of strings. Usually\n--- by concatenating rows into strings.\n---\n--- REGION ~\n--- Table representing region in a buffer. Fields <from> / <to> have inclusive\n--- start / end positions (<to> might be `nil` to describe empty region).\n--- Positions are also tables with <line> and <col> fields (both start at 1).\n---\n--- MODE ~\n--- Either charwise (\"char\", `v`, |charwise|), linewise (\"line\", `V`, |linewise|)\n--- or blockwise (\"block\", `<C-v>`, |blockwise-visual|)\n---@tag MiniAlign-glossary\n\n--- There are two main processes implemented in 'mini.align': strings alignment\n--- and interactive region alignment. See |MiniAlign-glossary| for more information\n--- about used terms.\n---\n--- # Strings alignment ~\n---\n--- Main implementation is in |MiniAlign.align_strings()|. Its input is array of\n--- strings and output - array of aligned strings. The process consists from three\n--- main steps (split, justify, merge) which can be preceded by any number of\n--- preliminary steps (pre-split, pre-justify, pre-merge).\n---\n--- Algorithm:\n--- - <Pre-split>. Take input array of strings and consecutively apply all\n---   pre-split steps (`steps.pre_split`). Each one has `(strings, opts)` signature\n---   and should modify array in place.\n--- - <Split>. Take array of strings and convert it to parts with `steps.split()`.\n---   It has `(strings, opts)` signature and should return parts.\n--- - <Pre-justify>. Take parts and consecutively apply all pre-justify\n---   steps (`steps.pre_justify`). Each one has `(parts, opts)` signature and\n---   should modify parts in place.\n--- - <Justify>. Take parts and apply `steps.justify()`. It has `(parts, opts)`\n---   signature and should modify parts in place.\n--- - <Pre-merge>. Take parts and consecutively apply all pre-merge\n---   steps (`steps.pre_merge`). Each one has `(parts, opts)` signature and\n---   should modify parts in place.\n--- - <Merge>. Take parts and convert it to array of strings with `steps.merge()`.\n---   It has `(parts, opts)` signature and should return array of strings.\n---\n--- Notes:\n--- - All table objects are initially copied so that modification in place doesn't\n---   affect workflow.\n--- - Default main steps are designed to be controlled via options. See\n---   |MiniAlign.align_strings()| and default step entries in |MiniAlign.gen_step|.\n--- - All steps are guaranteed to take same option table as second argument.\n---   This allows steps to \"talk\" to each other, i.e. earlier steps can pass data\n---   to later ones.\n---\n--- # Interactive region alignment ~\n---\n--- Interactive alignment is a main entry point for most users. It can be done\n--- in two flavors:\n--- - <Without-preview>. Initiated via mapping defined in `start` of\n---   `MiniAlign.config.mappings`. Alignment is accepted once split pattern becomes\n---   non-default.\n--- - <With-preview>. Initiated via mapping defined in `start_with_preview` of\n---   `MiniAlign.config.mappings`. Alignment result is shown after every modifier\n---   and is accepted after `<CR>` (`Enter`) is hit. Note: each preview is done by\n---   applying current alignment steps and options to the initial region lines,\n---   not the ones currently displaying in preview.\n---\n--- Lifecycle (assuming default mappings):\n--- - <Initiate-alignment>:\n---     - In Normal mode type `ga` (or `gA` to show preview) followed by textobject\n---       or motion defining region to be aligned.\n---     - In Visual mode select region and type `ga` (or `gA` to show preview).\n---   Strings contained in selected region will be used as input to\n---   |MiniAlign.align_strings()|.\n---   Beware of mode when selecting region: charwise (`v`), linewise (`V`), or\n---   blockwise (`<C-v>`). They all behave differently.\n--- - <Press-modifiers>. Press single keys one at a time:\n---     - If pressed key is among table keys of `modifiers` table of\n---       |MiniAlign.config|, its function value is executed. It usually modifies\n---       some options(s) and/or affects some pre-step(s).\n---     - If pressed key is not among defined modifiers, it is treated as plain\n---       split pattern.\n---   This process can either end by itself (usually in case of no preview and\n---   non-default split pattern being set) or you can choose to end it manually.\n--- - <Accept-or-discard>. In case of active preview, accept current result by\n---   pressing `<CR>`. Discard any result and return to initial regions with\n---   either `<Esc>` or `<C-c>`.\n---\n--- See more in |MiniAlign-modifiers-builtin| and |MiniAlign-examples|.\n---\n--- Notes:\n--- - Visual blockwise selection works best with 'virtualedit' equal to \"block\"\n---   or \"all\".\n--- - Alignment with preview works best with 'showmode' disabled.\n---@tag MiniAlign-algorithm\n\n--- Overview of builtin modifiers\n---\n--- All examples assume interactive alignment with preview in linewise mode. With\n--- default mappings, use `V` to select lines and `gA` to initiate alignment. It\n--- might be helpful to copy lines into modifiable buffer and experiment yourself.\n---\n--- Notes:\n--- - Any pressed key which doesn't have defined modifier will be treated as\n---   plain split pattern.\n--- - All modifiers can be customized inside |MiniAlign.setup()|. See \"Modifiers\"\n---   section of |MiniAlign.config|.\n---\n--- # Main option modifiers ~\n---\n--- <s> Enter split pattern (confirm prompt by pressing `<CR>`). Input is treated\n---   as plain delimiter.\n---\n---   Before: >\n---   a-b-c\n---   aa-bb-cc\n--- <\n---   After typing `s-<CR>`: >\n---   a -b -c\n---   aa-bb-cc\n--- <\n--- <j> Choose justify side. Prompts user (with helper message) to type single\n---   character identifier of side: `l`eft, `c`enter, `r`ight, `n`one.\n---\n---   Before: >\n---   a_b_c\n---   aa_bb_cc\n--- <\n---   After typing `_jr` (first make split by `_`): >\n---    a_ b_ c\n---   aa_bb_cc\n--- <\n--- <m> Enter merge delimiter (confirm prompt by pressing `<CR>`).\n---\n---   Before: >\n---   a_b_c\n---   aa_bb_cc\n--- <\n---   After typing `_m--<CR>` (first make split by `_`): >\n---   a --_--b --_--c\n---   aa--_--bb--_--cc\n--- <\n--- # Modifiers adding pre-steps ~\n---\n--- <f> Enter filter expression. See more details in |MiniAlign.gen_step.filter()|.\n---\n---   Before: >\n---   a_b_c\n---   aa_bb_cc\n--- <\n---   After typing `_fn==1<CR>` (first make split by `_`): >\n---   a _b_c\n---   aa_bb_cc\n--- <\n--- <i> Ignore some split matches. It modifies `split_exclude_patterns` option by\n---   adding commonly wanted patterns. See more details in\n---   |MiniAlign.gen_step.ignore_split()|.\n---\n---   Before: >\n---   /* This_is_assumed_to_be_comment */\n---   a\"_\"_b\n---   aa_bb\n--- <\n---   After typing `_i` (first make split by `_`): >\n---   /* This_is_assumed_to_be_comment */\n---   a\"_\"_b\n---   aa  _bb\n--- <\n--- <p> Pair neighboring parts.\n---\n---   Before: >\n---   a_b_c\n---   aaa_bbb_ccc\n--- <\n---   After typing `_p` (first make split by `_`): >\n---   a_  b_  c\n---   aaa_bbb_ccc\n--- <\n--- <t> Trim parts from whitespace on both sides (keeping indentation).\n---\n---   Before: >\n---   a   _   b   _   c\n---     aa _bb _cc\n--- <\n---   After typing `_t` (first make split by `_`): >\n---   a   _b _c\n---     aa_bb_cc\n--- <\n--- # Delete some last pre-step ~\n---\n--- <BS> Delete one of the pre-steps. If there is only one kind of pre-steps,\n---   remove its latest added one. If not, prompt user to choose pre-step kind\n---   by entering single character: `s`plit, `j`ustify, `m`erge.\n---\n---   Examples:\n---   - `tp<BS>` results in only \"trim\" step to be left.\n---   - `it<BS>` prompts to choose which step to delete (pre-split or\n---     pre-justify in this case).\n---\n--- # Special configurations for common splits ~\n---\n--- <=> Use special pattern to align by a group of consecutive \"=\". It can be\n---   preceded by any number of punctuation marks and followed by some sommon\n---   punctuation characters. Trim whitespace and merge with single space.\n---\n---   Before: >\n---   a=b\n---   aa<=bb\n---   aaa===bbb\n---   aaaa   =   cccc\n--- <\n---   After typing `=`: >\n---   a    =   b\n---   aa   <=  bb\n---   aaa  === bbb\n---   aaaa =   cccc\n--- <\n--- <,> Besides splitting by \",\" character, trim whitespace, pair neighboring\n---   parts and merge with single space.\n---\n---   Before: >\n---   a,b\n---   aa,bb\n---   aaa    ,    bbb\n--- <\n---   After typing `,`: >\n---   a,   b\n---   aa,  bb\n---   aaa, bbb\n--- <\n--- <|> Split by \"|\" character, trim whitespace, merge with single space.\n---\n---   Before: >\n---   |a|b|\n---   |aa|bb|\n---   |aaa    |    bbb   |\n--- <\n---   After typing `|`: >\n---   | a   | b   |\n---   | aa  | bb  |\n---   | aaa | bbb |\n--- <\n--- <Space> (Space bar) Squash consecutive whitespace into single space (except\n---   possible indentation) and split by `%s+` pattern (keeps indentation).\n---\n---   Before: >\n---   a b c\n---     aa    bb   cc\n--- <\n---   After typing `<Space>`: >\n---     a  b  c\n---     aa bb cc\n--- <\n---@tag MiniAlign-modifiers-builtin\n\n--- Copy lines in modifiable buffer, initiate alignment with preview (`gAip`)\n--- and try typing suggested key sequences.\n--- These are modified examples taken from 'junegunn/vim-easy-align'.\n---\n--- # Equal sign ~\n---\n--- Lines: >\n---\n---   # This=is=assumed=to be a comment\n---   \"a =\"\n---   a =\n---   a = 1\n---   bbbb = 2\n---   ccccccc = 3\n---   ccccccccccccccc\n---   ddd = 4\n---   eeee === eee = eee = eee=f\n---   fff = ggg += gg &&= gg\n---   g != hhhhhhhh == 888\n---   i   := 5\n---   i     %= 5\n---   i       *= 5\n---   j     =~ 5\n---   j   >= 5\n---   aa      =>         123\n---   aa <<= 123\n---   aa        >>= 123\n---   bbb               => 123\n---   c     => 1233123\n---   d   =>      123\n---   dddddd &&= 123\n---   dddddd ||= 123\n---   dddddd /= 123\n---   gg <=> ee\n--- <\n--- Key sequences:\n--- - `=`\n--- - `=jc`\n--- - `=jr`\n--- - `=m!<CR>`\n--- - `=p`\n--- - `=i` (execute `:lua vim.o.commentstring = '# %s'` for full experience)\n--- - `=<BS>`\n--- - `=<BS>p`\n--- - `=fn==1<CR>`\n--- - `=<BS>fn==1<CR>t`\n--- - `=frow>7<CR>`\n---@tag MiniAlign-examples\n\n---@alias __align_with_preview boolean|nil Whether to align with live preview.\n\n-- Module definition ==========================================================\nlocal MiniAlign = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniAlign.config|.\n---\n---@usage >lua\n---   require('mini.align').setup() -- use default config\n---   -- OR\n---   require('mini.align').setup({}) -- replace {} with your config table\n--- <\nMiniAlign.setup = function(config)\n  -- Export module\n  _G.MiniAlign = MiniAlign\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Modifiers ~\n---\n--- `MiniAlign.config.modifiers` is used to define interactive user experience\n--- of managing alignment process. It is a table with single character keys and\n--- modifier function values.\n---\n--- Each modifier function:\n--- - Is called when corresponding modifier key is pressed.\n--- - Has signature `(steps, opts)` and should modify any of its input in place.\n---\n--- Examples:\n--- - Modifier function used for default 'i' modifier: >lua\n---\n---   function(steps, _)\n---     table.insert(steps.pre_split, MiniAlign.gen_step.ignore_split())\n---   end\n--- <\n--- - Tweak 't' modifier to use highest indentation instead of keeping it: >lua\n---\n---   require('mini.align').setup({\n---     modifiers = {\n---       t = function(steps, _)\n---         local trim_high = MiniAlign.gen_step.trim('both', 'high')\n---         table.insert(steps.pre_justify, trim_high)\n---       end\n---     }\n---   })\n--- <\n--- - Tweak `j` modifier to cycle through available \"justify_side\" option\n---   values (like in 'junegunn/vim-easy-align'): >lua\n---\n---   require('mini.align').setup({\n---     modifiers = {\n---       j = function(_, opts)\n---         local next_option = ({\n---           left = 'center', center = 'right', right = 'none', none = 'left',\n---         })[opts.justify_side]\n---         opts.justify_side = next_option or 'left'\n---       end,\n---     },\n---   })\n--- <\n--- # Options ~\n---\n--- `MiniAlign.config.options` defines default values of options used to control\n--- behavior of steps.\n---\n--- Examples:\n--- - Set `justify_side = 'center'` to center align at initialization.\n---\n--- For more details about options see |MiniAlign.align_strings()| and entries of\n--- |MiniAlign.gen_step| for default main steps.\n---\n--- # Steps ~\n---\n--- `MiniAlign.config.steps` defines default steps to be applied during\n--- alignment process.\n---\n--- Examples:\n--- - Align by default only first pair of columns: >lua\n---\n---   local align = require('mini.align')\n---   align.setup({\n---     steps = {\n---       pre_justify = { align.gen_step.filter('n == 1') }\n---     },\n---   })\n--- <\nMiniAlign.config = {\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    start = 'ga',\n    start_with_preview = 'gA',\n  },\n\n  -- Modifiers changing alignment steps and/or options\n  modifiers = {\n    -- Main option modifiers\n    --minidoc_replace_start ['s'] = --<function: enter split pattern>,\n    ['s'] = function(_, opts)\n      local input = H.user_input('Enter split Lua pattern')\n      if input == nil then return end\n      opts.split_pattern = input\n    end,\n    --minidoc_replace_end\n    --minidoc_replace_start ['j'] = --<function: choose justify side>,\n    ['j'] = function(_, opts)\n      -- stylua: ignore\n      H.echo({\n        { 'Select justify: ', 'ModeMsg' }, { 'l', 'Question' }, { 'eft, ' },\n        { 'c', 'Question' }, { 'enter, ' }, { 'r', 'Question' }, { 'ight, ' },\n        { 'n', 'Question' }, { 'one' }\n      })\n      local ok, char = pcall(vim.fn.getcharstr)\n      if not ok or char == '\\27' then return end\n\n      local direction = ({ l = 'left', c = 'center', r = 'right', n = 'none' })[char]\n      if direction == nil then return end\n      opts.justify_side = direction\n    end,\n    --minidoc_replace_end\n    --minidoc_replace_start ['m'] = --<function: enter merge delimiter>,\n    ['m'] = function(_, opts)\n      local input = H.user_input('Enter merge delimiter')\n      if input == nil then return end\n      opts.merge_delimiter = input\n    end,\n    --minidoc_replace_end\n\n    -- Modifiers adding pre-steps\n    --minidoc_replace_start ['f'] = --<function: filter parts by entering Lua expression>,\n    ['f'] = function(steps, _)\n      local input = H.user_input('Enter filter expression')\n      local step = MiniAlign.gen_step.filter(input)\n      if step == nil then return end\n      table.insert(steps.pre_justify, step)\n    end,\n    --minidoc_replace_end\n    --minidoc_replace_start ['i'] = --<function: ignore some split matches>,\n    ['i'] = function(steps, _) table.insert(steps.pre_split, MiniAlign.gen_step.ignore_split()) end,\n    --minidoc_replace_end\n    --minidoc_replace_start ['p'] = --<function: pair parts>,\n    ['p'] = function(steps, _) table.insert(steps.pre_justify, MiniAlign.gen_step.pair()) end,\n    --minidoc_replace_end\n    --minidoc_replace_start ['t'] = --<function: trim parts>,\n    ['t'] = function(steps, _) table.insert(steps.pre_justify, MiniAlign.gen_step.trim()) end,\n    --minidoc_replace_end\n\n    -- Delete some last pre-step\n    --minidoc_replace_start ['<BS>'] = --<function: delete some last pre-step>,\n    [vim.api.nvim_replace_termcodes('<BS>', true, true, true)] = function(steps, _)\n      local has_pre = {}\n      for _, pre in ipairs({ 'pre_split', 'pre_justify', 'pre_merge' }) do\n        if #steps[pre] > 0 then table.insert(has_pre, pre) end\n      end\n\n      if #has_pre == 0 then return end\n\n      if #has_pre == 1 then\n        local pre = steps[has_pre[1]]\n        table.remove(pre, #pre)\n        return\n      end\n\n      --stylua: ignore\n      H.echo({\n        { 'Select pre-step to remove: ', 'ModeMsg' }, { 's', 'Question' }, { 'plit, ' },\n        { 'j', 'Question' }, { 'ustify, ' }, { 'm', 'Question' }, { 'erge' },\n      })\n      local ok, char = pcall(vim.fn.getcharstr)\n      if not ok or char == '\\27' then return end\n\n      if char == 's' then table.remove(steps.pre_split, #steps.pre_split) end\n      if char == 'j' then table.remove(steps.pre_justify, #steps.pre_justify) end\n      if char == 'm' then table.remove(steps.pre_merge, #steps.pre_merge) end\n    end,\n    --minidoc_replace_end\n\n    -- Special configurations for common splits\n    --minidoc_replace_start ['='] = --<function: enhanced setup for '='>,\n    ['='] = function(steps, opts)\n      opts.split_pattern = '%p*=+[<>~]*'\n      table.insert(steps.pre_justify, MiniAlign.gen_step.trim())\n      opts.merge_delimiter = ' '\n    end,\n    --minidoc_replace_end\n    --minidoc_replace_start [','] = --<function: enhanced setup for ','>,\n    [','] = function(steps, opts)\n      opts.split_pattern = ','\n      table.insert(steps.pre_justify, MiniAlign.gen_step.trim())\n      table.insert(steps.pre_justify, MiniAlign.gen_step.pair())\n      opts.merge_delimiter = ' '\n    end,\n    --minidoc_replace_end\n    --minidoc_replace_start ['|'] = --<function: enhanced setup for '|'>,\n    ['|'] = function(steps, opts)\n      opts.split_pattern = '|'\n      table.insert(steps.pre_justify, MiniAlign.gen_step.trim())\n      opts.merge_delimiter = ' '\n    end,\n    --minidoc_replace_end\n    --minidoc_replace_start [' '] = --<function: enhanced setup for ' '>,\n    [' '] = function(steps, opts)\n      table.insert(\n        steps.pre_split,\n        MiniAlign.new_step('squash', function(strings)\n          -- Replace all space sequences with single space (except indent)\n          for i, s in ipairs(strings) do\n            strings[i] = s:gsub('()(%s+)', function(n, space) return n == 1 and space or ' ' end)\n          end\n        end)\n      )\n      -- Don't use `' '` to respect indent\n      opts.split_pattern = '%s+'\n    end,\n    --minidoc_replace_end\n  },\n\n  -- Default options controlling alignment process\n  options = {\n    split_pattern = '',\n    justify_side = 'left',\n    merge_delimiter = '',\n  },\n\n  -- Default steps performing alignment (if `nil`, default is used)\n  steps = {\n    pre_split = {},\n    split = nil,\n    pre_justify = {},\n    justify = nil,\n    pre_merge = {},\n    merge = nil,\n  },\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Align strings\n---\n--- For details about alignment process see |MiniAlign-algorithm|.\n---\n---@param strings table Array of strings.\n---@param opts table|nil Options. Its copy will be passed to steps as second\n---   argument. Extended with `MiniAlign.config.options`.\n---   This is a place to control default main steps:\n---   - `opts.split_pattern` - Lua pattern(s) used to make split parts.\n---   - `opts.split_exclude_patterns` - which split matches should be ignored.\n---   - `opts.justify_side` - which direction(s) alignment should be done.\n---   - `opts.justify_offsets` - offsets tweaking width of first column\n---   - `opts.merge_delimiter` - which delimiter(s) to use when merging.\n---   For more information see |MiniAlign.gen_step| entry for corresponding\n---   default step.\n---@param steps table|nil Steps. Extended with `MiniAlign.config.steps`.\n---   Possible `nil` values are replaced with corresponding default steps:\n---   - `split` - |MiniAlign.gen_step.default_split()|.\n---   - `justify` - |MiniAlign.gen_step.default_justify()|.\n---   - `merge` - |MiniAlign.gen_step.default_merge()|.\nMiniAlign.align_strings = function(strings, opts, steps)\n  -- Validate arguments\n  if not H.is_array_of(strings, H.is_string) then\n    H.error('First argument of `MiniAlign.align_strings()` should be array of strings.')\n  end\n  opts = H.normalize_opts(opts)\n  steps = H.normalize_steps(steps, 'steps')\n\n  -- Make a copy so that modification in place doesn't affect input\n  strings = vim.deepcopy(strings)\n\n  -- Pre split\n  for _, step in ipairs(steps.pre_split) do\n    H.apply_step(step, strings, opts, 'pre_split')\n  end\n\n  -- Split\n  local parts = H.apply_step(steps.split, strings, opts, 'split')\n  if not H.is_parts(parts) then\n    if H.can_be_parts(parts) then\n      parts = MiniAlign.as_parts(parts)\n    else\n      H.error('Output of `split` step should be convertible to parts. See `:h MiniAlign.as_parts()`.')\n    end\n  end\n\n  -- Pre justify\n  for _, step in ipairs(steps.pre_justify) do\n    H.apply_step(step, parts, opts, 'pre_justify')\n  end\n\n  -- Justify\n  H.apply_step(steps.justify, parts, opts, 'justify')\n\n  -- Pre merge\n  for _, step in ipairs(steps.pre_merge) do\n    H.apply_step(step, parts, opts, 'pre_merge')\n  end\n\n  -- Merge\n  local new_strings = H.apply_step(steps.merge, parts, opts, 'merge')\n  if not H.is_array_of(new_strings, H.is_string) then H.error('Output of `merge` step should be array of strings.') end\n  return new_strings\nend\n\n--- Align current region with user-supplied steps\n---\n--- Mostly designed to be used inside mappings.\n---\n--- Will use |MiniAlign.align_strings()| and set the following options in `opts`:\n--- - `justify_offsets` - array of offsets used to achieve actual alignment of\n---   a region. It is non-trivial (not array of zeros) only for charwise\n---   selection: offset of first string is computed as width of prefix to the\n---   left of region start.\n--- - `region` - current affected region (see |MiniAlign-glossary|). Can be\n---   used to create more advanced steps.\n--- - `mode` - mode of selection (see |MiniAlign-glossary|).\n---\n---@param mode string Selection mode. One of \"char\", \"line\", \"block\".\nMiniAlign.align_user = function(mode)\n  local modifiers = H.get_config().modifiers\n  local with_preview = H.cache.with_preview\n  local opts = H.cache.opts or H.normalize_opts()\n  local steps = H.cache.steps or H.normalize_steps()\n\n  local steps_are_from_cache = H.cache.steps ~= nil\n  H.cache.region = nil\n\n  -- Track if lines were actually changed to properly undo during preview\n  local lines_were_changed = false\n\n  -- Make initial process\n  lines_were_changed = H.process_current_region(lines_were_changed, mode, opts, steps)\n\n  -- Make early return:\n  -- - If cache is present (enables dot-repeat).\n  -- - If `split` is not default with no preview (no more information needed).\n  if steps_are_from_cache or (not with_preview and opts.split_pattern ~= '') then return end\n\n  -- Ask user to input modifier id until no more is needed\n  local n_iter = 0\n  while true do\n    -- Get modifier from user\n    local id = H.user_modifier(with_preview, H.make_status_msg_chunks(opts, steps))\n    n_iter = n_iter + 1\n\n    -- Stop in case user supplied inappropriate modifier id (abort)\n    -- Also stop in case of too many iterations (guard from infinite cycle)\n    if id == nil or n_iter > 1000 then\n      if lines_were_changed then H.undo() end\n      if n_iter > 1000 then H.echo({ { 'Too many modifiers typed.', 'WarningMsg' } }, true) end\n      break\n    end\n\n    -- Stop preview after `<CR>` (confirmation)\n    if with_preview and id == '\\r' then break end\n\n    -- Apply modifier\n    local mod = modifiers[id]\n    if mod == nil then\n      -- Use supplied identifier as split pattern\n      opts.split_pattern = vim.pesc(id)\n    else\n      -- Modifier should change input `steps` table in place\n      local ok, out = pcall(mod, steps, opts)\n      if not ok then\n        -- Force message to appear for 500ms because it might be overridden by\n        -- helper status message\n        local msg = string.format('Modifier %s should be properly callable. Reason: %s', vim.inspect(id), out)\n        H.echo({ { msg, 'WarningMsg' } }, true)\n        vim.cmd('redraw')\n        vim.loop.sleep(500)\n      end\n    end\n\n    -- Normalize steps and options while validating their correctness\n    opts = H.normalize_opts(opts)\n    steps = H.normalize_steps(steps, opts)\n\n    -- Process region while tracking if lines were set at least once\n    local lines_now_changed = H.process_current_region(lines_were_changed, mode, opts, steps)\n    lines_were_changed = lines_were_changed or lines_now_changed\n\n    -- Stop in \"no preview\" mode right after `split` is defined\n    if not with_preview and opts.split_pattern ~= '' then break end\n  end\n\n  -- Remove helper status message (if shown)\n  H.unecho()\nend\n\n--- Convert 2d array of strings to parts\n---\n--- This function verifies if input is a proper 2d array of strings and adds\n--- methods to its copy.\n---\n---@class parts\n---\n---@field apply function Takes callable `f` and applies it to every part.\n---   Callable should have signature `(s, data)`: `s` is a string part,\n---   `data` - table with its data (<row> has row number, <col> has column number).\n---   Returns new 2d array.\n---\n---@field apply_inplace function Takes callable `f` and applies it to every part.\n---   Should have same signature as in `apply` method. Outputs (should all be\n---   strings) are assigned in place to a corresponding parts element. Returns\n---   parts itself to enable method chaining.\n---\n---@field get_dims function Return dimensions of parts array: a table with\n---   <row> and <col> keys having number of rows and number of columns (maximum\n---   number of elements across all rows).\n---\n---@field group function Concatenate neighboring strings based on supplied\n---   boolean mask and direction (one of \"left\", default, or \"right\"). Has\n---   signature `(mask, direction)` and modifies parts in place. Returns parts\n---   itself to enable method chaining.\n---   Example:\n---   - Parts: `{ { \"a\", \"b\", \"c\" }, { \"d\", \"e\" }, { \"f\" } }`\n---   - Mask: `{ { false, false, true }, { true, false }, { false } }`\n---   - Result for direction \"left\":  `{ { \"abc\" },    { \"d\", \"e\" }, { \"f\" } }`\n---   - Result for direction \"right\": `{ { \"ab\",\"c\" }, { \"de\" },     { \"f\" } }`\n---\n---@field pair function Concatenate neighboring element pairs. Takes\n---   `direction` as input (one of \"left\", default, or \"right\") and applies\n---   `group()` for an alternating mask.\n---   Example:\n---   - Parts: `{ { \"a\", \"b\", \"c\" }, { \"d\", \"e\" }, { \"f\" } }`\n---   - Result for direction \"left\":  `{ { \"ab\", \"c\" }, { \"de\" }, { \"f\" } }`\n---   - Result for direction \"right\": `{ { \"a\", \"bc\" }, { \"de\" }, { \"f\" } }`\n---\n---@field slice_col function Return column with input index `j`. Note: it might\n---   not be an array if rows have unequal number of columns.\n---\n---@field slice_row function Return row with input index `i`.\n---\n---@field trim function Trim elements whitespace. Has signature `(direction, indent)`\n---   and modifies parts in place. Returns parts itself to enable method chaining.\n---   - Possible values of `direction`: \"both\" (default), \"left\", \"right\",\n---   \"none\". Defines from which side whitespaces should be removed.\n---   - Possible values of `indent`: \"keep\" (default), \"low\", \"high\", \"remove\".\n---   Defines what to do with possible indent (left whitespace of first string\n---   in a row). Value \"keep\" keeps it; \"low\" makes all indent equal to the\n---   lowest across rows; \"high\" - highest across rows; \"remove\" - removes indent.\n---\n---@usage >lua\n---   parts = MiniAlign.as_parts({ { 'a', 'b' }, { 'c' } })\n---   print(vim.inspect(parts.get_dims())) -- Should be { row = 2, col = 2 }\n---\n---   parts.apply_inplace(function(s, data)\n---     return ' ' .. data.row .. s .. data.col .. ' '\n---   end)\n---   print(vim.inspect(parts)) -- Should be { { ' 1a1 ', ' 1b2 ' }, { ' 2c1 ' } }\n---\n---   parts.trim('both', 'remove').pair()\n---   print(vim.inspect(parts)) -- Should be { { '1a11b2' }, { '2c1' } }\n--- <\nMiniAlign.as_parts = function(arr2d)\n  local ok, msg = H.can_be_parts(arr2d)\n  if not ok then H.error('Input of `as_parts()` ' .. msg) end\n\n  local parts = vim.deepcopy(arr2d)\n  local methods = {}\n\n  methods.apply = function(f)\n    local res = {}\n    for i, row in ipairs(parts) do\n      res[i] = {}\n      for j, s in ipairs(row) do\n        res[i][j] = f(s, { row = i, col = j })\n      end\n    end\n    return res\n  end\n\n  methods.apply_inplace = function(f)\n    for i, row in ipairs(parts) do\n      for j, s in ipairs(row) do\n        local new_val = f(s, { row = i, col = j })\n        if type(new_val) ~= 'string' then H.error('Input of `apply_inplace()` method should always return string.') end\n        parts[i][j] = new_val\n      end\n    end\n\n    return parts\n  end\n\n  methods.get_dims = function()\n    local n_cols = 0\n    for _, row in ipairs(parts) do\n      n_cols = math.max(n_cols, #row)\n    end\n    return { row = #parts, col = n_cols }\n  end\n\n  -- Group cells into single string based on boolean mask.\n  -- Can be used for filtering separators and sticking separator to its part.\n  methods.group = function(mask, direction)\n    direction = direction or 'left'\n    for i, row in ipairs(parts) do\n      local group_tables = H.group_by_mask(row, mask[i], direction)\n      parts[i] = vim.tbl_map(table.concat, group_tables)\n    end\n    return parts\n  end\n\n  methods.pair = function(direction)\n    direction = direction or 'left'\n\n    local mask = {}\n    for i, row in ipairs(parts) do\n      mask[i] = {}\n      for j, _ in ipairs(row) do\n        -- Count from corresponding end\n        local num = direction == 'left' and j or (#row - j + 1)\n        mask[i][j] = num % 2 == 0\n      end\n    end\n\n    parts.group(mask, direction)\n    return parts\n  end\n\n  -- NOTE: output might not be an array (some rows can not have input column)\n  -- Use `vim.tbl_keys()` and `vim.tbl_values()`\n  methods.slice_col = function(j)\n    return vim.tbl_map(function(row) return row[j] end, parts)\n  end\n\n  methods.slice_row = function(i) return parts[i] or {} end\n\n  methods.trim = function(direction, indent)\n    direction = direction or 'both'\n    indent = indent or 'keep'\n\n    -- Verify arguments\n    local trim_fun = H.trim_functions[direction]\n    if not vim.is_callable(trim_fun) then\n      local allowed = vim.tbl_map(vim.inspect, vim.tbl_keys(H.trim_functions))\n      table.sort(allowed)\n      H.error('`direction` should be one of ' .. table.concat(allowed, ', ') .. '.')\n    end\n\n    local indent_fun = H.indent_functions[indent]\n    if not vim.is_callable(indent_fun) then\n      local allowed = vim.tbl_map(vim.inspect, vim.tbl_keys(H.indent_functions))\n      table.sort(allowed)\n      H.error('`indent` should be one of ' .. table.concat(allowed, ', ') .. '.')\n    end\n\n    -- Compute indentation to restore later\n    local row_indent = vim.tbl_map(function(row) return row[1]:match('^(%s*)') end, parts)\n    row_indent = indent_fun(row_indent)\n\n    -- Trim\n    parts.apply_inplace(trim_fun)\n\n    -- Restore indentation if it was removed\n    if vim.tbl_contains({ 'both', 'left' }, direction) then\n      for i, row in ipairs(parts) do\n        row[1] = string.format('%s%s', row_indent[i], row[1])\n      end\n    end\n\n    return parts\n  end\n\n  return setmetatable(parts, { class = 'parts', __index = methods })\nend\n\n--- Create step\n---\n--- A step is basically a named callable object. Having a name bundled with\n--- some action powers helper status message during interactive alignment process.\n---\n---@param name string Step name.\n---@param action function|table Step action. Should be a callable object\n---   (see |vim.is_callable()|).\n---\n---@return table A table with keys: <name> with `name` argument, <action> with `action`.\nMiniAlign.new_step = function(name, action)\n  if type(name) ~= 'string' then H.error('Step name should be string.') end\n  if not vim.is_callable(action) then H.error('Step action should be callable.') end\n  return { name = name, action = action }\nend\n\n--- Generate common action steps\n---\n--- This is a table with function elements. Call to actually get step.\n---\n--- Each step action is a function that has signature `(object, opts)`, where\n--- `object` is either parts or array of strings (depends on which stage of\n--- alignment process it is assumed to be applied) and `opts` is table of options.\n---\n--- Outputs of elements named `default_*` are used as default corresponding main\n--- step (split, justify, merge). Behavior of all of them depend on values from\n--- supplied options (second argument).\n---\n--- Outputs of other elements depend on both step generator input values and\n--- options supplied at execution. This design is mostly because their output\n--- can be used several times in pre-steps.\n---\n---@usage >lua\n---   local align = require('mini.align')\n---   align.setup({\n---     modifiers = {\n---       -- Use 'T' modifier to remove both whitespace and indent\n---       T = function(steps, _)\n---         table.insert(steps.pre_justify, align.gen_step.trim('both', 'remove'))\n---       end,\n---     },\n---     options = {\n---       -- By default align \"right\", \"left\", \"right\", \"left\", ...\n---       justify_side = { 'right', 'left' },\n---     },\n---     steps = {\n---       -- Align by default only first pair of columns\n---       pre_justify = { align.gen_step.filter('n == 1') },\n---     },\n---   })\n--- <\nMiniAlign.gen_step = {}\n\n--- Generate default split step\n---\n--- Output splits strings using matches of Lua pattern(s) from `split_pattern`\n--- option which are not dismissed by `split_exclude_patterns` option.\n---\n--- Outline of how single string is split:\n--- - Convert `split_pattern` option to array of strings (string is converted\n---   as one-element array). This array will be recycled in case there are more\n---   split matches than in converted `split_pattern` array (which almost always).\n--- - Find all forbidden spans (intervals inside string) - all matches of all\n---   patterns in `split_exclude_patterns`.\n--- - Find match for the next pattern. If it is not inside any forbidden span,\n---   add preceding unmatched substring and matched split as two parts. Repeat\n---   with the next pattern.\n--- - If no pattern match is found, add the rest of string as final part.\n---\n--- Output uses following options (as part second argument, `opts` table):\n--- - <split_pattern> - string or array of strings used to detect split matches\n---   and create parts. Default: `''` meaning no matches (whole string is used\n---   as part). Examples: `'%s+'`, `{ '<', '>' }`.\n--- - <split_exclude_patterns> - array of strings defining which regions to\n---   exclude from being matched. Default: `{}`. Examples: `{ '\".-\"', '^%s*#.*' }`.\n---\n---@return table A step named \"split\" and with appropriate callable action.\n---\n---@seealso |MiniAlign.gen_step.ignore_split()| heavily uses `split_exclude_patterns`.\nMiniAlign.gen_step.default_split = function() return MiniAlign.new_step('split', H.default_action_split) end\n\n--- Generate default justify step\n---\n--- Output makes column elements of string parts have equal width by adding\n--- left and/or right whitespace padding. Which side(s) to pad is defined by\n--- `justify_side` option. Width of first column can be tweaked with `justify_offsets`\n--- option.\n---\n--- Outline of how parts are justified:\n--- - Convert `justify_side` option to array of strings (single string is\n---   converted as one-element array). Recycle this array to have length equal\n---   to number of columns in parts.\n--- - For all columns compute maximum width of strings from it (add offsets from\n---   `justify_offsets` to first column widths). Note: for left alignment, width\n---   of last row element does not affect column width. This is mainly because\n---   it won't be padded and helps dealing with \"no single match\" lines.\n--- - Make all elements have same width inside column by adding appropriate\n---   amount of whitespace. Which side(s) to add is controlled by the corresponding\n---   `justify_side` array element. Note: padding is done with spaces which\n---   might conflict with tab indentation.\n---\n--- Output uses following options (as part second argument, `opts` table):\n--- - <justify_side> - string or array of strings. Each element can be one of\n---   \"left\" (pad right side), \"center\" (pad both sides equally), \"right\" (pad\n---   left side), \"none\" (no padding). Default: \"left\".\n--- - <justify_offsets> - array of numeric left offsets of rows. Used to adjust\n---   for possible not equal indents, like in case of charwise selection when\n---   left edge is not on the first column. Default: array of zeros. Set\n---   automatically during interactive alignment in charwise mode.\n---\n---@return table A step named \"justify\" and with appropriate callable action.\nMiniAlign.gen_step.default_justify = function() return MiniAlign.new_step('justify', H.default_action_justify) end\n\n--- Generate default merge step\n---\n--- Output merges rows of parts into strings by placing merge delimiter(s)\n--- between them.\n---\n--- Outline of how parts are converted to array of strings:\n--- - Convert `merge_delimiter` option to array of strings (single string is\n---   converted as one-element array). Recycle this array to have length equal\n---   to number of columns in parts minus 1. Also possibly trim leading whitespace\n---   in first merge character to not affect indentation.\n--- - Exclude empty strings from parts. They add nothing to output except extra\n---   usage of merge delimiter.\n--- - Concatenate each row interleaving with array of merge delimiters.\n---\n--- Output uses following options (as part second argument, `opts` table):\n--- - <merge_delimiter> - string or array of strings. Default: `''`.\n---   Examples: `' '`, `{ '', ' ' }`.\n---\n---@return table A step named \"merge\" and with appropriate callable action.\nMiniAlign.gen_step.default_merge = function() return MiniAlign.new_step('merge', H.default_action_merge) end\n\n--- Generate filter step\n---\n--- Construct function predicate from supplied Lua string expression and make\n--- step evaluating it on every part element.\n---\n--- Outline of how filtering is done:\n--- - Convert Lua filtering expression into function predicate which can be\n---   evaluated in manually created context (some specific variables being set).\n--- - Compute boolean mask for parts by applying predicate to each element of\n---   2d array with special variables set to specific values (see next section).\n--- - Group parts with computed mask. See `group()` method of parts in\n---   |MiniAlign.as_parts()|.\n---\n--- Special variables which can be used in expression:\n--- - <row> - row number of current element.\n--- - <ROW> - total number of rows in parts.\n--- - <col> - column number of current element.\n--- - <COL> - total number of columns in current row.\n--- - <s>   - string value of current element.\n--- - <n>   - column pair number of current element. Useful when filtering by\n---           result of pattern splitting.\n--- - <N>   - total number of column pairs in current row.\n--- - All variables from global table `_G`.\n---\n--- Tips:\n--- - This general filtering approach can be used to both include and exclude\n---   certain parts from alignment. Examples:\n---     - Use `row ~= 2` to align all parts except from second row.\n---     - Use `n == 1` to align only by first pair of columns.\n--- - Filtering by last equal sign usually can be done with `n >= (N - 1)`\n---   (because there is usually something to the right of it).\n---\n---@param expr string Lua expression as a string which will be used as predicate.\n---\n---@return table|nil A step named \"filter\" and with appropriate callable action.\nMiniAlign.gen_step.filter = function(expr)\n  local action = H.make_filter_action(expr)\n  if action == nil then return end\n  return MiniAlign.new_step('filter', action)\nend\n\n--- Generate ignore step\n---\n--- Output adds certain values to `split_exclude_patterns` option. Should be\n--- used as pre-split step.\n---\n---@param patterns table Array of patterns to be added to\n---   `split_exclude_patterns` as is. Default: `{ [[\".-\"]] }` (excludes strings\n---   for most cases).\n---@param exclude_comment boolean|nil Whether to add comment pattern to\n---   `split_exclude_patterns`. Comment pattern is derived from 'commentstring'\n---   option. Default: `true`.\n---\n---@return table A step named \"ignore\" and with appropriate callable action.\n---\n---@seealso |MiniAlign.gen_step.default_split()| for details about\n---   `split_exclude_patterns` option.\nMiniAlign.gen_step.ignore_split = function(patterns, exclude_comment)\n  patterns = patterns or { '\".-\"' }\n  if exclude_comment == nil then exclude_comment = true end\n\n  -- Validate ingput\n  if not H.is_array_of(patterns, H.is_string) then\n    H.error('Argument `patterns` of `ignore_split()` should be array of strings.')\n  end\n  if type(exclude_comment) ~= 'boolean' then\n    H.error('Argument `exclude_comment` of `ignore_split()` should be boolean.')\n  end\n\n  -- Make action which modifies `opts.split_exclude_patterns`\n  local action = function(_, opts)\n    local excl = opts.split_exclude_patterns or {}\n\n    -- Add supplied patterns while avoiding duplication\n    for _, patt in ipairs(patterns) do\n      if not vim.tbl_contains(excl, patt) then table.insert(excl, patt) end\n    end\n\n    -- Possibly add current comment pattern while avoiding duplication\n    if exclude_comment then\n      -- In 'commentstring', `%s` denotes the comment content\n      local comment_pattern = vim.pesc(vim.o.commentstring):gsub('%%%%s', '.-')\n      -- Ignore to the end of the string if 'commentstring' is like \"xxx%s\"\n      comment_pattern = comment_pattern:gsub('%.%-%s*$', '.*')\n      if not vim.tbl_contains(excl, comment_pattern) then table.insert(excl, comment_pattern) end\n    end\n\n    opts.split_exclude_patterns = excl\n  end\n\n  return MiniAlign.new_step('ignore', action)\nend\n\n--- Generate pair step\n---\n--- Output calls `pair()` method of parts (see |MiniAlign.as_parts()|) with\n--- supplied `direction` argument.\n---\n---@param direction string Which direction to pair. One of \"left\" (default) or\n---\"right\".\n---\n---@return table A step named \"pair\" and with appropriate callable action.\nMiniAlign.gen_step.pair = function(direction)\n  return MiniAlign.new_step('pair', function(parts, _) parts.pair(direction) end)\nend\n\n--- Generate trim step\n---\n--- Output calls `trim()` method of parts (see |MiniAlign.as_parts()|) with\n--- supplied `direction` and `indent` arguments.\n---\n---@param direction string|nil Which sides to trim whitespace. One of \"both\"\n---   (default), \"left\", \"right\", \"none\".\n---@param indent string|nil What to do with possible indent (left whitespace\n---   of first string in a row). One of \"keep\" (default), \"low\", \"high\", \"remove\".\n---\n---@return table A step named \"trim\" and with appropriate callable action.\nMiniAlign.gen_step.trim = function(direction, indent)\n  return MiniAlign.new_step('trim', function(parts, _) parts.trim(direction, indent) end)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniAlign.config)\n\n-- Cache for various operations\nH.cache = {}\n\n-- Module's namespaces\nH.ns_id = {\n  -- Track user input\n  input = vim.api.nvim_create_namespace('MiniAlignInput'),\n}\n\n-- Pad functions for supported justify directions\n-- Allow to not add trailing whitespace\nH.pad_functions = {\n  left = function(x, n_spaces, no_trailing)\n    if no_trailing or H.is_infinite(n_spaces) then return x end\n    return string.format('%s%s', x, string.rep(' ', n_spaces))\n  end,\n  center = function(x, n_spaces, no_trailing)\n    local n_left = math.floor(0.5 * n_spaces)\n    return H.pad_functions.right(H.pad_functions.left(x, n_left, no_trailing), n_spaces - n_left, no_trailing)\n  end,\n  right = function(x, n_spaces, no_trailing)\n    if (no_trailing and H.is_whitespace(x)) or H.is_infinite(n_spaces) then return x end\n    return string.format('%s%s', string.rep(' ', n_spaces), x)\n  end,\n  none = function(x, _, _) return x end,\n}\n\n-- Trim functions\nH.trim_functions = {\n  both = function(x) return H.trim_functions.left(H.trim_functions.right(x)) end,\n  left = function(x) return string.gsub(x, '^%s*', '') end,\n  right = function(x) return string.gsub(x, '%s*$', '') end,\n  none = function(x) return x end,\n}\n\n-- Indentation functions\nH.indent_functions = {\n  keep = function(indent_arr) return indent_arr end,\n  high = function(indent_arr)\n    local max_indent = indent_arr[1]\n    for i = 2, #indent_arr do\n      max_indent = (max_indent:len() < indent_arr[i]:len()) and indent_arr[i] or max_indent\n    end\n    return vim.tbl_map(function() return max_indent end, indent_arr)\n  end,\n  low = function(indent_arr)\n    local min_indent = indent_arr[1]\n    for i = 2, #indent_arr do\n      min_indent = (indent_arr[i]:len() < min_indent:len()) and indent_arr[i] or min_indent\n    end\n    return vim.tbl_map(function() return min_indent end, indent_arr)\n  end,\n  remove = function(indent_arr)\n    return vim.tbl_map(function() return '' end, indent_arr)\n  end,\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.start', config.mappings.start, 'string')\n  H.check_type('mappings.start_with_preview', config.mappings.start_with_preview, 'string')\n\n  H.check_type('modifiers', config.modifiers, 'table')\n  for k, v in pairs(config.modifiers) do\n    if not vim.is_callable(v) then H.error(string.format('`modifiers[%s]` should be callable.', vim.inspect(k))) end\n  end\n\n  H.validate_steps(config.steps, 'steps')\n  H.check_type('options', config.options, 'table')\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniAlign.config = config\n\n  --stylua: ignore start\n  H.map('n', config.mappings.start, H.make_action_normal(false), { expr = true, desc = 'Align' })\n  H.map('x', config.mappings.start, H.make_action_visual(false), { desc = 'Align' })\n\n  H.map('n', config.mappings.start_with_preview, H.make_action_normal(true), { expr = true, desc = 'Align with preview' })\n  H.map('x', config.mappings.start_with_preview, H.make_action_visual(true), { desc = 'Align with preview' })\n  --stylua: ignore end\nend\n\nH.is_disabled = function() return vim.g.minialign_disable == true or vim.b.minialign_disable == true end\n\nH.get_config = function()\n  -- Using `tbl_deep_extend()` works even in presense of `steps.pre_*` arrays\n  -- because default ones are empty.\n  return vim.tbl_deep_extend('force', MiniAlign.config, vim.b.minialign_config or {})\nend\n\n-- Mappings -------------------------------------------------------------------\nH.make_action_normal = function(with_preview)\n  return function()\n    if H.is_disabled() then return end\n\n    H.cache = { with_preview = with_preview }\n\n    -- Set 'operatorfunc' which will be later called with appropriate marks set\n    vim.o.operatorfunc = 'v:lua.MiniAlign.align_user'\n    return 'g@'\n  end\nend\n\nH.make_action_visual = function(with_preview)\n  return function()\n    if H.is_disabled() then return end\n\n    H.cache = { with_preview = with_preview }\n\n    -- Perform action and exit Visual mode\n    local mode = ({ ['v'] = 'char', ['V'] = 'line', ['\\22'] = 'block' })[vim.fn.mode(1)]\n    MiniAlign.align_user(mode)\n    vim.cmd('normal! \\27')\n  end\nend\n\n-- Work with steps and options ------------------------------------------------\nH.is_valid_steps = function(x, x_name)\n  x_name = x_name or 'config.steps'\n\n  if type(x) ~= 'table' then return false, string.format('`%s` should be table.', x_name) end\n\n  -- Validators\n  local is_steps_array = function(y) return H.is_array_of(y, H.is_step) end\n  local steps_array_msg = 'should be array of steps (see `:h MiniAlign.new_step()`).'\n\n  local is_maybe_step = function(y) return y == nil or H.is_step(y) end\n  local step_msg = 'should be step (see `:h MiniAlign.new_step()`).'\n\n  -- Actual checks\n  if not is_steps_array(x.pre_split) then return false, H.msg_bad_steps(x_name, 'pre_split', steps_array_msg) end\n\n  if not is_maybe_step(x.split) then return false, H.msg_bad_steps(x_name, 'split', step_msg) end\n\n  if not is_steps_array(x.pre_justify) then return false, H.msg_bad_steps(x_name, 'pre_justify', steps_array_msg) end\n\n  if not is_maybe_step(x.justify) then return false, H.msg_bad_steps(x_name, 'justify', step_msg) end\n\n  if not is_steps_array(x.pre_merge) then return false, H.msg_bad_steps(x_name, 'pre_merge', steps_array_msg) end\n\n  if not is_maybe_step(x.merge) then return false, H.msg_bad_steps(x_name, 'merge', step_msg) end\n\n  return true\nend\n\nH.validate_steps = function(x, x_name)\n  local is_valid, msg = H.is_valid_steps(x, x_name)\n  if not is_valid then H.error(msg) end\nend\n\nH.normalize_steps = function(steps, steps_name)\n  -- Infer all defaults from module config\n  -- NOTE: Don't use `tbl_deep_extend` to prefer full input arrays (if present)\n  local res = vim.tbl_extend('force', H.get_config().steps, steps or {})\n\n  H.validate_steps(res, steps_name)\n\n  -- Possibly fill in default main steps\n  res.split = res.split or MiniAlign.gen_step.default_split()\n  res.justify = res.justify or MiniAlign.gen_step.default_justify()\n  res.merge = res.merge or MiniAlign.gen_step.default_merge()\n\n  -- Deep copy to ensure that table values will not be affected (because if a\n  -- table value is present only in one input, it is taken as is).\n  return vim.deepcopy(res)\nend\n\nH.normalize_opts = function(opts)\n  local res = vim.tbl_deep_extend('force', H.get_config().options, opts or {})\n  return vim.deepcopy(res)\nend\n\nH.msg_bad_steps = function(steps_name, key, msg) return string.format('`%s.%s` %s', steps_name, key, msg) end\n\nH.apply_step = function(step, arr, opts, step_container_name)\n  local arr_name, predicate, suggest = 'parts', H.is_parts, ' See `:h MiniAlign.as_parts()`.'\n  if not H.is_parts(arr) then\n    arr_name = 'strings'\n    predicate = function(x) return H.is_array_of(x, H.is_string) end\n    suggest = ''\n  end\n\n  local res = step.action(arr, opts)\n\n  if not predicate(arr) then\n    --stylua: ignore\n    local msg = string.format(\n      'Step `%s` of `%s` should preserve structure of `%s`.%s',\n      step.name, step_container_name, arr_name, suggest\n    )\n    H.error(msg)\n  end\n\n  return res\nend\n\n-- Work with default actions --------------------------------------------------\nH.default_action_split = function(string_array, opts)\n  -- Prepare options\n  local pattern = opts.split_pattern\n  if not (H.is_string(pattern) or H.is_array_of(pattern, H.is_string)) then\n    H.error('Option `split_pattern` should be string or array of strings.')\n  end\n  if type(pattern) == 'string' then pattern = { pattern } end\n\n  local exclude_patterns = opts.split_exclude_patterns or {}\n  if not H.is_array_of(exclude_patterns, H.is_string) then\n    H.error('Option `split_exclude_patterns` should be array of strings.')\n  end\n\n  local capture_exclude_regions = vim.tbl_map(function(x)\n    local patt = x\n    patt = x:sub(1, 1) == '^' and ('^()' .. patt:sub(2)) or ('()' .. patt)\n    patt = x:sub(-1, -1) == '$' and (patt:sub(1, -2) .. '()$') or (patt .. '()')\n    return patt\n  end, exclude_patterns)\n\n  local forbidden_spans = {}\n  local add_to_forbidden = function(l, r) table.insert(forbidden_spans, { l, r - 1 }) end\n  local make_forbidden_spans = function(s)\n    forbidden_spans = {}\n    for _, capture_pat in ipairs(capture_exclude_regions) do\n      s:gsub(capture_pat, add_to_forbidden)\n    end\n    return forbidden_spans\n  end\n\n  -- Make splits excluding matches inside forbidden regions\n  local res = vim.tbl_map(\n    function(s) return H.default_action_split_string(s, pattern, make_forbidden_spans) end,\n    string_array\n  )\n  return MiniAlign.as_parts(res)\nend\n\nH.default_action_split_string = function(s, pattern_arr, make_forbidden_spans)\n  -- Construct forbidden spans for string\n  local forbidden_spans = make_forbidden_spans(s)\n\n  -- Split by recycled `pattern_arr`\n  local res = {}\n  local n_total, n_latest_add, n_find = s:len(), 0, 0\n  local n_pair = 1\n\n  while true do\n    local cur_split = H.slice_mod(pattern_arr, n_pair)\n    local sep_left, sep_right = H.string_find(s, cur_split, n_find)\n\n    if sep_left == nil then\n      -- Avoid adding empty string to non-empty input because it does nothing\n      -- but confuses \"don't add trailspace\" logic\n      local rest = s:sub(n_latest_add, n_total)\n      if not (rest == '' and #res > 0) then table.insert(res, rest) end\n      break\n    end\n\n    local is_good = #forbidden_spans == 0\n      or not H.is_any_point_inside_any_span({ sep_left, sep_right }, forbidden_spans)\n    if is_good then\n      table.insert(res, s:sub(n_latest_add, sep_left - 1))\n      table.insert(res, s:sub(sep_left, sep_right))\n      n_latest_add = sep_right + 1\n      n_pair = n_pair + 1\n    end\n\n    if (sep_right + 1) <= n_find then\n      H.error(string.format('Pattern %s can not advance search.', vim.inspect(cur_split)))\n    end\n    n_find = sep_right + 1\n  end\n\n  return res\nend\n\nH.default_action_justify = function(parts, opts)\n  -- Prepare options\n  local side = opts.justify_side\n  if not (H.is_justify_side(side) or H.is_array_of(side, H.is_justify_side)) then\n    H.error([[Option `justify_side` should be one of 'left', 'center', 'right', 'none', or array of those.]])\n  end\n  if type(side) == 'string' then side = { side } end\n\n  local offsets = opts.justify_offsets or H.tbl_repeat(0, #parts)\n\n  -- Recycle `justify` array and precompute padding functions\n  local dims = parts.get_dims()\n  local pad_funs, side_arr = {}, {}\n  for j = 1, dims.col do\n    local s = H.slice_mod(side, j)\n    side_arr[j] = s\n    pad_funs[j] = H.pad_functions[s]\n  end\n\n  -- Compute cell width and maximum column widths (adjusting for offsets)\n  local width_col = {}\n  for j = 1, dims.col do\n    width_col[j] = 0\n  end\n\n  local width = {}\n  for i, row in ipairs(parts) do\n    width[i] = {}\n    for j, s in ipairs(row) do\n      local w = vim.fn.strdisplaywidth(s)\n      width[i][j] = w\n\n      -- Compute offset\n      local off = j == 1 and offsets[i] or 0\n\n      -- Don't use last column in row to compute column width in case of left\n      -- justification (it won't be padded so shouldn't contribute to column)\n      if not (j == #row and side_arr[j] == 'left') then width_col[j] = math.max(off + w, width_col[j]) end\n    end\n  end\n\n  -- Pad cells to have same width across columns (adjusting for offsets)\n  for i, row in ipairs(parts) do\n    for j, s in ipairs(row) do\n      local off = j == 1 and offsets[i] or 0\n      local n_space = width_col[j] - width[i][j] - off\n      -- Don't add trailing whitespace for last column\n      parts[i][j] = pad_funs[j](s, n_space, j == #row)\n    end\n  end\nend\n\nH.default_action_merge = function(parts, opts)\n  -- Prepare options\n  local delimiter = opts.merge_delimiter\n  if not (H.is_string(delimiter) or H.is_array_of(delimiter, H.is_string)) then\n    H.error('Option `merge_delimiter` should be string or array of strings.')\n  end\n  if type(delimiter) == 'string' then delimiter = { delimiter } end\n\n  -- Precompute combination strings (recycle `merge` array)\n  local dims = parts.get_dims()\n  local delim_arr = {}\n  for j = 1, dims.col - 1 do\n    delim_arr[j] = H.slice_mod(delimiter, j)\n  end\n\n  -- Do not change indentation\n  local first_parts_are_indent = true\n  for i = 1, dims.row do\n    first_parts_are_indent = first_parts_are_indent and H.is_whitespace(parts[i][1])\n  end\n  delim_arr[1] = (first_parts_are_indent and delim_arr[1] ~= nil) and delim_arr[1]:gsub('^%s*', '') or delim_arr[1]\n\n  return vim.tbl_map(function(row) return H.concat_array(row, delim_arr) end, parts)\nend\n\n-- Work with modifiers --------------------------------------------------------\nH.make_filter_action = function(expr)\n  if expr == nil then return nil end\n  if expr == '' then expr = 'true' end\n\n  local is_loaded, f = pcall(function() return assert(loadstring('return ' .. expr)) end)\n  if not (is_loaded and vim.is_callable(f)) then H.error(vim.inspect(expr) .. ' is not a valid filter expression.') end\n\n  local predicate = function(data)\n    local context = setmetatable(data, { __index = _G })\n    debug.setfenv(f, context)\n    return f()\n  end\n\n  return function(parts, _)\n    local mask = {}\n    local data = { ROW = #parts }\n    for i, row in ipairs(parts) do\n      data.row = i\n      mask[i] = {}\n      for j, s in ipairs(row) do\n        data.col, data.COL = j, #row\n        data.s = s\n\n        -- Current and total number of pairs\n        data.n = math.ceil(0.5 * j)\n        data.N = math.ceil(0.5 * #row)\n\n        mask[i][j] = predicate(data)\n      end\n    end\n\n    parts.group(mask)\n  end\nend\n\n-- Work with regions ----------------------------------------------------------\n---@return boolean Whether some lines were actually set.\n---@private\nH.process_current_region = function(lines_were_changed, mode, opts, steps)\n  -- Cache current options and steps for dot-repeat\n  H.cache.opts, H.cache.steps = opts, steps\n\n  -- Undo previously set lines\n  if lines_were_changed then H.undo() end\n\n  -- Get current region. NOTE: use cached value to ensure that the same region\n  -- is processed during preview. Otherwise there might be problems with\n  -- getting \"current\" regions in Normal mode as necessary marks (`[` and `]`)\n  -- can be not valid.\n  local region = H.cache.region or H.get_current_region()\n  H.cache.region = region\n\n  -- Enrich options\n  opts.region = region\n  opts.mode = mode\n  opts.justify_offsets = H.tbl_repeat(0, region.to.line - region.from.line + 1)\n  if mode == 'char' then\n    -- Compute offset of first line for charwise selection\n    local prefix = vim.fn.getline(region.from.line):sub(1, region.from.col - 1)\n    opts.justify_offsets[1] = vim.fn.strdisplaywidth(prefix)\n  end\n\n  -- Actually process region\n  local strings = H.region_get_text(region, mode)\n  local strings_aligned = MiniAlign.align_strings(strings, opts, steps)\n  H.region_set_text(region, mode, strings_aligned)\n\n  -- Make sure that latest changes are shown\n  vim.cmd('redraw')\n\n  -- Confirm that lines were actually set\n  return table.concat(strings) ~= table.concat(strings_aligned)\nend\n\nH.get_current_region = function()\n  local from_expr, to_expr = \"'[\", \"']\"\n  if H.is_visual_mode() then\n    from_expr, to_expr = '.', 'v'\n  end\n\n  -- Add offset (*_pos[4]) to allow position go past end of line\n  local from_pos = vim.fn.getpos(from_expr)\n  local from = { line = from_pos[2], col = from_pos[3] + from_pos[4] }\n  local to_pos = vim.fn.getpos(to_expr)\n  local to = { line = to_pos[2], col = to_pos[3] + to_pos[4] }\n\n  -- Ensure correct order\n  if to.line < from.line or (to.line == from.line and to.col < from.col) then\n    from, to = to, from\n  end\n\n  return { from = from, to = to }\nend\n\nH.region_get_text = function(region, mode)\n  local from, to = region.from, region.to\n\n  if mode == 'char' then\n    local to_col_offset = vim.o.selection == 'exclusive' and 1 or 0\n    return H.get_text(from.line - 1, from.col - 1, to.line - 1, to.col - to_col_offset)\n  end\n\n  if mode == 'line' then return H.get_lines(from.line - 1, to.line) end\n\n  if mode == 'block' then\n    -- Use virtual columns to respect multibyte/wide/composing characters\n    local left_virtcol, right_virtcol = H.region_virtcols(region)\n\n    local res, lines = {}, H.get_lines(from.line - 1, to.line)\n    for i, l in ipairs(lines) do\n      local lnum = from.line + i - 1\n      local left_col = H.virtcol2col(lnum, left_virtcol)\n      local right_col = H.virtcol2col(lnum, right_virtcol)\n      right_col = right_col + H.str_utf_end(l, right_col)\n\n      table.insert(res, l:sub(left_col, right_col))\n    end\n    return res\n  end\nend\n\nH.region_set_text = function(region, mode, text)\n  local from, to = region.from, region.to\n\n  if mode == 'char' then\n    -- Ensure not going past last column (can happen with `$` in Visual mode)\n    local to_line_n_cols = vim.fn.col({ to.line, '$' }) - 1\n    local to_col = math.min(to.col, to_line_n_cols)\n    local to_col_offset = vim.o.selection == 'exclusive' and 1 or 0\n    H.set_text(from.line - 1, from.col - 1, to.line - 1, to_col - to_col_offset, text)\n  end\n\n  if mode == 'line' then H.set_lines(from.line - 1, to.line, text) end\n\n  if mode == 'block' then\n    if #text ~= (to.line - from.line + 1) then\n      H.error('Number of replacement lines should fit the region in blockwise mode')\n    end\n\n    -- Use virtual columns to respect multibyte characters\n    local left_virtcol, right_virtcol = H.region_virtcols(region)\n\n    local lines = H.get_lines(from.line - 1, to.line)\n    for i, l in ipairs(lines) do\n      local lnum = from.line + i - 1\n      local left_col = H.virtcol2col(lnum, left_virtcol)\n      local right_col = H.virtcol2col(lnum, right_virtcol)\n      right_col = right_col + H.str_utf_end(l, right_col)\n\n      -- Adjust columns to not go outside of line\n      -- TODO: Remove after compatibility with Neovim=0.9 is dropped\n      left_col, right_col = math.max(left_col - 1, 0), math.min(right_col, l:len())\n      H.set_text(lnum - 1, left_col, lnum - 1, right_col, { text[i] })\n    end\n  end\nend\n\nH.region_virtcols = function(region)\n  -- Account for multibyte characters and position past the line end\n  local from_virtcol = H.pos_to_virtcol(region.from)\n  local to_virtcol = H.pos_to_virtcol(region.to)\n\n  local left_virtcol, right_virtcol = math.min(from_virtcol, to_virtcol), math.max(from_virtcol, to_virtcol)\n  right_virtcol = right_virtcol - (vim.o.selection == 'exclusive' and 1 or 0)\n\n  return left_virtcol, right_virtcol\nend\n\nH.pos_to_virtcol = function(pos)\n  -- Account for position past line end\n  local eol_col = vim.fn.col({ pos.line, '$' })\n  if eol_col < pos.col then return vim.fn.virtcol({ pos.line, '$' }) + pos.col - eol_col end\n\n  return vim.fn.virtcol({ pos.line, pos.col })\nend\n\n-- Work with user interaction -------------------------------------------------\nH.user_modifier = function(with_preview, msg_chunks)\n  -- Get from user single character modifier\n  local needs_show_state = true\n  local delay = (H.cache.msg_shown or with_preview) and 0 or 1000\n  vim.defer_fn(function()\n    if not needs_show_state then return end\n\n    table.insert(msg_chunks, { ' Press modifier' })\n    H.echo(msg_chunks)\n    H.cache.msg_shown = true\n  end, delay)\n  local ok, char = pcall(vim.fn.getcharstr)\n  needs_show_state = false\n\n  -- Terminate if couldn't get input (like with <C-c>) or it is `<Esc>`\n  if not ok or char == '\\27' then return nil end\n  return char\nend\n\nH.user_input = function(prompt, text)\n  -- Use `on_key` to distinguish cancel with `<Esc>` and immediate `<CR>`\n  local was_cancelled = false\n  vim.on_key(function(key) was_cancelled = was_cancelled or key == '\\27' end, H.ns_id.input)\n\n  -- Ask for input. Use `pcall` to allow `<C-c>` to cancel user input\n  vim.cmd('echohl Question')\n  local ok, res = pcall(vim.fn.input, { prompt = '(mini.align) ' .. prompt .. ': ', default = text or '' })\n  vim.cmd('echohl None | echo \"\" | redraw')\n\n  vim.on_key(nil, H.ns_id.input)\n  return (ok and not was_cancelled) and res or nil\nend\n\nH.make_status_msg_chunks = function(opts, steps)\n  local single_to_string = function(pre_steps, opts_value)\n    local steps_str = ''\n    if #pre_steps > 0 then\n      local pre_names = vim.tbl_map(function(x) return x.name end, pre_steps)\n      steps_str = string.format('(%s) ', table.concat(pre_names, ', '))\n    end\n    return steps_str .. vim.inspect(opts_value)\n  end\n\n  return {\n    { 'Split: ', 'ModeMsg' },\n    { single_to_string(steps.pre_split, opts.split_pattern) },\n    { ' | ', 'Question' },\n    { 'Justify: ', 'ModeMsg' },\n    { single_to_string(steps.pre_justify, opts.justify_side) },\n    { ' | ', 'Question' },\n    { 'Merge: ', 'ModeMsg' },\n    { single_to_string(steps.pre_merge, opts.merge_delimiter) },\n    { ' |', 'Question' },\n  }\nend\n\n-- Predicates -----------------------------------------------------------------\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not predicate(v) then return false end\n  end\n  return true\nend\n\nH.is_step = function(x) return type(x) == 'table' and type(x.name) == 'string' and vim.is_callable(x.action) end\n\nH.is_string = function(v) return type(v) == 'string' end\n\nH.is_justify_side = function(x) return x == 'left' or x == 'center' or x == 'right' or x == 'none' end\n\nH.is_parts = function(x) return H.can_be_parts(x) and (getmetatable(x) or {}).class == 'parts' end\n\nH.can_be_parts = function(x)\n  if type(x) ~= 'table' then return false, 'should be table' end\n  for i = 1, #x do\n    if not H.is_array_of(x[i], H.is_string) then return false, 'values should be an array of strings' end\n  end\n  return true\nend\n\nH.is_infinite = function(x) return x == math.huge or x == -math.huge end\n\nH.is_visual_mode = function() return vim.tbl_contains({ 'v', 'V', '\\22' }, vim.fn.mode(1)) end\n\nH.is_whitespace = function(x) return type(x) == 'string' and x:find('^%s*$') ~= nil end\n\n-- Work with get/set text -----------------------------------------------------\nH.get_text = function(start_row, start_col, end_row, end_col)\n  return vim.api.nvim_buf_get_text(0, start_row, start_col, end_row, end_col, {})\nend\n\nH.get_lines = function(start_row, end_row) return vim.api.nvim_buf_get_lines(0, start_row, end_row, true) end\n\n--- Set text in current buffer without affecting marks\n---@private\nH.set_text = function(start_row, start_col, end_row, end_col, replacement)\n  --stylua: ignore\n  local cmd = string.format(\n    'lockmarks lua vim.api.nvim_buf_set_text(0, %d, %d, %d, %d, %s)',\n    start_row, start_col, end_row, end_col, vim.inspect(replacement)\n  )\n  vim.cmd(cmd)\nend\n\n--- Set lines in current buffer without affecting marks\n---@private\nH.set_lines = function(start_row, end_row, replacement)\n  --stylua: ignore\n  local cmd = string.format(\n    'lockmarks lua vim.api.nvim_buf_set_lines(0, %d, %d, true, %s)',\n    start_row, end_row, vim.inspect(replacement)\n  )\n  vim.cmd(cmd)\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.align) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg, add_to_history)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.align) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n  local chunks, tot_width = {}, 0\n  for _, ch in ipairs(msg) do\n    local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n    table.insert(chunks, new_ch)\n    tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n    if tot_width >= max_width then break end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, add_to_history, {})\nend\n\nH.unecho = function()\n  if H.cache.msg_shown then vim.cmd([[echo '' | redraw]]) end\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.slice_mod = function(x, i) return x[((i - 1) % #x) + 1] end\n\nH.tbl_repeat = function(val, n)\n  local res = {}\n  for i = 1, n do\n    res[i] = val\n  end\n  return res\nend\n\nH.group_by_mask = function(arr, mask, direction)\n  local res, cur_group = {}, {}\n\n  -- Construct actors based on direction\n  local from, to, by = 1, #arr, 1\n  local insert = function(t, v) table.insert(t, v) end\n  if direction == 'right' then\n    from, to, by = to, from, -1\n    insert = function(t, v) table.insert(t, 1, v) end\n  end\n\n  -- Group\n  for i = from, to, by do\n    insert(cur_group, arr[i])\n    if mask[i] or i == to then\n      insert(res, cur_group)\n      cur_group = {}\n    end\n  end\n\n  return res\nend\n\nH.concat_array = function(target_arr, concat_arr)\n  local ext_arr = {}\n  for i = 1, #target_arr - 1 do\n    -- Concat non-empty cells (empty cells at this point add only extra merge)\n    if target_arr[i] ~= '' then\n      table.insert(ext_arr, target_arr[i])\n      table.insert(ext_arr, concat_arr[i])\n    end\n  end\n  table.insert(ext_arr, target_arr[#target_arr])\n  return table.concat(ext_arr, '')\nend\n\nH.string_find = function(s, pattern, init)\n  init = init or 1\n\n  -- Match only start of full string if pattern says so.\n  -- This is needed because `string.find()` doesn't do this.\n  -- Example: `string.find('(aaa)', '^.*$', 4)` returns `4, 5`\n  if pattern:sub(1, 1) == '^' and init > 1 then return nil end\n\n  -- Treat `''` as if nothing is found (treats it as \"reset split\"). If not\n  -- altered, results in infinite loop.\n  if pattern == '' then return nil end\n\n  return string.find(s, pattern, init)\nend\n\nH.virtcol2col = function(lnum, col) return vim.fn.virtcol2col(0, lnum, col) end\nif vim.fn.has('nvim-0.10') == 0 then\n  -- Neovim<0.10 has `virtcol2col` returning cell's last column instead of\n  -- cell's first column in Neovim>=0.10\n  H.virtcol2col = function(lnum, col)\n    if vim.fn.virtcol2col(0, lnum, col) == 0 then return 0 end\n    return vim.fn.virtcol2col(0, lnum, col - 1) + 1\n  end\nend\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.str_utf_end = function(s, n) return n >= s:len() and 0 or vim.str_utf_end(s, n) end\nif vim.fn.has('nvim-0.10') == 0 then\n  H.str_utf_end = function(s, n) return n >= s:len() and 0 or (vim.str_byteindex(s, H.str_utfindex(s, n)) - n) end\nend\n\nH.is_any_point_inside_any_span = function(points, spans)\n  for _, point in ipairs(points) do\n    for _, span in ipairs(spans) do\n      if span[1] <= point and point <= span[2] then return true end\n    end\n  end\n  return false\nend\n\nH.undo = function()\n  if H.is_visual_mode() then\n    -- Can't use `u` in Visual mode because it makes all selection lowercase\n    local cur_mode = vim.fn.mode(1)\n    vim.cmd('silent! normal! \\27')\n\n    -- Undo\n    vim.cmd('silent! lockmarks undo')\n\n    -- Manually restore selection. There are issues with using restoring marks\n    -- via `gv` (couldn't figure out how to reliably preserve visual mode).\n    -- As this is called only if lines were set, region is cached.\n    local region = H.cache.region\n    vim.api.nvim_win_set_cursor(0, { region.from.line, region.from.col - 1 })\n    vim.cmd('silent! normal!' .. cur_mode)\n    vim.api.nvim_win_set_cursor(0, { region.to.line, region.to.col - 1 })\n  else\n    vim.cmd('silent! lockmarks normal! u')\n  end\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniAlign\n"
  },
  {
    "path": "lua/mini/animate.lua",
    "content": "--- *mini.animate* Animate common Neovim actions\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Features:\n--- - Works out of the box with a single `require('mini.animate').setup()`.\n---   No extra mappings or commands needed.\n---\n--- - Animate cursor movement inside same buffer by showing customizable path.\n---   See |MiniAnimate.config.cursor| for more details.\n---\n--- - Animate scrolling with a series of subscrolls (\"smooth scrolling\").\n---   See |MiniAnimate.config.scroll| for more details.\n---\n--- - Animate window resize by gradually changing sizes of all windows.\n---   See |MiniAnimate.config.resize| for more details.\n---\n--- - Animate window open/close with visually updating floating window.\n---   See |MiniAnimate.config.open| and |MiniAnimate.config.close| for more details.\n---\n--- - Timings for all actions can be customized independently.\n---   See |MiniAnimate-timing| for more details.\n---\n--- - Action animations can be enabled/disabled independently.\n---\n--- - All animations are asynchronous/non-blocking and trigger a targeted event\n---   which can be used to perform actions after animation is done.\n---\n--- - |MiniAnimate.animate()| function which can be used to perform own animations.\n---\n--- Notes:\n--- - Cursor movement is animated inside same window and buffer, not as cursor\n---   moves across the screen.\n---\n--- - Scroll and resize animations are done with \"side effects\": they actually\n---   change the state of what is animated (window view and sizes\n---   respectively). This has a downside of possibly needing extra work to\n---   account for asynchronous nature of animation (like adjusting certain\n---   mappings, etc.). See |MiniAnimate.config.scroll| and\n---   |MiniAnimate.config.resize| for more details.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.animate').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniAnimate`\n--- which you can use for scripting or manually (with `:lua MiniAnimate.*`).\n---\n--- See |MiniAnimate.config| for available config settings.\n---\n--- You can override runtime config settings (like `config.modifiers`) locally\n--- to buffer inside `vim.b.minianimate_config` which should have same structure\n--- as `MiniAnimate.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [Neovide](https://neovide.dev/):\n---     - Neovide is a standalone GUI which has more control over its animations.\n---       While 'mini.animate' works inside terminal emulator (with all its\n---       limitations, like lack of pixel-size control over animations).\n---     - Neovide animates cursor movement across screen, while 'mini.animate' -\n---       as it moves across same buffer.\n---     - Neovide has fixed number of animation effects per action, while\n---       'mini.animate' is fully customizable.\n---     - 'mini.animate' implements animations for window open/close, while\n---       Neovide does not.\n--- - [edluffy/specs.nvim](https://github.com/edluffy/specs.nvim):\n---     - 'mini.animate' approaches cursor movement visualization via\n---       customizable path function (uses extmarks), while 'specs.nvim' can\n---       customize within its own visual effects (shading and floating\n---       window resizing).\n--- - [karb94/neoscroll.nvim](https://github.com/karb94/neoscroll.nvim):\n---     - Scroll animation is triggered only inside dedicated mappings.\n---       'mini.animate' animates scroll resulting from any window view change.\n--- - [anuvyklack/windows.nvim](https://github.com/anuvyklack/windows.nvim):\n---     - Resize animation is done only within custom commands and mappings,\n---       while 'mini.animate' animates any resize with appropriate values of\n---       'winheight' / 'winwidth' and 'winminheight' / 'winminwidth').\n---\n--- # Highlight groups ~\n---\n--- - `MiniAnimateCursor` - highlight of cursor during its animated movement.\n--- - `MiniAnimateNormalFloat` - highlight of floating window for `open` and\n---   `close` animations.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minianimate_disable` (globally) or\n--- `vim.b.minianimate_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniAnimate\n\n---@diagnostic disable:undefined-field\n\n-- Module definition ==========================================================\nlocal MiniAnimate = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniAnimate.config|.\n---\n---@usage >lua\n---   require('mini.animate').setup() -- use default config\n---   -- OR\n---   require('mini.animate').setup({}) -- replace {} with your config table\n--- <\nMiniAnimate.setup = function(config)\n  -- Export module\n  _G.MiniAnimate = MiniAnimate\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n  H.track_scroll_state()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # General ~\n---\n--- - *MiniAnimate-timing* Every animation is a non-blockingly scheduled series of\n---   specific actions. They are executed in a sequence of timed steps controlled\n---   by `timing` option. It is a callable which, given next and total step numbers,\n---   returns wait time (in ms).\n---   See |MiniAnimate.gen_timing| for builtin timing functions.\n---   See |MiniAnimate.animate()| for more details about animation process.\n---\n--- - Every animation can be enabled/disabled independently by setting `enable`\n---   option to `true`/`false`.\n---\n--- - *MiniAnimate-done-event* Every animation triggers custom |User| event when it\n---   is finished. It is named `MiniAnimateDoneXxx` with `Xxx` replaced by capitalized\n---   supported animation action name (like `MiniAnimateDoneCursor`). Use it to\n---   schedule some action after certain animation is completed. Alternatively,\n---   you can use |MiniAnimate.execute_after()| (usually preferred in mappings).\n---\n--- - Each animation has its main step generator which defines how particular\n---   animation is done. They all are callables which take some input data and\n---   return an array of step data. Length of that array determines number of\n---   animation steps. Outputs `nil` and empty table result in no animation.\n---\n--- # Cursor ~\n--- *MiniAnimate.config.cursor*\n---\n--- This animation is triggered for each movement of cursor inside same window\n--- and buffer. Its visualization step consists from placing single extmark (see\n--- |extmarks|) at certain position. This extmark contains single space and is\n--- highlighted with `MiniAnimateCursor` highlight group.\n---\n--- Exact places of extmark and their number is controlled by `path` option. It\n--- is a callable which takes `destination` argument (2d integer point in\n--- `(line, col)` coordinates) and returns array of relative to `(0, 0)` places\n--- for extmark to be placed. Example:\n--- - Input `(2, -3)` means cursor jumped 2 lines forward and 3 columns backward.\n--- - Output `{ {0, 0 }, { 0, -1 }, { 0, -2 }, { 0, -3 }, { 1, -3 } }` means\n---   that path is first visualized along the initial line and then along final\n---   column.\n---\n--- See |MiniAnimate.gen_path| for builtin path generators.\n---\n--- Notes:\n--- - Input `destination` value is computed ignoring folds. This is by design\n---   as it helps better visualize distance between two cursor positions.\n--- - Outputs of path generator resulting in a place where extmark can't be\n---   placed are silently omitted during animation: this step won't show any\n---   visualization.\n---\n--- Configuration example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     cursor = {\n---       -- Animate for 200 milliseconds with linear easing\n---       timing = animate.gen_timing.linear({ duration = 200, unit = 'total' }),\n---\n---       -- Animate with shortest line for any cursor move\n---       path = animate.gen_path.line({\n---         predicate = function() return true end,\n---       }),\n---     }\n---   })\n--- <\n--- After animation is done, `MiniAnimateDoneCursor` event is triggered.\n---\n--- # Scroll ~\n--- *MiniAnimate.config.scroll*\n---\n--- This animation is triggered for each vertical scroll of current window.\n--- Its visualization step consists from performing a small subscroll which all\n--- in total will result into needed total scroll.\n---\n--- Exact subscroll values and their number is controlled by `subscroll` option.\n--- It is a callable which takes `total_scroll` argument (single non-negative\n--- integer) and returns array of non-negative integers each representing the\n--- amount of lines needed to be scrolled inside corresponding step. All\n--- subscroll values should sum to input `total_scroll`.\n--- Example:\n--- - Input `5` means that total scroll consists from 5 lines (either up or down,\n---   which doesn't matter).\n--- - Output of `{ 1, 1, 1, 1, 1 }` means that there are 5 equal subscrolls.\n---\n--- See |MiniAnimate.gen_subscroll| for builtin subscroll generators.\n---\n--- Notes:\n--- - Input value of `total_scroll` is computed taking folds into account.\n--- - As scroll animation is essentially a precisely scheduled non-blocking\n---   subscrolls, this has two important interconnected consequences:\n---     - If another scroll is attempted during the animation, it is done based\n---       on the **currently visible** window view. Example: if user presses\n---       |CTRL-D| and then |CTRL-U| when animation is half done, window will not\n---       display the previous view half of 'scroll' above it. This especially\n---       affects mouse wheel scrolling, as each its turn results in a new scroll\n---       for number of lines defined by 'mousescroll'. Tweak it to your liking.\n---     - It breaks the use of several relative scrolling commands in the same\n---       command. Use |MiniAnimate.execute_after()| to schedule action after\n---       reaching target window view.\n---       Example: a useful `nnoremap n nzvzz` mapping (consecutive application\n---       of |n|, |zv|, and |zz|) should be expressed in the following way: >lua\n---\n---         '<Cmd>lua vim.cmd(\"normal! n\"); ' ..\n---           'MiniAnimate.execute_after(\"scroll\", \"normal! zvzz\")<CR>'\n--- <\n--- - Default timing might conflict with scrolling via holding a key (like `j` or `k`\n---   with 'wrap' enabled) due to high key repeat rate: next scroll is done before\n---   first step of current one finishes. Resolve this by not scrolling like that\n---   or by ensuring maximum value of step duration to be lower than between\n---   repeated keys: set timing like `function(_, n) return math.min(250/n, 10) end`\n---   or use timing with constant step duration.\n---\n--- Configuration example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     scroll = {\n---       -- Animate for 200 milliseconds with linear easing\n---       timing = animate.gen_timing.linear({ duration = 200, unit = 'total' }),\n---\n---       -- Animate equally but with at most 120 steps instead of default 60\n---       subscroll = animate.gen_subscroll.equal({ max_output_steps = 120 }),\n---     }\n---   })\n--- <\n--- After animation is done, `MiniAnimateDoneScroll` event is triggered.\n---\n--- # Resize ~\n--- *MiniAnimate.config.resize*\n---\n--- This animation is triggered for window resize while having same layout of\n--- same windows. For example, it won't trigger when window is opened/closed or\n--- after something like |CTRL-W_K|. Its visualization step consists from setting\n--- certain sizes to all visible windows (last step being for \"true\" final sizes).\n---\n--- Exact window step sizes and their number is controlled by `subresize` option.\n--- It is a callable which takes `sizes_from` and `sizes_to` arguments (both\n--- tables with window id as keys and dimension table as values) and returns\n--- array of same shaped data.\n--- Example:\n--- - Input: >lua\n---\n---   -- First\n---   { [1000] = {width = 7, height = 5}, [1001] = {width = 7, height = 10} }\n---   -- Second\n---   { [1000] = {width = 9, height = 5}, [1001] = {width = 5, height = 10} }\n---   -- Means window 1000 increased its width by 2 in expense of window 1001\n--- <\n--- - The following output demonstrates equal resizing: >lua\n---\n---   {\n---     { [1000] = {width = 8, height = 5}, [1001] = {width = 6, height = 10} },\n---     { [1000] = {width = 9, height = 5}, [1001] = {width = 5, height = 10} },\n---   }\n--- <\n--- See |MiniAnimate.gen_subresize| for builtin subresize generators.\n---\n--- Notes:\n---\n--- - As resize animation is essentially a precisely scheduled non-blocking\n---   subresizes, this has two important interconnected consequences:\n---     - If another resize is attempted during the animation, it is done based\n---       on the **currently visible** window sizes. This might affect relative\n---       resizing.\n---     - It breaks the use of several relative resizing commands in the same\n---       command. Use |MiniAnimate.execute_after()| to schedule action after\n---       reaching target window sizes.\n---\n--- Configuration example: >lua\n---\n---   local is_many_wins = function(sizes_from, sizes_to)\n---     return vim.tbl_count(sizes_from) >= 3\n---   end\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     resize = {\n---       -- Animate for 200 milliseconds with linear easing\n---       timing = animate.gen_timing.linear({ duration = 200, unit = 'total' }),\n---\n---       -- Animate only if there are at least 3 windows\n---       subresize = animate.gen_subscroll.equal({ predicate = is_many_wins }),\n---     }\n---   })\n--- <\n--- After animation is done, `MiniAnimateDoneResize` event is triggered.\n---\n--- # Window open/close ~\n--- *MiniAnimate.config.open*\n--- *MiniAnimate.config.close*\n---\n--- These animations are similarly triggered for regular (non-floating) window\n--- open/close. Their visualization step consists from drawing empty floating\n--- window with customizable config and transparency.\n---\n--- Exact window visualization characteristics are controlled by `winconfig`\n--- and `winblend` options.\n---\n--- The `winconfig` option is a callable which takes window id (|window-ID|) as\n--- input and returns an array of floating window configs (as in `config`\n--- argument of |nvim_open_win()|). Its length determines number of animation steps.\n--- Example:\n--- - The following output results into two animation steps with second being\n---   upper left quarter of a first: >lua\n---\n---   {\n---     {\n---       row      = 0,        col    = 0,\n---       width    = 10,       height = 10,\n---       relative = 'editor', anchor = 'NW',   focusable = false,\n---       zindex   = 1,        border = 'none', style  = 'minimal',\n---     },\n---     {\n---       row      = 0,        col    = 0,\n---       width    = 5,        height = 5,\n---       relative = 'editor', anchor = 'NW',   focusable = false,\n---       zindex   = 1,        border = 'none', style  = 'minimal',\n---     },\n---   }\n--- <\n--- The `winblend` option is similar to `timing` option: it is a callable\n--- which, given current and total step numbers, returns value of floating\n--- window's 'winblend' option. Note, that it is called for current step (so\n--- starts from 0), as opposed to `timing` which is called before step.\n--- Example:\n--- - Function `function(s, n) return 80 + 20 * s / n end` results in linear\n---   transition from `winblend` value of 80 to 100.\n---\n--- See |MiniAnimate.gen_winconfig| for builtin window config generators.\n--- See |MiniAnimate.gen_winblend| for builtin window transparency generators.\n---\n--- Configuration example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     open = {\n---       -- Animate for 400 milliseconds with linear easing\n---       timing = animate.gen_timing.linear({ duration = 400, unit = 'total' }),\n---\n---       -- Animate with wiping from nearest edge instead of default static one\n---       winconfig = animate.gen_winconfig.wipe({ direction = 'from_edge' }),\n---\n---       -- Make bigger windows more transparent\n---       winblend = animate.gen_winblend.linear({ from = 80, to = 100 }),\n---     },\n---\n---     close = {\n---       -- Animate for 400 milliseconds with linear easing\n---       timing = animate.gen_timing.linear({ duration = 400, unit = 'total' }),\n---\n---       -- Animate with wiping to nearest edge instead of default static one\n---       winconfig = animate.gen_winconfig.wipe({ direction = 'to_edge' }),\n---\n---       -- Make bigger windows more transparent\n---       winblend = animate.gen_winblend.linear({ from = 100, to = 80 }),\n---     },\n---   })\n--- <\n--- After animation is done, `MiniAnimateDoneOpen` or `MiniAnimateDoneClose`\n--- event is triggered for `open` and `close` animation respectively.\nMiniAnimate.config = {\n  -- Cursor path\n  cursor = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    --minidoc_replace_start timing = --<function: linear animation, total 250ms>,\n    timing = function(_, n) return 250 / n end,\n    --minidoc_replace_end\n\n    -- Path generator for visualized cursor movement\n    --minidoc_replace_start path = --<function: implements shortest line path no longer than 1000>,\n    path = function(destination)\n      return H.path_line(destination, { predicate = H.default_path_predicate, max_output_steps = 1000 })\n    end,\n    --minidoc_replace_end\n  },\n\n  -- Vertical scroll\n  scroll = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    --minidoc_replace_start timing = --<function: linear animation, total 250ms>,\n    timing = function(_, n) return 250 / n end,\n    --minidoc_replace_end\n\n    -- Subscroll generator based on total scroll\n    --minidoc_replace_start subscroll = --<function: implements equal scroll with at most 60 steps>,\n    subscroll = function(total_scroll)\n      return H.subscroll_equal(total_scroll, { predicate = H.default_subscroll_predicate, max_output_steps = 60 })\n    end,\n    --minidoc_replace_end\n  },\n\n  -- Window resize\n  resize = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    --minidoc_replace_start timing = --<function: linear animation, total 250ms>,\n    timing = function(_, n) return 250 / n end,\n    --minidoc_replace_end\n\n    -- Subresize generator for all steps of resize animations\n    --minidoc_replace_start subresize = --<function: implements equal linear steps>,\n    subresize = function(sizes_from, sizes_to)\n      return H.subresize_equal(sizes_from, sizes_to, { predicate = H.default_subresize_predicate })\n    end,\n    --minidoc_replace_end\n  },\n\n  -- Window open\n  open = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    --minidoc_replace_start timing = --<function: linear animation, total 250ms>,\n    timing = function(_, n) return 250 / n end,\n    --minidoc_replace_end\n\n    -- Floating window config generator visualizing specific window\n    --minidoc_replace_start winconfig = --<function: implements static window for 25 steps>,\n    winconfig = function(win_id)\n      return H.winconfig_static(win_id, { predicate = H.default_winconfig_predicate, n_steps = 25 })\n    end,\n    --minidoc_replace_end\n\n    -- 'winblend' (window transparency) generator for floating window\n    --minidoc_replace_start winblend = --<function: implements equal linear steps from 80 to 100>,\n    winblend = function(s, n) return 80 + 20 * (s / n) end,\n    --minidoc_replace_end\n  },\n\n  -- Window close\n  close = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    --minidoc_replace_start timing = --<function: linear animation, total 250ms>,\n    timing = function(_, n) return 250 / n end,\n    --minidoc_replace_end\n\n    -- Floating window config generator visualizing specific window\n    --minidoc_replace_start winconfig = --<function: implements static window for 25 steps>,\n    winconfig = function(win_id)\n      return H.winconfig_static(win_id, { predicate = H.default_winconfig_predicate, n_steps = 25 })\n    end,\n    --minidoc_replace_end\n\n    -- 'winblend' (window transparency) generator for floating window\n    --minidoc_replace_start winblend = --<function: implements equal linear steps from 80 to 100>,\n    winblend = function(s, n) return 80 + 20 * (s / n) end,\n    --minidoc_replace_end\n  },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Check animation activity\n---\n---@param animation_type string One of supported animation types\n---   (entries of |MiniAnimate.config|, like `'cursor'`, etc.).\n---\n---@return boolean Whether the animation is currently active.\nMiniAnimate.is_active = function(animation_type)\n  local res = H.cache[animation_type .. '_is_active']\n  if res == nil then H.error('Wrong `animation_type` for `is_active()`.') end\n  return res\nend\n\n--- Execute action after some animation is done\n---\n--- Execute action immediately if animation is not active (checked with\n--- |MiniAnimate.is_active()|). Else, schedule its execution until after\n--- animation is done (on corresponding \"done event\", see\n--- |MiniAnimate-done-event|).\n---\n--- Mostly meant to be used inside mappings.\n---\n--- Example:\n---\n--- A useful `nnoremap n nzvzz` mapping (consecutive application of |n|, |zv|, and |zz|)\n--- should be expressed in the following way: >lua\n---\n---   '<Cmd>lua vim.cmd(\"normal! n\"); ' ..\n---     'MiniAnimate.execute_after(\"scroll\", \"normal! zvzz\")<CR>'\n--- <\n---@param animation_type string One of supported animation types\n---   (as in |MiniAnimate.is_active()|).\n---@param action string|function Action to be executed. If string, executed as\n---   command (via |vim.cmd()|).\nMiniAnimate.execute_after = function(animation_type, action)\n  local event_name = H.animation_done_events[animation_type]\n  if event_name == nil then H.error('Wrong `animation_type` for `execute_after`.') end\n\n  local callable = action\n  if type(callable) == 'string' then callable = function() vim.cmd(action) end end\n  if not vim.is_callable(callable) then\n    H.error('Argument `action` of `execute_after()` should be string or callable.')\n  end\n\n  -- Schedule conditional action execution to allow animation to actually take\n  -- effect. This helps creating more universal mappings, because some commands\n  -- (like `n`) not always result into scrolling.\n  vim.schedule(function()\n    if MiniAnimate.is_active(animation_type) then\n      vim.api.nvim_create_autocmd('User', { pattern = event_name, once = true, callback = callable })\n    else\n      callable()\n    end\n  end)\nend\n\n-- Action (step 0) - wait (step 1) - action (step 1) - ...\n-- `step_action` should return `false` or `nil` (equivalent to not returning anything explicitly) in order to stop animation.\n--- Animate action\n---\n--- This is equivalent to asynchronous execution of the following algorithm:\n--- - Call `step_action(0)` immediately after calling this function. Stop if\n---   action returned `false` or `nil`.\n--- - Wait `step_timing(1)` milliseconds.\n--- - Call `step_action(1)`. Stop if it returned `false` or `nil`.\n--- - Wait `step_timing(2)` milliseconds.\n--- - Call `step_action(2)`. Stop if it returned `false` or `nil`.\n--- - ...\n---\n--- Notes:\n--- - Animation is also stopped on action error or if maximum number of steps\n---   is reached.\n--- - Asynchronous execution is done with |uv.new_timer()|. It only allows\n---   integer parts as repeat value. This has several implications:\n---     - Outputs of `step_timing()` are accumulated in order to preserve total\n---       execution time.\n---     - Any wait time less than 1 ms means that action will be executed\n---       immediately.\n---\n---@param step_action function|table Callable which takes `step` (integer 0, 1, 2,\n---   etc. indicating current step) and executes some action. Its return value\n---   defines when animation should stop: values `false` and `nil` (equivalent\n---   to no explicit return) stop animation timer; any other continues it.\n---@param step_timing function|table Callable which takes `step` (integer 1, 2, etc.\n---   indicating next step) and returns how many milliseconds to wait before\n---   executing this step action.\n---@param opts table|nil Options. Possible fields:\n---   - <max_steps> - Maximum value of allowed step to execute. Default: 10000000.\nMiniAnimate.animate = function(step_action, step_timing, opts)\n  opts = vim.tbl_deep_extend('force', { max_steps = 10000000 }, opts or {})\n\n  local step, max_steps = 0, opts.max_steps\n  local timer, wait_time = vim.loop.new_timer(), 0\n\n  local draw_step\n  draw_step = vim.schedule_wrap(function()\n    local ok, should_continue = pcall(step_action, step)\n    if not (ok and should_continue and step < max_steps) then\n      timer:stop()\n      return\n    end\n\n    step = step + 1\n    wait_time = wait_time + step_timing(step)\n\n    -- Repeat value of `timer` seems to be rounded down to milliseconds. This\n    -- means that values less than 1 will lead to timer stop repeating. Instead\n    -- call next step function directly.\n    if wait_time < 1 then\n      timer:set_repeat(0)\n      -- Use `return` to make this proper \"tail call\"\n      return draw_step()\n    else\n      timer:set_repeat(wait_time)\n      wait_time = wait_time - timer:get_repeat()\n      timer:again()\n    end\n  end)\n\n  -- Start non-repeating timer without callback execution\n  timer:start(10000000, 0, draw_step)\n\n  -- Draw step zero (at origin) immediately\n  draw_step()\nend\n\n--- Generate animation timing\n---\n--- Each field corresponds to one family of progression which can be customized\n--- further by supplying appropriate arguments.\n---\n--- This is a table with function elements. Call to actually get timing function.\n---\n--- Example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     cursor = {\n---       timing = animate.gen_timing.linear({ duration = 100, unit = 'total' })\n---     },\n---   })\n--- <\n---@seealso |MiniIndentscope.gen_animation| for similar concept in 'mini.indentscope'.\nMiniAnimate.gen_timing = {}\n\n---@alias __animate_timing_opts table|nil Options that control progression. Possible keys:\n---   - <easing> `(string)` - a subtype of progression. One of \"in\"\n---     (accelerating from zero speed), \"out\" (decelerating to zero speed),\n---     \"in-out\" (default; accelerating halfway, decelerating after).\n---   - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n---   - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n---     of \"step\" (default; ensures average duration of step to be `opts.duration`)\n---     or \"total\" (ensures fixed total duration regardless of scope's range).\n---@alias __animate_timing_return function Timing function (see |MiniAnimate-timing|).\n\n--- Generate timing with no animation\n---\n--- Show final result immediately. Usually better to use `enable` field in `config`\n--- if you want to disable animation.\nMiniAnimate.gen_timing.none = function()\n  return function() return 0 end\nend\n\n--- Generate timing with linear progression\n---\n---@param opts __animate_timing_opts\n---\n---@return __animate_timing_return\nMiniAnimate.gen_timing.linear = function(opts) return H.timing_arithmetic(0, H.normalize_timing_opts(opts)) end\n\n--- Generate timing with quadratic progression\n---\n---@param opts __animate_timing_opts\n---\n---@return __animate_timing_return\nMiniAnimate.gen_timing.quadratic = function(opts) return H.timing_arithmetic(1, H.normalize_timing_opts(opts)) end\n\n--- Generate timing with cubic progression\n---\n---@param opts __animate_timing_opts\n---\n---@return __animate_timing_return\nMiniAnimate.gen_timing.cubic = function(opts) return H.timing_arithmetic(2, H.normalize_timing_opts(opts)) end\n\n--- Generate timing with quartic progression\n---\n---@param opts __animate_timing_opts\n---\n---@return __animate_timing_return\nMiniAnimate.gen_timing.quartic = function(opts) return H.timing_arithmetic(3, H.normalize_timing_opts(opts)) end\n\n--- Generate timing with exponential progression\n---\n---@param opts __animate_timing_opts\n---\n---@return __animate_timing_return\nMiniAnimate.gen_timing.exponential = function(opts) return H.timing_geometrical(H.normalize_timing_opts(opts)) end\n\n--- Generate cursor animation path\n---\n--- For more information see |MiniAnimate.config.cursor|.\n---\n--- This is a table with function elements. Call to actually get generator.\n---\n--- Example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     cursor = {\n---       -- Animate with line-column angle instead of shortest line\n---       path = animate.gen_path.angle(),\n---     }\n---   })\n--- <\nMiniAnimate.gen_path = {}\n\n---@alias __animate_path_opts_common table|nil Options that control generator. Possible keys:\n---   - <predicate> `(function)` - a callable which takes `destination` as input and\n---     returns boolean value indicating whether animation should be done.\n---     Default: `false` if `destination` is within one line of origin (reduces\n---     flickering), `true` otherwise.\n---@alias __animate_path_return function Path function (see |MiniAnimate.config.cursor|).\n\n--- Generate path as shortest line\n---\n---@param opts __animate_path_opts_common\n---   - <max_output_steps> `(number)` - maximum number of steps in output.\n---     Default: 1000.\n---\n---@return __animate_path_return\nMiniAnimate.gen_path.line = function(opts)\n  opts = vim.tbl_deep_extend('force', { predicate = H.default_path_predicate, max_output_steps = 1000 }, opts or {})\n\n  return function(destination) return H.path_line(destination, opts) end\nend\n\n--- Generate path as line/column angle\n---\n---@param opts __animate_path_opts_common\n---   - <max_output_steps> `(number)` - maximum number of steps per side in output.\n---     Default: 1000.\n---   - <first_direction> `(string)` - one of `\"horizontal\"` (default; animates\n---     across initial line first) or `\"vertical\"` (animates across initial\n---     column first).\n---\n---@return __animate_path_return\nMiniAnimate.gen_path.angle = function(opts)\n  local default_opts = { predicate = H.default_path_predicate, max_output_steps = 1000, first_direction = 'horizontal' }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  local append_horizontal = function(res, dest_col, const_line)\n    if dest_col == 0 then return end\n    local n_steps = math.min(math.abs(dest_col), opts.max_output_steps)\n    local coef = dest_col / n_steps\n    for i = 0, n_steps - 1 do\n      table.insert(res, { const_line, H.round(coef * i) })\n    end\n  end\n\n  local append_vertical = function(res, dest_line, const_col)\n    if dest_line == 0 then return end\n    local n_steps = math.min(math.abs(dest_line), opts.max_output_steps)\n    local coef = dest_line / n_steps\n    for i = 0, n_steps - 1 do\n      table.insert(res, { H.round(coef * i), const_col })\n    end\n  end\n\n  return function(destination)\n    -- Don't animate in case of false predicate\n    if not opts.predicate(destination) then return {} end\n\n    -- Travel along horizontal/vertical lines\n    local res = {}\n    if opts.first_direction == 'horizontal' then\n      append_horizontal(res, destination[2], 0)\n      append_vertical(res, destination[1], destination[2])\n    else\n      append_vertical(res, destination[1], 0)\n      append_horizontal(res, destination[2], destination[1])\n    end\n\n    return res\n  end\nend\n\n--- Generate path as closing walls at final position\n---\n---@param opts __animate_path_opts_common\n---   - <width> `(number)` - initial width of left and right walls. Default: 10.\n---\n---@return __animate_path_return\nMiniAnimate.gen_path.walls = function(opts)\n  opts = opts or {}\n  local predicate = opts.predicate or H.default_path_predicate\n  local width = opts.width or 10\n\n  return function(destination)\n    -- Don't animate in case of false predicate\n    if not predicate(destination) then return {} end\n\n    -- Don't animate in case of no movement\n    if destination[1] == 0 and destination[2] == 0 then return {} end\n\n    local dest_line, dest_col = destination[1], destination[2]\n    local res = {}\n    for i = width, 1, -1 do\n      table.insert(res, { dest_line, dest_col + i })\n      table.insert(res, { dest_line, dest_col - i })\n    end\n    return res\n  end\nend\n\n--- Generate path as diminishing spiral at final position\n---\n---@param opts __animate_path_opts_common\n---   - <width> `(number)` - initial width of spiral. Default: 2.\n---\n---@return __animate_path_return\nMiniAnimate.gen_path.spiral = function(opts)\n  opts = opts or {}\n  local predicate = opts.predicate or H.default_path_predicate\n  local width = opts.width or 2\n\n  local add_layer = function(res, w, destination)\n    local dest_line, dest_col = destination[1], destination[2]\n    --stylua: ignore start\n    for j = -w, w-1 do table.insert(res, { dest_line - w, dest_col + j }) end\n    for i = -w, w-1 do table.insert(res, { dest_line + i, dest_col + w }) end\n    for j = -w, w-1 do table.insert(res, { dest_line + w, dest_col - j }) end\n    for i = -w, w-1 do table.insert(res, { dest_line - i, dest_col - w }) end\n    --stylua: ignore end\n  end\n\n  return function(destination)\n    -- Don't animate in case of false predicate\n    if not predicate(destination) then return {} end\n\n    -- Don't animate in case of no movement\n    if destination[1] == 0 and destination[2] == 0 then return {} end\n\n    local res = {}\n    for w = width, 1, -1 do\n      add_layer(res, w, destination)\n    end\n    return res\n  end\nend\n\n--- Generate scroll animation subscroll\n---\n--- For more information see |MiniAnimate.config.scroll|.\n---\n--- This is a table with function elements. Call to actually get generator.\n---\n--- Example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     scroll = {\n---       -- Animate equally but with 120 maximum steps instead of default 60\n---       subscroll = animate.gen_subscroll.equal({ max_output_steps = 120 }),\n---     }\n---   })\n--- <\nMiniAnimate.gen_subscroll = {}\n\n--- Generate subscroll with equal steps\n---\n---@param opts table|nil Options that control generator. Possible keys:\n---   - <predicate> `(function)` - a callable which takes `total_scroll` as\n---     input and returns boolean value indicating whether animation should be\n---     done. Default: `false` if `total_scroll` is 1 or less (reduces\n---     unnecessary waiting), `true` otherwise.\n---   - <max_output_steps> `(number)` - maximum number of subscroll steps in output.\n---     Adjust this to reduce computations in expense of reduced smoothness.\n---     Default: 60.\n---\n---@return function Subscroll function (see |MiniAnimate.config.scroll|).\nMiniAnimate.gen_subscroll.equal = function(opts)\n  opts = vim.tbl_deep_extend('force', { predicate = H.default_subscroll_predicate, max_output_steps = 60 }, opts or {})\n\n  return function(total_scroll) return H.subscroll_equal(total_scroll, opts) end\nend\n\n--- Generate resize animation subresize\n---\n--- For more information see |MiniAnimate.config.resize|.\n---\n--- This is a table with function elements. Call to actually get generator.\n---\n--- Example: >lua\n---\n---   local is_many_wins = function(sizes_from, sizes_to)\n---     return vim.tbl_count(sizes_from) >= 3\n---   end\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     resize = {\n---       -- Animate only if there are at least 3 windows\n---       subresize = animate.gen_subresize.equal({ predicate = is_many_wins }),\n---     }\n---   })\n--- <\nMiniAnimate.gen_subresize = {}\n\n--- Generate subresize with equal steps\n---\n---@param opts table|nil Options that control generator. Possible keys:\n---   - <predicate> `(function)` - a callable which takes `sizes_from` and\n---     `sizes_to` as input and returns boolean value indicating whether\n---     animation should be done. Default: always `true`.\n---\n---@return function Subresize function (see |MiniAnimate.config.resize|).\nMiniAnimate.gen_subresize.equal = function(opts)\n  opts = vim.tbl_deep_extend('force', { predicate = H.default_subresize_predicate }, opts or {})\n\n  return function(sizes_from, sizes_to) return H.subresize_equal(sizes_from, sizes_to, opts) end\nend\n\n--- Generate open/close animation winconfig\n---\n--- For more information see |MiniAnimate.config.open| or |MiniAnimate.config.close|.\n---\n--- This is a table with function elements. Call to actually get generator.\n---\n--- Example: >lua\n---\n---   local is_not_single_window = function(win_id)\n---     local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n---     return #vim.api.nvim_tabpage_list_wins(tabpage_id) > 1\n---   end\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     open = {\n---       -- Animate with wiping from nearest edge instead of default static one\n---       -- and only if it is not a single window in tabpage\n---       winconfig = animate.gen_winconfig.wipe({\n---         predicate = is_not_single_window,\n---         direction = 'from_edge',\n---       }),\n---     },\n---     close = {\n---       -- Animate with wiping to nearest edge instead of default static one\n---       -- and only if it is not a single window in tabpage\n---       winconfig = animate.gen_winconfig.wipe({\n---         predicate = is_not_single_window,\n---         direction = 'to_edge',\n---       }),\n---     },\n---   })\n--- <\nMiniAnimate.gen_winconfig = {}\n\n---@alias __animate_winconfig_opts_common table|nil Options that control generator. Possible keys:\n---   - <predicate> `(function)` - a callable which takes `win_id` as input and\n---     returns boolean value indicating whether animation should be done.\n---     Default: always `true`.\n---@alias __animate_winconfig_return function Winconfig function (see |MiniAnimate.config.open|\n---   or |MiniAnimate.config.close|).\n\n--- Generate winconfig for static floating window\n---\n--- This will result into floating window statically covering whole target\n--- window.\n---\n---@param opts __animate_winconfig_opts_common\n---   - <n_steps> `(number)` - number of output steps, all with same config.\n---     Useful to tweak smoothness of transparency animation (done inside\n---     `winblend` config option). Default: 25.\n---\n---@return __animate_winconfig_return\nMiniAnimate.gen_winconfig.static = function(opts)\n  opts = vim.tbl_deep_extend('force', { predicate = H.default_winconfig_predicate, n_steps = 25 }, opts or {})\n\n  return function(win_id) return H.winconfig_static(win_id, opts) end\nend\n\n--- Generate winconfig for center-focused animated floating window\n---\n--- This will result into floating window growing from or shrinking to the\n--- target window center.\n---\n---@param opts __animate_winconfig_opts_common\n---   - <direction> `(string)` - one of `\"to_center\"` (default; window will\n---     shrink from full coverage to center) or `\"from_center\"` (window will\n---     grow from center to full coverage).\n---\n---@return __animate_winconfig_return\nMiniAnimate.gen_winconfig.center = function(opts)\n  opts = opts or {}\n  local predicate = opts.predicate or H.default_winconfig_predicate\n  local direction = opts.direction or 'to_center'\n\n  return function(win_id)\n    -- Don't animate in case of false predicate\n    if not predicate(win_id) then return {} end\n\n    local pos = vim.fn.win_screenpos(win_id)\n    local row, col = pos[1] - 1, pos[2] - 1\n    local height, width = vim.api.nvim_win_get_height(win_id), vim.api.nvim_win_get_width(win_id)\n\n    local n_steps = math.max(height, width)\n    local res = {}\n    -- Progression should be between fully covering target window and minimal\n    -- dimensions in target window center.\n    for i = 1, n_steps do\n      local coef = (i - 1) / n_steps\n\n      -- Reverse output if progression is from center\n      local res_ind = direction == 'to_center' and i or (n_steps - i + 1)\n\n      --stylua: ignore\n      res[res_ind] = {\n        relative  = 'editor',\n        anchor    = 'NW',\n        row       = H.round(row + 0.5 * coef * height),\n        col       = H.round(col + 0.5 * coef * width),\n        width     = math.ceil((1 - coef) * width),\n        height    = math.ceil((1 - coef) * height),\n        focusable = false,\n        zindex    = 1,\n        border    = 'none',\n        style     = 'minimal',\n      }\n    end\n\n    return res\n  end\nend\n\n--- Generate winconfig for wiping animated floating window\n---\n--- This will result into floating window growing from or shrinking to the\n--- nearest edge. This also takes into account the split type of target window:\n--- vertically split window will progress towards vertical edge; horizontally -\n--- towards horizontal.\n---\n---@param opts __animate_winconfig_opts_common\n---   - <direction> `(string)` - one of `\"to_edge\"` (default; window will\n---     shrink from full coverage to nearest edge) or `\"from_edge\"` (window\n---     will grow from edge to full coverage).\n---\n---@return __animate_winconfig_return\nMiniAnimate.gen_winconfig.wipe = function(opts)\n  opts = opts or {}\n  local predicate = opts.predicate or H.default_winconfig_predicate\n  local direction = opts.direction or 'to_edge'\n\n  return function(win_id)\n    -- Don't animate in case of false predicate\n    if not predicate(win_id) then return {} end\n\n    -- Get window data\n    local win_pos = vim.fn.win_screenpos(win_id)\n    local top_row, left_col = win_pos[1], win_pos[2]\n    local win_height, win_width = vim.api.nvim_win_get_height(win_id), vim.api.nvim_win_get_width(win_id)\n\n    -- Compute progression data\n    local cur_row, cur_col = top_row, left_col\n    local cur_width, cur_height = win_width, win_height\n\n    local increment_row, increment_col, increment_height, increment_width\n    local n_steps\n\n    local win_container = H.get_window_parent_container(win_id)\n    --stylua: ignore\n    if win_container == 'col' then\n      -- Determine closest top/bottom screen edge and progress to it\n      local bottom_row = top_row + win_height - 1\n      local is_top_edge_closer = top_row < (vim.o.lines - bottom_row + 1)\n\n      increment_row,   increment_col    = (is_top_edge_closer and 0 or 1), 0\n      increment_width, increment_height = 0,                               -1\n      n_steps = win_height\n    else\n      -- Determine closest left/right screen edge and progress to it\n      local right_col = left_col + win_width - 1\n      local is_left_edge_closer = left_col < (vim.o.columns - right_col + 1)\n\n      increment_row,   increment_col    =  0, (is_left_edge_closer and 0 or 1)\n      increment_width, increment_height = -1, 0\n      n_steps = win_width\n    end\n\n    -- Make step configs\n    local res = {}\n    for i = 1, n_steps do\n      -- Reverse output if progression is from edge\n      local res_ind = direction == 'to_edge' and i or (n_steps - i + 1)\n      res[res_ind] = {\n        relative = 'editor',\n        anchor = 'NW',\n        row = cur_row - 1,\n        col = cur_col - 1,\n        width = cur_width,\n        height = cur_height,\n        focusable = false,\n        zindex = 1,\n        border = 'none',\n        style = 'minimal',\n      }\n      cur_row = cur_row + increment_row\n      cur_col = cur_col + increment_col\n      cur_height = cur_height + increment_height\n      cur_width = cur_width + increment_width\n    end\n    return res\n  end\nend\n\n--- Generate open/close animation `winblend` progression\n---\n--- For more information see |MiniAnimate.config.open| or |MiniAnimate.config.close|.\n---\n--- This is a table with function elements. Call to actually get transparency\n--- function.\n---\n--- Example: >lua\n---\n---   local animate = require('mini.animate')\n---   animate.setup({\n---     open = {\n---       -- Change transparency from 60 to 80 instead of default 80 to 100\n---       winblend = animate.gen_winblend.linear({ from = 60, to = 80 }),\n---     },\n---     close = {\n---       -- Change transparency from 60 to 80 instead of default 80 to 100\n---       winblend = animate.gen_winblend.linear({ from = 60, to = 80 }),\n---     },\n---   })\n--- <\nMiniAnimate.gen_winblend = {}\n\n--- Generate linear `winblend` progression\n---\n---@param opts table|nil Options that control generator. Possible keys:\n---   - <from> `(number)` - initial value of 'winblend'.\n---   - <to> `(number)` - final value of 'winblend'.\n---\n---@return function Winblend function (see |MiniAnimate.config.open|\n---   or |MiniAnimate.config.close|).\nMiniAnimate.gen_winblend.linear = function(opts)\n  opts = opts or {}\n  local from = opts.from or 80\n  local to = opts.to or 100\n  local diff = to - from\n\n  return function(s, n) return from + (s / n) * diff end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniAnimate.config)\n\n-- Cache for various operations\nH.cache = {\n  -- Cursor move animation data\n  cursor_event_id = 0,\n  cursor_is_active = false,\n  cursor_state = { buf_id = nil, pos = {} },\n\n  -- Scroll animation data\n  scroll_event_id = 0,\n  scroll_is_active = false,\n  scroll_state = { buf_id = nil, win_id = nil, view = {}, cursor = {} },\n\n  -- Resize animation data\n  resize_event_id = 0,\n  resize_is_active = false,\n  resize_state = { layout = {}, sizes = {}, views = {} },\n\n  -- Window open animation data\n  open_event_id = 0,\n  open_is_active = false,\n  open_active_windows = {},\n\n  -- Window close animation data\n  close_event_id = 0,\n  close_is_active = false,\n  close_active_windows = {},\n}\n\n-- Namespaces for module operations\nH.ns_id = {\n  -- Extmarks used to show cursor path\n  cursor = vim.api.nvim_create_namespace('MiniAnimateCursor'),\n}\n\n-- Identifier of empty buffer used inside open/close animations\nH.empty_buf_id = nil\n\n-- Names of `User` events triggered after certain type of animation is done\nH.animation_done_events = {\n  cursor = 'MiniAnimateDoneCursor',\n  scroll = 'MiniAnimateDoneScroll',\n  resize = 'MiniAnimateDoneResize',\n  open = 'MiniAnimateDoneOpen',\n  close = 'MiniAnimateDoneClose',\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('cursor', config.cursor, 'table')\n  H.check_type('cursor.enable', config.cursor.enable, 'boolean')\n  H.check_type('cursor.timing', config.cursor.timing, 'callable')\n  H.check_type('cursor.path', config.cursor.path, 'callable')\n\n  H.check_type('scroll', config.scroll, 'table')\n  H.check_type('scroll.enable', config.scroll.enable, 'boolean')\n  H.check_type('scroll.timing', config.scroll.timing, 'callable')\n  H.check_type('scroll.subscroll', config.scroll.subscroll, 'callable')\n\n  H.check_type('resize', config.resize, 'table')\n  H.check_type('resize.enable', config.resize.enable, 'boolean')\n  H.check_type('resize.timing', config.resize.timing, 'callable')\n  H.check_type('resize.subresize', config.resize.subresize, 'callable')\n\n  H.check_type('open', config.open, 'table')\n  H.check_type('open.enable', config.open.enable, 'boolean')\n  H.check_type('open.timing', config.open.timing, 'callable')\n  H.check_type('open.winconfig', config.open.winconfig, 'callable')\n  H.check_type('open.winblend', config.open.winblend, 'callable')\n\n  H.check_type('close', config.close, 'table')\n  H.check_type('close.enable', config.close.enable, 'boolean')\n  H.check_type('close.timing', config.close.timing, 'callable')\n  H.check_type('close.winconfig', config.close.winconfig, 'callable')\n  H.check_type('close.winblend', config.close.winblend, 'callable')\n\n  return config\nend\n\nH.apply_config = function(config) MiniAnimate.config = config end\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniAnimate', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('CursorMoved', '*', H.auto_cursor, 'Animate cursor')\n\n  au('WinScrolled', '*', function()\n    -- Inside `WinScrolled` first animate resize before scroll to avoid flicker\n    H.auto_resize()\n    H.auto_scroll()\n  end, 'Animate resize and animate scroll')\n  -- Track scroll state on buffer and window enter to animate its first scroll.\n  -- Use `vim.schedule_wrap()` to allow other immediate commands to change view\n  -- (like builtin cursor center on buffer change) to avoid unnecessary\n  -- animated scroll.\n  au({ 'BufEnter', 'WinEnter' }, '*', vim.schedule_wrap(H.track_scroll_state), 'Track scroll state')\n  -- Track immediately scroll state after leaving terminal mode. Otherwise it\n  -- will lead to scroll animation starting at latest non-Terminal mode view.\n  au('TermLeave', '*', H.track_scroll_state, 'Track scroll state')\n  -- Track scroll state (partially) on every cursor move to keep cursor\n  -- position up to date. This enables visually better cursor positioning\n  -- during scroll animation (convex progression from start cursor position to\n  -- end). Use `vim.schedule()` to make it affect state only after scroll is\n  -- done and cursor is already in correct final position.\n  au('CursorMoved', '*', vim.schedule_wrap(H.track_scroll_state_partial), 'Track partial scroll state')\n  au('CmdlineLeave', '*', H.on_cmdline_leave, 'On CmdlineLeave')\n\n  -- Use `vim.schedule_wrap()` animation to get a window data used for\n  -- displaying (and not one after just opening). Useful for 'nvim-tree'.\n  au('WinNew', '*', vim.schedule_wrap(function() H.auto_openclose('open') end), 'Animate window open')\n\n  au('WinClosed', '*', function() H.auto_openclose('close') end, 'Animate window close')\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\nH.create_default_hl = function()\n  vim.api.nvim_set_hl(0, 'MiniAnimateCursor', { default = true, reverse = true, nocombine = true })\n  vim.api.nvim_set_hl(0, 'MiniAnimateNormalFloat', { default = true, link = 'NormalFloat' })\nend\n\nH.is_disabled = function() return vim.g.minianimate_disable == true or vim.b.minianimate_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniAnimate.config, vim.b.minianimate_config or {}, config or {})\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_cursor = function()\n  -- Don't animate if disabled\n  local cursor_config = H.get_config().cursor\n  if not cursor_config.enable or H.is_disabled() then\n    -- Reset state to not use an outdated one if enabled again\n    H.cache.cursor_state = { buf_id = nil, pos = {} }\n    return\n  end\n\n  -- Don't animate if inside scroll animation\n  if H.cache.scroll_is_active then return end\n\n  -- Update necessary information. NOTE: update state only on `CursorMoved` and\n  -- not inside every animation step (like in scroll animation) for performance\n  -- reasons: cursor movement is much more common action than scrolling.\n  local prev_state, new_state = H.cache.cursor_state, H.get_cursor_state()\n  H.cache.cursor_state = new_state\n  H.cache.cursor_event_id = H.cache.cursor_event_id + 1\n\n  -- Don't animate if changed buffer\n  if new_state.buf_id ~= prev_state.buf_id then return end\n\n  -- Make animation step data and possibly animate\n  local animate_step = H.make_cursor_step(prev_state, new_state, cursor_config)\n  if not animate_step then return end\n\n  H.start_cursor()\n  MiniAnimate.animate(animate_step.step_action, animate_step.step_timing)\nend\n\nH.auto_resize = function()\n  -- Don't animate if disabled\n  local resize_config = H.get_config().resize\n  if not resize_config.enable or H.is_disabled() then\n    -- Reset state to not use an outdated one if enabled again\n    H.cache.resize_state = { layout = {}, sizes = {}, views = {} }\n    return\n  end\n\n  -- Don't animate if inside scroll animation. This reduces computations and\n  -- occasional flickering.\n  if H.cache.scroll_is_active then return end\n\n  -- Update state. This also ensures that window views are up to date.\n  local prev_state, new_state = H.cache.resize_state, H.get_resize_state()\n  H.cache.resize_state = new_state\n\n  -- Don't animate if there is nothing to animate (should be same layout but\n  -- different sizes). This also stops triggering animation on window scrolls.\n  local same_state = H.is_equal_resize_state(prev_state, new_state)\n  if not (same_state.layout and not same_state.sizes) then return end\n\n  -- Register new event only in case there is something to animate\n  H.cache.resize_event_id = H.cache.resize_event_id + 1\n\n  -- Make animation step data and possibly animate\n  local animate_step = H.make_resize_step(prev_state, new_state, resize_config)\n  if not animate_step then return end\n\n  H.start_resize(prev_state)\n  MiniAnimate.animate(animate_step.step_action, animate_step.step_timing)\nend\n\nH.auto_scroll = function()\n  -- Don't animate if disabled\n  local scroll_config = H.get_config().scroll\n  if not scroll_config.enable or H.is_disabled() then\n    -- Reset state to not use an outdated one if enabled again\n    H.cache.scroll_state = { buf_id = nil, win_id = nil, view = {}, cursor = {} }\n    return\n  end\n\n  -- Get states\n  local prev_state, new_state = H.cache.scroll_state, H.get_scroll_state()\n\n  -- Don't animate if nothing to animate. Mostly used to distinguish\n  -- `WinScrolled` resulting from module animation from the other ones.\n  local is_same_bufwin = new_state.buf_id == prev_state.buf_id and new_state.win_id == prev_state.win_id\n  local is_same_topline = new_state.view.topline == prev_state.view.topline\n  if is_same_topline and is_same_bufwin then return end\n\n  -- Update necessary information\n  H.cache.scroll_state = new_state\n  H.cache.scroll_event_id = H.cache.scroll_event_id + 1\n\n  -- Don't animate if changed buffer or window\n  if not is_same_bufwin then return end\n\n  -- Don't animate if inside resize animation. This reduces computations and\n  -- occasional flickering.\n  if H.cache.resize_is_active then return end\n\n  -- Make animation step data and possibly animate\n  local animate_step = H.make_scroll_step(prev_state, new_state, scroll_config)\n  if not animate_step then return end\n\n  H.start_scroll(prev_state)\n  MiniAnimate.animate(animate_step.step_action, animate_step.step_timing)\nend\n\nH.track_scroll_state = function() H.cache.scroll_state = H.get_scroll_state() end\n\nH.track_scroll_state_partial = function()\n  -- This not only improves computation load, but seems to be crucial for\n  -- a proper state tracking\n  if H.cache.scroll_is_active then return end\n\n  H.cache.scroll_state.cursor = { line = vim.fn.line('.'), virtcol = vim.fn.virtcol('.') }\nend\n\nH.on_cmdline_leave = function()\n  local cmd_type = vim.fn.getcmdtype()\n  local is_insearch = vim.o.incsearch and (cmd_type == '/' or cmd_type == '?')\n  if not is_insearch then return end\n\n  -- Update scroll state so that there is no scroll animation after confirming\n  -- incremental search. Otherwise it leads to unnecessary animation from\n  -- initial scroll state to the one **already shown**.\n  H.track_scroll_state()\nend\n\nH.auto_openclose = function(action_type)\n  action_type = action_type or 'open'\n\n  -- Don't animate if disabled\n  local config = H.get_config()[action_type]\n  if not config.enable or H.is_disabled() then return end\n\n  -- Get window id to act upon\n  local win_id\n  if action_type == 'close' then win_id = tonumber(vim.fn.expand('<amatch>')) end\n  if action_type == 'open' then win_id = math.max(unpack(vim.api.nvim_list_wins())) end\n\n  -- Don't animate if created window is not right (valid and not floating)\n  if win_id == nil or not vim.api.nvim_win_is_valid(win_id) then return end\n  if vim.api.nvim_win_get_config(win_id).relative ~= '' then return end\n\n  -- Register new event only in case there is something to animate\n  local event_id_name = action_type .. '_event_id'\n  H.cache[event_id_name] = H.cache[event_id_name] + 1\n\n  -- Make animation step data and possibly animate\n  local animate_step = H.make_openclose_step(action_type, win_id, config)\n  if not animate_step then return end\n\n  H.start_openclose(action_type)\n  MiniAnimate.animate(animate_step.step_action, animate_step.step_timing)\nend\n\n-- General animation ----------------------------------------------------------\nH.trigger_done_event = function(animation_type) vim.cmd('doautocmd User ' .. H.animation_done_events[animation_type]) end\n\n-- Cursor ---------------------------------------------------------------------\nH.make_cursor_step = function(state_from, state_to, opts)\n  local pos_from, pos_to = state_from.pos, state_to.pos\n  local destination = { pos_to[1] - pos_from[1], pos_to[2] - pos_from[2] }\n  local path = opts.path(destination)\n  if path == nil or #path == 0 then return end\n\n  local n_steps = #path\n  local timing = opts.timing\n\n  -- Using explicit buffer id allows correct animation stop after buffer switch\n  local event_id, buf_id = H.cache.cursor_event_id, state_from.buf_id\n\n  return {\n    step_action = function(step)\n      -- Undraw previous mark. Doing it before early return allows to clear\n      -- last animation mark.\n      H.undraw_cursor_mark(buf_id)\n\n      -- Stop animation if another cursor movement is active. Don't use\n      -- `stop_cursor()` because it will also stop parallel animation.\n      if H.cache.cursor_event_id ~= event_id then return false end\n\n      -- Don't draw outside of set number of steps or not inside current buffer\n      if n_steps <= step or vim.api.nvim_get_current_buf() ~= buf_id then return H.stop_cursor() end\n\n      -- Draw cursor mark (starting from initial zero step)\n      local pos = path[step + 1]\n      H.draw_cursor_mark(pos_from[1] + pos[1], pos_from[2] + pos[2], buf_id)\n      return true\n    end,\n    step_timing = function(step) return timing(step, n_steps) end,\n  }\nend\n\nH.get_cursor_state = function()\n  -- Use virtual column to respect position outside of line width and tabs\n  return { buf_id = vim.api.nvim_get_current_buf(), pos = { vim.fn.line('.'), vim.fn.virtcol('.') } }\nend\n\nH.draw_cursor_mark = function(line, virt_col, buf_id)\n  -- Use only absolute coordinates. Allows to not draw outside of buffer.\n  if line <= 0 or virt_col <= 0 then return end\n\n  -- Compute window column at which to place mark. Don't use explicit `col`\n  -- argument because it won't allow placing mark outside of text line.\n  local win_col = virt_col - vim.fn.winsaveview().leftcol\n  if win_col < 1 then return end\n\n  -- Set extmark\n  local extmark_opts = {\n    id = 1,\n    hl_mode = 'combine',\n    priority = 1000,\n    right_gravity = false,\n    virt_text = { { ' ', 'MiniAnimateCursor' } },\n    virt_text_win_col = win_col - 1,\n    virt_text_pos = 'overlay',\n  }\n  pcall(vim.api.nvim_buf_set_extmark, buf_id, H.ns_id.cursor, line - 1, 0, extmark_opts)\nend\n\nH.undraw_cursor_mark = function(buf_id) pcall(vim.api.nvim_buf_del_extmark, buf_id, H.ns_id.cursor, 1) end\n\nH.start_cursor = function()\n  H.cache.cursor_is_active = true\n  return true\nend\n\nH.stop_cursor = function()\n  H.cache.cursor_is_active = false\n  H.trigger_done_event('cursor')\n  return false\nend\n\n-- Scroll ---------------------------------------------------------------------\nH.make_scroll_step = function(state_from, state_to, opts)\n  -- Do not animate in Select mode because it resets it\n  local is_select_mode = ({ s = true, S = true, ['\\19'] = true })[vim.fn.mode()]\n  if is_select_mode then return end\n\n  -- Compute how subscrolling is done\n  local from_line, to_line = state_from.view.topline, state_to.view.topline\n  local total_scroll = H.get_n_visible_lines(from_line, to_line) - 1\n  local step_scrolls = opts.subscroll(total_scroll)\n\n  -- Don't animate if no subscroll steps is returned\n  if step_scrolls == nil or #step_scrolls == 0 then return end\n\n  -- Compute scrolling key ('\\25' and '\\5' are escaped '<C-Y>' and '<C-E>')\n  local scroll_key = from_line < to_line and '\\5' or '\\25'\n\n  -- Cache frequently accessed data\n  local from_cur_line, to_cur_line = state_from.cursor.line, state_to.cursor.line\n  local from_cur_virtcol, to_cur_virtcol = state_from.cursor.virtcol, state_to.cursor.virtcol\n\n  local event_id, buf_id, win_id = H.cache.scroll_event_id, state_from.buf_id, state_from.win_id\n  local n_steps, timing = #step_scrolls, opts.timing\n\n  return {\n    step_action = function(step)\n      -- Stop animation if another scroll is active. Don't use `stop_scroll()`\n      -- because it will stop parallel animation.\n      if H.cache.scroll_event_id ~= event_id then return false end\n\n      -- Stop animation if jumped to different buffer or window. Don't restore\n      -- window view as it can only operate on current window.\n      local is_same_win_buf = vim.api.nvim_get_current_buf() == buf_id and vim.api.nvim_get_current_win() == win_id\n      if not is_same_win_buf then return H.stop_scroll() end\n\n      -- Compute intermediate cursor position. This relies on `virtualedit=all`\n      -- to be able to place cursor anywhere on screen (has better animation;\n      -- at least for default equally spread subscrolls).\n      local coef = step / n_steps\n      local cursor_line = H.convex_point(from_cur_line, to_cur_line, coef)\n      local cursor_virtcol = H.convex_point(from_cur_virtcol, to_cur_virtcol, coef)\n      local cursor_data = { line = cursor_line, virtcol = cursor_virtcol }\n\n      -- Perform scroll. Possibly stop on error.\n      local ok, _ = pcall(H.scroll_action, scroll_key, step_scrolls[step], cursor_data)\n      if not ok then return H.stop_scroll(state_to) end\n\n      -- Update current scroll state for two reasons:\n      -- - Be able to distinguish manual `WinScrolled` event from one created\n      --   by `H.scroll_action()`.\n      -- - Be able to start manual scrolling at any animation step.\n      H.cache.scroll_state = H.get_scroll_state()\n\n      -- Properly stop animation if step is too big\n      if n_steps <= step then return H.stop_scroll(state_to) end\n\n      return true\n    end,\n    step_timing = function(step) return timing(step, n_steps) end,\n  }\nend\n\nH.scroll_action = function(key, n, cursor_data)\n  -- Scroll. Allow supplying non-valid `n` for initial \"scroll\" which sets\n  -- cursor immediately, which reduces flicker.\n  if n ~= nil and n > 0 then\n    local command = string.format('normal! %d%s', n, key)\n    vim.cmd(command)\n  end\n\n  -- Set cursor to properly handle cursor position\n  -- Computation of available top/bottom line depends on `scrolloff = 0`\n  -- because otherwise it will go out of bounds causing scroll overshoot with\n  -- later \"bounce\" back on view restore (see\n  -- https://github.com/nvim-mini/mini.nvim/issues/177).\n  local top, bottom = vim.fn.line('w0'), vim.fn.line('w$')\n  local line = math.min(math.max(cursor_data.line, top), bottom)\n\n  -- Cursor can only be set using byte column. To place it in the most correct\n  -- virtual column, tweak output of `virtcol2col()`\n  local virtcol = cursor_data.virtcol\n  local col = vim.fn.virtcol2col(0, line, virtcol)\n  -- - Correct for virtual column being outside of line's last virtual column\n  local virtcol_past_lineend = vim.fn.virtcol({ line, '$' })\n  if virtcol_past_lineend <= virtcol then col = col + virtcol - virtcol_past_lineend + 1 end\n\n  pcall(vim.api.nvim_win_set_cursor, 0, { line, col - 1 })\nend\n\nH.start_scroll = function(start_state)\n  H.cache.scroll_is_active = true\n  -- Disable scrolloff in order to be able to place cursor on top/bottom window\n  -- line inside scroll step.\n  -- Incorporating `vim.wo.scrolloff` in computation of available top and\n  -- bottom window lines works, but only in absence of folds. It gets tricky\n  -- otherwise, so disabling on scroll start and restore on scroll end is\n  -- better solution.\n  vim.wo.scrolloff = 0\n  -- Allow placing cursor anywhere on screen for better cursor placing\n  vim.wo.virtualedit = 'all'\n\n  if start_state ~= nil then\n    vim.fn.winrestview(start_state.view)\n    -- Track state because `winrestview()` later triggers `WinScrolled`.\n    -- Otherwise mapping like `u<Cmd>lua _G.n = 0<CR>` (as in 'mini.bracketed')\n    -- can result into \"inverted scroll\": from destination to current state.\n    H.track_scroll_state()\n  end\n\n  return true\nend\n\nH.stop_scroll = function(end_state)\n  if end_state ~= nil then\n    vim.fn.winrestview(end_state.view)\n    H.track_scroll_state()\n  end\n\n  vim.wo.scrolloff = end_state.scrolloff\n  vim.wo.virtualedit = end_state.virtualedit\n\n  H.cache.scroll_is_active = false\n  H.trigger_done_event('scroll')\n\n  return false\nend\n\nH.get_scroll_state = function()\n  return {\n    buf_id = vim.api.nvim_get_current_buf(),\n    win_id = vim.api.nvim_get_current_win(),\n    view = vim.fn.winsaveview(),\n    cursor = { line = vim.fn.line('.'), virtcol = vim.fn.virtcol('.') },\n    scrolloff = H.cache.scroll_is_active and H.cache.scroll_state.scrolloff or vim.wo.scrolloff,\n    virtualedit = H.cache.scroll_is_active and H.cache.scroll_state.virtualedit or vim.wo.virtualedit,\n  }\nend\n\n-- Resize ---------------------------------------------------------------------\nH.make_resize_step = function(state_from, state_to, opts)\n  -- Compute number of animation steps\n  local step_sizes = opts.subresize(state_from.sizes, state_to.sizes)\n  if step_sizes == nil or #step_sizes == 0 then return end\n  local n_steps = #step_sizes\n\n  -- Create animation step\n  local event_id, timing = H.cache.resize_event_id, opts.timing\n\n  return {\n    step_action = function(step)\n      -- Do nothing on initialization\n      if step == 0 then return true end\n\n      -- Stop animation if another resize animation is active. Don't use\n      -- `stop_resize()` because it will also stop parallel animation.\n      if H.cache.resize_event_id ~= event_id then return false end\n\n      -- Perform animation. Possibly stop on error.\n      -- Use `false` to not restore cursor position to avoid horizontal flicker\n      local ok, _ = pcall(H.apply_resize_state, { sizes = step_sizes[step] }, false)\n      if not ok then return H.stop_resize(state_to) end\n\n      -- Properly stop animation if step is too big\n      if n_steps <= step then return H.stop_resize(state_to) end\n\n      return true\n    end,\n    step_timing = function(step) return timing(step, n_steps) end,\n  }\nend\n\nH.start_resize = function(start_state)\n  H.cache.resize_is_active = true\n  -- Don't restore cursor position to avoid horizontal flicker\n  if start_state ~= nil then H.apply_resize_state(start_state, false) end\n  return true\nend\n\nH.stop_resize = function(end_state)\n  if end_state ~= nil then H.apply_resize_state(end_state, true) end\n  H.cache.resize_is_active = false\n  H.trigger_done_event('resize')\n  return false\nend\n\nH.get_resize_state = function()\n  local layout = vim.fn.winlayout()\n\n  local windows = H.get_layout_windows(layout)\n  local sizes, views = {}, {}\n  for _, win_id in ipairs(windows) do\n    sizes[win_id] = { height = vim.api.nvim_win_get_height(win_id), width = vim.api.nvim_win_get_width(win_id) }\n    views[win_id] = vim.api.nvim_win_call(win_id, function() return vim.fn.winsaveview() end)\n  end\n\n  return { layout = layout, sizes = sizes, views = views }\nend\n\nH.is_equal_resize_state = function(state_1, state_2)\n  return {\n    layout = vim.deep_equal(state_1.layout, state_2.layout),\n    sizes = vim.deep_equal(state_1.sizes, state_2.sizes),\n  }\nend\n\nH.get_layout_windows = function(layout)\n  local res = {}\n  local traverse\n  traverse = function(l)\n    if l[1] == 'leaf' then\n      table.insert(res, l[2])\n      return\n    end\n    for _, sub_l in ipairs(l[2]) do\n      traverse(sub_l)\n    end\n  end\n  traverse(layout)\n\n  return res\nend\n\nH.apply_resize_state = function(state, full_view)\n  -- Set window sizes while ensuring that 'cmdheight' will not change. Can\n  -- happen if changing height of window main row layout or increase terminal\n  -- height quickly (see #270)\n  local cache_cmdheight = vim.o.cmdheight\n\n  for win_id, dims in pairs(state.sizes) do\n    vim.api.nvim_win_set_height(win_id, dims.height)\n    vim.api.nvim_win_set_width(win_id, dims.width)\n  end\n\n  vim.o.cmdheight = cache_cmdheight\n\n  -- Use `or {}` to allow states without `view` (mainly inside animation)\n  for win_id, view in pairs(state.views or {}) do\n    vim.api.nvim_win_call(win_id, function()\n      -- Allow to not restore full view. It mainly solves horizontal flickering\n      -- when resizing from small to big width and cursor is on the end of long\n      -- line. This is especially visible for high 'winwidth'.\n      -- Example: `set winwidth=120 winheight=40` and hop between two\n      -- vertically split windows with cursor on `$` of long line.\n      if full_view then\n        vim.fn.winrestview(view)\n        return\n      end\n\n      -- This triggers `CursorMoved` event, but nothing can be done\n      -- (`noautocmd` is of no use, see https://github.com/vim/vim/issues/2084)\n      pcall(vim.api.nvim_win_set_cursor, win_id, { view.lnum, view.leftcol })\n      vim.fn.winrestview({ topline = view.topline, leftcol = view.leftcol })\n    end)\n  end\n\n  -- Update current resize state to be able to start another resize animation\n  -- at any current animation step. Recompute state to also capture `view`.\n  H.cache.resize_state = H.get_resize_state()\nend\n\n-- Open/close -----------------------------------------------------------------\nH.make_openclose_step = function(action_type, win_id, config)\n  -- Compute winconfig progression\n  local step_winconfigs = config.winconfig(win_id)\n  if step_winconfigs == nil or #step_winconfigs == 0 then return end\n\n  -- Produce animation steps.\n  local n_steps, event_id_name = #step_winconfigs, action_type .. '_event_id'\n  local timing, winblend, event_id = config.timing, config.winblend, H.cache[event_id_name]\n  local float_win_id\n\n  return {\n    step_action = function(step)\n      -- Stop animation if another similar animation is active. Don't use\n      -- `stop_openclose()` because it will also stop parallel animation.\n      if H.cache[event_id_name] ~= event_id then\n        pcall(vim.api.nvim_win_close, float_win_id, true)\n        return false\n      end\n\n      -- Stop animation if exceeded number of steps\n      if n_steps <= step then\n        pcall(vim.api.nvim_win_close, float_win_id, true)\n        return H.stop_openclose(action_type)\n      end\n\n      -- Empty buffer should always be valid (might have been closed by user command)\n      if H.empty_buf_id == nil or not vim.api.nvim_buf_is_valid(H.empty_buf_id) then\n        H.empty_buf_id = vim.api.nvim_create_buf(false, true)\n        H.set_buf_name(H.empty_buf_id, 'open-close-scratch')\n      end\n\n      -- Set step config to window. Possibly (re)open (it could have been\n      -- manually closed like after `:only`)\n      local float_config = step_winconfigs[step + 1]\n      if step == 0 or not vim.api.nvim_win_is_valid(float_win_id) then\n        float_win_id = vim.api.nvim_open_win(H.empty_buf_id, false, float_config)\n        vim.wo[float_win_id].winhighlight = 'Normal:MiniAnimateNormalFloat'\n      else\n        vim.api.nvim_win_set_config(float_win_id, float_config)\n      end\n\n      vim.wo[float_win_id].winblend = H.round(winblend(step, n_steps))\n\n      return true\n    end,\n    step_timing = function(step) return timing(step, n_steps) end,\n  }\nend\n\nH.start_openclose = function(action_type)\n  H.cache[action_type .. '_is_active'] = true\n  return true\nend\n\nH.stop_openclose = function(action_type)\n  H.cache[action_type .. '_is_active'] = false\n  H.trigger_done_event(action_type)\n  return false\nend\n\n-- Animation timings ----------------------------------------------------------\nH.normalize_timing_opts = function(x)\n  x = vim.tbl_deep_extend('force', H.get_config(), { easing = 'in-out', duration = 20, unit = 'step' }, x or {})\n  H.validate_if(H.is_valid_timing_opts, x, 'opts')\n  return x\nend\n\nH.is_valid_timing_opts = function(x)\n  if type(x.duration) ~= 'number' or x.duration < 0 then\n    return false, [[In `gen_timing` option `duration` should be a positive number.]]\n  end\n\n  if not vim.tbl_contains({ 'in', 'out', 'in-out' }, x.easing) then\n    return false, [[In `gen_timing` option `easing` should be one of 'in', 'out', or 'in-out'.]]\n  end\n\n  if not vim.tbl_contains({ 'total', 'step' }, x.unit) then\n    return false, [[In `gen_timing` option `unit` should be one of 'step' or 'total'.]]\n  end\n\n  return true\nend\n\n--- Imitate common power easing function\n---\n--- Every step is preceded by waiting time decreasing/increasing in power\n--- series fashion (`d` is \"delta\", ensures total duration time):\n--- - \"in\":  d*n^p; d*(n-1)^p; ... ; d*2^p;     d*1^p\n--- - \"out\": d*1^p; d*2^p;     ... ; d*(n-1)^p; d*n^p\n--- - \"in-out\": \"in\" until 0.5*n, \"out\" afterwards\n---\n--- This way it imitates `power + 1` common easing function because animation\n--- progression behaves as sum of `power` elements.\n---\n---@param power number Power of series.\n---@param opts table Options from `MiniAnimate.gen_timing` entry.\n---@private\nH.timing_arithmetic = function(power, opts)\n  -- Sum of first `n_steps` natural numbers raised to `power`\n  local arith_power_sum = ({\n    [0] = function(n_steps) return n_steps end,\n    [1] = function(n_steps) return n_steps * (n_steps + 1) / 2 end,\n    [2] = function(n_steps) return n_steps * (n_steps + 1) * (2 * n_steps + 1) / 6 end,\n    [3] = function(n_steps) return n_steps ^ 2 * (n_steps + 1) ^ 2 / 4 end,\n  })[power]\n\n  -- Function which computes common delta so that overall duration will have\n  -- desired value (based on supplied `opts`)\n  local duration_unit, duration_value = opts.unit, opts.duration\n  local make_delta = function(n_steps, is_in_out)\n    local total_time = duration_unit == 'total' and duration_value or (duration_value * n_steps)\n    local total_parts\n    if is_in_out then\n      -- Examples:\n      -- - n_steps=5: 3^d, 2^d, 1^d, 2^d, 3^d\n      -- - n_steps=6: 3^d, 2^d, 1^d, 1^d, 2^d, 3^d\n      total_parts = 2 * arith_power_sum(math.ceil(0.5 * n_steps)) - (n_steps % 2 == 1 and 1 or 0)\n    else\n      total_parts = arith_power_sum(n_steps)\n    end\n    return total_time / total_parts\n  end\n\n  return ({\n    ['in'] = function(s, n) return make_delta(n) * (n - s + 1) ^ power end,\n    ['out'] = function(s, n) return make_delta(n) * s ^ power end,\n    ['in-out'] = function(s, n)\n      local n_half = math.ceil(0.5 * n)\n      local s_halved\n      if n % 2 == 0 then\n        s_halved = s <= n_half and (n_half - s + 1) or (s - n_half)\n      else\n        s_halved = s < n_half and (n_half - s + 1) or (s - n_half + 1)\n      end\n      return make_delta(n, true) * s_halved ^ power\n    end,\n  })[opts.easing]\nend\n\n--- Imitate common exponential easing function\n---\n--- Every step is preceded by waiting time decreasing/increasing in geometric\n--- progression fashion (`d` is 'delta', ensures total duration time):\n--- - 'in':  (d-1)*d^(n-1); (d-1)*d^(n-2); ...; (d-1)*d^1;     (d-1)*d^0\n--- - 'out': (d-1)*d^0;     (d-1)*d^1;     ...; (d-1)*d^(n-2); (d-1)*d^(n-1)\n--- - 'in-out': 'in' until 0.5*n, 'out' afterwards\n---\n---@param opts table Options from `MiniAnimate.gen_timing` entry.\n---@private\nH.timing_geometrical = function(opts)\n  -- Function which computes common delta so that overall duration will have\n  -- desired value (based on supplied `opts`)\n  local duration_unit, duration_value = opts.unit, opts.duration\n  local make_delta = function(n_steps, is_in_out)\n    local total_time = duration_unit == 'step' and (duration_value * n_steps) or duration_value\n    -- Exact solution to avoid possible (bad) approximation\n    if n_steps == 1 then return total_time + 1 end\n    if is_in_out then\n      local n_half = math.ceil(0.5 * n_steps)\n      if n_steps % 2 == 1 then total_time = total_time + math.pow(0.5 * total_time + 1, 1 / n_half) - 1 end\n      return math.pow(0.5 * total_time + 1, 1 / n_half)\n    end\n    return math.pow(total_time + 1, 1 / n_steps)\n  end\n\n  return ({\n    ['in'] = function(s, n)\n      local delta = make_delta(n)\n      return (delta - 1) * delta ^ (n - s)\n    end,\n    ['out'] = function(s, n)\n      local delta = make_delta(n)\n      return (delta - 1) * delta ^ (s - 1)\n    end,\n    ['in-out'] = function(s, n)\n      local n_half, delta = math.ceil(0.5 * n), make_delta(n, true)\n      local s_halved\n      if n % 2 == 0 then\n        s_halved = s <= n_half and (n_half - s) or (s - n_half - 1)\n      else\n        s_halved = s < n_half and (n_half - s) or (s - n_half)\n      end\n      return (delta - 1) * delta ^ s_halved\n    end,\n  })[opts.easing]\nend\n\n-- Animation path -------------------------------------------------------------\nH.path_line = function(destination, opts)\n  -- Don't animate in case of false predicate\n  if not opts.predicate(destination) then return {} end\n\n  -- Travel along the biggest horizontal/vertical difference, but stop one\n  -- step before destination\n  local l, c = destination[1], destination[2]\n  local l_abs, c_abs = math.abs(l), math.abs(c)\n  local max_diff = math.min(math.max(l_abs, c_abs), opts.max_output_steps)\n\n  local res = {}\n  for i = 0, max_diff - 1 do\n    local prop = i / max_diff\n    table.insert(res, { H.round(prop * l), H.round(prop * c) })\n  end\n  return res\nend\n\nH.default_path_predicate = function(destination) return destination[1] < -1 or 1 < destination[1] end\n\n-- Animation subscroll --------------------------------------------------------\nH.subscroll_equal = function(total_scroll, opts)\n  -- Don't animate in case of false predicate\n  if not opts.predicate(total_scroll) then return {} end\n\n  -- Make equal steps, but no more than `max_output_steps`\n  local n_steps = math.min(total_scroll, opts.max_output_steps)\n  local res, coef = {}, total_scroll / n_steps\n  for i = 1, n_steps do\n    res[i] = math.floor(i * coef) - math.floor((i - 1) * coef)\n  end\n  return res\nend\n\nH.default_subscroll_predicate = function(total_scroll) return total_scroll > 1 end\n\n-- Animation subresize --------------------------------------------------------\nH.subresize_equal = function(sizes_from, sizes_to, opts)\n  -- Don't animate in case of false predicate\n  if not opts.predicate(sizes_from, sizes_to) then return {} end\n\n  -- Don't animate single window\n  if #vim.tbl_keys(sizes_from) == 1 then return {} end\n\n  -- Compute number of steps\n  local n_steps = 0\n  for win_id, dims_from in pairs(sizes_from) do\n    local height_absidff = math.abs(sizes_to[win_id].height - dims_from.height)\n    local width_absidff = math.abs(sizes_to[win_id].width - dims_from.width)\n    n_steps = math.max(n_steps, height_absidff, width_absidff)\n  end\n  if n_steps <= 1 then return {} end\n\n  -- Make subresize array\n  local res = {}\n  for i = 1, n_steps do\n    local coef = i / n_steps\n    local sub_res = {}\n    for win_id, dims_from in pairs(sizes_from) do\n      sub_res[win_id] = {\n        height = H.convex_point(dims_from.height, sizes_to[win_id].height, coef),\n        width = H.convex_point(dims_from.width, sizes_to[win_id].width, coef),\n      }\n    end\n    res[i] = sub_res\n  end\n\n  return res\nend\n\nH.default_subresize_predicate = function(sizes_from, sizes_to) return true end\n\n-- Animation winconfig --------------------------------------------------------\nH.winconfig_static = function(win_id, opts)\n  -- Don't animate in case of false predicate\n  if not opts.predicate(win_id) then return {} end\n\n  local pos = vim.fn.win_screenpos(win_id)\n  local width, height = vim.api.nvim_win_get_width(win_id), vim.api.nvim_win_get_height(win_id)\n  local res = {}\n  for i = 1, opts.n_steps do\n      --stylua: ignore\n      res[i] = {\n        relative  = 'editor',\n        anchor    = 'NW',\n        row       = pos[1] - 1,\n        col       = pos[2] - 1,\n        width     = width,\n        height    = height,\n        focusable = false,\n        zindex    = 1,\n        border    = 'none',\n        style     = 'minimal',\n      }\n  end\n  return res\nend\n\nH.get_window_parent_container = function(win_id)\n  local f\n  f = function(layout, parent_container)\n    local container, second = layout[1], layout[2]\n    if container == 'leaf' then\n      if second == win_id then return parent_container end\n      return\n    end\n\n    for _, sub_layout in ipairs(second) do\n      local res = f(sub_layout, container)\n      if res ~= nil then return res end\n    end\n  end\n\n  -- Important to get layout of tabpage window actually belongs to (as it can\n  -- already be not current tabpage)\n  -- NOTE: `winlayout()` takes tabpage number (non unique), not tabpage id\n  local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n  local tabpage_nr = vim.api.nvim_tabpage_get_number(tabpage_id)\n  return f(vim.fn.winlayout(tabpage_nr), 'single')\nend\n\nH.default_winconfig_predicate = function(win_id) return true end\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.animate) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minianimate://' .. buf_id .. '/' .. name) end\n\nH.validate_if = function(predicate, x, x_name)\n  local is_valid, msg = predicate(x, x_name)\n  if not is_valid then H.error(msg) end\nend\n\nH.get_n_visible_lines = function(from_line, to_line)\n  local min_line, max_line = math.min(from_line, to_line), math.max(from_line, to_line)\n\n  -- If `max_line` is inside fold, scrol should stop on the fold (not after)\n  local max_line_fold_start = vim.fn.foldclosed(max_line)\n  local target_line = max_line_fold_start == -1 and max_line or max_line_fold_start\n\n  local i, res = min_line, 1\n  while i < target_line do\n    res = res + 1\n    local end_fold_line = vim.fn.foldclosedend(i)\n    i = (end_fold_line == -1 and i or end_fold_line) + 1\n  end\n  return res\nend\n\nH.round = function(x) return math.floor(x + 0.5) end\n\nH.convex_point = function(x, y, coef) return H.round((1 - coef) * x + coef * y) end\n\nreturn MiniAnimate\n"
  },
  {
    "path": "lua/mini/base16.lua",
    "content": "--- *mini.base16* Base16 colorscheme creation\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Fast implementation of [chriskempson/base16](https://github.com/chriskempson/base16)\n--- color scheme (with Copyright (C) 2012 Chris Kempson) adapted for modern Neovim\n--- Lua plugins. Extra features:\n--- - Configurable automatic support of cterm colors (see |highlight-cterm|).\n--- - Opinionated palette generator based only on background and foreground\n---   colors.\n---\n--- Supported highlight groups:\n--- - Built-in Neovim LSP and diagnostic.\n---\n--- - Plugins (either with explicit definition or by verification that default\n---   highlighting works appropriately):\n---     - [nvim-mini/mini.nvim](https://nvim-mini.org/mini.nvim)\n---     - [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n---     - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n---     - [DanilaMihailov/beacon.nvim](https://github.com/DanilaMihailov/beacon.nvim)\n---     - [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n---     - [folke/noice.nvim](https://github.com/folke/noice.nvim)\n---     - [folke/snacks.nvim](https://github.com/folke/snacks.nvim)\n---     - [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n---     - [folke/trouble.nvim](https://github.com/folke/trouble.nvim)\n---     - [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n---     - [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n---     - [ggandor/lightspeed.nvim](https://github.com/ggandor/lightspeed.nvim)\n---     - [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n---     - [glepnir/lspsaga.nvim](https://github.com/glepnir/lspsaga.nvim)\n---     - [HiPhish/rainbow-delimiters.nvim](https://github.com/HiPhish/rainbow-delimiters.nvim)\n---     - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n---     - [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n---     - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n---     - [kevinhwang91/nvim-bqf](https://github.com/kevinhwang91/nvim-bqf)\n---     - [kevinhwang91/nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n---     - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n---     - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n---     - [MeanderingProgrammer/render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)\n---     - [neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)\n---     - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n---     - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n---     - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n---     - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n---     - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n---     - [OXY2DEV/helpview.nvim](https://github.com/OXY2DEV/helpview.nvim)\n---     - [OXY2DEV/markview.nvim](https://github.com/OXY2DEV/markview.nvim)\n---     - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim)\n---     - [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)\n---     - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n---     - [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n---     - [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n---     - [stevearc/aerial.nvim](https://github.com/stevearc/aerial.nvim)\n---     - [williamboman/mason.nvim](https://github.com/williamboman/mason.nvim)\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.base16').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table\n--- `MiniBase16` which you can use for scripting or manually (with\n--- `:lua MiniBase16.*`).\n---\n--- See |MiniBase16.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minibase16_config`\n--- will have no effect here.\n---\n--- Example: >lua\n---\n---   require('mini.base16').setup({\n---     palette = {\n---       base00 = '#112641',\n---       base01 = '#3a475e',\n---       base02 = '#606b81',\n---       base03 = '#8691a7',\n---       base04 = '#d5dc81',\n---       base05 = '#e2e98f',\n---       base06 = '#eff69c',\n---       base07 = '#fcffaa',\n---       base08 = '#ffcfa0',\n---       base09 = '#cc7e46',\n---       base0A = '#46a436',\n---       base0B = '#9ff895',\n---       base0C = '#ca6ecf',\n---       base0D = '#42f7ff',\n---       base0E = '#ffc4ff',\n---       base0F = '#00a5c5',\n---     },\n---     use_cterm = true,\n---     plugins = {\n---       default = false,\n---       ['nvim-mini/mini.nvim'] = true,\n---     },\n---   })\n--- <\n--- # Notes ~\n---\n--- 1. This is used to create some of plugin's color schemes\n---    (see |MiniBase16-color-schemes|).\n--- 2. Using `setup()` doesn't actually create a |:colorscheme|. It basically\n---    creates a coordinated set of |highlight-groups|. To create your own theme:\n---     - Put \"myscheme.lua\" file (name after your chosen theme name) inside\n---       any \"colors\" directory reachable from 'runtimepath' (\"colors\" inside\n---       your Neovim config directory is usually enough).\n---     - Inside \"myscheme.lua\" call `require('mini.base16').setup()` with your\n---       palette and only after that set |g:colors_name| to \"myscheme\".\n---@tag MiniBase16\n\n--- # Base16 colorschemes ~\n---\n--- This module comes with several pre-built color schemes. Each of them is\n--- a |mini.base16| theme created with faster version of the following Lua code: >lua\n---\n---   require('mini.base16').setup({ palette = palette, use_cterm = true })\n--- <\n--- Activate them as regular |:colorscheme| (for example, `:colorscheme minischeme`).\n---\n--- ## minischeme ~\n--- *minischeme*\n---\n--- Blue and yellow main colors with high contrast and saturation palette.\n--- Palettes are: >lua\n---\n---   -- For dark 'background':\n---   MiniBase16.mini_palette('#112641', '#e2e98f', 75)\n---\n---   -- For light 'background':\n---   MiniBase16.mini_palette('#e2e5ca', '#002a83', 75)\n--- <\n--- ## minicyan ~\n--- *minicyan*\n---\n--- Cyan and grey main colors with moderate contrast and saturation palette.\n--- Palettes are: >lua\n---\n---   -- For dark 'background':\n---   MiniBase16.mini_palette('#0A2A2A', '#D0D0D0', 50)\n---\n---   -- For light 'background':\n---   MiniBase16.mini_palette('#C0D2D2', '#262626', 80)\n--- <\n---@tag MiniBase16-color-schemes\n\n-- Module definition ==========================================================\nlocal MiniBase16 = {}\nlocal H = {}\n\n--- Module setup\n---\n--- Setup is done by applying base16 palette to enable colorscheme. Highlight\n--- groups make an extended set from original\n--- [base16-vim](https://github.com/chriskempson/base16-vim/) plugin. It is a\n--- good idea to have `config.palette` respect the original [styling\n--- principles](https://github.com/chriskempson/base16/blob/master/styling.md).\n---\n--- By default only 'gui highlighting' (see |highlight-gui| and\n--- |'termguicolors'|) is supported. To support 'cterm highlighting' (see\n--- |highlight-cterm|) supply `config.use_cterm` argument in one of the formats:\n--- - `true` to auto-generate from `palette` (as closest colors).\n--- - Table with similar structure to `palette` but having terminal colors\n---   (integers from 0 to 255) instead of hex strings.\n---\n---@param config table Module config table. See |MiniBase16.config|.\n---\n---@usage >lua\n---   require('mini.base16').setup({}) -- replace {} with your config table\n---                                    -- needs `palette` field present\n--- <\nMiniBase16.setup = function(config)\n  -- Export module\n  _G.MiniBase16 = MiniBase16\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Plugin integrations ~\n---\n--- `config.plugins` defines for which supported plugins highlight groups will\n--- be created. Limiting number of integrations slightly decreases startup time.\n--- It is a table with boolean (`true`/`false`) values which are applied as follows:\n--- - If plugin name (as listed in |mini.base16|) has entry, it is used.\n--- - Otherwise `config.plugins.default` is used.\n---\n--- Example which will load only \"mini.nvim\" integration: >lua\n---\n---   require('mini.base16').setup({\n---     palette = require('mini.base16').mini_palette('#112641', '#e2e98f', 75),\n---     plugins = {\n---       default = false,\n---       ['nvim-mini/mini.nvim'] = true,\n---     }\n---   })\n--- <\nMiniBase16.config = {\n  -- Table with names from `base00` to `base0F` and values being strings of\n  -- HEX colors with format \"#RRGGBB\". NOTE: this should be explicitly\n  -- supplied in `setup()`.\n  palette = nil,\n\n  -- Whether to support cterm colors. Can be boolean, `nil` (same as\n  -- `false`), or table with cterm colors. See `setup()` documentation for\n  -- more information.\n  use_cterm = nil,\n\n  -- Plugin integrations. Use `default = false` to disable all integrations.\n  -- Also can be set per plugin (see |MiniBase16.config|).\n  plugins = { default = true },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Create 'mini' palette\n---\n--- Create base16 palette based on the HEX (string '#RRGGBB') colors of main\n--- background and foreground with optional setting of accent chroma (see\n--- details).\n---\n--- # Algorithm design ~\n---\n--- - Main operating color space is\n---   [CIELCh(uv)](https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_(CIELCh))\n---   which is a cylindrical representation of a perceptually uniform CIELUV\n---   color space. It defines color by three values: lightness L (values from 0\n---   to 100), chroma (positive values), and hue (circular values from 0 to 360\n---   degrees). Useful converting tool: https://www.easyrgb.com/en/convert.php\n--- - There are four important lightness values: background, foreground, focus\n---   (around the middle of background and foreground, leaning towards\n---   foreground), and edge (extreme lightness closest to foreground).\n--- - First four colors have the same chroma and hue as `background` but\n---   lightness progresses from background towards focus.\n--- - Second four colors have the same chroma and hue as `foreground` but\n---   lightness progresses from foreground towards edge in such a way that\n---   'base05' color is main foreground color.\n--- - The rest eight colors are accent colors which are created in pairs\n---     - Each pair has same hue from set of hues 'most different' to\n---       background and foreground hues (if respective chorma is positive).\n---     - All colors have the same chroma equal to `accent_chroma` (if not\n---       provided, chroma of foreground is used, as they will appear next\n---       to each other). Note: this means that in case of low foreground\n---       chroma, it is a good idea to set `accent_chroma` manually.\n---       Values from 30 (low chorma) to 80 (high chroma) are common.\n---     - Within pair there is base lightness (equal to foreground\n---       lightness) and alternative (equal to focus lightness). Base\n---       lightness goes to colors which will be used more frequently in\n---       code: base08 (variables), base0B (strings), base0D (functions),\n---       base0E (keywords).\n---   How exactly accent colors are mapped to base16 palette is a result of\n---   trial and error. One rule of thumb was: colors within one hue pair should\n---   be more often seen next to each other. This is because it is easier to\n---   distinguish them and seems to be more visually appealing. That is why\n---   `base0D` and `base0F` have same hues because they usually represent\n---   functions and delimiter (brackets included).\n---\n---@param background string Background HEX color (formatted as `#RRGGBB`).\n---@param foreground string Foreground HEX color (formatted as `#RRGGBB`).\n---@param accent_chroma number Optional positive number (usually between 0\n---   and 100). Default: chroma of foreground color.\n---\n---@return table Table with base16 palette.\n---\n---@usage >lua\n---   local p = require('mini.base16').mini_palette('#112641', '#e2e98f', 75)\n---   require('mini.base16').setup({ palette = p })\n--- <\nMiniBase16.mini_palette = function(background, foreground, accent_chroma)\n  H.validate_hex(background, 'background')\n  H.validate_hex(foreground, 'foreground')\n  if accent_chroma and not (type(accent_chroma) == 'number' and accent_chroma >= 0) then\n    error('(mini.base16) `accent_chroma` should be a positive number or `nil`.')\n  end\n  local bg, fg = H.hex2lch(background), H.hex2lch(foreground)\n  accent_chroma = accent_chroma or fg.c\n\n  local palette = {}\n\n  -- Target lightness values\n  -- Justification for skewness towards foreground in focus is mainly because\n  -- it will be paired with foreground lightness and used for text.\n  local focus_l = 0.4 * bg.l + 0.6 * fg.l\n  local edge_l = fg.l > 50 and 99 or 1\n\n  -- Background colors\n  local bg_step = (focus_l - bg.l) / 3\n  palette[1] = { l = bg.l + 0 * bg_step, c = bg.c, h = bg.h }\n  palette[2] = { l = bg.l + 1 * bg_step, c = bg.c, h = bg.h }\n  palette[3] = { l = bg.l + 2 * bg_step, c = bg.c, h = bg.h }\n  palette[4] = { l = bg.l + 3 * bg_step, c = bg.c, h = bg.h }\n\n  -- Foreground colors Possible negative value of `palette[5].l` will be\n  -- handled in future conversion to hex.\n  local fg_step = (edge_l - fg.l) / 2\n  palette[5] = { l = fg.l - 1 * fg_step, c = fg.c, h = fg.h }\n  palette[6] = { l = fg.l + 0 * fg_step, c = fg.c, h = fg.h }\n  palette[7] = { l = fg.l + 1 * fg_step, c = fg.c, h = fg.h }\n  palette[8] = { l = fg.l + 2 * fg_step, c = fg.c, h = fg.h }\n\n  -- Accent colors\n\n  -- Only try to avoid color if it has positive chroma, because with zero\n  -- chroma hue is meaningless (as in polar coordinates)\n  local present_hues = {}\n  if bg.c > 0 then table.insert(present_hues, bg.h) end\n  if fg.c > 0 then table.insert(present_hues, fg.h) end\n  local hues = H.make_different_hues(present_hues, 4)\n\n  -- stylua: ignore start\n  palette[9]  = { l = fg.l,    c = accent_chroma, h = hues[1] }\n  palette[10] = { l = focus_l, c = accent_chroma, h = hues[1] }\n  palette[11] = { l = focus_l, c = accent_chroma, h = hues[2] }\n  palette[12] = { l = fg.l,    c = accent_chroma, h = hues[2] }\n  palette[13] = { l = focus_l, c = accent_chroma, h = hues[4] }\n  palette[14] = { l = fg.l,    c = accent_chroma, h = hues[3] }\n  palette[15] = { l = fg.l,    c = accent_chroma, h = hues[4] }\n  palette[16] = { l = focus_l, c = accent_chroma, h = hues[3] }\n  -- stylua: ignore end\n\n  -- Convert to base16 palette\n  local base16_palette = {}\n  for i, lch in ipairs(palette) do\n    local name = H.base16_names[i]\n    -- It is ensured in `lch2hex` that only valid HEX values are produced\n    base16_palette[name] = H.lch2hex(lch)\n  end\n\n  return base16_palette\nend\n\n--- Converts palette with RGB colors to terminal colors\n---\n--- Useful for caching `use_cterm` variable to increase speed.\n---\n---@param palette table Table with base16 palette (same as in\n---   `MiniBase16.config.palette`).\n---\n---@return table Table with base16 palette using |highlight-cterm|.\nMiniBase16.rgb_palette_to_cterm_palette = function(palette)\n  H.validate_base16_palette(palette, 'palette')\n\n  -- Create cterm palette only when it is needed to decrease load time\n  H.ensure_cterm_palette()\n\n  return vim.tbl_map(function(hex) return H.nearest_rgb_id(H.hex2rgb(hex), H.cterm_palette) end, palette)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniBase16.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  -- Validate settings\n  H.validate_base16_palette(config.palette, 'config.palette')\n  H.validate_use_cterm(config.use_cterm, 'config.use_cterm')\n  H.check_type('plugins', config.plugins, 'table')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniBase16.config = config\n\n  H.apply_palette(config.palette, config.use_cterm)\nend\n\n-- Validators -----------------------------------------------------------------\nH.base16_names = {\n  'base00',\n  'base01',\n  'base02',\n  'base03',\n  'base04',\n  'base05',\n  'base06',\n  'base07',\n  'base08',\n  'base09',\n  'base0A',\n  'base0B',\n  'base0C',\n  'base0D',\n  'base0E',\n  'base0F',\n}\n\nH.validate_base16_palette = function(x, x_name)\n  if type(x) ~= 'table' then error(string.format('(mini.base16) `%s` is not a table.', x_name)) end\n\n  for _, color_name in pairs(H.base16_names) do\n    local c = x[color_name]\n    if c == nil then\n      local msg = string.format('(mini.base16) `%s` does not have value %s.', x_name, color_name)\n      error(msg)\n    end\n    H.validate_hex(c, string.format('%s.%s', x_name, color_name))\n  end\n\n  return true\nend\n\nH.validate_use_cterm = function(x, x_name)\n  if not x or type(x) == 'boolean' then return true end\n\n  if type(x) ~= 'table' then\n    local msg = string.format('(mini.base16) `%s` should be boolean or table with cterm colors.', x_name)\n    error(msg)\n  end\n\n  for _, color_name in pairs(H.base16_names) do\n    local c = x[color_name]\n    if c == nil then\n      local msg = string.format('(mini.base16) `%s` does not have value %s.', x_name, color_name)\n      error(msg)\n    end\n    if not (type(c) == 'number' and 0 <= c and c <= 255) then\n      local msg = string.format('(mini.base16) `%s.%s` is not a cterm color.', x_name, color_name)\n      error(msg)\n    end\n  end\n\n  return true\nend\n\nH.validate_hex = function(x, x_name)\n  local is_hex = type(x) == 'string' and x:len() == 7 and x:sub(1, 1) == '#' and (tonumber(x:sub(2), 16) ~= nil)\n\n  if not is_hex then\n    local msg = string.format('(mini.base16) `%s` is not a HEX color (string \"#RRGGBB\").', x_name)\n    error(msg)\n  end\n\n  return true\nend\n\n-- Highlighting ---------------------------------------------------------------\nH.apply_palette = function(palette, use_cterm)\n  -- Prepare highlighting application. Notes:\n  -- - Clear current highlight only if other theme was loaded previously.\n  -- - No need to `syntax reset` because *all* syntax groups are defined later.\n  if vim.g.colors_name then vim.cmd('highlight clear') end\n  -- As this doesn't create colorscheme, don't store any name. Not doing it\n  -- might cause some issues with `syntax on`.\n  vim.g.colors_name = nil\n\n  local p, hi\n  if use_cterm then\n    p, hi = H.make_compound_palette(palette, use_cterm), H.highlight_both\n  else\n    p, hi = palette, H.highlight_gui\n  end\n\n  -- NOTE: recommendations for adding new highlight groups:\n  -- - Put all related groups (like for new plugin) in single paragraph.\n  -- - Sort within group alphabetically (by hl-group name) ignoring case.\n  -- - Link all repeated groups within paragraph (lowers execution time).\n  -- - Align by commas.\n\n  -- stylua: ignore start\n  -- Builtin highlighting groups. Some groups which are missing in 'base16-vim'\n  -- are added based on groups to which they are linked.\n  hi('ColorColumn',    {fg=nil,      bg=p.base01, attr=nil,            sp=nil})\n  hi('ComplMatchIns',  {fg=nil,      bg=nil,      attr=nil,            sp=nil})\n  hi('Conceal',        {fg=p.base0D, bg=nil,      attr=nil,            sp=nil})\n  hi('CurSearch',      {fg=p.base01, bg=p.base09, attr=nil,            sp=nil})\n  hi('Cursor',         {fg=p.base00, bg=p.base05, attr=nil,            sp=nil})\n  hi('CursorColumn',   {fg=nil,      bg=p.base01, attr=nil,            sp=nil})\n  hi('CursorIM',       {fg=p.base00, bg=p.base05, attr=nil,            sp=nil})\n  hi('CursorLine',     {fg=nil,      bg=p.base01, attr=nil,            sp=nil})\n  hi('CursorLineFold', {fg=p.base0C, bg=p.base01, attr=nil,            sp=nil})\n  hi('CursorLineNr',   {fg=p.base04, bg=p.base01, attr=nil,            sp=nil})\n  hi('CursorLineSign', {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('DiffAdd',        {fg=p.base0B, bg=p.base01, attr=nil,            sp=nil})\n  -- Differs from base16-vim, but according to general style guide\n  hi('DiffChange',     {fg=p.base0E, bg=p.base01, attr=nil,            sp=nil})\n  hi('DiffDelete',     {fg=p.base08, bg=p.base01, attr=nil,            sp=nil})\n  hi('DiffText',       {fg=p.base0D, bg=p.base01, attr=nil,            sp=nil})\n  hi('DiffTextAdd',    {link='DiffAdd'})\n  hi('Directory',      {fg=p.base0D, bg=nil,      attr=nil,            sp=nil})\n  hi('EndOfBuffer',    {fg=p.base03, bg=nil,      attr=nil,            sp=nil})\n  hi('ErrorMsg',       {fg=p.base08, bg=nil,      attr=nil,            sp=nil})\n  hi('FloatBorder',    {link='NormalFloat'})\n  hi('FoldColumn',     {fg=p.base0C, bg=p.base01, attr=nil,            sp=nil})\n  hi('Folded',         {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('IncSearch',      {fg=p.base01, bg=p.base09, attr=nil,            sp=nil})\n  hi('lCursor',        {fg=p.base00, bg=p.base05, attr=nil,            sp=nil})\n  hi('LineNr',         {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('LineNrAbove',    {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('LineNrBelow',    {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  -- Slight difference from base16, where `bg=base03` is used. This makes\n  -- it possible to comfortably see this highlighting in comments.\n  hi('MatchParen',     {fg=nil,      bg=p.base02, attr=nil,            sp=nil})\n  hi('ModeMsg',        {fg=p.base0B, bg=nil,      attr=nil,            sp=nil})\n  hi('MoreMsg',        {fg=p.base0B, bg=nil,      attr=nil,            sp=nil})\n  hi('MsgArea',        {link='Normal'})\n  hi('MsgSeparator',   {fg=p.base02, bg=p.base02, attr=nil,            sp=nil})\n  hi('NonText',        {fg=p.base03, bg=nil,      attr=nil,            sp=nil})\n  hi('Normal',         {fg=p.base05, bg=p.base00, attr=nil,            sp=nil})\n  hi('NormalFloat',    {fg=p.base05, bg=p.base01, attr=nil,            sp=nil})\n  hi('NormalNC',       {fg=p.base05, bg=p.base00, attr=nil,            sp=nil})\n  hi('OkMsg',          {fg=p.base0B, bg=nil,      attr=nil,            sp=nil})\n  hi('Pmenu',          {fg=p.base05, bg=p.base01, attr=nil,            sp=nil})\n  hi('PmenuExtra',     {link='Pmenu'})\n  hi('PmenuExtraSel',  {link='PmenuSel'})\n  hi('PmenuKind',      {link='Pmenu'})\n  hi('PmenuKindSel',   {link='PmenuSel'})\n  hi('PmenuMatch',     {fg=p.base05, bg=nil,      attr='bold',         sp=nil})\n  hi('PmenuMatchSel',  {fg=p.base05, bg=nil,      attr='bold,reverse', sp=nil})\n  hi('PmenuSbar',      {fg=nil,      bg=p.base02, attr=nil,            sp=nil})\n  hi('PmenuSel',       {fg=p.base05, bg=p.base01, attr='reverse',      sp=nil})\n  hi('PmenuThumb',     {fg=nil,      bg=p.base07, attr=nil,            sp=nil})\n  hi('Question',       {fg=p.base0D, bg=nil,      attr=nil,            sp=nil})\n  hi('QuickFixLine',   {fg=nil,      bg=p.base01, attr=nil,            sp=nil})\n  hi('Search',         {fg=p.base01, bg=p.base0A, attr=nil,            sp=nil})\n  hi('SignColumn',     {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('SpecialKey',     {fg=p.base03, bg=nil,      attr=nil,            sp=nil})\n  hi('SpellBad',       {fg=nil,      bg=nil,      attr='undercurl',    sp=p.base08})\n  hi('SpellCap',       {fg=nil,      bg=nil,      attr='undercurl',    sp=p.base0D})\n  hi('SpellLocal',     {fg=nil,      bg=nil,      attr='undercurl',    sp=p.base0C})\n  hi('SpellRare',      {fg=nil,      bg=nil,      attr='undercurl',    sp=p.base0E})\n  hi('StatusLine',     {fg=p.base04, bg=p.base02, attr=nil,            sp=nil})\n  hi('StatusLineNC',   {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('StderrMsg',      {link='ErrorMsg'})\n  hi('StdoutMsg',      {link='MsgArea'})\n  hi('Substitute',     {fg=p.base01, bg=p.base0A, attr=nil,            sp=nil})\n  hi('TabLine',        {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('TabLineFill',    {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('TabLineSel',     {fg=p.base0B, bg=p.base01, attr=nil,            sp=nil})\n  hi('TermCursor',     {fg=nil,      bg=nil,      attr='reverse',      sp=nil})\n  hi('TermCursorNC',   {fg=nil,      bg=nil,      attr='reverse',      sp=nil})\n  hi('Title',          {fg=p.base0D, bg=nil,      attr=nil,            sp=nil})\n  hi('VertSplit',      {fg=p.base02, bg=p.base02, attr=nil,            sp=nil})\n  hi('Visual',         {fg=nil,      bg=p.base02, attr=nil,            sp=nil})\n  hi('VisualNOS',      {fg=p.base08, bg=nil,      attr=nil,            sp=nil})\n  hi('WarningMsg',     {fg=p.base08, bg=nil,      attr=nil,            sp=nil})\n  hi('Whitespace',     {fg=p.base03, bg=nil,      attr=nil,            sp=nil})\n  hi('WildMenu',       {fg=p.base08, bg=p.base0A, attr=nil,            sp=nil})\n  hi('WinBar',         {fg=p.base04, bg=p.base02, attr=nil,            sp=nil})\n  hi('WinBarNC',       {fg=p.base03, bg=p.base01, attr=nil,            sp=nil})\n  hi('WinSeparator',   {fg=p.base02, bg=p.base02, attr=nil,            sp=nil})\n\n  -- Standard syntax (affects treesitter)\n  hi('Boolean',        {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n  hi('Character',      {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  hi('Comment',        {fg=p.base03, bg=nil,      attr=nil, sp=nil})\n  hi('Conditional',    {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n  hi('Constant',       {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n  hi('Debug',          {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  hi('Define',         {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n  hi('Delimiter',      {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n  hi('Error',          {fg=p.base00, bg=p.base08, attr=nil, sp=nil})\n  hi('Exception',      {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  hi('Float',          {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n  hi('Function',       {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n  hi('Identifier',     {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  hi('Ignore',         {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n  hi('Include',        {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n  hi('Keyword',        {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n  hi('Label',          {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('Macro',          {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  hi('Number',         {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n  hi('Operator',       {fg=p.base05, bg=nil,      attr=nil, sp=nil})\n  hi('PreCondit',      {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('PreProc',        {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('Repeat',         {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('Special',        {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n  hi('SpecialChar',    {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n  hi('SpecialComment', {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n  hi('Statement',      {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  hi('StorageClass',   {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('String',         {fg=p.base0B, bg=nil,      attr=nil, sp=nil})\n  hi('Structure',      {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n  hi('Tag',            {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('Todo',           {fg=p.base0A, bg=p.base01, attr=nil, sp=nil})\n  hi('Type',           {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n  hi('Typedef',        {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n\n  -- Other from 'base16-vim'\n  hi('Bold',       {fg=nil,      bg=nil, attr='bold',      sp=nil})\n  hi('Italic',     {fg=nil,      bg=nil, attr='italic',    sp=nil})\n  hi('TooLong',    {fg=p.base08, bg=nil, attr=nil,         sp=nil})\n  hi('Underlined', {fg=nil,      bg=nil, attr='underline', sp=nil})\n\n  -- Patch diff\n  hi('diffAdded',   {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n  hi('diffChanged', {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n  hi('diffFile',    {fg=p.base09, bg=nil, attr=nil, sp=nil})\n  hi('diffLine',    {fg=p.base0C, bg=nil, attr=nil, sp=nil})\n  hi('diffRemoved', {fg=p.base08, bg=nil, attr=nil, sp=nil})\n  hi('Added',       {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n  hi('Changed',     {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n  hi('Removed',     {fg=p.base08, bg=nil, attr=nil, sp=nil})\n\n  -- Git commit\n  hi('gitcommitBranch',        {fg=p.base09, bg=nil, attr='bold', sp=nil})\n  hi('gitcommitComment',       {link='Comment'})\n  hi('gitcommitDiscarded',     {link='Comment'})\n  hi('gitcommitDiscardedFile', {fg=p.base08, bg=nil, attr='bold', sp=nil})\n  hi('gitcommitDiscardedType', {fg=p.base0D, bg=nil, attr=nil,    sp=nil})\n  hi('gitcommitHeader',        {fg=p.base0E, bg=nil, attr=nil,    sp=nil})\n  hi('gitcommitOverflow',      {fg=p.base08, bg=nil, attr=nil,    sp=nil})\n  hi('gitcommitSelected',      {link='Comment'})\n  hi('gitcommitSelectedFile',  {fg=p.base0B, bg=nil, attr='bold', sp=nil})\n  hi('gitcommitSelectedType',  {link='gitcommitDiscardedType'})\n  hi('gitcommitSummary',       {fg=p.base0B, bg=nil, attr=nil,    sp=nil})\n  hi('gitcommitUnmergedFile',  {link='gitcommitDiscardedFile'})\n  hi('gitcommitUnmergedType',  {link='gitcommitDiscardedType'})\n  hi('gitcommitUntracked',     {link='Comment'})\n  hi('gitcommitUntrackedFile', {fg=p.base0A, bg=nil, attr=nil,    sp=nil})\n\n  -- Built-in diagnostic\n  hi('DiagnosticError', {fg=p.base08, bg=nil, attr=nil, sp=nil})\n  hi('DiagnosticHint',  {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n  hi('DiagnosticInfo',  {fg=p.base0C, bg=nil, attr=nil, sp=nil})\n  hi('DiagnosticOk',    {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n  hi('DiagnosticWarn',  {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n\n  hi('DiagnosticFloatingError', {fg=p.base08, bg=p.base01, attr=nil, sp=nil})\n  hi('DiagnosticFloatingHint',  {fg=p.base0D, bg=p.base01, attr=nil, sp=nil})\n  hi('DiagnosticFloatingInfo',  {fg=p.base0C, bg=p.base01, attr=nil, sp=nil})\n  hi('DiagnosticFloatingOk',    {fg=p.base0B, bg=p.base01, attr=nil, sp=nil})\n  hi('DiagnosticFloatingWarn',  {fg=p.base0E, bg=p.base01, attr=nil, sp=nil})\n\n  hi('DiagnosticSignError', {link='DiagnosticFloatingError'})\n  hi('DiagnosticSignHint',  {link='DiagnosticFloatingHint'})\n  hi('DiagnosticSignInfo',  {link='DiagnosticFloatingInfo'})\n  hi('DiagnosticSignOk',    {link='DiagnosticFloatingOk'})\n  hi('DiagnosticSignWarn',  {link='DiagnosticFloatingWarn'})\n\n  hi('DiagnosticUnderlineError', {fg=nil, bg=nil, attr='underline', sp=p.base08})\n  hi('DiagnosticUnderlineHint',  {fg=nil, bg=nil, attr='underline', sp=p.base0D})\n  hi('DiagnosticUnderlineInfo',  {fg=nil, bg=nil, attr='underline', sp=p.base0C})\n  hi('DiagnosticUnderlineOk',    {fg=nil, bg=nil, attr='underline', sp=p.base0B})\n  hi('DiagnosticUnderlineWarn',  {fg=nil, bg=nil, attr='underline', sp=p.base0E})\n\n  -- Built-in LSP\n  hi('LspReferenceText',  {fg=nil, bg=p.base02, attr=nil, sp=nil})\n  hi('LspReferenceRead',  {link='LspReferenceText'})\n  hi('LspReferenceWrite', {link='LspReferenceText'})\n\n  hi('LspSignatureActiveParameter', {link='LspReferenceText'})\n\n  hi('LspCodeLens',          {link='Comment'})\n  hi('LspCodeLensSeparator', {link='Comment'})\n\n  -- Built-in snippets\n  hi('SnippetTabstop',       {link='Visual'})\n  hi('SnippetTabstopActive', {link='SnippetTabstop'})\n\n  -- Built-in markdown syntax\n  hi('markdownH1', {fg=p.base09, bg=nil, attr=nil, sp=nil})\n  hi('markdownH2', {fg=p.base0A, bg=nil, attr=nil, sp=nil})\n  hi('markdownH3', {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n  hi('markdownH4', {fg=p.base0C, bg=nil, attr=nil, sp=nil})\n  hi('markdownH5', {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n  hi('markdownH6', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n\n  -- Tree-sitter\n  -- Sources:\n  -- - `:h treesitter-highlight-groups`\n  -- - https://github.com/nvim-treesitter/nvim-treesitter/blob/master/CONTRIBUTING.md#highlights\n  -- Included only those differing from default links\n  hi('@keyword.return', {fg=p.base08, bg=nil, attr=nil, sp=nil})\n  hi('@symbol',         {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n  hi('@variable',       {fg=p.base05, bg=nil, attr=nil, sp=nil})\n\n  hi('@text.strong',    {fg=nil, bg=nil, attr='bold',          sp=nil})\n  hi('@text.emphasis',  {fg=nil, bg=nil, attr='italic',        sp=nil})\n  hi('@text.strike',    {fg=nil, bg=nil, attr='strikethrough', sp=nil})\n  hi('@text.underline', {link='Underlined'})\n\n  -- Semantic tokens. Source: `:h lsp-semantic-highlight`.\n  -- Included only those differing from default links\n  hi('@lsp.type.variable',  {fg=p.base05, bg=nil, attr=nil, sp=nil})\n  hi('@lsp.mod.deprecated', {fg=p.base08, bg=nil, attr=nil, sp=nil})\n\n  -- New tree-sitter groups\n  if vim.fn.has('nvim-0.10') == 1 then\n    -- Source: `:h treesitter-highlight-groups`\n    -- Included only those differing from default links\n    hi('@markup.strong',        {link='@text.strong'})\n    hi('@markup.italic',        {link='@text.emphasis'})\n    hi('@markup.strikethrough', {link='@text.strike'})\n    hi('@markup.underline',     {link='@text.underline'})\n\n    hi('@markup.heading.1', {link='markdownH1'})\n    hi('@markup.heading.2', {link='markdownH2'})\n    hi('@markup.heading.3', {link='markdownH3'})\n    hi('@markup.heading.4', {link='markdownH4'})\n    hi('@markup.heading.5', {link='markdownH5'})\n    hi('@markup.heading.6', {link='markdownH6'})\n\n    hi('@string.special.vimdoc',     {link='SpecialChar'})\n    hi('@variable.parameter.vimdoc', {fg=p.base09, bg=nil, attr=nil, sp=nil})\n    hi('@markup.heading.4.vimdoc',   {link='Title'})\n  end\n\n  -- Plugins\n  -- nvim-mini/mini.nvim\n  -- TODO: Remove 'echasnovski/mini.nvim' fallback after September 2026\n  if H.has_integration('nvim-mini/mini.nvim') or H.has_integration('echasnovski/mini.nvim') then\n    hi('MiniAnimateCursor',      {fg=nil, bg=nil, attr='reverse,nocombine', sp=nil})\n    hi('MiniAnimateNormalFloat', {link='NormalFloat'})\n\n    hi('MiniClueBorder',              {link='FloatBorder'})\n    hi('MiniClueDescGroup',           {link='DiagnosticFloatingWarn'})\n    hi('MiniClueDescSingle',          {link='NormalFloat'})\n    hi('MiniClueNextKey',             {link='DiagnosticFloatingHint'})\n    hi('MiniClueNextKeyWithPostkeys', {link='DiagnosticFloatingError'})\n    hi('MiniClueSeparator',           {link='DiagnosticFloatingInfo'})\n    hi('MiniClueTitle',               {fg=p.base0D, bg=p.base01, attr='bold', sp=nil})\n\n    hi('MiniCmdlinePeekBorder', {link='FloatBorder'})\n    hi('MiniCmdlinePeekLineNr', {link='DiagnosticSignWarn'})\n    hi('MiniCmdlinePeekNormal', {link='NormalFloat'})\n    hi('MiniCmdlinePeekSep',    {link='SignColumn'})\n    hi('MiniCmdlinePeekSign',   {link='DiagnosticSignHint'})\n    hi('MiniCmdlinePeekTitle',  {fg=p.base0D, bg=p.base01, attr='bold', sp=nil})\n\n    hi('MiniCompletionActiveParameter',    {link='LspSignatureActiveParameter'})\n    hi('MiniCompletionDeprecated',         {link='DiagnosticDeprecated'})\n    hi('MiniCompletionInfoBorderOutdated', {link='DiagnosticFloatingWarn'})\n\n    hi('MiniCursorword',        {fg=nil, bg=nil, attr='underline', sp=nil})\n    hi('MiniCursorwordCurrent', {fg=nil, bg=nil, attr='underline', sp=nil})\n\n    hi('MiniDepsChangeAdded',   {link='diffAdded'})\n    hi('MiniDepsChangeRemoved', {link='diffRemoved'})\n    hi('MiniDepsHint',          {link='DiagnosticHint'})\n    hi('MiniDepsInfo',          {link='DiagnosticInfo'})\n    hi('MiniDepsMsgBreaking',   {link='DiagnosticWarn'})\n    hi('MiniDepsPlaceholder',   {link='Comment'})\n    hi('MiniDepsTitle',         {link='Title'})\n    hi('MiniDepsTitleError',    {link='DiffDelete'})\n    hi('MiniDepsTitleSame',     {link='DiffText'})\n    hi('MiniDepsTitleUpdate',   {link='DiffAdd'})\n\n    hi('MiniDiffSignAdd',        {fg=p.base0B, bg=p.base01, attr=nil, sp=nil})\n    hi('MiniDiffSignChange',     {fg=p.base0E, bg=p.base01, attr=nil, sp=nil})\n    hi('MiniDiffSignDelete',     {fg=p.base08, bg=p.base01, attr=nil, sp=nil})\n    hi('MiniDiffOverAdd',        {link='DiffAdd'})\n    hi('MiniDiffOverChange',     {link='DiffText'})\n    hi('MiniDiffOverChangeBuf',  {link='MiniDiffOverChange'})\n    hi('MiniDiffOverContext',    {link='DiffChange'})\n    hi('MiniDiffOverContextBuf', {})\n    hi('MiniDiffOverDelete',     {link='DiffDelete'})\n\n    hi('MiniFilesBorder',         {link='FloatBorder'})\n    hi('MiniFilesBorderModified', {link='DiagnosticFloatingWarn'})\n    hi('MiniFilesCursorLine',     {fg=nil,      bg=p.base02, attr=nil,    sp=nil})\n    hi('MiniFilesDirectory',      {link='Directory'})\n    hi('MiniFilesFile',           {fg=p.base05, bg=nil,      attr=nil,    sp=nil})\n    hi('MiniFilesNormal',         {link='NormalFloat'})\n    hi('MiniFilesTitle',          {fg=p.base0D, bg=p.base01, attr=nil,    sp=nil})\n    hi('MiniFilesTitleFocused',   {fg=p.base0D, bg=p.base01, attr='bold', sp=nil})\n\n    hi('MiniHipatternsFixme', {fg=p.base00, bg=p.base08, attr='bold', sp=nil})\n    hi('MiniHipatternsHack',  {fg=p.base00, bg=p.base0E, attr='bold', sp=nil})\n    hi('MiniHipatternsNote',  {fg=p.base00, bg=p.base0D, attr='bold', sp=nil})\n    hi('MiniHipatternsTodo',  {fg=p.base00, bg=p.base0C, attr='bold', sp=nil})\n\n    hi('MiniIconsAzure',  {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsBlue',   {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsCyan',   {fg=p.base0C, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsGreen',  {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsGrey',   {fg=p.base07, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsOrange', {fg=p.base09, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsPurple', {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsRed',    {fg=p.base08, bg=nil, attr=nil, sp=nil})\n    hi('MiniIconsYellow', {fg=p.base0A, bg=nil, attr=nil, sp=nil})\n\n    hi('MiniIndentscopeSymbol',    {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('MiniIndentscopeSymbolOff', {fg=p.base08, bg=nil, attr=nil, sp=nil})\n\n    hi('MiniJump', {link='SpellRare'})\n\n    hi('MiniJump2dDim',        {link='Comment'})\n    hi('MiniJump2dSpot',       {fg=p.base07, bg=p.base01, attr='bold,nocombine', sp=nil})\n    hi('MiniJump2dSpotAhead',  {fg=p.base06, bg=p.base00, attr='nocombine',      sp=nil})\n    hi('MiniJump2dSpotUnique', {link='MiniJump2dSpot'})\n\n    hi('MiniMapNormal',      {fg=p.base05, bg=p.base01, attr=nil, sp=nil})\n    hi('MiniMapSymbolCount', {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n    hi('MiniMapSymbolLine',  {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n    hi('MiniMapSymbolView',  {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n\n    hi('MiniNotifyBorder',      {link='FloatBorder'})\n    hi('MiniNotifyLspProgress', {link='MiniNotifyNormal'})\n    hi('MiniNotifyNormal',      {link='NormalFloat'})\n    hi('MiniNotifyTitle',       {link='FloatTitle'})\n\n    hi('MiniOperatorsExchangeFrom', {link='IncSearch'})\n\n    hi('MiniPickBorder',        {link='FloatBorder'})\n    hi('MiniPickBorderBusy',    {fg=p.base0E, bg=p.base01, attr=nil,         sp=nil})\n    hi('MiniPickBorderText',    {fg=p.base0D, bg=p.base01, attr='bold',      sp=nil})\n    hi('MiniPickCursor',        {fg=nil,      bg=nil,      attr='nocombine', sp=nil, blend=100})\n    hi('MiniPickIconDirectory', {link='Directory'})\n    hi('MiniPickIconFile',      {fg=p.base05, bg=nil,      attr=nil,         sp=nil})\n    hi('MiniPickHeader',        {link='DiagnosticFloatingHint'})\n    hi('MiniPickMatchCurrent',  {fg=nil,      bg=p.base02, attr=nil,         sp=nil})\n    hi('MiniPickMatchMarked',   {fg=nil,      bg=p.base03, attr=nil,         sp=nil})\n    hi('MiniPickMatchRanges',   {link='DiagnosticFloatingHint'})\n    hi('MiniPickNormal',        {link='NormalFloat'})\n    hi('MiniPickPreviewLine',   {fg=nil,      bg=p.base02, attr=nil,         sp=nil})\n    hi('MiniPickPreviewRegion', {link='IncSearch'})\n    hi('MiniPickPrompt',        {link='MiniPickMatchRanges'})\n    hi('MiniPickPromptCaret' ,  {fg=p.base0B, bg=p.base01, attr=nil,         sp=nil})\n    hi('MiniPickPromptPrefix',  {fg=p.base0B, bg=p.base01, attr=nil,         sp=nil})\n\n    hi('MiniSnippetsCurrent',        {fg=nil, bg=nil, attr='underdouble', sp=p.base0E})\n    hi('MiniSnippetsCurrentReplace', {fg=nil, bg=nil, attr='underdouble', sp=p.base08})\n    hi('MiniSnippetsFinal',          {fg=nil, bg=nil, attr='underdouble', sp=p.base0B})\n    hi('MiniSnippetsUnvisited',      {fg=nil, bg=nil, attr='underdouble', sp=p.base0D})\n    hi('MiniSnippetsVisited',        {fg=nil, bg=nil, attr='underdouble', sp=p.base0C})\n\n    hi('MiniStarterCurrent',    {link='MiniStarterItem'})\n    hi('MiniStarterFooter',     {fg=p.base0D, bg=nil, attr=nil,    sp=nil})\n    hi('MiniStarterHeader',     {fg=p.base0D, bg=nil, attr=nil,    sp=nil})\n    hi('MiniStarterInactive',   {link='Comment'})\n    hi('MiniStarterItem',       {fg=p.base05, bg=nil, attr=nil,    sp=nil})\n    hi('MiniStarterItemBullet', {fg=p.base0F, bg=nil, attr=nil,    sp=nil})\n    hi('MiniStarterItemPrefix', {fg=p.base08, bg=nil, attr='bold', sp=nil})\n    hi('MiniStarterSection',    {fg=p.base0F, bg=nil, attr=nil,    sp=nil})\n    hi('MiniStarterQuery',      {fg=p.base0B, bg=nil, attr='bold', sp=nil})\n\n    hi('MiniStatuslineDevinfo',     {fg=p.base04, bg=p.base02, attr=nil,    sp=nil})\n    hi('MiniStatuslineFileinfo',    {link='MiniStatuslineDevinfo'})\n    hi('MiniStatuslineFilename',    {fg=p.base03, bg=p.base01, attr=nil,    sp=nil})\n    hi('MiniStatuslineInactive',    {link='StatusLineNC'})\n    hi('MiniStatuslineModeCommand', {fg=p.base00, bg=p.base08, attr='bold', sp=nil})\n    hi('MiniStatuslineModeInsert',  {fg=p.base00, bg=p.base0D, attr='bold', sp=nil})\n    hi('MiniStatuslineModeNormal',  {fg=p.base00, bg=p.base05, attr='bold', sp=nil})\n    hi('MiniStatuslineModeOther',   {fg=p.base00, bg=p.base03, attr='bold', sp=nil})\n    hi('MiniStatuslineModeReplace', {fg=p.base00, bg=p.base0E, attr='bold', sp=nil})\n    hi('MiniStatuslineModeVisual',  {fg=p.base00, bg=p.base0B, attr='bold', sp=nil})\n\n    hi('MiniSurround', {link='IncSearch'})\n\n    hi('MiniTablineCurrent',         {fg=p.base05, bg=p.base02, attr='bold', sp=nil})\n    hi('MiniTablineFill',            {link='Normal'})\n    hi('MiniTablineHidden',          {fg=p.base04, bg=p.base01, attr=nil,    sp=nil})\n    hi('MiniTablineModifiedCurrent', {fg=p.base02, bg=p.base05, attr='bold', sp=nil})\n    hi('MiniTablineModifiedHidden',  {fg=p.base01, bg=p.base04, attr=nil,    sp=nil})\n    hi('MiniTablineModifiedVisible', {fg=p.base02, bg=p.base04, attr='bold', sp=nil})\n    hi('MiniTablineTabpagesection',  {fg=p.base01, bg=p.base0A, attr='bold', sp=nil})\n    hi('MiniTablineTrunc',           {fg=p.base05, bg=p.base01, attr='bold', sp=nil})\n    hi('MiniTablineVisible',         {fg=p.base05, bg=p.base01, attr='bold', sp=nil})\n\n    hi('MiniTestEmphasis', {fg=nil,      bg=nil, attr='bold', sp=nil})\n    hi('MiniTestFail',     {fg=p.base08, bg=nil, attr='bold', sp=nil})\n    hi('MiniTestPass',     {fg=p.base0B, bg=nil, attr='bold', sp=nil})\n\n    hi('MiniTrailspace', {link='Error'})\n  end\n\n  if H.has_integration('akinsho/bufferline.nvim') then\n    hi('BufferLineBuffer',              {fg=p.base04, bg=nil,      attr=nil,    sp=nil})\n    hi('BufferLineBufferSelected',      {fg=p.base05, bg=nil,      attr='bold', sp=nil})\n    hi('BufferLineBufferVisible',       {fg=p.base05, bg=nil,      attr=nil,    sp=nil})\n    hi('BufferLineCloseButton',         {link='BufferLineBackground'})\n    hi('BufferLineCloseButtonSelected', {link='BufferLineBufferSelected'})\n    hi('BufferLineCloseButtonVisible',  {link='BufferLineBufferVisible'})\n    hi('BufferLineFill',                {link='Normal'})\n    hi('BufferLineTab',                 {fg=p.base00, bg=p.base0A, attr=nil,    sp=nil})\n    hi('BufferLineTabSelected',         {fg=p.base00, bg=p.base0A, attr='bold', sp=nil})\n  end\n\n  if H.has_integration('anuvyklack/hydra.nvim') then\n    hi('HydraRed',      {fg=p.base08, bg=nil, attr=nil, sp=nil})\n    hi('HydraBlue',     {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('HydraAmaranth', {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n    hi('HydraTeal',     {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n    hi('HydraPink',     {fg=p.base09, bg=nil, attr=nil, sp=nil})\n    hi('HydraHint',     {link='NormalFloat'})\n  end\n\n  if H.has_integration('DanilaMihailov/beacon.nvim') then\n    hi('Beacon', {fg=nil, bg=p.base07, attr=nil, sp=nil})\n  end\n\n  if H.has_integration('folke/lazy.nvim') then\n    hi('LazyButton',       {fg=nil, bg=p.base01, attr=nil,    sp=nil})\n    hi('LazyButtonActive', {fg=nil, bg=p.base02, attr=nil,    sp=nil})\n    hi('LazyDimmed',       {link='Comment'})\n    hi('LazyH1',           {fg=nil, bg=p.base02, attr='bold', sp=nil})\n  end\n\n  if H.has_integration('folke/noice.nvim') then\n    hi('NoiceCmdlinePopupBorder', {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('NoiceConfirmBorder',      {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n  end\n\n  -- folke/snacks.nvim\n  -- Everything works correctly out of the box\n\n  -- folke/trouble.nvim\n  if H.has_integration('folke/trouble.nvim') then\n    hi('TroubleCount',           {fg=p.base0B, bg=nil, attr='bold', sp=nil})\n    hi('TroubleFoldIcon',        {fg=p.base05, bg=nil, attr=nil,    sp=nil})\n    hi('TroubleIndent',          {fg=p.base02, bg=nil, attr=nil,    sp=nil})\n    hi('TroubleLocation',        {fg=p.base04, bg=nil, attr=nil,    sp=nil})\n    hi('TroubleSignError',       {link='DiagnosticError'})\n    hi('TroubleSignHint',        {link='DiagnosticHint'})\n    hi('TroubleSignInformation', {link='DiagnosticInfo'})\n    hi('TroubleSignOther',       {link='DiagnosticInfo'})\n    hi('TroubleSignWarning',     {link='DiagnosticWarn'})\n    hi('TroubleText',            {fg=p.base05, bg=nil, attr=nil,    sp=nil})\n    hi('TroubleTextError',       {link='TroubleText'})\n    hi('TroubleTextHint',        {link='TroubleText'})\n    hi('TroubleTextInformation', {link='TroubleText'})\n    hi('TroubleTextWarning',     {link='TroubleText'})\n  end\n\n  -- folke/todo-comments.nvim\n  -- Everything works correctly out of the box\n\n  if H.has_integration('folke/which-key.nvim') then\n    hi('WhichKey',          {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n    hi('WhichKeyDesc',      {fg=p.base05, bg=nil,      attr=nil, sp=nil})\n    hi('WhichKeyFloat',     {fg=p.base05, bg=p.base01, attr=nil, sp=nil})\n    hi('WhichKeyGroup',     {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n    hi('WhichKeySeparator', {fg=p.base0B, bg=p.base01, attr=nil, sp=nil})\n    hi('WhichKeyValue',     {fg=p.base03, bg=nil,      attr=nil, sp=nil})\n  end\n\n  if H.has_integration('ggandor/leap.nvim') then\n    hi('LeapMatch',          {fg=p.base0E, bg=nil, attr='bold,nocombine,underline', sp=nil})\n    hi('LeapLabel',          {fg=p.base08, bg=nil, attr='bold,nocombine',           sp=nil})\n    hi('LeapLabelSelected',  {fg=p.base09, bg=nil, attr='bold,nocombine',           sp=nil})\n    hi('LeapBackdrop',       {link='Comment'})\n  end\n\n  if H.has_integration('ggandor/lightspeed.nvim') then\n    hi('LightspeedLabel',          {fg=p.base0E, bg=nil, attr='bold,underline', sp=nil})\n    hi('LightspeedLabelDistant',   {fg=p.base0D, bg=nil, attr='bold,underline', sp=nil})\n    hi('LightspeedShortcut',       {fg=p.base07, bg=nil, attr='bold', sp=nil})\n    hi('LightspeedMaskedChar',     {fg=p.base04, bg=nil, attr=nil, sp=nil})\n    hi('LightspeedUnlabeledMatch', {fg=p.base05, bg=nil, attr='bold', sp=nil})\n    hi('LightspeedGreyWash',       {link='Comment'})\n    hi('LightspeedUniqueChar',     {link='LightspeedUnlabeledMatch'})\n    hi('LightspeedOneCharMatch',   {link='LightspeedShortcut'})\n    hi('LightspeedPendingOpArea',  {link='IncSearch'})\n    hi('LightspeedCursor',         {link='Cursor'})\n  end\n\n  if H.has_integration('glepnir/dashboard-nvim') then\n    hi('DashboardCenter',   {link='Delimiter'})\n    hi('DashboardFooter',   {link='Title'})\n    hi('DashboardHeader',   {link='Title'})\n    hi('DashboardShortCut', {link='WarningMsg'})\n  end\n\n  if H.has_integration('glepnir/lspsaga.nvim') then\n    hi('LspSagaCodeActionBorder',  {fg=p.base0F, bg=nil, attr=nil,    sp=nil})\n    hi('LspSagaCodeActionContent', {fg=p.base05, bg=nil, attr=nil,    sp=nil})\n    hi('LspSagaCodeActionTitle',   {fg=p.base0D, bg=nil, attr='bold', sp=nil})\n\n    hi('Definitions',            {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n    hi('DefinitionsIcon',        {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('FinderParam',            {fg=p.base08, bg=nil, attr=nil, sp=nil})\n    hi('FinderVirtText',         {fg=p.base09, bg=nil, attr=nil, sp=nil})\n    hi('LspSagaAutoPreview',     {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('LspSagaFinderSelection', {fg=p.base0A, bg=nil, attr=nil, sp=nil})\n    hi('LspSagaLspFinderBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('References',             {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n    hi('ReferencesIcon',         {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('TargetFileName',         {fg=p.base05, bg=nil, attr=nil, sp=nil})\n\n    hi('FinderSpinner',       {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n    hi('FinderSpinnerBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('FinderSpinnerTitle',  {link='Title'})\n\n    hi('LspSagaDefPreviewBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n\n    hi('LspSagaHoverBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n\n    hi('LspSagaRenameBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n\n    hi('LspSagaDiagnosticBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('LspSagaDiagnosticHeader', {link='Title'})\n    hi('LspSagaDiagnosticSource', {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n\n    hi('LspSagaBorderTitle', {link='Title'})\n\n    hi('LspSagaSignatureHelpBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n\n    hi('LSOutlinePreviewBorder', {fg=p.base0F, bg=nil, attr=nil, sp=nil})\n    hi('OutlineDetail',          {fg=p.base03, bg=nil, attr=nil, sp=nil})\n    hi('OutlineFoldPrefix',      {fg=p.base08, bg=nil, attr=nil, sp=nil})\n    hi('OutlineIndentEvn',       {fg=p.base04, bg=nil, attr=nil, sp=nil})\n    hi('OutlineIndentOdd',       {fg=p.base05, bg=nil, attr=nil, sp=nil})\n  end\n\n  if H.has_integration('HiPhish/rainbow-delimiters.nvim') then\n    hi('RainbowDelimiterBlue',   {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('RainbowDelimiterCyan',   {fg=p.base0C, bg=nil, attr=nil, sp=nil})\n    hi('RainbowDelimiterGreen',  {fg=p.base0B, bg=nil, attr=nil, sp=nil})\n    hi('RainbowDelimiterOrange', {fg=p.base09, bg=nil, attr=nil, sp=nil})\n    hi('RainbowDelimiterRed',    {fg=p.base08, bg=nil, attr=nil, sp=nil})\n    hi('RainbowDelimiterViolet', {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n    hi('RainbowDelimiterYellow', {fg=p.base0A, bg=nil, attr=nil, sp=nil})\n  end\n\n  if H.has_integration('hrsh7th/nvim-cmp') then\n    hi('CmpItemAbbr',           {fg=p.base05, bg=nil,      attr=nil,    sp=nil})\n    hi('CmpItemAbbrDeprecated', {fg=p.base03, bg=nil,      attr=nil,    sp=nil})\n    hi('CmpItemAbbrMatch',      {fg=p.base0A, bg=nil,      attr='bold', sp=nil})\n    hi('CmpItemAbbrMatchFuzzy', {fg=p.base0A, bg=nil,      attr='bold', sp=nil})\n    hi('CmpItemKind',           {fg=p.base0F, bg=p.base01, attr=nil,    sp=nil})\n    hi('CmpItemMenu',           {fg=p.base05, bg=p.base01, attr=nil,    sp=nil})\n\n    hi('CmpItemKindClass',         {link='Type'})\n    hi('CmpItemKindColor',         {link='Special'})\n    hi('CmpItemKindConstant',      {link='Constant'})\n    hi('CmpItemKindConstructor',   {link='Type'})\n    hi('CmpItemKindEnum',          {link='Structure'})\n    hi('CmpItemKindEnumMember',    {link='Structure'})\n    hi('CmpItemKindEvent',         {link='Exception'})\n    hi('CmpItemKindField',         {link='Structure'})\n    hi('CmpItemKindFile',          {link='Tag'})\n    hi('CmpItemKindFolder',        {link='Directory'})\n    hi('CmpItemKindFunction',      {link='Function'})\n    hi('CmpItemKindInterface',     {link='Structure'})\n    hi('CmpItemKindKeyword',       {link='Keyword'})\n    hi('CmpItemKindMethod',        {link='Function'})\n    hi('CmpItemKindModule',        {link='Structure'})\n    hi('CmpItemKindOperator',      {link='Operator'})\n    hi('CmpItemKindProperty',      {link='Structure'})\n    hi('CmpItemKindReference',     {link='Tag'})\n    hi('CmpItemKindSnippet',       {link='Special'})\n    hi('CmpItemKindStruct',        {link='Structure'})\n    hi('CmpItemKindText',          {link='Statement'})\n    hi('CmpItemKindTypeParameter', {link='Type'})\n    hi('CmpItemKindUnit',          {link='Special'})\n    hi('CmpItemKindValue',         {link='Identifier'})\n    hi('CmpItemKindVariable',      {link='Delimiter'})\n  end\n\n  if H.has_integration('ibhagwan/fzf-lua') then\n    hi('FzfLuaBufFlagAlt', {link='Special'})\n    hi('FzfLuaBufFlagCur', {link='CursorLineNr'})\n    hi('FzfLuaBufNr',      {link='DiagnosticHint'})\n    hi('FzfLuaHeaderBind', {link='DiagnosticWarn'})\n    hi('FzfLuaHeaderText', {link='DiagnosticInfo'})\n    hi('FzfLuaLiveSym',    {link='DiagnosticHint'})\n    hi('FzfLuaPathColNr',  {link='DiagnosticHint'})\n    hi('FzfLuaPathLineNr', {link='DiagnosticInfo'})\n    hi('FzfLuaTabMarker',  {link='DiagnosticHint'})\n    hi('FzfLuaTabTitle',   {link='Title'})\n    hi('FzfLuaTitle',      {link='FloatTitle'})\n  end\n\n  if H.has_integration('justinmk/vim-sneak') then\n    hi('Sneak',      {fg=p.base00, bg=p.base0E, attr=nil,    sp=nil})\n    hi('SneakScope', {fg=p.base00, bg=p.base07, attr=nil,    sp=nil})\n    hi('SneakLabel', {fg=p.base00, bg=p.base0E, attr='bold', sp=nil})\n  end\n\n  -- 'kevinhwang91/nvim-bqf'\n  if H.has_integration('kevinhwang91/nvim-bqf') then\n    hi('BqfPreviewFloat', {link='NormalFloat'})\n    hi('BqfPreviewTitle', {fg=p.base0D, bg=p.base01, attr=nil, sp=nil})\n    hi('BqfSign',         {fg=p.base0C, bg=p.base01, attr=nil, sp=nil})\n  end\n\n  -- 'kevinhwang91/nvim-ufo'\n  -- Everything works correctly out of the box\n\n  if H.has_integration('lewis6991/gitsigns.nvim') then\n    hi('GitSignsAdd',             {fg=p.base0B, bg=p.base01, attr=nil, sp=nil})\n    hi('GitSignsAddLn',           {link='GitSignsAdd'})\n    hi('GitSignsAddInline',       {link='GitSignsAdd'})\n\n    hi('GitSignsChange',          {fg=p.base0E, bg=p.base01, attr=nil, sp=nil})\n    hi('GitSignsChangeLn',        {link='GitSignsChange'})\n    hi('GitSignsChangeInline',    {link='GitSignsChange'})\n\n    hi('GitSignsDelete',          {fg=p.base08, bg=p.base01, attr=nil, sp=nil})\n    hi('GitSignsDeleteLn',        {link='GitSignsDelete'})\n    hi('GitSignsDeleteInline',    {link='GitSignsDelete'})\n\n    hi('GitSignsUntracked',       {fg=p.base0D, bg=p.base01, attr=nil, sp=nil})\n    hi('GitSignsUntrackedLn',     {link='GitSignsUntracked'})\n    hi('GitSignsUntrackedInline', {link='GitSignsUntracked'})\n  end\n\n  if H.has_integration('lukas-reineke/indent-blankline.nvim') then\n    hi('IndentBlanklineChar',         {fg=p.base02, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineContextChar',  {fg=p.base0F, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineContextStart', {fg=nil,      bg=nil, attr='underline,nocombine', sp=p.base0F})\n    hi('IndentBlanklineIndent1',      {fg=p.base08, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent2',      {fg=p.base09, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent3',      {fg=p.base0A, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent4',      {fg=p.base0B, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent5',      {fg=p.base0C, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent6',      {fg=p.base0D, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent7',      {fg=p.base0E, bg=nil, attr='nocombine',           sp=nil})\n    hi('IndentBlanklineIndent8',      {fg=p.base0F, bg=nil, attr='nocombine',           sp=nil})\n  end\n\n  if H.has_integration('MeanderingProgrammer/render-markdown.nvim') then\n    hi('RenderMarkdownBullet',     {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownChecked',    {link='DiagnosticOk'})\n    hi('RenderMarkdownCode',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownCodeInline', {link='Normal'})\n    hi('RenderMarkdownDash',       {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH1',         {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH1Bg',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownH2',         {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH2Bg',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownH3',         {fg=p.base0B, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH3Bg',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownH4',         {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH4Bg',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownH5',         {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH5Bg',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownH6',         {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n    hi('RenderMarkdownH6Bg',       {fg=nil,      bg=p.base01, attr=nil, sp=nil})\n    hi('RenderMarkdownTodo',       {link='Todo'})\n    hi('RenderMarkdownUnchecked',  {link='DiagnosticWarn'})\n  end\n\n  if H.has_integration('neoclide/coc.nvim') then\n    hi('CocCodeLens',             {link='LspCodeLens'})\n    hi('CocDisabled',             {link='Comment'})\n    hi('CocFadeOut',              {link='Comment'})\n    hi('CocMarkdownLink',         {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n    hi('CocMenuSel',              {fg=nil,      bg=p.base02, attr=nil, sp=nil})\n    hi('CocNotificationProgress', {link='CocMarkdownLink'})\n    hi('CocPumVirtualText',       {link='CocMarkdownLink'})\n    hi('CocSearch',               {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n    hi('CocSelectedText',         {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n  end\n\n  -- NeogitOrg/neogit\n  if H.has_integration('NeogitOrg/neogit') then\n    hi('NeogitCommitViewHeader',    {link='Special'})\n    hi('NeogitDiffAddHighlight',    {link='DiffAdd'})\n    hi('NeogitDiffAdd',             {link='DiffAdd'})\n    hi('NeogitDiffDeleteHighlight', {link='DiffDelete'})\n    hi('NeogitDiffDelete',          {link='DiffDelete'})\n    hi('NeogitFold',                {link='FoldColumn'})\n    hi('NeogitHunkHeader',          {fg=p.base0D, bg=nil, attr=nil,    sp=nil})\n    hi('NeogitHunkHeaderHighlight', {fg=p.base0D, bg=nil, attr='bold', sp=nil})\n    hi('NeogitNotificationError',   {link='DiagnosticError'})\n    hi('NeogitNotificationInfo',    {link='DiagnosticInfo'})\n    hi('NeogitNotificationWarning', {link='DiagnosticWarn'})\n  end\n\n  -- nvim-lualine/lualine.nvim\n  -- Everything works correctly out of the box\n\n  if H.has_integration('nvim-neo-tree/neo-tree.nvim') then\n    hi('NeoTreeDimText',              {fg=p.base03, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeDotfile',              {fg=p.base04, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeFadeText1',            {link='NeoTreeDimText'})\n    hi('NeoTreeFadeText2',            {fg=p.base02, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeGitAdded',             {fg=p.base0B, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeGitConflict',          {fg=p.base08, bg=nil,      attr='bold', sp=nil})\n    hi('NeoTreeGitDeleted',           {fg=p.base08, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeGitModified',          {fg=p.base0E, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeGitUnstaged',          {fg=p.base08, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeGitUntracked',         {fg=p.base0A, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeMessage',              {fg=p.base05, bg=p.base01, attr=nil,    sp=nil})\n    hi('NeoTreeModified',             {fg=p.base07, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeRootName',             {fg=p.base0D, bg=nil,      attr='bold', sp=nil})\n    hi('NeoTreeTabInactive',          {fg=p.base04, bg=nil,      attr=nil,    sp=nil})\n    hi('NeoTreeTabSeparatorActive',   {fg=p.base03, bg=p.base02, attr=nil,    sp=nil})\n    hi('NeoTreeTabSeparatorInactive', {fg=p.base01, bg=p.base01, attr=nil,    sp=nil})\n  end\n\n  if H.has_integration('nvim-telescope/telescope.nvim') then\n    hi('TelescopeBorder',         {fg=p.base0F, bg=nil,      attr=nil,    sp=nil})\n    hi('TelescopeMatching',       {fg=p.base0A, bg=nil,      attr=nil,    sp=nil})\n    hi('TelescopeMultiSelection', {fg=nil,      bg=p.base01, attr='bold', sp=nil})\n    hi('TelescopeSelection',      {fg=nil,      bg=p.base01, attr='bold', sp=nil})\n  end\n\n  if H.has_integration('nvim-tree/nvim-tree.lua') then\n    hi('NvimTreeExecFile',     {fg=p.base0B, bg=nil,      attr='bold',           sp=nil})\n    hi('NvimTreeFolderIcon',   {fg=p.base03, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeGitDeleted',   {fg=p.base08, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeGitDirty',     {fg=p.base08, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeGitMerge',     {fg=p.base0C, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeGitNew',       {fg=p.base0A, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeGitRenamed',   {fg=p.base0E, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeGitStaged',    {fg=p.base0B, bg=nil,      attr=nil,              sp=nil})\n    hi('NvimTreeImageFile',    {fg=p.base0E, bg=nil,      attr='bold',           sp=nil})\n    hi('NvimTreeIndentMarker', {link='NvimTreeFolderIcon'})\n    hi('NvimTreeOpenedFile',   {link='NvimTreeExecFile'})\n    hi('NvimTreeRootFolder',   {link='NvimTreeGitRenamed'})\n    hi('NvimTreeSpecialFile',  {fg=p.base0D, bg=nil,      attr='bold,underline', sp=nil})\n    hi('NvimTreeSymlink',      {fg=p.base0F, bg=nil,      attr='bold',           sp=nil})\n    hi('NvimTreeWindowPicker', {fg=p.base05, bg=p.base01, attr=\"bold\",           sp=nil})\n  end\n\n  if H.has_integration('OXY2DEV/helpview.nvim') then\n    hi('HelpviewHeading1',     {link='markdownH1'})\n    hi('HelpviewHeading2',     {link='markdownH2'})\n    hi('HelpviewHeading3',     {link='markdownH3'})\n    hi('HelpviewHeading4',     {link='markdownH4'})\n    hi('HelpviewMentionlink',  {fg=nil,      bg=nil, attr='underline', sp=nil})\n    hi('HelpviewOptionlink',   {fg=p.base0D, bg=nil, attr='underline', sp=nil})\n    hi('HelpviewTaglink',      {fg=p.base0A, bg=nil, attr='bold',      sp=nil})\n    hi('HelpviewTitle',        {link='Title'})\n  end\n\n  if H.has_integration('OXY2DEV/markview.nvim') then\n    hi('MarkviewPalette0',     {fg=p.base0E, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette0Fg',   {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette0Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette0Sign', {fg=p.base0E, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette1',     {fg=p.base08, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette1Fg',   {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette1Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette1Sign', {fg=p.base08, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette2',     {fg=p.base09, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette2Fg',   {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette2Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette2Sign', {fg=p.base09, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette3',     {fg=p.base0A, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette3Fg',   {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette3Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette3Sign', {fg=p.base0A, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette4',     {fg=p.base0B, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette4Fg',   {fg=p.base0B, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette4Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette4Sign', {fg=p.base0B, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette5',     {fg=p.base0C, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette5Fg',   {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette5Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette5Sign', {fg=p.base0C, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette6',     {fg=p.base0D, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette6Fg',   {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette6Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette6Sign', {fg=p.base0D, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette7',     {fg=p.base0F, bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette7Fg',   {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n    hi('MarkviewPalette7Bg',   {fg=nil,      bg=p.base00, attr=nil, sp=nil})\n    hi('MarkviewPalette7Sign', {fg=p.base0F, bg=nil,      attr=nil, sp=nil})\n  end\n\n  if H.has_integration('phaazon/hop.nvim') then\n    hi('HopNextKey',   {fg=p.base0E, bg=nil, attr='bold,nocombine', sp=nil})\n    hi('HopNextKey1',  {fg=p.base08, bg=nil, attr='bold,nocombine', sp=nil})\n    hi('HopNextKey2',  {fg=p.base04, bg=nil, attr='bold,nocombine', sp=nil})\n    hi('HopPreview',   {fg=p.base09, bg=nil, attr='bold,nocombine', sp=nil})\n    hi('HopUnmatched', {link='Comment'})\n  end\n\n  if H.has_integration('rcarriga/nvim-dap-ui') then\n    hi('DapUIScope',                   {link='Title'})\n    hi('DapUIType',                    {link='Type'})\n    hi('DapUIModifiedValue',           {fg=p.base0E, bg=nil, attr='bold', sp=nil})\n    hi('DapUIDecoration',              {link='Title'})\n    hi('DapUIThread',                  {link='String'})\n    hi('DapUIStoppedThread',           {link='Title'})\n    hi('DapUISource',                  {link='Directory'})\n    hi('DapUILineNumber',              {link='Title'})\n    hi('DapUIFloatBorder',             {link='SpecialChar'})\n    hi('DapUIWatchesEmpty',            {link='ErrorMsg'})\n    hi('DapUIWatchesValue',            {link='String'})\n    hi('DapUIWatchesError',            {link='DiagnosticError'})\n    hi('DapUIBreakpointsPath',         {link='Directory'})\n    hi('DapUIBreakpointsInfo',         {link='DiagnosticInfo'})\n    hi('DapUIBreakpointsCurrentLine',  {fg=p.base0B, bg=nil, attr='bold', sp=nil})\n    hi('DapUIBreakpointsDisabledLine', {link='Comment'})\n  end\n\n  if H.has_integration('rcarriga/nvim-notify') then\n    hi('NotifyDEBUGBorder', {fg=p.base03, bg=nil, attr=nil, sp=nil})\n    hi('NotifyDEBUGIcon',   {link='NotifyDEBUGBorder'})\n    hi('NotifyDEBUGTitle',  {link='NotifyDEBUGBorder'})\n    hi('NotifyERRORBorder', {fg=p.base08, bg=nil, attr=nil, sp=nil})\n    hi('NotifyERRORIcon',   {link='NotifyERRORBorder'})\n    hi('NotifyERRORTitle',  {link='NotifyERRORBorder'})\n    hi('NotifyINFOBorder',  {fg=p.base0C, bg=nil, attr=nil, sp=nil})\n    hi('NotifyINFOIcon',    {link='NotifyINFOBorder'})\n    hi('NotifyINFOTitle',   {link='NotifyINFOBorder'})\n    hi('NotifyTRACEBorder', {fg=p.base0D, bg=nil, attr=nil, sp=nil})\n    hi('NotifyTRACEIcon',   {link='NotifyTRACEBorder'})\n    hi('NotifyTRACETitle',  {link='NotifyTRACEBorder'})\n    hi('NotifyWARNBorder',  {fg=p.base0E, bg=nil, attr=nil, sp=nil})\n    hi('NotifyWARNIcon',    {link='NotifyWARNBorder'})\n    hi('NotifyWARNTitle',   {link='NotifyWARNBorder'})\n  end\n\n  if H.has_integration('rlane/pounce.nvim') then\n    hi('PounceMatch',      {fg=p.base00, bg=p.base05, attr='bold,nocombine', sp=nil})\n    hi('PounceGap',        {fg=p.base00, bg=p.base03, attr='bold,nocombine', sp=nil})\n    hi('PounceAccept',     {fg=p.base00, bg=p.base08, attr='bold,nocombine', sp=nil})\n    hi('PounceAcceptBest', {fg=p.base00, bg=p.base0B, attr='bold,nocombine', sp=nil})\n  end\n\n  if H.has_integration('romgrk/barbar.nvim') then\n    hi('BufferCurrent',       {fg=p.base05, bg=p.base02, attr='bold', sp=nil})\n    hi('BufferCurrentIcon',   {fg=nil,      bg=p.base02, attr=nil,    sp=nil})\n    hi('BufferCurrentIndex',  {link='BufferCurrentIcon'})\n    hi('BufferCurrentMod',    {fg=p.base08, bg=p.base02, attr='bold', sp=nil})\n    hi('BufferCurrentSign',   {link='BufferCurrent'})\n    hi('BufferCurrentTarget', {fg=p.base0E, bg=p.base02, attr='bold', sp=nil})\n\n    hi('BufferInactive',       {fg=p.base04, bg=p.base01, attr=nil,    sp=nil})\n    hi('BufferInactiveIcon',   {fg=nil,      bg=p.base01, attr=nil,    sp=nil})\n    hi('BufferInactiveIndex',  {link='BufferInactiveIcon'})\n    hi('BufferInactiveMod',    {fg=p.base08, bg=p.base01, attr=nil,    sp=nil})\n    hi('BufferInactiveSign',   {link='BufferInactive'})\n    hi('BufferInactiveTarget', {fg=p.base0E, bg=p.base01, attr='bold', sp=nil})\n\n    hi('BufferOffset',      {link='Normal'})\n    hi('BufferTabpages',    {fg=p.base01, bg=p.base0A, attr='bold', sp=nil})\n    hi('BufferTabpageFill', {link='Normal'})\n\n    hi('BufferVisible',       {fg=p.base05, bg=p.base01, attr='bold', sp=nil})\n    hi('BufferVisibleIcon',   {fg=nil,      bg=p.base01, attr=nil,    sp=nil})\n    hi('BufferVisibleIndex',  {link='BufferVisibleIcon'})\n    hi('BufferVisibleMod',    {fg=p.base08, bg=p.base01, attr='bold', sp=nil})\n    hi('BufferVisibleSign',   {link='BufferVisible'})\n    hi('BufferVisibleTarget', {fg=p.base0E, bg=p.base01, attr='bold', sp=nil})\n  end\n\n  -- stevearc/aerial.nvim\n  -- Everything works correctly out of the box\n\n  if H.has_integration('williamboman/mason.nvim') then\n    hi('MasonError',                       {fg=p.base08, bg=nil,      attr=nil,    sp=nil})\n    hi('MasonHeader',                      {fg=p.base00, bg=p.base0D, attr='bold', sp=nil})\n    hi('MasonHeaderSecondary',             {fg=p.base00, bg=p.base0F, attr='bold', sp=nil})\n    hi('MasonHeading',                     {link='Bold'})\n    hi('MasonHighlight',                   {fg=p.base0F, bg=nil,      attr=nil,    sp=nil})\n    hi('MasonHighlightBlock',              {fg=p.base00, bg=p.base0F, attr=nil,    sp=nil})\n    hi('MasonHighlightBlockBold',          {link='MasonHeaderSecondary'})\n    hi('MasonHighlightBlockBoldSecondary', {link='MasonHeader'})\n    hi('MasonHighlightBlockSecondary',     {fg=p.base00, bg=p.base0D, attr=nil,    sp=nil})\n    hi('MasonHighlightSecondary',          {fg=p.base0D, bg=nil,      attr=nil,    sp=nil})\n    hi('MasonLink',                        {link='MasonHighlight'})\n    hi('MasonMuted',                       {link='Comment'})\n    hi('MasonMutedBlock',                  {fg=p.base00, bg=p.base03, attr=nil,    sp=nil})\n    hi('MasonMutedBlockBold',              {fg=p.base00, bg=p.base03, attr='bold', sp=nil})\n  end\n  -- stylua: ignore end\n\n  -- Terminal colors\n  vim.g.terminal_color_0 = palette.base00\n  vim.g.terminal_color_1 = palette.base08\n  vim.g.terminal_color_2 = palette.base0B\n  vim.g.terminal_color_3 = palette.base0A\n  vim.g.terminal_color_4 = palette.base0D\n  vim.g.terminal_color_5 = palette.base0E\n  vim.g.terminal_color_6 = palette.base0C\n  vim.g.terminal_color_7 = palette.base05\n  vim.g.terminal_color_8 = palette.base03\n  vim.g.terminal_color_9 = palette.base08\n  vim.g.terminal_color_10 = palette.base0B\n  vim.g.terminal_color_11 = palette.base0A\n  vim.g.terminal_color_12 = palette.base0D\n  vim.g.terminal_color_13 = palette.base0E\n  vim.g.terminal_color_14 = palette.base0C\n  vim.g.terminal_color_15 = palette.base07\nend\n\nH.has_integration = function(name)\n  local entry = MiniBase16.config.plugins[name]\n  if entry == nil then return MiniBase16.config.plugins.default end\n  return entry\nend\n\nH.highlight_gui = function(group, args)\n  -- NOTE: using `string.format` instead of gradually growing string with `..`\n  -- is faster. Crude estimate for this particular case: whole colorscheme\n  -- loading decreased from ~3.6ms to ~3.0ms, i.e. by about 20%.\n  local command\n  if args.link ~= nil then\n    command = string.format('highlight! link %s %s', group, args.link)\n  else\n    command = string.format(\n      'highlight %s guifg=%s guibg=%s gui=%s guisp=%s blend=%s',\n      group,\n      args.fg or 'NONE',\n      args.bg or 'NONE',\n      args.attr or 'NONE',\n      args.sp or 'NONE',\n      args.blend or 'NONE'\n    )\n  end\n  vim.cmd(command)\nend\n\nH.highlight_both = function(group, args)\n  local command\n  if args.link ~= nil then\n    command = string.format('highlight! link %s %s', group, args.link)\n  else\n    command = string.format(\n      'highlight %s guifg=%s ctermfg=%s guibg=%s ctermbg=%s gui=%s cterm=%s guisp=%s blend=%s',\n      group,\n      args.fg and args.fg.gui or 'NONE',\n      args.fg and args.fg.cterm or 'NONE',\n      args.bg and args.bg.gui or 'NONE',\n      args.bg and args.bg.cterm or 'NONE',\n      args.attr or 'NONE',\n      args.attr or 'NONE',\n      args.sp and args.sp.gui or 'NONE',\n      args.blend or 'NONE'\n    )\n  end\n  vim.cmd(command)\nend\n\n-- Compound (gui and cterm) palette -------------------------------------------\nH.make_compound_palette = function(palette, use_cterm)\n  local cterm_table = use_cterm\n  if type(use_cterm) == 'boolean' then cterm_table = MiniBase16.rgb_palette_to_cterm_palette(palette) end\n\n  local res = {}\n  for name, _ in pairs(palette) do\n    res[name] = { gui = palette[name], cterm = cterm_table[name] }\n  end\n  return res\nend\n\n-- Optimal scales. Make a set of equally spaced hues which are as different to\n-- present hues as possible\nH.make_different_hues = function(present_hues, n)\n  local max_offset = math.floor(360 / n + 0.5)\n\n  local dist, best_dist = nil, -math.huge\n  local best_hues, new_hues\n\n  for offset = 0, max_offset - 1, 1 do\n    new_hues = H.make_hue_scale(n, offset)\n\n    -- Compute distance as usual 'minimum distance' between two sets\n    dist = H.dist_circle_set(new_hues, present_hues)\n\n    -- Decide if it is the best\n    if dist > best_dist then\n      best_hues, best_dist = new_hues, dist\n    end\n  end\n\n  return best_hues\nend\n\nH.make_hue_scale = function(n, offset)\n  local step = math.floor(360 / n + 0.5)\n  local res = {}\n  for i = 0, n - 1, 1 do\n    table.insert(res, (offset + i * step) % 360)\n  end\n  return res\nend\n\n-- Terminal colors ------------------------------------------------------------\n-- Sources:\n-- - https://github.com/shawncplus/Vim-toCterm/blob/master/lib/Xterm.php\n-- - https://gist.github.com/MicahElliott/719710\n-- stylua: ignore start\nH.cterm_first16 = {\n  { r = 0,   g = 0,   b = 0 },\n  { r = 205, g = 0,   b = 0 },\n  { r = 0,   g = 205, b = 0 },\n  { r = 205, g = 205, b = 0 },\n  { r = 0,   g = 0,   b = 238 },\n  { r = 205, g = 0,   b = 205 },\n  { r = 0,   g = 205, b = 205 },\n  { r = 229, g = 229, b = 229 },\n  { r = 127, g = 127, b = 127 },\n  { r = 255, g = 0,   b = 0 },\n  { r = 0,   g = 255, b = 0 },\n  { r = 255, g = 255, b = 0 },\n  { r = 92,  g = 92,  b = 255 },\n  { r = 255, g = 0,   b = 255 },\n  { r = 0,   g = 255, b = 255 },\n  { r = 255, g = 255, b = 255 },\n}\n-- stylua: ignore end\n\nH.cterm_basis = { 0, 95, 135, 175, 215, 255 }\n\nH.cterm2rgb = function(i)\n  if i < 16 then return H.cterm_first16[i + 1] end\n  if 16 <= i and i <= 231 then\n    i = i - 16\n    local r = H.cterm_basis[math.floor(i / 36) % 6 + 1]\n    local g = H.cterm_basis[math.floor(i / 6) % 6 + 1]\n    local b = H.cterm_basis[i % 6 + 1]\n    return { r = r, g = g, b = b }\n  end\n  if 232 <= i and i <= 255 then\n    local c = 8 + (i - 232) * 10\n    return { r = c, g = c, b = c }\n  end\nend\n\nH.ensure_cterm_palette = function()\n  if H.cterm_palette then return end\n  H.cterm_palette = {}\n  for i = 0, 255 do\n    H.cterm_palette[i] = H.cterm2rgb(i)\n  end\nend\n\n-- Color conversion -----------------------------------------------------------\n-- Source: https://www.easyrgb.com/en/math.php\n-- Accuracy is usually around 2-3 decimal digits, which should be fine\n\n-- HEX <-> CIELCh(uv)\nH.hex2lch = function(hex)\n  local res = hex\n  for _, f in pairs({ H.hex2rgb, H.rgb2xyz, H.xyz2luv, H.luv2lch }) do\n    res = f(res)\n  end\n  return res\nend\n\nH.lch2hex = function(lch)\n  local res = lch\n  for _, f in pairs({ H.lch2luv, H.luv2xyz, H.xyz2rgb, H.rgb2hex }) do\n    res = f(res)\n  end\n  return res\nend\n\n-- HEX <-> RGB\nH.hex2rgb = function(hex)\n  local dec = tonumber(hex:sub(2), 16)\n\n  local b = math.fmod(dec, 256)\n  local g = math.fmod((dec - b) / 256, 256)\n  local r = math.floor(dec / 65536)\n\n  return { r = r, g = g, b = b }\nend\n\nH.rgb2hex = function(rgb)\n  -- Round and trim values\n  local t = vim.tbl_map(function(x)\n    x = math.min(math.max(x, 0), 255)\n    return math.floor(x + 0.5)\n  end, rgb)\n\n  return '#' .. string.format('%02x', t.r) .. string.format('%02x', t.g) .. string.format('%02x', t.b)\nend\n\n-- RGB <-> XYZ\nH.rgb2xyz = function(rgb)\n  local t = vim.tbl_map(function(c)\n    c = c / 255\n    if c > 0.04045 then\n      c = ((c + 0.055) / 1.055) ^ 2.4\n    else\n      c = c / 12.92\n    end\n    return 100 * c\n  end, rgb)\n\n  -- Source of better matrix: http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html\n  local x = 0.41246 * t.r + 0.35757 * t.g + 0.18043 * t.b\n  local y = 0.21267 * t.r + 0.71515 * t.g + 0.07217 * t.b\n  local z = 0.01933 * t.r + 0.11919 * t.g + 0.95030 * t.b\n  return { x = x, y = y, z = z }\nend\n\nH.xyz2rgb = function(xyz)\n  -- Source of better matrix: http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html\n  -- stylua: ignore start\n  local r =  3.24045 * xyz.x - 1.53713 * xyz.y - 0.49853 * xyz.z\n  local g = -0.96927 * xyz.x + 1.87601 * xyz.y + 0.04155 * xyz.z\n  local b =  0.05564 * xyz.x - 0.20403 * xyz.y + 1.05722 * xyz.z\n  -- stylua: ignore end\n\n  return vim.tbl_map(function(c)\n    c = c / 100\n    if c > 0.0031308 then\n      c = 1.055 * (c ^ (1 / 2.4)) - 0.055\n    else\n      c = 12.92 * c\n    end\n    return 255 * c\n  end, {\n    r = r,\n    g = g,\n    b = b,\n  })\nend\n\n-- XYZ <-> CIELuv\n-- Using white reference for D65 and 2 degrees\nH.ref_u = (4 * 95.047) / (95.047 + (15 * 100) + (3 * 108.883))\nH.ref_v = (9 * 100) / (95.047 + (15 * 100) + (3 * 108.883))\n\nH.xyz2luv = function(xyz)\n  local x, y, z = xyz.x, xyz.y, xyz.z\n  if x + y + z == 0 then return { l = 0, u = 0, v = 0 } end\n\n  local var_u = 4 * x / (x + 15 * y + 3 * z)\n  local var_v = 9 * y / (x + 15 * y + 3 * z)\n  local var_y = y / 100\n  if var_y > 0.008856 then\n    var_y = var_y ^ (1 / 3)\n  else\n    var_y = (7.787 * var_y) + (16 / 116)\n  end\n\n  local l = (116 * var_y) - 16\n  local u = 13 * l * (var_u - H.ref_u)\n  local v = 13 * l * (var_v - H.ref_v)\n  return { l = l, u = u, v = v }\nend\n\nH.luv2xyz = function(luv)\n  if luv.l == 0 then return { x = 0, y = 0, z = 0 } end\n\n  local var_y = (luv.l + 16) / 116\n  if var_y ^ 3 > 0.008856 then\n    var_y = var_y ^ 3\n  else\n    var_y = (var_y - 16 / 116) / 7.787\n  end\n\n  local var_u = luv.u / (13 * luv.l) + H.ref_u\n  local var_v = luv.v / (13 * luv.l) + H.ref_v\n\n  local y = var_y * 100\n  local x = -(9 * y * var_u) / ((var_u - 4) * var_v - var_u * var_v)\n  local z = (9 * y - 15 * var_v * y - var_v * x) / (3 * var_v)\n  return { x = x, y = y, z = z }\nend\n\n-- CIELuv <-> CIELCh(uv)\nH.tau = 2 * math.pi\n\nH.luv2lch = function(luv)\n  local c = math.sqrt(luv.u ^ 2 + luv.v ^ 2)\n  local h\n  if c == 0 then\n    h = 0\n  else\n    -- Convert [-pi, pi] radians to [0, 360] degrees\n    h = (math.atan2(luv.v, luv.u) % H.tau) * 360 / H.tau\n  end\n  return { l = luv.l, c = c, h = h }\nend\n\nH.lch2luv = function(lch)\n  local angle = lch.h * H.tau / 360\n  local u = lch.c * math.cos(angle)\n  local v = lch.c * math.sin(angle)\n  return { l = lch.l, u = u, v = v }\nend\n\n-- Distances ------------------------------------------------------------------\nH.dist_circle = function(x, y)\n  local d = math.abs(x - y) % 360\n  return d > 180 and (360 - d) or d\nend\n\nH.dist_circle_set = function(set1, set2)\n  -- Minimum distance between all pairs\n  local dist = math.huge\n  local d\n  for _, x in pairs(set1) do\n    for _, y in pairs(set2) do\n      d = H.dist_circle(x, y)\n      if dist > d then dist = d end\n    end\n  end\n  return dist\nend\n\nH.nearest_rgb_id = function(rgb_target, rgb_palette)\n  local best_dist = math.huge\n  local best_id, dist\n  for id, rgb in pairs(rgb_palette) do\n    dist = math.abs(rgb_target.r - rgb.r) + math.abs(rgb_target.g - rgb.g) + math.abs(rgb_target.b - rgb.b)\n    if dist < best_dist then\n      best_id, best_dist = id, dist\n    end\n  end\n\n  return best_id\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.base16) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nreturn MiniBase16\n"
  },
  {
    "path": "lua/mini/basics.lua",
    "content": "--- *mini.basics* Common configuration presets\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Install, create 'init.lua', add `require('mini.basics').setup()`, and you\n--- are good to go.\n---\n--- Features:\n--- - Presets for common options. It will only change option if it wasn't\n---   manually set before. See more in |MiniBasics.config.options|.\n---\n--- - Presets for common mappings. It will only add a mapping if it wasn't\n---   manually created before. See more in |MiniBasics.config.mappings|.\n---\n--- - Presets for common autocommands. See more in |MiniBasics.config.autocommands|.\n---\n--- - Reverse compatibility is a high priority. Any decision to change already\n---   present behavior will be made with great care.\n---\n--- Notes:\n--- - Main goal of this module is to provide a relatively easier way for\n---   new-ish Neovim users to have better \"works out of the box\" experience\n---   while having documented relevant options/mappings/autocommands to study.\n---   It is based partially on survey among Neovim users and partially is\n---   coming from personal preferences.\n---\n---   However, more seasoned users almost surely will find something useful.\n---\n---   Still, it is recommended to read about used options/mappings/autocommands\n---   and decide if they are needed. The main way to do that is by reading\n---   Neovim's help pages (linked in help file) and this module's source code\n---   (thoroughly documented for easier comprehension).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.basics').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniBasics`\n--- which you can use for scripting or manually (with `:lua MiniBasics.*`).\n---\n--- See |MiniBasics.config| for available config settings.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Comparisons ~\n---\n--- - [tpope/vim-sensible](https://github.com/tpope/vim-sensible):\n---     - Most of 'tpope/vim-sensible' is already incorporated as default\n---       options in Neovim (see |nvim-defaults|). This module has a much\n---       broader effect.\n--- - [tpope/vim-unimpaired](https://github.com/tpope/vim-unimpaired):\n---     - The 'tpope/vim-unimpaired' has mapping for toggling options with `yo`\n---       prefix. This module implements similar functionality with `\\` prefix\n---       (see |MiniBasics.config.mappings|).\n---@tag MiniBasics\n\n---@diagnostic disable:undefined-field\n\n-- To study source behind presets, search for:\n-- - `-- Options ---` for `config.options`.\n-- - `-- Mappings ---` for `config.mappings`.\n-- - `-- Autocommands ---` for `config.autocommands`.\n\n-- Module definition ==========================================================\nlocal MiniBasics = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniBasics.config|.\n---\n---@usage >lua\n---   require('mini.basics').setup() -- use default config\n---   -- OR\n---   require('mini.basics').setup({}) -- replace {} with your config table\n--- <\nMiniBasics.setup = function(config)\n  -- Export module\n  _G.MiniBasics = MiniBasics\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Options ~\n--- *MiniBasics.config.options*\n---\n--- Usage example: >lua\n---\n---   require('mini.basics').setup({\n---     options = {\n---       basic = true,\n---       extra_ui = true,\n---       win_borders = 'double',\n---     }\n---   })\n--- <\n--- ## options.basic ~\n---\n--- The `config.options.basic` sets certain options to values which are quite\n--- commonly used (judging by study of available Neovim pre-configurations,\n--- public dotfiles, and surveys).\n--- Any option is changed only if it was not set manually beforehand.\n--- For exact changes, please see source code ('lua/mini/basics.lua').\n---\n--- Here is the list of affected options (put cursor on it and press |CTRL-]|):\n--- - General:\n---     - Sets |<Leader>| key to |<Space>|. Be sure to make all Leader mappings\n---       after this (otherwise they are made with default <Leader>).\n---     - Runs `:filetype plugin indent on` (see |:filetype-overview|)\n---     - |'backup'|\n---     - |'mouse'|\n---     - |'undofile'|\n---     - |'writebackup'|\n--- - Appearance\n---     - |'breakindent'|\n---     - |'cursorline'|\n---     - |'fillchars'|\n---     - |'linebreak'|\n---     - |'number'|\n---     - |'ruler'|\n---     - |'showmode'|\n---     - |'signcolumn'|\n---     - |'shortmess'|\n---     - |'splitbelow'|\n---     - |'splitkeep'|\n---     - |'splitright'|\n---     - |'termguicolors'| (on Neovim<0.10; later versions have it smartly enabled)\n---     - |'wrap'|\n--- - Editing\n---     - |'completeopt'|\n---     - |'formatoptions'|\n---     - |'ignorecase'|\n---     - |'incsearch'|\n---     - |'infercase'|\n---     - |'smartcase'|\n---     - |'smartindent'|\n---     - |'virtualedit'|\n---\n--- ## options.extra_ui ~\n---\n--- The `config.options.extra_ui` sets certain options for visual appearance\n--- which might not be aligned with common preferences, but still worth trying.\n--- Any option is changed only if it was not set manually beforehand.\n--- For exact changes, please see source code ('lua/mini/basics.lua').\n---\n--- List of affected options:\n--- - |'list'|\n--- - |'listchars'|\n--- - |'pumblend'|\n--- - |'pumheight'|\n--- - |'winblend'|\n--- - Runs `:syntax on` (see |:syntax-on|)\n---\n--- ## options.win_borders ~\n---\n--- The `config.options.win_borders` updates |'fillchars'| to have a consistent set\n--- of characters for window border (`vert`, `horiz`, `msgsep`, etc.).\n---\n--- Available values:\n--- - `'auto'` - infer from |'winborder'|. On Neovim<0.11 do nothing.\n--- - `'bold'` - bold lines.\n--- - `'dot'` - dot in every cell.\n--- - `'double'` - double line.\n--- - `'single'` - single line.\n--- - `'solid'` - no symbol, only background.\n---\n--- # Mappings ~\n--- *MiniBasics.config.mappings*\n---\n--- Usage example: >lua\n---\n---   require('mini.basics').setup({\n---     mappings = {\n---       basic = true,\n---       option_toggle_prefix = [[\\]],\n---       windows = true,\n---       move_with_alt = true,\n---     }\n---   })\n--- <\n--- If you want some mappings to be different or not made at all, set or delete\n--- them after calling |MiniBasics.setup()|.\n---\n--- ## mappings.basic ~\n---\n--- The `config.mappings.basic` creates mappings for certain commonly mapped actions\n--- (judging by study of available Neovim pre-configurations and public dotfiles).\n---\n--- Some of the mappings override built-in ones to either improve their\n--- behavior or override its default not very useful action.\n--- It will only add a mapping if it wasn't manually created before.\n---\n--- Here is a table with created mappings : >\n---\n---  |Keys   |     Modes       |                  Description                  |\n---  |-------|-----------------|-----------------------------------------------|\n---  | j     | Normal, Visual  | Move down by visible lines with no [count]    |\n---  | k     | Normal, Visual  | Move up by visible lines with no [count]      |\n---  | go    | Normal          | Add [count] empty lines after cursor          |\n---  | gO    | Normal          | Add [count] empty lines before cursor         |\n---  | gy    | Normal, Visual  | Copy to system clipboard                      |\n---  | gp    | Normal, Visual  | Paste from system clipboard                   |\n---  | gV    | Normal          | Visually select latest changed or yanked text |\n---  | g/    | Visual          | Search inside current visual selection        |\n---  | *     | Visual          | Search forward for current visual selection   |\n---  | #     | Visual          | Search backward for current visual selection  |\n---  | <C-s> | Normal, Visual, | Save and go to Normal mode                    |\n---  |       |     Insert      |                                               |\n--- <\n--- Notes:\n--- - See |[count]| for its meaning.\n--- - On Neovim>=0.10 mappings for `#` and `*` are not created as their\n---   enhanced variants are made built-in. See |v_star-default| and |v_#-default|.\n--- - On Neovim>=0.11 there are |[<Space>| / |]<Space>| for adding empty lines.\n---   The `gO` and `go` mappings are still created as they are more aligned with\n---   similarly purposed |O| and |o| keys (although sometimes conflict with |gO|).\n---\n--- ## mappings.option_toggle_prefix ~\n---\n--- The `config.mappings.option_toggle_prefix` defines a prefix used for\n--- creating mappings that toggle common options. The result mappings will be\n--- `<prefix> + <suffix>`. For example, with default value, `\\w` will toggle |'wrap'|.\n---\n--- Other viable choices for prefix are\n--- - `,` (as a mnemonic for several values to toggle).\n--- - `|` (as a same mnemonic).\n--- - `yo` (used in 'tpope/vim-unimpaired')\n--- - Something with |<Leader>| key, like `<Leader>t` (`t` for \"toggle\"). Note:\n---   if your prefix contains `<Leader>` key, make sure to set it before\n---   calling |MiniBasics.setup()| (as is done with default `basic` field of\n---   |MiniBasics.config.options|).\n---\n--- After toggling, there will be a feedback about the current option value if\n--- prior to `require('mini.basics').setup()` module wasn't silenced (see\n--- \"Silencing\" section in |mini.basics|).\n---\n--- It will only add a mapping if it wasn't manually created before.\n---\n--- Here is a list of suffixes for created toggling mappings (all in Normal mode):\n---\n--- - `b` - |'background'|.\n--- - `c` - |'cursorline'|.\n--- - `C` - |'cursorcolumn'|.\n--- - `d` - diagnostic (via |vim.diagnostic| functions).\n--- - `h` - |'hlsearch'| (or |v:hlsearch| to be precise).\n--- - `i` - |'ignorecase'|.\n--- - `l` - |'list'|.\n--- - `n` - |'number'|.\n--- - `r` - |'relativenumber'|.\n--- - `s` - |'spell'|.\n--- - `w` - |'wrap'|.\n---\n--- ## mappings.windows ~\n---\n--- The `config.mappings.windows` creates mappings for easiere window manipulation.\n---\n--- It will only add a mapping if it wasn't manually created before.\n---\n--- Here is a list with created Normal mode mappings (all respect |[count]|):\n--- - Window navigation:\n---     - `<C-h>` - focus on left window (see |CTRL-W_H|).\n---     - `<C-j>` - focus on below window (see |CTRL-W_J|).\n---     - `<C-k>` - focus on above window (see |CTRL-W_K|).\n---     - `<C-l>` - focus on right window (see |CTRL-W_L|).\n--- - Window resize (all use arrow keys; variants of |:resize|; respect |[count]|):\n---     - `<C-left>`  - decrease window width.\n---     - `<C-down>`  - decrease window height.\n---     - `<C-up>`    - increase window height.\n---     - `<C-right>` - increase window width.\n---\n--- ## mappings.move_with_alt ~\n---\n--- The `config.mappings.move_with_alt` creates mappings for a more consistent\n--- cursor move in Insert, Command, and Terminal modes. For example, it proves\n--- useful in combination of autopair plugin (like |mini.pairs|) to move right\n--- outside of inserted pairs (no matter what the pair is).\n---\n--- It will only add a mapping if it wasn't manually created before.\n---\n--- Here is a list of created mappings (`<M-x>` means `Alt`/`Meta` plus `x`):\n--- - `<M-h>` - move cursor left.  Modes: Insert, Terminal, Command.\n--- - `<M-j>` - move cursor down.  Modes: Insert, Terminal.\n--- - `<M-k>` - move cursor up.    Modes: Insert, Terminal.\n--- - `<M-l>` - move cursor right. Modes: Insert, Terminal, Command.\n---\n--- # Autocommands ~\n--- *MiniBasics.config.autocommands*\n---\n--- Usage example: >lua\n---\n---   require('mini.basics').setup({\n---     autocommands = {\n---       basic = true,\n---       relnum_in_visual_mode = true,\n---     }\n---   })\n--- <\n--- ## autocommands.basic ~\n---\n--- The `config.autocommands.basic` creates some common autocommands:\n---\n--- - Starts insert mode when opening terminal (see |:startinsert| and |TermOpen|).\n--- - Highlights yanked text for a brief period of time (see |vim.hl.on_yank()|;\n---   on Neovim<0.11 - |vim.hl.on_yank()|) and |TextYankPost|).\n---\n--- ## autocommands.relnum_in_visual_mode ~\n---\n--- The `config.autocommands.relnum_in_visual_mode` creates autocommands that\n--- enable |'relativenumber'| in linewise and blockwise Visual modes and disable\n--- otherwise. See |ModeChanged|.\nMiniBasics.config = {\n  -- Options. Set field to `false` to disable.\n  options = {\n    -- Basic options ('number', 'ignorecase', and many more)\n    basic = true,\n\n    -- Extra UI features ('winblend', 'listchars', 'pumheight', ...)\n    extra_ui = false,\n\n    -- Presets for window borders ('single', 'double', ...)\n    -- Default 'auto' infers from 'winborder' option\n    win_borders = 'auto',\n  },\n\n  -- Mappings. Set field to `false` to disable.\n  mappings = {\n    -- Basic mappings (better 'jk', save with Ctrl+S, ...)\n    basic = true,\n\n    -- Prefix for mappings that toggle common options ('wrap', 'spell', ...).\n    -- Supply empty string to not create these mappings.\n    option_toggle_prefix = [[\\]],\n\n    -- Window navigation with <C-hjkl>, resize with <C-arrow>\n    windows = false,\n\n    -- Move cursor in Insert, Command, and Terminal mode with <M-hjkl>\n    move_with_alt = false,\n  },\n\n  -- Autocommands. Set field to `false` to disable\n  autocommands = {\n    -- Basic autocommands (highlight on yank, start Insert in terminal, ...)\n    basic = true,\n\n    -- Set 'relativenumber' only in linewise and blockwise Visual mode\n    relnum_in_visual_mode = false,\n  },\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n--minidoc_afterlines_end\n\n--- Toggle diagnostic for current buffer\n---\n--- This uses |vim.diagnostic| functions per buffer.\n---\n---@return string String indicator for new state. Similar to what |:set| `{option}?` shows.\nMiniBasics.toggle_diagnostic = function()\n  local buf_id = vim.api.nvim_get_current_buf()\n  local is_enabled = H.diagnostic_is_enabled(buf_id)\n\n  local f\n  if vim.fn.has('nvim-0.10') == 1 then\n    f = function(bufnr) vim.diagnostic.enable(not is_enabled, { bufnr = bufnr }) end\n  else\n    f = is_enabled and vim.diagnostic.disable or vim.diagnostic.enable\n  end\n  f(buf_id)\n\n  local new_buf_state = not is_enabled\n\n  return new_buf_state and '  diagnostic' or 'nodiagnostic'\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniBasics.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('options', config.options, 'table')\n\n  H.check_type('options.basic', config.options.basic, 'boolean')\n  H.check_type('options.extra_ui', config.options.extra_ui, 'boolean')\n  H.check_type('options.win_borders', config.options.win_borders, 'string')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.basic', config.mappings.basic, 'boolean')\n  H.check_type('mappings.option_toggle_prefix', config.mappings.option_toggle_prefix, 'string')\n  H.check_type('mappings.windows', config.mappings.windows, 'boolean')\n  H.check_type('mappings.move_with_alt', config.mappings.move_with_alt, 'boolean')\n\n  H.check_type('autocommands', config.autocommands, 'table')\n  H.check_type('autocommands.basic', config.autocommands.basic, 'boolean')\n  H.check_type('autocommands.relnum_in_visual_mode', config.autocommands.relnum_in_visual_mode, 'boolean')\n\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniBasics.config = config\n\n  H.apply_options(config)\n  H.apply_mappings(config)\n  H.apply_autocommands(config)\nend\n\n-- Options --------------------------------------------------------------------\n--stylua: ignore\nH.apply_options = function(config)\n  -- Use `local o, opt = vim.o, vim.opt` to copy lines as is.\n  -- Or use `vim.o` and `vim.opt` directly.\n  local o, opt = H.vim_o, H.vim_opt\n\n  -- Basic options\n  if config.options.basic then\n    -- Leader key\n    if vim.g.mapleader == nil then\n      vim.g.mapleader = ' ' -- Use space as the one and only true Leader key\n    end\n\n    -- General\n    o.undofile    = true  -- Enable persistent undo (see also `:h undodir`)\n\n    o.backup      = false -- Don't store backup while overwriting the file\n    o.writebackup = false -- Don't store backup while overwriting the file\n\n    o.mouse       = 'a'   -- Enable mouse for all available modes\n\n    vim.cmd('filetype plugin indent on') -- Enable all filetype plugins\n\n    -- Appearance\n    o.breakindent   = true    -- Indent wrapped lines to match line start\n    o.cursorline    = true    -- Highlight current line\n    o.linebreak     = true    -- Wrap long lines at 'breakat' (if 'wrap' is set)\n    o.number        = true    -- Show line numbers\n    o.splitbelow    = true    -- Horizontal splits will be below\n    o.splitright    = true    -- Vertical splits will be to the right\n\n    o.ruler         = false   -- Don't show cursor position in command line\n    o.showmode      = false   -- Don't show mode in command line\n    o.wrap          = false   -- Display long lines as just one line\n\n    o.signcolumn    = 'yes'   -- Always show sign column (otherwise it will shift text)\n    o.fillchars     = 'eob: ' -- Don't show `~` outside of buffer\n\n    -- Editing\n    o.ignorecase  = true -- Ignore case when searching (use `\\C` to force not doing that)\n    o.incsearch   = true -- Show search results while typing\n    o.infercase   = true -- Infer letter cases for a richer built-in keyword completion\n    o.smartcase   = true -- Don't ignore case when searching if pattern has upper case\n    o.smartindent = true -- Make indenting smart\n\n    o.completeopt   = 'menuone,noselect' -- Customize completions\n    o.virtualedit   = 'block'            -- Allow going past the end of line in visual block mode\n    o.formatoptions = 'qjl1'             -- Don't autoformat comments\n\n    -- Neovim version dependent\n    opt.shortmess:append('WcC') -- Reduce command line messages\n    o.splitkeep = 'screen'      -- Reduce scroll during window split\n\n    if vim.fn.has('nvim-0.10') == 0 then\n      o.termguicolors = true -- Enable gui colors\n    end\n  end\n\n  -- Some opinioneted extra UI options\n  if config.options.extra_ui then\n    o.pumblend  = 10 -- Make builtin completion menus slightly transparent\n    o.pumheight = 10 -- Make popup menu smaller\n    o.winblend  = 10 -- Make floating windows slightly transparent\n\n    -- NOTE: Having `tab` present is needed because `^I` will be shown if\n    -- omitted (documented in `:h listchars`).\n    -- Having it equal to a default value should be less intrusive.\n    o.listchars = 'tab:> ,extends:…,precedes:…,nbsp:␣' -- Define which helper symbols to show\n    o.list      = true                                 -- Show some helper symbols\n\n    -- Enable syntax highlighting if it wasn't already (as it is time consuming)\n    if vim.fn.exists(\"syntax_on\") ~= 1 then vim.cmd([[syntax enable]]) end\n  end\n\n  -- Use some common window borders presets\n  local win_borders = config.options.win_borders\n  if win_borders == 'auto' and vim.fn.has('nvim-0.11') == 1 then\n    local option_value = vim.o.winborder\n    win_borders = H.winborder_map[option_value] or option_value\n  end\n  local border_chars = H.win_borders_fillchars[win_borders]\n  if border_chars ~= nil then vim.opt.fillchars:append(border_chars) end\nend\n\nH.vim_o = setmetatable({}, {\n  __newindex = function(_, name, value)\n    local was_set = vim.api.nvim_get_option_info2(name, { scope = 'global' }).was_set\n    if was_set then return end\n\n    vim.o[name] = value\n  end,\n})\n\nH.vim_opt = setmetatable({}, {\n  __index = function(_, name)\n    local was_set = vim.api.nvim_get_option_info2(name, { scope = 'global' }).was_set\n    if was_set then return { append = function() end, remove = function() end } end\n\n    return vim.opt[name]\n  end,\n})\n\n--stylua: ignore\nH.win_borders_fillchars = {\n  bold   = 'vert:┃,horiz:━,horizdown:┳,horizup:┻,verthoriz:╋,vertleft:┫,vertright:┣,msgsep:━',\n  dot    = 'vert:·,horiz:·,horizdown:·,horizup:·,verthoriz:·,vertleft:·,vertright:·,msgsep:·',\n  double = 'vert:║,horiz:═,horizdown:╦,horizup:╩,verthoriz:╬,vertleft:╣,vertright:╠,msgsep:═',\n  single = 'vert:│,horiz:─,horizdown:┬,horizup:┴,verthoriz:┼,vertleft:┤,vertright:├,msgsep:─',\n  solid  = 'vert: ,horiz: ,horizdown: ,horizup: ,verthoriz: ,vertleft: ,vertright: ,msgsep: ',\n}\nH.winborder_map = { none = 'solid', rounded = 'single', shadow = 'solid' }\n\n-- Mappings -------------------------------------------------------------------\n--stylua: ignore\nH.apply_mappings = function(config)\n  -- Use `local map = vim.keymap.set` to copy lines as is. Or use it directly.\n  local map = H.keymap_set\n\n  if config.mappings.basic then\n    -- Move by visible lines. Notes:\n    -- - Don't map in Operator-pending mode because it severely changes behavior:\n    --   like `dj` on non-wrapped line will not delete it.\n    -- - Condition on `v:count == 0` to allow easier use of relative line numbers.\n    map({ 'n', 'x' }, 'j', [[v:count == 0 ? 'gj' : 'j']], { expr = true })\n    map({ 'n', 'x' }, 'k', [[v:count == 0 ? 'gk' : 'k']], { expr = true })\n\n    -- Add empty lines before and after cursor line supporting dot-repeat\n    MiniBasics.put_empty_line = function(put_above)\n      -- This has a typical workflow for enabling dot-repeat:\n      -- - On first call it sets `operatorfunc`, caches data, and calls\n      --   `operatorfunc` on current cursor position.\n      -- - On second call it performs task: puts `v:count1` empty lines\n      --   above/below current line.\n      if type(put_above) == 'boolean' then\n        vim.o.operatorfunc = 'v:lua.MiniBasics.put_empty_line'\n        MiniBasics.cache_empty_line = { put_above = put_above }\n        return 'g@l'\n      end\n\n      local target_line = vim.fn.line('.') - (MiniBasics.cache_empty_line.put_above and 1 or 0)\n      vim.fn.append(target_line, vim.fn['repeat']({ '' }, vim.v.count1))\n    end\n\n    -- NOTE: if you don't want to support dot-repeat, use this snippet:\n    -- ```\n    -- map('n', 'gO', \"<Cmd>call append(line('.') - 1, repeat([''], v:count1))<CR>\")\n    -- map('n', 'go', \"<Cmd>call append(line('.'),     repeat([''], v:count1))<CR>\")\n    -- ```\n    map('n', 'gO', 'v:lua.MiniBasics.put_empty_line(v:true)',  { expr = true, desc = 'Put empty line above' })\n    map('n', 'go', 'v:lua.MiniBasics.put_empty_line(v:false)', { expr = true, desc = 'Put empty line below' })\n\n    -- Copy/paste with system clipboard\n    map({ 'n', 'x' }, 'gy', '\"+y', { desc = 'Copy to system clipboard' })\n    map(  'n',        'gp', '\"+p', { desc = 'Paste from system clipboard' })\n    -- - Paste in Visual with `P` to not copy selected text (`:h v_P`)\n    map(  'x',        'gp', '\"+P', { desc = 'Paste from system clipboard' })\n\n    -- Reselect latest changed, put, or yanked text\n    map('n', 'gV', '\"g`[\" . strpart(getregtype(), 0, 1) . \"g`]\"', { expr = true, replace_keycodes = false, desc = 'Visually select changed text' })\n\n    -- Search inside visually highlighted text. Use `silent = false` for it to\n    -- make effect immediately.\n    map('x', 'g/', '<esc>/\\\\%V', { silent = false, desc = 'Search inside visual selection' })\n\n    -- Search visually selected text (slightly better than builtins in\n    -- Neovim<0.10 but slightly worse than builtins in Neovim>=0.10)\n    -- TODO: Remove this after compatibility with Neovim=0.9 is dropped\n    if vim.fn.has('nvim-0.10') == 0 then\n      map('x', '*', [[y/\\V<C-R>=escape(@\", '/\\')<CR><CR>]], { desc = 'Search forward' })\n      map('x', '#', [[y?\\V<C-R>=escape(@\", '?\\')<CR><CR>]], { desc = 'Search backward' })\n    end\n\n    -- Alternative way to save and exit in Normal mode.\n    -- NOTE: Adding `redraw` helps with `cmdheight=0` if buffer is not modified\n    map(  'n',        '<C-S>', '<Cmd>silent! update | redraw<CR>',      { desc = 'Save' })\n    map({ 'i', 'x' }, '<C-S>', '<Esc><Cmd>silent! update | redraw<CR>', { desc = 'Save and go to Normal mode' })\n  end\n\n  local toggle_prefix = config.mappings.option_toggle_prefix\n  if type(toggle_prefix) == 'string' and toggle_prefix ~= '' then\n    local map_toggle = function(lhs, rhs, desc) map('n', toggle_prefix .. lhs, rhs, { desc = desc }) end\n\n    if config.silent then\n      -- Toggle without feedback\n      map_toggle('b', '<Cmd>lua vim.o.bg = vim.o.bg == \"dark\" and \"light\" or \"dark\"<CR>', \"Toggle 'background'\")\n      map_toggle('c', '<Cmd>setlocal cursorline!<CR>',                                    \"Toggle 'cursorline'\")\n      map_toggle('C', '<Cmd>setlocal cursorcolumn!<CR>',                                  \"Toggle 'cursorcolumn'\")\n      map_toggle('d', '<Cmd>lua MiniBasics.toggle_diagnostic()<CR>',                      'Toggle diagnostic')\n      map_toggle('h', '<Cmd>let v:hlsearch = 1 - v:hlsearch<CR>',                         'Toggle search highlight')\n      map_toggle('i', '<Cmd>setlocal ignorecase!<CR>',                                    \"Toggle 'ignorecase'\")\n      map_toggle('l', '<Cmd>setlocal list!<CR>',                                          \"Toggle 'list'\")\n      map_toggle('n', '<Cmd>setlocal number!<CR>',                                        \"Toggle 'number'\")\n      map_toggle('r', '<Cmd>setlocal relativenumber!<CR>',                                \"Toggle 'relativenumber'\")\n      map_toggle('s', '<Cmd>setlocal spell!<CR>',                                         \"Toggle 'spell'\")\n      map_toggle('w', '<Cmd>setlocal wrap!<CR>',                                          \"Toggle 'wrap'\")\n    else\n      map_toggle('b', '<Cmd>lua vim.o.bg = vim.o.bg == \"dark\" and \"light\" or \"dark\"; print(vim.o.bg)<CR>',       \"Toggle 'background'\")\n      map_toggle('c', '<Cmd>setlocal cursorline! cursorline?<CR>',                                               \"Toggle 'cursorline'\")\n      map_toggle('C', '<Cmd>setlocal cursorcolumn! cursorcolumn?<CR>',                                           \"Toggle 'cursorcolumn'\")\n      map_toggle('d', '<Cmd>lua print(MiniBasics.toggle_diagnostic())<CR>',                                      'Toggle diagnostic')\n      map_toggle('h', '<Cmd>let v:hlsearch = 1 - v:hlsearch | echo (v:hlsearch ? \"  \" : \"no\") . \"hlsearch\"<CR>', 'Toggle search highlight')\n      map_toggle('i', '<Cmd>setlocal ignorecase! ignorecase?<CR>',                                               \"Toggle 'ignorecase'\")\n      map_toggle('l', '<Cmd>setlocal list! list?<CR>',                                                           \"Toggle 'list'\")\n      map_toggle('n', '<Cmd>setlocal number! number?<CR>',                                                       \"Toggle 'number'\")\n      map_toggle('r', '<Cmd>setlocal relativenumber! relativenumber?<CR>',                                       \"Toggle 'relativenumber'\")\n      map_toggle('s', '<Cmd>setlocal spell! spell?<CR>',                                                         \"Toggle 'spell'\")\n      map_toggle('w', '<Cmd>setlocal wrap! wrap?<CR>',                                                           \"Toggle 'wrap'\")\n    end\n  end\n\n  if config.mappings.windows then\n    -- Window navigation\n    map('n', '<C-H>', '<C-w>h', { desc = 'Focus on left window' })\n    map('n', '<C-J>', '<C-w>j', { desc = 'Focus on below window' })\n    map('n', '<C-K>', '<C-w>k', { desc = 'Focus on above window' })\n    map('n', '<C-L>', '<C-w>l', { desc = 'Focus on right window' })\n\n    -- Window resize (respecting `v:count`)\n    map('n', '<C-Left>',  '\"<Cmd>vertical resize -\" . v:count1 . \"<CR>\"', { expr = true, replace_keycodes = false, desc = 'Decrease window width' })\n    map('n', '<C-Down>',  '\"<Cmd>resize -\"          . v:count1 . \"<CR>\"', { expr = true, replace_keycodes = false, desc = 'Decrease window height' })\n    map('n', '<C-Up>',    '\"<Cmd>resize +\"          . v:count1 . \"<CR>\"', { expr = true, replace_keycodes = false, desc = 'Increase window height' })\n    map('n', '<C-Right>', '\"<Cmd>vertical resize +\" . v:count1 . \"<CR>\"', { expr = true, replace_keycodes = false, desc = 'Increase window width' })\n  end\n\n  if config.mappings.move_with_alt then\n    -- Move only sideways in command mode. Using `silent = false` makes movements\n    -- to be immediately shown.\n    map('c', '<M-h>', '<Left>',  { silent = false, desc = 'Left' })\n    map('c', '<M-l>', '<Right>', { silent = false, desc = 'Right' })\n\n    -- Don't `noremap` in insert mode to have these keybindings behave exactly\n    -- like arrows (crucial inside TelescopePrompt)\n    map('i', '<M-h>', '<Left>',  { noremap = false, desc = 'Left' })\n    map('i', '<M-j>', '<Down>',  { noremap = false, desc = 'Down' })\n    map('i', '<M-k>', '<Up>',    { noremap = false, desc = 'Up' })\n    map('i', '<M-l>', '<Right>', { noremap = false, desc = 'Right' })\n\n    map('t', '<M-h>', '<Left>',  { desc = 'Left' })\n    map('t', '<M-j>', '<Down>',  { desc = 'Down' })\n    map('t', '<M-k>', '<Up>',    { desc = 'Up' })\n    map('t', '<M-l>', '<Right>', { desc = 'Right' })\n  end\nend\n\nH.keymap_set = function(modes, lhs, rhs, opts)\n  -- NOTE: Use `<C-H>`, `<C-Up>`, `<M-h>` casing (instead of `<C-h>`, `<C-up>`,\n  -- `<M-H>`) to match the `lhs` of keymap info. Otherwise it will say that\n  -- mapping doesn't exist when in fact it does.\n  if type(modes) == 'string' then modes = { modes } end\n\n  for _, mode in ipairs(modes) do\n    -- Don't map if mapping is already set **globally**\n    local map_info = H.get_map_info(mode, lhs)\n    if not H.is_default_keymap(mode, lhs, map_info) then return end\n\n    -- Map\n    H.map(mode, lhs, rhs, opts)\n  end\nend\n\nH.is_default_keymap = function(mode, lhs, map_info)\n  if map_info == nil then return true end\n  local rhs, desc = map_info.rhs or '', map_info.desc or ''\n\n  -- Some mappings are set by default in Neovim\n  if mode == 'n' and lhs == '<C-L>' then return rhs:find('nohl') ~= nil end\n  if mode == 'n' and lhs == 'gO' and vim.fn.has('nvim-0.11') == 1 then return desc:find('vim%.lsp') ~= nil end\n  if mode == 'i' and lhs == '<C-S>' then return desc:find('signature') ~= nil end\n  if mode == 'x' and lhs == '*' then return rhs == [[y/\\V<C-R>\"<CR>]] end\n  if mode == 'x' and lhs == '#' then return rhs == [[y?\\V<C-R>\"<CR>]] end\nend\n\nH.get_map_info = function(mode, lhs)\n  local keymaps = vim.api.nvim_get_keymap(mode)\n  for _, info in ipairs(keymaps) do\n    if info.lhs == lhs then return info end\n  end\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.apply_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniBasicsAutocommands', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  if config.autocommands.basic then\n    local f = function() vim.hl.on_yank() end\n    if vim.fn.has('nvim-0.11') == 0 then f = function() vim.highlight.on_yank() end end\n    au('TextYankPost', '*', f, 'Highlight yanked text')\n\n    local start_terminal_insert = vim.schedule_wrap(function(data)\n      -- Try to start terminal mode only if target terminal is current\n      if not (vim.api.nvim_get_current_buf() == data.buf and vim.bo.buftype == 'terminal') then return end\n      vim.cmd('startinsert')\n    end)\n    au('TermOpen', 'term://*', start_terminal_insert, 'Start builtin terminal in Insert mode')\n  end\n\n  if config.autocommands.relnum_in_visual_mode then\n    au(\n      'ModeChanged',\n      -- Show relative numbers only when they matter (linewise and blockwise\n      -- selection) and 'number' is set (avoids horizontal flickering)\n      '*:[V\\x16]*',\n      function() vim.wo.relativenumber = vim.wo.number end,\n      'Show relative line numbers'\n    )\n    au(\n      'ModeChanged',\n      '[V\\x16]*:*',\n      -- Hide relative numbers when neither linewise/blockwise mode is on\n      function() vim.wo.relativenumber = string.find(vim.fn.mode(), '^[V\\22]') ~= nil end,\n      'Hide relative line numbers'\n    )\n  end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.basics) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nif vim.fn.has('nvim-0.10') == 1 then\n  H.diagnostic_is_enabled = function(buf_id) return vim.diagnostic.is_enabled({ bufnr = buf_id }) end\nelse\n  H.diagnostic_is_enabled = function(buf_id) return not vim.diagnostic.is_disabled(buf_id) end\nend\n\nreturn MiniBasics\n"
  },
  {
    "path": "lua/mini/bracketed.lua",
    "content": "--- *mini.bracketed* Go forward/backward with square brackets\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Configurable Lua functions to go forward/backward to a certain target.\n---   Each function can be customized with:\n---     - Direction. One of \"forward\", \"backward\", \"first\" (forward starting\n---       from first one), \"last\" (backward starting from last one).\n---     - Number of times to go.\n---     - Whether to wrap on edges (going forward on last one goes to first).\n---     - Some other target specific options.\n---\n--- - Mappings using square brackets. They are created using configurable\n---   target suffix and can be selectively disabled.\n---\n---   Each mapping supports |[count]|. Mappings are created in Normal mode; for\n---   targets which move cursor in current buffer also Visual and\n---   Operator-pending (with dot-repeat) modes are supported.\n---\n---   Using `lower-suffix` and `upper-suffix` (lower and upper case suffix) for\n---   a single target the following mappings are created:\n---     - `[` + `upper-suffix` : go first.\n---     - `[` + `lower-suffix` : go backward.\n---     - `]` + `lower-suffix` : go forward.\n---     - `]` + `upper-suffix` : go last.\n---\n--- - Supported targets (for more information see help for corresponding Lua\n---   function):\n---\n---   `Target`                           `Mappings`         `Lua function`\n---   Buffer ......................... `[B` `[b` `]b` `]B` .... |MiniBracketed.buffer()|\n---   Comment block .................. `[C` `[c` `]c` `]C` .... |MiniBracketed.comment()|\n---   Conflict marker ................ `[X` `[x` `]x` `]X` .... |MiniBracketed.conflict()|\n---   Diagnostic ..................... `[D` `[d` `]d` `]D` .... |MiniBracketed.diagnostic()|\n---   File on disk ................... `[F` `[f` `]f` `]F` .... |MiniBracketed.file()|\n---   Indent change .................. `[I` `[i` `]i` `]I` .... |MiniBracketed.indent()|\n---   Jump inside current buffer ..... `[J` `[j` `]j` `]J` .... |MiniBracketed.jump()|\n---   Location from |location-list| .... `[L` `[l` `]l` `]L` .... |MiniBracketed.location()|\n---   Old files ...................... `[O` `[o` `]o` `]O` .... |MiniBracketed.oldfile()|\n---   Quickfix entry from |Quickfix| ... `[Q` `[q` `]q` `]Q` .... |MiniBracketed.quickfix()|\n---   Tree-sitter node and parents ... `[T` `[t` `]t` `]T` .... |MiniBracketed.treesitter()|\n---   Undo from linear history ....... `[U` `[u` `]u` `]U` .... |MiniBracketed.undo()|\n---   Window in current tab .......... `[W` `[w` `]w` `]W` .... |MiniBracketed.window()|\n---   Yank entry over put region ..... `[Y` `[y` `]y` `]Y` .... |MiniBracketed.yank()|\n---\n--- Notes:\n--- - The `undo` target remaps |u| and |CTRL-R| keys to register undo state\n---   after undo and redo respectively. If this conflicts with your setup,\n---   either disable `undo` target or make your remaps after calling\n---   |MiniBracketed.setup()|. To use `undo` target, remap your undo/redo keys\n---   to call |MiniBracketed.register_undo_state()| after the action.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.bracketed').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniBracketed`\n--- which you can use for scripting or manually (with `:lua MiniBracketed.*`).\n---\n--- See |MiniBracketed.config| for available config settings.\n---\n--- You can override runtime config settings (like target options) locally\n--- to buffer inside `vim.b.minibracketed_config` which should have same structure\n--- as `MiniBracketed.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [tpope/vim-unimpaired](https://github.com/tpope/vim-unimpaired):\n---     - Supports buffer, conflict, file, location, and quickfix targets mostly\n---       via built-in commands (like |:bprevious|, etc.) without configuration.\n---     - Supports files from argument list and tags. This module does not.\n---     - Doesn't support most other this module's targets (comment, indent, ...).\n--- - |mini.indentscope|:\n---     - Target |MiniBracketed.indent()| target can go to \"first\" and \"last\"\n---       indent change. It also can go not only to line with smaller indent,\n---       but also bigger or different one.\n---     - Mappings from 'mini.indentscope' have more flexibility in computation of\n---       indent scope, like how to treat empty lines near border or whether to\n---       compute indent at cursor.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minibracketed_disable` (globally) or\n--- `vim.b.minibracketed_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniBracketed\n\n---@diagnostic disable:luadoc-miss-type-name\n---@alias __bracketed_direction string One of \"first\", \"backward\", \"forward\", \"last\".\n---@alias __bracketed_add_to_jumplist - <add_to_jumplist> (`boolean`) - Whether to add current position to jumplist.\n---     Default: `false`.\n---@alias __bracketed_opts table|nil Options. A table with fields:\n---   - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n---   - <wrap> `(boolean)` - Whether to wrap around edges. Default: `true`.\n\n---@diagnostic disable:undefined-field\n\n-- Module definition ==========================================================\nlocal MiniBracketed = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniBracketed.config|.\n---\n---@usage >lua\n---   require('mini.bracketed').setup() -- use default config\n---   -- OR\n---   require('mini.bracketed').setup({}) -- replace {} with your config table\n--- <\nMiniBracketed.setup = function(config)\n  -- Export module\n  _G.MiniBracketed = MiniBracketed\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text Options ~\n---\n--- Each entry configures target with the same name and can have data configuring\n--- mapping suffix and target options.\n---\n--- Example of configuration: >lua\n---\n---   require('mini.bracketed').setup({\n---     -- Map [N, [n, ]n, ]N for conflict marker like in 'tpope/vim-unimpaired'\n---     conflict = { suffix = 'n' },\n---\n---     -- Make diagnostic advance only by errors\n---     diagnostic = { options = { severity = vim.diagnostic.severity.ERROR } },\n---\n---     -- Disable creation of mappings for `indent` target (for example,\n---     -- in favor of ones from |mini.indentscope|)\n---     indent = { suffix = '' },\n---\n---     -- Disable mappings for `window` target in favor of custom ones\n---     window = { suffix = '' },\n---   })\n---\n---   -- Create custom `window` mappings\n---   local map = vim.keymap.set\n---   map('n', '<Leader>wH', \"<Cmd>lua MiniBracketed.window('first')<CR>\")\n---   map('n', '<Leader>wh', \"<Cmd>lua MiniBracketed.window('backward')<CR>\")\n---   map('n', '<Leader>wl', \"<Cmd>lua MiniBracketed.window('forward')<CR>\")\n---   map('n', '<Leader>wL', \"<Cmd>lua MiniBracketed.window('last')<CR>\")\n--- <\n--- ## Suffix ~\n---\n--- The `suffix` key is used to create target mappings.\n---\n--- Supply empty string to disable mapping creation for that particular target.\n--- To create a completely different mapping (like with |<Leader>|) use target\n--- function manually.\n---\n--- Using `lower-suffix` and `upper-suffix` (lower and upper case suffix) for\n--- a single target the following mappings are created:\n--- - `[` + `upper-suffix` : go first.\n--- - `[` + `lower-suffix` : go backward.\n--- - `]` + `lower-suffix` : go forward.\n--- - `]` + `upper-suffix` : go last.\n---\n--- When supplied with a non-letter, only forward/backward mappings are created.\n---\n--- ## Options ~\n---\n--- The `options` key is directly forwarded as `opts` to corresponding Lua function.\nMiniBracketed.config = {\n  -- First-level elements are tables describing behavior of a target:\n  --\n  -- - <suffix> - single character suffix. Used after `[` / `]` in mappings.\n  --   For example, with `b` creates `[B`, `[b`, `]b`, `]B` mappings.\n  --   Supply empty string `''` to not create mappings.\n  --\n  -- - <options> - table overriding target options.\n  --\n  -- See `:h MiniBracketed.config` for more info.\n\n  buffer     = { suffix = 'b', options = {} },\n  comment    = { suffix = 'c', options = {} },\n  conflict   = { suffix = 'x', options = {} },\n  diagnostic = { suffix = 'd', options = {} },\n  file       = { suffix = 'f', options = {} },\n  indent     = { suffix = 'i', options = {} },\n  jump       = { suffix = 'j', options = {} },\n  location   = { suffix = 'l', options = {} },\n  oldfile    = { suffix = 'o', options = {} },\n  quickfix   = { suffix = 'q', options = {} },\n  treesitter = { suffix = 't', options = {} },\n  undo       = { suffix = 'u', options = {} },\n  window     = { suffix = 'w', options = {} },\n  yank       = { suffix = 'y', options = {} },\n}\n--minidoc_afterlines_end\n\n--- Listed buffer\n---\n--- Go to next/previous listed buffer. Order by their number (see |bufnr()|).\n---\n--- Direction \"forward\" increases number, \"backward\" - decreases.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.buffer = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'buffer')\n  opts =\n    vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().buffer.options, opts or {})\n\n  -- Define iterator that traverses all valid listed buffers\n  -- (should be same as `:bnext` / `:bprev`)\n  local buf_list = vim.api.nvim_list_bufs()\n  local is_listed = function(buf_id) return vim.api.nvim_buf_is_valid(buf_id) and vim.bo[buf_id].buflisted end\n\n  local iterator = {}\n\n  iterator.next = function(buf_id)\n    for id = buf_id + 1, buf_list[#buf_list] do\n      if is_listed(id) then return id end\n    end\n  end\n\n  iterator.prev = function(buf_id)\n    for id = buf_id - 1, buf_list[1], -1 do\n      if is_listed(id) then return id end\n    end\n  end\n\n  iterator.state = vim.api.nvim_get_current_buf()\n  iterator.start_edge = buf_list[1] - 1\n  iterator.end_edge = buf_list[#buf_list] + 1\n\n  -- Iterate\n  local res_buf_id = MiniBracketed.advance(iterator, direction, opts)\n  if res_buf_id == iterator.state then return end\n\n  -- Apply\n  vim.api.nvim_set_current_buf(res_buf_id)\nend\n\n--- Comment block\n---\n--- Go to next/previous comment block. Only linewise comments using\n--- 'commentsring' are recognized.\n---\n--- Direction \"forward\" increases line number, \"backward\" - decreases.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\n---   __bracketed_add_to_jumplist\n---   - <block_side> `(string)` - which side of comment block to use. One of\n---     \"near\" (default; use nearest side), \"start\" (use first line), \"end\"\n---     (use last line), \"both\" (use both first and last lines).\nMiniBracketed.comment = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'comment')\n  opts = vim.tbl_deep_extend(\n    'force',\n    { add_to_jumplist = false, block_side = 'near', n_times = vim.v.count1, wrap = true },\n    H.get_config().comment.options,\n    opts or {}\n  )\n\n  -- Compute loop data to traverse target commented lines in current buffer\n  local is_commented = H.make_comment_checker()\n  if is_commented == nil then return end\n\n  local predicate = ({\n    near = function(_, cur, _, recent) return cur and not recent end,\n    start = function(above, cur, _, _) return cur and not above end,\n    ['end'] = function(_, cur, below, _) return cur and not below end,\n    both = function(above, cur, below, _) return cur and not (above and below) end,\n  })[opts.block_side]\n  if predicate == nil then return end\n\n  -- Define iterator\n  local iterator = {}\n\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  iterator.next = function(line_num)\n    local above, cur = is_commented(line_num), is_commented(line_num + 1)\n    for lnum = line_num + 1, n_lines do\n      local below = is_commented(lnum + 1)\n      if predicate(above, cur, below, above) then return lnum end\n      above, cur = cur, below\n    end\n  end\n\n  iterator.prev = function(line_num)\n    local cur, below = is_commented(line_num - 1), is_commented(line_num)\n    for lnum = line_num - 1, 1, -1 do\n      local above = is_commented(lnum - 1)\n      if predicate(above, cur, below, below) then return lnum end\n      below, cur = cur, above\n    end\n  end\n\n  iterator.state = vim.fn.line('.')\n  iterator.start_edge = 0\n  iterator.end_edge = n_lines + 1\n\n  -- Iterate\n  local res_line_num = MiniBracketed.advance(iterator, direction, opts)\n  local is_outside = res_line_num <= 0 or n_lines < res_line_num\n  if res_line_num == nil or res_line_num == iterator.state or is_outside then return end\n\n  -- Possibly add current position to jumplist\n  if opts.add_to_jumplist then H.add_to_jumplist() end\n\n  -- Apply. Open just enough folds and put cursor on first non-blank.\n  H.set_cursor(res_line_num, 0)\n  vim.cmd('normal! zv^')\nend\n\n--- Git conflict marker\n---\n--- Go to next/previous lines containing Git conflict marker. That is, if it\n--- starts with \"<<<<<<< \", \">>>>>>> \", or is \"=======\".\n---\n--- Direction \"forward\" increases line number, \"backward\" - decreases.\n---\n--- Notes:\n--- - Using this target in Operator-pending mode allows the following approach\n---   at resolving merge conflicts:\n---     - Place cursor on `=======` line.\n---     - Execute one of these: `d]x[xdd` (choose upper part) or\n---       `d[x]xdd` (choose lower part).\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\n---   __bracketed_add_to_jumplist\nMiniBracketed.conflict = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'conflict')\n  opts = vim.tbl_deep_extend(\n    'force',\n    { add_to_jumplist = false, n_times = vim.v.count1, wrap = true },\n    H.get_config().conflict.options,\n    opts or {}\n  )\n\n  -- Define iterator that traverses all conflict markers in current buffer\n  local n_lines = vim.api.nvim_buf_line_count(0)\n\n  local iterator = {}\n\n  iterator.next = function(line_num)\n    for lnum = line_num + 1, n_lines do\n      if H.is_conflict_mark(lnum) then return lnum end\n    end\n  end\n\n  iterator.prev = function(line_num)\n    for lnum = line_num - 1, 1, -1 do\n      if H.is_conflict_mark(lnum) then return lnum end\n    end\n  end\n\n  iterator.state = vim.fn.line('.')\n  iterator.start_edge = 0\n  iterator.end_edge = n_lines + 1\n\n  -- Iterate\n  local res_line_num = MiniBracketed.advance(iterator, direction, opts)\n  local is_outside = res_line_num <= 0 or n_lines < res_line_num\n  if res_line_num == nil or res_line_num == iterator.state or is_outside then return end\n\n  -- Possibly add current position to jumplist\n  if opts.add_to_jumplist then H.add_to_jumplist() end\n\n  -- Apply. Open just enough folds and put cursor on first non-blank.\n  H.set_cursor(res_line_num, 0)\n  vim.cmd('normal! zv^')\nend\n\n--- Diagnostic\n---\n--- Go to next/previous diagnostic. This is mostly similar to built-in\n--- |vim.diagnostic.jump()| (on Neovim<0.11 it is |vim.diagnostic.goto_next()| and\n--- |vim.diagnostic.goto_prev()|) which has an interface and behavior\n--- consistent with other methods of the module.\n---\n--- Direction \"forward\" increases line number, \"backward\" - decreases.\n---\n--- Notes:\n--- - Using `severity` option, this target can be used in mappings like \"go to\n---   next/previous error\" (), etc. Using code similar to this: >lua\n---\n---   local severity_error = vim.diagnostic.severity.ERROR\n---   -- Use these inside custom mappings\n---   MiniBracketed.diagnostic('forward', { severity = severity_error })\n---   MiniBracketed.diagnostic('backward', { severity = severity_error })\n--- <\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\n---   - <float> `(boolean|table)` - control floating window after movement.\n---     For available values see |vim.diagnostic.goto_next()|.\n---   - <severity> `(string|table)` - which severity to use.\n---     For available values see |diagnostic-severity|.\nMiniBracketed.diagnostic = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'diagnostic')\n  local default_opts = { float = vim.diagnostic.config().float, n_times = vim.v.count1, severity = nil, wrap = true }\n  local buf_id = vim.api.nvim_get_current_buf()\n  if vim.is_callable(default_opts.float) then default_opts.float = default_opts.float(nil, buf_id) end\n  opts = vim.tbl_extend('force', default_opts, H.get_config().diagnostic.options, opts or {})\n\n  -- Define iterator that traverses all diagnostic entries in current buffer\n  local to_cursor_pos = function(pos) return { pos[1] + 1, pos[2] } end\n  local pos_field = vim.fn.has('nvim-0.11') == 1 and 'pos' or 'cursor_position'\n  local iterator = {}\n\n  iterator.next = function(position)\n    local next_opts = { [pos_field] = to_cursor_pos(position), severity = opts.severity, wrap = false }\n    local next = vim.diagnostic.get_next(next_opts)\n    if next == nil then return end\n    return { next.lnum, next.col }\n  end\n\n  iterator.prev = function(position)\n    local prev_opts = { [pos_field] = to_cursor_pos(position), severity = opts.severity, wrap = false }\n    local prev = vim.diagnostic.get_prev(prev_opts)\n    if prev == nil then return end\n    return { prev.lnum, prev.col }\n  end\n\n  -- - Define states with zero-based indexing as used in `vim.diagnostic`.\n  -- - Go outside of proper buffer position for `start_edge` and `end_edge` to\n  --   correctly spot diagnostic entry right and start and end of buffer.\n  local cursor_pos = vim.api.nvim_win_get_cursor(0)\n  iterator.state = { cursor_pos[1] - 1, cursor_pos[2] }\n\n  iterator.start_edge = { 0, -1 }\n\n  local last_line = vim.api.nvim_buf_line_count(0)\n  iterator.end_edge = { last_line - 1, vim.fn.col({ last_line, '$' }) - 1 }\n\n  -- Iterate\n  local res_pos = MiniBracketed.advance(iterator, direction, opts)\n  if res_pos == nil or res_pos == iterator.state then return end\n\n  -- Apply. Use built-in jump with offsetted cursor position to make it respect\n  -- `vim.diagnostic.config()`.\n  H.diagnostic_jump({ res_pos[1] + 1, res_pos[2] - 1 }, opts.float, opts.severity)\nend\n\n--- File on disk\n---\n--- Go to next/previous file on disk alphabetically. Files are taken from\n--- directory of file in current buffer (or current working directory if buffer\n--- doesn't contain a readable file). Only first-level files are used, i.e. it\n--- doesn't go inside subdirectories.\n---\n--- Direction \"forward\" goes forward alphabetically, \"backward\" - backward.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.file = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'file')\n  opts = vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().file.options, opts or {})\n\n  -- Get file data\n  local file_data = H.get_file_data()\n  if file_data == nil then return end\n  local file_basenames, directory = file_data.file_basenames, file_data.directory\n\n  -- Define iterator that traverses all found files\n  local iterator = {}\n  local n_files = #file_basenames\n\n  iterator.next = function(ind)\n    -- Allow advance in untrackable current buffer\n    if ind == nil then return 1 end\n    if n_files <= ind then return end\n    return ind + 1\n  end\n\n  iterator.prev = function(ind)\n    -- Allow advance in untrackable current buffer\n    if ind == nil then return n_files end\n    if ind <= 1 then return end\n    return ind - 1\n  end\n\n  -- - Find filename array index of current buffer\n  local cur_basename = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(0), ':t')\n  local cur_basename_ind\n  if cur_basename ~= '' then\n    for i, f in ipairs(file_basenames) do\n      if cur_basename == f then\n        cur_basename_ind = i\n        break\n      end\n    end\n  end\n\n  iterator.state = cur_basename_ind\n  iterator.start_edge = 0\n  iterator.end_edge = n_files + 1\n\n  -- Iterate\n  local res_ind = MiniBracketed.advance(iterator, direction, opts)\n  if res_ind == iterator.state then return end\n\n  -- Apply. Open target_path.\n  local path_sep = package.config:sub(1, 1)\n  local target_path = directory .. path_sep .. file_basenames[res_ind]\n  H.edit(target_path)\nend\n\n--- Indent change\n---\n--- Go to next/previous line with different indent (see |indent()|).\n--- Can be used to go to lines with smaller, bigger, or different indent.\n---\n--- Notes:\n--- - Directions \"first\" and \"last\" work differently from most other targets\n---   for performance reasons. They are essentially \"backward\" and \"forward\"\n---   with very big `n_times` option.\n--- - For similar reasons, `wrap` is not supported.\n--- - Blank line inherit indent from near non-blank line in direction of movement.\n---\n--- Direction \"forward\" increases line number, \"backward\" - decreases.\n---\n---@param direction __bracketed_direction\n---@param opts table|nil Options. A table with fields:\n---   - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n---   __bracketed_add_to_jumplist\n---   - <change_type> `(string)` - which type of indent change to use.\n---     One of \"less\" (default; smaller indent), \"more\" (bigger indent),\n---     \"diff\" (different indent).\nMiniBracketed.indent = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'indent')\n  opts = vim.tbl_deep_extend(\n    'force',\n    { add_to_jumplist = false, change_type = 'less', n_times = vim.v.count1 },\n    H.get_config().indent.options,\n    opts or {}\n  )\n\n  opts.wrap = false\n\n  if direction == 'first' then\n    -- For some reason using `n_times = math.huge` leads to infinite loop\n    direction, opts.n_times = 'backward', vim.api.nvim_buf_line_count(0) + 1\n  end\n  if direction == 'last' then\n    direction, opts.n_times = 'forward', vim.api.nvim_buf_line_count(0) + 1\n  end\n\n  -- Compute loop data to traverse target commented lines in current buffer\n  local predicate = ({\n    less = function(new, cur) return new < cur or cur == 0 end,\n    more = function(new, cur) return new > cur end,\n    diff = function(new, cur) return new ~= cur end,\n  })[opts.change_type]\n  if predicate == nil then return end\n\n  -- Define iterator\n  local iterator = {}\n\n  iterator.next = function(cur_lnum)\n    -- Correctly process empty current line\n    cur_lnum = vim.fn.nextnonblank(cur_lnum)\n    local cur_indent = vim.fn.indent(cur_lnum)\n\n    local new_lnum, new_indent = cur_lnum, cur_indent\n    -- Check with `new_lnum > 0` because `nextnonblank()` returns -1 if line is\n    -- outside of line range\n    while new_lnum > 0 do\n      new_indent = vim.fn.indent(new_lnum)\n      if predicate(new_indent, cur_indent) then return new_lnum end\n      new_lnum = vim.fn.nextnonblank(new_lnum + 1)\n    end\n  end\n\n  iterator.prev = function(cur_lnum)\n    cur_lnum = vim.fn.prevnonblank(cur_lnum)\n    local cur_indent = vim.fn.indent(cur_lnum)\n\n    local new_lnum, new_indent = cur_lnum, cur_indent\n    while new_lnum > 0 do\n      new_indent = vim.fn.indent(new_lnum)\n      if predicate(new_indent, cur_indent) then return new_lnum end\n      new_lnum = vim.fn.prevnonblank(new_lnum - 1)\n    end\n  end\n\n  -- - Don't add first and last states as there is no wrapping around edges\n  iterator.state = vim.fn.line('.')\n\n  -- Iterate\n  local res_line_num = MiniBracketed.advance(iterator, direction, opts)\n  if res_line_num == nil or res_line_num == iterator.state then return end\n\n  -- Possibly add current position to jumplist\n  if opts.add_to_jumplist then H.add_to_jumplist() end\n\n  -- Apply. Open just enough folds and put cursor on first non-blank.\n  H.set_cursor(res_line_num, 0)\n  vim.cmd('normal! zv^')\nend\n\n--- Jump inside current buffer\n---\n--- Go to next/previous jump from |jumplist| which is inside current buffer.\n---\n--- Notes:\n--- - There are no Visual mode mappings due to implementation problems.\n---\n--- Direction \"forward\" increases jump number, \"backward\" - decreases.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.jump = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'jump')\n  opts = vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().jump.options, opts or {})\n\n  -- Define iterator that traverses all jumplist entries inside current buffer\n  local cur_buf_id = vim.api.nvim_get_current_buf()\n  local jump_list, cur_jump_num = unpack(vim.fn.getjumplist())\n  local n_list = #jump_list\n  if n_list == 0 then return end\n  -- - Correct for zero-based indexing\n  cur_jump_num = cur_jump_num + 1\n\n  local iterator = {}\n\n  local is_jump_num_from_current_buffer = function(jump_num)\n    local jump_entry = jump_list[jump_num]\n    if jump_entry == nil then return end\n    return jump_entry.bufnr == cur_buf_id\n  end\n\n  iterator.next = function(jump_num)\n    for num = jump_num + 1, n_list do\n      if is_jump_num_from_current_buffer(num) then return num end\n    end\n  end\n\n  iterator.prev = function(jump_num)\n    for num = jump_num - 1, 1, -1 do\n      if is_jump_num_from_current_buffer(num) then return num end\n    end\n  end\n\n  iterator.state = cur_jump_num\n  iterator.start_edge = 0\n  iterator.end_edge = n_list + 1\n\n  -- Iterate\n  local res_jump_num = MiniBracketed.advance(iterator, direction, opts)\n  if res_jump_num == nil or jump_list[res_jump_num] == nil then return end\n\n  -- Apply. Make jump. Allow jumping to current jump entry as it might be\n  -- different from current cursor position.\n  H.make_jump(jump_list, cur_jump_num, res_jump_num)\nend\n\n--- Location from location list\n---\n--- Go to next/previous location from |location-list|. This is similar to\n--- |:lfirst|, |:lprevious|, |:lnext|, and |:llast| but with support of\n--- wrapping around edges and |[count]| for \"first\"/\"last\" direction.\n---\n--- Direction \"forward\" increases location number, \"backward\" - decreases.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.location = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'location')\n  opts =\n    vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().location.options, opts or {})\n\n  H.qf_loc_implementation('location', direction, opts)\nend\n\n--- Old files from previous and current sessions\n---\n--- Go to older/newer readable file either from previous session (see |v:oldfiles|)\n--- or the current one (updated automatically after |MiniBracketed.setup()| call).\n---\n--- Direction \"forward\" goes to more recent files, \"backward\" - to older.\n---\n--- Notes:\n--- - In current session it tracks only normal buffers (see |'buftype'|) for\n---   some readable file.\n--- - No new file is tracked when advancing this target. Only after buffer\n---   change is done not through this target (like with |MiniBracketed.buffer()|),\n---   it updates recency of last advanced and new buffers.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.oldfile = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'oldfile')\n  opts =\n    vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().oldfile.options, opts or {})\n\n  -- Define iterator that traverses all old files\n  local cur_path = vim.api.nvim_buf_get_name(0)\n\n  H.oldfile_normalize()\n  local oldfile_arr = H.oldfile_get_array()\n  local n_oldfiles = #oldfile_arr\n\n  local iterator = {}\n\n  iterator.next = function(ind)\n    -- Allow advance in untrackable current buffer\n    if ind == nil then return 1 end\n    if n_oldfiles <= ind then return end\n    return ind + 1\n  end\n\n  iterator.prev = function(ind)\n    -- Allow advance in untrackable current buffer\n    if ind == nil then return n_oldfiles end\n    if ind <= 1 then return end\n    return ind - 1\n  end\n\n  iterator.state = H.cache.oldfile.recency[cur_path]\n  iterator.start_edge = 0\n  iterator.end_edge = n_oldfiles + 1\n\n  -- Iterate\n  local res_arr_ind = MiniBracketed.advance(iterator, direction, opts)\n  if res_arr_ind == nil or res_arr_ind == iterator.state then return end\n\n  -- Apply. Edit file at path while marking it not for tracking.\n  H.cache.oldfile.is_advancing = true\n  H.edit(oldfile_arr[res_arr_ind])\nend\n\n--- Quickfix from quickfix list\n---\n--- Go to next/previous entry from |quickfix| list. This is similar to\n--- |:cfirst|, |:cprevious|, |:cnext|, and |:clast| but with support of\n--- wrapping around edges and |[count]| for \"first\"/\"last\" direction.\n---\n--- Direction \"forward\" increases location number, \"backward\" - decreases.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.quickfix = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'quickfix')\n  opts =\n    vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().quickfix.options, opts or {})\n\n  H.qf_loc_implementation('quickfix', direction, opts)\nend\n\n--- Tree-sitter node\n---\n--- Go to end/start of current tree-sitter node and its parents (except root).\n---\n--- Notes:\n--- - Requires loaded tree-sitter parser in the current buffer.\n--- - Directions \"first\" and \"last\" work differently from most other targets\n---   for performance reasons. They are essentially \"backward\" and \"forward\"\n---   with very big `n_times` option.\n--- - For similar reasons, `wrap` is not supported.\n---\n--- Direction \"forward\" moves cursor forward to node's end, \"backward\" - backward\n--- to node's start.\n---\n---@param direction __bracketed_direction\n---@param opts table|nil Options. A table with fields:\n---   - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n---   __bracketed_add_to_jumplist\nMiniBracketed.treesitter = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'treesitter')\n  opts = vim.tbl_deep_extend(\n    'force',\n    { add_to_jumplist = false, n_times = vim.v.count1 },\n    H.get_config().treesitter.options,\n    opts or {}\n  )\n\n  opts.wrap = false\n\n  if direction == 'first' then\n    direction, opts.n_times = 'backward', math.huge\n  end\n  if direction == 'last' then\n    direction, opts.n_times = 'forward', math.huge\n  end\n\n  -- Define iterator that traverses current node and its parents (except root)\n  local is_bad_node = function(node) return node == nil or node:parent() == nil end\n  local is_after = function(row_new, col_new, row_ref, col_ref)\n    return row_ref < row_new or (row_ref == row_new and col_ref < col_new)\n  end\n  local is_before = function(row_new, col_new, row_ref, col_ref) return is_after(row_ref, col_ref, row_new, col_new) end\n\n  local iterator = {}\n\n  -- Traverse node and parents until node's end is after current position\n  iterator.next = function(node_pos)\n    local node = node_pos.node\n    if is_bad_node(node) then return nil end\n\n    local init_row, init_col = node_pos.pos[1], node_pos.pos[2]\n    local cur_row, cur_col, cur_node = init_row, init_col, node\n\n    repeat\n      if is_bad_node(cur_node) then break end\n\n      cur_row, cur_col = cur_node:end_()\n      -- Correct for end-exclusiveness\n      cur_col = cur_col - 1\n      cur_node = cur_node:parent()\n    until is_after(cur_row, cur_col, init_row, init_col)\n\n    if not is_after(cur_row, cur_col, init_row, init_col) then return end\n\n    return { node = cur_node, pos = { cur_row, cur_col } }\n  end\n\n  -- Traverse node and parents until node's start is before current position\n  iterator.prev = function(node_pos)\n    local node = node_pos.node\n    if is_bad_node(node) then return nil end\n\n    local init_row, init_col = node_pos.pos[1], node_pos.pos[2]\n    local cur_row, cur_col, cur_node = init_row, init_col, node\n\n    repeat\n      if is_bad_node(cur_node) then break end\n\n      cur_row, cur_col = cur_node:start()\n      cur_node = cur_node:parent()\n    until is_before(cur_row, cur_col, init_row, init_col)\n\n    if not is_before(cur_row, cur_col, init_row, init_col) then return end\n\n    return { node = cur_node, pos = { cur_row, cur_col } }\n  end\n\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  local ok, node = pcall(H.get_treesitter_node, cur_pos[1] - 1, cur_pos[2])\n  if not ok then\n    H.error(\n      'In `treesitter()` target can not find tree-sitter node under cursor.'\n        .. ' Do you have tree-sitter enabled in current buffer?'\n    )\n  end\n  iterator.state = { pos = { cur_pos[1] - 1, cur_pos[2] }, node = node }\n\n  -- Iterate\n  local res_node_pos = MiniBracketed.advance(iterator, direction, opts)\n  if res_node_pos == nil then return end\n\n  -- Possibly add current position to jumplist\n  if opts.add_to_jumplist then H.add_to_jumplist() end\n\n  -- Apply\n  H.set_cursor(res_node_pos.pos[1] + 1, res_node_pos.pos[2])\nend\n\n--- Undo along a tracked linear history\n---\n--- In a nutshell:\n--- - Keys |u| and |CTRL-R| (although remapped) can be used as usual, but every\n---   their execution new state is recorded in this module's linear undo history.\n--- - Advancing this target goes along linear undo history revealing undo states\n---   **in order they actually appeared**.\n--- - One big difference with built-in methods is that tracked linear history\n---   can repeat undo states (not consecutively, though).\n---\n--- Neovim's default way of managing undo history is through branches (see\n--- |undo-branches|). Basically it means that if you undo several changes and then\n--- make new ones, it creates new undo branch while usually (see |'undolevels'|)\n--- saving previous buffer states in another branch. While there are commands\n--- to navigate by time of undo state creation (like |:earlier| and |:later|),\n--- there is no intuitive way to cycle through them. Existing |g-| and |g+|\n--- cycle through undo states **based on their creation time**, which often\n--- gets confusing really guickly in extensively edited buffer.\n---\n--- This `undo()` target provides a way to cycle through linear undo history\n--- **in order states actually appeared**. It does so by registering any new undo\n--- states plus every time |MiniBracketed.register_undo_state()| is called. To have\n--- more \"out of the box\" experience, |u| and |CTRL-R| are remapped to call it after\n--- they perform their undo/redo.\n---\n--- Example:\n---\n--- To show more clearly the difference between advancing this target and using\n--- built-in functionality, here is an example:\n---\n--- - Create undo history in a new buffer (|:new|):\n---     - Enter `one two three` text.\n---     - Delete first word with `daw` and undo the change with `u`.\n---     - Delete second word with `daw` and undo the change with `u`.\n---     - Delete third word with `daw` and undo the change with `u`.\n---\n--- - Now try one of the following (each one after performing previous steps in\n---   separate new buffer):\n---     - Press `u`. It goes back to empty buffer. Press `<C-R>` twice and it\n---       goes to the latest change (`one two`). No way to get to other states\n---       (like `two three` or `one three`) with these two keys.\n---\n---     - Press `g-`. It goes to an empty buffer. Press `g+` 4 times. It cycles\n---       through all available undo states **in order they were created**.\n---\n---     - Finally, press `[u`. It goes back to `one two` - state which was\n---       **previously visited** by the user. Another `[u` restores `one two three`.\n---       Use `]U` to go to latest visited undo state.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.undo = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'undo')\n  opts = vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().undo.options, opts or {})\n\n  -- Define iterator that traverses undo states in order they appeared\n  local buf_id = vim.api.nvim_get_current_buf()\n  H.undo_sync(buf_id, vim.fn.undotree())\n\n  local iterator = {}\n  local buf_history = H.cache.undo[buf_id]\n  local n = #buf_history\n\n  iterator.next = function(id)\n    if id == nil or n <= id then return end\n    return id + 1\n  end\n\n  iterator.prev = function(id)\n    if id == nil or id <= 1 then return end\n    return id - 1\n  end\n\n  iterator.state = buf_history.current_id\n  iterator.start_edge = 0\n  iterator.end_edge = n + 1\n\n  -- Iterate\n  local res_id = MiniBracketed.advance(iterator, direction, opts)\n  if res_id == nil or res_id == iterator.state then return end\n\n  -- Apply. Move to undo state by number while recording current history id\n  buf_history.is_advancing = true\n  vim.cmd('undo ' .. buf_history[res_id])\n\n  buf_history.current_id = res_id\nend\n\n--- Register state for undo target\n---\n--- Use this function to add current undo state to this module's linear undo\n--- history. It is used in |MiniBracketed.setup()| to remap |u| and |CTRL-R| keys\n--- to add their new state to linear undo history.\nMiniBracketed.register_undo_state = function()\n  local buf_id = vim.api.nvim_get_current_buf()\n  local tree = vim.fn.undotree()\n\n  -- Synchronize undo history and stop advancing\n  H.undo_sync(buf_id, tree, false)\n\n  -- Append new undo state to linear history\n  local buf_history = H.cache.undo[buf_id]\n  H.undo_append_state(buf_history, tree.seq_cur)\n  buf_history.current_id = #buf_history\nend\n\n--- Normal window\n---\n--- Go to next/previous normal window. Order by their number (see |winnr()|).\n---\n--- Direction \"forward\" increases window number, \"backward\" - decreases.\n---\n--- Only normal (non-floating) windows are used.\n---\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\nMiniBracketed.window = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'window')\n  opts =\n    vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, H.get_config().window.options, opts or {})\n\n  -- Define iterator that traverses all normal windows in \"natural\" order\n  local is_normal = function(win_nr)\n    local win_id = vim.fn.win_getid(win_nr)\n    return vim.api.nvim_win_get_config(win_id).relative == ''\n  end\n\n  local iterator = {}\n\n  iterator.next = function(win_nr)\n    for nr = win_nr + 1, vim.fn.winnr('$') do\n      if is_normal(nr) then return nr end\n    end\n  end\n\n  iterator.prev = function(win_nr)\n    for nr = win_nr - 1, 1, -1 do\n      if is_normal(nr) then return nr end\n    end\n  end\n\n  iterator.state = vim.fn.winnr()\n  iterator.start_edge = 0\n  iterator.end_edge = vim.fn.winnr('$') + 1\n\n  -- Iterate\n  local res_win_nr = MiniBracketed.advance(iterator, direction, opts)\n  if res_win_nr == iterator.state then return end\n\n  -- Apply\n  vim.api.nvim_set_current_win(vim.fn.win_getid(res_win_nr))\nend\n\n--- Replace \"latest put region\" with yank history entry\n---\n--- After |MiniBracketed.setup()| is called, on every yank/delete/change operation\n--- (technically, every trigger of |TextYankPost| event) the object of operation\n--- is added to yank history. Advancing this target will replace the region of\n--- latest put operation with entry from yank history.\n---\n--- By default works best if called **right after** text paste (like with |p| or |P|).\n---\n--- To better detect \"latest put region\", use |MiniBracketed.register_put_region()|\n--- as described later.\n---\n--- Direction \"forward\" goes to newer yank history entry, \"backward\" - to older.\n---\n--- Example:\n---\n--- - Type `one two three`.\n--- - Yank each word with `yiw`.\n--- - Create new line and press `p`. This should paste `three`.\n--- - Type `[y`. This should replace latest `three` with `two`.\n---\n--- # Latest put region ~\n---\n--- \"Latest put region\" is (in order of decreasing priority):\n--- - The one from latest advance of this target.\n--- - The one registered by user with |MiniBracketed.register_put_region()|.\n--- - The one taken from |'[| and |']| marks.\n---\n--- For users there are these approaches to manage which region will be used:\n--- - Do nothing. In this case region between `[` / `]` marks will always be used\n---   for first `yank` advance.\n---   Although doable, this has several drawbacks: it will use latest yanked or\n---   changed region or the entire buffer if marks are not set.\n---   If remember to advance this target only after recent put operation, this\n---   should work as expected.\n---\n--- - Remap common put operations to use |MiniBracketed.register_put_region()|.\n---   After that, only regions from mapped put operations will be used for first\n---   advance. Example of custom mappings (note use of |:map-expression|): >lua\n---\n---     local put_keys = { 'p', 'P' }\n---     for _, lhs in ipairs(put_keys) do\n---       local rhs = 'v:lua.MiniBracketed.register_put_region(\"' .. lhs .. '\")'\n---       vim.keymap.set({ 'n', 'x' }, lhs, rhs, { expr = true })\n---     end\n--- <\n---@param direction __bracketed_direction\n---@param opts __bracketed_opts\n---   - <operators> `(table)` - array of operator names (\"c\", \"d\", or \"y\") for\n---     which yank entry should be used to advance. For example, use `{ \"y\" }`\n---     to advance only by entries actually resulted from yank operation with |y|.\n---     Default: `{ 'c', 'd', 'y' }`.\nMiniBracketed.yank = function(direction, opts)\n  if H.is_disabled() then return end\n\n  H.validate_direction(direction, { 'first', 'backward', 'forward', 'last' }, 'yank')\n  -- NOTE: Don't use `tbl_deep_extend` to prefer full input `operators` array\n  local default_opts = { n_times = vim.v.count1, operators = { 'c', 'd', 'y' }, wrap = true }\n  opts = vim.tbl_extend('force', default_opts, H.get_config().yank.options, opts or {})\n\n  -- Update yank history data\n  local cache_yank, history = H.cache.yank, H.cache.yank.history\n  local n_history = #history\n  local cur_state = H.get_yank_state()\n  if not vim.deep_equal(cur_state, cache_yank.state) then H.yank_stop_advancing() end\n\n  -- Define iterator that traverses yank history for entry with proper operator\n  local iterator = {}\n\n  iterator.next = function(id)\n    for i = id + 1, n_history do\n      if vim.tbl_contains(opts.operators, history[i].operator) then return i end\n    end\n  end\n\n  iterator.prev = function(id)\n    for i = id - 1, 1, -1 do\n      if vim.tbl_contains(opts.operators, history[i].operator) then return i end\n    end\n  end\n\n  iterator.state = cache_yank.current_id\n  iterator.start_edge = 0\n  iterator.end_edge = n_history + 1\n\n  -- Iterate\n  local res_id = MiniBracketed.advance(iterator, direction, opts)\n  if res_id == nil then return end\n\n  -- Apply. Replace latest put region with yank history entry\n  -- - Account for possible errors when latest region became out of bounds\n  local ok, _ = pcall(H.replace_latest_put_region, cache_yank.history[res_id])\n  if not ok then return end\n\n  cache_yank.current_id = res_id\n  cache_yank.is_advancing = true\n  cache_yank.state = H.get_yank_state()\nend\n\n--- Register \"latest put region\"\n---\n--- This function should be called after put register becomes relevant\n--- (|v:register| is appropriately set) but before put operation takes place\n--- (|'[| and |']| marks become relevant).\n---\n--- Designed to be used in a user-facing expression mapping (see |:map-expression|).\n--- For mapping examples see |MiniBracketed.yank()|.\n---\n---@param put_key string Put keys to be remapped.\n---\n---@return string Returns `put_key` for a better usage inside expression mappings.\nMiniBracketed.register_put_region = function(put_key)\n  local buf_id = vim.api.nvim_get_current_buf()\n\n  -- Compute mode of register **before** putting (while it is still relevant)\n  local mode = H.get_register_mode(vim.v.register)\n\n  -- Register latest put region **after** it is done (when it becomes relevant)\n  vim.schedule(function() H.cache.yank.user_put_regions[buf_id] = H.get_latest_region(mode) end)\n\n  return put_key\nend\n\n--- Advance iterator\n---\n--- This is the main function which performs any forward/backward/first/last\n--- advance in this module. Its basic idea is to take iterator (object containing\n--- information about current state and how to go to next/previous one) and go\n--- in certain direction until needed/allowed.\n---\n--- Notes:\n--- - Directions \"first\" and \"last\" are convenience wrappers for \"forward\" and\n---   \"backward\" with pre-setting initial state to `start_edge` and `end_edge`.\n--- - Iterators `next()` and `prev()` methods should be able to handle `nil` as input.\n--- - This function only returns new state and doesn't modify `iterator.state`.\n---\n---@param iterator table Table:\n---   - Methods:\n---       - <next> - given state, return state in forward direction (no wrap).\n---       - <prev> - given state, return state in backward direction (no wrap).\n---   - Fields:\n---       - <state> - object describing current state.\n---       - <start_edge> (optional) - object with `forward(start_edge)` describing\n---         first state. If `nil`, can't wrap forward or use direction \"first\".\n---       - <end_edge> (optional) - object with `backward(end_edge)` describing\n---         last state. If `nil`, can't wrap backward or use direction \"last\".\n---@param direction string Direction. One of \"first\", \"backward\", \"forward\", \"last\".\n---@param opts table|nil Options with the following keys:\n---   - <n_times> `(number)` - number of times to go in input direction.\n---     Default: `v:count1`.\n---   - <wrap> `(boolean)` - whether to wrap around edges when `next()` or\n---     `prev()` return `nil`. Default: `true`.\n---\n---@return any Result state. If `nil`, could not reach any valid result state.\nMiniBracketed.advance = function(iterator, direction, opts)\n  opts = vim.tbl_deep_extend('force', { n_times = vim.v.count1, wrap = true }, opts or {})\n\n  -- Use two states: \"result\" will be used as result, \"current\" will be used\n  -- for iteration. Separation is needed at least for two reasons:\n  -- - Allow partial reach of `n_times`.\n  -- - Don't allow `start_edge` and `end_edge` be the output.\n  local res_state = iterator.state\n\n  -- Compute loop data\n  local iter_method = 'next'\n  local cur_state = res_state\n\n  if direction == 'backward' then iter_method = 'prev' end\n\n  if direction == 'first' then\n    cur_state, iter_method = iterator.start_edge, 'next'\n  end\n\n  if direction == 'last' then\n    cur_state, iter_method = iterator.end_edge, 'prev'\n  end\n\n  -- Loop\n  local iter = iterator[iter_method]\n  for _ = 1, opts.n_times do\n    -- Advance\n    cur_state = iter(cur_state)\n\n    if cur_state == nil then\n      -- Stop if can't wrap around edges\n      if not opts.wrap then break end\n\n      -- Wrap around edge\n      local edge = iterator.start_edge\n      if iter_method == 'prev' then edge = iterator.end_edge end\n      if edge == nil then break end\n\n      cur_state = iter(edge)\n\n      -- Ensure non-nil new state (can happen when there are no targets)\n      if cur_state == nil then break end\n    end\n\n    -- Allow only partial reach of `n_times`\n    res_state = cur_state\n  end\n\n  return res_state\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniBracketed.config)\n\nH.cache = {\n  -- Tracking of old files for `oldfile()` (this data structure is designed to be\n  -- fast to add new file; initially `nil` to postpone initialization from\n  -- `v:oldfiles` up until it is actually needed):\n  -- - `recency` is a table with file paths as fields and numerical values\n  --   indicating how recent file was accessed (higher - more recent).\n  -- - `max_recency` is a maximum currently used `recency`. Used to add new file.\n  -- - `is_advancing` is an indicator that buffer change was done inside\n  --   `oldfile()` function. It is a key to enabling moving along old files\n  --   (and not just going back and forth between two files because they swap\n  --   places as two most recent files).\n  -- - `last_advanced_bufname` - name of last advanced buffer. Used to update\n  --   recency of only the last buffer entered during advancing.\n  oldfile = nil,\n\n  -- Per buffer history of visited undo states. A table for each buffer id:\n  -- - Numerical fields indicate actual history of visited undo states (from\n  --   oldest to latest).\n  -- - <current_id> - identifier of current history entry (used for iteration).\n  -- - <seq_last> - latest recorded state (`seq_last` from `undotree()`).\n  -- - <is_advancing> - whether currently advancing. Used to allow consecutive\n  --   advances along tracked undo history.\n  undo = {},\n\n  -- Cache for `yank` targets\n  yank = {\n    -- Per-buffer region of latest advance. Used to correctly determine range\n    -- and mode of latest advanced region.\n    advance_put_regions = {},\n    -- Current id of yank entry in yank history\n    current_id = 0,\n    -- Yank history. Each element contains data necessary to replace latest put\n    -- region with yanked one. See `track_yank()`.\n    history = {},\n    -- Whether currently advancing\n    is_advancing = false,\n    -- State of latest yank advancement to determine of currently advancing\n    state = {},\n    -- Per-buffer region registered by user as \"latest put region\". Used to\n    -- overcome limitations of automatic detection of latest put region (like\n    -- not reliable mode detection when pasting from register; respecting not\n    -- only regions of put operations, but also yank and change).\n    user_put_regions = {},\n  },\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('buffer', config.buffer, 'table')\n  H.check_type('buffer.suffix', config.buffer.suffix, 'string')\n  H.check_type('buffer.options', config.buffer.options, 'table')\n\n  H.check_type('comment', config.comment, 'table')\n  H.check_type('comment.suffix', config.comment.suffix, 'string')\n  H.check_type('comment.options', config.comment.options, 'table')\n\n  H.check_type('conflict', config.conflict, 'table')\n  H.check_type('conflict.suffix', config.conflict.suffix, 'string')\n  H.check_type('conflict.options', config.conflict.options, 'table')\n\n  H.check_type('diagnostic', config.diagnostic, 'table')\n  H.check_type('diagnostic.suffix', config.diagnostic.suffix, 'string')\n  H.check_type('diagnostic.options', config.diagnostic.options, 'table')\n\n  H.check_type('file', config.file, 'table')\n  H.check_type('file.suffix', config.file.suffix, 'string')\n  H.check_type('file.options', config.file.options, 'table')\n\n  H.check_type('indent', config.indent, 'table')\n  H.check_type('indent.suffix', config.indent.suffix, 'string')\n  H.check_type('indent.options', config.indent.options, 'table')\n\n  H.check_type('jump', config.jump, 'table')\n  H.check_type('jump.suffix', config.jump.suffix, 'string')\n  H.check_type('jump.options', config.jump.options, 'table')\n\n  H.check_type('location', config.location, 'table')\n  H.check_type('location.suffix', config.location.suffix, 'string')\n  H.check_type('location.options', config.location.options, 'table')\n\n  H.check_type('oldfile', config.oldfile, 'table')\n  H.check_type('oldfile.suffix', config.oldfile.suffix, 'string')\n  H.check_type('oldfile.options', config.oldfile.options, 'table')\n\n  H.check_type('quickfix', config.quickfix, 'table')\n  H.check_type('quickfix.suffix', config.quickfix.suffix, 'string')\n  H.check_type('quickfix.options', config.quickfix.options, 'table')\n\n  H.check_type('treesitter', config.treesitter, 'table')\n  H.check_type('treesitter.suffix', config.treesitter.suffix, 'string')\n  H.check_type('treesitter.options', config.treesitter.options, 'table')\n\n  H.check_type('undo', config.undo, 'table')\n  H.check_type('undo.suffix', config.undo.suffix, 'string')\n  H.check_type('undo.options', config.undo.options, 'table')\n\n  H.check_type('window', config.window, 'table')\n  H.check_type('window.suffix', config.window.suffix, 'string')\n  H.check_type('window.options', config.window.options, 'table')\n\n  H.check_type('yank', config.yank, 'table')\n  H.check_type('yank.suffix', config.yank.suffix, 'string')\n  H.check_type('yank.options', config.yank.options, 'table')\n\n  return config\nend\n\n--stylua: ignore\nH.apply_config = function(config)\n  MiniBracketed.config = config\n\n  -- Make mappings. NOTE: make 'forward'/'backward' *after* 'first'/'last' to\n  -- allow non-letter suffixes define 'forward'/'backward'.\n  if config.buffer.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.buffer.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.buffer('first')<CR>\",    { desc = 'Buffer first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.buffer('last')<CR>\",     { desc = 'Buffer last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.buffer('backward')<CR>\", { desc = 'Buffer backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.buffer('forward')<CR>\",  { desc = 'Buffer forward' })\n  end\n\n  if config.comment.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.comment.suffix)\n    H.map('n', '[' .. up, \"<Cmd>lua MiniBracketed.comment('first')<CR>\",  { desc = 'Comment first' })\n    H.map('x', '[' .. up, \"<Cmd>lua MiniBracketed.comment('first')<CR>\",  { desc = 'Comment first' })\n    H.map('o', '[' .. up, \"V<Cmd>lua MiniBracketed.comment('first')<CR>\", { desc = 'Comment first' })\n\n    H.map('n', ']' .. up, \"<Cmd>lua MiniBracketed.comment('last')<CR>\",  { desc = 'Comment last' })\n    H.map('x', ']' .. up, \"<Cmd>lua MiniBracketed.comment('last')<CR>\",  { desc = 'Comment last' })\n    H.map('o', ']' .. up, \"V<Cmd>lua MiniBracketed.comment('last')<CR>\", { desc = 'Comment last' })\n\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.comment('backward')<CR>\",  { desc = 'Comment backward' })\n    H.map('x', '[' .. low, \"<Cmd>lua MiniBracketed.comment('backward')<CR>\",  { desc = 'Comment backward' })\n    H.map('o', '[' .. low, \"V<Cmd>lua MiniBracketed.comment('backward')<CR>\", { desc = 'Comment backward' })\n\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.comment('forward')<CR>\",  { desc = 'Comment forward' })\n    H.map('x', ']' .. low, \"<Cmd>lua MiniBracketed.comment('forward')<CR>\",  { desc = 'Comment forward' })\n    H.map('o', ']' .. low, \"V<Cmd>lua MiniBracketed.comment('forward')<CR>\", { desc = 'Comment forward' })\n  end\n\n  if config.conflict.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.conflict.suffix)\n    H.map('n', '[' .. up, \"<Cmd>lua MiniBracketed.conflict('first')<CR>\",  { desc = 'Conflict first' })\n    H.map('x', '[' .. up, \"<Cmd>lua MiniBracketed.conflict('first')<CR>\",  { desc = 'Conflict first' })\n    H.map('o', '[' .. up, \"V<Cmd>lua MiniBracketed.conflict('first')<CR>\", { desc = 'Conflict first' })\n\n    H.map('n', ']' .. up, \"<Cmd>lua MiniBracketed.conflict('last')<CR>\",  { desc = 'Conflict last' })\n    H.map('x', ']' .. up, \"<Cmd>lua MiniBracketed.conflict('last')<CR>\",  { desc = 'Conflict last' })\n    H.map('o', ']' .. up, \"V<Cmd>lua MiniBracketed.conflict('last')<CR>\", { desc = 'Conflict last' })\n\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.conflict('backward')<CR>\",  { desc = 'Conflict backward' })\n    H.map('x', '[' .. low, \"<Cmd>lua MiniBracketed.conflict('backward')<CR>\",  { desc = 'Conflict backward' })\n    H.map('o', '[' .. low, \"V<Cmd>lua MiniBracketed.conflict('backward')<CR>\", { desc = 'Conflict backward' })\n\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.conflict('forward')<CR>\",  { desc = 'Conflict forward' })\n    H.map('x', ']' .. low, \"<Cmd>lua MiniBracketed.conflict('forward')<CR>\",  { desc = 'Conflict forward' })\n    H.map('o', ']' .. low, \"V<Cmd>lua MiniBracketed.conflict('forward')<CR>\", { desc = 'Conflict forward' })\n  end\n\n  if config.diagnostic.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.diagnostic.suffix)\n    H.map('n', '[' .. up, \"<Cmd>lua MiniBracketed.diagnostic('first')<CR>\",  { desc = 'Diagnostic first' })\n    H.map('x', '[' .. up, \"<Cmd>lua MiniBracketed.diagnostic('first')<CR>\",  { desc = 'Diagnostic first' })\n    H.map('o', '[' .. up, \"v<Cmd>lua MiniBracketed.diagnostic('first')<CR>\", { desc = 'Diagnostic first' })\n\n    H.map('n', ']' .. up, \"<Cmd>lua MiniBracketed.diagnostic('last')<CR>\",  { desc = 'Diagnostic last' })\n    H.map('x', ']' .. up, \"<Cmd>lua MiniBracketed.diagnostic('last')<CR>\",  { desc = 'Diagnostic last' })\n    H.map('o', ']' .. up, \"v<Cmd>lua MiniBracketed.diagnostic('last')<CR>\", { desc = 'Diagnostic last' })\n\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.diagnostic('backward')<CR>\",  { desc = 'Diagnostic backward' })\n    H.map('x', '[' .. low, \"<Cmd>lua MiniBracketed.diagnostic('backward')<CR>\",  { desc = 'Diagnostic backward' })\n    H.map('o', '[' .. low, \"v<Cmd>lua MiniBracketed.diagnostic('backward')<CR>\", { desc = 'Diagnostic backward' })\n\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.diagnostic('forward')<CR>\",  { desc = 'Diagnostic forward' })\n    H.map('x', ']' .. low, \"<Cmd>lua MiniBracketed.diagnostic('forward')<CR>\",  { desc = 'Diagnostic forward' })\n    H.map('o', ']' .. low, \"v<Cmd>lua MiniBracketed.diagnostic('forward')<CR>\", { desc = 'Diagnostic forward' })\n  end\n\n  if config.file.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.file.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.file('first')<CR>\",    { desc = 'File first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.file('last')<CR>\",     { desc = 'File last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.file('backward')<CR>\", { desc = 'File backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.file('forward')<CR>\",  { desc = 'File forward' })\n  end\n\n  if config.indent.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.indent.suffix)\n    H.map('n', '[' .. up, \"<Cmd>lua MiniBracketed.indent('first')<CR>\",  { desc = 'Indent first' })\n    H.map('x', '[' .. up, \"<Cmd>lua MiniBracketed.indent('first')<CR>\",  { desc = 'Indent first' })\n    H.map('o', '[' .. up, \"V<Cmd>lua MiniBracketed.indent('first')<CR>\", { desc = 'Indent first' })\n\n    H.map('n', ']' .. up, \"<Cmd>lua MiniBracketed.indent('last')<CR>\",  { desc = 'Indent last' })\n    H.map('x', ']' .. up, \"<Cmd>lua MiniBracketed.indent('last')<CR>\",  { desc = 'Indent last' })\n    H.map('o', ']' .. up, \"V<Cmd>lua MiniBracketed.indent('last')<CR>\", { desc = 'Indent last' })\n\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.indent('backward')<CR>\",  { desc = 'Indent backward' })\n    H.map('x', '[' .. low, \"<Cmd>lua MiniBracketed.indent('backward')<CR>\",  { desc = 'Indent backward' })\n    H.map('o', '[' .. low, \"V<Cmd>lua MiniBracketed.indent('backward')<CR>\", { desc = 'Indent backward' })\n\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.indent('forward')<CR>\",  { desc = 'Indent forward' })\n    H.map('x', ']' .. low, \"<Cmd>lua MiniBracketed.indent('forward')<CR>\",  { desc = 'Indent forward' })\n    H.map('o', ']' .. low, \"V<Cmd>lua MiniBracketed.indent('forward')<CR>\", { desc = 'Indent forward' })\n  end\n\n  if config.jump.suffix ~= '' then\n    -- No Visual mode mappings due to implementation problems ()\n    local low, up = H.get_suffix_variants(config.jump.suffix)\n    H.map('n', '[' .. up, \"<Cmd>lua MiniBracketed.jump('first')<CR>\",  { desc = 'Jump first' })\n    H.map('o', '[' .. up, \"v<Cmd>lua MiniBracketed.jump('first')<CR>\", { desc = 'Jump first' })\n\n    H.map('n', ']' .. up, \"<Cmd>lua MiniBracketed.jump('last')<CR>\",  { desc = 'Jump last' })\n    H.map('o', ']' .. up, \"v<Cmd>lua MiniBracketed.jump('last')<CR>\", { desc = 'Jump last' })\n\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.jump('backward')<CR>\",  { desc = 'Jump backward' })\n    H.map('o', '[' .. low, \"v<Cmd>lua MiniBracketed.jump('backward')<CR>\", { desc = 'Jump backward' })\n\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.jump('forward')<CR>\",  { desc = 'Jump forward' })\n    H.map('o', ']' .. low, \"v<Cmd>lua MiniBracketed.jump('forward')<CR>\", { desc = 'Jump forward' })\n  end\n\n  if config.oldfile.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.oldfile.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.oldfile('first')<CR>\",    { desc = 'Oldfile first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.oldfile('last')<CR>\",     { desc = 'Oldfile last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.oldfile('backward')<CR>\", { desc = 'Oldfile backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.oldfile('forward')<CR>\",  { desc = 'Oldfile forward' })\n  end\n\n  if config.location.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.location.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.location('first')<CR>\",    { desc = 'Location first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.location('last')<CR>\",     { desc = 'Location last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.location('backward')<CR>\", { desc = 'Location backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.location('forward')<CR>\",  { desc = 'Location forward' })\n  end\n\n  if config.quickfix.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.quickfix.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.quickfix('first')<CR>\",    { desc = 'Quickfix first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.quickfix('last')<CR>\",     { desc = 'Quickfix last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.quickfix('backward')<CR>\", { desc = 'Quickfix backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.quickfix('forward')<CR>\",  { desc = 'Quickfix forward' })\n  end\n\n  if config.treesitter.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.treesitter.suffix)\n    H.map('n', '[' .. up, \"<Cmd>lua MiniBracketed.treesitter('first')<CR>\",  { desc = 'Treesitter first' })\n    H.map('x', '[' .. up, \"<Cmd>lua MiniBracketed.treesitter('first')<CR>\",  { desc = 'Treesitter first' })\n    H.map('o', '[' .. up, \"v<Cmd>lua MiniBracketed.treesitter('first')<CR>\", { desc = 'Treesitter first' })\n\n    H.map('n', ']' .. up, \"<Cmd>lua MiniBracketed.treesitter('last')<CR>\",  { desc = 'Treesitter last' })\n    H.map('x', ']' .. up, \"<Cmd>lua MiniBracketed.treesitter('last')<CR>\",  { desc = 'Treesitter last' })\n    H.map('o', ']' .. up, \"v<Cmd>lua MiniBracketed.treesitter('last')<CR>\", { desc = 'Treesitter last' })\n\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.treesitter('backward')<CR>\",  { desc = 'Treesitter backward' })\n    H.map('x', '[' .. low, \"<Cmd>lua MiniBracketed.treesitter('backward')<CR>\",  { desc = 'Treesitter backward' })\n    H.map('o', '[' .. low, \"v<Cmd>lua MiniBracketed.treesitter('backward')<CR>\", { desc = 'Treesitter backward' })\n\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.treesitter('forward')<CR>\",  { desc = 'Treesitter forward' })\n    H.map('x', ']' .. low, \"<Cmd>lua MiniBracketed.treesitter('forward')<CR>\",  { desc = 'Treesitter forward' })\n    H.map('o', ']' .. low, \"v<Cmd>lua MiniBracketed.treesitter('forward')<CR>\", { desc = 'Treesitter forward' })\n  end\n\n  if config.undo.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.undo.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.undo('first')<CR>\",    { desc = 'Undo first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.undo('last')<CR>\",     { desc = 'Undo last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.undo('backward')<CR>\", { desc = 'Undo backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.undo('forward')<CR>\",  { desc = 'Undo forward' })\n\n    H.map('n', 'u',     'u<Cmd>lua MiniBracketed.register_undo_state()<CR>')\n    H.map('n', '<C-R>', '<C-R><Cmd>lua MiniBracketed.register_undo_state()<CR>')\n  end\n\n  if config.window.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.window.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.window('first')<CR>\",    { desc = 'Window first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.window('last')<CR>\",     { desc = 'Window last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.window('backward')<CR>\", { desc = 'Window backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.window('forward')<CR>\",  { desc = 'Window forward' })\n  end\n\n  if config.yank.suffix ~= '' then\n    local low, up = H.get_suffix_variants(config.yank.suffix)\n    H.map('n', '[' .. up,  \"<Cmd>lua MiniBracketed.yank('first')<CR>\",    { desc = 'Yank first' })\n    H.map('n', ']' .. up,  \"<Cmd>lua MiniBracketed.yank('last')<CR>\",     { desc = 'Yank last' })\n    H.map('n', '[' .. low, \"<Cmd>lua MiniBracketed.yank('backward')<CR>\", { desc = 'Yank backward' })\n    H.map('n', ']' .. low, \"<Cmd>lua MiniBracketed.yank('forward')<CR>\",  { desc = 'Yank forward' })\n  end\nend\n\nH.get_suffix_variants = function(char) return char:lower(), char:upper() end\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniBracketed', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('BufEnter', '*', H.track_oldfile, 'Track oldfile')\n  au('TextYankPost', '*', H.track_yank, 'Track yank')\nend\n\nH.is_disabled = function() return vim.g.minibracketed_disable == true or vim.b.minibracketed_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniBracketed.config, vim.b.minibracketed_config or {}, config or {})\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.track_oldfile = function()\n  if H.is_disabled() then return end\n\n  -- Ensure tracking data is initialized\n  H.oldfile_ensure_initialized()\n\n  -- Reset tracking indicator to allow proper tracking of next buffer\n  local is_advancing = H.cache.oldfile.is_advancing\n  H.cache.oldfile.is_advancing = false\n\n  -- Track only appropriate buffers (normal buffers with path)\n  local path = vim.api.nvim_buf_get_name(0)\n  local is_proper_buffer = path ~= '' and vim.bo.buftype == ''\n  if not is_proper_buffer then return end\n\n  -- If advancing, don't touch tracking data to be able to consecutively move\n  -- along recent files. Cache advanced buffer name to later update recency of\n  -- the last one (just before buffer switching outside of `oldfile()`)\n  local cache_oldfile = H.cache.oldfile\n\n  if is_advancing then\n    cache_oldfile.last_advanced_bufname = path\n    return\n  end\n\n  -- If not advancing, update recency of a single latest advanced buffer (if\n  -- present) and then update recency of current buffer\n  if cache_oldfile.last_advanced_bufname ~= nil then\n    H.oldfile_update_recency(cache_oldfile.last_advanced_bufname)\n    cache_oldfile.last_advanced_bufname = nil\n  end\n\n  H.oldfile_update_recency(path)\nend\n\nH.track_yank = function()\n  -- Don't track if asked not to. Allows other functionality to disable\n  -- tracking (like in 'mini.move').\n  if H.is_disabled() then return end\n\n  -- Track all `TextYankPost` events without exceptions. This leads to a better\n  -- handling of charwise/linewise/blockwise selection detection.\n  local event = vim.v.event\n  table.insert(\n    H.cache.yank.history,\n    { operator = event.operator, regcontents = event.regcontents, regtype = event.regtype }\n  )\n\n  H.yank_stop_advancing()\nend\n\n-- Comments -------------------------------------------------------------------\nH.make_comment_checker = function()\n  local left, right = unpack(vim.fn.split(vim.bo.commentstring, '%s'))\n  left, right = left or '', right or ''\n  if left == '' and right == '' then return nil end\n\n  -- String is commented if it has structure:\n  -- <space> <left> <anything> <right> <space>\n  local regex = string.format('^%%s-%s.*%s%%s-$', vim.pesc(vim.trim(left)), vim.pesc(vim.trim(right)))\n\n  -- Check if line with number `line_num` is a comment. NOTE: `getline()`\n  -- return empty string for invalid line number, which makes them *not\n  -- commented*.\n  return function(line_num) return vim.fn.getline(line_num):find(regex) ~= nil end\nend\n\n-- Conflicts ------------------------------------------------------------------\nH.is_conflict_mark = function(line_num)\n  local l_start = vim.fn.getline(line_num):sub(1, 8)\n  return l_start == '<<<<<<< ' or l_start == '=======' or l_start == '>>>>>>> '\nend\n\n-- Diagnostic -----------------------------------------------------------------\nH.diagnostic_jump = function(pos, float, severity)\n  vim.diagnostic.jump({ count = 1, pos = pos, float = float, severity = severity })\nend\nif vim.fn.has('nvim-0.11') == 0 then\n  H.diagnostic_jump = function(pos, float, severity)\n    vim.diagnostic.goto_next({ cursor_position = pos, float = float, severity = severity })\n  end\nend\n\n-- Files ----------------------------------------------------------------------\nH.get_file_data = function()\n  -- Compute target directory\n  local cur_buf_path = vim.api.nvim_buf_get_name(0)\n  local dir_path = cur_buf_path ~= '' and vim.fn.fnamemodify(cur_buf_path, ':p:h') or vim.fn.getcwd()\n\n  -- Compute sorted array of all files in target directory\n  local dir_handle = vim.loop.fs_scandir(dir_path)\n  local files_stream = function() return vim.loop.fs_scandir_next(dir_handle) end\n\n  local files = {}\n  for basename, fs_type in files_stream do\n    if fs_type == 'file' then table.insert(files, basename) end\n  end\n\n  -- - Sort files ignoring case\n  table.sort(files, function(x, y) return x:lower() < y:lower() end)\n\n  if #files == 0 then return end\n  return { directory = dir_path, file_basenames = files }\nend\n\n-- Jumps ----------------------------------------------------------------------\nH.make_jump = function(jump_list, cur_jump_num, new_jump_num)\n  local num_diff = new_jump_num - cur_jump_num\n\n  if num_diff == 0 then\n    -- Perform jump manually to always jump. Example: move to last jump and\n    -- move manually; then jump with \"last\" direction should move to last jump.\n    local jump_entry = jump_list[new_jump_num]\n    pcall(vim.fn.cursor, { jump_entry.lnum, jump_entry.col + 1, jump_entry.coladd })\n  else\n    -- Use builtin mappings to also update current jump entry\n    local key = num_diff > 0 and '\\t' or '\\15'\n    vim.cmd('normal! ' .. math.abs(num_diff) .. key)\n  end\n\n  -- Open just enough folds\n  vim.cmd('normal! zv')\nend\n\n-- Oldfile --------------------------------------------------------------------\nH.oldfile_normalize = function()\n  -- Ensure that tracking data is initialized\n  H.oldfile_ensure_initialized()\n\n  -- Order currently readable paths in increasing order of recency\n  local recency_pairs = {}\n  for path, rec in pairs(H.cache.oldfile.recency) do\n    if vim.fn.filereadable(path) == 1 then table.insert(recency_pairs, { path, rec }) end\n  end\n  table.sort(recency_pairs, function(x, y) return x[2] < y[2] end)\n\n  -- Construct new tracking data with recency from 1 to number of entries\n  local new_recency = {}\n  for i, pair in ipairs(recency_pairs) do\n    new_recency[pair[1]] = i\n  end\n\n  H.cache.oldfile = { recency = new_recency, max_recency = #recency_pairs, is_advancing = H.cache.oldfile.is_advancing }\nend\n\nH.oldfile_ensure_initialized = function()\n  if H.cache.oldfile ~= nil or vim.v.oldfiles == nil then return end\n\n  local n = #vim.v.oldfiles\n  local recency = {}\n  for i, path in ipairs(vim.v.oldfiles) do\n    recency[path] = n - i + 1\n  end\n\n  H.cache.oldfile = { recency = recency, max_recency = n, is_advancing = false }\nend\n\nH.oldfile_get_array = function()\n  local res = {}\n  for path, i in pairs(H.cache.oldfile.recency) do\n    res[i] = path\n  end\n  return res\nend\n\nH.oldfile_update_recency = function(path)\n  local n = H.cache.oldfile.max_recency + 1\n  H.cache.oldfile.recency[path] = n\n  H.cache.oldfile.max_recency = n\nend\n\n-- Quickfix/Location lists ----------------------------------------------------\nH.qf_loc_implementation = function(list_type, direction, opts)\n  local get_list, goto_command = vim.fn.getqflist, 'cc'\n  if list_type == 'location' then\n    get_list, goto_command = function(...) return vim.fn.getloclist(0, ...) end, 'll'\n  end\n\n  -- Define iterator that traverses quickfix/location list entries\n  local list = get_list()\n  local n_list = #list\n  if n_list == 0 then return end\n\n  local iterator = {}\n\n  iterator.next = function(ind)\n    if ind == nil or n_list <= ind then return end\n    return ind + 1\n  end\n\n  iterator.prev = function(ind)\n    if ind == nil or ind <= 1 then return end\n    return ind - 1\n  end\n\n  iterator.state = get_list({ idx = 0 }).idx\n  iterator.start_edge = 0\n  iterator.end_edge = n_list + 1\n\n  -- Iterate\n  local res_ind = MiniBracketed.advance(iterator, direction, opts)\n\n  -- Apply. Focus target entry, open enough folds and center. Allow jumping to\n  -- current quickfix/loclist entry as it might be different from current\n  -- cursor position.\n  vim.cmd(goto_command .. ' ' .. res_ind)\n  vim.cmd('normal! zvzz')\nend\n\n-- Treesitter -----------------------------------------------------------------\nH.get_treesitter_node = function(row, col) return vim.treesitter.get_node({ pos = { row, col } }) end\n\n-- Undo -----------------------------------------------------------------------\nH.undo_sync = function(buf_id, tree, is_advancing)\n  -- Get or initialize buffer history of visited undo states\n  local prev_buf_history = H.cache.undo[buf_id] or H.undo_init(tree)\n  if is_advancing == nil then is_advancing = prev_buf_history.is_advancing end\n\n  -- Prune current buffer history to contain only allowed state numbers. This\n  -- assumes that once undo state is not allowed, it will always be not\n  -- allowed. This step is needed because allowed undo state numbers can:\n  -- - Not start from 1 due to 'undolevels'.\n  -- - Contain range of missing state numbers due to `:undo!`.\n  --\n  -- Do this even if advancing because `:undo!` can be executed at any time.\n  local allowed_states = H.undo_get_allowed_state_numbers(tree)\n\n  local buf_history = {}\n  for i, state_num in ipairs(prev_buf_history) do\n    -- Use only allowed states\n    if allowed_states[state_num] then H.undo_append_state(buf_history, state_num) end\n\n    -- Correctly track current id when advancing\n    if i == prev_buf_history.current_id then buf_history.current_id = #buf_history end\n  end\n  buf_history.current_id = buf_history.current_id or #buf_history\n  buf_history.is_advancing = prev_buf_history.is_advancing\n  buf_history.seq_last = prev_buf_history.seq_last\n\n  H.cache.undo[buf_id] = buf_history\n\n  -- Continue only if not actually advancing: either if set so manually *or* if\n  -- there were additions to undo history *or* some states became not allowed\n  -- (due to `:undo!`).\n  if is_advancing and tree.seq_last <= buf_history.seq_last and #buf_history == #prev_buf_history then return end\n\n  -- Register current undo state (if not equal to last).\n  -- Usually it is a result of advance but also can be due to `:undo`/`:undo!`.\n  H.undo_append_state(buf_history, tree.seq_cur)\n\n  -- Add all new *allowed* undo states created since last sync\n  for new_state = buf_history.seq_last + 1, tree.seq_last do\n    if allowed_states[new_state] then H.undo_append_state(buf_history, new_state) end\n  end\n\n  -- Update data to be most recent\n  buf_history.current_id = #buf_history\n  buf_history.is_advancing = false\n  buf_history.seq_last = tree.seq_last\nend\n\nH.undo_append_state = function(buf_history, state_num)\n  -- Ensure that there are no two consecutive equal states\n  if state_num == nil or buf_history[#buf_history] == state_num then return end\n\n  table.insert(buf_history, state_num)\nend\n\nH.undo_init = function(tree)\n  -- Assume all previous states are allowed\n  local res = {}\n  for i = 0, tree.seq_last do\n    res[i + 1] = i\n  end\n  res.current_id = #res\n  res.is_advancing = false\n  res.seq_last = tree.seq_last\n\n  return res\nend\n\nH.undo_get_allowed_state_numbers = function(tree)\n  -- `:undo 0` is always possible (goes to *before* the first allowed state).\n  local res = { [0] = true }\n  local traverse\n  traverse = function(entries)\n    for _, e in ipairs(entries) do\n      if e.alt ~= nil then traverse(e.alt) end\n      res[e.seq] = true\n    end\n  end\n\n  traverse(tree.entries)\n  return res\nend\n\n-- Yank -----------------------------------------------------------------------\nH.yank_stop_advancing = function()\n  H.cache.yank.current_id = #H.cache.yank.history\n  H.cache.yank.is_advancing = false\n  H.cache.yank.advance_put_regions[vim.api.nvim_get_current_buf()] = nil\nend\n\nH.get_yank_state = function() return { buf_id = vim.api.nvim_get_current_buf(), changedtick = vim.b.changedtick } end\n\nH.replace_latest_put_region = function(yank_data)\n  -- Squash all yank advancing in a single undo block\n  local normal_command = (H.cache.yank.is_advancing and 'undojoin | ' or '') .. 'silent normal! '\n  local normal_fun = function(x) vim.cmd(normal_command .. x) end\n\n  -- Compute latest put region: from latest `yank` advance; or from user's\n  -- latest put; or from `[`/`]` marks\n  local cache_yank = H.cache.yank\n  local buf_id = vim.api.nvim_get_current_buf()\n  local latest_region = cache_yank.advance_put_regions[buf_id]\n    or cache_yank.user_put_regions[buf_id]\n    or H.get_latest_region()\n\n  -- Compute modes for replaced and new regions.\n  local latest_mode = latest_region.mode\n  local new_mode = yank_data.regtype:sub(1, 1)\n\n  -- Compute later put key based on replaced and new regions.\n  -- Prefer `P` but use `p` in cases replaced region was on the edge: last line\n  -- for linewise-linewise replace or last column for nonlinewise-nonlinewise.\n  local is_linewise = (latest_mode == 'V' and new_mode == 'V')\n  local is_edge_line = is_linewise and latest_region.to.line == vim.fn.line('$')\n\n  local is_charblockwise = (latest_mode ~= 'V' and new_mode ~= 'V')\n  local is_edge_col = is_charblockwise and latest_region.to.col == vim.fn.getline(latest_region.to.line):len()\n\n  local is_edge = is_edge_line or is_edge_col\n  local put_key = is_edge and 'p' or 'P'\n\n  -- Delete latest region\n  H.region_delete(latest_region, normal_fun)\n\n  -- Paste yank data using temporary register\n  local cache_z_reg = vim.fn.getreg('z')\n  vim.fn.setreg('z', yank_data.regcontents, yank_data.regtype)\n\n  normal_fun('\"z' .. put_key)\n\n  vim.fn.setreg('z', cache_z_reg)\n\n  -- Register newly put region for correct further advancing\n  cache_yank.advance_put_regions[buf_id] = H.get_latest_region(new_mode)\nend\n\nH.get_latest_region = function(mode)\n  local left, right = vim.fn.getpos(\"'[\"), vim.fn.getpos(\"']\")\n  return {\n    from = { line = left[2], col = left[3] },\n    to = { line = right[2], col = right[3] },\n    -- Mode should be one of 'v', 'V', or '\\22' ('<C-v>')\n    -- By default use mode of current or unnamed register\n    -- NOTE: this breaks if latest paste was not from unnamed register.\n    -- To account for that, use `register_put_region()`.\n    mode = mode or H.get_register_mode(vim.v.register),\n  }\nend\n\nH.region_delete = function(region, normal_fun)\n  -- Start with `to` to have cursor positioned on region start after deletion\n  H.set_cursor(region.to.line, region.to.col - 1)\n\n  -- Do nothing more if region is empty (or leads to unnecessary line deletion)\n  local is_empty = region.from.line == region.to.line\n    and region.from.col == region.to.col\n    and vim.fn.getline(region.from.line) == ''\n\n  if is_empty then return end\n\n  -- Select region in correct Visual mode\n  normal_fun(region.mode)\n  H.set_cursor(region.from.line, region.from.col - 1)\n\n  -- Delete region in \"black hole\" register\n  -- - NOTE: it doesn't affect history as `\"_` doesn't trigger `TextYankPost`\n  normal_fun('\"_d')\nend\n\nH.get_register_mode = function(register)\n  -- Use only first character to correctly get '\\22' in blockwise mode\n  return vim.fn.getregtype(register):sub(1, 1)\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.bracketed) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.validate_direction = function(direction, choices, fun_name)\n  if not vim.tbl_contains(choices, direction) then\n    local choices_string = \"'\" .. table.concat(choices, \"', '\") .. \"'\"\n    local error_text = string.format('In `%s()` argument `direction` should be one of %s.', fun_name, choices_string)\n    H.error(error_text)\n  end\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.edit = function(path, win_id)\n  if type(path) ~= 'string' then return end\n  local b = vim.api.nvim_win_get_buf(win_id or 0)\n  local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)\n    and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))\n  local buf_id = vim.fn.bufadd(vim.fn.fnamemodify(path, ':.'))\n  -- Showing in window also loads. Use `pcall` to not error with swap messages.\n  pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)\n  vim.bo[buf_id].buflisted = true\n  if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end\n  return buf_id\nend\n\nH.add_to_jumplist = function() vim.cmd([[normal! m']]) end\n\nH.set_cursor = function(row, col)\n  if row <= 0 then return vim.api.nvim_win_set_cursor(0, { 1, 0 }) end\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  if n_lines < row then return vim.api.nvim_win_set_cursor(0, { n_lines, vim.fn.getline(n_lines):len() - 1 }) end\n  col = math.min(math.max(col, 0), vim.fn.getline(row):len())\n  return vim.api.nvim_win_set_cursor(0, { row, col })\nend\n\nreturn MiniBracketed\n"
  },
  {
    "path": "lua/mini/bufremove.lua",
    "content": "--- *mini.bufremove* Remove buffers\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Unshow, delete, and wipeout buffer while saving window layout\n---   (opposite to builtin Neovim's commands).\n---\n--- # Setup ~\n---\n--- This module doesn't need setup, but it can be done to improve usability.\n--- Setup with `require('mini.bufremove').setup({})` (replace `{}` with your\n--- `config` table). It will create global Lua table `MiniBufremove` which you\n--- can use for scripting or manually (with `:lua MiniBufremove.*`).\n---\n--- See |MiniBufremove.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minibufremove_config`\n--- will have no effect here.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Notes ~\n---\n--- 1. Which buffer to show in window(s) after its current buffer is removed is\n---    decided by the algorithm:\n---    - If alternate buffer (see |CTRL-^|) is listed (see |buflisted()|), use it.\n---    - If previous listed buffer (see |:bprevious|) is different, use it.\n---    - Otherwise create a new one with `nvim_create_buf(true, false)` and use it.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.minibufremove_disable` (globally) or\n--- `vim.b.minibufremove_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniBufremove\n\n---@alias __bufremove_return boolean|nil Whether operation was successful. If `nil`, no operation was done.\n---@alias __bufremove_buf_id number|nil Buffer identifier (see |bufnr()|) to use.\n---   Default: 0 for current.\n---@alias __bufremove_force boolean|nil Whether to ignore unsaved changes (using `!` version of\n---   command). If `false`, calling with unsaved changes will prompt confirm dialog.\n---   Default: `false`.\n\n-- Module definition ==========================================================\nlocal MiniBufremove = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniBufremove.config|.\n---\n---@usage >lua\n---   require('mini.bufremove').setup() -- use default config\n---   -- OR\n---   require('mini.bufremove').setup({}) -- replace {} with your config table\n--- <\nMiniBufremove.setup = function(config)\n  -- Export module\n  _G.MiniBufremove = MiniBufremove\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniBufremove.config = {\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Delete buffer `buf_id` with |:bdelete| after unshowing it\n---\n---@param buf_id __bufremove_buf_id\n---@param force __bufremove_force\n---\n---@return __bufremove_return\nMiniBufremove.delete = function(buf_id, force)\n  if H.is_disabled() then return end\n\n  return H.unshow_and_cmd(buf_id, force, 'bdelete')\nend\n\n--- Wipeout buffer `buf_id` with |:bwipeout| after unshowing it\n---\n---@param buf_id __bufremove_buf_id\n---@param force __bufremove_force\n---\n---@return __bufremove_return\nMiniBufremove.wipeout = function(buf_id, force)\n  if H.is_disabled() then return end\n\n  return H.unshow_and_cmd(buf_id, force, 'bwipeout')\nend\n\n--- Stop showing buffer `buf_id` in all windows\n---\n---@param buf_id __bufremove_buf_id\n---\n---@return __bufremove_return\nMiniBufremove.unshow = function(buf_id)\n  if H.is_disabled() then return end\n\n  buf_id = H.normalize_buf_id(buf_id)\n\n  if not H.is_valid_id(buf_id, 'buffer') then return false end\n\n  vim.tbl_map(MiniBufremove.unshow_in_window, vim.fn.win_findbuf(buf_id))\n\n  return true\nend\n\n--- Stop showing current buffer of window `win_id`\n---\n--- Notes:\n--- - If `win_id` represents |cmdline-window|, this function will close it.\n---\n---@param win_id number|nil Window identifier (see |win_getid()|) to use.\n---   Default: 0 for current.\n---\n---@return __bufremove_return\nMiniBufremove.unshow_in_window = function(win_id)\n  if H.is_disabled() then return nil end\n\n  win_id = (win_id == nil) and 0 or win_id\n\n  if not H.is_valid_id(win_id, 'window') then return false end\n\n  local cur_buf = vim.api.nvim_win_get_buf(win_id)\n\n  -- Temporary use window `win_id` as current to have Vim's functions working\n  vim.api.nvim_win_call(win_id, function()\n    if vim.fn.getcmdwintype() ~= '' then\n      vim.cmd('close!')\n      return\n    end\n\n    -- Try using alternate buffer\n    local alt_buf = vim.fn.bufnr('#')\n    if alt_buf ~= cur_buf and vim.fn.buflisted(alt_buf) == 1 then\n      vim.api.nvim_win_set_buf(win_id, alt_buf)\n      return\n    end\n\n    -- Try using previous buffer\n    local has_previous = pcall(vim.cmd, 'bprevious')\n    if has_previous and cur_buf ~= vim.api.nvim_win_get_buf(win_id) then return end\n\n    -- Create new listed scratch buffer\n    -- NOTE: leave it unnamed to allow `:h buffer-reuse`\n    local new_buf = vim.api.nvim_create_buf(true, false)\n    vim.api.nvim_win_set_buf(win_id, new_buf)\n  end)\n\n  return true\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniBufremove.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config) MiniBufremove.config = config end\n\nH.is_disabled = function() return vim.g.minibufremove_disable == true or vim.b.minibufremove_disable == true end\n\n-- Removing implementation ----------------------------------------------------\nH.unshow_and_cmd = function(buf_id, force, cmd)\n  buf_id = H.normalize_buf_id(buf_id)\n  if not H.is_valid_id(buf_id, 'buffer') then\n    H.message(buf_id .. ' is not a valid buffer id.')\n    return false\n  end\n\n  if force == nil then force = false end\n  if type(force) ~= 'boolean' then\n    H.message('`force` should be boolean.')\n    return false\n  end\n\n  local fun_name = ({ ['bdelete'] = 'delete', ['bwipeout'] = 'wipeout' })[cmd]\n  if not H.can_remove(buf_id, force, fun_name) then return false end\n\n  -- Unshow buffer from all windows\n  MiniBufremove.unshow(buf_id)\n\n  -- Execute command\n  local command = string.format('%s! %d', cmd, buf_id)\n  -- Use `pcall` here to take care of case where `unshow()` was enough. This\n  -- can happen with 'bufhidden' option values:\n  -- - If `delete` then `unshow()` already `bdelete`d buffer. Without `pcall`\n  --   it gives E516 for `MiniBufremove.delete()` (`wipeout` works).\n  -- - If `wipe` then `unshow()` already `bwipeout`ed buffer. Without `pcall`\n  --   it gives E517 for module's `wipeout()` (still E516 for `delete()`).\n  --\n  -- Also account for executing command in command-line window.\n  -- It gives E11 if trying to execute command. The `unshow()` call should\n  -- close such window but somehow it doesn't seem to happen immediately.\n  local ok, result = pcall(vim.cmd, command)\n  if not (ok or result:find('E516%D') or result:find('E517%D') or result:find('E11%D')) then\n    H.message(result)\n    return false\n  end\n\n  return true\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.bufremove) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg, is_important)\n  if MiniBufremove.config.silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.bufremove) ', 'WarningMsg' })\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(msg, is_important, {})\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.is_valid_id = function(x, type)\n  local is_valid = false\n  if type == 'buffer' then\n    is_valid = vim.api.nvim_buf_is_valid(x)\n  elseif type == 'window' then\n    is_valid = vim.api.nvim_win_is_valid(x)\n  end\n\n  if not is_valid then H.message(string.format('%s is not a valid %s id.', tostring(x), type)) end\n  return is_valid\nend\n\n-- Check if buffer can be removed with `MiniBufremove.fun_name` function\nH.can_remove = function(buf_id, force, fun_name)\n  if force or not vim.bo[buf_id].modified then return true end\n  local msg = string.format('Buffer %d has unsaved changes. Do you want to force %s?', buf_id, fun_name)\n  return vim.fn.confirm(msg, '&No\\n&Yes', 1, 'Question') == 2\nend\n\n-- Compute 'true' buffer id (strictly positive integer). Treat `nil` and 0 as\n-- current buffer.\nH.normalize_buf_id = function(buf_id)\n  if buf_id == nil or buf_id == 0 then return vim.api.nvim_get_current_buf() end\n  return buf_id\nend\n\nreturn MiniBufremove\n"
  },
  {
    "path": "lua/mini/clue.lua",
    "content": "--- *mini.clue* Show next key clues\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Implement custom key query process to reach target key combination:\n---     - Starts after customizable opt-in triggers (mode + keys).\n---\n---     - Each key press narrows down set of possible targets.\n---       Pressing `<BS>` removes previous user entry.\n---       Pressing `<Esc>` or `<C-c>` leads to an early stop.\n---       Doesn't depend on 'timeoutlen' and has basic support for 'langmap'.\n---\n---     - Ends when there is at most one target left or user pressed `<CR>`.\n---       Results into emulating pressing all query keys plus possible postkeys.\n---\n--- - Show window (after configurable delay) with clues. It lists available\n---   next keys along with their descriptions (auto generated from descriptions\n---   present keymaps and user-supplied clues; preferring the former).\n---\n--- - Configurable \"postkeys\" for key combinations - keys which will be emulated\n---   after combination is reached during key query process.\n---\n--- - Provide customizable sets of clues for common built-in keys/concepts:\n---     - `g` key.\n---     - `z` key.\n---     - Window commands.\n---     - Built-in completion.\n---     - Marks.\n---     - Registers.\n---\n--- - Lua functions to disable/enable triggers globally or per buffer.\n---\n--- For more details see:\n--- - |MiniClue-key-query-process|.\n--- - |MiniClue-examples|.\n--- - |MiniClue.config|.\n--- - |MiniClue.gen_clues|.\n---\n--- Notes:\n--- - There is no functionality to create mappings while defining clues.\n---   This is done to clearly separate these two different actions.\n---   The best suggested practice is to manually create mappings with\n---   descriptions (`desc` field in options), as they will be automatically\n---   used inside clue window.\n---\n--- - Triggers are implemented as special buffer-local mappings. This leads to\n---   several caveats:\n---     - They will override same regular buffer-local mappings and have\n---       precedence over global one.\n---\n---       Example: having set `<C-w>` as Normal mode trigger means that\n---       there should not be another `<C-w>` mapping.\n---\n---     - They need to be the latest created buffer-local mappings or they will\n---       not function properly. Most common indicator of this is that some\n---       mapping starts to work only after clue window is shown.\n---\n---       Example: `g` is set as Normal mode trigger, but `gcc` from |mini.comment|\n---       doesn't work right away. This is probably because there are some\n---       other buffer-local mappings starting with `g` which were created after\n---       mapping for `g` trigger. Most common places for this are in LSP server's\n---       `on_attach` or during tree-sitter start in buffer.\n---\n---       To check if trigger is the most recent buffer-local mapping, execute\n---       `:<mode-char>map <trigger-keys>` (like `:nmap g` for previous example).\n---       Mapping for trigger should be the first listed.\n---\n---       This module makes the best effort to work out of the box and cover\n---       most common cases, but it is not foolproof. The solution here is to\n---       ensure that triggers are created after making all buffer-local mappings:\n---       run either |MiniClue.setup()| or |MiniClue.ensure_buf_triggers()|.\n---\n--- - Descriptions from existing mappings take precedence over user-supplied\n---   clues. This is to ensure that information shown in clue window is as\n---   relevant as possible. To add/customize description of an already existing\n---   mapping, use |MiniClue.set_mapping_desc()|.\n---\n--- - Due to technical difficulties, there is no foolproof support for\n---   Operator-pending mode triggers (like `a`/`i` from |mini.ai|):\n---     - Doesn't work as part of a command in \"temporary Normal mode\" (like\n---       after |i_CTRL-O|) due to implementation difficulties.\n---     - Can have unexpected behavior with custom operators.\n---\n--- - Has (mostly solved) issues with macros:\n---     - All triggers are disabled during macro recording due to technical\n---       reasons.\n---     - The `@` and `Q` keys are specially mapped inside |MiniClue.setup()|\n---       (if the key is not already mapped) to temporarily disable triggers.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.clue').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniClue`\n--- which you can use for scripting or manually (with `:lua MiniClue.*`).\n---\n--- Config table **needs to have triggers configured**, none is set up by default.\n---\n--- See |MiniClue.config| for available config settings.\n---\n--- You can override runtime config settings (like clues or window options)\n--- locally to a buffer inside `vim.b.miniclue_config` which should have same\n--- structure as `MiniClue.config`. See |mini.nvim-buffer-local-config| for\n--- more details.\n---\n--- # Comparisons ~\n---\n--- - [folke/which-key.nvim](https://github.com/folke/which-key.nvim):\n---     - Both have the same main goal: show available next keys along with\n---       their customizable descriptions.\n---     - Has different UI and content layout.\n---     - Allows creating mappings inside its configuration, while this module\n---       doesn't have this by design (to clearly separate two different tasks).\n---     - Doesn't allow creating submodes, while this module does (via `postkeys`).\n---\n--- - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim):\n---     - Both allow creating submodes: state which starts at certain key\n---       combination; treats some keys differently; ends after `<Esc>`.\n---     - Doesn't show information about available next keys (outside of\n---       submodes), while that is this module's main goal.\n---\n--- # Highlight groups ~\n---\n--- - `MiniClueBorder` - window border.\n--- - `MiniClueDescGroup` - group description in clue window.\n--- - `MiniClueDescSingle` - single target description in clue window.\n--- - `MiniClueNextKey` - next key label in clue window.\n--- - `MiniClueNextKeyWithPostkeys` - next key label with postkeys in clue window.\n--- - `MiniClueSeparator` - separator in clue window.\n--- - `MiniClueTitle` - window title.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable creating triggers, set `vim.g.miniclue_disable` (globally) or\n--- `vim.b.miniclue_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniClue\n\n--- # General info ~\n---\n--- This module implements custom key query process imitating a usual built-in\n--- mechanism of user pressing keys in order to execute a mapping. General idea\n--- is the same: narrow down key combinations until the target is reached.\n---\n--- Main goals of its existence are:\n---\n--- - Allow reaching certain mappings be independent of 'timeoutlen'. That is,\n---   there is no fixed timeout after which currently typed keys are executed.\n---\n--- - Enable automated showing of next key clues after user-supplied delay\n---   (also independent of 'timeoutlen').\n---\n--- - Allow emulating configurable key presses after certain key combination is\n---   reached. This granular control allows creating so called \"submodes\".\n---   See more at |MiniClue-examples-submodes|.\n---\n--- This process is primarily designed for nested `<Leader>` mappings in Normal\n--- mode but works in all other main modes: Visual, Insert, Operator-pending\n--- (with caveats; no foolproof guarantees), Command-line, Terminal.\n---\n--- # Lifecycle ~\n---\n--- - Key query process starts when user types a trigger: certain keys in certain\n---   mode. Those keys are put into key query as a single user input. All possible\n---   mode key combinations are filtered to ones starting with the trigger keys.\n---\n---   Note: trigger is implemented as a regular mapping, so if it has at least\n---   two keys, they should be pressed within 'timeoutlen' milliseconds.\n---\n--- - Wait (indefinitely) for user to press a key. Advance depending on the key:\n---\n---     - Special key:\n---\n---         - If `<Esc>` or `<C-c>`, stop the process without any action.\n---\n---         - If `<CR>`, stop the process and execute current key query, meaning\n---           emulate (with |nvim_feedkeys()|) user pressing those keys.\n---\n---         - If `<BS>`, remove previous user input from the query. If query becomes\n---           empty, stop the process without any action.\n---\n---         - If a key for scrolling clue window (`scroll_down` / `scroll_up`\n---           in `config.window`; `<C-d>` / `<C-u>` by default), scroll clue window\n---           and wait for the next user key.\n---           Note: if clue window is not shown, treated as a not special key.\n---\n---     - Not special key. Add key to the query while filtering all available\n---       key combinations to start with the current key query. Advance:\n---\n---         - If there is a single available key combination matching current\n---           key query, execute it.\n---\n---         - If there is no key combinations starting with the current query,\n---           execute it. This, for instance, allows a seamless execution of\n---           operators in presence of a longer key combinations. Example: with\n---           `g` as trigger in Normal mode and available mappings `gc` / `gcc`\n---           (like from |mini.comment|), this allows typing `gcip` to comment\n---           current paragraph, although there are no key combinations\n---           starting with `gci`.\n---\n---         - Otherwise wait for the new user key press.\n---\n--- # Clue window ~\n---\n--- After initiating key query process and after each key press, a timer is\n--- started to show a clue window: floating window with information about\n--- available next keys along with their descriptions. Note: if window is\n--- already shown, its content is updated right away.\n---\n--- Clues can have these types:\n---\n--- - \"Terminal next key\": when pressed, will lead to query execution.\n---\n--- - \"Terminal next key with postkeys\": when pressed, will lead to query\n---   execution plus some configured postkeys.\n---\n--- - \"Group next key\": when pressed, will narrow down available key combinations\n---   and wait for another key press. Note: can have configured description\n---   (inside `config.clues`) or it will be auto generated based on the number of\n---   available key combinations.\n---@tag MiniClue-key-query-process\n\n--- # Full starter example ~\n---\n--- If not sure where to start, try this example with all provided clues from\n--- this module plus all |<Leader>| mappings in Normal and Visual modes: >lua\n---\n---   local miniclue = require('mini.clue')\n---   miniclue.setup({\n---     triggers = {\n---       -- Leader triggers\n---       { mode = { 'n', 'x' }, keys = '<Leader>' },\n---\n---       -- `[` and `]` keys\n---       { mode = 'n', keys = '[' },\n---       { mode = 'n', keys = ']' },\n---\n---       -- Built-in completion\n---       { mode = 'i', keys = '<C-x>' },\n---\n---       -- `g` key\n---       { mode = { 'n', 'x' }, keys = 'g' },\n---\n---       -- Marks\n---       { mode = { 'n', 'x' }, keys = \"'\" },\n---       { mode = { 'n', 'x' }, keys = '`' },\n---\n---       -- Registers\n---       { mode = { 'n', 'x' }, keys = '\"' },\n---       { mode = { 'i', 'c' }, keys = '<C-r>' },\n---\n---       -- Window commands\n---       { mode = 'n', keys = '<C-w>' },\n---\n---       -- `z` key\n---       { mode = { 'n', 'x' }, keys = 'z' },\n---     },\n---\n---     clues = {\n---       -- Enhance this by adding descriptions for <Leader> mapping groups\n---       miniclue.gen_clues.square_brackets(),\n---       miniclue.gen_clues.builtin_completion(),\n---       miniclue.gen_clues.g(),\n---       miniclue.gen_clues.marks(),\n---       miniclue.gen_clues.registers(),\n---       miniclue.gen_clues.windows(),\n---       miniclue.gen_clues.z(),\n---     },\n---   })\n--- <\n--- # Leader clues ~\n---\n--- Assume there are these |<Leader>| mappings set up: >lua\n---\n---   -- Set `<Leader>` before making any mappings and configuring 'mini.clue'\n---   vim.g.mapleader = ' '\n---\n---   local nmap_leader = function(suffix, rhs, desc)\n---     vim.keymap.set('n', '<Leader>' .. suffix, rhs, { desc = desc })\n---   end\n---   local xmap_leader = function(suffix, rhs, desc)\n---     vim.keymap.set('x', '<Leader>' .. suffix, rhs, { desc = desc })\n---   end\n---\n---   nmap_leader('bd', '<Cmd>lua MiniBufremove.delete()<CR>',  'Delete')\n---   nmap_leader('bw', '<Cmd>lua MiniBufremove.wipeout()<CR>', 'Wipeout')\n---\n---   nmap_leader('lf', '<Cmd>lua vim.lsp.buf.format()<CR>',     'Format')\n---   xmap_leader('lf', '<Cmd>lua vim.lsp.buf.format()<CR>',     'Format')\n---   nmap_leader('lr', '<Cmd>lua vim.lsp.buf.rename()<CR>',     'Rename')\n---   nmap_leader('lR', '<Cmd>lua vim.lsp.buf.references()<CR>', 'References')\n--- <\n--- The following setup will enable |<Leader>| as trigger in Normal and Visual\n--- modes and add descriptions to mapping groups: >lua\n---\n---   require('mini.clue').setup({\n---     -- Register `<Leader>` as trigger\n---     triggers = {\n---       { mode = { 'n', 'x' }, keys = '<Leader>' },\n---     },\n---\n---     -- Add descriptions for mapping groups\n---     clues = {\n---       { mode = 'n', keys = '<Leader>b', desc = '+Buffers' },\n---       { mode = 'n', keys = '<Leader>l', desc = '+LSP' },\n---     },\n---   })\n--- <\n--- # Clues without mappings ~\n---\n--- Clues can be shown not only for actually present mappings. This is helpful for\n--- showing clues for built-in key combinations. Here is an example of clues for\n--- a subset of built-in completion (see |MiniClue.gen_clues.builtin_completion()|\n--- to generate clues for all available completion sources): >lua\n---\n---   require('mini.clue').setup({\n---     -- Make `<C-x>` a trigger. Otherwise, key query process won't start.\n---     triggers = {\n---       { mode = 'i', keys = '<C-x>' },\n---     },\n---\n---     -- Register custom clues\n---     clues = {\n---       { mode = 'i', keys = '<C-x><C-f>', desc = 'File names' },\n---       { mode = 'i', keys = '<C-x><C-l>', desc = 'Whole lines' },\n---       { mode = 'i', keys = '<C-x><C-o>', desc = 'Omni completion' },\n---       { mode = 'i', keys = '<C-x><C-s>', desc = 'Spelling suggestions' },\n---       { mode = 'i', keys = '<C-x><C-u>', desc = \"With 'completefunc'\" },\n---     }\n---   })\n--- <\n--- # Triggers in special buffers ~\n---\n--- By default triggers are automatically created in listed ('buflisted') and some\n--- special non-listed buffers. Use |MiniClue.ensure_buf_triggers()| to manually\n--- enable in when you need them. For example: >vim\n---\n---   au FileType special_ft lua MiniClue.ensure_buf_triggers()\n--- <\n--- # Submodes ~\n--- *MiniClue-examples-submodes*\n---\n--- Submode is a state initiated after pressing certain key combination (\"prefix\")\n--- during which some keys are interpreted differently.\n---\n--- In this module submode can be implemented following these steps:\n---\n--- - Create mappings for each key inside submode. Left hand side of mappings\n---   should consist from prefix followed by the key.\n---\n--- - Create clue for each key inside submode with `postkeys` value equal to\n---   prefix. It would mean that after executing particular key combination from\n---   this submode, pressing its prefix will be automatically emulated (leading\n---   back to being inside submode).\n---\n--- - Register submode prefix (or some of its starting part) as trigger. Do not\n---   register \"overlapping\" triggers, like `<Leader>` and `<Leader>m`.\n---\n--- ## Submode examples ~\n---\n--- - Submode for moving with |mini.move|:\n---     - Press `<Leader>m` to start submode.\n---     - Press any of `h`/`j`/`k`/`l` to move selection/line.\n---     - Press `<Esc>` to stop submode.\n---\n---   The code: >lua\n---\n---   require('mini.move').setup({\n---     mappings = {\n---       left       = '<Leader>mh',\n---       right      = '<Leader>ml',\n---       down       = '<Leader>mj',\n---       up         = '<Leader>mk',\n---       line_left  = '<Leader>mh',\n---       line_right = '<Leader>ml',\n---       line_down  = '<Leader>mj',\n---       line_up    = '<Leader>mk',\n---     },\n---   })\n---\n---   require('mini.clue').setup({\n---     triggers = {\n---       -- This can also set up directly `<Leader>m` as a trigger, but make\n---       -- sure to not also use `<Leader>`, as they would \"overlap\"\n---       { mode = { 'n', 'x' }, keys = '<Leader>' },\n---     },\n---     clues = {\n---       { mode = 'n', keys = '<Leader>m', desc = '+Move' },\n---\n---       { mode = { 'n', 'x' }, keys = '<Leader>mh', postkeys = '<Leader>m' },\n---       { mode = { 'n', 'x' }, keys = '<Leader>mj', postkeys = '<Leader>m' },\n---       { mode = { 'n', 'x' }, keys = '<Leader>mk', postkeys = '<Leader>m' },\n---       { mode = { 'n', 'x' }, keys = '<Leader>ml', postkeys = '<Leader>m' },\n---     },\n---   })\n--- <\n--- - Submode for iterating buffers and windows with |mini.bracketed|:\n---     - Press `[` or `]` to start key query process for certain direction.\n---     - Press `b` / `w` to iterate buffers/windows until reach target one.\n---     - Press `<Esc>` to stop submode.\n---\n---   The code: >lua\n---\n---   require('mini.bracketed').setup()\n---\n---   require('mini.clue').setup({\n---     triggers = {\n---       { mode = 'n', keys = ']' },\n---       { mode = 'n', keys = '[' },\n---     },\n---     clues = {\n---       { mode = 'n', keys = ']b', postkeys = ']' },\n---       { mode = 'n', keys = ']w', postkeys = ']' },\n---\n---       { mode = 'n', keys = '[b', postkeys = '[' },\n---       { mode = 'n', keys = '[w', postkeys = '[' },\n---     },\n---   })\n--- <\n--- - Submode for window commands using |MiniClue.gen_clues.windows()|:\n---     - Press `<C-w>` to start key query process.\n---     - Press keys which move / change focus / resize windows.\n---     - Press `<Esc>` to stop submode.\n---\n---   The code: >lua\n---\n---   local miniclue = require('mini.clue')\n---   miniclue.setup({\n---     triggers = {\n---       { mode = 'n', keys = '<C-w>' },\n---     },\n---     clues = {\n---       miniclue.gen_clues.windows({\n---         submode_move = true,\n---         submode_navigate = true,\n---         submode_resize = true,\n---       })\n---     },\n---   })\n--- <\n--- # Window config ~\n--- >lua\n---   require('mini.clue').setup({\n---     triggers = { { mode = 'n', keys = '<Leader>' } },\n---\n---     window = {\n---       -- Show window immediately\n---       delay = 0,\n---\n---       config = {\n---         -- Compute window width automatically\n---         width = 'auto',\n---\n---         -- Use double-line border\n---         border = 'double',\n---       },\n---     },\n---   })\n--- <\n---@tag MiniClue-examples\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n\n-- Module definition ==========================================================\nlocal MiniClue = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniClue.config|.\n---\n---@usage >lua\n---   require('mini.clue').setup({}) -- replace {} with your config table\n---                                  -- needs `triggers` field present\n--- <\nMiniClue.setup = function(config)\n  -- Export module\n  _G.MiniClue = MiniClue\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # General info ~\n---\n--- - To use |<Leader>| as part of the config (either as trigger or inside clues),\n---   set it prior to running |MiniClue.setup()|.\n---\n--- - See |MiniClue-examples| for examples.\n---\n--- # Clues ~\n---\n--- `config.clues` is an array with extra information about key combinations.\n--- Each element can be one of:\n--- - Clue table.\n--- - Array (possibly nested) of clue tables.\n--- - Callable (function) returning either of the previous two.\n---\n--- A clue table is a table with the following fields:\n--- - <mode> `(string|table)` - single character describing mode short-name of\n---   key combination as in `nvim_set_keymap()` ('n', 'x', 'i', 'o', 'c', etc.),\n---   or a array thereof.\n--- - <keys> `(string)` - key combination for which clue will be shown.\n---   \"Human-readable\" key names as in |key-notation| (like \"<Leader>\", \"<Space>\",\n---   \"<Tab>\", etc.) are allowed.\n--- - <desc> `(string|function|nil)` - optional key combination description which is\n---   shown in clue window. If function, should return string description.\n--- - <postkeys> `(string|nil)` - optional postkeys which will be executed\n---   automatically after `keys`. Allows creation of submodes\n---   (see |MiniClue-examples-submodes|).\n---\n--- Notes:\n--- - Postkeys are literal simulation of keypresses with |nvim_feedkeys()|.\n---\n--- - Suggested approach to configuring clues is to create mappings with `desc`\n---   field while supplying to `config.clues` only elements describing groups,\n---   postkeys, and built-in mappings.\n---\n--- # Triggers ~\n---\n--- `config.triggers` is an array with information when |MiniClue-key-query-process|\n--- should start. Each element is a trigger table with the fields <mode> and\n--- <keys> which are treated the same as in clue table.\n---\n--- # Window ~\n---\n--- `config.window` defines behavior of clue window.\n---\n--- `config.window.delay` is a number of milliseconds after which clue window will\n--- appear. Can be 0 to show immediately.\n---\n--- `config.window.config` is a table defining floating window characteristics\n--- or a callable returning such table (will be called with identifier of\n--- window's buffer already showing all clues). It should have the same\n--- structure as in |nvim_open_win()| with the following enhancements:\n--- - <width> field can be equal to `\"auto\"` leading to window width being\n---   computed automatically based on its content. Default is fixed width of 30.\n--- - <row> and <col> can be equal to `\"auto\"` in which case they will be\n---   computed to \"stick\" to set anchor (\"SE\" by default; see |nvim_open_win()|).\n---   This allows changing corner in which window is shown: >lua\n---\n---   -- Pick one anchor\n---   local anchor = 'NW' -- top-left\n---   local anchor = 'NE' -- top-right\n---   local anchor = 'SW' -- bottom-left\n---   local anchor = 'SE' -- bottom-right\n---\n---   require('mini.clue').setup({\n---     window = {\n---       config = { anchor = anchor, row = 'auto', col = 'auto' },\n---     },\n---   })\n--- <\n--- `config.window.scroll_down` / `config.window.scroll_up` are strings defining\n--- keys which will scroll clue window down / up which is useful in case not\n--- all clues fit in current window height. Set to empty string `''` to disable\n--- either of them.\nMiniClue.config = {\n  -- Array of extra clues to show\n  clues = {},\n\n  -- Array of opt-in triggers which start custom key query process.\n  -- **Needs to have something in order to show clues**.\n  triggers = {},\n\n  -- Clue window settings\n  window = {\n    -- Floating window config\n    config = {},\n\n    -- Delay before showing clue window\n    delay = 1000,\n\n    -- Keys to scroll inside the clue window\n    scroll_down = '<C-d>',\n    scroll_up = '<C-u>',\n  },\n}\n--minidoc_afterlines_end\n\n--- Enable triggers in loaded listed and some special buffers\nMiniClue.enable_all_triggers = function()\n  local loaded_bufs = vim.tbl_filter(vim.api.nvim_buf_is_loaded, vim.api.nvim_list_bufs())\n  for _, buf_id in ipairs(loaded_bufs) do\n    -- Map only inside valid listed buffers and ones with special filetypes\n    local is_special = H.ft_to_enable[vim.bo[buf_id].filetype]\n    if vim.fn.buflisted(buf_id) == 1 or is_special then H.map_buf_triggers(buf_id) end\n  end\nend\n\n--- Enable triggers in buffer\n---\n---@param buf_id number|nil Buffer identifier. Default: current buffer.\nMiniClue.enable_buf_triggers = function(buf_id)\n  buf_id = (buf_id == nil or buf_id == 0) and vim.api.nvim_get_current_buf() or buf_id\n  if not H.is_valid_buf(buf_id) then H.error('`buf_id` should be a valid buffer identifier.') end\n  H.map_buf_triggers(buf_id)\nend\n\n--- Disable triggers in loaded buffers\nMiniClue.disable_all_triggers = function()\n  local loaded_bufs = vim.tbl_filter(vim.api.nvim_buf_is_loaded, vim.api.nvim_list_bufs())\n  for _, buf_id in ipairs(loaded_bufs) do\n    H.unmap_buf_triggers(buf_id)\n  end\nend\n\n--- Disable triggers in buffer\n---\n---@param buf_id number|nil Buffer identifier. Default: current buffer.\nMiniClue.disable_buf_triggers = function(buf_id)\n  buf_id = (buf_id == nil or buf_id == 0) and vim.api.nvim_get_current_buf() or buf_id\n  if not H.is_valid_buf(buf_id) then H.error('`buf_id` should be a valid buffer identifier.') end\n  H.unmap_buf_triggers(buf_id)\nend\n\n--- Ensure all triggers are valid\nMiniClue.ensure_all_triggers = function()\n  MiniClue.disable_all_triggers()\n  MiniClue.enable_all_triggers()\nend\n\n--- Ensure buffer triggers are valid\n---\n---@param buf_id number|nil Buffer identifier. Default: current buffer.\nMiniClue.ensure_buf_triggers = function(buf_id)\n  MiniClue.disable_buf_triggers(buf_id)\n  MiniClue.enable_buf_triggers(buf_id)\nend\n\n--- Update description of an existing mapping\n---\n--- Notes:\n--- - Uses buffer-local mapping in case there are both global and buffer-local\n---   mappings with same mode and LHS. Similar to |maparg()|.\n---\n---@param mode string Mapping mode (as in `maparg()`).\n---@param lhs string Mapping left hand side (as `name` in `maparg()`).\n---@param desc string New description to set.\nMiniClue.set_mapping_desc = function(mode, lhs, desc)\n  if type(mode) ~= 'string' then H.error('`mode` should be string.') end\n  if type(lhs) ~= 'string' then H.error('`lhs` should be string.') end\n  if type(desc) ~= 'string' then H.error('`desc` should be string.') end\n\n  local ok_get, map_data = pcall(vim.fn.maparg, lhs, mode, false, true)\n  if not ok_get or vim.tbl_count(map_data) == 0 then\n    local msg = string.format('No mapping found for mode %s and LHS %s.', vim.inspect(mode), vim.inspect(lhs))\n    H.error(msg)\n  end\n\n  map_data.desc = desc\n  local ok_set = pcall(vim.fn.mapset, mode, false, map_data)\n  if not ok_set then H.error(vim.inspect(desc) .. ' is not a valid description.') end\nend\n\n--- Generate pre-configured clues\n---\n--- This is a table with function elements. Call to actually get array of clues.\nMiniClue.gen_clues = {}\n\n--- Generate clues for built-in completion\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = 'i', keys = '<C-x>' }\n--- <\n---@return table Array of clues.\nMiniClue.gen_clues.builtin_completion = function()\n  --stylua: ignore\n  return {\n    { mode = 'i', keys = '<C-x><C-d>', desc = 'Defined identifiers' },\n    { mode = 'i', keys = '<C-x><C-e>', desc = 'Scroll up' },\n    { mode = 'i', keys = '<C-x><C-f>', desc = 'File names' },\n    { mode = 'i', keys = '<C-x><C-i>', desc = 'Identifiers' },\n    { mode = 'i', keys = '<C-x><C-k>', desc = 'Identifiers from dictionary' },\n    { mode = 'i', keys = '<C-x><C-l>', desc = 'Whole lines' },\n    { mode = 'i', keys = '<C-x><C-n>', desc = 'Next completion' },\n    { mode = 'i', keys = '<C-x><C-o>', desc = 'Omni completion' },\n    { mode = 'i', keys = '<C-x><C-p>', desc = 'Previous completion' },\n    { mode = 'i', keys = '<C-x><C-s>', desc = 'Spelling suggestions' },\n    { mode = 'i', keys = '<C-x><C-t>', desc = 'Identifiers from thesaurus' },\n    { mode = 'i', keys = '<C-x><C-y>', desc = 'Scroll down' },\n    { mode = 'i', keys = '<C-x><C-u>', desc = \"With 'completefunc'\" },\n    { mode = 'i', keys = '<C-x><C-v>', desc = 'Like in command line' },\n    { mode = 'i', keys = '<C-x><C-z>', desc = 'Stop completion' },\n    { mode = 'i', keys = '<C-x><C-]>', desc = 'Tags' },\n    { mode = 'i', keys = '<C-x>s',     desc = 'Spelling suggestions' },\n  }\nend\n\n--- Generate clues for `g` key\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = { 'n', 'x' }, keys = 'g' }\n--- <\n---@return table Array of clues.\nMiniClue.gen_clues.g = function()\n  local gr_clue = vim.fn.has('nvim-0.11') == 1 and { mode = 'n', keys = 'gr', desc = '+LSP' }\n    or { mode = 'n', keys = 'gr', desc = 'Virtual replace with character' }\n  local gr_clue_viz = vim.fn.has('nvim-0.11') == 1 and { mode = 'x', keys = 'gr', desc = '+LSP' } or {}\n\n  --stylua: ignore\n  return {\n    { mode = 'n', keys = 'g0',     desc = 'Go to leftmost visible column' },\n    { mode = 'n', keys = 'g8',     desc = 'Print hex value of char under cursor' },\n    { mode = 'n', keys = 'ga',     desc = 'Print ascii value' },\n    { mode = 'n', keys = 'gD',     desc = 'Go to definition in file' },\n    { mode = 'n', keys = 'gd',     desc = 'Go to definition in function' },\n    { mode = 'n', keys = 'gE',     desc = 'Go backwards to end of previous WORD' },\n    { mode = 'n', keys = 'ge',     desc = 'Go backwards to end of previous word' },\n    { mode = 'n', keys = 'gF',     desc = 'Edit file under cursor + jump line' },\n    { mode = 'n', keys = 'gf',     desc = 'Edit file under cursor' },\n    { mode = 'n', keys = 'gg',     desc = 'Go to line (def: first)' },\n    { mode = 'n', keys = 'gH',     desc = 'Start Select line mode' },\n    { mode = 'n', keys = 'gh',     desc = 'Start Select mode' },\n    { mode = 'n', keys = 'gI',     desc = 'Start Insert at column 1' },\n    { mode = 'n', keys = 'gi',     desc = 'Start Insert where it stopped' },\n    { mode = 'n', keys = 'gJ',     desc = 'Join lines without extra spaces' },\n    { mode = 'n', keys = 'gj',     desc = 'Go down by screen lines' },\n    { mode = 'n', keys = 'gk',     desc = 'Go up by screen lines' },\n    { mode = 'n', keys = 'gM',     desc = 'Go to middle of text line' },\n    { mode = 'n', keys = 'gm',     desc = 'Go to middle of screen line' },\n    { mode = 'n', keys = 'gN',     desc = 'Select previous search match' },\n    { mode = 'n', keys = 'gn',     desc = 'Select next search match' },\n    { mode = 'n', keys = 'go',     desc = 'Go to byte' },\n    { mode = 'n', keys = 'gP',     desc = 'Put text before cursor + stay after it' },\n    { mode = 'n', keys = 'gp',     desc = 'Put text after cursor + stay after it' },\n    { mode = 'n', keys = 'gQ',     desc = 'Switch to \"Ex\" mode' },\n    { mode = 'n', keys = 'gq',     desc = 'Format text (operator)' },\n    { mode = 'n', keys = 'gR',     desc = 'Enter Virtual Replace mode' },\n    gr_clue,\n    { mode = 'n', keys = 'gs',     desc = 'Sleep' },\n    { mode = 'n', keys = 'gT',     desc = 'Go to previous tabpage' },\n    { mode = 'n', keys = 'gt',     desc = 'Go to next tabpage' },\n    { mode = 'n', keys = 'gU',     desc = 'Make uppercase (operator)' },\n    { mode = 'n', keys = 'gu',     desc = 'Make lowercase (operator)' },\n    { mode = 'n', keys = 'gV',     desc = 'Avoid reselect' },\n    { mode = 'n', keys = 'gv',     desc = 'Reselect previous Visual area' },\n    { mode = 'n', keys = 'gw',     desc = 'Format text + keep cursor (operator)' },\n    { mode = 'n', keys = 'gx',     desc = 'Execute app for file under cursor' },\n    { mode = 'n', keys = 'g<C-]>', desc = '`:tjump` to tag under cursor' },\n    { mode = 'n', keys = 'g<C-a>', desc = 'Dump a memory profile' },\n    { mode = 'n', keys = 'g<C-g>', desc = 'Show information about cursor' },\n    { mode = 'n', keys = 'g<C-h>', desc = 'Start Select block mode' },\n    { mode = 'n', keys = 'g<Tab>', desc = 'Go to last accessed tabpage' },\n    { mode = 'n', keys = \"g'\",     desc = \"Jump to mark (don't affect jumplist)\" },\n    { mode = 'n', keys = 'g#',     desc = 'Search backwards word under cursor' },\n    { mode = 'n', keys = 'g$',     desc = 'Go to rightmost visible column' },\n    { mode = 'n', keys = 'g%',     desc = 'Cycle through matching groups' },\n    { mode = 'n', keys = 'g&',     desc = 'Repeat last `:s` on all lines' },\n    { mode = 'n', keys = 'g*',     desc = 'Search word under cursor' },\n    { mode = 'n', keys = 'g+',     desc = 'Go to newer text state' },\n    { mode = 'n', keys = 'g,',     desc = 'Go to newer position in change list' },\n    { mode = 'n', keys = 'g-',     desc = 'Go to older text state' },\n    { mode = 'n', keys = 'g;',     desc = 'Go to older position in change list' },\n    { mode = 'n', keys = 'g<',     desc = 'Display previous command output' },\n    { mode = 'n', keys = 'g?',     desc = 'Rot13 encode (operator)' },\n    { mode = 'n', keys = 'g@',     desc = \"Call 'operatorfunc' (operator)\" },\n    { mode = 'n', keys = 'g]',     desc = '`:tselect` tag under cursor' },\n    { mode = 'n', keys = 'g^',     desc = 'Go to leftmost visible non-whitespace' },\n    { mode = 'n', keys = 'g_',     desc = 'Go to lower line' },\n    { mode = 'n', keys = 'g`',     desc = \"Jump to mark (don't affect jumplist)\" },\n    { mode = 'n', keys = 'g~',     desc = 'Swap case (operator)' },\n\n    { mode = 'x', keys = 'gf',     desc = 'Edit selected file' },\n    { mode = 'x', keys = 'gJ',     desc = 'Join selected lines without extra spaces' },\n    { mode = 'x', keys = 'gq',     desc = 'Format selection' },\n    gr_clue_viz,\n    { mode = 'x', keys = 'gV',     desc = 'Avoid reselect' },\n    { mode = 'x', keys = 'gw',     desc = 'Format selection + keep cursor' },\n    { mode = 'x', keys = 'g<C-]>', desc = '`:tjump` to selected tag' },\n    { mode = 'x', keys = 'g<C-a>', desc = 'Increment with compound' },\n    { mode = 'x', keys = 'g<C-g>', desc = 'Show information about selection' },\n    { mode = 'x', keys = 'g<C-x>', desc = 'Decrement with compound' },\n    { mode = 'x', keys = 'g]',     desc = '`:tselect` selected tag' },\n    { mode = 'x', keys = 'g?',     desc = 'Rot13 encode selection' },\n  }\nend\n\n--- Generate clues for `[` and `]` keys\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = 'n', keys = '[' }\n---   { mode = 'n', keys = ']' }\n--- <\n---@return table Array of clues.\nMiniClue.gen_clues.square_brackets = function()\n  --stylua: ignore\n  return {\n    { mode = 'n', keys = '[<C-D>', desc = 'Go to first macro def with cursor word', },\n    { mode = 'n', keys = '[<C-I>', desc = 'Go to first match with cursor word', },\n    { mode = 'n', keys = '[%', desc = 'Go to previous unmatched group' },\n    { mode = 'n', keys = '[#', desc = 'Go to previous unmatched #if/#else/#ifdef' },\n    { mode = 'n', keys = \"['\", desc = 'Go to previous mark, first non-blank' },\n    { mode = 'n', keys = '[`', desc = 'Go to previous mark' },\n    { mode = 'n', keys = '[(', desc = \"Go to previous unmatched '('\" },\n    { mode = 'n', keys = '[/', desc = 'Go to previous C comment start' },\n    { mode = 'n', keys = '[*', desc = 'Go to previous C comment start' },\n    { mode = 'n', keys = '[I', desc = 'Show lines with cursor word', },\n    { mode = 'n', keys = '[D', desc = 'Show macro defs with cursor word' },\n    { mode = 'n', keys = '[p', desc = 'Paste with current indent' },\n    { mode = 'n', keys = '[P', desc = 'Paste with current indent' },\n    { mode = 'n', keys = '[[', desc = 'Go to previous section' },\n    { mode = 'n', keys = '[]', desc = 'Go to previous SECTION' },\n    { mode = 'n', keys = '[c', desc = 'Go to previous change' },\n    { mode = 'n', keys = '[d', desc = 'Show first macro def with cursor word' },\n    { mode = 'n', keys = '[f', desc = 'Edit file under cursor' },\n    { mode = 'n', keys = '[i', desc = 'Show first line with cursor word', },\n    { mode = 'n', keys = '[m', desc = 'Go to previous method start' },\n    { mode = 'n', keys = '[M', desc = 'Go to previous method end' },\n    { mode = 'n', keys = '[s', desc = 'Go to previous misspelled word' },\n    { mode = 'n', keys = '[z', desc = 'Go to current open fold start' },\n    { mode = 'n', keys = '[{', desc = \"Go to previous unmatched '{'\" },\n    { mode = 'n', keys = ']<C-D>', desc = 'Go to next macro def with cursor word', },\n    { mode = 'n', keys = ']<C-I>', desc = 'Go to next match with cursor word', },\n    { mode = 'n', keys = ']%', desc = 'Go to next unmatched group' },\n    { mode = 'n', keys = ']#', desc = 'Go to next unmatched #if/#else/#ifdef' },\n    { mode = 'n', keys = \"]'\", desc = \"Go to next mark, first non-blank\" },\n    { mode = 'n', keys = ']`', desc = 'Go to next mark' },\n    { mode = 'n', keys = '])', desc = \"Go to next unmatched ')'\" },\n    { mode = 'n', keys = ']/', desc = 'Go to next C comment end' },\n    { mode = 'n', keys = ']*', desc = 'Go to next C comment end' },\n    { mode = 'n', keys = ']D', desc = 'Show below macro defs with cursor word' },\n    { mode = 'n', keys = ']I', desc = 'Show below lines with cursor word', },\n    { mode = 'n', keys = ']P', desc = 'Paste with current indent' },\n    { mode = 'n', keys = '][', desc = 'Go to next SECTION' },\n    { mode = 'n', keys = ']]', desc = 'Go to next section' },\n    { mode = 'n', keys = ']c', desc = 'Go to next change' },\n    { mode = 'n', keys = ']d', desc = 'Show next macro def with cursor word' },\n    { mode = 'n', keys = ']f', desc = 'Edit file under cursor' },\n    { mode = 'n', keys = ']i', desc = 'Show next line with cursor word', },\n    { mode = 'n', keys = ']m', desc = 'Go to next method start' },\n    { mode = 'n', keys = ']M', desc = 'Go to next method end' },\n    { mode = 'n', keys = ']p', desc = 'Paste with current indent' },\n    { mode = 'n', keys = ']s', desc = 'Go to next misspelled word' },\n    { mode = 'n', keys = ']z', desc = 'Go to current open fold end' },\n    { mode = 'n', keys = ']}', desc = \"Go to next unmatched '}'\" },\n  }\nend\n\n--- Generate clues for marks\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = { 'n', 'x' }, keys = \"'\" }\n---   { mode = { 'n', 'x' }, keys = \"g'\" }\n---   { mode = { 'n', 'x' }, keys = '`' }\n---   { mode = { 'n', 'x' }, keys = 'g`' }\n--- <\n--- Note: if you use \"g\" as trigger (like to enable |MiniClue.gen_clues.g()|),\n--- don't add \"g'\" and \"g`\" as triggers: they already will be taken into account.\n---\n---@return table Array of clues.\n---\n---@seealso |mark-motions|\nMiniClue.gen_clues.marks = function()\n  local describe_marks = function(mode, prefix)\n    local make_clue = function(register, desc) return { mode = mode, keys = prefix .. register, desc = desc } end\n\n    return {\n      make_clue('^', 'Latest insert position'),\n      make_clue('.', 'Latest change'),\n      make_clue('\"', 'Latest exited position'),\n      make_clue(\"'\", 'Line before jump'),\n      make_clue('`', 'Position before jump'),\n      make_clue('[', 'Start of latest changed or yanked text'),\n      make_clue(']', 'End of latest changed or yanked text'),\n      make_clue('(', 'Start of sentence'),\n      make_clue(')', 'End of sentence'),\n      make_clue('{', 'Start of paragraph'),\n      make_clue('}', 'End of paragraph'),\n      make_clue('<', 'Start of latest visual selection'),\n      make_clue('>', 'End of latest visual selection'),\n    }\n  end\n\n  --stylua: ignore\n  return {\n    -- Normal and Visual mode\n    describe_marks({ 'n', 'x' }, \"'\"),\n    describe_marks({ 'n', 'x' }, \"g'\"),\n    describe_marks({ 'n', 'x' }, \"`\"),\n    describe_marks({ 'n', 'x' }, \"g`\"),\n  }\nend\n\n--- Generate clues for registers\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = { 'n', 'x' }, keys = '\"' }\n---   { mode = { 'i', 'c' }, keys = '<C-r>' }\n--- <\n---@param opts table|nil Options. Possible keys:\n---   - <show_contents> `(boolean)` - whether to show contents of all possible\n---     registers. If `false`, only description of special registers is shown.\n---     Default: `false`.\n---\n---@return table Array of clues.\n---\n---@seealso |registers|\nMiniClue.gen_clues.registers = function(opts)\n  opts = vim.tbl_deep_extend('force', { show_contents = false }, opts or {})\n\n  local describe_registers\n  if opts.show_contents then\n    describe_registers = H.make_clues_with_register_contents\n  else\n    describe_registers = function(mode, prefix)\n      local make_clue = function(register, desc) return { mode = mode, keys = prefix .. register, desc = desc } end\n      return {\n        make_clue('0', 'Latest yank'),\n        make_clue('1', 'Latest big delete'),\n        make_clue('\"', 'Default register'),\n        make_clue('#', 'Alternate buffer'),\n        make_clue('%', 'Name of the current file'),\n        make_clue('*', 'Selection clipboard'),\n        make_clue('+', 'System clipboard'),\n        make_clue('-', 'Latest small delete'),\n        make_clue('.', 'Latest inserted text'),\n        make_clue('/', 'Latest search pattern'),\n        make_clue(':', 'Latest executed command'),\n        make_clue('=', 'Result of expression'),\n        make_clue('_', 'Black hole'),\n      }\n    end\n  end\n\n  --stylua: ignore\n  return {\n    -- Normal and Visual mode\n    describe_registers({ 'n', 'x' }, '\"'),\n\n    -- Insert mode\n    describe_registers('i', '<C-r>'),\n\n    { mode = 'i', keys = '<C-r><C-r>', desc = '+Insert literally' },\n    describe_registers('i', '<C-r><C-r>'),\n\n    { mode = 'i', keys = '<C-r><C-o>', desc = '+Insert literally + not auto-indent' },\n    describe_registers('i', '<C-r><C-o>'),\n\n    { mode = 'i', keys = '<C-r><C-p>', desc = '+Insert + fix indent' },\n    describe_registers('i', '<C-r><C-p>'),\n\n    -- Command-line mode\n    describe_registers('c', '<C-r>'),\n\n    { mode = 'c', keys = '<C-r><C-r>', desc = '+Insert literally' },\n    describe_registers('c', '<C-r><C-r>'),\n\n    { mode = 'c', keys = '<C-r><C-o>', desc = '+Insert literally' },\n    describe_registers('c', '<C-r><C-o>'),\n  }\nend\n\n--- Generate clues for window commands\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = 'n', keys = '<C-w>' }\n--- <\n--- Note: only non-duplicated commands are included. For full list see |CTRL-W|.\n---\n---@param opts table|nil Options. Possible keys:\n---   - <submode_move> `(boolean)` - whether to make move (change layout)\n---     commands a submode by using `postkeys` field. Default: `false`.\n---   - <submode_navigate> `(boolean)` - whether to make navigation (change\n---     focus) commands a submode by using `postkeys` field. Default: `false`.\n---   - <submode_resize> `(boolean)` - whether to make resize (change size)\n---     commands a submode by using `postkeys` field. Default: `false`.\n---\n---@return table Array of clues.\nMiniClue.gen_clues.windows = function(opts)\n  local default_opts = { submode_navigate = false, submode_move = false, submode_resize = false }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  local postkeys_move, postkeys_navigate, postkeys_resize = nil, nil, nil\n  if opts.submode_move then postkeys_move = '<C-w>' end\n  if opts.submode_navigate then postkeys_navigate = '<C-w>' end\n  if opts.submode_resize then postkeys_resize = '<C-w>' end\n\n  --stylua: ignore\n  return {\n    { mode = 'n', keys = '<C-w>+',      desc = 'Increase height',         postkeys = postkeys_resize },\n    { mode = 'n', keys = '<C-w>-',      desc = 'Decrease height',         postkeys = postkeys_resize },\n    { mode = 'n', keys = '<C-w><',      desc = 'Decrease width',          postkeys = postkeys_resize },\n    { mode = 'n', keys = '<C-w>>',      desc = 'Increase width',          postkeys = postkeys_resize },\n    { mode = 'n', keys = '<C-w>=',      desc = 'Make windows same dimensions' },\n    { mode = 'n', keys = '<C-w>]',      desc = 'Split + jump to tag' },\n    { mode = 'n', keys = '<C-w>^',      desc = 'Split + edit alternate file' },\n    { mode = 'n', keys = '<C-w>_',      desc = 'Set height (def: very high)' },\n    { mode = 'n', keys = '<C-w>|',      desc = 'Set width (def: very wide)' },\n    { mode = 'n', keys = '<C-w>}',      desc = 'Show tag in preview' },\n    { mode = 'n', keys = '<C-w>b',      desc = 'Focus bottom',            postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>c',      desc = 'Close' },\n    { mode = 'n', keys = '<C-w>d',      desc = 'Split + jump to definition' },\n    { mode = 'n', keys = '<C-w>F',      desc = 'Split + edit file name + jump' },\n    { mode = 'n', keys = '<C-w>f',      desc = 'Split + edit file name' },\n    { mode = 'n', keys = '<C-w>g',      desc = '+Extra actions' },\n    { mode = 'n', keys = '<C-w>g]',     desc = 'Split + list tags' },\n    { mode = 'n', keys = '<C-w>g}',     desc = 'Do `:ptjump`' },\n    { mode = 'n', keys = '<C-w>g<C-]>', desc = 'Split + jump to tag with `:tjump`' },\n    { mode = 'n', keys = '<C-w>g<Tab>', desc = 'Focus last accessed tab', postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>gF',     desc = 'New tabpage + edit file name + jump' },\n    { mode = 'n', keys = '<C-w>gf',     desc = 'New tabpage + edit file name' },\n    { mode = 'n', keys = '<C-w>gT',     desc = 'Focus previous tabpage',  postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>gt',     desc = 'Focus next tabpage',      postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>H',      desc = 'Move to very left',       postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>h',      desc = 'Focus left',              postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>i',      desc = 'Split + jump to declaration' },\n    { mode = 'n', keys = '<C-w>J',      desc = 'Move to very bottom',     postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>j',      desc = 'Focus down',              postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>K',      desc = 'Move to very top',        postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>k',      desc = 'Focus up',                postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>L',      desc = 'Move to very right',      postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>l',      desc = 'Focus right',             postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>n',      desc = 'Open new' },\n    { mode = 'n', keys = '<C-w>o',      desc = 'Close all but current' },\n    { mode = 'n', keys = '<C-w>P',      desc = 'Focus preview',           postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>p',      desc = 'Focus last accessed',     postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>q',      desc = 'Quit current' },\n    { mode = 'n', keys = '<C-w>R',      desc = 'Rotate up/left',          postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>r',      desc = 'Rotate down/right',       postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>s',      desc = 'Split horizontally' },\n    { mode = 'n', keys = '<C-w>T',      desc = 'Create new tabpage + move' },\n    { mode = 'n', keys = '<C-w>t',      desc = 'Focus top',               postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>v',      desc = 'Split vertically' },\n    { mode = 'n', keys = '<C-w>W',      desc = 'Focus previous',          postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>w',      desc = 'Focus next',              postkeys = postkeys_navigate },\n    { mode = 'n', keys = '<C-w>x',      desc = 'Exchange windows',        postkeys = postkeys_move },\n    { mode = 'n', keys = '<C-w>z',      desc = 'Close preview' },\n  }\nend\n\n--- Generate clues for `z` key\n---\n--- Contains clues for the following triggers: >lua\n---\n---   { mode = { 'n', 'x' }, keys = 'z' }\n--- <\n---@return table Array of clues.\nMiniClue.gen_clues.z = function()\n  --stylua: ignore\n  return {\n    { mode = 'n', keys = 'zA',   desc = 'Toggle folds recursively' },\n    { mode = 'n', keys = 'za',   desc = 'Toggle fold' },\n    { mode = 'n', keys = 'zb',   desc = 'Redraw at bottom' },\n    { mode = 'n', keys = 'zC',   desc = 'Close folds recursively' },\n    { mode = 'n', keys = 'zc',   desc = 'Close fold' },\n    { mode = 'n', keys = 'zD',   desc = 'Delete folds recursively' },\n    { mode = 'n', keys = 'zd',   desc = 'Delete fold' },\n    { mode = 'n', keys = 'zE',   desc = 'Eliminate all folds' },\n    { mode = 'n', keys = 'ze',   desc = 'Scroll to cursor on right screen side' },\n    { mode = 'n', keys = 'zF',   desc = 'Create fold' },\n    { mode = 'n', keys = 'zf',   desc = 'Create fold (operator)' },\n    { mode = 'n', keys = 'zG',   desc = 'Temporarily mark as correctly spelled' },\n    { mode = 'n', keys = 'zg',   desc = 'Permanently mark as correctly spelled' },\n    { mode = 'n', keys = 'zH',   desc = 'Scroll left half screen' },\n    { mode = 'n', keys = 'zh',   desc = 'Scroll left' },\n    { mode = 'n', keys = 'zi',   desc = \"Toggle 'foldenable'\" },\n    { mode = 'n', keys = 'zj',   desc = 'Move to start of next fold' },\n    { mode = 'n', keys = 'zk',   desc = 'Move to end of previous fold' },\n    { mode = 'n', keys = 'zL',   desc = 'Scroll right half screen' },\n    { mode = 'n', keys = 'zl',   desc = 'Scroll right' },\n    { mode = 'n', keys = 'zM',   desc = 'Close all folds' },\n    { mode = 'n', keys = 'zm',   desc = 'Fold more' },\n    { mode = 'n', keys = 'zN',   desc = \"Set 'foldenable'\" },\n    { mode = 'n', keys = 'zn',   desc = \"Reset 'foldenable'\" },\n    { mode = 'n', keys = 'zO',   desc = 'Open folds recursively' },\n    { mode = 'n', keys = 'zo',   desc = 'Open fold' },\n    { mode = 'n', keys = 'zP',   desc = 'Paste without trailspace' },\n    { mode = 'n', keys = 'zp',   desc = 'Paste without trailspace' },\n    { mode = 'n', keys = 'zR',   desc = 'Open all folds' },\n    { mode = 'n', keys = 'zr',   desc = 'Fold less' },\n    { mode = 'n', keys = 'zs',   desc = 'Scroll to cursor on left screen side' },\n    { mode = 'n', keys = 'zt',   desc = 'Redraw at top' },\n    { mode = 'n', keys = 'zu',   desc = '+Undo spelling commands' },\n    { mode = 'n', keys = 'zug',  desc = 'Undo `zg`' },\n    { mode = 'n', keys = 'zuG',  desc = 'Undo `zG`' },\n    { mode = 'n', keys = 'zuw',  desc = 'Undo `zw`' },\n    { mode = 'n', keys = 'zuW',  desc = 'Undo `zW`' },\n    { mode = 'n', keys = 'zv',   desc = 'Open enough folds' },\n    { mode = 'n', keys = 'zW',   desc = 'Temporarily mark as incorrectly spelled' },\n    { mode = 'n', keys = 'zw',   desc = 'Permanently mark as incorrectly spelled' },\n    { mode = 'n', keys = 'zX',   desc = 'Update folds' },\n    { mode = 'n', keys = 'zx',   desc = 'Update folds + open enough folds' },\n    { mode = 'n', keys = 'zy',   desc = 'Yank without trailing spaces (operator)' },\n    { mode = 'n', keys = 'zz',   desc = 'Redraw at center' },\n    { mode = 'n', keys = 'z+',   desc = 'Redraw under bottom at top' },\n    { mode = 'n', keys = 'z-',   desc = 'Redraw at bottom + cursor on first non-blank' },\n    { mode = 'n', keys = 'z.',   desc = 'Redraw at center + cursor on first non-blank' },\n    { mode = 'n', keys = 'z=',   desc = 'Show spelling suggestions' },\n    { mode = 'n', keys = 'z^',   desc = 'Redraw above top at bottom' },\n\n    { mode = 'x', keys = 'zf',   desc = 'Create fold from selection' },\n  }\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniClue.config)\n\n-- Namespaces\nH.ns_id = {\n  highlight = vim.api.nvim_create_namespace('MiniClueHighlight'),\n}\n\n-- State of user input\nH.state = {\n  trigger = nil,\n  -- Array of raw keys\n  query = {},\n  clues = {},\n  timer = vim.loop.new_timer(),\n  buf_id = nil,\n  win_id = nil,\n  is_after_postkeys = false,\n}\n\n-- Default window config\nH.default_win_config = {\n  anchor = 'SE',\n  focusable = false,\n  relative = 'editor',\n  style = 'minimal',\n  width = 30,\n  -- Use high enough value to be on top of built-in windows (pmenu, etc.)\n  zindex = 251,\n}\n\n-- Precomputed raw keys\nH.keys = {\n  bs = vim.api.nvim_replace_termcodes('<BS>', true, true, true),\n  cr = vim.api.nvim_replace_termcodes('<CR>', true, true, true),\n  exit = vim.api.nvim_replace_termcodes([[<C-\\><C-n>]], true, true, true),\n  ctrl_d = vim.api.nvim_replace_termcodes('<C-d>', true, true, true),\n  ctrl_u = vim.api.nvim_replace_termcodes('<C-u>', true, true, true),\n}\n\n-- Special filetypes for which to enable triggers. These are common interactive\n-- not listed filetypes. NOTE: no 'minifiles' as `'` trigger conflicts with its\n-- local `'`. Plus it pollutes `g?` content.\nH.ft_to_enable = { help = true, git = true, ministarter = true }\n\n-- Timers\nH.timers = {\n  getcharstr = vim.loop.new_timer(),\n}\n\n-- Undo autocommand to be created for several operator tweaks\nH.undo_autocommand = 'au ModeChanged * ++once undo!'\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('clues', config.clues, 'table')\n  H.check_type('triggers', config.triggers, 'table')\n\n  H.check_type('window', config.window, 'table')\n  if not (type(config.window.config) == 'table' or vim.is_callable(config.window.config)) then\n    H.error('`window.config` should be table or callable, not ' .. type(config.window.config))\n  end\n  H.check_type('window.delay', config.window.delay, 'number')\n  H.check_type('window.scroll_down', config.window.scroll_down, 'string')\n  H.check_type('window.scroll_up', config.window.scroll_up, 'string')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniClue.config = config\n\n  -- Create trigger keymaps for all existing buffers\n  MiniClue.enable_all_triggers()\n\n  -- Tweak macro execution\n  local exec_macro = function(key, register)\n    if register == nil then return end\n    MiniClue.disable_all_triggers()\n    vim.schedule(function() MiniClue.enable_all_triggers() end)\n    -- NOTE: Use `t` flag for \"Handle as if typed\" for better integration with\n    -- other modules/plugins (like 'mini.jump').\n    pcall(vim.api.nvim_feedkeys, vim.v.count1 .. key .. register, 'nt', false)\n  end\n\n  local macro_keymap_opts = { nowait = true, desc = \"Execute macro without 'mini.clue' triggers\" }\n\n  local exec_register_macro = function() exec_macro('@', H.getcharstr()) end\n  if vim.fn.maparg('@', 'n') == '' then vim.keymap.set('n', '@', exec_register_macro, macro_keymap_opts) end\n\n  local exec_latest_macro = function() exec_macro('Q', '') end\n  if vim.fn.maparg('Q', 'n') == '' then vim.keymap.set('n', 'Q', exec_latest_macro, macro_keymap_opts) end\nend\n\nH.is_disabled = function(buf_id)\n  local buf_disable = H.get_buf_var(buf_id, 'miniclue_disable')\n  return vim.g.miniclue_disable == true or buf_disable == true\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniClue', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  -- Ensure buffer-local mappings for triggers are the latest ones to fully\n  -- utilize `<nowait>`. Use `vim.schedule_wrap` to allow other events to\n  -- create `vim.b.miniclue_config` and `vim.b.miniclue_disable`.\n  -- Check for listed buffer in `BufWinEnter` (instead of using `BufAdd`) to\n  -- delay acting until buffer is loaded (otherwise buffer-local options can be\n  -- prematurely \"finalized\"). Process it at most once for performance.\n  local did_ensure = {}\n  local ensure_triggers = vim.schedule_wrap(function(ev)\n    if not H.is_valid_buf(ev.buf) then return end\n    local skip_triggers = ev.event == 'BufWinEnter' and (did_ensure[ev.buf] or vim.fn.buflisted(ev.buf) ~= 1)\n    did_ensure[ev.buf] = true\n    if skip_triggers then return end\n    MiniClue.ensure_buf_triggers(ev.buf)\n  end)\n  -- - Respect `LspAttach` as it is a common source of buffer-local mappings\n  au({ 'BufWinEnter', 'LspAttach' }, '*', ensure_triggers, 'Ensure buffer-local trigger keymaps')\n  au('BufUnload', '*', function(ev) did_ensure[ev.buf] = nil end, 'Track buffer-local trigger keymaps')\n  au('Filetype', vim.tbl_keys(H.ft_to_enable), ensure_triggers, 'Ensure buffer-local trigger keymaps')\n\n  -- Disable all triggers (current and future) when recording macro as they\n  -- interfere with what is actually recorded\n  local cache_disable\n  local disable_all_plus = function()\n    MiniClue.disable_all_triggers()\n    cache_disable = vim.g.miniclue_disable\n    vim.g.miniclue_disable = true\n  end\n  local enable_all_plus = function()\n    vim.g.miniclue_disable = cache_disable\n    MiniClue.enable_all_triggers()\n  end\n  au('RecordingEnter', '*', disable_all_plus, 'Disable all triggers')\n  au('RecordingLeave', '*', enable_all_plus, 'Enable all triggers')\n\n  au('VimResized', '*', H.window_update, 'Update window on resize')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  hi('MiniClueBorder',              { link = 'FloatBorder' })\n  hi('MiniClueDescGroup',           { link = 'DiagnosticFloatingWarn' })\n  hi('MiniClueDescSingle',          { link = 'NormalFloat' })\n  hi('MiniClueNextKey',             { link = 'DiagnosticFloatingHint' })\n  hi('MiniClueNextKeyWithPostkeys', { link = 'DiagnosticFloatingError' })\n  hi('MiniClueSeparator',           { link = 'DiagnosticFloatingInfo' })\n  hi('MiniClueTitle',               { link = 'FloatTitle' })\nend\n\nH.get_config = function(config, buf_id)\n  config = config or {}\n  local buf_config = H.get_buf_var(buf_id, 'miniclue_config') or {}\n  local global_config = MiniClue.config\n\n  -- Manually reconstruct to allow array elements to be concatenated\n  local res = {\n    clues = H.list_concat(global_config.clues, buf_config.clues, config.clues),\n    triggers = H.list_concat(global_config.triggers, buf_config.triggers, config.triggers),\n    window = vim.tbl_deep_extend('force', global_config.window, buf_config.window or {}, config.window or {}),\n  }\n  return res\nend\n\nH.get_buf_var = function(buf_id, name)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.is_valid_buf(buf_id) then return nil end\n  return vim.b[buf_id][name]\nend\n\n-- Triggers -------------------------------------------------------------------\nH.map_buf_triggers = function(buf_id)\n  if not H.is_valid_buf(buf_id) or H.is_disabled(buf_id) then return end\n\n  for _, trigger in ipairs(H.get_config(nil, buf_id).triggers) do\n    local modes = type(trigger.mode) == 'table' and trigger.mode or { trigger.mode }\n    for _, mode in ipairs(modes) do\n      H.map_trigger(buf_id, { mode = mode, keys = trigger.keys })\n    end\n  end\nend\n\nH.unmap_buf_triggers = function(buf_id)\n  if not H.is_valid_buf(buf_id) or H.is_disabled(buf_id) then return end\n\n  for _, trigger in ipairs(H.get_config(nil, buf_id).triggers) do\n    local modes = type(trigger.mode) == 'table' and trigger.mode or { trigger.mode }\n    for _, mode in ipairs(modes) do\n      H.unmap_trigger(buf_id, { mode = mode, keys = trigger.keys })\n    end\n  end\nend\n\nH.map_trigger = function(buf_id, trigger)\n  if not H.is_valid_buf(buf_id) then return end\n\n  -- Compute mapping RHS\n  trigger.keys = H.replace_termcodes(trigger.keys)\n  local lhs = H.keytrans(trigger.keys)\n\n  local is_ministarter_map = vim.bo[buf_id].filetype == 'ministarter'\n    and vim.api.nvim_buf_call(buf_id, function() return vim.fn.maparg(lhs, trigger.mode) ~= '' end)\n  if is_ministarter_map then return end\n\n  local rhs = function()\n    -- Don't act if for some reason entered the same trigger during state exec\n    local is_in_exec = type(H.exec_trigger) == 'table'\n      and H.exec_trigger.mode == trigger.mode\n      and H.exec_trigger.keys == trigger.keys\n    if is_in_exec then\n      H.exec_trigger = nil\n      return\n    end\n\n    -- Start user query\n    H.state_set(trigger, { trigger.keys })\n\n    -- Do not advance if no other clues to query. NOTE: it is `<= 1` and not\n    -- `<= 0` because the \"init query\" mapping should match.\n    if vim.tbl_count(H.state.clues) <= 1 then return H.state_exec() end\n\n    H.state_advance()\n  end\n\n  -- Use buffer-local mappings and `nowait` to make it a primary source of\n  -- keymap execution\n  local desc = string.format('Query keys after \"%s\"', lhs)\n  local opts = { buffer = buf_id, nowait = true, desc = desc }\n\n  -- Create mapping. Use translated variant to make it work with <F*> keys.\n  vim.keymap.set(trigger.mode, lhs, rhs, opts)\nend\n\nH.unmap_trigger = function(buf_id, trigger)\n  if not H.is_valid_buf(buf_id) then return end\n  pcall(vim.keymap.del, trigger.mode, H.keytrans(trigger.keys), { buffer = buf_id })\nend\n\n-- State ----------------------------------------------------------------------\nH.state_advance = function(opts)\n  opts = opts or {}\n  local config_window = H.get_config().window\n\n  -- Show clues: delay (debounce) first show; update immediately if shown or\n  -- after postkeys (for visual feedback that extra key is needed to stop)\n  H.state.timer:stop()\n  local show_immediately = H.is_valid_win(H.state.win_id) or H.state.is_after_postkeys\n  local delay = show_immediately and 0 or config_window.delay\n  H.state.timer:start(delay, 0, function() H.window_update(opts.same_content) end)\n\n  -- Reset postkeys right now to not flicker when trying to close window during\n  -- \"not querying\" check\n  H.state.is_after_postkeys = false\n\n  -- Query user for new key\n  local key = H.getcharstr()\n\n  -- Handle key\n  if key == nil then return H.state_reset() end\n\n  if key == H.keys.cr then return H.state_exec() end\n\n  local is_window_shown = H.is_valid_win(H.state.win_id)\n  local is_scroll_down = key == H.replace_termcodes(config_window.scroll_down)\n  local is_scroll_up = key == H.replace_termcodes(config_window.scroll_up)\n  if is_window_shown and (is_scroll_down or is_scroll_up) then\n    H.window_scroll(is_scroll_down)\n    return H.state_advance({ same_content = true })\n  end\n\n  if key == H.keys.bs then\n    H.state_pop()\n  else\n    H.state_push(key)\n  end\n\n  -- Advance state\n  -- - Execute if reached single target keymap\n  if H.state_is_at_target() then return H.state_exec() end\n\n  -- - Reset if there are no keys (like after `<BS>`)\n  if #H.state.query == 0 then return H.state_reset() end\n\n  -- - Query user for more information if there is not enough\n  --   NOTE: still advance even if there is single clue because it is still not\n  --   a target but can be one.\n  if vim.tbl_count(H.state.clues) >= 1 then return H.state_advance() end\n\n  -- - Fall back for executing what user typed\n  H.state_exec()\nend\n\nH.state_set = function(trigger, query)\n  H.state.trigger = trigger\n  H.state.query = query\n  H.state.clues = H.clues_filter(H.clues_get_all(trigger.mode), query)\nend\n\nH.state_reset = function(keep_window)\n  H.state.trigger = nil\n  H.state.query = {}\n  H.state.clues = {}\n  H.state.is_after_postkeys = false\n\n  H.state.timer:stop()\n  if not keep_window then H.window_close() end\nend\n\nH.state_exec = function()\n  -- Compute keys to type\n  local keys_to_type = H.compute_exec_keys()\n\n  -- Add extra (redundant) safety flag to try to avoid infinite recursion\n  local trigger, clue = H.state.trigger, H.state_get_query_clue()\n  H.exec_trigger = trigger\n  vim.schedule(function() H.exec_trigger = nil end)\n\n  -- Reset state\n  local has_postkeys = (clue or {}).postkeys ~= nil\n  H.state_reset(has_postkeys)\n\n  -- Disable trigger !!!VERY IMPORTANT!!!\n  -- This is a workaround against infinite recursion (like if `g` is trigger\n  -- then typing `gg`/`g~` would introduce infinite recursion).\n  local buf_id = vim.api.nvim_get_current_buf()\n  H.unmap_trigger(buf_id, trigger)\n\n  -- Execute keys. The `i` flag is used to fully support Operator-pending mode.\n  -- Flag `t` imitates keys as if user typed, which is reasonable but has small\n  -- downside with edge cases of 'langmap' (like ':\\;;\\;:') as it \"inverts\" key\n  -- meaning second time (at least in Normal mode).\n  vim.api.nvim_feedkeys(keys_to_type, 'mit', false)\n\n  -- Enable trigger back after it can no longer harm\n  vim.schedule(function() H.map_trigger(buf_id, trigger) end)\n\n  -- Apply postkeys (in scheduled fashion)\n  if has_postkeys then H.state_apply_postkeys(clue.postkeys) end\nend\n\nH.state_push = function(keys)\n  table.insert(H.state.query, keys)\n  H.state.clues = H.clues_filter(H.state.clues, H.state.query)\nend\n\nH.state_pop = function()\n  H.state.query[#H.state.query] = nil\n  H.state.clues = H.clues_filter(H.clues_get_all(H.state.trigger.mode), H.state.query)\nend\n\nH.state_apply_postkeys = vim.schedule_wrap(function(postkeys)\n  -- Register that possible future querying is a result of postkeys.\n  -- This enables (keep) showing window immediately.\n  H.state.is_after_postkeys = true\n\n  -- Use `nvim_feedkeys()` because using `state_set()` and\n  -- `state_advance()` directly does not work: it doesn't guarantee to be\n  -- executed **after** keys from `nvim_feedkeys()`.\n  vim.api.nvim_feedkeys(postkeys, 'mit', false)\n\n  -- Defer check of whether postkeys resulted into window.\n  -- Could not find proper way to check this which guarantees to be executed\n  -- after `nvim_feedkeys()` takes effect **end** doesn't result into flicker\n  -- when consecutively applying \"submode\" keys.\n  vim.defer_fn(function()\n    if #H.state.query == 0 then H.window_close() end\n  end, 50)\nend)\n\nH.state_is_at_target = function()\n  return vim.tbl_count(H.state.clues) == 1 and H.state.clues[H.query_to_keys(H.state.query)] ~= nil\nend\n\nH.state_get_query_clue = function()\n  local keys = H.query_to_keys(H.state.query)\n  return H.state.clues[keys]\nend\n\nH.compute_exec_keys = function()\n  local keys_count = vim.v.count > 0 and vim.v.count or ''\n  local keys_query = H.query_to_keys(H.state.query)\n  local res = keys_count .. keys_query\n\n  local cur_mode = vim.fn.mode(1)\n\n  -- Using `feedkeys()` inside Operator-pending mode leads to its cancel into\n  -- Normal/Insert mode so extra work should be done to rebuild all keys\n  if vim.startswith(cur_mode, 'no') then\n    local operator_tweak = H.operator_tweaks[vim.v.operator] or function(x) return x end\n    res = operator_tweak(vim.v.operator .. H.get_forced_submode() .. res)\n  elseif not vim.startswith(cur_mode, 'i') and H.get_default_register() ~= vim.v.register then\n    -- Force non-default register but not in Insert mode\n    local expr_reg_keys = vim.v.register == '=' and (vim.fn.getreginfo('=').regcontents[1] .. '\\r') or ''\n    res = '\"' .. vim.v.register .. expr_reg_keys .. res\n  end\n\n  -- `feedkeys()` inside \"temporary\" Normal mode is executed **after** it is\n  -- already back from Normal mode. Go into it again with `<C-o>` ('\\15').\n  -- NOTE: This only works when Normal mode trigger is triggered in\n  -- \"temporary\" Normal mode. Still doesn't work when Operator-pending mode is\n  -- triggered afterwards (like in `<C-o>gUiw` with 'i' as trigger).\n  if cur_mode:find('^ni') ~= nil then res = '\\15' .. res end\n\n  return res\nend\n\n-- Some operators needs special tweaking due to their nature:\n-- - Some operators perform on register. Solution: add register explicitly.\n-- - Some operators end up changing mode which affects `feedkeys()`.\n--   Solution: explicitly exit to Normal mode with '<C-\\><C-n>'.\n-- - Some operators still perform some redundant operation before `feedkeys()`\n--   takes effect. Solution: add one-shot autocommand undoing that.\nH.operator_tweaks = {\n  ['c'] = function(keys)\n    -- Doing '<C-\\><C-n>' moves cursor one space to left (same as `i<Esc>`).\n    -- Solution: add one-shot autocommand correcting cursor position.\n    vim.cmd('au InsertLeave * ++once normal! l')\n    return H.keys.exit .. '\"' .. vim.v.register .. keys\n  end,\n  ['d'] = function(keys) return '\"' .. vim.v.register .. keys end,\n  ['y'] = function(keys) return '\"' .. vim.v.register .. keys end,\n  ['~'] = function(keys)\n    if vim.fn.col('.') == 1 then vim.cmd(H.undo_autocommand) end\n    return keys\n  end,\n  ['g~'] = function(keys)\n    if vim.fn.col('.') == 1 then vim.cmd(H.undo_autocommand) end\n    return keys\n  end,\n  ['g?'] = function(keys)\n    if vim.fn.col('.') == 1 then vim.cmd(H.undo_autocommand) end\n    return keys\n  end,\n  ['!'] = function(keys) return H.keys.exit .. keys end,\n  ['>'] = function(keys)\n    vim.cmd(H.undo_autocommand)\n    return keys\n  end,\n  ['<'] = function(keys)\n    vim.cmd(H.undo_autocommand)\n    return keys\n  end,\n  ['g@'] = function(keys)\n    -- Cancelling in-process `g@` operator seems to be particularly hard.\n    -- Not even sure why specifically this combination works, but having `x`\n    -- flag in `feedkeys()` is crucial.\n    vim.api.nvim_feedkeys(H.keys.exit, 'nx', false)\n    return H.keys.exit .. keys\n  end,\n}\n\nH.query_to_keys = function(query) return table.concat(query, '') end\n\n-- Window ---------------------------------------------------------------------\nH.window_update = vim.schedule_wrap(function(same_content)\n  -- Make sure that outdated windows are not shown\n  if #H.state.query == 0 then return H.window_close() end\n  local win_id = H.state.win_id\n\n  -- Close window if it is not in current tabpage (as only window is tracked)\n  local is_different_tabpage = H.is_valid_win(win_id)\n    and vim.api.nvim_win_get_tabpage(win_id) ~= vim.api.nvim_get_current_tabpage()\n  if is_different_tabpage then H.window_close() end\n\n  -- Create-update buffer showing clues\n  if not same_content then H.state.buf_id = H.buffer_update() end\n\n  -- Create-update window showing buffer\n  local win_config = H.window_get_config()\n  if not H.is_valid_win(win_id) then\n    win_config.noautocmd = true\n    win_id = H.window_open(win_config)\n    H.state.win_id = win_id\n  else\n    vim.api.nvim_win_set_config(win_id, win_config)\n    vim.wo[win_id].list = true\n  end\n\n  -- Make scroll not persist. NOTE: Don't use 'normal! gg' inside target window\n  -- as it resets `v:count` and `v:register` which results into invalid keys\n  -- reproduction in Operator-pending mode.\n  if not same_content then vim.api.nvim_win_set_cursor(win_id, { 1, 0 }) end\n\n  -- Add redraw because Neovim won't do it when `getcharstr()` is active\n  vim.cmd('redraw')\nend)\n\nH.window_scroll = function(is_scroll_down)\n  local scroll_key = is_scroll_down and H.keys.ctrl_d or H.keys.ctrl_u\n  local f = function()\n    local cache_scroll, bot_line, n_lines = vim.wo.scroll, vim.fn.line('w$'), vim.api.nvim_buf_line_count(0)\n    -- Do not scroll past the end of buffer\n    local scroll_count = is_scroll_down and math.min(cache_scroll, n_lines - bot_line) or cache_scroll\n    if scroll_count > 0 then pcall(vim.cmd, 'normal! ' .. scroll_count .. scroll_key) end\n    vim.wo.scroll = cache_scroll\n  end\n  vim.api.nvim_win_call(H.state.win_id, f)\nend\n\nH.window_open = function(config)\n  local win_id = vim.api.nvim_open_win(H.state.buf_id, false, config)\n\n  vim.wo[win_id].foldenable = false\n  vim.wo[win_id].foldmethod = 'manual'\n  vim.wo[win_id].wrap = false\n  vim.wo[win_id].list = true\n  vim.wo[win_id].listchars = 'extends:…'\n\n  local win_hl = 'FloatBorder:MiniClueBorder,FloatTitle:MiniClueTitle'\n  vim.wo[win_id].winhighlight = win_hl\n\n  return win_id\nend\n\nH.window_close = function()\n  -- Closing floating window when Command-line window is active is not allowed\n  -- on Neovim<0.10. Make sure it is closed after leaving it.\n  -- See https://github.com/neovim/neovim/issues/24452\n  local win_id = H.state.win_id\n  if vim.fn.has('nvim-0.10') == 0 and vim.fn.getcmdwintype() ~= '' then\n    vim.api.nvim_create_autocmd(\n      'CmdwinLeave',\n      { once = true, callback = function() pcall(vim.api.nvim_win_close, win_id, true) end }\n    )\n    return\n  else\n    pcall(vim.api.nvim_win_close, win_id, true)\n  end\n\n  H.state.win_id = nil\nend\n\nH.window_get_config = function()\n  local has_statusline = vim.o.laststatus > 0\n  local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)\n  -- Remove 2 from maximum height to account for top and bottom borders\n  local max_height = vim.o.lines - vim.o.cmdheight - (has_tabline and 1 or 0) - (has_statusline and 1 or 0) - 2\n  max_height = math.max(max_height, 1)\n\n  local keys = H.query_to_keys(H.state.query)\n  local query_clue = (H.state.clues[keys] or {}).desc or ''\n  local title = (#H.state.query <= 1 or query_clue == '') and H.keytrans(keys) or query_clue\n\n  local buf_id = H.state.buf_id\n  local cur_config_fields = {\n    row = vim.o.lines - vim.o.cmdheight - (has_statusline and 1 or 0),\n    col = vim.o.columns,\n    height = math.min(vim.api.nvim_buf_line_count(buf_id), max_height),\n    title = ' ' .. title .. ' ',\n    border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil,\n  }\n  local user_config = H.expand_callable(H.get_config().window.config, buf_id) or {}\n  local res = vim.tbl_deep_extend('force', H.default_win_config, cur_config_fields, user_config)\n\n  -- Tweak \"auto\" fields\n  if res.width == 'auto' then res.width = H.buffer_get_width() + 1 end\n\n  if res.row == 'auto' then\n    local is_on_top = res.anchor == 'NW' or res.anchor == 'NE'\n    res.row = is_on_top and (has_tabline and 1 or 0) or cur_config_fields.row\n  end\n\n  if res.col == 'auto' then\n    local is_on_left = res.anchor == 'NW' or res.anchor == 'SW'\n    res.col = is_on_left and 0 or cur_config_fields.col\n  end\n\n  -- Ensure proper config\n  res.width = math.min(math.max(res.width, 1), vim.o.columns - 2)\n  if type(res.title) == 'string' then res.title = H.fit_to_width(res.title, res.width) end\n\n  return res\nend\n\n-- Buffer ---------------------------------------------------------------------\nH.buffer_update = function()\n  local buf_id = H.state.buf_id\n  if not H.is_valid_buf(buf_id) then\n    buf_id = vim.api.nvim_create_buf(false, true)\n    H.set_buf_name(buf_id, 'content')\n  end\n\n  -- Compute content data\n  local keys = H.query_to_keys(H.state.query)\n  local content = H.clues_to_buffer_content(H.state.clues, keys)\n\n  -- Add lines\n  local lines = {}\n  for _, line_content in ipairs(content) do\n    table.insert(lines, string.format(' %s │ %s', line_content.next_key, line_content.desc))\n  end\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n\n  -- Add highlighting\n  local ns_id = H.ns_id.highlight\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n\n  local set_hl = function(hl_group, line_from, col_from, line_to, col_to)\n    local opts = { end_row = line_to, end_col = col_to, hl_group = hl_group, hl_eol = true }\n    vim.api.nvim_buf_set_extmark(buf_id, ns_id, line_from, col_from, opts)\n  end\n\n  for i, line_content in ipairs(content) do\n    local sep_start = line_content.next_key:len() + 3\n    local next_key_hl_group = line_content.has_postkeys and 'MiniClueNextKeyWithPostkeys' or 'MiniClueNextKey'\n    set_hl(next_key_hl_group, i - 1, 0, i - 1, sep_start - 1)\n\n    -- NOTE: Separator '│' is 3 bytes long\n    set_hl('MiniClueSeparator', i - 1, sep_start - 1, i - 1, sep_start + 2)\n\n    local desc_hl_group = line_content.is_group and 'MiniClueDescGroup' or 'MiniClueDescSingle'\n    set_hl(desc_hl_group, i - 1, sep_start + 2, i, 0)\n  end\n\n  return buf_id\nend\n\nH.buffer_get_width = function()\n  if not H.is_valid_buf(H.state.buf_id) then return end\n  local lines = vim.api.nvim_buf_get_lines(H.state.buf_id, 0, -1, false)\n  local res = 0\n  for _, l in ipairs(lines) do\n    res = math.max(res, vim.fn.strdisplaywidth(l))\n  end\n  return res\nend\n\n-- Clues ----------------------------------------------------------------------\nH.clues_get_all = function(mode)\n  local res = {}\n\n  -- Order of clue precedence: config clues < buffer mappings < global mappings\n  local config_clues = H.clues_normalize(H.get_config().clues) or {}\n  local mode_filter = function(x) return type(x.mode) == 'table' and vim.tbl_contains(x.mode, mode) or x.mode == mode end\n  local mode_clues = vim.tbl_filter(mode_filter, config_clues)\n  for _, clue in ipairs(mode_clues) do\n    local lhsraw = H.replace_termcodes(clue.keys)\n\n    local res_data = res[lhsraw] or {}\n\n    -- - Allow callable clue description\n    local desc = H.expand_callable(clue.desc)\n    -- - Fall back to possibly already present fields to allow partial\n    --   overwrite in later clues. Like to add `postkeys` and inherit `desc`.\n    res_data.desc = desc or res_data.desc\n    res_data.postkeys = H.replace_termcodes(clue.postkeys) or res_data.postkeys\n\n    res[lhsraw] = res_data\n  end\n\n  for _, map_data in ipairs(vim.api.nvim_get_keymap(mode)) do\n    local lhsraw = H.replace_termcodes(map_data.lhs)\n    local res_data = res[lhsraw] or {}\n    res_data.desc = map_data.desc or ''\n    res[lhsraw] = res_data\n  end\n\n  for _, map_data in ipairs(vim.api.nvim_buf_get_keymap(0, mode)) do\n    local lhsraw = H.replace_termcodes(map_data.lhs)\n    local res_data = res[lhsraw] or {}\n    res_data.desc = map_data.desc or ''\n    res[lhsraw] = res_data\n  end\n\n  return res\nend\n\nH.clues_normalize = function(clues)\n  local res = {}\n  local process\n  process = function(x)\n    x = H.expand_callable(x)\n    if H.is_clue(x) then return table.insert(res, x) end\n    if not H.islist(x) then return nil end\n    for _, y in ipairs(x) do\n      process(y)\n    end\n  end\n\n  process(clues)\n  return res\nend\n\nH.clues_filter = function(clues, query)\n  local keys = H.query_to_keys(query)\n  for clue_keys, _ in pairs(clues) do\n    if not vim.startswith(clue_keys, keys) then clues[clue_keys] = nil end\n  end\n  return clues\nend\n\nH.clues_to_buffer_content = function(clues, keys)\n  -- Use translated keys to properly handle cases like `<Del>`, `<End>`, etc.\n  keys = H.keytrans(keys)\n\n  -- Gather clue data\n  local keys_len = keys:len()\n  local keys_pattern = string.format('^%s(.+)$', vim.pesc(keys))\n\n  local next_key_data, next_key_max_width = {}, 0\n  for clue_keys, clue_data in pairs(clues) do\n    local left, _, rest_keys = H.keytrans(clue_keys):find(keys_pattern)\n\n    -- Add non-trivial next key data only if clue matches current keys plus\n    -- something more\n    if left ~= nil then\n      local next_key = H.clues_get_first_key(rest_keys)\n\n      -- Update description data\n      local data = next_key_data[next_key] or {}\n      data.n_choices = (data.n_choices or 0) + 1\n\n      -- - Add description directly if it is group clue with description or\n      --   a non-group clue\n      if next_key == rest_keys then\n        data.desc = clue_data.desc or ''\n        data.has_postkeys = clue_data.postkeys ~= nil\n      end\n\n      next_key_data[next_key] = data\n\n      -- Update width data\n      local next_key_width = vim.fn.strchars(next_key)\n      data.next_key_width = next_key_width\n      next_key_max_width = math.max(next_key_max_width, next_key_width)\n    end\n  end\n\n  -- Convert to array sorted by keys and finalize content\n  local next_keys_extra = vim.tbl_map(\n    function(x) return { key = x, keytype = H.clues_get_next_key_type(x) } end,\n    vim.tbl_keys(next_key_data)\n  )\n  table.sort(next_keys_extra, H.clues_compare_next_key)\n  local next_keys = vim.tbl_map(function(x) return x.key end, next_keys_extra)\n\n  local res = {}\n  for _, key in ipairs(next_keys) do\n    local data = next_key_data[key]\n    local is_group = data.n_choices > 1\n    local desc = data.desc or string.format('+%d choice%s', data.n_choices, is_group and 's' or '')\n    local next_key = key .. string.rep(' ', next_key_max_width - data.next_key_width)\n    table.insert(res, { next_key = next_key, desc = desc, is_group = is_group, has_postkeys = data.has_postkeys })\n  end\n\n  return res\nend\n\nH.clues_get_first_key = function(keys)\n  -- `keys` are assumed to be translated\n  -- Special keys\n  local special = keys:match('^(%b<>)')\n  if special ~= nil then return special end\n\n  -- <\n  if keys:find('^<') ~= nil then return '<' end\n\n  -- Other characters\n  return vim.fn.strcharpart(keys, 0, 1)\nend\n\nH.clues_get_next_key_type = function(x)\n  if x:find('^%w$') ~= nil then return 'alphanum' end\n  if x:find('^<.*>$') ~= nil then return 'mod' end\n  return 'other'\nend\n\nH.clues_compare_next_key = function(a, b)\n  local a_type, b_type = a.keytype, b.keytype\n  if a_type == b_type then\n    local cmp = vim.stricmp(a.key, b.key)\n    return cmp == -1 or (cmp == 0 and a.key < b.key)\n  end\n\n  if a_type == 'alphanum' then return true end\n  if b_type == 'alphanum' then return false end\n\n  if a_type == 'mod' then return true end\n  if b_type == 'mod' then return false end\nend\n\n-- Clue generators ------------------------------------------------------------\nH.make_clues_with_register_contents = function(mode, prefix)\n  local make_register_desc = function(register)\n    return function()\n      local ok, value = pcall(vim.fn.getreg, register, 1)\n      if not ok or value == '' then return nil end\n      return vim.inspect(value)\n    end\n  end\n\n  local all_registers = vim.split('0123456789abcdefghijklmnopqrstuvwxyz*+\"-:.%/#', '')\n\n  local res = {}\n  for _, register in ipairs(all_registers) do\n    table.insert(res, { mode = mode, keys = prefix .. register, desc = make_register_desc(register) })\n  end\n  table.insert(res, { mode = mode, keys = prefix .. '=', desc = 'Result of expression' })\n\n  return res\nend\n\n-- Predicates -----------------------------------------------------------------\nH.is_trigger = function(x)\n  return type(x) == 'table' and (type(x.mode) == 'string' or type(x.mode) == 'table') and type(x.keys) == 'string'\nend\n\nH.is_clue = function(x)\n  if type(x) ~= 'table' then return false end\n  local mandatory = (type(x.mode) == 'string' or type(x.mode) == 'table') and type(x.keys) == 'string'\n  local extra = (x.desc == nil or type(x.desc) == 'string' or vim.is_callable(x.desc))\n    and (x.postkeys == nil or type(x.postkeys) == 'string')\n  return mandatory and extra\nend\n\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not predicate(v) then return false end\n  end\n  return true\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.clue) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'miniclue://' .. buf_id .. '/' .. name) end\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.replace_termcodes = function(x)\n  if x == nil then return nil end\n  -- Use `keytrans` prior replacing termcodes to work correctly on already\n  -- replaced variant of `<F*>` keys\n  return vim.api.nvim_replace_termcodes(H.keytrans(x), true, true, true)\nend\n\nH.keytrans = function(x)\n  local res = vim.fn.keytrans(x):gsub('<NL>', '<C-J>'):gsub('<S%-NL>', '<C-S-J>'):gsub('<M%-NL>', '<C-M-J>')\n  return (res:gsub('<lt>', '<'))\nend\n\nH.get_forced_submode = function()\n  local mode = vim.fn.mode(1)\n  if not mode:sub(1, 2) == 'no' then return '' end\n  return mode:sub(3)\nend\n\nH.get_default_register = function()\n  local clipboard = vim.o.clipboard\n  if clipboard:find('unnamedplus') ~= nil then return '+' end\n  if clipboard:find('unnamed') ~= nil then return '*' end\n  return '\"'\nend\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.expand_callable = function(x, ...)\n  if vim.is_callable(x) then return x(...) end\n  return x\nend\n\nH.redraw_scheduled = vim.schedule_wrap(function() vim.cmd('redraw') end)\n\nH.getcharstr = function()\n  -- Ensure redraws still happen. This is needed to not block \"interactive\"\n  -- behavior (smooth scrolling) and not immediate submodes (scheduled DAP).\n  -- TODO: Use \"do not block redraw\" `getcharstr()` option if it ever happens\n  H.timers.getcharstr:start(0, 50, H.redraw_scheduled)\n  local ok, char = pcall(vim.fn.getcharstr)\n  H.timers.getcharstr:stop()\n  -- Terminate if couldn't get input (like with <C-c>) or it is `<Esc>`\n  if not ok or char == '\\27' or char == '' then return end\n  return H.get_langmap()[char] or char\nend\n\nH.get_langmap = function()\n  if vim.o.langmap == '' then return {} end\n\n  -- Get langmap parts by splitting at \",\" not preceded by \"\\\"\n  local langmap_parts = vim.fn.split(vim.o.langmap, '[^\\\\\\\\]\\\\zs,')\n\n  -- Process each langmap part\n  local res = {}\n  for _, part in ipairs(langmap_parts) do\n    H.process_langmap_part(res, part)\n  end\n  return res\nend\n\nH.process_langmap_part = function(res, part)\n  local semicolon_byte_ind = vim.fn.match(part, '[^\\\\\\\\]\\\\zs;') + 1\n\n  -- Part is without ';', like 'aAbB'\n  if semicolon_byte_ind == 0 then\n    -- Drop backslash escapes\n    part = part:gsub('\\\\([^\\\\])', '%1')\n\n    for i = 1, vim.fn.strchars(part), 2 do\n      -- `strcharpart()` has 0-based indexes\n      local from, to = vim.fn.strcharpart(part, i - 1, 1), vim.fn.strcharpart(part, i, 1)\n      if from ~= '' and to ~= '' then res[from] = to end\n    end\n\n    return\n  end\n\n  -- Part is with ';', like 'ab;AB'\n  -- - Drop backslash escape\n  local left = part:sub(1, semicolon_byte_ind - 1):gsub('\\\\([^\\\\])', '%1')\n  local right = part:sub(semicolon_byte_ind + 1):gsub('\\\\([^\\\\])', '%1')\n\n  for i = 1, vim.fn.strchars(left) do\n    local from, to = vim.fn.strcharpart(left, i - 1, 1), vim.fn.strcharpart(right, i - 1, 1)\n    if from ~= '' and to ~= '' then res[from] = to end\n  end\nend\n\nH.list_concat = function(...)\n  local res = {}\n  for i = 1, select('#', ...) do\n    for _, x in ipairs(select(i, ...) or {}) do\n      table.insert(res, x)\n    end\n  end\n  return res\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniClue\n"
  },
  {
    "path": "lua/mini/cmdline.lua",
    "content": "--- *mini.cmdline* Command line tweaks\n---\n--- MIT License Copyright (c) 2025 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Autocomplete with customizable delay. Enhances |cmdline-completion| and\n---   manual |'wildchar'| pressing experience.\n---   Requires Neovim>=0.11, though Neovim>=0.12 is recommended.\n---\n--- - Autocorrect words as-you-type. Only words that must come from a fixed set of\n---   candidates (like commands and options) are autocorrected by default.\n---\n--- - Autopeek command range as-you-type. Shows a floating window with range lines\n---   along with customizable context lines.\n---\n--- What it doesn't do:\n---\n--- - Customization of command line UI. Use |vim._extui| (on Neovim>=0.12).\n---\n--- - Customization of autocompletion candidates. They are computed\n---   via |cmdline-completion|.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.cmdline').setup({})` (replace `{}`\n--- with your `config` table). It will create global Lua table `MiniCmdline` which\n--- you can use for scripting or manually (with `:lua MiniCmdline.*`).\n---\n--- See |MiniCmdline.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minicmdline_config` which should have same structure as\n--- `MiniCmdline.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Suggested option values ~\n---\n--- Some options are set automatically (if not set before |MiniCmdline.setup()|):\n--- - |'wildmode'| is set to \"noselect,full\" for less intrusive autocompletion.\n---   Requires Neovim>=0.11 and enabled `config.autocomplete`.\n--- - |'wildoptions'| is set to \"pum,fuzzy\" to enable fuzzy matching.\n---\n--- # Comparisons ~\n---\n--- - [folke/noice.nvim](https://github.com/folke/noice.nvim):\n---     - Mostly focuses on visual aspects of the Command line.\n---       This modules is aimed to improve its workflow without changing UI.\n---\n--- - [nacro90/numb.nvim](https://github.com/nacro90/numb.nvim):\n---     - Designed to preview only a single line range defined by numbers.\n---       This module handles any form of |:range| and |:range-offset| for both\n---       one and two line ranges.\n---     - Shows target line directly in the normal window.\n---       This module uses a dedicated floating window.\n---\n--- - Built-in |cmdline-autocompletion| (on Neovim>=0.12):\n---     - This module on Neovim>=0.12 uses that as its base for autocompletion.\n---       Ont top of that it also provides customizable delay and predicate.\n---\n--- - Built-in |vim._extui| (on Neovim>=0.12):\n---     - Mostly focuses on visual aspects of the Command line.\n---       This modules is aimed to improve its workflow without changing UI.\n---\n--- # Highlight groups ~\n---\n--- - `MiniCmdlinePeekBorder` - border of autopeek window.\n--- - `MiniCmdlinePeekLineNr` - line numbers in autopeek window.\n--- - `MiniCmdlinePeekNormal` - basic foreground/background of autopeek window.\n--- - `MiniCmdlinePeekSep` - statuscolumn separator in autopeek window.\n--- - `MiniCmdlinePeekSign` - signs in autopeek window.\n--- - `MiniCmdlinePeekTitle` - title of autopeek window.\n---\n--- # Disabling ~\n---\n--- To disable acting in mappings, set `vim.g.minicmdline_disable` (globally) or\n--- `vim.b.minicmdline_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user.\n--- See |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniCmdline\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniCmdline = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniCmdline.config|.\n---\n---@usage >lua\n---   require('mini.cmdline').setup() -- use default config\n---   -- OR\n---   require('mini.cmdline').setup({}) -- replace {} with your config table\n--- <\nMiniCmdline.setup = function(config)\n  -- Export module\n  _G.MiniCmdline = MiniCmdline\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # General ~\n---\n--- - Each feature is configured via separate table.\n--- - Use `enable = false` to disable a feature.\n---\n---# Autocomplete ~\n---\n--- `config.autocomplete` is used to configure autocompletion: automatic show\n--- of |'wildmenu'|.\n---\n--- `autocomplete.delay` defines a (debounce style) delay after which |'wildchar'|\n--- is triggered to show wildmenu.\n--- Default: 0. Note: Neovim>=0.12 is recommended for positive values if you\n--- want to reduce flicker (thanks to |wildtrigger()|).\n---\n--- `autocomplete.predicate` defines a condition of whether to trigger completion\n--- at the current command line state. Takes a table with input data and should\n--- return `true` to show completion and `false` otherwise. Will be called before\n--- the possible delay at current command line state.\n--- Default: |MiniCmdline.default_autocomplete_predicate()|.\n---\n--- Input data fields:\n--- - <line> `(string)` - current command line text. See |getcmdline()|.\n--- - <pos> `(number)` - current command line column. See |getcmdpos()|.\n--- - <line_prev> `(string)` - command line text before the latest change.\n--- - <pos_prev> `(number)` - command line column before the latest cursor move.\n---\n--- Example of blocking completion based on completion type (as some may be slow): >lua\n---\n---   local block_compltype = { shellcmd = true }\n---   require('mini.cmdline').setup({\n---     autocomplete = {\n---       predicate = function()\n---         return not block_compltype[vim.fn.getcmdcompltype()]\n---       end,\n---     },\n---   })\n--- <\n--- Similar approach can be used to enable completion only for normal Ex commands.\n--- Use `return vim.fn.getcmdtype() == ':'` as a predicate output.\n---\n---# Autocorrect ~\n---\n--- `config.autocorrect` is used to configure autocorrection: automatic adjustment\n--- of bad words as you type them. This works only when appending single character\n--- at the end of the command line. Editing already typed words does not trigger\n--- autocorrect (allows correcting the autocorrection).\n---\n--- When to autocorrect is computed automatically based on |getcmdcomplpat()| after\n--- every key press: if it doesn't add the character to completion pattern, then\n--- the pattern before the key press is attempted to be corrected.\n--- There is also an autocorrection attempt for the last word just before\n--- executing the command.\n---\n--- Notes:\n--- - This is intended mostly for fixing typos and not as a shortcut for fuzzy\n---   matching. Performing the latter automatically is too intrusive. Explicitly\n---   use fuzzy completion for that (set up by default).\n---\n--- - Default autocorrection is done only for words that must come from a fixed\n---   set of candidates (like commands and options) by choosing the one with\n---   the lowest string distance.\n---   See |MiniCmdline.default_autocorrect_func()| for details.\n---\n--- - Word that matches some Command-line |abbreviation| is not autocorrected.\n---\n--- - If current command expects only a single argument (like |:colorscheme|), then\n---   autocorrection will happen only just before executing the command.\n---\n--- `autocorrect.func` is a function that can be used to customize autocorrection.\n--- Takes a table with input data and should return a string with the correct word\n--- or `nil` for no autocorrection. Default: |MiniCmdline.default_autocorrect_func()|.\n---\n--- Input data fields:\n--- - <word> `(string)` - word to be autocorrected. Never empty string.\n--- - <type> `(string)` - word type. Output of |getcmdcompltype()|.\n---\n---# Autopeek ~\n---\n--- `config.autopeek` is used to configure automatic peeking: show command's target\n--- range in a floating window. The window will appear above command line and show\n--- current buffer with the focus on left and right (if present and differs from\n--- left) range lines.\n---\n--- `autopeek.n_context` defines how many lines to show above and below the target.\n--- The range itself is visualized by default with the statuscolumn signs.\n--- Default: 1.\n---\n--- `autopeek.predicate` defines a condition of whether to show peek window at\n--- the current command line state. Takes a table with input data and should\n--- return `true` to peek and `false` otherwise.\n--- Will be called only if it is possible to parse range from the current command\n--- line text and it is for buffer lines (no command or |:command-addr| is `lines`)\n--- Default: |MiniCmdline.default_autopeek_predicate()|.\n---\n--- Input data fields:\n--- - <left> `(number)` - left range edge. Not necessarily smallest.\n--- - <right> `(number)` - right range edge. Same as `left` for a single line range.\n--- - <cmd> `(string)` - full command name. Can be empty string if no valid\n---   command is (yet) entered.\n---\n--- `autopeek.window` defines behavior of a peek window.\n--- `autopeek.window.config` is a table defining floating window characteristics\n--- or a callable returning such table.\n--- It should have the same structure as in |nvim_open_win()|.\n---\n--- `autopeek.window.statuscolumn` is a special function that can be used to\n--- customize |'statuscolumn'| value for the peek window. Takes a table with input\n--- data and should return a string to display for line |v:lnum|.\n--- Default: |MiniCmdline.default_autopeek_statuscolumn()|.\n--- Input data fields are the same as for `autopeek.predicate`.\n---\n--- Example of showing `<` and `>` signs on range lines: >lua\n---\n---   function(data)\n---     local n, l, r = vim.v.lnum, data.left, data.right\n---     local s = n == l and (n == r and '* ' or '< ') or n == r and '> ' or ''\n---     -- Needs explicit highlighting via `:h 'statusline'` syntax\n---     return '%#MiniCmdlinePeekSign#' .. s\n---   end\n--- <\n--- Notes:\n--- - Peek window directly shows current buffer, which means that all its\n---   extmarks, virtual text, virtual lines, etc. are also shown.\n--- - Non-zero context might work unreliably if there are virtual lines.\n--- - Peeking intentionally hides Visual selection if Command-line mode is entered\n---   directly from it. Peeking `'<,'>` range already visualizes the selection.\n---   To disable autopeek for this case, add the following code BEFORE\n---   executing `require('mini.cmdline').setup()`: >lua\n---\n---     local disable = vim.schedule_wrap(function()\n---       local is_from_visual = vim.startswith(vim.fn.getcmdline(), \"'<,'>\")\n---       MiniCmdline.config.autopeek.enable = not is_from_visual\n---     end)\n---     local reenable = function() MiniCmdline.config.autopeek.enable = true end\n---\n---     vim.api.nvim_create_autocmd('CmdlineEnter', { callback = disable })\n---     vim.api.nvim_create_autocmd('CmdlineLeave', { callback = reenable })\n--- <\nMiniCmdline.config = {\n  -- Autocompletion: show `:h 'wildmenu'` as you type\n  autocomplete = {\n    enable = true,\n\n    -- Delay (in ms) after which to trigger completion\n    -- Neovim>=0.12 is recommended for positive values\n    delay = 0,\n\n    -- Custom rule of when to trigger completion\n    predicate = nil,\n\n    -- Whether to map arrow keys for more consistent wildmenu behavior\n    map_arrows = true,\n  },\n\n  -- Autocorrection: adjust non-existing words (commands, options, etc.)\n  autocorrect = {\n    enable = true,\n\n    -- Custom autocorrection rule\n    func = nil,\n  },\n\n  -- Autopeek: show command's target range in a floating window\n  autopeek = {\n    enable = true,\n\n    -- Number of lines to show above and below range lines\n    n_context = 1,\n\n    -- Custom rule of when to show peek window\n    predicate = nil,\n\n    -- Window options\n    window = {\n      -- Floating window config\n      config = {},\n\n      -- Function to render statuscolumn\n      statuscolumn = nil,\n    },\n  },\n}\n--minidoc_afterlines_end\n\n--- Default autocompletion predicate\n---\n---@param data table Input autocompletion data. As described in |MiniCmdline.config|.\n---@param opts table|nil Options. Reserved for future use.\n---\n---@return boolean If command line does not (yet) contain a letter - `false`,\n---   otherwise - `true`. This makes autopeek easier to use for a numerical range.\nMiniCmdline.default_autocomplete_predicate = function(data, opts) return data.line:find('%a') ~= nil end\n\n--- Default autocorrection function\n---\n--- - Return input word if `opts.strict_type=true` and input `type` is not proper.\n--- - Get candidates via `opts.get_candidates()`.\n---   Default: mostly via |getcompletion()| with empty pattern and input `type`.\n---   Exceptions are `help` and `option` types: both list all available candidates\n---   in their own ways.\n--- - Choose the candidate with the lowest Damerau–Levenshtein distance\n---   (smallest number of deletion/insertion/substitution/transposition needed\n---   to transform one word into another; slightly prefers transposition).\n---   Notes:\n---     - Type `'command'` also chooses from all valid candidate abbreviations.\n---     - Comparison is done both respecting and ignoring case.\n---\n---@param data table Input autocorrection data. As described in |MiniCmdline.config|.\n---@param opts table|nil Options. Possible fields:\n---   - <strict_type> `(boolean)` - whether to restrict output only for types which\n---     must have words from a fixed set of candidates (like command or option\n---     names). Note: does not include `help` type since |:help| already has\n---     \"sophisticated algorithm\" to handle typos. Default: `true`.\n---   - <get_candidates> `(function)` - source of candidates. Will be called\n---     with `data` as argument and should return array of string candidates to\n---     choose from.\n---     Default: for most types -  |getcompletion()| with empty pattern and\n---     input `type`; for `help` and `option` type - all available help tags and\n---     option names (long and short) respectively.\n---\n---@return string Autocorrected word.\nMiniCmdline.default_autocorrect_func = function(data, opts)\n  H.check_type('data', data, 'table')\n  H.check_type('data.word', data.word, 'string')\n  H.check_type('data.type', data.type, 'string')\n\n  opts = opts or {}\n  local strict_type = opts.strict_type == nil or opts.strict_type\n  if strict_type and not H.autocorrect_strict_types[data.type] then return data.word end\n\n  -- Get all valid words\n  local all = vim.is_callable(opts.get_candidates) and opts.get_candidates(data) or H.get_autocorrect_candidates(data)\n  if vim.tbl_contains(all, data.word) or data.word == '' then return data.word end\n\n  -- Make results stable in case several candidates have the same distance\n  table.sort(all)\n\n  -- Handle commands separately: need dedicated abbreviation length\n  -- computation and to allow `!`\n  if data.type == 'command' then return H.get_nearest_command(data.word, all) end\n\n  -- Fall back to computing nearest string without allowing abbreviations\n  local abbr_lens = vim.tbl_map(string.len, all)\n  return H.get_nearest_abbr(data.word, all, abbr_lens)\nend\n\n--- Default autopeek predicate\n---\n---@param data table Input autopeek data. As described in |MiniCmdline.config|.\n---@param opts table|nil Options. Reserved for future use.\n---\n---@return boolean If command defines |:command-preview| - `false`, otherwise - `true`.\n---   This makes autopeek easier to use for commands like |:substitute|,\n---   especially if |'inccommand'| is set to `split`.\nMiniCmdline.default_autopeek_predicate = function(data, opts)\n  local cmd_preview_map = H.cache.cmd_preview_map or H.get_cmd_preview_map()\n  return cmd_preview_map[data.cmd] ~= true\nend\n\n--- Default autopeek statuscolumn\n---\n--- - Show signs next to lines depending on their relation to peeked range.\n---   Highlighted with `MiniCmdlinePeekSign` group.\n--- - Show line numbers for left and right parts of the range.\n---   Highlighted with `MiniCmdlinePeekLineNr` group.\n--- - Separate statuscolumn and buffer text with dedicated separator character.\n---   Highlighted with `MiniCmdlinePeekSep` group.\n---\n--- Notes:\n--- - Intended to only be used as a part of |'statuscolumn'| function, as it\n---   uses |v:lnum| and |v:virtnum| to compute the output.\n---\n--- Example of adjusting a `mid` sign: >lua\n---\n---   local peek_stc_opts = { signs = { mid = '+' } }\n---   local peek_stc = function(data)\n---     return MiniCmdline.default_autopeek_statuscolumn(data, peek_stc_opts)\n---   end\n---   require('mini.cmdline').setup({\n---     autopeek = { window = { statuscolumn = peek_stc } },\n---   })\n--- <\n---@param data table Input peek data. As described in |MiniCmdline.config|.\n---@param opts table|nil Options. Possible fields:\n---   - <signs> `(table)` - signs to show. Possible fields:\n---       - <same> `(string)` - on range if `left=right`. Default: `'🭬'`.\n---       - <left> `(string)`  - on `left` line.  Default: `'┌'`.\n---       - <mid> `(string)`   - inside range.  Default: `'┊'`.\n---       - <right> `(string)` - on `right` line. Default: `'└'`.\n---       - <out> `(string)` - outside of range. Default: `''` (no sign).\n---       - <virt> `(string)` - virtual line. Default: `'•'`.\n---       - <wrap> `(string)` - wrapped line. Default: `'↳'`.\n---   - <sep> `(string)` - string to put at the end to separate statuscolumn and\n---     buffer text. Default: `'│'`\n---\n---   Note: Any sign and separator should have every `%` escaped as `%%` (due to its\n---   special meaning in |'statuscolumn'|).\nMiniCmdline.default_autopeek_statuscolumn = function(data, opts)\n  opts = opts or {}\n  local signs = opts.signs or {}\n  local sep_format = opts.sep == nil and '│' or opts.sep:gsub('%%', '%%%%')\n\n  if vim.v.virtnum ~= 0 then\n    local sign = (vim.v.virtnum < 0 and (signs.virt or '•') or (signs.wrap or '↳'))\n    -- Format as `sign %= sep-hl sep`\n    return sign .. '%=%#MiniCmdlinePeekSep#' .. sep_format:gsub('%%%%', '%%')\n  end\n\n  local n, l, r = vim.v.lnum, data.left, data.right\n  -- Format as `sign-hl sign linenr-hl %= linenr sep-hl sep`\n  local fmt = '%%#MiniCmdlinePeekSign#%s%%#MiniCmdlinePeekLineNr#%%=%s%%#MiniCmdlinePeekSep#' .. sep_format\n  if n == l and n == r then return string.format(fmt, signs.same or '🭬', n) end\n  if n == l then return string.format(fmt, signs.left or '┌', n) end\n  if n == r then return string.format(fmt, signs.right or '└', n) end\n  if (l < n and n < r) or (r < n and n < l) then return string.format(fmt, signs.mid or '┊', '') end\n  return string.format(fmt, signs.out or '', '')\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniCmdline.config)\n\n-- Timers\nH.timers = {\n  autocomplete = vim.loop.new_timer(),\n}\n\n-- Autocomplete requires `noselect` flag of 'wildmode'. Present in Neovim>=0.11\nH.can_autocomplete = vim.fn.has('nvim-0.11') == 1\n\n-- Autocorrect types for which words *must* be from some fixed set\n-- Basically a subset of `:h :command-complete` which might lead to an error if\n-- word is not from a fixed set. Can be adjusted for more nuances.\n-- Reasons for not including a type:\n-- - The main reason is because type's usage can be done in context when\n--   creating a new object. Like `:edit new-file` for `file` type.\n-- - No `help` because there already is an autocorrection with a \"sophisticated\n--   algorithm to decide which match is better than another one\".\n-- - No `buffer` because completion candidates only include names for listed\n--   buffers. So ids of listed buffers and name+ids of unlisted buffers are\n--   missing. Also, partial buffer name is enough for `:buffer`, which would\n--   be too cumbersome to account for.\n--stylua: ignore\nH.autocorrect_strict_types = {\n  arglist       = true, -- file names in argument list\n  -- augroup       = true, -- autocmd groups\n  -- breakpoint    = true, -- |:breakadd| suboptions\n  -- buffer        = true, -- buffer names\n  color         = true, -- color schemes\n  command       = true, -- Ex command (and arguments)\n  compiler      = true, -- compilers\n  diff_buffer   = true, -- diff buffer names\n  -- dir           = true, -- directory names\n  -- dir_in_path   = true, -- directory names in |'cdpath'|\n  -- environment   = true, -- environment variable names\n  event         = true, -- autocommand events\n  -- expression    = true, -- Vim expression\n  -- file          = true, -- file and directory names\n  -- file_in_path  = true, -- file and directory names in |'path'|\n  filetype      = true, -- filetype names |'filetype'|\n  -- ['function']  = true, -- function name\n  -- help          = true, -- help subjects\n  -- highlight     = true, -- highlight groups\n  history       = true, -- |:history| suboptions\n  keymap        = true, -- keyboard mappings\n  locale        = true, -- locale names (as output of locale -a)\n  -- lua           = true, -- Lua expression |:lua|\n  mapclear      = true, -- buffer argument\n  -- mapping       = true, -- mapping name\n  -- menu          = true, -- menus\n  messages      = true, -- |:messages| suboptions\n  option        = true, -- options\n  packadd       = true, -- optional package |pack-add| names\n  -- runtime       = true, -- file and directory names in |'runtimepath'|\n  -- scriptnames   = true, -- sourced script names\n  -- shellcmd      = true, -- Shell command\n  -- shellcmdline  = true, -- First is a shell command and subsequent ones are filenames\n  sign          = true, -- |:sign| suboptions\n  syntax        = true, -- syntax file names |'syntax'|\n  syntime       = true, -- |:syntime| suboptions\n  -- tag           = true, -- tags\n  -- tag_listfiles = true, -- tags, file names are shown when CTRL-D is hit\n  -- user          = true, -- user names\n  -- var           = true, -- user variables\n}\n\n-- Various cache to use during command line edit\nH.cache = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('autocomplete', config.autocomplete, 'table')\n  H.check_type('autocomplete.enable', config.autocomplete.enable, 'boolean')\n  H.check_type('autocomplete.delay', config.autocomplete.delay, 'number')\n  H.check_type('autocomplete.predicate', config.autocomplete.predicate, 'function', true)\n  H.check_type('autocomplete.map_arrows', config.autocomplete.map_arrows, 'boolean')\n\n  H.check_type('autocorrect', config.autocorrect, 'table')\n  H.check_type('autocorrect.enable', config.autocorrect.enable, 'boolean')\n  H.check_type('autocorrect.func', config.autocorrect.func, 'function', true)\n\n  H.check_type('autopeek', config.autopeek, 'table')\n  H.check_type('autopeek.enable', config.autopeek.enable, 'boolean')\n  H.check_type('autopeek.n_context', config.autopeek.n_context, 'number')\n  H.check_type('autopeek.predicate', config.autopeek.predicate, 'callable', true)\n  H.check_type('autopeek.window', config.autopeek.window, 'table')\n  local autopeek_win_config = config.autopeek.window.config\n  if not (type(autopeek_win_config) == 'table' or vim.is_callable(autopeek_win_config)) then\n    H.error('`autopeek.window.config` should be table or callable, not ' .. type(autopeek_win_config))\n  end\n  H.check_type('autopeek.window.statuscolumn', config.autopeek.window.statuscolumn, 'callable', true)\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniCmdline.config = config\n\n  -- Try setting suggested option values\n  -- NOTE: This makes it more like 'mini.completion' (with 'noselect')\n  local was_set = vim.api.nvim_get_option_info2('wildmode', { scope = 'global' }).was_set\n  if not was_set and config.autocomplete.enable and H.can_autocomplete then vim.o.wildmode = 'noselect,full' end\n\n  was_set = vim.api.nvim_get_option_info2('wildoptions', { scope = 'global' }).was_set\n  if not was_set then vim.o.wildoptions = 'pum,fuzzy' end\n\n  -- Set useful mappings\n  if config.autocomplete.map_arrows then\n    local map_arrow = function(dir, wildmenu_prefix, desc)\n      local rhs = function() return (vim.fn.wildmenumode() == 1 and wildmenu_prefix or '') .. dir end\n      vim.keymap.set('c', dir, rhs, { expr = true, desc = desc })\n    end\n    map_arrow('<Left>', '<Space><BS>', 'Move cursor left')\n    map_arrow('<Right>', '<Space><BS>', 'Move cursor right')\n    -- NOTE: All tests seem to pass without these mappings. But it is mentioned\n    -- in `:h cmdline-autocompletion`, so probably worth adding\n    map_arrow('<Up>', '<C-e>', 'Go to earlier history')\n    map_arrow('<Down>', '<C-e>', 'Go to newer history')\n  end\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniCmdline', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  -- Act on command line events. Notes:\n  -- - Schedule for 'CmdlineEnter' to not act on mappings like `:...`\n  --   (like `:<C-u>...` popular for Visual mode).\n  -- - Schedule for 'CmdlineChanged' to work around autcompletion issues with\n  --   mocking wildchar.\n  -- - Do not schedule 'CmdlineLeave' to be able to set command text before\n  --   executing it.\n  au('CmdlineEnter', '*', vim.schedule_wrap(H.on_cmdline_enter), 'Act on command line enter')\n  au('CmdlineChanged', '*', vim.schedule_wrap(H.on_cmdline_changed), 'Act on command line change')\n  au('CmdlineLeave', '*', H.on_cmdline_leave, 'Act on command line leave')\n\n  au('VimResized', '*', function() H.autopeek(true) end, 'Adjust peek window')\n  au('CmdwinEnter', '*', function() H.peek_hide() end, 'Hide peek window')\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  hi('MiniCmdlinePeekBorder', { link = 'FloatBorder' })\n  hi('MiniCmdlinePeekLineNr', { link = 'DiagnosticSignWarn' })\n  hi('MiniCmdlinePeekNormal', { link = 'NormalFloat' })\n  hi('MiniCmdlinePeekSep', { link = 'SignColumn' })\n  hi('MiniCmdlinePeekSign', { link = 'DiagnosticSignHint' })\n  hi('MiniCmdlinePeekTitle', { link = 'FloatTitle' })\nend\n\nH.is_disabled = function() return vim.g.minicmdline_disable == true or vim.b.minicmdline_disable == true end\n\nH.get_config = function() return vim.tbl_deep_extend('force', MiniCmdline.config, vim.b.minicmdline_config or {}) end\n\n-- Autocommands ---------------------------------------------------------------\nH.on_cmdline_enter = function()\n  -- Check for Command-line mode to not act on `:...` mappings\n  if H.is_disabled() or vim.fn.mode() ~= 'c' then return end\n\n  -- Act only on \"not nested\" command line (for simplicity). It can nest after\n  -- `c_CTRL-R_=`, since there are CmdlineEnter-CmdlineChanged-CmdlineLeave for\n  -- it without explicit leave-enter for the initial normal Ex command mode.\n  -- There doesn't seem to be a way to have `n_nested > 1`, but use counter of\n  -- nested levels instead of a boolean `is_nested` just in case.\n  if H.cache.state ~= nil then\n    H.cache.n_nested = (H.cache.n_nested or 0) + 1\n    return\n  end\n\n  H.cache = {\n    buf_id = vim.api.nvim_get_current_buf(),\n    cmd_preview_map = H.get_cmd_preview_map(),\n    cmd_type = vim.fn.getcmdtype(),\n    config = H.get_config(),\n    peek = {},\n    state = H.get_cmd_state(),\n    state_prev = H.get_cmd_state(true),\n  }\n  H.cache.autocomplete_predicate = H.cache.config.autocomplete.predicate or MiniCmdline.default_autocomplete_predicate\n  H.cache.buf_is_cmdwin = vim.fn.getbufinfo(H.cache.buf_id)[1].command == 1\n\n  H.cache.autopeek_predicate = H.cache.config.autopeek.predicate or MiniCmdline.default_autopeek_predicate\n  MiniCmdline._peek_statuscolumn = H.make_peek_statuscolumn()\n  if H.cache.config.autopeek.enable then H.autopeek() end\nend\n\nH.on_cmdline_changed = function()\n  if H.cache.state == nil or H.cache.n_nested ~= nil then return end\n\n  -- Act only on actual line change\n  local state = H.get_cmd_state()\n  if state.line == H.cache.state.line then return end\n\n  -- Update state accounting for some edge cases\n  if H.cache.state_prev.compltype == 'option' then H.adjust_option_cmd_state(state) end\n  H.cache.state_prev, H.cache.state = H.cache.state, state\n\n  local config = H.cache.config\n  if config.autocomplete.enable and H.can_autocomplete then H.autocomplete() end\n  if config.autocorrect.enable then H.autocorrect(false) end\n  if config.autopeek.enable then H.autopeek() end\nend\n\nH.on_cmdline_leave = function()\n  if H.cache.state == nil then return end\n  if H.cache.n_nested ~= nil then\n    H.cache.n_nested = H.cache.n_nested > 1 and (H.cache.n_nested - 1) or nil\n    return\n  end\n\n  if H.cache.config.autocorrect.enable and not vim.v.event.abort then H.autocorrect(true) end\n  H.peek_hide()\n  H.cache = {}\n  MiniCmdline._peek_statuscolumn = nil\nend\n\nH.get_cmd_state = function(is_init)\n  local compltype = vim.fn.getcmdcompltype()\n  if is_init then return { complpat = '', compltype = compltype, line = '', pos = 1, cmd = {} } end\n  return { complpat = H.getcmdcomplpat(), compltype = compltype, line = vim.fn.getcmdline(), pos = vim.fn.getcmdpos() }\nend\n\nH.adjust_option_cmd_state = function(state)\n  -- Cases like `set nowrap invmagic` are completed specially. After `no`/`inv`\n  -- there is a specialized completion only for boolean options. In practice it\n  -- results into `compltype=''` and `complpat=<text after no/inv>`.\n  -- This interferes with how autocorrection is detected, as it relies on whole\n  -- `nowrap` / `invmagic` to be a single complpat *with compltype=option*.\n  --\n  -- The solution is to detect cases \"it was compltype=option but now it isn't\"\n  -- and try to expand complpat to match the whole word on cursor's left.\n  if state.compltype == 'option' then return end\n  state.complpat = state.line:sub(1, state.pos - 1):match(' (%w+)$') or ''\n  state.compltype = state.complpat ~= '' and 'option' or state.compltype\nend\n\n-- Autocomplete ---------------------------------------------------------------\nH.autocomplete = function()\n  H.timers.autocomplete:stop()\n\n  -- Do not complete if predicate says so\n  local state, state_prev = H.cache.state, H.cache.state_prev\n  local data = { line = state.line, pos = state.pos, line_prev = state_prev.line, pos_prev = state_prev.pos }\n  if not H.cache.autocomplete_predicate(data) then return H.hide_wild() end\n\n  -- Do nothing in some problematic cases (when wildmenu does not work)\n  -- TODO: Remove after compatibility with Neovim=0.11 is dropped\n  if H.block_autocomplete() then return end\n\n  local delay = H.cache.config.autocomplete.delay\n  if delay == 0 then return H.trigger_complete() end\n  H.timers.autocomplete:start(delay, 0, H.trigger_complete_scheduled)\nend\n\nH.block_autocomplete = function() return false end\nif vim.fn.has('nvim-0.12') == 0 then\n  H.block_autocomplete = function()\n    -- Block for non-interactive command type\n    if H.cache.cmd_type ~= ':' then return true end\n\n    -- Block for cases when there is no completion candidates. This affects\n    -- performance (completion candidates are computed twice), but it is\n    -- the most robust way of dealing with problematic situations:\n    -- - Some commands don't have completion defined: `:s`, `:g`, etc.\n    -- - Some cases result in verbatim `^I` inserted. Like after bang (`:q!`).\n    --\n    -- The `vim.fn.getcmdcompltype() == ''` condition is too wide as it denies\n    -- legitimate cases of when there are available completion candidates.\n    -- Like in user commands created with `vim.api.nvim_create_user_command()`.\n    local line_before_pos = H.cache.state.line:sub(1, H.cache.state.pos - 1)\n    -- `getcompletion` may result in error, like after `:ltag `\n    local ok, candidates = pcall(vim.fn.getcompletion, line_before_pos, 'cmdline')\n    return not (ok and #candidates > 0)\n  end\nend\n\nH.trigger_complete = function()\n  if vim.fn.mode() ~= 'c' then return end\n  H.trigger_wild()\nend\n\nH.trigger_complete_scheduled = vim.schedule_wrap(H.trigger_complete)\n\nH.trigger_wild = function() vim.fn.wildtrigger() end\nif vim.fn.has('nvim-0.12') == 0 then\n  H.trigger_wild = function()\n    -- Not triggerring when wildmenu is shown helps avoiding trigger after\n    -- manually pressing wildchar (as text is also changes).\n    if vim.fn.wildmenumode() == 1 then return end\n    -- Type `<C-z>` which is \"Trigger 'wildmode', but always available.\"\n    vim.api.nvim_feedkeys('\\26', 'nt', false)\n  end\nend\n\nH.hide_wild = function()\n  -- Ensure that there is no outdated pmenu after `wildtrigger()`\n  vim.cmd('redraw')\n\n  -- This works, but it triggers wildmenu, which is not usable when the point\n  -- is to hide pmenu if `autocomplete.predicate()` returned `false` ()\n  -- local keys = (vim.fn.wildmenumode() == 0 and '\\26' or '') .. '\\5'\n  -- vim.api.nvim_feedkeys(keys, 'nt', false)\nend\nif vim.fn.has('nvim-0.12') == 0 then H.hide_wild = function() end end\n\n-- Autocorrect ----------------------------------------------------------------\nH.autocorrect = function(is_final)\n  -- Act only for normal Ex commands after a word is just finished typing\n  if not (H.cache.cmd_type == ':' and H.cache.state.line:find('%S') ~= nil) then return end\n\n  local state, state_prev = H.cache.state, H.cache.state_prev\n  local line, line_prev = state.line, state_prev.line\n  local pos, pos_prev = state.pos, state_prev.pos\n\n  -- Act only when a char is appended. It makes tweaking autocorrected text\n  -- easier by going back and editing it. This is also easier to implement.\n  local is_at_end, was_at_end = (pos - 1) == line:len(), (pos_prev - 1) == line_prev:len()\n  local new = line:sub(pos_prev)\n  local is_char_append = is_at_end and was_at_end and line == (line_prev .. new) and vim.fn.strchars(new) <= 1\n  local is_word_finished = not vim.startswith(state.complpat, state_prev.complpat)\n\n  if not (is_char_append and (is_word_finished or is_final)) then return end\n\n  -- Compute autocorrection\n  local state_to_use = is_final and state or state_prev\n  local word = state_to_use.complpat\n  if word == '' or vim.fn.maparg(word, 'c', true) ~= '' then return end\n\n  local func = H.cache.config.autocorrect.func or MiniCmdline.default_autocorrect_func\n  local new_word = func({ word = word, type = state_to_use.compltype }) or word\n\n  if word == new_word then return end\n  if type(new_word) ~= 'string' then return H.notify('Can not autocorrect for ' .. vim.inspect(word), 'WARN') end\n\n  -- Set corrected word\n  local init_pos = state_to_use.pos\n  local new_line = line:sub(1, init_pos - word:len() - 1) .. new_word .. line:sub(init_pos)\n  -- - Use `noautocmd` to not conflict with `autocomplete` on `CmdlineChanged`\n  local cmd = string.format('call setcmdline(%s, %s)', vim.inspect(new_line), new_line:len() + 1)\n  vim.cmd('noautocmd ' .. cmd)\nend\n\nH.get_autocorrect_candidates = function(data)\n  if data.type == 'help' then\n    local help_buf = vim.api.nvim_create_buf(false, true)\n    vim.bo[help_buf].buftype = 'help'\n    -- - NOTE: no dedicated buffer name because it is immediately wiped out\n    local tags = vim.api.nvim_buf_call(help_buf, function() return vim.fn.taglist('.*') end)\n    vim.api.nvim_buf_delete(help_buf, { force = true })\n    return vim.tbl_map(function(x) return x.name end, tags)\n  end\n\n  if data.type == 'option' then\n    local all = {}\n    for name, info in pairs(vim.api.nvim_get_all_options_info()) do\n      table.insert(all, name)\n\n      local is_bool = info.type == 'boolean'\n      table.insert(all, is_bool and ('no' .. name) or nil)\n      table.insert(all, is_bool and ('inv' .. name) or nil)\n\n      local has_shortname = info.shortname ~= ''\n      table.insert(all, has_shortname and info.shortname or nil)\n      table.insert(all, (has_shortname and is_bool) and ('no' .. info.shortname) or nil)\n      table.insert(all, (has_shortname and is_bool) and ('inv' .. info.shortname) or nil)\n    end\n    return all\n  end\n\n  local ok, all = pcall(vim.fn.getcompletion, '', data.type)\n  return ok and all or { data.word }\nend\n\nH.get_nearest_command = function(ref, all)\n  -- Do not alter `:=` command, as it is a special Lua shorthand command\n  if ref:sub(1, 1) == '=' then return ref end\n\n  -- Allow trailing special punctuation (specific to commands)\n  local word, suffix = ref:match('^(.+)([!|]?)$')\n\n  -- Account for the fact that commands can be abbreviated (`:h |20.2|`):\n  local cmd_abbr_lens, usr_cmds, usr_max_len = {}, {}, 0\n  for _, cmd in ipairs(all) do\n    -- User command abbreviation needs to uniquely identify command name\n    if cmd:find('^[A-Z]') ~= nil then\n      usr_cmds[cmd] = true\n      usr_max_len = math.max(usr_max_len, cmd:len())\n    else\n      -- ANY abbreviation of ANY built-in command is a valid command (may be\n      -- different; `wincmd`->`w`==`write`). Its an internal optimization.\n      -- EXCEPT: `:def` abbreviation of `:defer` is not allowed.\n      cmd_abbr_lens[cmd] = cmd == 'defer' and 4 or 1\n    end\n  end\n\n  -- Slice user commands with increasing abbreviation length to find which\n  -- ones can be uniquely identified by it\n  for cur_abbr_len = 1, usr_max_len do\n    local cur_abbrs = {}\n    for cmd, _ in pairs(usr_cmds) do\n      local abbr = cmd:sub(1, cur_abbr_len)\n      cur_abbrs[abbr] = cur_abbrs[abbr] or {}\n      table.insert(cur_abbrs[abbr], cmd)\n    end\n\n    for _, cmd_arr in pairs(cur_abbrs) do\n      if #cmd_arr == 1 then\n        local cmd = cmd_arr[1]\n        cmd_abbr_lens[cmd] = math.min(cur_abbr_len, cmd:len())\n        usr_cmds[cmd] = nil\n      end\n    end\n  end\n\n  local abbr_lens = vim.tbl_map(function(x) return cmd_abbr_lens[x] end, all)\n  return H.get_nearest_abbr(word, all, abbr_lens) .. suffix\nend\n\nH.get_nearest_abbr = function(word, candidates, abbr_lens)\n  local tolower = vim.fn.tolower\n  local word_split = vim.split(word, '')\n  local word_split_l = vim.split(tolower(word), '')\n\n  -- Prefer closest string respecting case first, then try ignorecase\n  local res, res_dist = nil, math.huge\n  for i, cand in ipairs(candidates) do\n    local min_abbr_len = abbr_lens[i]\n    local d, abbr_len = H.string_abbr_dist(word_split, vim.split(cand, ''), min_abbr_len)\n    if d < res_dist then\n      res, res_dist = cand:sub(1, abbr_len), d\n    end\n  end\n  for i, cand in ipairs(candidates) do\n    local min_abbr_len = abbr_lens[i]\n    local cand_word_l = tolower(cand)\n    local d_l, abbr_len_l = H.string_abbr_dist(word_split_l, vim.split(cand_word_l, ''), min_abbr_len)\n    if d_l < res_dist then\n      res, res_dist = cand:sub(1, abbr_len_l), d_l\n    end\n  end\n\n  return res\nend\n\nH.string_abbr_dist = function(ref, cand, min_abbr_len)\n  -- Source: https://en.wikipedia.org/wiki/Damerau-Levenshtein_distance\n  -- d[i][j] - distance between `ref[1:i]` and `cand[1:j]` abbreviations\n  local d = {}\n  for i = 0, #ref do\n    d[i] = { [0] = i }\n  end\n  for j = 0, #cand do\n    d[0][j] = j\n  end\n  for i = 1, #ref do\n    for j = 1, #cand do\n      local cost = ref[i] == cand[j] and 0 or 1\n      -- Account for deletion, insertion, substitution\n      d[i][j] = math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost)\n      -- Account for transposition. Slightly favor them over others, as it is\n      -- a common source for autocorrection\n      if i > 1 and j > 1 and ref[i] == cand[j - 1] and ref[i - 1] == cand[j] then\n        d[i][j] = math.min(d[i][j], d[i - 2][j - 2] + 0.99 * cost)\n      end\n    end\n  end\n\n  -- Find the candidate abbreviation with the smallest distance\n  local abbr_d = d[#ref]\n  local dist, abbr_len = math.huge, nil\n  for j = min_abbr_len, #cand do\n    if abbr_d[j] < dist then\n      dist, abbr_len = abbr_d[j], j\n    end\n  end\n\n  return dist, abbr_len\nend\n\n-- Autopeek -------------------------------------------------------------------\nH.autopeek = function(force)\n  -- Decide if peek needs to be shown or hidden\n  if not (H.cache.cmd_type == ':' and not H.cache.buf_is_cmdwin) then return end\n\n  local line = H.cache.state.line\n  if line:find('%S') == nil then H.peek_hide() end\n\n  local parsed = H.parse_cmd(line)\n  local range, cmd = parsed.range, parsed.cmd\n  if range[1] == nil and range[2] == nil then return H.peek_hide() end\n\n  -- Normalize range lines\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  local left = H.clamp(range[1] or range[2], 1, n_lines)\n  local right = H.clamp(range[2] or range[1], 1, n_lines)\n  local from = right < left and right or left\n  local to = right < left and left or right\n  local data = { left = left, right = right, cmd = parsed.cmd }\n\n  -- Do not peek if predicate says so\n  if not H.cache.autopeek_predicate(data) then return H.peek_hide() end\n\n  -- Force peek update if command line height has changed when typing\n  local cmdheight = math.ceil((vim.fn.strdisplaywidth(line) + 1) / vim.o.columns)\n  cmdheight = math.max(cmdheight, vim.o.cmdheight)\n  force = force or cmdheight ~= H.cache.peek.cmdheight\n\n  -- Skip peek update if command line state is the same (for performance)\n  local cur_data = H.cache.peek.data or {}\n  local is_data_same = left == cur_data.left and right == cur_data.right and cmd == cur_data.cmd\n  if not force and is_data_same then return end\n\n  H.cache.peek.cmdheight = cmdheight\n  H.cache.peek.data = data\n  H.cache.peek.win_id = H.peek_show(from, to)\nend\n\nH.peek_show = function(from, to)\n  -- Compute height to show union of left and right contexts plus possible fold\n  local n_context = math.max(H.cache.config.autopeek.n_context, 0)\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  local cont_from = H.peek_new_context(from, n_context, n_lines)\n  local cont_to = H.peek_new_context(to, n_context, n_lines)\n  local height = H.peek_get_height(cont_from, cont_to)\n\n  -- Ensure opened window of enough height.\n  -- NOTE: This uses current buffer directly, which means that all its extmarks\n  -- are shown. This is both good (for extra text highlighting) and bad\n  -- (virtual lines and text) thing. Ideally, extmark \"owners\" should take care\n  -- of where they should be shown. Usually setting something like \"only show\n  -- inside this particular window\" makes sense. Like in 'mini.diff' and\n  -- 'mini.indentscope'. This is currently not (robustly) possible. Sources:\n  -- - https://github.com/neovim/neovim/issues/19654\n  -- - https://github.com/neovim/neovim/pull/27361\n  -- - https://github.com/neovim/neovim/pull/28432\n  -- - https://github.com/neovim/neovim/pull/28728\n  local config = H.peek_get_config(height)\n  local win_id = H.cache.peek.win_id\n  win_id = H.is_valid_win(win_id) and win_id or vim.api.nvim_open_win(0, false, config)\n  vim.api.nvim_win_set_config(win_id, config)\n\n  -- Ensure context fits the window (it may be not enough height to fit whole)\n  if config.height < height then H.peek_adjust_context(cont_from, cont_to, height, config.height) end\n\n  -- Finalize window view\n  vim.api.nvim_win_call(win_id, function()\n    -- Define window-local options\n    vim.cmd(\"setlocal foldenable foldlevel=0 foldmethod=manual foldminlines=1 foldtext=''\")\n    vim.cmd('setlocal foldcolumn=0 nocursorline nonumber scrolloff=0 signcolumn=no nowrap')\n    vim.wo.list = vim.go.list\n    vim.wo.listchars = vim.go.listchars\n    vim.wo.statuscolumn = '%{%v:lua.MiniCmdline._peek_statuscolumn()%}'\n    vim.wo.winhighlight = 'NormalFloat:MiniCmdlinePeekNormal'\n      .. ',FloatBorder:MiniCmdlinePeekBorder'\n      .. ',FloatTitle:MiniCmdlinePeekTitle'\n\n    -- Display range lines with context, fold the excess, ensure at least one\n    -- range end is shown (might be not the case if there are virtual lines).\n    vim.api.nvim_win_set_cursor(0, { cont_from.before, 0 })\n    vim.cmd('normal! zEzt')\n    vim.api.nvim_win_set_cursor(0, { cont_from.at, 0 })\n    local from_after, to_before = cont_from.after, cont_to.before\n    if to_before - from_after > 1 then vim.cmd(string.format('%s,%sfold', from_after + 1, to_before - 1)) end\n  end)\n\n  -- NOTE: Need explicit redraw because otherwise window is not shown\n  vim.cmd('redraw')\n  return win_id\nend\n\nH.peek_new_context = function(at, n_context, n_lines)\n  return { before = H.clamp(at - n_context, 1, n_lines), at = at, after = H.clamp(at + n_context, 1, n_lines) }\nend\n\nH.peek_get_height = function(cont_from, cont_to)\n  -- L(a or b) = L(a) + L(b) - L(a and b). Also adjust for fold.\n  local n_from = cont_from.after - cont_from.before + 1\n  local n_to = cont_to.after - cont_to.before + 1\n  local n_both = math.max(cont_from.after - cont_to.before + 1, 0)\n  local n_fold = (cont_to.before - cont_from.after > 1) and 1 or 0\n  return (n_from + n_to - n_both) + n_fold\nend\n\nH.peek_get_config = function(height)\n  local cmdheight = H.cache.peek.cmdheight\n\n  local default_config = { relative = 'editor', style = 'minimal', zindex = 199 }\n  default_config.anchor = 'SE'\n  default_config.row = math.max(vim.o.lines - cmdheight, 1)\n  default_config.col = 1\n  default_config.width = vim.o.columns\n  default_config.height = height\n\n  default_config.border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil\n  default_config.title = ' Peek '\n  default_config.focusable = false\n\n  local win_config = H.cache.config.autopeek.window.config\n  if vim.is_callable(win_config) then win_config = win_config() end\n  local config = vim.tbl_deep_extend('force', default_config, win_config or {})\n\n  -- Tweak config values to ensure they are proper, accounting for border\n  local offset = config.border == 'none' and 0 or 2\n  config.height = math.max(math.min(config.height, vim.o.lines - cmdheight - offset), 1)\n  config.width = math.min(config.width, vim.o.columns - offset)\n\n  if type(config.title) == 'string' then config.title = H.fit_to_width(config.title, config.width) end\n\n  return config\nend\n\nH.peek_adjust_context = function(cont_from, cont_to, height, target_height)\n  local extra = height - target_height\n\n  -- First truncate outer context (keeping top and bottom equal)\n  -- NOTE: Reduce in a cycle and not via a formula since outer context can be\n  -- shorter if its range line is close to file border\n  while extra > 0 do\n    local n_from_out, n_to_out = cont_from.at - cont_from.before, cont_to.after - cont_to.at\n    if n_from_out <= 0 and n_to_out <= 0 then break end\n\n    local is_reduce_from = n_from_out > n_to_out\n    cont_from.before = cont_from.before + (is_reduce_from and 1 or 0)\n    cont_to.after = cont_to.after - (is_reduce_from and 0 or 1)\n    extra = extra - 1\n  end\n  if extra <= 0 then return end\n\n  -- Hide excess inner context under the fold\n  -- NOTE: Reduce height by 3 to make space for `from`, `to`, and fold\n  local inner_context_lines = math.max(target_height - 3, 0)\n  local half_height = math.floor(0.5 * inner_context_lines)\n  cont_from.after = cont_from.at + half_height\n  cont_to.before = cont_to.at - (inner_context_lines - half_height)\nend\n\nH.peek_hide = function()\n  local info = H.cache.peek or {}\n  H.win_close_safely(info.win_id)\n  H.cache.peek = {}\nend\n\nH.make_peek_statuscolumn = function()\n  local statuscolumn = H.cache.config.autopeek.window.statuscolumn or MiniCmdline.default_autopeek_statuscolumn\n  return function() return statuscolumn(H.cache.peek.data) or '' end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.cmdline) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.notify = function(msg, level_name, silent)\n  if not silent then vim.notify('(mini.cmdline) ' .. msg, vim.log.levels[level_name]) end\nend\n\nH.clamp = function(x, from, to) return math.min(math.max(x, from), to) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.win_close_safely = function(win_id)\n  if H.is_valid_win(win_id) then vim.api.nvim_win_close(win_id, true) end\nend\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.get_cmd_preview_map = function()\n  local res = { substitute = true, smagic = true, snomagic = true }\n  -- NOTE: Check `name` type as on Neovim<0.11 output can be `{ [true] = 6 }`\n  for name, data in pairs(vim.api.nvim_get_commands({})) do\n    if type(name) == 'string' and data.preview then res[name] = true end\n  end\n  for name, data in pairs(vim.api.nvim_buf_get_commands(0, {})) do\n    if type(name) == 'string' and data.preview then res[name] = true end\n  end\n  return res\nend\n\nH.parse_cmd = function(line)\n  local ok, parsed = pcall(vim.api.nvim_parse_cmd, line, {})\n  local needs_reparse = not ok\n\n  -- Try extra parsing to have a result for some edge cases\n  -- - Line with only range\n  if not ok then\n    ok, parsed = pcall(vim.api.nvim_parse_cmd, line .. 'sort', {})\n  end\n  -- - Unfinished `/xxx` range\n  if not ok and line:find('/') ~= nil then\n    ok, parsed = pcall(vim.api.nvim_parse_cmd, line .. '/sort', {})\n  end\n  -- - Unrecognized command\n  if not ok and line:find('%a') ~= nil and line:find('^%A') ~= nil then\n    ok, parsed = pcall(vim.api.nvim_parse_cmd, line:match('^%A+') .. 'sort', {})\n  end\n\n  -- Treat `range` only as a \"line range\"\n  local range = (ok and parsed.addr == 'line') and parsed.range or {}\n  local cmd = needs_reparse and '' or parsed.cmd\n  return { range = range, cmd = cmd }\nend\n\nH.getcmdcomplpat = function() return vim.fn.getcmdcomplpat() end\nif vim.fn.has('nvim-0.11') == 0 then\n  -- Match alphanumeric characters to cursor's left, if present\n  -- This is not 100% how it works, but good enough\n  H.getcmdcomplpat = function() return vim.fn.getcmdline():sub(1, vim.fn.getcmdpos() - 1):match('%w+$') or '' end\nend\n\nreturn MiniCmdline\n"
  },
  {
    "path": "lua/mini/colors.lua",
    "content": "--- *mini.colors* Tweak and save any color scheme\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Create colorscheme object: either manually (|MiniColors.as_colorscheme()|)\n---   or by querying present color schemes (including currently active one; see\n---   |MiniColors.get_colorscheme()|).\n---\n--- - Infer data about color scheme and/or modify based on it:\n---     - Add transparency by removing background color (requires transparency\n---       in terminal emulator).\n---     - Infer cterm attributes (|cterm-colors|) based on gui colors making it\n---       compatible with 'notermguicolors'.\n---     - Resolve highlight group links (|:highlight-link|).\n---     - Compress by removing redundant highlight groups.\n---     - Extract palette of used colors and/or infer terminal colors\n---       (|terminal-config|) based on it.\n---\n--- - Modify colors to better fit your taste and/or goals (see more in\n---   |MiniColors-colorscheme-methods|):\n---     - Apply any function to color hex string.\n---     - Update channels (like lightness, saturation, hue, temperature, red,\n---       green, blue, etc.; see more in |MiniColors-channels|).\n---       Use either own function or one of the implemented methods:\n---         - Add value to channel or multiply it by coefficient. Like \"add 10\n---           to saturation of every color\" or \"multiply saturation by 2\" to\n---           make colors more saturated (less gray).\n---         - Invert. Like \"invert lightness\" to convert between dark/light theme.\n---         - Set to one or more values (picks closest to current one). Like\n---           \"set to one or two hues\" to make mono- or dichromatic color scheme.\n---         - Repel from certain source(s) with stronger effect for closer values.\n---           Like \"repel from hue 30\" to remove red color from color scheme.\n---           Repel hue (how much is removed) is configurable.\n---     - Simulate color vision deficiency.\n---\n--- - Once color scheme is ready, either apply it to see effects right away or\n---   write it into a Lua file as a fully functioning separate color scheme.\n---\n--- - Experiment interactively with a feedback (|MiniColors.interactive()|).\n---\n--- - Animate transition between color schemes either with |MiniColors.animate()|\n---   or with |:Colorscheme| user command.\n---\n--- - Convert within supported color spaces (|MiniColors.convert()|):\n---     - Hex string.\n---     - 8-bit number (terminal colors).\n---     - RGB.\n---     - Oklab, Oklch, Okhsl (https://bottosson.github.io/posts/oklab/).\n---\n--- Notes:\n--- - There is a collection of |MiniColors-recipes| with code snippets for some\n---   common tasks.\n--- - There is no goal to support as many color spaces as possible, only the\n---   already present ones.\n---\n--- # Tweak quick start ~\n---\n--- - Execute `:lua require('mini.colors').interactive()`.\n---\n--- - Experiment by writing calls to exposed color scheme methods and applying\n---   them with `<M-a>`. For more information, see |MiniColors-colorscheme-methods|\n---   and |MiniColors-recipes|.\n---\n--- - If you are happy with result, write color scheme with `<M-w>`. If not,\n---   reset to initial color scheme with `<M-r>`.\n---\n--- - If only some highlight groups can be made better, adjust them manually\n---   inside written color scheme file.\n---\n--- # Setup ~\n---\n--- This module doesn't need setup, but it can be done to improve usability.\n--- Setup with `require('mini.colors').setup({})` (replace `{}` with your\n--- `config` table). It will create global Lua table `MiniColors` which you can\n--- use for scripting or manually (with `:lua MiniColors.*`).\n---\n--- See |MiniColors.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minicolors_config`\n--- will have no effect here.\n---\n--- # Comparisons ~\n---\n--- - [rktjmp/lush.nvim](https://github.com/rktjmp/lush.nvim):\n---     - Oriented towards tweaking separate highlight groups, while 'mini.colors'\n---       is more designed to work with color scheme as a whole.\n---     - Uses HSL and HSLuv color spaces, while 'mini.colors' uses Oklab, Oklch,\n---       and Okhsl which have slightly better perceptual uniformity properties.\n---     - Doesn't have functionality to infer and repair missing data in color\n---       scheme (like cterm attributes, terminal colors, transparency, etc.),\n---       while 'mini.colors' does.\n---     - Doesn't implement animation of color scheme transition, while\n---       'mini.colors' does.\n--- - [lifepillar/vim-colortemplate](https://github.com/lifepillar/vim-colortemplate):\n---     - Comparisons are similar to that of 'rktjmp/lush.nvim'.\n--- - [tjdevries/colorbuddy.nvim](https://github.com/tjdevries/colorbuddy.nvim):\n---     - Comparisons are similar to that of 'rktjmp/lush.nvim'.\n---@tag MiniColors\n\n--- All following code snippets assume to be executed inside interactive buffer\n--- (|MiniColors.interactive()|). They are directly copy-pasteable.\n---\n--- To apply single method to current color scheme, use >vim\n---   :lua MiniColors.get_colorscheme():<method goes here>:apply().\n--- <\n--- Recipes:\n--- - Tweak lightness: >lua\n---\n---   -- Invert dark/light color scheme to be light/dark\n---   chan_invert('lightness', { gamut_clip = 'cusp' })\n---\n---   -- Ensure constant contrast ratio\n---   chan_set('lightness', 15, { filter = 'bg' })\n---   chan_set('lightness', 85, { filter = 'fg' })\n--- <\n--- - Tweak saturation: >lua\n---\n---   -- Make background colors less saturated and foreground - more\n---   chan_add('saturation', -20, { filter = 'bg' })\n---   chan_add('saturation', 20,  { filter = 'fg' })\n---\n---   -- Convert to grayscale\n---   chan_set('saturation', 0)\n--- <\n--- - Tweak hue: >lua\n---\n---   -- Create monochromatic variant (this uses green color)\n---   chan_set('hue', 135)\n---\n---   -- Create dichromatic variant (this uses Neovim-themed hues)\n---   chan_set('hue', { 140, 245 })\n--- <\n--- - Tweak temperature: >lua\n---\n---   -- Invert temperature (make cold theme become warm and vice versa)\n---   chan_invert('temperature')\n---\n---   -- Make background colors colder and foreground warmer\n---   chan_add('temperature', -40, { filter = 'bg' })\n---   chan_add('temperature', 40,  { filter = 'fg' })\n--- <\n--- - Counter color vision deficiency (try combinations of these to see which\n---   one works best for you):\n---\n---     - Improve text saturation contrast (usually the best starting approach): >lua\n---\n---       chan_set('saturation', { 10, 90 }, { filter = 'fg' })\n--- <\n---     - Remove certain hues from all colors (use 30 for red, 90 for yellow,\n---       135 for green, 270 for blue): >lua\n---\n---       -- Repel red color\n---       chan_repel('hue', 30, 45)\n--- <\n---     - Force equally spaced palette (remove ones with which you know you\n---       have trouble): >lua\n---\n---       -- Might be a good choice for red-green color blindness\n---       chan_set('hue', { 90, 180, 270})\n---\n---       -- Might be a good choice for blue-yellow color blindness\n---       chan_set('hue', { 0, 90, 180 })\n--- <\n---     - Inverting temperature or pressure can sometimes improve readability: >lua\n---\n---       chan_invert('temperature')\n---       chan_invert('pressure')\n--- <\n---     - If all hope is lost, hue random generation might help if you are lucky: >lua\n---\n---       chan_modify('hue', function() return math.random(0, 359) end)\n--- <\n--- - For color scheme creators use |MiniColors-colorscheme:simulate_cvd()| to\n---   simulate various color vision deficiency types to see how color scheme\n---   would look in the eyes of color blind person.\n---@tag MiniColors-recipes\n\n--- Color space is a way to quantitatively describe a color. In this module\n--- color spaces are used both as source for |MiniColors-channels| and inputs\n--- for |MiniColors.convert()|\n---\n--- List of supported color spaces (along with their id in parenthesis):\n--- - 8-bit (`8-bit`) - integer between 16 and 255. Usually values 0-15 are also\n---   supported, but they depend on terminal emulator theme which is not reliable.\n---   See https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit .\n---\n--- - Hex (`hex`) - string of the form \"#xxxxxx\" where `x` is a hexadecimal number.\n---\n--- - RGB (`rgb`) - table with numeric fields `r` (red), `g` (green), `b` (blue).\n---   Visible range is from 0 to 255.\n---\n--- - Oklab (`oklab`) - table with fields `l` (lightness; numeric in [0; 100]),\n---   `a`, `b` (both are unbounded numeric; visible range is usually between\n---   -30 to 30). Field `l` describes how light is color; `a` - how \"green-red\" it is;\n---   `b` - how \"blue-yellow\" it is.\n---\n--- - Oklch (`oklch`) - table with fields `l` (same as in Oklab),\n---   `c` (chroma; positive numeric, visible range usually lower than 32),\n---   `h` (`nil` for grays or periodic numeric in [0, 360)). Field `c` describes how\n---   colorful a color is; `h` is a value of \"true color\" on color circle/wheel.\n---   NOTE: gray colors, being achromatic by nature, don't have hue.\n---\n--- - Okhsl (`okhsl`) - Oklch but with `c` replaced by `s` (saturation; numeric\n---   in [0; 100]). Field `s` describes a percent of chroma relative to maximum\n---   visible chroma for the particular lightness and hue combination. Note,\n---   that mathematical model used to compute maximum visible chroma is\n---   approximate which might lead to inaccuracies for highly saturated colors\n---   with relatively low or high lightness.\n---\n--- Sources for Oklab/Oklch/Okhsl:\n--- - https://bottosson.github.io/posts/oklab/ - initial derivation and\n---   introduction of Oklab and Oklch.\n--- - https://bottosson.github.io/misc/colorpicker - interactive color picker.\n---   Great way for a hands-on introduction to concepts of lightness, chroma,\n---   saturation, and hue.\n---\n--- Note that Oklab/Oklch/Okhsl use channel normalization for `l`, `a`, `b`, `c`, `s` that\n--- is more oriented towards integer numbers (according to the above sources).\n--- Some implementations (like in CSS) are more oriented towards [0; 1] range or\n--- percentages. Adjust accordingly by dividing/multiplying output by 100.\n--- Also use `adjust_lightness = false` in |MiniColors.convert()|.\n---\n--- # Gamut clip ~\n--- *MiniColors-gamut-clip*\n---\n--- In Neovim highlight group colors are usually specified by their red, green,\n--- and blue values from 0 to 255 in the form of HEX string (see |gui-colors|).\n--- Although plenty, these are not all possible colors.\n---\n--- When performing color manipulation using |MiniColors-colorscheme-methods|,\n--- it is possible to end up with \"impossible\" color (which can't be directly\n--- converted to HEX string). For example, inverting lightness of color \"#fce094\"\n--- will lead to a color `{ l = 10, c = 10, h = 90 }` in Oklch space, i.e.\n--- \"dark yellow\" which is impossible to show in HEX.\n---\n--- **Gamut clipping** is an action of converting color outside of visible gamut\n--- (colors representable with HEX string) to be inside it while preserving\n--- certain perceptual characteristics as much as possible.\n---\n--- Gamut clipping in this module is done inside Oklch color space. The goal is to\n--- preserve hue as much as possible while manipulating lightness and/or chroma.\n---\n--- List of supported gamut clip methods (along with their id in parenthesis):\n--- - Clip chroma (`'chroma'`) - reduce chroma while preserving lightness until\n---   color is inside visible gamut. Default method.\n---\n--- - Clip lightness (`'lightness'`) - reduce lightness while preserving chroma\n---   until color is inside visible gamut.\n---\n--- - Clip according to \"cusp\" (`'cusp'`) - reduce both lightness and chroma in\n---   a compromise way depending on hue.\n---   Cusp is a color with the highest chroma inside slice of visible gamut\n---   with the same hue (hue leaf). It is called that way because the slice has\n---   a roughly triangular shape with points at (0, 0) - (0, 100) - \"cusp\" in\n---   (chroma, lightness) coordinates.\n---   Gamut clipping using \"cusp\" as reference is done by changing color towards\n---   (0, cusp_lightness) point (gray with lightness equal to that of a current\n---   cusp) until color is inside visible gamut.\n---\n--- In short:\n--- - Usually `'chroma'` is enough.\n--- - If colors are too desaturated - try `'cusp'`.\n--- - If still not colorful enough - try `'lightness'`.\n---\n--- Notes:\n--- - Currently implemented formulas are approximate (by design; to reduce code\n---   complexity) so there might be problems for highly saturated colors with\n---   relatively low or high lightness.\n---@tag MiniColors-color-spaces\n\n--- A color channel is a number describing one particular aspect of a color.\n--- It is usually direct or modified coordinate of a color space. See\n--- |MiniColors-color-spaces| for information on color spaces.\n---\n--- List of supported channels (along with their id in parenthesis):\n--- - Lightness (`lightness`) - corrected `l` component of Oklch. Describes how\n---   light is a color. Ranges from 0 (black dark) to 100 (white light).\n---\n--- - Chroma (`chroma`) - `c` component of Oklch. Describes how colorful is\n---   a color in absolute units. Ranges from 0 (gray) to infinity (more like\n---   around 30 in practice).\n---\n--- - Saturation (`saturation`) - `s` component of Okhsl. Describes how colorful\n---   is color in relative units. Ranges from 0 (gray) to 100 (maximum saturation\n---   for a given lightness-hue pair).\n---\n--- - Hue (`hue`) - `h` component of Oklch. Describes \"true color value\" (like\n---   red/green/blue) as a number. It is a periodic value from 0 (included) to\n---   360 (not included). Best perceived as a degree on a color circle/wheel.\n---\n---   Approximate values for common color names:\n---     - 0   - pink.\n---     - 30  - red.\n---     - 60  - orange.\n---     - 90  - yellow.\n---     - 135 - green.\n---     - 180 - cyan.\n---     - 225 - light blue.\n---     - 270 - blue.\n---     - 315 - magenta/purple.\n---\n--- - Temperature (`temperature`) - circular distance from current hue to hue 270\n---   angle (blue). Ranges from 0 (cool) to 180 (hot) anchored at hues 270 (blue)\n---   and 90 (yellow). Similar to `b` channel but tries to preserve chroma.\n---\n--- - Pressure (`pressure`) - circular distance from current hue to hue 180.\n---   Ranges from 0 (low; green-ish) to 180 (high; red-ish) anchored at hues\n---   180 and 0. Similar to `a` channel but tries to preserve chroma.\n---   Not widely used; added to have something similar to temperature.\n---\n--- - a (`a`) - `a` component of Oklab. Describes how \"green-red\" a color is.\n---   Can have any value. Negative values are \"green-ish\", positive - \"red-ish\".\n---\n--- - b (`b`) - `b` component of Oklab. Describes how \"blue-yellow\" a color is.\n---   Can have any value. Negative values are \"blue-ish\", positive - \"yellow-ish\".\n---\n--- - Red (`red`) - `r` component of RGB. Describes how much red a color has.\n---   Ranges from 0 (no red) to 255 (full red).\n---\n--- - Green (`green`) - `g` component of RGB. Describes how much green a color has.\n---   Ranges from 0 (no green) to 255 (full green).\n---\n--- - Blue (`blue`) - `b` component of RGB. Describes how much blue a color has.\n---   Ranges from 0 (no blue) to 255 (full blue).\n---@tag MiniColors-channels\n\n---@alias __colors_channel `(string)` One of supported |MiniColors-channels|.\n---@alias __colors_chan_opts `(table|nil)` Options. Possible fields:\n---   - <filter> `(function|string)` - filter colors to update. Possible values:\n---       - String representing target attributes. One of `'fg'`, `'bg'`, `'sp'`,\n---         `'term'` (only terminal colors).\n---       - Callable with signature as in |MiniColors-colorscheme:color_modify()|.\n---     Default: `nil` to update all colors.\n---   - <gamut_clip> `(string)` - gamut clipping method. One of `'chroma'`,\n---     `'lightness'`, `'cusp'`. See |MiniColors-gamut-clip|. Default: `'chroma'`.\n\n--- Colorscheme object is a central structure of this module. It contains all\n--- data relevant to colors in fields and provides methods to modify it.\n---\n--- Create colorscheme object manually with |MiniColors.as_colorscheme()|: >lua\n---\n---   MiniColors.as_colorscheme({\n---     name = 'my_cs',\n---     groups = {\n---       Normal   = { fg = '#dddddd', bg = '#222222' },\n---       SpellBad = { sp = '#dd2222', undercurl = true },\n---     },\n---     terminal = { [0] = '#222222', [1] = '#dd2222' },\n---   })\n--- <\n--- Get any registered color scheme (including currently active) as colorscheme\n--- object with |MiniColors.get_colorscheme()|: >lua\n---\n---   -- Get current color scheme\n---   MiniColors.get_colorscheme()\n---\n---   -- Get registered color scheme by name\n---   MiniColors.get_colorscheme('minischeme', { new_name = 'maxischeme' })\n--- <\n---@class Colorscheme\n---\n--- *MiniColors-colorscheme-fields*\n---\n---@field name string|nil Name of the color scheme (as in |g:colors_name|).\n---\n---@field groups table|nil Table with highlight groups data. Keys are group\n---   names appropriate for `name` argument of |nvim_set_hl()|, values - tables\n---   appropriate for its `val` argument. Note: gui colors are accepted only in\n---   short form (`fg`, `bg`, `sp`).\n---\n---@field terminal table|nil Table with terminal colors data (|terminal-config|).\n---   Keys are numbers from 0 to 15, values - strings representing color (hex\n---   string or plain color name; see |nvim_get_color_by_name()|).\n---\n--- # Methods ~\n--- *MiniColors-colorscheme-methods*\n---\n--- Notes about all methods:\n--- - They never modify underlying colorscheme object instead returning deep\n---   copy with modified fields.\n--- - They accept `self` colorscheme object as first argument meaning they should be\n---   called with `:` notation (like `cs:method()`).\n---\n--- Example calling methods: >lua\n---\n---   -- Get current color scheme, set hue of colors to 135, infer cterm\n---   -- attributes and apply\n---   local cs = MiniColors.get_colorscheme()\n---   cs:chan_set('hue', 135):add_cterm_attributes():apply()\n--- <\n--- ## add_cterm_attributes() ~\n--- *MiniColors-colorscheme:add_cterm_attributes()*\n---\n--- Infer |cterm-colors| based on present |gui-colors|. It updates `ctermbg`/`ctermfg`\n--- based on `fg`/`bg` by approximating in perceptually uniform distance in Oklab\n--- space (|MiniColors-color-spaces|).\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields:\n---   - <force> `(boolean)` - Whether to replace already present cterm attributes\n---     with inferred ones. Default: `true`.\n---\n--- ## add_terminal_colors() ~\n--- *MiniColors-colorscheme:add_terminal_colors()*\n---\n--- Infer terminal colors (|terminal-config|) based on colorscheme palette\n--- (see |MiniColors-colorscheme:get_palette()|). It updates `terminal` field\n--- based on color scheme's palette by picking the most appropriate entry to\n--- represent terminal color. Colors from 0 to 7 are attempted to be black,\n--- red, green, yellow, blue, magenta, cyan, white. Colors from 8 to 15 are\n--- the same as from 0 to 7.\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields:\n---   - <force> `(boolean)` - Whether to replace already present terminal colors\n---     with inferred ones. Default: `true`.\n---   - <palette_args> `(table)` - |MiniColors-colorscheme:get_palette()| arguments.\n---\n--- ## add_transparency() ~\n--- *MiniColors-colorscheme:add_transparency()*\n---\n--- Add transparency by removing background from a certain highlight groups.\n--- Requires actual transparency from terminal emulator to see background image.\n--- Has no effect on linked groups; use |MiniColors-colorscheme:resolve_links()|\n--- explicitly before applying transparency.\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields can be used to configure which\n---   sets of highlight groups to update:\n---   - <general> `(boolean)` - general groups (like `Normal`). Default: `true`.\n---   - <float> `(boolean)` - built-in groups for floating windows. Default: `false`.\n---   - <statuscolumn> `(boolean)` - groups related to 'statuscolumn' (signcolumn,\n---     numbercolumn, foldcolumn, `DiagnosticSignXxx`, and `XxxMsg` groups). Also\n---     updates groups for all currently defined signs. Default: `false`.\n---   - <statusline> `(boolean)` - built-in groups for 'statusline'. Default: `false`.\n---   - <tabline> `(boolean)` - built-in groups for 'tabline'. Default: `false`.\n---   - <winbar> `(boolean)` - built-in groups for 'winbar'. Default: `false`.\n---\n--- ## apply() ~\n--- *MiniColors-colorscheme:apply()*\n---\n--- Apply colorscheme:\n--- - Set |g:colors_name| to a `name` field.\n--- - Apply highlight groups in a `groups` field.\n--- - Set terminal colors from a `terminal` field.\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields:\n---   - <clear> `(boolean)` - whether to execute |:hi-clear| first. Default: `true`.\n---\n--- ## chan_add() ~\n--- *MiniColors-colorscheme:chan_add()*\n---\n--- Add value to a channel (see |MiniColors-channels|).\n---\n--- ### Parameters ~\n--- {channel} __colors_channel\n--- {value} `(number)` Number to add (can be negative).\n--- {opts} __colors_chan_opts\n---\n---\n--- ## chan_invert() ~\n--- *MiniColors-colorscheme:chan_invert()*\n---\n--- Invert value in a channel (see |MiniColors-channels|).\n---\n--- Notes:\n--- - Most Oklab/Oklch inversions are not exactly invertible: applying it twice\n---   might lead to slightly different colors depending on gamut clip method\n---   (|MiniColors-gamut-clip|) like smaller chroma with default `'chroma'` method.\n---\n--- ### Parameters ~\n--- {channel} __colors_channel\n--- {opts} __colors_chan_opts\n---\n--- ## chan_modify() ~\n--- *MiniColors-colorscheme:chan_modify()*\n---\n--- Modify channel with a callable.\n---\n--- ### Parameters ~\n--- {channel} __colors_channel\n--- {f} `(function)` - callable which defines modification. Should take current\n---   value of a channel and return a new one.\n--- {opts} __colors_chan_opts\n---\n--- ## chan_multiply() ~\n--- *MiniColors-colorscheme:chan_multiply()*\n---\n--- Multiply value of a channel (see |MiniColors-channels|).\n---\n--- ### Parameters ~\n--- {channel} __colors_channel\n--- {coef} `(number)` Number to multiply with (can be negative).\n--- {opts} __colors_chan_opts\n---\n--- ## chan_repel() ~\n--- *MiniColors-colorscheme:chan_repel()*\n---\n--- Repel from certain sources.\n---\n--- Given an array of repel centers (`sources`) and repel degree (`coef`) add to\n--- current channel value some amount (\"nudge\") with the following properties:\n--- - Nudges from several sources are added together.\n--- - Nudge is directly proportional to `coef`: bigger `coef` means bigger nudge.\n--- - Nudge is inversely proportional to the distance between current value and\n---   source: for positive `coef` bigger distance means smaller nudge, i.e.\n---   repel effect weakens with distance.\n--- - With positive `coef` nudges close to source are computed in a way to remove\n---   whole `[source - coef; source + coef]` range.\n--- - Negative `coef` results into attraction to source. Nudges in\n---   `[source - coef; source + coef]` range are computed to completely collapse it\n---   into `source`.\n---\n--- Examples: >lua\n---\n---   -- Repel hue from red color removing hue in range from 20 to 40\n---   chan_repel('hue', 30, 10)\n---\n---   -- Attract hue to red color collapsing [20; 40] range into 30.\n---   chan_repel('hue', 30, -10)\n--- <\n--- ### Parameters ~\n--- {channel} __colors_channel\n--- {sources} `(table|number)` Single or multiple source from which to repel.\n--- {coef} `(number)` Repel degree (can be negative to attract).\n--- {opts} __colors_chan_opts\n---\n--- ## chan_set() ~\n--- *MiniColors-colorscheme:chan_set()*\n---\n--- Set channel to certain value(s). This can be used to ensure that channel has\n--- value(s) only within supplied set. If more than one is supplied, closest\n--- element to current value is used.\n---\n--- ### Parameters ~\n--- {channel} __colors_channel\n--- {values} `(table|number)` Single or multiple values to set.\n--- {opts} __colors_chan_opts\n---\n--- ## color_modify() ~\n--- *MiniColors-colorscheme:color_modify()*\n---\n--- Modify all colors with a callable. It should return new color value (hex\n--- string or `nil` to remove attribute) base on the following input:\n--- - Current color as hex string.\n--- - Data about the color: a table with fields:\n---     - <attr> - one of `'fg'`, `'bg'`, `'sp'`, and `'term'` for terminal color.\n---     - <name> - name of color source. Either a name of highlight group or\n---       string of the form `terminal_color_x` for terminal color (as in\n---       |terminal-config|).\n---\n--- Example: >lua\n---\n---   -- Set to '#dd2222' all foreground colors for groups starting with \"N\"\n---   color_modify(function(hex, data)\n---     if data.attr == 'fg' and data.name:find('^N') then\n---       return '#dd2222'\n---     end\n---     return hex\n---   end)\n--- <\n--- ### Parameters ~\n--- {f} `(function)` Callable returning new color value.\n---\n--- ## compress() ~\n--- *MiniColors-colorscheme:compress()*\n---\n--- Remove redundant highlight groups. These are one of the two kinds:\n--- - Having values identical to ones after |:hi-clear| (meaning they usually\n---   don't add new information).\n--- - Coming from a curated list of plugins with highlight groups usually not\n---   worth keeping around. Current list of such plugins:\n---     - [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n---     - [norcalli/nvim-colorizer.lua](https://github.com/norcalli/nvim-colorizer.lua)\n---\n--- This method is useful to reduce size of color scheme before writing into\n--- the file with |MiniColors-colorscheme:write()|.\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields:\n---   - <plugins> `(boolean)` - whether to remove highlight groups from a curated\n---     list of plugins. Default: `true`.\n---\n--- ## get_palette() ~\n--- *MiniColors-colorscheme:get_palette()*\n---\n--- Get commonly used colors. This basically counts number of all color\n--- occurrences and filter out rare ones.\n---\n--- It is usually a good idea to apply both |MiniColors-colorscheme:compress()|\n--- and |MiniColors-colorscheme:resolve_links()| before applying this.\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields:\n---   - <threshold> `(number)` - relative threshold for groups to keep. A group\n---     is not included in output if it has less than this many occurrences\n---     relative to a total number of colors. Default: 0.01.\n---\n--- ## resolve_links() ~\n--- *MiniColors-colorscheme:resolve_links()*\n---\n--- Resolve links (|:highlight-link|). This makes all highlight groups with `link`\n--- attribute have data from a linked one.\n---\n--- Notes:\n--- - Resolves nested links.\n--- - If some group is linked to a group missing in current colorscheme object,\n---   it is not resolved.\n---\n--- ## simulate_cvd() ~\n--- *MiniColors-colorscheme:simulate_cvd()*\n---\n--- Simulate color vision deficiency (CVD, color blindness). This is basically\n--- a wrapper using |MiniColors.simulate_cvd()| as a part of\n--- call to |MiniColors-colorscheme:color_modify()| method.\n---\n--- ### Parameters ~\n--- {cvd_type} `(string)` One of `'protan'`, `'deutan'`, `'tritan'`, `'mono'`.\n--- {severity} `(number|nil)` Severity of CVD, number between 0 and 1. Default: 1.\n---\n--- ## write() ~\n--- *MiniColors-colorscheme:write()*\n---\n--- Write color scheme to a file. It will be a Lua script readily usable as\n--- a regular color scheme. Useful to both save results of color scheme tweaking\n--- and making local snapshot of some other color scheme.\n---\n--- Sourcing this file on startup usually leads to a better performance that\n--- sourcing initial color scheme, as it is essentially a conditioned\n--- |:hi-clear| call followed by a series of |nvim_set_hl()| calls.\n---\n--- Default writing location is a \"colors\" directory of your Neovim config\n--- directory (see |base-directories|). After writing, it should be available\n--- for sourcing with |:colorscheme| or |:Colorscheme|.\n---\n--- Name of the file by default is taken from `name` field (`'mini_colors'` is\n--- used if it is `nil`). If color scheme with this name already exists, it\n--- appends prefix based on current time to make it unique.\n---\n--- Notes:\n--- - If colors were updated, it is usually a good idea to infer cterm attributes\n---   with |MiniColors-colorscheme:add_cterm_attributes()| prior to writing.\n---\n--- ### Parameters ~\n--- {opts} `(table|nil)` Options. Possible fields:\n---   - <compress> `(boolean)` - whether to call |MiniColors-colorscheme:compress()|\n---     prior to writing. Default: `true`.\n---   - <name> `(string|nil)` - basename of written file. Default: `nil` to infer\n---     from `name` field.\n---   - <directory> `(string)` - directory to where file should be saved.\n---     Default: \"colors\" subdirectory of Neovim home config (`stdpath(\"config\")`).\n---@tag MiniColors-colorscheme\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniColors = {}\nlocal H = {}\n\n--- Module setup\n---\n--- # :Colorscheme ~\n--- *:Colorscheme*\n---\n--- Calling this function creates a `:Colorscheme` user command. It takes one or\n--- more registered color scheme names and performs animated transition between\n--- them (starting from currently active color scheme).\n--- It uses |MiniColors.animate()| with default options.\n---\n---@param config table|nil Module config table. See |MiniColors.config|.\n---\n---@usage >lua\n---   require('mini.colors').setup() -- use default config\n---   -- OR\n---   require('mini.colors').setup({}) -- replace {} with your config table\n--- <\nMiniColors.setup = function(config)\n  -- Export module\n  _G.MiniColors = MiniColors\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Create user commands\n  H.create_user_commands()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniColors.config = {}\n--minidoc_afterlines_end\n\n--- Create colorscheme object\n---\n---@param x table Table to be transformed into |MiniColors-colorscheme| object.\n---\n---@return table Copy of `x` transformed into a colorscheme object.\nMiniColors.as_colorscheme = function(x)\n  -- Validate input\n  if not H.is_table(x) then H.error('Input of `as_colorscheme()` should be table.') end\n\n  if x.groups ~= nil then\n    if not H.is_table(x.groups) then H.error('Field `groups` of colorscheme should be table or nil.') end\n    if not H.all(x.groups, H.is_table) then H.error('All elements of `groups` colorscheme field should be tables.') end\n  end\n\n  if x.terminal ~= nil then\n    if not H.is_table(x.terminal) then H.error('Field `terminal` of colorscheme should be table or nil.') end\n    if not H.all(x.terminal, H.is_string) then\n      H.error('All elements of `terminal` colorscheme field should be strings.')\n    end\n  end\n\n  -- Create a proper copy\n  local res = vim.deepcopy(x)\n\n  -- - Ensure that tables for highlight groups are independent (can not be the\n  --   case if some point to literally the same table)\n  if H.is_table(res.groups) then\n    for key, val in pairs(res.groups) do\n      res.groups[key] = vim.deepcopy(val)\n    end\n  end\n\n  -- Fields\n  res.groups = res.groups or {}\n  res.name = res.name\n  res.terminal = res.terminal or {}\n\n  -- Methods\n  res.add_cterm_attributes = H.cs_add_cterm_attributes\n  res.add_terminal_colors = H.cs_add_terminal_colors\n  res.add_transparency = H.cs_add_transparency\n  res.apply = H.cs_apply\n  res.chan_add = H.cs_chan_add\n  res.chan_invert = H.cs_chan_invert\n  res.chan_modify = H.cs_chan_modify\n  res.chan_multiply = H.cs_chan_multiply\n  res.chan_repel = H.cs_chan_repel\n  res.chan_set = H.cs_chan_set\n  res.color_modify = H.cs_color_modify\n  res.compress = H.cs_compress\n  res.get_palette = H.cs_get_palette\n  res.resolve_links = H.cs_resolve_links\n  res.simulate_cvd = H.cs_simulate_cvd\n  res.write = H.cs_write\n\n  return res\nend\n\n--- Get colorscheme object from registered color scheme\n---\n---@param name string|nil Name of color scheme to use. If `nil` (default) creates\n---  colorscheme object based on currently active data (|g:colors_name|,\n---  highlight groups, terminal colors). If string, converts color scheme with\n---  that name to a colorscheme object.\n---@param opts table|nil Options. Possible fields:\n---   - <new_name> `(string|nil)` - new name of colorscheme object.\n---\n---@return table Colorscheme object (|MiniColors-colorscheme|).\nMiniColors.get_colorscheme = function(name, opts)\n  if not (name == nil or type(name) == 'string') then H.error('Argument `name` should be string or `nil`.') end\n  opts = vim.tbl_deep_extend('force', { new_name = nil }, opts or {})\n\n  -- Return current color scheme if no `name` is supplied\n  if name == nil then\n    return MiniColors.as_colorscheme({\n      name = opts.new_name or vim.g.colors_name,\n      groups = H.get_current_groups(),\n      terminal = H.get_current_terminal(),\n    })\n  end\n\n  -- Source supplied color scheme, collect it and return back\n  local current_cs = MiniColors.get_colorscheme()\n  local res, au_id\n  au_id = vim.api.nvim_create_autocmd('ColorScheme', {\n    callback = function()\n      res = MiniColors.get_colorscheme(nil, opts)\n      -- Apply right now to avoid flickering\n      current_cs:apply()\n      -- Explicitly delete autocommand to account for error in `:colorscheme`\n      vim.api.nvim_del_autocmd(au_id)\n    end,\n  })\n  local ok, _ = pcall(vim.cmd, 'colorscheme ' .. name)\n  if not ok then H.error(string.format('No color scheme named \"%s\".', name)) end\n\n  return res\nend\n\n--- Start interactive experiments\n---\n--- Create a special buffer in which user can write plain Lua code to tweak\n--- color scheme and apply to get visual feedback.\n---\n--- # General principles ~\n--- - Initial colorscheme object is fixed to interactive buffer on its creation.\n---\n--- - There are special buffer convenience mappings:\n---     - Apply (source) current buffer content.\n---     - Reset color scheme (make initial colorscheme the current one).\n---     - Write to a file the result of applying current buffer content.\n---       This sources current content and calls |MiniColors-colorscheme:write()|.\n---     - Quit interactive buffer.\n---\n--- - User is expected to iteratively tweak color scheme by writing general Lua\n---   code in interactive buffer and applying it using convenience mapping.\n---\n--- - Application of interactive buffer is essentially these steps:\n---     - Expose `self` as initial colorscheme object on any application.\n---       It is always the same for every application.\n---     - Expose initial colorscheme methods as standalone functions. So instead\n---       of writing `self = self:add_transparency()` user can only write\n---       `add_transparency()`.\n---     - Source buffer content as plain Lua code.\n---\n--- Example of interactive buffer content: >lua\n---\n---   chan_modify('hue', function() return math.random(0, 359) end)\n---   simulate_cvd('protan')\n---   add_cterm_attributes()\n---   add_terminal_colors()\n--- <\n---@param opts table|nil Options. Possible fields:\n---   - <colorscheme> `(table|nil)` - |MiniColors-colorscheme| object to be\n---     used as initial colorscheme for executed code. By default uses current\n---     color scheme.\n---   - <mappings> `table` - buffer mappings for actions. Possible fields:\n---       - <Apply> `(string)` - apply buffer code. Default: `'<M-a>'`.\n---       - <Reset> `(string)` - apply initial color scheme as is. Default: `'<M-r>'`.\n---       - <Quit> `(string)` - close interactive buffer. Default: `'<M-q>'`.\n---       - <Write> `(string)` - write result of buffer code into a file.\n---         Prompts for file name with |vim.ui.input()| and then\n---         uses |MiniColors-colorscheme:write()| with other options being default.\n---         Default: `'<M-w>'`.\nMiniColors.interactive = function(opts)\n  opts = vim.tbl_deep_extend(\n    'force',\n    { colorscheme = nil, mappings = { Apply = '<M-a>', Reset = '<M-r>', Quit = '<M-q>', Write = '<M-w>' } },\n    opts or {}\n  )\n  local maps = opts.mappings\n\n  -- Prepare\n  local init_cs = opts.colorscheme == nil and MiniColors.get_colorscheme()\n    or MiniColors.as_colorscheme(opts.colorscheme)\n  local buf_id = vim.api.nvim_create_buf(true, true)\n  H.set_buf_name(buf_id, 'interactive')\n\n  -- Write header lines\n  local header_lines = {\n    [[-- Experiment with color scheme using 'mini.colors']],\n    '--',\n    '-- Treat this as regular Lua file',\n    '-- Methods of initial color scheme can be called directly',\n    '-- See more in `:h MiniColors.interactive()`',\n    '--',\n    '-- Initial color scheme: ' .. (init_cs.name or '<unnamed>'),\n    '-- Buffer-local mappings (Normal mode):',\n    '--   Apply: ' .. maps.Apply,\n    '--   Reset: ' .. maps.Reset,\n    '--   Quit:  ' .. maps.Quit,\n    '--   Write: ' .. maps.Write,\n    '--',\n    '-- Examples:',\n    '--',\n    '-- Invert dark/light color scheme to be light/dark',\n    \"-- chan_invert('lightness', { gamut_clip = 'cusp' })\",\n    '--',\n    '-- Make foreground text more saturated',\n    \"-- chan_add('saturation', 20,  { filter = 'fg' })\",\n    '',\n    '',\n  }\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, true, header_lines)\n\n  -- Make local mappings\n  local m = function(action, rhs) vim.keymap.set('n', maps[action], rhs, { desc = action, buffer = buf_id }) end\n\n  m('Apply', function()\n    local new_cs = H.apply_interactive_buffer(buf_id, init_cs)\n    new_cs:apply()\n  end)\n  m('Reset', function() init_cs:apply() end)\n  m('Quit', function()\n    local ok, bufremove = pcall(require, 'mini.bufremove')\n    if ok then\n      bufremove.wipeout(buf_id, true)\n    else\n      vim.api.nvim_buf_delete(buf_id, { force = true })\n    end\n  end)\n  m('Write', function()\n    vim.ui.input(\n      { prompt = [[Write to 'colors/' of your config under this name: ]], default = init_cs.name },\n      function(input)\n        if input == nil then return end\n        local new_cs = H.apply_interactive_buffer(buf_id, init_cs)\n        new_cs.name = input\n        new_cs:write({ name = input })\n      end\n    )\n  end)\n\n  -- Set local options\n  vim.bo[buf_id].filetype = 'lua'\n\n  -- Make current\n  vim.api.nvim_set_current_buf(buf_id)\n  vim.api.nvim_win_set_cursor(0, { vim.api.nvim_buf_line_count(buf_id), 0 })\nend\n\n--- Animate color scheme change\n---\n--- Start from currently active color scheme and loop through `cs_array`.\n---\n--- Powers |:Colorscheme| user command created in |MiniColors.setup()|.\n---\n---@param cs_array table Array of |MiniColors-colorscheme| objects.\n---@param opts table|nil Options. Possible fields:\n---   - <transition_steps> `(number)` - number of intermediate steps to show\n---     during transition between two color schemes. Bigger values result in\n---     smoother visual feedback but require more computational power.\n---     Default: 25.\n---   - <transition_duration> `(number)` - number of milliseconds to spend\n---     showing transition. Default: 1000.\n---   - <show_duration> `(number)` - number of milliseconds to show intermediate\n---     color schemes (all but last in `cs_array`). Default: 1000.\nMiniColors.animate = function(cs_array, opts)\n  if not (H.islist(cs_array) and H.all(cs_array, H.is_colorscheme)) then\n    H.error('Argument `cs_array` should be an array of color schemes.')\n  end\n  opts = vim.tbl_deep_extend(\n    'force',\n    { transition_steps = 25, transition_duration = 1000, show_duration = 1000 },\n    opts or {}\n  )\n\n  if #cs_array == 0 then return end\n\n  -- Pre-compute common data\n  local cs_oklab = vim.tbl_map(function(cs) return H.cs_hex_to_oklab(vim.deepcopy(cs)) end, cs_array)\n  local cs_oklab_current = H.cs_hex_to_oklab(MiniColors.get_colorscheme())\n\n  -- Make \"chain after action\" which animates transitions one by one\n  local cs_id, after_action = 1, nil\n  after_action = function(data)\n    -- Ensure authentic color scheme is active\n    cs_array[cs_id]:apply()\n\n    -- Advance if possible\n    cs_id = cs_id + 1\n    if #cs_array < cs_id then return end\n\n    -- Wait before starting another animation\n    local callback = function() H.animate_single_transition(cs_oklab[cs_id - 1], cs_oklab[cs_id], after_action, opts) end\n\n    vim.defer_fn(callback, opts.show_duration)\n  end\n\n  H.animate_single_transition(cs_oklab_current, cs_oklab[1], after_action, opts)\nend\n\n--- Convert between color spaces\n---\n--- For a list of supported colors spaces see |MiniColors-color-spaces|.\n---\n---@param x table|string|number|nil Color to convert from. Its color space is\n---   inferred automatically.\n---@param to_space string Id of allowed color space.\n---@param opts table|nil Options. Possible fields:\n---   - <adjust_lightness> `(boolean)` - whether to adjust lightness value to have\n---     a more uniform progression from 0 to 100. Set `false` for results more\n---     compatible with some other Oklab/Oklch implementations (like in CSS).\n---     Source: \"Intermission - a new lightness estimate for Oklab\" section of\n---     https://bottosson.github.io/posts/colorpicker\n---     Default: `true`.\n---   - <gamut_clip> `(string)` - method for |MiniColors-gamut-clip|.\n---     Default: `'chroma'`.\n---\n---@return table|string|number|nil Color in space `to_space` or `nil` if input is `nil`.\nMiniColors.convert = function(x, to_space, opts)\n  if x == nil then return nil end\n  if not vim.tbl_contains(H.allowed_spaces, to_space) then\n    local spaces = table.concat(vim.tbl_map(vim.inspect, H.allowed_spaces), ', ')\n    H.error('Argument `to_space` should be one of ' .. spaces .. '.')\n  end\n  opts = vim.tbl_deep_extend('force', { adjust_lightness = true, gamut_clip = 'chroma' }, opts or {})\n\n  -- Set reference value here once to not have to pass it as argument to many\n  -- downstream places\n  H.adjust_lightness = opts.adjust_lightness\n  return H.converters[to_space](x, H.infer_color_space(x), opts)\nend\n\n--- Modify channel\n---\n---@param x table|string|number|nil Color which channel will be modified. Color\n---   space is inferred automatically.\n---@param channel string One of supported |MiniColors-channels|.\n---@param f function Callable which defines modification. Should take current\n---   value of a channel and return a new one.\n---@param opts table|nil Options. Possible fields:\n---   - <gamut_clip> `(string)` - method for |MiniColors-gamut-clip|.\n---     Default: `'chroma'`.\n---\n---@return string|nil Hex string of color with modified channel or `nil` if input is `nil`.\nMiniColors.modify_channel = function(x, channel, f, opts)\n  channel = H.normalize_channel(channel)\n  f = H.normalize_f(f)\n  opts = vim.tbl_deep_extend('force', { gamut_clip = 'chroma' }, opts or {})\n\n  local modify_channel = H.channel_modifiers[channel]\n  return modify_channel(x, f, opts.gamut_clip)\nend\n\n--- Simulate color vision deficiency\n---\n---@param x table|string|number|nil Color to convert from. Its color space is\n---   inferred automatically.\n---@param cvd_type string Type of CVD. One of `'protan'`, `'deutan'`,\n---`'tritan'`, or `'mono'` (equivalent to converting to graysacle).\n---@param severity number|nil Severity of CVD. A number between 0 and 1 (default).\n---\n---@return string|nil Hex string of simulated color or `nil` if input is `nil`.\nMiniColors.simulate_cvd = function(x, cvd_type, severity)\n  if x == nil then return nil end\n  if not (cvd_type == 'protan' or cvd_type == 'deutan' or cvd_type == 'tritan' or cvd_type == 'mono') then\n    H.error('Argument `cvd_type` should be one of \"protan\", \"deutan\", \"tritan\", \"mono\".')\n  end\n  severity = severity or 1\n  if not H.is_number(severity) then H.error('Argument `severity` should be number.') end\n\n  -- Simulate monochromacy by setting zero 'crhoma'\n  if cvd_type == 'mono' then\n    local lch = MiniColors.convert(x, 'oklch')\n    lch.c, lch.h = 0, nil\n    ---@diagnostic disable:return-type-mismatch\n    return MiniColors.convert(lch, 'hex')\n  end\n\n  -- Simulate regular CVD by multiplying with appropriate matrix\n  severity = H.clip(H.round(10 * severity), 0, 10)\n  local mat = H.cvd_matricies[cvd_type][severity]\n  local rgb = MiniColors.convert(x, 'rgb')\n  local new_rgb = {\n    r = mat[1][1] * rgb.r + mat[1][2] * rgb.g + mat[1][3] * rgb.b,\n    g = mat[2][1] * rgb.r + mat[2][2] * rgb.g + mat[2][3] * rgb.b,\n    b = mat[3][1] * rgb.r + mat[3][2] * rgb.g + mat[3][3] * rgb.b,\n  }\n\n  return H.rgb2hex(new_rgb)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniColors.config)\n\n-- Color conversion constants\nH.tau = 2 * math.pi\n\n-- Cusps for Oklch color space. These represent (c, l) points of Oklch space\n-- (with **not corrected lightness**) inside a hue leaf (points with\n-- `math.floor(h) = <index>`) with the highest value of chroma (`c`).\n-- They are used to model the whole RGB gamut (region inside which sRGB colors\n-- are converted in Oklch space). It is modelled as triangle with vertices:\n-- (0, 0), (0, 100) and cusp. NOTE: this is an approximation, i.e. not all RGB\n-- colors lie inside this triangle **AND** not all points inside triangle are\n-- RGB colors. But both proportions are small: around 0.5% with similar modeled\n-- RGB color for first one and around 2.16% for second one.\n--stylua: ignore start\n---@diagnostic disable start\n---@private\nH.cusps = {\n  [0] = {26.23,64.74},\n  {26.14,64.65},{26.06,64.56},{25.98,64.48},{25.91,64.39},{25.82,64.29},{25.76,64.21},{25.70,64.13},{25.65,64.06},\n  {25.59,63.97},{25.55,63.90},{25.52,63.83},{25.48,63.77},{25.45,63.69},{25.43,63.63},{25.41,63.55},{25.40,63.50},\n  {25.39,63.43},{25.40,63.33},{25.40,63.27},{25.42,63.22},{25.44,63.15},{25.46,63.11},{25.50,63.05},{25.53,63.00},\n  {25.58,62.95},{25.63,62.90},{25.69,62.85},{25.75,62.81},{25.77,62.80},{25.34,63.25},{24.84,63.79},{24.37,64.32},\n  {23.92,64.83},{23.48,65.35},{23.08,65.85},{22.65,66.38},{22.28,66.86},{21.98,67.27},{21.67,67.70},{21.36,68.14},\n  {21.05,68.60},{20.74,69.08},{20.50,69.45},{20.27,69.83},{20.04,70.22},{19.82,70.62},{19.60,71.03},{19.38,71.44},\n  {19.17,71.87},{19.03,72.16},{18.83,72.59},{18.71,72.89},{18.52,73.34},{18.40,73.64},{18.28,73.95},{18.17,74.26},\n  {18.01,74.74},{17.91,75.05},{17.82,75.38},{17.72,75.70},{17.64,76.03},{17.56,76.36},{17.48,76.69},{17.41,77.03},\n  {17.35,77.36},{17.29,77.71},{17.24,78.05},{17.19,78.39},{17.15,78.74},{17.12,79.09},{17.09,79.45},{17.07,79.80},\n  {17.05,80.16},{17.04,80.52},{17.04,81.06},{17.04,81.42},{17.05,81.79},{17.07,82.16},{17.08,82.53},{17.11,82.72},\n  {17.14,83.09},{17.18,83.46},{17.22,83.84},{17.27,84.22},{17.33,84.60},{17.39,84.98},{17.48,85.56},{17.56,85.94},\n  {17.64,86.33},{17.73,86.72},{17.81,87.10},{17.91,87.50},{18.04,88.09},{18.16,88.48},{18.27,88.88},{18.40,89.48},\n  {18.57,89.87},{18.69,90.27},{18.88,90.87},{19.03,91.48},{19.22,91.88},{19.44,92.49},{19.66,93.10},{19.85,93.71},\n  {20.04,94.33},{20.33,94.94},{20.60,95.56},{20.85,96.18},{21.10,96.80},{21.19,96.48},{21.27,96.24},{21.38,95.93},\n  {21.47,95.70},{21.59,95.40},{21.72,95.10},{21.86,94.80},{21.97,94.58},{22.12,94.30},{22.27,94.02},{22.43,93.74},\n  {22.64,93.40},{22.81,93.14},{23.04,92.81},{23.22,92.56},{23.45,92.25},{23.68,91.95},{23.92,91.65},{24.21,91.31},\n  {24.45,91.04},{24.74,90.72},{25.08,90.36},{25.37,90.07},{25.70,89.74},{26.08,89.39},{26.44,89.07},{26.87,88.69},\n  {27.27,88.34},{27.72,87.98},{28.19,87.61},{28.68,87.23},{29.21,86.84},{29.48,86.64},{28.99,86.70},{28.13,86.81},\n  {27.28,86.92},{26.56,87.02},{25.83,87.12},{25.18,87.22},{24.57,87.32},{24.01,87.41},{23.53,87.49},{23.03,87.58},\n  {22.53,87.68},{22.10,87.76},{21.68,87.84},{21.26,87.93},{20.92,88.01},{20.58,88.08},{20.25,88.16},{19.92,88.24},\n  {19.59,88.33},{19.35,88.39},{19.12,88.46},{18.81,88.55},{18.58,88.61},{18.36,88.68},{18.14,88.76},{17.93,88.83},\n  {17.79,88.88},{17.59,88.95},{17.39,89.03},{17.26,89.08},{17.08,89.16},{16.96,89.21},{16.79,89.29},{16.68,89.35},\n  {16.58,89.41},{16.43,89.49},{16.33,89.55},{16.24,89.60},{16.16,89.66},{16.04,89.75},{15.96,89.81},{15.89,89.87},\n  {15.83,89.93},{15.77,89.99},{15.71,90.05},{15.66,90.12},{15.61,90.18},{15.57,90.24},{15.54,90.31},{15.51,90.37},\n  {15.48,90.44},{15.46,90.51},{15.40,90.30},{15.30,89.83},{15.21,89.36},{15.12,88.89},{15.03,88.67},{14.99,88.18},\n  {14.92,87.71},{14.85,87.24},{14.78,86.77},{14.75,86.53},{14.70,86.06},{14.65,85.59},{14.61,85.12},{14.60,84.89},\n  {14.57,84.42},{14.54,83.94},{14.53,83.71},{14.52,83.24},{14.51,82.77},{14.52,82.30},{14.52,81.83},{14.53,81.60},\n  {14.55,81.13},{14.58,80.66},{14.59,80.43},{14.63,79.96},{14.68,79.49},{14.70,79.26},{14.76,78.79},{14.82,78.32},\n  {14.85,78.09},{14.93,77.62},{15.01,77.16},{15.10,76.69},{15.19,76.23},{15.24,76.00},{15.34,75.54},{15.45,75.07},\n  {15.57,74.61},{15.69,74.15},{15.82,73.69},{15.96,73.23},{16.10,72.77},{16.24,72.31},{16.39,71.86},{16.55,71.40},\n  {16.71,70.95},{16.96,70.26},{17.14,69.81},{17.32,69.36},{17.59,68.69},{17.88,68.02},{18.07,67.57},{18.37,66.90},\n  {18.67,66.24},{18.99,65.58},{19.30,64.93},{19.74,64.06},{20.07,63.42},{20.51,62.57},{20.97,61.73},{21.54,60.69},\n  {22.00,59.87},{22.70,58.66},{23.39,57.49},{24.19,56.16},{25.20,54.52},{26.38,52.66},{28.55,49.32},{31.32,45.20},\n  {31.15,45.42},{30.99,45.64},{30.85,45.85},{30.72,46.06},{30.57,46.31},{30.47,46.50},{30.34,46.75},{30.23,46.97},\n  {30.13,47.20},{30.03,47.45},{29.93,47.71},{29.86,47.91},{29.77,48.20},{29.71,48.43},{29.65,48.66},{29.58,48.98},\n  {29.53,49.23},{29.48,49.48},{29.44,49.74},{29.41,50.01},{29.37,50.29},{29.35,50.57},{29.33,50.86},{29.31,51.16},\n  {29.30,51.56},{29.29,51.87},{29.29,52.39},{29.30,52.72},{29.31,53.05},{29.33,53.38},{29.35,53.72},{29.37,54.06},\n  {29.40,54.41},{29.43,54.76},{29.47,55.12},{29.52,55.60},{29.56,55.97},{29.61,56.34},{29.66,56.72},{29.73,57.22},\n  {29.79,57.61},{29.84,57.99},{29.93,58.52},{29.99,58.91},{30.08,59.44},{30.15,59.84},{30.24,60.38},{30.34,60.93},\n  {30.42,61.34},{30.52,61.90},{30.63,62.45},{30.73,63.02},{30.85,63.58},{30.96,64.15},{31.08,64.72},{31.19,65.30},\n  {31.31,65.88},{31.44,66.46},{31.59,67.20},{31.72,67.79},{31.88,68.53},{32.01,69.12},{32.18,69.87},{32.25,70.17},\n  {32.06,69.99},{31.76,69.70},{31.45,69.42},{31.21,69.20},{30.97,68.98},{30.68,68.71},{30.44,68.50},{30.21,68.29},\n  {29.98,68.09},{29.75,67.89},{29.53,67.69},{29.31,67.50},{29.09,67.31},{28.88,67.12},{28.72,66.98},{28.52,66.80},\n  {28.31,66.63},{28.16,66.50},{27.97,66.33},{27.78,66.17},{27.64,66.05},{27.49,65.94},{27.33,65.77},{27.20,65.66},\n  {27.04,65.51},{26.92,65.40},{26.81,65.30},{26.66,65.16},{26.55,65.06},{26.45,64.96},{26.35,64.87},\n}\n\n-- Matrices used to simulate color vision deficiency (CVD; color blindness).\n-- Each first-level entry describes CVD type; second-level - severity times 10.\n-- Source:\n-- https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html\nH.cvd_matricies = {\n  protan = {\n    [00]={{1.000000, 0.000000,  -0.000000}, {0.000000,  1.000000, 0.000000}, {-0.000000, -0.000000, 1.000000}},\n    [01]={{0.856167, 0.182038,  -0.038205}, {0.029342,  0.955115, 0.015544}, {-0.002880, -0.001563, 1.004443}},\n    [02]={{0.734766, 0.334872,  -0.069637}, {0.051840,  0.919198, 0.028963}, {-0.004928, -0.004209, 1.009137}},\n    [03]={{0.630323, 0.465641,  -0.095964}, {0.069181,  0.890046, 0.040773}, {-0.006308, -0.007724, 1.014032}},\n    [04]={{0.539009, 0.579343,  -0.118352}, {0.082546,  0.866121, 0.051332}, {-0.007136, -0.011959, 1.019095}},\n    [05]={{0.458064, 0.679578,  -0.137642}, {0.092785,  0.846313, 0.060902}, {-0.007494, -0.016807, 1.024301}},\n    [06]={{0.385450, 0.769005,  -0.154455}, {0.100526,  0.829802, 0.069673}, {-0.007442, -0.022190, 1.029632}},\n    [07]={{0.319627, 0.849633,  -0.169261}, {0.106241,  0.815969, 0.077790}, {-0.007025, -0.028051, 1.035076}},\n    [08]={{0.259411, 0.923008,  -0.182420}, {0.110296,  0.804340, 0.085364}, {-0.006276, -0.034346, 1.040622}},\n    [09]={{0.203876, 0.990338,  -0.194214}, {0.112975,  0.794542, 0.092483}, {-0.005222, -0.041043, 1.046265}},\n    [10]={{0.152286, 1.052583,  -0.204868}, {0.114503,  0.786281, 0.099216}, {-0.003882, -0.048116, 1.051998}},\n  },\n  deutan = {\n    [00]={{1.000000, 0.000000,  -0.000000}, {0.000000,  1.000000, 0.000000}, {-0.000000, -0.000000, 1.000000}},\n    [01]={{0.866435, 0.177704,  -0.044139}, {0.049567,  0.939063, 0.011370}, {-0.003453, 0.007233,  0.996220}},\n    [02]={{0.760729, 0.319078,  -0.079807}, {0.090568,  0.889315, 0.020117}, {-0.006027, 0.013325,  0.992702}},\n    [03]={{0.675425, 0.433850,  -0.109275}, {0.125303,  0.847755, 0.026942}, {-0.007950, 0.018572,  0.989378}},\n    [04]={{0.605511, 0.528560,  -0.134071}, {0.155318,  0.812366, 0.032316}, {-0.009376, 0.023176,  0.986200}},\n    [05]={{0.547494, 0.607765,  -0.155259}, {0.181692,  0.781742, 0.036566}, {-0.010410, 0.027275,  0.983136}},\n    [06]={{0.498864, 0.674741,  -0.173604}, {0.205199,  0.754872, 0.039929}, {-0.011131, 0.030969,  0.980162}},\n    [07]={{0.457771, 0.731899,  -0.189670}, {0.226409,  0.731012, 0.042579}, {-0.011595, 0.034333,  0.977261}},\n    [08]={{0.422823, 0.781057,  -0.203881}, {0.245752,  0.709602, 0.044646}, {-0.011843, 0.037423,  0.974421}},\n    [09]={{0.392952, 0.823610,  -0.216562}, {0.263559,  0.690210, 0.046232}, {-0.011910, 0.040281,  0.971630}},\n    [10]={{0.367322, 0.860646,  -0.227968}, {0.280085,  0.672501, 0.047413}, {-0.011820, 0.042940,  0.968881}},\n  },\n  tritan = {\n    [00]={{1.000000, 0.000000,  -0.000000}, {0.000000,  1.000000, 0.000000}, {-0.000000, -0.000000, 1.000000}},\n    [01]={{0.926670, 0.092514,  -0.019184}, {0.021191,  0.964503, 0.014306}, {0.008437,  0.054813,  0.936750}},\n    [02]={{0.895720, 0.133330,  -0.029050}, {0.029997,  0.945400, 0.024603}, {0.013027,  0.104707,  0.882266}},\n    [03]={{0.905871, 0.127791,  -0.033662}, {0.026856,  0.941251, 0.031893}, {0.013410,  0.148296,  0.838294}},\n    [04]={{0.948035, 0.089490,  -0.037526}, {0.014364,  0.946792, 0.038844}, {0.010853,  0.193991,  0.795156}},\n    [05]={{1.017277, 0.027029,  -0.044306}, {-0.006113, 0.958479, 0.047634}, {0.006379,  0.248708,  0.744913}},\n    [06]={{1.104996, -0.046633, -0.058363}, {-0.032137, 0.971635, 0.060503}, {0.001336,  0.317922,  0.680742}},\n    [07]={{1.193214, -0.109812, -0.083402}, {-0.058496, 0.979410, 0.079086}, {-0.002346, 0.403492,  0.598854}},\n    [08]={{1.257728, -0.139648, -0.118081}, {-0.078003, 0.975409, 0.102594}, {-0.003316, 0.501214,  0.502102}},\n    [09]={{1.278864, -0.125333, -0.153531}, {-0.084748, 0.957674, 0.127074}, {-0.000989, 0.601151,  0.399838}},\n    [10]={{1.255528, -0.076749, -0.178779}, {-0.078411, 0.930809, 0.147602}, {0.004733,  0.691367,  0.303900}},\n  },\n}\n---@diagnostic disable end\n--stylua: ignore end\n\nH.allowed_spaces = { '8-bit', 'hex', 'rgb', 'oklab', 'oklch', 'okhsl' }\n\nH.allowed_channels =\n  { 'lightness', 'chroma', 'saturation', 'hue', 'temperature', 'pressure', 'a', 'b', 'red', 'green', 'blue' }\n\nH.ns_id = { interactive = vim.api.nvim_create_namespace('MiniColorsInteractive') }\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  return config\nend\n\nH.apply_config = function(config) MiniColors.config = config end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniColors.config, vim.b.minicolors_config or {}, config or {})\nend\n\nH.create_user_commands = function()\n  local callback = function(input)\n    local cs_array = vim.tbl_map(MiniColors.get_colorscheme, input.fargs)\n    MiniColors.animate(cs_array)\n  end\n  vim.api.nvim_create_user_command('Colorscheme', callback, { nargs = '+', complete = 'color' })\nend\n\n-- Color scheme methods -------------------------------------------------------\nH.cs_add_cterm_attributes = function(self, opts)\n  local res = vim.deepcopy(self)\n  opts = vim.tbl_deep_extend('force', { force = true }, opts or {})\n\n  -- Compute Oklab coordinates of terminal colors for better approximation\n  local term_oklab = H.compute_term_oklab()\n\n  local force = opts.force\n  for _, gr in pairs(res.groups) do\n    if gr.fg and (force or not gr.ctermfg) then gr.ctermfg = H.get_closest_color_id(gr.fg, term_oklab) end\n    if gr.bg and (force or not gr.ctermbg) then gr.ctermbg = H.get_closest_color_id(gr.bg, term_oklab) end\n  end\n\n  return res\nend\n\nH.cs_add_terminal_colors = function(self, opts)\n  local res = vim.deepcopy(self)\n  opts = vim.tbl_deep_extend('force', { force = true, palette_args = {} }, opts or {})\n\n  -- General meaning of terminal colors are taken from here:\n  -- https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit\n  -- Regular and bright versions will be equal (to simplify algorithm)\n\n  -- Compress (for better palette representation) and resolve links (accounts\n  -- for possibly linked 'Normal' group)\n  local cs = res:compress():resolve_links()\n\n  -- Get palette and convert in Oklch\n  local palette = cs:get_palette(opts.palette_args)\n  local palette_oklch = vim.tbl_map(function(x) return MiniColors.convert(x, 'oklch') end, palette)\n\n  local terminal = {}\n\n  -- Black and white are colors from `Normal` group.\n  local normal = cs.groups.Normal or {}\n  local black, white = normal.bg, normal.fg\n\n  terminal[0], terminal[8] = black, black\n  terminal[7], terminal[15] = white, white\n\n  -- Colors are computed as closest to reference (pre-defined hue with white\n  -- lightness) taking into account only normalized lightness and hue\n  local white_oklch = MiniColors.convert(white, 'oklch')\n  local ref_l = white ~= nil and white_oklch.l or (vim.o.background == 'dark' and 85 or 15)\n  local ref_color_data = {\n    { l = ref_l, h = 30 }, -- Red\n    { l = ref_l, h = 150 }, -- Green\n    { l = ref_l, h = 90 }, -- Yellow\n    { l = ref_l, h = 270 }, -- Blue\n    { l = ref_l, h = 330 }, -- Magenta\n    { l = ref_l, h = 210 }, -- Cyan\n  }\n  local dist_color = function(x, y) return H.dist(x.l, y.l) / 100 + H.dist_circle(x.h, y.h) / 90 end\n  for i, ref in ipairs(ref_color_data) do\n    local col = H.get_closest(ref, palette_oklch, dist_color)\n    terminal[i], terminal[i + 8] = col, col\n  end\n\n  -- Update current `terminal` field\n  for i = 0, 15 do\n    if opts.force or not res.terminal[i] then res.terminal[i] = MiniColors.convert(terminal[i], 'hex') end\n  end\n\n  return res\nend\n\nH.cs_add_transparency = function(self, opts)\n  opts = vim.tbl_deep_extend('force', {\n    general = true,\n    float = false,\n    statuscolumn = false,\n    statusline = false,\n    tabline = false,\n    winbar = false,\n  }, opts or {})\n\n  local res = vim.deepcopy(self)\n  local groups = res.groups\n  local update = function(names)\n    for _, n in pairs(names) do\n      local gr = groups[n]\n      if gr == nil then return end\n      gr.bg, gr.ctermbg = nil, nil\n      gr.blend = 0\n    end\n  end\n\n  if opts.general then\n    update({ 'Normal', 'NormalNC', 'EndOfBuffer', 'MsgArea', 'MsgSeparator', 'VertSplit', 'WinSeparator' })\n    update({ 'ErrorMsg', 'WarningMsg', 'OkMsg', 'ModeMsg', 'MoreMsg', 'StderrMsg', 'StdoutMsg' })\n  end\n\n  if opts.float then update({ 'FloatBorder', 'FloatTitle', 'NormalFloat' }) end\n\n  if opts.statuscolumn then\n    update({ 'FoldColumn', 'LineNr', 'LineNrAbove', 'LineNrBelow', 'SignColumn' })\n    local diag_hl = vim.tbl_map(function(x) return 'DiagnosticSign' .. x end, { 'Error', 'Warn', 'Info', 'Hint', 'Ok' })\n    update(diag_hl)\n\n    -- Remove statuscolumn background coming from signs\n    local signs = vim.fn.sign_getdefined()\n    local groups = {}\n    for _, sign in ipairs(vim.fn.sign_getdefined()) do\n      table.insert(groups, sign.texthl)\n      table.insert(groups, sign.numhl)\n    end\n    update(groups)\n  end\n\n  if opts.statusline then update({ 'StatusLine', 'StatusLineNC', 'StatusLineTerm', 'StatusLineTermNC' }) end\n\n  if opts.tabline then update({ 'TabLine', 'TabLineFill', 'TabLineSel' }) end\n\n  if opts.winbar then update({ 'WinBar', 'WinBarNC' }) end\n\n  return res\nend\n\nH.cs_apply = function(self, opts)\n  opts = vim.tbl_deep_extend('force', { clear = true }, opts or {})\n\n  if opts.clear then vim.cmd('highlight clear') end\n  vim.g.colors_name = self.name\n\n  -- Highlight groups\n  local hi = vim.api.nvim_set_hl\n  local groups_arr = H.hl_groups_to_array(self.groups)\n  for _, hl_data in ipairs(groups_arr) do\n    hi(0, hl_data.name, hl_data.spec)\n  end\n\n  -- Terminal colors. Apply all colors in order to possibly remove previously\n  -- set ones.\n  for i = 0, 15 do\n    vim.g['terminal_color_' .. i] = self.terminal[i]\n  end\n\n  return self\nend\n\nH.cs_chan_add = function(self, channel, value, opts)\n  channel = H.normalize_channel(channel)\n  value = H.normalize_number(value, 'value')\n  if value == 0 then return vim.deepcopy(self) end\n\n  return self:chan_modify(channel, function(x) return x + value end, opts)\nend\n\nH.cs_chan_invert = function(self, channel, opts)\n  channel = H.normalize_channel(channel)\n  -- Don't invert 'chroma' directly because of lack of useful reference point\n  if channel == 'chroma' then channel = 'saturation' end\n  return self:chan_modify(channel, H.chan_inverters[channel], opts)\nend\n\nH.cs_chan_modify = function(self, channel, f, opts)\n  channel = H.normalize_channel(channel)\n  f = H.normalize_f(f)\n  opts = opts or {}\n  local filter = H.normalize_filter(opts.filter)\n  local gamut_clip = H.normalize_gamut_clip(opts.gamut_clip)\n\n  local modify_channel = H.channel_modifiers[channel]\n\n  local f_color = function(hex, data)\n    if not filter(hex, data) then return hex end\n    return modify_channel(hex, f, gamut_clip)\n  end\n\n  return self:color_modify(f_color)\nend\n\nH.cs_chan_multiply = function(self, channel, coef, opts)\n  channel = H.normalize_channel(channel)\n  coef = H.normalize_number(coef, 'coef')\n  if coef == 1 then return vim.deepcopy(self) end\n\n  return self:chan_modify(channel, function(x) return coef * x end, opts)\nend\n\nH.cs_chan_repel = function(self, channel, sources, coef, opts)\n  channel = H.normalize_channel(channel)\n  sources = H.normalize_number_array(sources, 'sources')\n  coef = H.normalize_number(coef, 'coef')\n\n  if #sources == {} or coef == 0 then return vim.deepcopy(self) end\n\n  -- Account for periodic nature of \"hue\" channel\n  sources = channel == 'hue' and H.add_circle_sources(sources) or sources\n  local tie_breaker = H.repel_tie_breakers[channel]\n  local f = function(x) return H.repel(x, sources, coef, tie_breaker) end\n\n  return self:chan_modify(channel, f, opts)\nend\n\nH.cs_chan_set = function(self, channel, values, opts)\n  channel = H.normalize_channel(channel)\n  values = H.normalize_number_array(values, 'values')\n  if #values == 0 then return H.error('Argument `values` should not be empty.') end\n\n  local dist_fun = channel == 'hue' and H.dist_circle or H.dist\n  local f = function(x) return H.get_closest(x, values, dist_fun) end\n\n  return self:chan_modify(channel, f, opts)\nend\n\nH.cs_color_modify = function(self, f)\n  f = H.normalize_f(f)\n\n  local res = vim.deepcopy(self)\n\n  -- Highlight groups\n  for name, spec in pairs(res.groups) do\n    if spec.fg ~= nil then spec.fg = f(spec.fg, { attr = 'fg', name = name }) end\n    if spec.bg ~= nil then spec.bg = f(spec.bg, { attr = 'bg', name = name }) end\n    if spec.sp ~= nil then spec.sp = f(spec.sp, { attr = 'sp', name = name }) end\n  end\n\n  -- Terminal colors\n  for i, hex in pairs(res.terminal) do\n    res.terminal[i] = f(hex, { attr = 'term', name = 'terminal_color_' .. i })\n  end\n\n  return res\nend\n\nH.cs_compress = function(self, opts)\n  opts = vim.tbl_deep_extend('force', { plugins = true }, opts or {})\n  local current_cs = MiniColors.get_colorscheme()\n\n  vim.cmd('highlight clear')\n  local clear_cs_groups = MiniColors.get_colorscheme().groups\n\n  local new_groups = {}\n  for name, spec in pairs(self.groups) do\n    -- Group should stay only if it adds new information compared to the state\n    -- after `:hi clear`\n    local is_from_clear = vim.deep_equal(clear_cs_groups[name], spec)\n\n    -- `^DevIcon` groups come from 'nvim-tree/nvim-web-devicons' and don't\n    -- really have value outside of that plugin. Plus there are **many** of\n    -- them and they are created in that plugin.\n    local is_devicon = opts.plugins and name:find('^DevIcon') ~= nil\n\n    -- `^colorizer_` groups come from 'norcalli/nvim-colorizer.lua' plugin and\n    -- don't really have value outside of that plugin.\n    local is_colorizer = opts.plugins and name:find('^colorizer_') ~= nil\n\n    -- 'mini.hipatterns' defines groups for hex color highlighting\n    local is_hipatterns_hex_color = opts.plugins and name:find('^MiniHipatterns%x%x%x%x%x%x$') ~= nil\n\n    if not (is_from_clear or is_devicon or is_colorizer) then new_groups[name] = spec end\n  end\n\n  current_cs:apply()\n\n  return MiniColors.as_colorscheme({ name = self.name, groups = new_groups, terminal = self.terminal })\nend\n\nH.cs_get_palette = function(self, opts)\n  opts = vim.tbl_deep_extend('force', { threshold = 0.01 }, opts or {})\n\n  -- Traverse all colors\n  local colors, n_color_uses = {}, 0\n  self:color_modify(function(hex)\n    colors[hex] = (colors[hex] or 0) + 1\n    n_color_uses = n_color_uses + 1\n  end)\n\n  -- Filter out and sort in descending order of lightness\n  local all_colors = {}\n  for hex, count in pairs(colors) do\n    if opts.threshold <= (count / n_color_uses) then\n      table.insert(all_colors, { hex, MiniColors.convert(hex, 'oklch').l })\n    end\n  end\n  table.sort(all_colors, function(a, b) return a[2] < b[2] end)\n\n  return vim.tbl_map(function(x) return x[1] end, all_colors)\nend\n\nH.cs_resolve_links = function(self)\n  local res = vim.deepcopy(self)\n\n  -- Resolve direct links (highlight groups linking to group without link)\n  -- iteratively one level at a time\n  repeat\n    local n_resolved_links = 0\n    for hl_name, hl_data in pairs(res.groups) do\n      -- Resolve link only if:\n      -- - Current highlight group is linked.\n      -- - Target link is present in color scheme and is not itself linked.\n      local link_data = res.groups[hl_data.link]\n      if link_data ~= nil and link_data.link == nil then\n        res.groups[hl_name] = vim.deepcopy(res.groups[hl_data.link])\n        n_resolved_links = n_resolved_links + 1\n      end\n    end\n  until n_resolved_links == 0\n\n  return res\nend\n\nH.cs_simulate_cvd = function(self, cvd_type, severity, opts)\n  local f = function(hex) return MiniColors.simulate_cvd(hex, cvd_type, severity, opts) end\n  return self:color_modify(f)\nend\n\nH.cs_write = function(self, opts)\n  opts = vim.tbl_extend(\n    'force',\n    { compress = true, directory = (vim.fn.stdpath('config') .. '/colors'), name = nil },\n    opts or {}\n  )\n\n  local name = opts.name or H.make_file_basename(self.name or 'mini_colors')\n\n  local cs = opts.compress and self:compress() or self\n\n  -- Create file lines\n  -- - Header\n  local lines = {\n    [[-- Made with 'mini.colors' module of https://nvim-mini.org/mini.nvim]],\n    '',\n    [[if vim.g.colors_name ~= nil then vim.cmd('highlight clear') end]],\n    'vim.g.colors_name = ' .. vim.inspect(cs.name),\n  }\n\n  -- - Highlight groups\n  if vim.tbl_count(cs.groups) > 0 then\n    vim.list_extend(lines, { '', '-- Highlight groups', 'local hi = vim.api.nvim_set_hl', '' })\n  else\n    vim.list_extend(lines, { '', '-- No highlight groups defined' })\n  end\n\n  local make_hi_line = function(hl)\n    local spec = setmetatable(hl.spec, nil)\n    return string.format('hi(0, \"%s\", %s)', hl.name, vim.inspect(spec, { newline = ' ', indent = '' }))\n  end\n  vim.list_extend(lines, vim.tbl_map(make_hi_line, H.hl_groups_to_array(cs.groups)))\n\n  -- - Terminal colors\n  if vim.tbl_count(cs.terminal) > 0 then\n    vim.list_extend(lines, { '', '-- Terminal colors', 'local g = vim.g', '' })\n  else\n    vim.list_extend(lines, { '', '-- No terminal colors defined' })\n  end\n\n  for i, hex in pairs(cs.terminal) do\n    local l = string.format('g.terminal_color_%d = \"%s\"', i, hex)\n    table.insert(lines, l)\n  end\n\n  -- Create file and populate with computed lines\n  vim.fn.mkdir(opts.directory, 'p')\n  local path = string.format('%s/%s.lua', opts.directory, name)\n  vim.fn.writefile(lines, path)\n\n  return self\nend\n\nH.is_colorscheme = function(x) return type(x) == 'table' and type(x.groups) == 'table' and type(x.terminal) == 'table' end\n\nH.normalize_f = function(f)\n  if not vim.is_callable(f) then H.error('Argument `f` should be callable.') end\n  return f\nend\n\nH.normalize_channel = function(x)\n  if not vim.tbl_contains(H.allowed_channels, x) then\n    local allowed = table.concat(vim.tbl_map(vim.inspect, H.allowed_channels), ', ')\n    local msg = string.format('Channel should be one of %s. Not %s.', allowed, vim.inspect(x))\n    H.error(msg)\n  end\n  return x\nend\n\nH.normalize_filter = function(x)\n  -- Treat `nil` filter as no filter\n  if x == nil then x = function() return true end end\n\n  -- Treat string filter as filter on attribute ('fg', 'bg', etc.)\n  if x == 'fg' or x == 'bg' or x == 'sp' or x == 'term' then\n    local attr_val = x\n    x = function(_, data) return data.attr == attr_val end\n  end\n\n  if not vim.is_callable(x) then\n    H.error('Argument `opts.filter` should be either proper attribute string or callable.')\n  end\n\n  return x\nend\n\nH.normalize_gamut_clip = function(x)\n  x = x or 'chroma'\n  if x == 'chroma' or x == 'lightness' or x == 'cusp' then return x end\n  H.error('Argument `opts.gamut_clip` should one of \"chroma\", \"lightness\", \"cusp\".')\nend\n\nH.normalize_number = function(x, arg_name)\n  if type(x) ~= 'number' then H.error('Argument `' .. arg_name .. '` should be a number.') end\n  return x\nend\n\nH.normalize_number_array = function(x, arg_name)\n  if H.is_number(x) then x = { x } end\n  if not (H.is_table(x) and H.all(x, H.is_number)) then\n    H.error('Argument `' .. arg_name .. '` should be number or array of numbers.')\n  end\n  return x\nend\n\n-- Color scheme helpers -------------------------------------------------------\nH.make_file_basename = function(name)\n  -- If there already is color scheme named `name`, append unique suffix\n  local all_colorschemes = vim.fn.getcompletion('', 'color')\n\n  if not vim.tbl_contains(all_colorschemes, name) then return name end\n  return name .. vim.fn.strftime('_%Y%m%d_%H%M%S')\nend\n\n-- -- TODO: Use `vim.api.nvim_get_hl()` when it is more stable (doesn't have\n--    issues with including not created highlight highlight groups for semantic\n--    tokens)\n-- H.get_current_groups = function()\n--   local res = {}\n--\n--   for name, new_t in pairs(vim.api.nvim_get_hl(0, {})) do\n--     -- Return plain `{}` instead of `vim.empty_dict()`\n--     local new_t = setmetatable(new_t, nil)\n--     -- Use HEX when needed\n--     new_t.fg, new_t.bg, new_t.sp = H.dec2hex(new_t.fg), H.dec2hex(new_t.bg), H.dec2hex(new_t.sp)\n--     res[name] = new_t\n--   end\n--\n--   return res\n-- end\n\nH.get_current_groups = function()\n  -- Get present highlight group names and if they are linked\n  local group_data = vim.split(vim.api.nvim_exec('highlight', true), '\\n')\n  local group_names = vim.tbl_map(function(x) return x:match('^(%S+)') end, group_data)\n  local link_data = vim.tbl_map(function(x) return x:match('^%S+.* links to (%S+)$') end, group_data)\n\n  local res = {}\n  for i, name in pairs(group_names) do\n    if link_data[i] ~= nil then\n      res[name] = { link = link_data[i] }\n    else\n      res[name] = H.get_hl_by_name(name)\n    end\n  end\n  return res\nend\n\nH.get_hl_by_name = function(name)\n  local res = vim.api.nvim_get_hl_by_name(name, true)\n\n  -- Convert decimal colors to hex strings\n  res.fg = H.dec2hex(res.foreground)\n  res.bg = H.dec2hex(res.background)\n  res.sp = H.dec2hex(res.special)\n\n  res.foreground, res.background, res.special = nil, nil, nil\n\n  -- Add terminal colors\n  local cterm_data = vim.api.nvim_get_hl_by_name(name, false)\n  res.ctermfg = cterm_data.foreground\n  res.ctermbg = cterm_data.background\n\n  -- At the moment, having `res[true] = 6` indicates that group is cleared\n  -- NOTE: actually return empty dictionary and not `nil` to preserve\n  -- information that group was cleared. This might matter if highlight group\n  -- was cleared but default links to something else (like if group\n  -- `@lsp.type.variable` is cleared to use tree-sitter highlighting but by\n  -- default it links to `Identifier`).\n  res[true] = nil\n\n  -- Return plain `{}` instead of `vim.empty_dict()`\n  return setmetatable(res, nil)\nend\n\nH.get_current_terminal = function()\n  local res = {}\n  for i = 0, 15 do\n    local col = vim.g['terminal_color_' .. i]\n    if type(col) == 'string' then res[i] = H.dec2hex(vim.api.nvim_get_color_by_name(col)) end\n  end\n\n  return res\nend\n\nH.dec2hex = function(dec)\n  if dec == nil or dec < 0 then return nil end\n  return string.format('#%06x', dec)\nend\n\nH.hl_groups_to_array = function(hl_groups)\n  local res = {}\n  for name, spec in pairs(hl_groups) do\n    table.insert(res, { name = name, spec = spec })\n  end\n  table.sort(res, function(a, b) return a.name < b.name end)\n  return res\nend\n\n-- Terminal colors ------------------------------------------------------------\n-- Source: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit\nH.compute_term_oklab = function()\n  -- Use cached values if they are already computed\n  if H.term_oklab ~= nil then return H.term_oklab end\n\n  local res = {}\n\n  -- Main colors. Don't use 0-15 because they are terminal dependent\n  local cterm_basis = { 0, 95, 135, 175, 215, 255 }\n  for i = 16, 231 do\n    local j = i - 16\n    local r = cterm_basis[math.floor(j / 36) % 6 + 1]\n    local g = cterm_basis[math.floor(j / 6) % 6 + 1]\n    local b = cterm_basis[j % 6 + 1]\n    res[i] = MiniColors.convert({ r = r, g = g, b = b }, 'oklab')\n  end\n\n  -- Grays\n  for i = 232, 255 do\n    local c = 8 + (i - 232) * 10\n    res[i] = MiniColors.convert({ r = c, g = c, b = c }, 'oklab')\n  end\n\n  H.term_oklab = res\n  return res\nend\n\nH.get_closest_color_id = function(x, ref_oklab)\n  local _, res = H.get_closest(MiniColors.convert(x, 'oklab'), ref_oklab, H.dist_oklab)\n  return res\nend\n\n-- Animation ------------------------------------------------------------------\nH.animate_single_transition = function(from_cs, to_cs, after_action, opts)\n  local all_group_names = H.union(vim.tbl_keys(from_cs.groups), vim.tbl_keys(to_cs.groups))\n  local n_steps = math.max(opts.transition_steps, 1)\n  local step_duration = math.max(opts.transition_duration / n_steps, 1)\n\n  -- Start animation\n  local cur_step = 1\n  local timer = vim.loop.new_timer()\n\n  local apply_step\n  apply_step = vim.schedule_wrap(function()\n    -- Ensure that current step is not too big. This handles weird issue with\n    -- small `step_duration` when this continued calling after `timer:stop()`.\n    -- Probably due to considerable time it takes to execute single step.\n    if n_steps < cur_step then return end\n\n    -- Compute and apply transition step\n    local cs_step = H.compute_animate_step(from_cs, to_cs, cur_step / n_steps, all_group_names)\n    -- - Use implementation helper instead of using `as_colorscheme()` to avoid\n    --   unnecessary `deepcopy()` increasing performance\n    H.cs_apply(cs_step)\n    vim.cmd('redraw')\n\n    -- Advance\n    cur_step = cur_step + 1\n    if n_steps < cur_step then\n      timer:stop()\n      pcall(after_action, { n_steps = n_steps, cur_step = cur_step })\n      return\n    end\n\n    -- Handle timer repeat here in order to ensure concurrency of steps\n    timer:set_repeat(step_duration)\n    timer:again()\n  end)\n\n  -- Start non-repeating timer\n  timer:start(step_duration, 0, apply_step)\nend\n\nH.cs_hex_to_oklab = function(cs)\n  local to_oklab = function(hex) return MiniColors.convert(hex, 'oklab') end\n  cs.groups = vim.tbl_map(function(gr)\n    gr.fg, gr.bg, gr.sp = to_oklab(gr.fg), to_oklab(gr.bg), to_oklab(gr.sp)\n    return gr\n  end, cs.groups)\n\n  cs.terminal = vim.tbl_map(to_oklab, cs.terminal)\n\n  return cs\nend\n\nH.cs_oklab_to_hex = function(cs)\n  -- 'chroma' clipping preserves lightness resulting into smoother transitions\n  local to_hex = function(lab) return MiniColors.convert(lab, 'hex', { gamut_clip = 'chroma' }) end\n  cs.groups = vim.tbl_map(function(gr)\n    gr.fg, gr.bg, gr.sp = to_hex(gr.fg), to_hex(gr.bg), to_hex(gr.sp)\n    return gr\n  end, cs.groups)\n\n  cs.terminal = vim.tbl_map(to_hex, cs.terminal)\n\n  return cs\nend\n\nH.compute_animate_step = function(from, to, coef, all_group_names)\n  local groups = {}\n  for _, name in ipairs(all_group_names) do\n    groups[name] = H.convex_hl_group(from.groups[name], to.groups[name], coef)\n  end\n\n  local terminal = {}\n  for i = 0, 15 do\n    terminal[i] = H.convex_lab(from.terminal[i], to.terminal[i], coef)\n  end\n\n  local cs_data = { name = 'transition_step', groups = groups, terminal = terminal }\n  return H.cs_oklab_to_hex(cs_data)\nend\n\nH.convex_hl_group = function(from, to, coef)\n  if from == nil or to == nil or from.link ~= nil or to.link ~= nil then return H.convex_discrete(from, to, coef) end\n\n  --stylua: ignore\n  return {\n    -- No `cterm` in convex combination because it is not trivial to create\n    -- proper gradient for them\n    fg = H.convex_lab(from.fg, to.fg, coef),\n    bg = H.convex_lab(from.bg, to.bg, coef),\n    sp = H.convex_lab(from.sp, to.sp, coef),\n\n    blend = H.round(H.convex_continuous(from.blend, to.blend, coef)),\n\n    bold          = H.convex_discrete(from.bold,          to.bold,          coef),\n    italic        = H.convex_discrete(from.italic,        to.italic,        coef),\n    nocombine     = H.convex_discrete(from.nocombine,     to.nocombine,     coef),\n    reverse       = H.convex_discrete(from.reverse,       to.reverse,       coef),\n    standout      = H.convex_discrete(from.standout,      to.standout,      coef),\n    strikethrough = H.convex_discrete(from.strikethrough, to.strikethrough, coef),\n    undercurl     = H.convex_discrete(from.undercurl,     to.undercurl,     coef),\n    underdashed   = H.convex_discrete(from.underdashed,   to.underdashed,   coef),\n    underdotted   = H.convex_discrete(from.underdotted,   to.underdotted,   coef),\n    underdouble   = H.convex_discrete(from.underdouble,   to.underdouble,   coef),\n    underline     = H.convex_discrete(from.underline,     to.underline,     coef),\n  }\nend\n\nH.convex_lab = function(from_lab, to_lab, coef)\n  if from_lab == nil or to_lab == nil then return H.convex_discrete(from_lab, to_lab, coef) end\n  return {\n    l = H.convex_continuous(from_lab.l, to_lab.l, coef),\n    a = H.convex_continuous(from_lab.a, to_lab.a, coef),\n    b = H.convex_continuous(from_lab.b, to_lab.b, coef),\n  }\nend\n\n-- Channel modifiers ----------------------------------------------------------\nH.channel_modifiers = {}\n\nH.channel_modifiers.lightness = function(hex, f, gamut_clip)\n  local lch = MiniColors.convert(hex, 'oklch')\n  lch.l = H.clip(f(lch.l), 0, 100)\n  return MiniColors.convert(lch, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.chroma = function(hex, f, gamut_clip)\n  local lch = MiniColors.convert(hex, 'oklch')\n  lch.c = H.clip(f(lch.c), 0, math.huge)\n  return MiniColors.convert(lch, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.saturation = function(hex, f, gamut_clip)\n  local lsh = MiniColors.convert(hex, 'okhsl')\n  lsh.s = H.clip(f(lsh.s), 0, 100)\n  return MiniColors.convert(lsh, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.hue = function(hex, f, gamut_clip)\n  local lch = MiniColors.convert(hex, 'oklch')\n  if lch.h == nil then return hex end\n  lch.h = f(lch.h) % 360\n  return MiniColors.convert(lch, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.temperature = function(hex, f, gamut_clip)\n  local lch = MiniColors.convert(hex, 'oklch')\n  if lch.h == nil then return hex end\n\n  -- Temperature is a circular distance to 270 hue degrees\n  -- Output value will lie in the same vertical half plane\n  local is_left = 90 <= lch.h and lch.h < 270\n  local temp = (is_left and (270 - lch.h) or (lch.h + 90)) % 360\n  local new_temp = H.clip(f(temp), 0, 180)\n  lch.h = (is_left and (270 - new_temp) or (new_temp - 90)) % 360\n\n  return MiniColors.convert(lch, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.pressure = function(hex, f, gamut_clip)\n  local lch = MiniColors.convert(hex, 'oklch')\n  if lch.h == nil then return hex end\n\n  -- Pressure is a circular distance to 180 hue degrees\n  -- Output value will lie in the same horizontal half plane\n  local is_up = 0 <= lch.h and lch.h < 180\n  local press = is_up and (180 - lch.h) or (lch.h - 180)\n  local new_press = H.clip(f(press), 0, 180)\n  lch.h = is_up and (180 - new_press) or (new_press + 180)\n\n  return MiniColors.convert(lch, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.a = function(hex, f, gamut_clip)\n  local lab = MiniColors.convert(hex, 'oklab')\n  lab.a = f(lab.a)\n  return MiniColors.convert(lab, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.b = function(hex, f, gamut_clip)\n  local lab = MiniColors.convert(hex, 'oklab')\n  lab.b = f(lab.b)\n  return MiniColors.convert(lab, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.red = function(hex, f, gamut_clip)\n  local rgb = H.hex2rgb(hex)\n  rgb.r = H.clip(f(rgb.r), 0, 255)\n  return MiniColors.convert(rgb, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.green = function(hex, f, gamut_clip)\n  local rgb = H.hex2rgb(hex)\n  rgb.g = H.clip(f(rgb.g), 0, 255)\n  return MiniColors.convert(rgb, 'hex', { gamut_clip = gamut_clip })\nend\n\nH.channel_modifiers.blue = function(hex, f, gamut_clip)\n  local rgb = H.hex2rgb(hex)\n  rgb.b = H.clip(f(rgb.b), 0, 255)\n  return MiniColors.convert(rgb, 'hex', { gamut_clip = gamut_clip })\nend\n\n-- Channel invert -------------------------------------------------------------\n--stylua: ignore\nH.chan_inverters = {\n  lightness   = function(x) return 100 - x end,\n  -- chroma is the same as saturation\n  saturation  = function(x) return 100 - x end,\n  hue         = function(x) return 360 - x end,\n  temperature = function(x) return 180 - x end,\n  pressure    = function(x) return 180 - x end,\n  a           = function(x) return -x end,\n  b           = function(x) return -x end,\n  red         = function(x) return 255-x end,\n  green       = function(x) return 255-x end,\n  blue        = function(x) return 255-x end,\n}\n\n-- Channel repel --------------------------------------------------------------\n-- Use tie breakers when target is close to source\nH.repel_tie_breakers = {\n  lightness = 50,\n  chroma = 100,\n  saturation = 50,\n  hue = 180,\n  temperature = 90,\n  pressure = 90,\n  a = 0,\n  b = 0,\n  red = 127,\n  green = 127,\n  blue = 127,\n}\n\nH.nudge_repel = function(d, coef)\n  -- Repel nudge will be added to distance from point to source.\n  -- Ideas behind approach:\n  -- - Nudge at `d = 0` should be equal to `coef`.\n  -- - Nudge should monotonically decrease to 0 as distance tends to infinity.\n  -- - The `d + nudge(d)` (distance after adding nudge) should be still\n  --   monotonically increasing as to preserve order of repelled points.\n  return coef * math.exp(-d / coef)\nend\n\nH.nudge_attract = function(d, coef)\n  -- Repel nudge will be added to distance from point to source.\n  -- Ideas behind approach:\n  -- - Adding nudge when `0 <= d <= coef` should lead to 0. This results into all\n  --   points from `coef` neighborhood of source collapse into source.\n  -- - Nudge should monotonically decrease to 0 as distance tends to infinity.\n  -- - The `d + nudge(d)` (distance after adding nudge) should be still\n  --   monotonically increasing as to preserve order of repelled points.\n  return d <= coef and -d or (-coef * math.exp(1 - d / coef))\nend\n\nH.repel = function(x, sources, coef, tie_breaker)\n  if coef == 0 then return x end\n\n  local nudge = coef > 0 and H.nudge_repel or H.nudge_attract\n  coef = math.abs(coef)\n\n  -- Use direction **towards** `tie_breaker` if `x` is very close to source\n  -- to allow more useful repelling from sources on channel allowed edges.\n  -- Example: both `repel(0, { 0 }, 10)` and `repel(100, { 100 }, 10)` should\n  -- result into repelling **inside** [0; 100] resulting into 10 and 90.\n  local tie_breaker_sign = tie_breaker < x and -1 or 1\n\n  local res = x\n  for _, src in ipairs(sources) do\n    -- Determine which way to move based on how `x` and source are positioned:\n    -- - Towards tie breaker if tie.\n    -- - To left if `x` is on left of source (and `coef > 0`).\n    -- - To right if `x` is on right of source (and `coef > 0`).\n    is_tie = math.abs(x - src) < 1e-4\n    dir_sign = is_tie and tie_breaker_sign or (x < src and -1 or 1)\n\n    -- Using regular distance is a proper choice even for \"hue\" channel because\n    -- it allows correct computation of nudge. Its periodic nature is accounted\n    -- by prior adjustment of `sources` (adding periodic ones)\n    res = res + dir_sign * nudge(H.dist(x, src), coef)\n  end\n  return res\nend\n\nH.add_circle_sources = function(sources)\n  local res = {}\n  -- Adding two new sources in periodic fashion makes repel more periodic\n  for _, src in ipairs(sources) do\n    table.insert(res, src)\n    table.insert(res, src - 360)\n    table.insert(res, src + 360)\n  end\n  return res\nend\n\n-- Color conversion -----------------------------------------------------------\nH.converters = {}\n\nH.converters['8-bit'] = function(x, _, _) return H.get_closest_color_id(x, H.compute_term_oklab()) end\n\nH.converters.hex = function(x, from_space, opts)\n  if from_space == 'hex' then return x end\n  return H.rgb2hex(MiniColors.convert(x, 'rgb', opts))\nend\n\nH.converters.rgb = function(x, from_space, opts)\n  if from_space == '8-bit' then\n    local rgb = H.oklab2rgb(H.compute_term_oklab()[x])\n    return vim.tbl_map(H.round, rgb)\n  end\n  if from_space == 'hex' then return H.hex2rgb(x) end\n\n  if from_space == 'rgb' then return { r = H.clip(x.r, 0, 255), g = H.clip(x.g, 0, 255), b = H.clip(x.b, 0, 255) } end\n\n  -- Clip non-gray color to be in gamut\n  local lch = MiniColors.convert(x, 'oklch', opts)\n  if lch.h ~= nil then lch = H.clip_to_gamut(lch, opts.gamut_clip) end\n\n  return H.oklab2rgb(H.oklch2oklab(lch))\nend\n\nH.converters.oklab = function(x, from_space, opts) return H.oklch2oklab(MiniColors.convert(x, 'oklch', opts)) end\n\nH.converters.oklch = function(x, from_space, opts)\n  local res = nil\n  if from_space == '8-bit' then res = H.oklab2oklch(H.compute_term_oklab()[x]) end\n  if from_space == 'hex' then res = H.oklab2oklch(H.rgb2oklab(H.hex2rgb(x))) end\n  if from_space == 'rgb' then res = H.oklab2oklch(H.rgb2oklab(x)) end\n  if from_space == 'oklab' then res = H.oklab2oklch(x) end\n  if from_space == 'oklch' then res = x end\n  if from_space == 'okhsl' then res = H.okhsl2oklch(x) end\n\n  -- Normalize\n  res.l = H.clip(res.l, 0, 100)\n\n  -- - Deal with grays separately\n  if res.c <= 0 or res.h == nil then\n    res.c, res.h = 0, nil\n  else\n    res.c, res.h = H.clip(res.c, 0, 100), res.h % 360\n  end\n\n  return res\nend\n\nH.converters.okhsl = function(x, from_space, opts) return H.oklch2okhsl(MiniColors.convert(x, 'oklch', opts)) end\n\nH.infer_color_space = function(x)\n  if type(x) == 'number' and 16 <= x and x <= 255 then return '8-bit' end\n  if type(x) == 'string' and x:find('^#%x%x%x%x%x%x$') ~= nil then return 'hex' end\n\n  local err_msg = 'Can not infer color space of ' .. vim.inspect(x)\n  if type(x) ~= 'table' then H.error(err_msg) end\n\n  local is_num = H.is_number\n  if is_num(x.l) then\n    if is_num(x.c) then return 'oklch' end\n    if is_num(x.a) and is_num(x.b) then return 'oklab' end\n    if is_num(x.s) then return 'okhsl' end\n  end\n\n  if is_num(x.r) and is_num(x.g) and is_num(x.b) then return 'rgb' end\n\n  H.error(err_msg)\nend\n\n-- HEX <-> RGB in [0; 255]\nH.hex2rgb = function(hex)\n  local dec = tonumber(hex:sub(2), 16)\n\n  local b = math.fmod(dec, 256)\n  local g = math.fmod((dec - b) / 256, 256)\n  local r = math.floor(dec / 65536)\n\n  return { r = r, g = g, b = b }\nend\n\nH.rgb2hex = function(rgb)\n  -- Use straightforward clipping to [0; 255] here to ensure correctness.\n  -- Modify `rgb` prior to this to ensure only a small distortion.\n  local r = H.clip(H.round(rgb.r), 0, 255)\n  local g = H.clip(H.round(rgb.g), 0, 255)\n  local b = H.clip(H.round(rgb.b), 0, 255)\n\n  return string.format('#%02x%02x%02x', r, g, b)\nend\n\n-- Sources for Oklab/Oklch:\n-- https://github.com/bottosson/bottosson.github.io/blob/master/misc/colorpicker/colorconversion.js\n-- https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab\n--\n-- Okhsl is a local variant of Oklch with `s` for \"saturation\" - percent of\n-- chroma relative to maximum possible chroma for this lightness and hue.\n--\n-- NOTEs:\n-- - Coordinates ranges: `l` - [0; 100], `a`/`b` - no range, `c` - [0; 100]\n--   (way less in gamut), `s` - [0; 100], `h` - [0; 360).\n-- - Lightness is always assumed to be corrected\n\n-- RGB in [0; 255] <-> Oklab\n-- https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab\nH.rgb2oklab = function(rgb)\n  -- Convert to linear RGB\n  local r, g, b = H.correct_channel(rgb.r / 255), H.correct_channel(rgb.g / 255), H.correct_channel(rgb.b / 255)\n\n  -- Convert to Oklab\n  local l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b\n  local m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b\n  local s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b\n\n  local l_, m_, s_ = H.cuberoot(l), H.cuberoot(m), H.cuberoot(s)\n\n  local L = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_\n  local A = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_\n  local B = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_\n\n  -- Explicitly convert for nearly achromatic colors\n  if math.abs(A) < 1e-4 then A = 0 end\n  if math.abs(B) < 1e-4 then B = 0 end\n\n  -- Normalize to appropriate range\n  return { l = H.correct_lightness(100 * L), a = 100 * A, b = 100 * B }\nend\n\nH.oklab2rgb = function(lab)\n  local L, A, B = 0.01 * H.correct_lightness_inv(lab.l), 0.01 * lab.a, 0.01 * lab.b\n\n  local l_ = L + 0.3963377774 * A + 0.2158037573 * B\n  local m_ = L - 0.1055613458 * A - 0.0638541728 * B\n  local s_ = L - 0.0894841775 * A - 1.2914855480 * B\n\n  local l = l_ * l_ * l_\n  local m = m_ * m_ * m_\n  local s = s_ * s_ * s_\n\n  --stylua: ignore\n  local r =  4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s\n  local g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s\n  local b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s\n\n  return { r = 255 * H.correct_channel_inv(r), g = 255 * H.correct_channel_inv(g), b = 255 * H.correct_channel_inv(b) }\nend\n\n-- Oklab <-> Oklch\nH.oklab2oklch = function(lab)\n  local c = math.sqrt(lab.a ^ 2 + lab.b ^ 2)\n  -- Treat grays specially\n  local h = nil\n  if c > 0 then h = H.rad2degree(math.atan2(lab.b, lab.a)) end\n  return { l = lab.l, c = c, h = h }\nend\n\nH.oklch2oklab = function(lch)\n  -- Treat grays specially\n  if lch.c <= 0 or lch.h == nil then return { l = lch.l, a = 0, b = 0 } end\n\n  local a = lch.c * math.cos(H.degree2rad(lch.h))\n  local b = lch.c * math.sin(H.degree2rad(lch.h))\n  return { l = lch.l, a = a, b = b }\nend\n\n-- Oklch <-> Okhsl\nH.oklch2okhsl = function(lch)\n  if lch.c <= 0 or lch.h == nil then return { l = lch.l, s = 0 } end\n\n  local gamut_points = H.get_gamut_points(lch)\n  local percent = 100 * lch.c / gamut_points.c_upper\n\n  return { l = lch.l, s = H.clip(percent, 0, 100), h = lch.h }\nend\n\nH.okhsl2oklch = function(lsh)\n  if lsh.s <= 0 or lsh.h == nil then return { l = lsh.l, c = 0 } end\n\n  local gamut_points = H.get_gamut_points(lsh)\n  local c = 0.01 * lsh.s * gamut_points.c_upper\n\n  return { l = lsh.l, c = H.clip(c, 0, math.huge), h = lsh.h }\nend\n\n-- Degree in [0; 360] <-> Radian in [0; 2*pi]\nH.rad2degree = function(x) return (x % H.tau) * 360 / H.tau end\n\nH.degree2rad = function(x) return (x % 360) * H.tau / 360 end\n\n-- Functions for RGB channel correction. Assumes input in [0; 1] range\n-- https://bottosson.github.io/posts/colorwrong/#what-can-we-do%3F\nH.correct_channel = function(x) return 0.04045 < x and math.pow((x + 0.055) / 1.055, 2.4) or (x / 12.92) end\n\nH.correct_channel_inv = function(x)\n  return (0.0031308 >= x) and (12.92 * x) or (1.055 * math.pow(x, 0.416666667) - 0.055)\nend\n\n-- Functions for lightness correction\n-- https://bottosson.github.io/posts/colorpicker/#intermission---a-new-lightness-estimate-for-oklab\nH.correct_lightness = function(x)\n  if not H.adjust_lightness then return x end\n\n  x = 0.01 * x\n  local k1, k2 = 0.206, 0.03\n  local k3 = (1 + k1) / (1 + k2)\n\n  local res = 0.5 * (k3 * x - k1 + math.sqrt((k3 * x - k1) ^ 2 + 4 * k2 * k3 * x))\n  return 100 * res\nend\n\nH.correct_lightness_inv = function(x)\n  if not H.adjust_lightness then return x end\n\n  x = 0.01 * x\n  local k1, k2 = 0.206, 0.03\n  local k3 = (1 + k1) / (1 + k2)\n  local res = (x / k3) * (x + k1) / (x + k2)\n  return 100 * res\nend\n\n-- Get gamut ranges for Lch point. They are computed for its hue leaf as\n-- segments of triangle in (c, l) coordinates ((0, 0), (0, 100), cusp).\n-- Equations for triangle parts:\n-- - Lower segment ((0; 0) to cusp): y * c_cusp = x * L_cusp\n-- - Upper segment ((0; 100) to cusp): (100 - y) * c_cusp = x * (100 - L_cusp)\n-- NOTEs:\n-- - It is **very important** that this triangle is computed for **not\n--   corrected** lightness. But it is assumed **corrected lightness** in input.\n-- - This approach is not entirely accurate and can results in ranges outside\n--   of input `lch` for in-gamut point. Put it should be pretty rare: ~0.5%\n--   cases for most saturated colors.\nH.get_gamut_points = function(lch)\n  local c, l = lch.c, H.clip(lch.l, 0, 100)\n  l = H.correct_lightness_inv(l)\n  local cusp = H.cusps[math.floor(lch.h % 360)]\n  local c_cusp, l_cusp = cusp[1], cusp[2]\n\n  -- Maximum allowed chroma is computed based on current lightness and depends\n  -- on whether `l` is below or above cusp's `l`:\n  -- - If below, then it is from lower triangle segment.\n  -- - If above - from upper segment.\n  local c_upper = l <= l_cusp and (c_cusp * l / l_cusp) or (c_cusp * (100 - l) / (100 - l_cusp))\n  -- - Don't allow negative chroma (can happen if `l` is out of [0; 100])\n  c_upper = H.clip(c_upper, 0, math.huge)\n\n  -- Other points can be computed only in presence of actual chroma\n  if c == nil then return { c_upper = c_upper } end\n\n  -- Range of allowed lightness is computed based on current chroma:\n  -- - Lower is from segment between (0, 0) and cusp.\n  -- - Upper is from segment between (0, 100) and cusp.\n  local l_lower, l_upper\n  if c < 0 then\n    l_lower, l_upper = 0, 100\n  elseif c_cusp < c then\n    l_lower, l_upper = l_cusp, l_cusp\n  else\n    local saturation = c / c_cusp\n    l_lower = saturation * l_cusp\n    l_upper = saturation * (l_cusp - 100) + 100\n  end\n\n  -- Intersection of segment between (c, l) and (0, l_cusp) with gamut boundary\n  local c_cusp_clip, l_cusp_clip\n  if c <= 0 then\n    c_cusp_clip, l_cusp_clip = c, l\n  elseif l <= l_cusp then\n    -- Intersection with lower segment\n    local prop = 1 - l / l_cusp\n    c_cusp_clip = c_cusp * c / (c_cusp * prop + c)\n    l_cusp_clip = l_cusp * c_cusp_clip / c_cusp\n  else\n    -- Intersection with upper segment\n    local prop = 1 - (l - 100) / (l_cusp - 100)\n    c_cusp_clip = c_cusp * c / (c_cusp * prop + c)\n    l_cusp_clip = 100 + c_cusp_clip * (l_cusp - 100) / c_cusp\n  end\n\n  return {\n    l_lower = H.correct_lightness(l_lower),\n    l_upper = H.correct_lightness(l_upper),\n    c_upper = c_upper,\n    l_cusp_clip = H.correct_lightness(l_cusp_clip),\n    c_cusp_clip = c_cusp_clip,\n  }\nend\n\nH.clip_to_gamut = function(lch, gamut_clip)\n  -- `lch` should have not corrected lightness\n  local res = vim.deepcopy(lch)\n  local gamut_points = H.get_gamut_points(lch)\n\n  local is_inside_gamut = lch.c <= gamut_points.c_upper\n  if is_inside_gamut then return res end\n\n  -- Clip by going towards (0, l_cusp) until in gamut. This approach proved to\n  -- be the best because of reasonable compromise between chroma and lightness.\n  -- In particular when inverting lightness of dark color schemes:\n  -- - Clipping by reducing chroma with constant lightness leads to a dark\n  --   foreground with hardly distinguishable colors.\n  -- - Clipping by adjusting lightness with constant chroma leads to very low\n  --   contrast on a particularly saturated foreground colors.\n  if gamut_clip == 'cusp' then\n    res.l, res.c = gamut_points.l_cusp_clip, gamut_points.c_cusp_clip\n  end\n\n  -- Preserve lightness by clipping chroma\n  if gamut_clip == 'chroma' then res.c = H.clip(res.c, 0, gamut_points.c_upper) end\n\n  -- Preserve chroma by clipping lightness\n  if gamut_clip == 'lightness' then res.l = H.clip(res.l, gamut_points.l_lower, gamut_points.l_upper) end\n\n  return res\nend\n\n-- Interactive ----------------------------------------------------------------\nH.apply_interactive_buffer = function(buf_id, init_cs)\n  -- Create temporary color scheme\n  _G._interactive_cs = vim.deepcopy(init_cs)\n\n  -- Create initial script lines exposing color scheme and its methods\n  local lines = { '-- Source code for interactive buffer', 'local self = _G._interactive_cs' }\n  for key, val in pairs(_G._interactive_cs) do\n    if vim.is_callable(val) then\n      local l = string.format('local %s = function(...) self = self:%s(...) end', key, key)\n      table.insert(lines, l)\n    end\n  end\n\n  -- Add current lines\n  lines = vim.list_extend(lines, vim.api.nvim_buf_get_lines(buf_id, 0, -1, true))\n\n  -- Return final result\n  table.insert(lines, 'return self')\n\n  -- Source\n  local ok, res = pcall(loadstring(table.concat(lines, '\\n')))\n  _G._interactive_cs = nil\n\n  if not ok then error(res) end\n  return res\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.colors) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minicolors://' .. buf_id .. '/' .. name) end\n\nH.round = function(x)\n  if x == nil then return nil end\n  return math.floor(x + 0.5)\nend\n\nH.clip = function(x, from, to) return math.min(math.max(x, from), to) end\n\nH.cuberoot = function(x) return math.pow(x, 0.333333) end\n\nH.dist = function(x, y) return math.abs(x - y) end\n\nH.dist_circle = function(x, y)\n  -- Respect gray colors which don't have hue\n  if x == nil and y == nil then return 0 end\n  if x == nil or y == nil then return math.huge end\n\n  local d = H.dist(x % 360, y % 360)\n  return math.min(d, 360 - d)\nend\n\nH.dist_oklab = function(x, y) return math.abs(x.l - y.l) + math.abs(x.a - y.a) + math.abs(x.b - y.b) end\n\nH.convex_continuous = function(x, y, coef)\n  if x == nil or y == nil then return H.convex_discrete(x, y, coef) end\n  return H.round((1 - coef) * x + coef * y)\nend\n\nH.convex_discrete = function(x, y, coef)\n  -- Using `vim.deepcopy()` ensures no side effects\n  if coef < 0.5 then return vim.deepcopy(x) end\n  return vim.deepcopy(y)\nend\n\nH.union = function(arr1, arr2)\n  local value_is_present = {}\n  for _, x in ipairs(arr1) do\n    value_is_present[x] = true\n  end\n  for _, x in ipairs(arr2) do\n    value_is_present[x] = true\n  end\n  return vim.tbl_keys(value_is_present)\nend\n\nH.get_closest = function(x, values, dist_fun)\n  local best_val, best_key, best_dist = nil, nil, math.huge\n  for key, val in pairs(values) do\n    local cur_dist = dist_fun(x, val)\n    if cur_dist <= best_dist then\n      best_val, best_key, best_dist = val, key, cur_dist\n    end\n  end\n\n  return best_val, best_key\nend\n\nH.is_number = function(x) return type(x) == 'number' end\n\nH.is_table = function(x) return type(x) == 'table' end\n\nH.is_string = function(x) return type(x) == 'string' end\n\nH.all = function(arr, predicate)\n  predicate = predicate or function(x) return x end\n  for _, x in pairs(arr) do\n    if not predicate(x) then return false end\n  end\n  return true\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniColors\n"
  },
  {
    "path": "lua/mini/comment.lua",
    "content": "--- *mini.comment* Comment lines\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Commenting in Normal mode respects |count| and is dot-repeatable.\n---\n--- - Comment structure by default is inferred from 'commentstring': either\n---   from current buffer or from locally active tree-sitter language.\n---   It can be customized via `options.custom_commentstring`\n---   (see |MiniComment.config| for details).\n---\n--- - Allows custom hooks before and after successful commenting.\n---\n--- - Configurable options for some nuanced behavior.\n---\n--- What it doesn't do:\n--- - Block and sub-line comments. This will only support per-line commenting.\n---\n--- - Handle indentation with mixed tab and space.\n---\n--- - Preserve trailing whitespace in empty lines.\n---\n--- Notes:\n--- - To use tree-sitter aware commenting, global value of 'commentstring'\n---   should be `''` (empty string). This is the default value, so make sure to\n---   not set it manually to a different value.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.comment').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table\n--- `MiniComment` which you can use for scripting or manually (with\n--- `:lua MiniComment.*`).\n---\n--- See |MiniComment.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minicomment_config` which should have same structure as\n--- `MiniComment.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.minicomment_disable` (globally) or\n--- `vim.b.minicomment_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniComment\n\n-- Module definition ==========================================================\nlocal MiniComment = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniComment.config|.\n---\n---@usage >lua\n---   require('mini.comment').setup() -- use default config\n---   -- OR\n---   require('mini.comment').setup({}) -- replace {} with your config table\n--- <\nMiniComment.setup = function(config)\n  -- Export module\n  _G.MiniComment = MiniComment\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Options ~\n---\n--- ## Custom commentstring ~\n---\n--- `options.custom_commentstring` can be a function customizing 'commentstring'\n--- option used to infer comment structure. It is called once before every\n--- commenting action with the following arguments:\n--- - `ref_position` - position at which to compute 'commentstring' (might be\n---   relevant for a text with locally different commenting rules). Its structure\n---   is the same as `opts.ref_position` in |MiniComment.toggle_lines()|.\n---\n--- Its output should be a valid 'commentstring' (string containing `%s`).\n---\n--- If not set or the output is `nil`, |MiniComment.get_commentstring()| is used.\n---\n--- For example, this option can be used to always use buffer 'commentstring'\n--- even in case of present active tree-sitter parser: >lua\n---\n---   require('mini.comment').setup({\n---     options = {\n---       custom_commentstring = function() return vim.bo.commentstring end,\n---     }\n---   })\n--- <\n--- # Hooks ~\n---\n--- `hooks.pre` and `hooks.post` functions are executed before and after successful\n--- commenting action (toggle or computing textobject). They will be called\n--- with a single table argument which has the following fields:\n--- - <action> `(string)` - action name. One of \"toggle\" (when actual toggle\n---   direction is yet unknown), \"comment\", \"uncomment\", \"textobject\".\n--- - <line_start> `(number|nil)` - action start line. Can be absent if yet unknown.\n--- - <line_end> `(number|nil)` - action end line. Can be absent if yet unknown.\n--- - <ref_position> `(table|nil)` - reference position.\n---\n--- Notes:\n--- - Changing 'commentstring' in `hooks.pre` is allowed and will take effect.\n--- - If hook returns `false`, any further action is terminated.\nMiniComment.config = {\n  -- Options which control module behavior\n  options = {\n    -- Function to compute custom 'commentstring' (optional)\n    custom_commentstring = nil,\n\n    -- Whether to ignore blank lines in actions and textobject\n    ignore_blank_line = false,\n\n    -- Whether to recognize as comment only lines without indent\n    start_of_line = false,\n\n    -- Whether to force single space inner padding for comment parts\n    pad_comment_parts = true,\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Toggle comment (like `gcip` - comment inner paragraph) for both\n    -- Normal and Visual modes\n    comment = 'gc',\n\n    -- Toggle comment on current line\n    comment_line = 'gcc',\n\n    -- Toggle comment on visual selection\n    comment_visual = 'gc',\n\n    -- Define 'comment' textobject (like `dgc` - delete whole comment block)\n    -- Works also in Visual mode if mapping differs from `comment_visual`\n    textobject = 'gc',\n  },\n\n  -- Hook functions to be executed at certain stage of commenting\n  hooks = {\n    -- Before successful commenting. Does nothing by default.\n    pre = function() end,\n    -- After successful commenting. Does nothing by default.\n    post = function() end,\n  },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Main function to be mapped\n---\n--- It is meant to be used in expression mappings (see |:map-<expr>|) to enable\n--- dot-repeatability and commenting on range. There is no need to do this\n--- manually, everything is done inside |MiniComment.setup()|.\n---\n--- It has a somewhat unintuitive logic (because of how expression mapping with\n--- dot-repeatability works): it should be called without arguments inside\n--- expression mapping and with argument when action should be performed.\n---\n---@param mode string|nil Optional string with 'operatorfunc' mode (see |g@|).\n---\n---@return string|nil 'g@' if called without argument, '' otherwise (but after\n---   performing action).\nMiniComment.operator = function(mode)\n  if H.is_disabled() then return '' end\n\n  -- If used without arguments inside expression mapping:\n  -- - Set itself as `operatorfunc` to be called later to perform action.\n  -- - Return 'g@' which will then be executed resulting into waiting for a\n  --   motion or text object. This textobject will then be recorded using `'[`\n  --   and `']` marks. After that, `operatorfunc` is called with `mode` equal\n  --   to one of \"line\", \"char\", or \"block\".\n  -- NOTE: setting `operatorfunc` inside this function enables usage of 'count'\n  -- like `10gc_` toggles comments of 10 lines below (starting with current).\n  if mode == nil then\n    vim.o.operatorfunc = 'v:lua.MiniComment.operator'\n    return 'g@'\n  end\n\n  -- If called with non-nil `mode`, get target region and act on it\n  -- This also works in expression mapping in Visual mode, as `g@` seems to\n  -- place these marks on start and end of visual selection\n  local mark_left, mark_right = '[', ']'\n  local lnum_from, col_from = unpack(vim.api.nvim_buf_get_mark(0, mark_left))\n  local lnum_to, col_to = unpack(vim.api.nvim_buf_get_mark(0, mark_right))\n\n  -- Do nothing if \"from\" mark is after \"to\" (like in empty textobject)\n  if (lnum_from > lnum_to) or (lnum_from == lnum_to and col_from > col_to) then return end\n\n  -- NOTE: use cursor position as reference for possibly computing local\n  -- tree-sitter-based 'commentstring'. Recompute every time for a proper\n  -- dot-repeat. In Visual and sometimes Normal mode it uses left position.\n  local cursor = vim.api.nvim_win_get_cursor(0)\n  MiniComment.toggle_lines(lnum_from, lnum_to, { ref_position = { cursor[1], cursor[2] + 1 } })\n  return ''\nend\n\n--- Toggle comments between two line numbers\n---\n--- It uncomments if lines are comment (every line is a comment or blank) and\n--- comments otherwise. It respects indentation and doesn't insert trailing\n--- whitespace. Toggle commenting not in visual mode is also dot-repeatable\n--- and respects |count|.\n---\n--- # Notes ~\n---\n--- - Comment structure is inferred from buffer's 'commentstring' option or\n---   local language of tree-sitter parser (if active).\n---\n--- - Call to this function will remove all |extmarks| from target range.\n---\n---@param line_start number Start line number (inclusive from 1 to number of lines).\n---@param line_end number End line number (inclusive from 1 to number of lines).\n---@param opts table|nil Options. Possible fields:\n---   - <ref_position> `(table)` - A two-value array with `{ row, col }` (both\n---     starting at 1) of reference position at which 'commentstring' value\n---     will be computed. Default: `{ line_start, 1 }`.\nMiniComment.toggle_lines = function(line_start, line_end, opts)\n  if H.is_disabled() then return end\n\n  opts = opts or {}\n  local ref_position = vim.deepcopy(opts.ref_position) or { line_start, 1 }\n\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  if not (1 <= line_start and line_start <= n_lines and 1 <= line_end and line_end <= n_lines) then\n    error('(mini.comment) `line_start` and `line_end` should be within range [1; ' .. n_lines .. '].')\n  end\n  if not (line_start <= line_end) then\n    error('(mini.comment) `line_start` should be less than or equal to `line_end`.')\n  end\n\n  local config = H.get_config()\n  local hook_arg = { action = 'toggle', line_start = line_start, line_end = line_end, ref_position = ref_position }\n  if config.hooks.pre(hook_arg) == false then return end\n\n  local parts = H.get_comment_parts(ref_position, config.options)\n  local lines = vim.api.nvim_buf_get_lines(0, line_start - 1, line_end, false)\n  local indent, is_comment = H.get_lines_info(lines, parts, config.options)\n\n  local f = is_comment and H.make_uncomment_function(parts) or H.make_comment_function(parts, indent, config.options)\n\n  -- NOTE: Direct of `nvim_buf_set_lines()` essentially removes (squashes to\n  -- empty range at either side of the region) both regular and extended marks\n  -- inside region. It can be resolved at least in the following ways:\n  -- 1. Use `lockmarks`. Preserves regular but does nothing for extmarks.\n  -- 2. Use `vim.fn.setline(line_start, new_lines)`. Preserves regular marks,\n  --    but squashes extmarks within a single line.\n  -- 3. Refactor to use precise editing of lines with `nvim_buf_set_text()`.\n  --    Preserves both regular and extended marks.\n  --\n  -- But:\n  -- - Options 2 and 3 are **significantly** slower for a large-ish regions.\n  --   Toggle of ~4000 lines takes 20 ms for 1, 200 ms for 2, 400 ms for 3.\n  --\n  -- - Preserving extmarks is not a universally good thing to do. It looks like\n  --   a good idea for extmarks which are not used for directly highlighting\n  --   text (like for 'mini.diff' signs or smartly tracking buffer position).\n  --   However, preserving extmarks is not 100% desirable when they highlight\n  --   text area, as every comment toggle at least results in a flickering\n  --   due to those extmarks still highlighting a (un)commented region.\n  --   Main example is LSP semantic token highlighting. Although it can have\n  --   special treatment (precisely clear those extmarks in the target region),\n  --   it is not 100% effective (they are restored after undo, again resulting\n  --   into flicker) and there might be more unnoticed issues.\n  --\n  -- So all in all, computing and replacing whole lines with `lockmarks` is the\n  -- best compromise so far. It also aligns with treating \"toggle comment\" in\n  -- a semantic way (those lines lines now have completely different meaning)\n  -- rather than in a text edit way (add comment parts to those lines).\n  _G._from, _G._to, _G._lines = line_start - 1, line_end, vim.tbl_map(f, lines)\n  vim.cmd('lockmarks lua pcall(vim.api.nvim_buf_set_lines, 0, _G._from, _G._to, false, _G._lines)')\n  _G._from, _G._to, _G._lines = nil, nil, nil\n\n  hook_arg.action = is_comment and 'uncomment' or 'comment'\n  if config.hooks.post(hook_arg) == false then return end\nend\n\n--- Select comment textobject\n---\n--- This selects all commented lines adjacent to cursor line. If `ignore_blank_line`\n--- option is enabled (see |MiniComment.config|), blank lines between commented\n--- lines are treated as part of textobject.\n--- Designed to be used with operator mode mappings (see |mapmode-o|).\nMiniComment.textobject = function()\n  if H.is_disabled() then return end\n\n  local config = H.get_config()\n  local hook_args = { action = 'textobject' }\n  if config.hooks.pre(hook_args) == false then return end\n\n  local lnum_cur = vim.fn.line('.')\n  local parts = H.get_comment_parts({ lnum_cur, vim.fn.col('.') }, config.options)\n  local comment_check = H.make_comment_check(parts, config.options)\n  local lnum_from, lnum_to\n\n  local ignore_blank_line = config.options.ignore_blank_line\n  local check = function(lnum)\n    if lnum == 0 then return false end\n    local l = vim.fn.getline(lnum)\n    return comment_check(l) or (ignore_blank_line and H.is_blank(l))\n  end\n\n  -- Recognize textobject only if on comment or blank between comments\n  local lnum_prev, lnum_next = vim.fn.prevnonblank(lnum_cur), vim.fn.nextnonblank(lnum_cur)\n  local is_in_comments = check(lnum_prev) and (lnum_prev == lnum_cur or check(lnum_next))\n\n  if is_in_comments then\n    lnum_from = lnum_cur\n    while (lnum_from >= 2) and check(lnum_from - 1) do\n      lnum_from = lnum_from - 1\n    end\n    if ignore_blank_line then lnum_from = vim.fn.nextnonblank(lnum_from) end\n\n    lnum_to = lnum_cur\n    local n_lines = vim.api.nvim_buf_line_count(0)\n    while (lnum_to <= n_lines - 1) and check(lnum_to + 1) do\n      lnum_to = lnum_to + 1\n    end\n    if ignore_blank_line then lnum_to = vim.fn.prevnonblank(lnum_to) end\n\n    local is_visual = vim.tbl_contains({ 'v', 'V', '\\22' }, vim.fn.mode())\n    if is_visual then vim.cmd('normal! \\27') end\n\n    -- This visual selection doesn't seem to change `'<` and `'>` marks when\n    -- executed as `onoremap` mapping\n    vim.cmd('normal! ' .. lnum_from .. 'GV' .. lnum_to .. 'G')\n  end\n\n  hook_args.line_start, hook_args.line_end = lnum_from, lnum_to\n  if config.hooks.post(hook_args) == false then return end\nend\n\n--- Get 'commentstring'\n---\n--- This function represents default approach of computing relevant\n--- 'commentstring' option in current buffer. Used to infer comment structure.\n---\n--- It has the following logic:\n--- - If there is an active tree-sitter parser, try to get 'commentstring' from\n---   the local language at `ref_position`.\n---\n--- - If first step is not successful, use buffer's 'commentstring' directly.\n---\n---@param ref_position table Reference position inside current buffer at which\n---   to compute 'commentstring'. Same structure as `opts.ref_position`\n---   in |MiniComment.toggle_lines()|.\n---\n---@return string Relevant value of 'commentstring'.\nMiniComment.get_commentstring = function(ref_position)\n  local buf_cs = vim.bo.commentstring\n\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, 0, nil, { error = false })\n  if not has_parser or parser == nil then return buf_cs end\n\n  -- Try to get 'commentstring' associated with local tree-sitter language.\n  -- This is useful for injected languages (like markdown with code blocks).\n  -- Sources:\n  -- - https://github.com/neovim/neovim/pull/22634#issue-1620078948\n  -- - https://github.com/neovim/neovim/pull/22643\n  local row, col = ref_position[1] - 1, ref_position[2] - 1\n  local ref_range = { row, col, row, col + 1 }\n\n  -- - Get 'commentstring' from the deepest LanguageTree which both contains\n  --   reference range and has valid 'commentstring' (meaning it has at least\n  --   one associated 'filetype' with valid 'commentstring').\n  --   In simple cases using `parser:language_for_range()` would be enough, but\n  --   it fails for languages without valid 'commentstring' (like 'comment').\n  local ts_cs, res_level = nil, 0\n  local traverse\n\n  traverse = function(lang_tree, level)\n    if not lang_tree:contains(ref_range) then return end\n\n    local lang = lang_tree:lang()\n    local filetypes = vim.treesitter.language.get_filetypes(lang)\n    for _, ft in ipairs(filetypes) do\n      -- Using `vim.filetype.get_option()` for performance as it has caching\n      local cur_cs = vim.filetype.get_option(ft, 'commentstring')\n      if type(cur_cs) == 'string' and cur_cs ~= '' and level > res_level then\n        ts_cs, res_level = cur_cs, level\n      end\n    end\n\n    for _, child_lang_tree in pairs(lang_tree:children()) do\n      traverse(child_lang_tree, level + 1)\n    end\n  end\n  traverse(parser, 1)\n\n  return ts_cs or buf_cs\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniComment.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('options', config.options, 'table')\n  H.check_type('options.custom_commentstring', config.options.custom_commentstring, 'function', true)\n  H.check_type('options.ignore_blank_line', config.options.ignore_blank_line, 'boolean')\n  H.check_type('options.start_of_line', config.options.start_of_line, 'boolean')\n  H.check_type('options.pad_comment_parts', config.options.pad_comment_parts, 'boolean')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.comment', config.mappings.comment, 'string')\n  H.check_type('mappings.comment_line', config.mappings.comment_line, 'string')\n  H.check_type('mappings.comment_visual', config.mappings.comment_visual, 'string')\n  H.check_type('mappings.textobject', config.mappings.textobject, 'string')\n\n  H.check_type('hooks', config.hooks, 'table')\n  H.check_type('hooks.pre', config.hooks.pre, 'function')\n  H.check_type('hooks.post', config.hooks.post, 'function')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniComment.config = config\n\n  -- Make mappings\n  local operator_rhs = function() return MiniComment.operator() end\n  H.map('n', config.mappings.comment, operator_rhs, { expr = true, desc = 'Comment' })\n  H.map('x', config.mappings.comment_visual, operator_rhs, { expr = true, desc = 'Comment selection' })\n  H.map(\n    'n',\n    config.mappings.comment_line,\n    function() return MiniComment.operator() .. '_' end,\n    { expr = true, desc = 'Comment line' }\n  )\n  -- Use `<Cmd>...<CR>` to have proper dot-repeat\n  -- See https://github.com/neovim/neovim/issues/23406\n  local modes = config.mappings.textobject == config.mappings.comment_visual and { 'o' } or { 'x', 'o' }\n  H.map(modes, config.mappings.textobject, '<Cmd>lua MiniComment.textobject()<CR>', { desc = 'Comment textobject' })\nend\n\nH.is_disabled = function() return vim.g.minicomment_disable == true or vim.b.minicomment_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniComment.config, vim.b.minicomment_config or {}, config or {})\nend\n\n-- Core implementations -------------------------------------------------------\nH.get_comment_parts = function(ref_position, options)\n  local cs\n  if vim.is_callable(options.custom_commentstring) then cs = options.custom_commentstring(ref_position) end\n  cs = cs or MiniComment.get_commentstring(ref_position)\n\n  if cs == nil or cs == '' then\n    vim.api.nvim_echo({ { '(mini.comment) ', 'WarningMsg' }, { [[Option 'commentstring' is empty.]] } }, true, {})\n    return { left = '', right = '' }\n  end\n\n  if not (type(cs) == 'string' and string.find(cs, '%%s') ~= nil) then\n    H.error(vim.inspect(cs) .. \" is not a valid 'commentstring'.\")\n  end\n\n  -- Structure of 'commentstring': <left part> <%s> <right part>\n  local left, right = string.match(cs, '^(.-)%%s(.-)$')\n\n  -- Force single space padding if requested\n  if options.pad_comment_parts then\n    left, right = vim.trim(left), vim.trim(right)\n    left, right = left == '' and '' or (left .. ' '), right == '' and '' or (' ' .. right)\n  end\n  return { left = left, right = right }\nend\n\nH.make_comment_check = function(parts, options)\n  local l_esc, r_esc = vim.pesc(parts.left), vim.pesc(parts.right)\n  local prefix = options.start_of_line and '' or '%s-'\n\n  -- Commented line has the following structure:\n  -- <whitespace> <trimmed left> <anything> <trimmed right> <whitespace>\n  local regex = '^' .. prefix .. vim.trim(l_esc) .. '.*' .. vim.trim(r_esc) .. '%s-$'\n\n  return function(line) return string.find(line, regex) ~= nil end\nend\n\nH.get_lines_info = function(lines, parts, options)\n  local comment_check = H.make_comment_check(parts, options)\n\n  local is_commented = true\n  local indent, indent_width = nil, math.huge\n\n  for _, l in ipairs(lines) do\n    -- Update lines indent: minimum of all indents except blank lines\n    local _, indent_width_cur, indent_cur = string.find(l, '^(%s*)')\n\n    -- Ignore blank lines completely when making a decision\n    if indent_width_cur < l:len() then\n      -- NOTE: Copying actual indent instead of recreating it with `indent_width`\n      -- allows to handle both tabs and spaces\n      if indent_width_cur < indent_width then\n        indent_width, indent = indent_width_cur, indent_cur\n      end\n\n      -- Update comment info: commented if every non-blank line is commented\n      if is_commented then is_commented = comment_check(l) end\n    end\n  end\n\n  -- `indent` can still be `nil` in case all `lines` are empty\n  return indent or '', is_commented\nend\n\nH.make_comment_function = function(parts, indent, options)\n  local prefix = options.start_of_line and (parts.left .. indent) or (indent .. parts.left)\n  local nonindent_start = string.len(indent) + 1\n  local suffix = parts.right\n\n  local blank_comment = indent .. vim.trim(parts.left) .. vim.trim(parts.right)\n  local ignore_blank_line = options.ignore_blank_line\n\n  return function(line)\n    if H.is_blank(line) then return ignore_blank_line and line or blank_comment end\n\n    return prefix .. string.sub(line, nonindent_start) .. suffix\n  end\nend\n\nH.make_uncomment_function = function(parts)\n  local l_esc, r_esc = vim.pesc(parts.left), vim.pesc(parts.right)\n  local regex = '^(%s*)' .. l_esc .. '(.*)' .. r_esc .. '(%s-)$'\n  local regex_trimmed = '^(%s*)' .. vim.trim(l_esc) .. '(.*)' .. vim.trim(r_esc) .. '(%s-)$'\n\n  return function(line)\n    -- Try regex with exact comment parts first, fall back to trimmed parts\n    local indent, new_line, trail = line:match(regex)\n    if new_line == nil then\n      indent, new_line, trail = line:match(regex_trimmed)\n    end\n\n    -- Return original if line is not commented\n    if new_line == nil then return line end\n\n    -- Prevent trailing whitespace\n    if H.is_blank(new_line) then\n      indent, trail = '', ''\n    end\n\n    return indent .. new_line .. trail\n  end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.comment) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.is_blank = function(x) return string.find(x, '^%s*$') ~= nil end\n\nreturn MiniComment\n"
  },
  {
    "path": "lua/mini/completion.lua",
    "content": "--- *mini.completion* Completion and signature help\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Key design ideas:\n--- - Have an async (with customizable \"debounce\" delay) \"two-stage chain\n---   completion\": first try to get completion items from LSP client (if set\n---   up) and if no result, fallback to custom action.\n---\n--- - Managing completion is done as much with Neovim's built-in tools as\n---   possible. |popupmenu-completion| is used to show completion suggestions.\n---\n--- Features:\n--- - Two-stage chain completion:\n---     - First stage is an LSP completion implemented via\n---       |MiniCompletion.completefunc_lsp()|. It should be set up as either\n---       |'completefunc'| or |'omnifunc'|. It tries to get completion items from\n---       LSP client (via 'textDocument/completion' request). Custom\n---       preprocessing of response items is possible (with\n---       `MiniCompletion.config.lsp_completion.process_items`), for example\n---       with fuzzy matching. By default items directly starting with completed\n---       word are kept and are sorted according to LSP specification.\n---       Supports `additionalTextEdits`, like auto-import and others (see 'Notes'),\n---       and snippet items (best results require |mini.snippets| dependency).\n---     - If first stage is not set up or resulted into no candidates, fallback\n---       action is executed. The most tested actions are Neovim's built-in\n---       insert completion (see |ins-completion|).\n---\n--- - Automatic display in floating window of completion item info (via\n---   'completionItem/resolve' request) and signature help (with highlighting\n---   of active parameter if LSP server provides such information).\n---   Signature help is shown if character to cursor's left is a dedicated trigger\n---   character (configured in `signatureHelpProvider.triggerCharacters` of LSP\n---   server capabilities) and updated without delay if is currently opened.\n---   Already shown window for signature help is fixed and is closed when there\n---   is nothing to show, its text is different, or when leaving Insert mode.\n---   Scroll in either info/signature window with `<C-f>` / `<C-b>` (by default).\n---\n--- - Automatic actions are done after some configurable amount of delay. This\n---   reduces computational load and allows fast typing (completion and\n---   signature help) and item selection (item info)\n---\n--- - Force two-stage/fallback completion (`<C-Space>` / `<A-Space>` by default).\n---\n--- - Customizable highlighting of LSP items. Requires Neovim>=0.11.\n---   Use `config.lsp_completion.process_items` to set dedicated highlight group\n---   in supported fields:\n---     - <abbr_hlgroup> - item label (`abbr` in terms of |complete-items|).\n---       By default only checks if item is marked as deprecated and sets\n---       `MiniCompletionDeprecated` highlight group.\n---     - <kind_hlgroup> - LSP kind (\"Function\", \"Keyword\", etc.). By default\n---       uses \"lsp\" category of |mini.icons| (if enabled).\n---\n--- What it doesn't do:\n--- - Many configurable sources.\n--- - Automatic mapping of `<CR>`, `<Tab>`, etc. Those tend to have highly\n---   variable user expectations. See 'Helpful mappings' for suggestions or\n---   use |MiniKeymap.map_multistep()| with `\"pmenu_*\"` built-in steps.\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies (provide extra functionality, will work without them):\n---\n--- - Enabled |mini.icons| module to highlight LSP kind (requires Neovim>=0.11).\n---   If absent, |MiniCompletion.default_process_items()| does not add highlighting.\n---   Also take a look at |MiniIcons.tweak_lsp_kind()|.\n--- - Enabled |mini.snippets| module for better snippet handling (much recommended).\n---   If absent and custom snippet insert is not configured, |vim.snippet.expand()|\n---   is used on Neovim>=0.10 (nothing extra is done on earlier versions).\n---   See |MiniCompletion.default_snippet_insert()|.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.completion').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniCompletion` which you can use for scripting or manually (with\n--- `:lua MiniCompletion.*`).\n---\n--- See |MiniCompletion.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minicompletion_config` which should have same structure as\n--- `MiniCompletion.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Suggested option values ~\n---\n--- Some options are set automatically (if not set before |MiniCompletion.setup()|):\n--- - 'completeopt' is set to \"menuone,noselect\" for less intrusive popup.\n---   To enable fuzzy matching, manually set to \"menuone,noselect,fuzzy\". Consider\n---   also adding \"nosort\" flag to preserve initial order when filtering.\n--- - 'shortmess' is appended with \"c\" flag for silent <C-n> fallback.\n--- - 'complete' gets removed \"t\" flag (if fallback action is default), as it\n---   leads to visible lags.\n---\n--- # Snippets ~\n---\n--- As per LSP specification, some completion items can be supplied in the form of\n--- snippet - a template with both pre-defined text and places (called \"tabstops\")\n--- for user to interactively change/add text during snippet session.\n---\n--- In 'mini.completion' items that will insert snippet have \"S\" symbol shown in\n--- the popup (as part of `menu` in |complete-items|). To actually insert a snippet:\n--- - Select an item via <C-n> / <C-p>. This will insert item's label (usually not\n---   full snippet) first to reduce visual flicker. The full snippet text will be\n---   shown in info window if LSP server doesn't provide its own info for an item.\n--- - Press <C-y> (|complete_CTRL-Y|) or attempt inserting a non-keyword character\n---   (like <CR>; new character will be removed). It will clear text from previous\n---   step, set cursor, and call `lsp_completion.snippet_insert` with snippet text.\n--- - Press <C-e> (|complete_CTRL-E|) to cancel snippet insert and properly end\n---   completion.\n---\n--- See |MiniCompletion.default_snippet_insert()| for overview of how to work with\n--- inserted snippets.\n---\n--- Notes:\n--- - To stop LSP server from suggesting snippets, disable (set to `false`) the\n---   following capability during LSP server start:\n---   `textDocument.completion.completionItem.snippetSupport`.\n--- - If snippet body doesn't contain tabstop, variable, tab, or newline,\n---   `lsp_completion.snippet_insert` is not called and text is inserted as-is.\n---\n--- # Notes ~\n---\n--- - A more appropriate (albeit slightly advanced) LSP completion setup is to set\n---   it not on every |BufEnter| event (default), but on every attach of LSP client.\n---   To do that:\n---     - Use in |MiniCompletion.setup()| config: >lua\n---\n---       lsp_completion = { source_func = 'omnifunc', auto_setup = false }\n--- <\n---     - Set 'omnifunc' option to exactly `v:lua.MiniCompletion.completefunc_lsp`\n---       for every client attach in an |LspAttach| event. Like this: >lua\n---\n---       local on_attach = function(args)\n---         vim.bo[args.buf].omnifunc = 'v:lua.MiniCompletion.completefunc_lsp'\n---       end\n---       vim.api.nvim_create_autocmd('LspAttach', { callback = on_attach })\n--- <\n---   This setup is not default to allow simultaneous usage of filetype-specific\n---   'omnifunc' (with manual |i_CTRL-X_CTRL-O|) and automated LSP completion.\n---\n--- - Use |MiniCompletion.get_lsp_capabilities()| to get/set information about part\n---   of LSP specification supported by module. See its help for usability notes.\n---\n--- - Uses `vim.lsp.protocol.CompletionItemKind` map in LSP step to show a readable\n---   version of item's kind. Modify it directly to change what is displayed.\n---   If you have |mini.icons| enabled, take a look at |MiniIcons.tweak_lsp_kind()|.\n---\n--- - If you have trouble using custom (overridden) |vim.ui.input()|, disable\n---   'mini.completion' for input buffer (usually based on its 'filetype').\n---\n--- # Comparisons ~\n---\n--- - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp):\n---     - Implements own popup menu to show completion candidates, while this\n---       module reuses |ins-completion-menu|.\n---     - Has more complex design which allows multiple sources, each in a form of\n---       a separate plugin. This module has two built-in: LSP and fallback.\n---     - Requires separate plugin for automated signature help.\n---     - Implements own \"ghost text\" feature, while this module does not.\n---\n--- - [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp):\n---     - Mostly similar to 'nvim-cmp' comparison: provides more features at the\n---       cost of more code and config complexity, while this module is designed\n---       to provide only a handful of \"enough\" features while relying on Neovim's\n---       built-in capabilities as much as possible.\n---     - Both provide automated signature help out of the box.\n---\n--- # Helpful mappings ~\n---\n--- If there is |mini.keymap| available, prefer using |MiniKeymap.map_multistep()|\n--- with `\"pmenu_*\"` built-in steps. See |MiniKeymap-examples| for examples.\n---\n--- To use `<Tab>` and `<S-Tab>` for navigation through completion list, make\n--- these mappings: >lua\n---\n---   local imap_expr = function(lhs, rhs)\n---     vim.keymap.set('i', lhs, rhs, { expr = true })\n---   end\n---   imap_expr('<Tab>',   [[pumvisible() ? \"\\<C-n>\" : \"\\<Tab>\"]])\n---   imap_expr('<S-Tab>', [[pumvisible() ? \"\\<C-p>\" : \"\\<S-Tab>\"]])\n--- <\n--- To get more consistent behavior of `<CR>`, you can use this template in\n--- your 'init.lua' to make customized mapping: >lua\n---\n---   _G.cr_action = function()\n---     -- If there is selected item in popup, accept it with <C-y>\n---     if vim.fn.complete_info()['selected'] ~= -1 then return '\\25' end\n---     -- Fall back to plain `<CR>`. You might want to customize according\n---     -- to other plugins. For example if 'mini.pairs' is set up, replace\n---     -- next line with `return MiniPairs.cr()`\n---     return '\\r'\n---   end\n---\n---   vim.keymap.set('i', '<CR>', 'v:lua.cr_action()', { expr = true })\n--- <\n--- # Highlight groups ~\n---\n--- - `MiniCompletionActiveParameter` - signature active parameter.\n--- - `MiniCompletionDeprecated` - candidates that marked as deprecated.\n--- - `MiniCompletionInfoBorderOutdated` - info window border when text is outdated\n---   due to explicit delay during fast movement through candidates.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minicompletion_disable` (globally) or\n--- `vim.b.minicompletion_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniCompletion\n\n--- To allow user customization, certain |User| autocommand events are\n--- triggered under common circumstances:\n---\n--- - Info and signature help window:\n---     - `MiniCompletionWindowOpen` - after opening new window.\n---     - `MiniCompletionWindowUpdate` - after updating existing window.\n---\n---     Each event's |event-data| table contains `kind` (one of \"info\" or \"signature\")\n---     and `win_id` (affected window identifier) fields.\n---@tag MiniCompletion-events\n\n-- Overall implementation design:\n-- - Completion:\n--     - On `InsertCharPre` event try to start auto completion. If needed,\n--       start timer which after delay will start completion process. Stop this\n--       timer if it is not needed.\n--     - When timer is activated, first execute LSP source (if set up and there\n--       is an active LSP client) by calling built-in complete function\n--       (`completefunc` or `omnifunc`) which tries LSP completion by\n--       asynchronously sending LSP 'textDocument/completion' request to all\n--       LSP clients. When all are done, execute callback which processes\n--       results, stores them in LSP cache and reruns built-in complete\n--       function which produces completion popup.\n--     - If previous step didn't result into any completion, execute (in Insert\n--       mode and if no popup) fallback action.\n-- - Documentation:\n--     - On `CompleteChanged` start auto info with similar to completion timer\n--       pattern.\n--     - If timer is activated, try these sources of item info:\n--         - 'info' field of completion item (see `:h complete-items`).\n--         - 'documentation' field of LSP's previously returned result.\n--         - 'documentation' field in result of asynchronous\n--           'completeItem/resolve' LSP request.\n--     - If info doesn't consist only from whitespace, show floating window\n--       with its content. Its dimensions and position are computed based on\n--       current state of Neovim's data and content itself (which will be\n--       displayed wrapped with `linebreak` option).\n-- - Signature help (similar to item info):\n--     - On `CursorMovedI` start auto signature (if there is any active LSP\n--       client) with similar to completion timer pattern. Better event might\n--       be `InsertCharPre` but there are issues with 'autopair-type' plugins.\n--       Update immediately if already shown or after delay if character to the\n--       left is signature help trigger (after delay has passed).\n--     - If timer is activated, send 'textDocument/signatureHelp' request to\n--       all LSP clients. On callback, process their results. Window is opened\n--       if not already with the same text (its characteristics are computed\n--       similar to item info). For every LSP client it shows only active\n--       signature (in case there are many). If LSP response has data about\n--       active parameter, it is highlighted with\n--       `MiniCompletionActiveParameter` highlight group.\n\n-- Module definition ==========================================================\nlocal MiniCompletion = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniCompletion.config|.\n---\n---@usage >lua\n---   require('mini.completion').setup() -- use default config\n---   -- OR\n---   require('mini.completion').setup({}) -- replace {} with your config table\n--- <\nMiniCompletion.setup = function(config)\n  -- Export module\n  _G.MiniCompletion = MiniCompletion\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniCompletion.config = {\n  -- Delay (debounce type, in ms) between certain Neovim event and action.\n  -- This can be used to (virtually) disable certain automatic actions by\n  -- setting very high delay time (like 10^7).\n  delay = { completion = 100, info = 100, signature = 50 },\n\n  -- Configuration for action windows:\n  -- - `height` and `width` are maximum dimensions.\n  -- - `border` defines border (as in `nvim_open_win()`; default \"single\").\n  window = {\n    info = { height = 25, width = 80, border = nil },\n    signature = { height = 25, width = 80, border = nil },\n  },\n\n  -- Way of how module does LSP completion\n  lsp_completion = {\n    -- `source_func` should be one of 'completefunc' or 'omnifunc'.\n    source_func = 'completefunc',\n\n    -- `auto_setup` should be boolean indicating if LSP completion is set up\n    -- on every `BufEnter` event.\n    auto_setup = true,\n\n    -- A function which takes LSP 'textDocument/completion' response items\n    -- (each with `client_id` field for item's server) and word to complete.\n    -- Output should be a table of the same nature as input. Common use case\n    -- is custom filter/sort. Default: `default_process_items`\n    process_items = nil,\n\n    -- A function which takes a snippet as string and inserts it at cursor.\n    -- Default: `default_snippet_insert` which tries to use 'mini.snippets'\n    -- and falls back to `vim.snippet.expand` (on Neovim>=0.10).\n    snippet_insert = nil,\n  },\n\n  -- Fallback action as function/string. Executed in Insert mode.\n  -- To use built-in completion (`:h ins-completion`), set its mapping as\n  -- string. Example: set '<C-x><C-l>' for 'whole lines' completion.\n  fallback_action = '<C-n>',\n\n  -- Module mappings. Use `''` (empty string) to disable one. Some of them\n  -- might conflict with system mappings.\n  mappings = {\n    -- Force two-step/fallback completions\n    force_twostep = '<C-Space>',\n    force_fallback = '<A-Space>',\n\n    -- Scroll info/signature window down/up. When overriding, check for\n    -- conflicts with built-in keys for popup menu (like `<C-u>`/`<C-o>`\n    -- for 'completefunc'/'omnifunc' source function; or `<C-n>`/`<C-p>`).\n    scroll_down = '<C-f>',\n    scroll_up = '<C-b>',\n  },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Run two-stage completion\n---\n---@param fallback boolean|nil Whether to use fallback completion. Default: `true`.\n---@param force boolean|nil Whether to force update of completion popup.\n---   Default: `true`.\nMiniCompletion.complete_twostage = function(fallback, force)\n  if H.is_disabled() then return end\n  if fallback == nil then fallback = true end\n  if force == nil then force = true end\n\n  H.stop_completion()\n  H.completion.fallback, H.completion.force = fallback, force\n  H.trigger_twostep()\nend\n\n--- Run fallback completion\nMiniCompletion.complete_fallback = function()\n  if H.is_disabled() then return end\n\n  H.stop_completion()\n  H.completion.fallback, H.completion.force = true, true\n  H.trigger_fallback()\nend\n\n--- Scroll in info/signature window\n---\n--- Designed to be used in |:map-<expr>|.\n--- Scrolling is done as if |CTRL-F| and |CTRL-B| is pressed inside target window.\n--- Used in default `config.mappings.scroll_xxx` mappings.\n---\n---@param direction string One of `\"down\"` or `\"up\"`.\n---\n---@return boolean Whether scroll is scheduled to be done.\nMiniCompletion.scroll = function(direction)\n  if not (direction == 'down' or direction == 'up') then H.error('`direction` should be one of \"up\" or \"down\"') end\n  local win_id = H.is_valid_win(H.info.win_id) and H.info.win_id\n    or (H.is_valid_win(H.signature.win_id) and H.signature.win_id or nil)\n  if win_id == nil then return false end\n\n  -- Schedule execution as scrolling is not allowed in expression mappings\n  local key = direction == 'down' and '\\6' or '\\2'\n  vim.schedule(function()\n    if not H.is_valid_win(win_id) then return end\n    vim.api.nvim_win_call(win_id, function() vim.cmd('noautocmd normal! ' .. key) end)\n  end)\n  return true\nend\n\n--- Stop actions\n---\n--- This stops currently active (because of module delay or LSP answer delay)\n--- actions.\n---\n--- Designed to be used with |autocmd|. No need to use it directly, everything\n--- is setup in |MiniCompletion.setup()|.\n---\n---@param actions table|nil Array containing any of 'completion', 'info', or\n---   'signature' string. Default: array containing all of them.\nMiniCompletion.stop = function(actions)\n  actions = actions or { 'completion', 'info', 'signature' }\n  for _, n in ipairs(actions) do\n    H.stop_actions[n]()\n  end\nend\n\n--- Module's |complete-functions|\n---\n--- This is the main function which enables two-stage completion. It should be\n--- set as one of |'completefunc'| or |'omnifunc'|.\n---\n--- No need to use it directly, everything is setup in |MiniCompletion.setup()|.\nMiniCompletion.completefunc_lsp = function(findstart, base)\n  -- Early return\n  if not H.has_lsp_clients('completionProvider') or H.completion.lsp.status == 'sent' then\n    return findstart == 1 and -3 or {}\n  end\n\n  -- NOTE: having code for request inside this function enables its use\n  -- directly with `<C-x><...>` and as a reaction to `<BS>`.\n  if H.completion.lsp.status ~= 'received' then\n    -- NOTE: it is CRUCIAL to make LSP request on the first call to\n    -- 'complete-function' (as in Vim's help). This is due to the fact that\n    -- cursor line and position are different on the first and second calls to\n    -- 'complete-function'. For example, when calling this function at the end\n    -- of the line '  he', cursor position on the first call will be\n    -- (<linenum>, 4) and line will be '  he' but on the second call -\n    -- (<linenum>, 2) and '  ' (because 2 is a column of completion start).\n    --\n    -- This request is not executed on second call because it returns `-3` on\n    -- first call (which means cancel and leave completion mode).\n    H.make_completion_request()\n\n    -- End completion and wait for LSP callback to re-trigger this\n    return findstart == 1 and -3 or {}\n  else\n    if findstart == 1 then\n      local from, to = H.get_completion_range(H.completion.lsp.result)\n      -- Cache initial completion state to revert to it when inserting snippet\n      -- NOTE: Track only length of base for performance, since this is enough\n      H.completion.init_base = { lnum = from[1], col = from[2], length = math.max(to[2] - from[2], 0) }\n      return from[2]\n    end\n\n    local is_incomplete = false\n    local all_items = H.process_lsp_response(H.completion.lsp.result, function(response, client_id)\n      is_incomplete = is_incomplete or (response.isIncomplete == true)\n      -- Response can be `CompletionList` with 'items' field plus their\n      -- defaults or `CompletionItem[]`\n      local items = H.table_get(response, { 'items' }) or response\n      if type(items) ~= 'table' then return {} end\n\n      items = H.apply_item_defaults(items, response.itemDefaults)\n      for _, item in ipairs(items) do\n        item.client_id = client_id\n      end\n      return items\n    end)\n\n    -- Process items\n    local process_items = H.get_config().lsp_completion.process_items or MiniCompletion.default_process_items\n    all_items = process_items(all_items, base)\n    local candidates = H.lsp_completion_response_items_to_complete_items(all_items)\n\n    H.completion.lsp.status = 'done'\n    H.completion.lsp.is_incomplete = is_incomplete\n\n    -- Maybe trigger fallback action\n    if vim.tbl_isempty(candidates) and H.completion.fallback then return H.trigger_fallback() end\n\n    -- Track from which source is current popup\n    H.completion.source = 'lsp'\n    return candidates\n  end\nend\n\n--- Default processing of LSP items\n---\n--- Steps:\n--- - Filter and sort items according to supplied method.\n--- - Arrange items further by completion item kind according to their priority.\n--- - Add `MiniCompletionDeprecated` <abbr_hlgroup> if item is marked as deprecated.\n--- - If |mini.icons| is enabled, add <kind_hlgroup> based on the \"lsp\" category.\n---\n--- Example of forcing fuzzy matching, filtering out `Text` items, and putting\n--- `Snippet` items last: >lua\n---\n---   local kind_priority = { Text = -1, Snippet = 99 }\n---   local opts = { filtersort = 'fuzzy', kind_priority = kind_priority }\n---   local process_items = function(items, base)\n---     return MiniCompletion.default_process_items(items, base, opts)\n---   end\n---   require('mini.completion').setup({\n---     lsp_completion = { process_items = process_items },\n---   })\n--- <\n---@param items table Array of items from LSP response.\n---@param base string Base for which completion is done. See |complete-functions|.\n---@param opts table|nil Options. Possible fields:\n---   - <filtersort> `(string|function)` - method of filtering and sorting items.\n---     If string, should be one of the following:\n---       - `'prefix'` - filter out items not starting with `base`, sort according\n---         to LSP specification. Use `filterText` and `sortText` respectively with\n---         fallback to `label`.\n---       - `'fuzzy'` - filter and sort with |matchfuzzy()| using `filterText`.\n---       - `'none'` - no filter and no sort.\n---     If callable, should take `items` and `base` arguments and return items array.\n---     Default: `'fuzzy'` if 'completeopt' contains \"fuzzy\", `'prefix'` otherwise.\n---   - <kind_priority> `(table)` - map of completion item kinds (like `Variable`,\n---     `Snippet`; see string keys of `vim.lsp.protocol.CompletionItemKind`) to\n---     their numerical priority. It will be used after applying <filtersort> to\n---     arrange by completion item kind: items with negative priority kinds will\n---     be filtered out, the rest are sorted by decreasing priority (preserving\n---     order in case of same priority).\n---     Priorities can be any number, only matters how they compare to each other.\n---     Value 100 is used for missing kinds (i.e. not all can be supplied).\n---     Default: `{}` (all equal priority).\n---\n---@return table Array of processed items from LSP response.\nMiniCompletion.default_process_items = function(items, base, opts)\n  opts = opts or {}\n\n  -- Filter+sort (important with frequent `isIncomplete`)\n  local fs = opts.filtersort or (vim.o.completeopt:find('fuzzy') ~= nil and 'fuzzy' or 'prefix')\n  if type(fs) == 'string' then fs = H.filtersort_methods[fs] end\n  if not vim.is_callable(fs) then H.error('`filtersort` should be callable or one of \"prefix\", \"fuzzy\", \"none\"') end\n  local res = fs(items, base)\n\n  -- Arrange by kind\n  if opts.kind_priority ~= nil then res = H.lsp_arrange_by_kind(res, opts.kind_priority) end\n\n  -- Add custom highlighting\n  local add_abbr_hlgroup = H.make_add_abbr_hlgroup()\n  local add_kind_hlgroup = H.make_add_kind_hlgroup()\n  for _, item in ipairs(res) do\n    add_abbr_hlgroup(item)\n    add_kind_hlgroup(item)\n  end\n  return res\nend\n\n--- Default snippet insert\n---\n--- Order of preference:\n--- - Use |mini.snippets| if set up (i.e. after `require('mini.snippets').setup()`).\n--- - Use |vim.snippet.expand()| on Neovim>=0.10\n--- - Add snippet text at cursor as is.\n---\n--- After snippet is inserted, user is expected to navigate/jump between dedicated\n--- places (tabstops) to adjust inserted text as needed:\n--- - |mini.snippets| by default uses <C-l> / <C-h> to jump to next/previous tabstop.\n---   Can be adjusted in `mappings` of |MiniSnippets.config|.\n--- - |vim.snippet| on Neovim=0.10 requires manually created mappings for jumping\n---   between tabstops (see |vim.snippet.jump()|). Neovim>=0.11 sets them up\n---   automatically to <Tab> / <S-Tab> (if not overridden by user).\n---\n--- End session by navigating all the way to the last tabstop. In 'mini.snippets':\n--- - Also make any text edit or exit Insert mode to end the session. This allows\n---   smoother navigation to previous tabstops in case of a lately spotted typo.\n--- - Press `<C-c>` to force session stop.\n---\n---@param snippet string Snippet body to insert at cursor.\n---\n---@seealso - |MiniSnippets-session| if 'mini.snippets' is set up.\n--- - |vim.snippet| for Neovim's built-in snippet engine.\nMiniCompletion.default_snippet_insert = function(snippet)\n  if _G.MiniSnippets then\n    local insert = MiniSnippets.config.expand.insert or MiniSnippets.default_insert\n    return insert({ body = snippet })\n  end\n  if vim.fn.has('nvim-0.10') == 1 then return vim.snippet.expand(snippet) end\n\n  local pos, lines = vim.api.nvim_win_get_cursor(0), vim.split(snippet, '\\n')\n  vim.api.nvim_buf_set_text(0, pos[1] - 1, pos[2], pos[1] - 1, pos[2], lines)\n  local n = #lines\n  local new_pos = n == 1 and { pos[1], pos[2] + lines[n]:len() } or { pos[1] + n - 1, lines[n]:len() }\n  vim.api.nvim_win_set_cursor(0, new_pos)\nend\n\n--- Get client LSP capabilities\n---\n--- Possible usages:\n--- - On Neovim>=0.11 via |vim.lsp.config()|: >lua\n---\n---   vim.lsp.config('*', {capabilities = MiniCompletion.get_lsp_capabilities()})\n--- <\n--- - Together with |vim.lsp.protocol.make_client_capabilities()| to get the full\n---   client capabilities (use |vim.tbl_deep_extend()| to merge tables).\n---\n--- - Manually execute `:=MiniCompletion.get_lsp_capabilities()` to see the info.\n---\n--- Notes:\n--- - It declares completion resolve support for `'additionalTextEdits'` (usually\n---   used for something like auto-import feature), as it is usually a more robust\n---   choice for various LSP servers. As a consequence, this requires selecting\n---   completion item and waiting for `config.delay.info` milliseconds plus server\n---   response time (i.e. until information window shows relevant text).\n---   To not have to wait after an item selection and if the server handles absent\n---   `'additionalTextEdits'` well, set `opts.resolve_additional_text_edits = false`.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <resolve_additional_text_edits> `(boolean)` - whether to declare\n---     `'additionalTextEdits'` as possible to resolve in `'completionitem/resolve'`\n---     requrest. See above \"Notes\" section.\n---     Default: `true`.\n---\n---@return table Data about LSP capabilities supported by 'mini.completion'. Has same\n---   structure as relevant parts of |vim.lsp.protocol.make_client_capabilities()|.\n---\n---@seealso Structures of `completionClientCapabilities` and `signatureHelpClientCapabilities`\n--- at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification\nMiniCompletion.get_lsp_capabilities = function(opts)\n  opts = vim.tbl_extend('force', { resolve_additional_text_edits = true }, opts or {})\n\n  local resolve_support = { 'detail', 'documentation' }\n  if opts.resolve_additional_text_edits then table.insert(resolve_support, 1, 'additionalTextEdits') end\n\n  local tag_valueset = vim.fn.has('nvim-0.11') == 1 and { vim.lsp.protocol.CompletionTag.Deprecated } or {}\n\n  return {\n    textDocument = {\n      -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionClientCapabilities\n      completion = {\n        dynamicRegistration = false,\n        completionItem = {\n          snippetSupport = true,\n          commitCharactersSupport = false,\n          documentationFormat = { 'markdown', 'plaintext' },\n          deprecatedSupport = true,\n          preselectSupport = false,\n          tagSupport = { valueSet = tag_valueset },\n          insertReplaceSupport = true,\n          resolveSupport = { properties = resolve_support },\n          insertTextModeSupport = { valueSet = { 1 } },\n          labelDetailsSupport = true,\n        },\n        completionItemKind = {\n          valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 },\n        },\n        contextSupport = true,\n        insertTextMode = 1,\n        completionList = {\n          itemDefaults = { 'commitCharacters', 'editRange', 'insertTextFormat', 'insertTextMode', 'data' },\n        },\n      },\n      -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#signatureHelpClientCapabilities\n      signatureHelp = {\n        dynamicRegistration = false,\n        signatureInformation = {\n          documentationFormat = { 'markdown', 'plaintext' },\n          parameterInformation = {\n            labelOffsetSupport = true,\n          },\n          activeParameterSupport = true,\n        },\n        contextSupport = false,\n      },\n    },\n  }\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniCompletion.config)\n\n-- Track Insert mode changes\nH.text_changed_id = 0\n\n-- Namespace for highlighting\nH.ns_id = vim.api.nvim_create_namespace('MiniCompletion')\n\n-- Commonly used key sequences\nH.keys = {\n  completefunc = vim.api.nvim_replace_termcodes('<C-x><C-u>', true, false, true),\n  omnifunc = vim.api.nvim_replace_termcodes('<C-x><C-o>', true, false, true),\n  ctrl_n = vim.api.nvim_replace_termcodes('<C-g><C-g><C-n>', true, false, true),\n}\n\n-- Flags for whether there is support for dedicated options\nH.has_no_winborder = vim.fn.has('nvim-0.11') == 0\nH.has_pumborder = vim.fn.exists('+pumborder') == 1 -- Neovim>=0.12\n\n-- Caches for different actions -----------------------------------------------\n-- Field `lsp` is a table describing state of all used LSP requests. It has the\n-- following structure:\n-- - id: identifier (consecutive numbers).\n-- - status: one of 'sent', 'received', 'done', 'canceled'\n-- - is_incomplete: whether request was incomplete and require recomputing\n-- - result: result of request.\n-- - cancel_fun: function which cancels current request.\n\n-- Cache for completion\nH.completion = {\n  fallback = true,\n  force = false,\n  source = nil,\n  text_changed_id = 0,\n  timer = vim.loop.new_timer(),\n  lsp = { id = 0, status = nil, is_incomplete = false, result = nil, resolved = {}, cancel_fun = nil, context = nil },\n  init_base = { lnum = nil, col = nil, length = nil },\n}\n\n-- Cache for completion item info\nH.info = {\n  bufnr = nil,\n  event = nil,\n  id = 0,\n  timer = vim.loop.new_timer(),\n  win_id = nil,\n  lsp = { id = 0, status = nil, result = nil, cancel_fun = nil },\n}\n\n-- Cache for signature help\nH.signature = {\n  bufnr = nil,\n  text = nil,\n  timer = vim.loop.new_timer(),\n  win_id = nil,\n  lsp = { id = 0, status = nil, result = nil, cancel_fun = nil },\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('delay', config.delay, 'table')\n  H.check_type('window', config.window, 'table')\n  H.check_type('lsp_completion', config.lsp_completion, 'table')\n  if not (type(config.fallback_action) == 'function' or type(config.fallback_action) == 'string') then\n    H.error('`fallback_action` should be function or string, not ' .. type(config.fallback_action))\n  end\n  H.check_type('mappings', config.mappings, 'table')\n\n  H.check_type('delay.completion', config.delay.completion, 'number')\n  H.check_type('delay.info', config.delay.info, 'number')\n  H.check_type('delay.signature', config.delay.signature, 'number')\n\n  H.check_type('window.info', config.window.info, 'table')\n  H.check_type('window.signature', config.window.signature, 'table')\n\n  if not (config.lsp_completion.source_func == 'completefunc' or config.lsp_completion.source_func == 'omnifunc') then\n    H.error('`lsp_completion.source_func` should be one of \"completefunc\" or \"omnifunc\"')\n  end\n  H.check_type('lsp_completion.auto_setup', config.lsp_completion.auto_setup, 'boolean')\n  H.check_type('lsp_completion.process_items', config.lsp_completion.process_items, 'callable', true)\n  H.check_type('lsp_completion.snippet_insert', config.lsp_completion.snippet_insert, 'callable', true)\n\n  H.check_type('mappings.force_twostep', config.mappings.force_twostep, 'string')\n  H.check_type('mappings.force_fallback', config.mappings.force_fallback, 'string')\n  H.check_type('mappings.scroll_down', config.mappings.scroll_down, 'string')\n  H.check_type('mappings.scroll_up', config.mappings.scroll_up, 'string')\n\n  local is_string_or_array = function(x) return type(x) == 'string' or H.islist(x) end\n  H.check_type('window.info.height', config.window.info.height, 'number')\n  H.check_type('window.info.width', config.window.info.width, 'number')\n  if not is_string_or_array(config.window.info.border or 'single') then\n    H.error('`config.window.info.border` should be either string or array, not ' .. type(config.window.info.border))\n  end\n  H.check_type('window.signature.height', config.window.signature.height, 'number')\n  H.check_type('window.signature.width', config.window.signature.width, 'number')\n  if not is_string_or_array(config.window.signature.border or 'single') then\n    H.error(\n      '`config.window.signature.border` should be either string or array, not ' .. type(config.window.signature.border)\n    )\n  end\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniCompletion.config = config\n\n  H.map('i', config.mappings.force_twostep, MiniCompletion.complete_twostage, { desc = 'Complete with two-stage' })\n  H.map('i', config.mappings.force_fallback, MiniCompletion.complete_fallback, { desc = 'Complete with fallback' })\n\n  local map_scroll = function(lhs, direction)\n    local rhs = function() return MiniCompletion.scroll(direction) and '' or lhs end\n    H.map('i', lhs, rhs, { expr = true, desc = 'Scroll info/signature ' .. direction })\n  end\n  map_scroll(config.mappings.scroll_down, 'down')\n  map_scroll(config.mappings.scroll_up, 'up')\n\n  -- Try setting suggested option values\n  -- - More common completion behavior\n  local was_set = vim.api.nvim_get_option_info2('completeopt', { scope = 'global' }).was_set\n  if not was_set then vim.o.completeopt = 'menuone,noselect' end\n\n  -- - Don't show ins-completion-menu messages (\"C\" is default on Neovim>=0.10)\n  local shortmess_flags = 'c' .. (vim.fn.has('nvim-0.10') == 0 and 'C' or '')\n  was_set = vim.api.nvim_get_option_info2('shortmess', { scope = 'global' }).was_set\n  if not was_set then vim.opt.shortmess:append(shortmess_flags) end\n\n  -- - Remove \"t\" flag to reduce visible lags\n  was_set = vim.api.nvim_get_option_info2('complete', { scope = 'global' }).was_set\n  if not was_set and config.fallback_action == '<C-n>' then vim.opt.complete:remove('t') end\nend\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniCompletion', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('InsertCharPre', '*', H.auto_completion, 'Auto show completion')\n  au('CompleteChanged', '*', H.auto_info, 'Auto show info')\n  au('CursorMovedI', '*', H.auto_signature, 'Auto show signature')\n  au('ModeChanged', 'i*:[^i]*', function() MiniCompletion.stop() end, 'Stop completion')\n  au('CompleteDonePre', '*', H.on_completedonepre, 'On CompleteDonePre')\n  au('TextChangedI', '*', H.on_text_changed_i, 'On TextChangedI')\n  au('TextChangedP', '*', H.on_text_changed_p, 'On TextChangedP')\n\n  if config.lsp_completion.auto_setup then\n    local source_func = config.lsp_completion.source_func\n    local callback = function() vim.bo[source_func] = 'v:lua.MiniCompletion.completefunc_lsp' end\n    au('BufEnter', '*', callback, 'Set completion function')\n  end\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\n  au('FileType', 'TelescopePrompt', function() vim.b.minicompletion_disable = true end, 'Disable locally')\nend\n\nH.create_default_hl = function()\n  vim.api.nvim_set_hl(0, 'MiniCompletionActiveParameter', { default = true, link = 'LspSignatureActiveParameter' })\n  vim.api.nvim_set_hl(0, 'MiniCompletionDeprecated', { default = true, link = 'DiagnosticDeprecated' })\n  vim.api.nvim_set_hl(0, 'MiniCompletionInfoBorderOutdated', { default = true, link = 'DiagnosticFloatingWarn' })\nend\n\nH.is_disabled = function() return vim.g.minicompletion_disable == true or vim.b.minicompletion_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniCompletion.config, vim.b.minicompletion_config or {}, config or {})\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_completion = function()\n  if H.is_disabled() then return end\n\n  H.completion.timer:stop()\n\n  local is_incomplete = H.completion.lsp.is_incomplete\n  local is_trigger = H.is_lsp_trigger(vim.v.char, 'completion')\n  local force = is_trigger or is_incomplete\n  if force then\n    -- Force fresh LSP completion if needed. Check before checking pumvisible\n    -- because it should be forced even if there are visible candidates.\n    -- Keep positive `is_incomplete` to allow fast typing and not \"forget\" that\n    -- list was incomplete after the second fast key press. This will force LSP\n    -- completion until `isIncomplete=false` response or general `stop()`.\n    H.stop_completion(false, is_incomplete)\n  elseif H.pumvisible() then\n    -- Do nothing if popup is visible. `H.pumvisible()` might be `true` even if\n    -- there is no popup. It is common when manually typing candidate followed\n    -- by an LSP trigger (like \".\").\n    -- Keep completion source as it is needed all time when popup is visible.\n    -- Keep resolved candidates because they should be relevant in this route.\n    return H.stop_completion(true, false, true)\n  elseif not H.is_char_keyword(vim.v.char) then\n    -- Stop everything if inserted character is not appropriate. Check this\n    -- after popup check to allow completion candidates to have bad characters.\n    return H.stop_completion(false)\n  end\n\n  -- Start non-forced completion with fallback or forced LSP source for trigger\n  H.completion.fallback, H.completion.force = not force, force\n\n  -- Cache id of Insert mode \"text changed\" event for a later tracking (reduces\n  -- false positive delayed triggers). The intention is to trigger completion\n  -- after the delay only if text wasn't changed during waiting. Using only\n  -- `InsertCharPre` is not enough though, as not every Insert mode change\n  -- triggers `InsertCharPre` event (notable example - hitting `<CR>`).\n  -- Also, using `+ 1` here because it is a `Pre` event and needs to cache\n  -- after inserting character.\n  H.completion.text_changed_id = H.text_changed_id + 1\n\n  -- If completion was requested after 'lsp' source exhausted itself (there\n  -- were matches on typing start, but they disappeared during filtering), call\n  -- fallback immediately.\n  if H.completion.source == 'lsp' then return H.trigger_fallback() end\n\n  -- Set completion context with information about how it was triggered\n  -- Prefer manual `TriggerCharacter` over automated `...ForIncomplete...`.\n  local trigger_kind_name = is_trigger and 'TriggerCharacter'\n    or (is_incomplete and 'TriggerForIncompleteCompletions' or 'Invoked')\n  local trigger_kind = vim.lsp.protocol.CompletionTriggerKind[trigger_kind_name]\n  local trigger_char = trigger_kind_name == 'TriggerCharacter' and vim.v.char or nil\n  H.completion.lsp.context = { triggerKind = trigger_kind, triggerCharacter = trigger_char }\n\n  -- Debounce delay improves experience (can type fast without many popups)\n  -- Request right away if improving incomplete suggestions (less flickering),\n  -- but still with `vim.schedule` because line is still not up to date during\n  -- `InsertCharPre` event.\n  local delay = is_incomplete and 0 or H.get_config().delay.completion\n  H.completion.timer:start(delay, 0, vim.schedule_wrap(H.trigger_twostep))\nend\n\nH.auto_info = function()\n  if H.is_disabled() then return end\n\n  -- Stop current LSP request that tries to get already not current data\n  H.cancel_lsp({ H.info })\n\n  -- Update metadata before leaving to register a `CompleteChanged` event\n  H.info.timer:stop()\n  H.info.event = vim.v.event\n  H.info.id = H.info.id + 1\n\n  -- Stop showing window if no candidate is selected\n  local completed_item = H.info.event.completed_item or {}\n  if completed_item.word == nil then\n    return vim.schedule(function() H.close_action_window(H.info) end)\n  end\n\n  -- Show info content without delay for visited and resolved LSP item.\n  -- Otherwise delay to not spam LSP requests on up/down navigation.\n  local item_id = H.table_get(completed_item, { 'user_data', 'lsp', 'item_id' })\n  local is_resolved = item_id == nil or H.completion.lsp.resolved[item_id] ~= nil\n  local delay = is_resolved and 0 or H.get_config().delay.info\n\n  -- Mark visually that currently shown content will be outdated for a while\n  local win_id = H.info.win_id\n  if H.is_valid_win(win_id) and delay > 0 then\n    vim.wo[win_id].winhighlight = vim.wo[win_id].winhighlight .. ',FloatBorder:MiniCompletionInfoBorderOutdated'\n  end\n  local cur_info_id = H.info.id\n  H.info.timer:start(delay, 0, function() H.show_info_window(cur_info_id) end)\nend\n\nH.auto_signature = function()\n  if H.is_disabled() then return end\n\n  H.signature.timer:stop()\n  if not H.has_lsp_clients('signatureHelpProvider') then return end\n\n  local is_shown = H.is_valid_win(H.signature.win_id)\n  local left_char_is_trigger = H.is_lsp_trigger(H.get_left_char(), 'signature')\n  if not (is_shown or left_char_is_trigger) then return end\n\n  local delay = is_shown and 0 or H.get_config().delay.signature\n  H.signature.timer:start(delay, 0, vim.schedule_wrap(H.show_signature_window))\nend\n\nH.on_completedonepre = function()\n  -- Do nothing if it is triggered inside `trigger_lsp()` as a result of\n  -- emulating 'completefunc'/'omnifunc' keys. This can happen if popup is\n  -- visible and pressing keys first hides it with 'CompleteDonePre' event.\n  if H.completion.lsp.status == 'received' then return end\n\n  -- Do extra actions for LSP completion items\n  local lsp_data = H.table_get(vim.v.completed_item, { 'user_data', 'lsp' })\n  if lsp_data ~= nil then H.make_lsp_extra_actions(lsp_data) end\n\n  -- Stop processes\n  MiniCompletion.stop({ 'completion', 'info' })\nend\n\nH.on_text_changed_i = function()\n  -- Track Insert mode changes\n  H.text_changed_id = H.text_changed_id + 1\n\n  -- Stop 'info' processes in case no completion event is triggered but popup\n  -- is not visible. See https://github.com/neovim/neovim/issues/15077\n  H.stop_info()\nend\n\nH.on_text_changed_p = function()\n  -- Track Insert mode changes\n  H.text_changed_id = H.text_changed_id + 1\nend\n\n-- Completion triggers --------------------------------------------------------\nH.trigger_twostep = function()\n  -- Trigger only in Insert mode and if text didn't change after trigger\n  -- request, unless completion is forced\n  -- NOTE: check for `text_changed_id` equality is still not 100% solution as\n  -- there are cases when, for example, `<CR>` is hit just before this check.\n  -- Because of asynchronous id update and this function call (called after\n  -- delay), these still match.\n  local allow_trigger = (vim.fn.mode() == 'i')\n    and (H.completion.force or (H.completion.text_changed_id == H.text_changed_id))\n  if not allow_trigger then return end\n\n  if H.has_lsp_clients('completionProvider') and H.has_lsp_completion() then\n    H.trigger_lsp()\n  elseif H.completion.fallback then\n    H.trigger_fallback()\n  end\nend\n\nH.trigger_lsp = function()\n  -- Check for popup visibility is needed to reduce flickering.\n  -- Possible issue timeline (with 100ms delay with set up LSP):\n  -- 0ms: Key is pressed.\n  -- 100ms: LSP is triggered from first key press.\n  -- 110ms: Another key is pressed.\n  -- 200ms: LSP callback is processed, triggers complete-function which\n  --   processes \"received\" LSP request.\n  -- 201ms: LSP request is processed, completion is (should be almost\n  --   immediately) provided, request is marked as \"done\".\n  -- 210ms: LSP is triggered from second key press. As previous request is\n  --   \"done\", it will once make whole LSP request. Having check for visible\n  --   popup should prevent here the call to complete-function.\n\n  -- Do not trigger if not needed and/or allowed\n  if vim.fn.mode() ~= 'i' or (H.pumvisible() and not H.completion.force) then return end\n\n  -- Overall idea: first make LSP request and re-trigger this same function\n  -- inside its callback to take the \"received\" route. This reduces flickering\n  -- in case popup is visible (like for `isIncomplete` and trigger characters)\n  -- as pressing 'completefunc'/'omnifunc' keys first hides completion menu.\n  -- There are still minor visual defects: typing new character reduces number\n  -- of matched items which can visually shrink popup while later increase it\n  -- again after LSP response is received. This is usually fine (especially\n  -- with not huge 'pumheight').\n  if H.completion.lsp.status ~= 'received' then return H.make_completion_request() end\n  local keys = H.keys[H.get_config().lsp_completion.source_func]\n  vim.api.nvim_feedkeys(keys, 'n', false)\nend\n\nH.trigger_fallback = function()\n  -- Fallback only in Insert mode when no popup is visible\n  local has_popup = H.pumvisible() and not H.completion.force\n  if has_popup or vim.fn.mode() ~= 'i' then return end\n\n  -- Track from which source is current popup\n  H.completion.source = 'fallback'\n\n  -- Execute fallback action\n  local fallback_action = H.get_config().fallback_action or H.default_fallback_action\n  fallback_action = fallback_action == '<C-n>' and H.default_fallback_action or fallback_action\n  if vim.is_callable(fallback_action) then return fallback_action() end\n  if type(fallback_action) ~= 'string' then return end\n\n  -- Having `<C-g><C-g>` also (for some mysterious reason) helps to avoid\n  -- some weird behavior. For example, if `keys = '<C-x><C-l>'` then Neovim\n  -- starts new line when there is no suggestions.\n  local keys = string.format('<C-g><C-g>%s', fallback_action)\n  local trigger_keys = vim.api.nvim_replace_termcodes(keys, true, false, true)\n  vim.api.nvim_feedkeys(trigger_keys, 'n', false)\nend\n\nH.default_fallback_action = function() vim.api.nvim_feedkeys(H.keys.ctrl_n, 'n', false) end\n\n-- Stop actions ---------------------------------------------------------------\nH.stop_completion = function(keep_source, keep_lsp_is_incomplete, keep_lsp_resolved)\n  H.completion.timer:stop()\n  H.cancel_lsp({ H.completion })\n  H.completion.lsp.context = nil\n  H.completion.fallback, H.completion.force = true, false\n  if not keep_source then H.completion.source = nil end\n  if not keep_lsp_is_incomplete then H.completion.lsp.is_incomplete = false end\n  if not keep_lsp_resolved then H.completion.lsp.resolved = {} end\nend\n\nH.stop_info = function()\n  -- Id update is needed to notify that all previous work is not current\n  H.info.id = H.info.id + 1\n  H.info.timer:stop()\n  H.cancel_lsp({ H.info })\n  H.close_action_window(H.info)\nend\n\nH.stop_signature = function()\n  H.signature.text = nil\n  H.signature.timer:stop()\n  H.cancel_lsp({ H.signature })\n  H.close_action_window(H.signature)\nend\n\nH.stop_actions = {\n  completion = H.stop_completion,\n  info = H.stop_info,\n  signature = H.stop_signature,\n}\n\n-- LSP ------------------------------------------------------------------------\n---@param capability string|table|nil Server capability (possibly nested\n---   supplied via table) to check.\n---\n---@return boolean Whether at least one LSP client supports `capability`.\n---@private\nH.has_lsp_clients = function(capability)\n  local clients = H.get_buf_lsp_clients()\n  if vim.tbl_isempty(clients) then return false end\n  if not capability then return true end\n\n  for _, c in pairs(clients) do\n    local has_capability = H.table_get(c.server_capabilities, capability)\n    if has_capability then return true end\n  end\n  return false\nend\n\nH.has_lsp_completion = function()\n  local source_func = H.get_config().lsp_completion.source_func\n  local func = vim.bo[source_func]\n  return func == 'v:lua.MiniCompletion.completefunc_lsp'\nend\n\nH.is_lsp_trigger = function(char, type)\n  local triggers\n  local providers = { completion = 'completionProvider', signature = 'signatureHelpProvider' }\n\n  for _, client in ipairs(H.get_buf_lsp_clients()) do\n    triggers = H.table_get(client, { 'server_capabilities', providers[type], 'triggerCharacters' })\n    if vim.tbl_contains(triggers or {}, char) then return true end\n  end\n  return false\nend\n\nH.cancel_lsp = function(caches)\n  caches = caches or { H.completion, H.info, H.signature }\n  for _, c in ipairs(caches) do\n    if vim.tbl_contains({ 'sent', 'received' }, c.lsp.status) then\n      if c.lsp.cancel_fun then c.lsp.cancel_fun() end\n      c.lsp.status = 'canceled'\n    end\n\n    c.lsp.result, c.lsp.cancel_fun = nil, nil\n  end\nend\n\nH.process_lsp_response = function(request_result, processor)\n  if not request_result then return {} end\n\n  local res = {}\n  for client_id, item in pairs(request_result) do\n    -- TODO: Use only `.err` after compatibility with Neovim=0.10 is dropped\n    if not (item.err or item.error) and item.result then\n      vim.list_extend(res, processor(item.result, client_id) or {})\n    end\n  end\n\n  return res\nend\n\nH.is_lsp_current = function(cache, id) return cache.lsp.id == id and cache.lsp.status == 'sent' end\n\nH.filtersort_methods = {\n  prefix = function(items, base)\n    local res = vim.tbl_filter(function(x) return vim.startswith(H.lsp_get_filterword(x), base) end, items)\n    res = vim.deepcopy(res)\n    table.sort(res, H.lsp_item_compare)\n    return res\n  end,\n  fuzzy = function(items, base)\n    if base == '' then return vim.deepcopy(items) end\n    return vim.fn.matchfuzzy(items, base, { text_cb = H.lsp_get_filterword })\n  end,\n  none = function(items, _) return vim.deepcopy(items) end,\n}\n\nH.lsp_arrange_by_kind = function(items, kind_priority)\n  if type(kind_priority) ~= 'table' then H.error('`kind_priority` should be table') end\n\n  H.ensure_kind_map()\n\n  local res_raw = {}\n  for i, item in ipairs(items) do\n    local priority = kind_priority[H.kind_map[item.kind]] or 100\n    if priority >= 0 then table.insert(res_raw, { priority, i, item }) end\n  end\n\n  local compare = function(a, b) return a[1] > b[1] or (a[1] == b[1] and a[2] < b[2]) end\n  table.sort(res_raw, compare)\n  return vim.tbl_map(function(x) return x[3] end, res_raw)\nend\n\nH.lsp_get_filterword = function(x) return x.filterText or x.label end\n\nH.lsp_item_compare = function(a, b) return (a.sortText or a.label) < (b.sortText or b.label) end\n\n-- Completion -----------------------------------------------------------------\nH.make_completion_request = function()\n  local current_id = H.completion.lsp.id + 1\n  H.completion.lsp.id = current_id\n  H.completion.lsp.status = 'sent'\n\n  local context = H.completion.lsp.context or { triggerKind = vim.lsp.protocol.CompletionTriggerKind.Invoked }\n  local buf_id, params = vim.api.nvim_get_current_buf(), H.make_position_params(context)\n  -- NOTE: use `buf_request_all()` (instead of `buf_request()`) to easily\n  -- handle possible fallback and to have all completion suggestions be later\n  -- filtered with one `base`. Anyway, the most common situation is with one\n  -- attached LSP client.\n  local cancel_fun = vim.lsp.buf_request_all(buf_id, 'textDocument/completion', params, function(result)\n    if not H.is_lsp_current(H.completion, current_id) then return end\n\n    H.completion.lsp.status = 'received'\n    H.completion.lsp.result = result\n\n    -- Trigger LSP completion to use completefunc/omnifunc route\n    H.trigger_lsp()\n  end)\n\n  -- Cache cancel function to disable requests when they are not needed\n  H.completion.lsp.cancel_fun = cancel_fun\nend\n\nH.apply_item_defaults = function(items, defaults)\n  if type(defaults) ~= 'table' then return items end\n\n  local edit_range, has_edit_range = defaults.editRange, type(defaults.editRange) == 'table'\n  local edit_range_range = (edit_range or {}).start ~= nil and edit_range or nil\n  for _, item in ipairs(items) do\n    item.commitCharacters = item.commitCharacters or defaults.commitCharacters\n    item.data = item.data or defaults.data\n    item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat\n    item.insertTextMode = item.insertTextMode or defaults.insertTextMode\n    if has_edit_range then\n      item.textEdit = item.textEdit or {}\n      -- Infer new text from `item.textEditText` designed for default edit case\n      item.textEdit.newText = item.textEdit.newText or item.textEditText or item.label\n      -- Default `editRange` is range (start+end) or insert+replace ranges\n      item.textEdit.range = item.textEdit.range or edit_range_range\n      item.textEdit.insert = item.textEdit.insert or edit_range.insert\n      item.textEdit.replace = item.textEdit.replace or edit_range.replace\n    end\n  end\n  return items\nend\n\n-- Source:\n-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_completion\nH.lsp_completion_response_items_to_complete_items = function(items)\n  if vim.tbl_count(items) == 0 then return {} end\n\n  local res, item_kinds = {}, vim.lsp.protocol.CompletionItemKind\n  local snippet_kind = vim.lsp.protocol.CompletionItemKind.Snippet\n  local snippet_inserttextformat = vim.lsp.protocol.InsertTextFormat.Snippet\n  for i, item in ipairs(items) do\n    local word = H.get_completion_word(item)\n\n    local is_snippet_kind = item.kind == snippet_kind\n    local is_snippet_format = item.insertTextFormat == snippet_inserttextformat\n    -- Treat item as snippet only if it has tabstop, variable, tab, or newline.\n    -- It is important to make \"implicit\" expand work with LSP servers that\n    -- report even regular words as `InsertTextFormat.Snippet` (like `gopls`).\n    -- Otherwise it will \"eat\" the next typed non-keyword charater.\n    -- Account for tabs and newline to allow `snippet_insert` to deal with\n    -- reindenting and tab expansion.\n    local has_snippet_features = (word:find('[^\\\\]%${?%w') or word:find('^%${?%w') or word:find('[\\n\\t]')) ~= nil\n    local needs_snippet_insert = (is_snippet_kind or is_snippet_format) and has_snippet_features\n\n    local details = item.labelDetails or {}\n    -- NOTE: Using `table.concat({}, ' ')` would be cleaner but less performant\n    local snip, detail, desc = needs_snippet_insert and 'S' or '', details.detail or '', details.description or ''\n    local pad = (snip ~= '' and detail ~= '') and ' ' or ''\n    local label_detail = snip .. pad .. detail\n    pad = (label_detail ~= '' and desc ~= '') and ' ' or ''\n    label_detail = label_detail .. pad .. desc\n\n    local lsp_data = { item = item, item_id = i }\n    lsp_data.needs_snippet_insert = needs_snippet_insert\n    table.insert(res, {\n      -- Show less for snippet items (usually less confusion), but preserve\n      -- built-in filtering capabilities (as it uses `word` to filter).\n      word = needs_snippet_insert and H.lsp_get_filterword(item) or word,\n      abbr = item.label,\n      abbr_hlgroup = item.abbr_hlgroup,\n      kind = item_kinds[item.kind] or 'Unknown',\n      kind_hlgroup = item.kind_hlgroup,\n      menu = label_detail,\n      -- NOTE: info will be attempted to resolve, use snippet text as fallback\n      info = needs_snippet_insert and word or nil,\n      icase = 1,\n      dup = 1,\n      empty = 1,\n      user_data = { lsp = lsp_data },\n    })\n  end\n  return res\nend\n\nH.make_add_abbr_hlgroup = function()\n  local deprecated_tag = vim.lsp.protocol.CompletionTag.Deprecated\n  local contains = vim.list_contains\n  return function(item)\n    local is_deprecated = item.deprecated or (item.tags and contains(item.tags, deprecated_tag))\n    item.abbr_hlgroup = item.abbr_hlgroup or (is_deprecated and 'MiniCompletionDeprecated' or nil)\n  end\nend\nif vim.fn.has('nvim-0.11') == 0 then H.make_add_abbr_hlgroup = function()\n  return function() end\nend end\n\nH.make_add_kind_hlgroup = function()\n  -- Account for possible effect of `MiniIcons.tweak_lsp_kind()` which modifies\n  -- only array part of `CompletionItemKind` but not \"map\" part\n  H.ensure_kind_map()\n\n  if _G.MiniIcons == nil then\n    return function() end\n  end\n\n  return function(item)\n    local _, hl, is_default = _G.MiniIcons.get('lsp', H.kind_map[item.kind] or 'Unknown')\n    item.kind_hlgroup = item.kind_hlgroup or (not is_default and hl or nil)\n  end\nend\n\nH.ensure_kind_map = function()\n  if H.kind_map ~= nil then return end\n\n  -- Cache kind map so as to not recompute it each time (as it will be called\n  -- in performance sensitive context). Assumes `tweak_lsp_kind()` is called\n  -- right after `require('mini.icons').setup()`.\n  H.kind_map = {}\n  for k, v in pairs(vim.lsp.protocol.CompletionItemKind) do\n    if type(k) == 'string' and type(v) == 'number' then H.kind_map[v] = k end\n  end\nend\n\nH.get_completion_word = function(item)\n  return H.table_get(item, { 'textEdit', 'newText' }) or item.insertText or H.lsp_get_filterword(item) or ''\nend\n\nH.make_lsp_extra_actions = function(lsp_data)\n  -- Prefer resolved item over the one from 'textDocument/completion'\n  local item = H.completion.lsp.resolved[lsp_data.item_id] or lsp_data.item\n\n  if item.additionalTextEdits == nil and not lsp_data.needs_snippet_insert then return end\n  local snippet = lsp_data.needs_snippet_insert and H.get_completion_word(item) or nil\n\n  -- Make extra actions not only after an explicit `<C-y>` (accept completed\n  -- item), but also after implicit non-keyword character. This needs:\n  -- - Keeping track of newly added non-keyword character and cursor move (like\n  --   after 'mini.pairs') for a later undo. Do it via using expanding extmark.\n  -- - Delay actual execution to operate *after* characters are inserted (as it\n  --   is not immediate). Otherwise those characters will get \"inserted\" after\n  --   snippet is inserted and its session is active.\n  local cur = vim.api.nvim_win_get_cursor(0)\n  local extmark_opts = { end_row = cur[1] - 1, end_col = cur[2], right_gravity = false, end_right_gravity = true }\n  local track_extmark_id = vim.api.nvim_buf_set_extmark(0, H.ns_id, cur[1] - 1, cur[2], extmark_opts)\n\n  vim.schedule(function()\n    -- Do nothing if user exited Insert mode\n    if vim.fn.mode() ~= 'i' then return end\n\n    -- Undo possible non-keyword character(s) and cursor move. Do this before\n    -- text edits to have more proper state (as it was at the time edits were\n    -- created by server), but only if there is snippet (keep new characters\n    -- for *only* text edits).\n    if snippet ~= nil then\n      H.del_extmark(track_extmark_id, true)\n      pcall(vim.api.nvim_win_set_cursor, 0, cur)\n    end\n\n    -- Try to only apply additional text edits for non-snippet items\n    if snippet == nil then return H.apply_text_edits(item.client_id, item.additionalTextEdits) end\n\n    -- Revert to initial completion state to respect text edit coordinates\n    local init_base = H.completion.init_base\n    local from, to = { init_base.lnum, init_base.col }, vim.api.nvim_win_get_cursor(0)\n    -- NOTE: actual base string should not be relevant here, only byte count\n    local prefix = string.rep('x', init_base.length)\n    pcall(vim.api.nvim_buf_set_text, 0, from[1] - 1, from[2], to[1] - 1, to[2], { prefix })\n    to = { from[1], from[2] + init_base.length }\n    local prefix_extmark_opts = { end_row = to[1] - 1, end_col = to[2] }\n    local prefix_extmark_id = vim.api.nvim_buf_set_extmark(0, H.ns_id, from[1] - 1, from[2], prefix_extmark_opts)\n\n    -- Possibly adjust tracked range to come from LSP item. Clamp to existing\n    -- text state because some LSP servers update `textEdit` during resolve\n    -- (although the must not to) which can error when setting extmarks.\n    local edit_range = H.get_lsp_edit_range({ result = { item } })\n    if edit_range ~= nil then\n      local n_lines = vim.api.nvim_buf_line_count(0)\n      local start_lnum = math.min(edit_range.start.line + 1, n_lines)\n      local end_lnum = math.min(edit_range['end'].line + 1, n_lines)\n      local start_col = math.min(edit_range.start.character, vim.fn.getline(start_lnum):len())\n      local end_col = math.min(edit_range['end'].character, vim.fn.getline(end_lnum):len())\n      from, to = { start_lnum, start_col }, { end_lnum, end_col }\n    end\n\n    -- Try to apply additional text edits *after* restoring state because their\n    -- data is computed by the server at that state. Keep track of the range\n    -- that needs clearing as it might change during edits.\n    from, to = H.apply_tracked_text_edits(item.client_id, item.additionalTextEdits, from, to)\n\n    -- Expand snippet: remove base and insert at cursor\n    pcall(vim.api.nvim_buf_set_text, 0, from[1] - 1, from[2], to[1] - 1, to[2], { '' })\n    -- - Ensure to work with bad `textEdit`, like not covering cursor position\n    vim.api.nvim_win_set_cursor(0, from)\n    H.del_extmark(prefix_extmark_id, true)\n    local insert = H.get_config().lsp_completion.snippet_insert or MiniCompletion.default_snippet_insert\n    insert(snippet)\n  end)\nend\n\nH.apply_text_edits = function(client_id, text_edits)\n  if text_edits == nil then return end\n  local offset_encoding = client_id == nil and 'utf-16' or vim.lsp.get_client_by_id(client_id).offset_encoding\n  vim.lsp.util.apply_text_edits(text_edits, vim.api.nvim_get_current_buf(), offset_encoding)\nend\n\nH.apply_tracked_text_edits = function(client_id, text_edits, from, to)\n  if text_edits == nil then return from, to end\n\n  -- Prepare extmarks to track relevant positions\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  local cursor_extmark_id = vim.api.nvim_buf_set_extmark(0, H.ns_id, cur_pos[1] - 1, cur_pos[2], {})\n\n  local from_extmark_id = vim.api.nvim_buf_set_extmark(0, H.ns_id, from[1] - 1, from[2], {})\n  local to_extmark_id = vim.api.nvim_buf_set_extmark(0, H.ns_id, to[1] - 1, to[2], {})\n\n  -- Do text edits\n  H.apply_text_edits(client_id, text_edits)\n\n  -- Restore cursor position\n  local cursor_data = H.del_extmark(cursor_extmark_id)\n  pcall(vim.api.nvim_win_set_cursor, 0, { cursor_data[1] + 1, cursor_data[2] })\n\n  -- Update in place tracked range\n  local from_data = H.del_extmark(from_extmark_id)\n  local to_data = H.del_extmark(to_extmark_id)\n  return { from_data[1] + 1, from_data[2] }, { to_data[1] + 1, to_data[2] }\nend\n\n-- Completion item info -------------------------------------------------------\nH.show_info_window = vim.schedule_wrap(function(info_id)\n  -- Do nothing if completion item was changed. For example, after autoinvoked\n  -- in timer with zero delay but after it there is another `CompleteChanged`\n  -- that closes popup. This only stops the timer *but* not actually cancelling\n  -- this function.\n  if H.info.id ~= info_id then return end\n\n  -- Get info lines to show. Wait for resolve if returned `false`.\n  local lines = H.info_window_lines(info_id)\n  if lines == false then return end\n  if lines == nil or H.is_whitespace(lines) then lines = { '-No-info-' } end\n\n  -- Ensure permanent buffer with \"markdown\" highlighting to display info\n  H.ensure_buffer(H.info, 'item-info')\n  H.ensure_highlight(H.info, 'markdown')\n  H.ensure_no_concealed_lines(H.info.bufnr)\n  vim.api.nvim_buf_set_lines(H.info.bufnr, 0, -1, false, lines)\n\n  -- Compute floating window options\n  local opts = H.info_window_options()\n\n  -- Adjust section separator with better visual alternative\n  lines = vim.tbl_map(function(l) return l:gsub('^%-%-%-%-*$', string.rep('─', opts.width)) end, lines)\n  vim.api.nvim_buf_set_lines(H.info.bufnr, 0, -1, false, lines)\n\n  -- Defer execution because of textlock during `CompleteChanged` event\n  vim.schedule(function()\n    -- Ensure that window doesn't open when it shouldn't be\n    if not (H.pumvisible() and vim.fn.mode() == 'i') then return end\n    H.ensure_action_window('info', opts)\n    local win_id = H.info.win_id\n    if not H.is_valid_win(win_id) then return end\n\n    -- Hide helper syntax elements (like ``` code blocks, etc.)\n    vim.wo[H.info.win_id].conceallevel = 3\n\n    -- Scroll past first line if it is a visible (Neovim<0.11) codeblock start\n    if vim.fn.has('nvim-0.11') == 0 and lines[1]:find('^```%S*$') ~= nil then\n      vim.api.nvim_win_call(win_id, function() vim.fn.winrestview({ topline = 2 }) end)\n    end\n  end)\nend)\n\nH.info_window_lines = function(info_id)\n  local completed_item = H.info.event.completed_item\n  local info = completed_item.info or ''\n  local lsp_data = H.table_get(completed_item, { 'user_data', 'lsp' })\n\n  -- If popup is not from a known LSP server, use 'info' field of complete-item\n  if lsp_data == nil or lsp_data.item.client_id == nil then return vim.split(info, '\\n') end\n\n  -- Prefer reusing (without new LSP request) already resolved completion item\n  local item_id, resolved_cache = lsp_data.item_id, H.completion.lsp.resolved\n  if resolved_cache[item_id] ~= nil then return H.normalize_item_doc(resolved_cache[item_id], info) end\n\n  -- Try to get documentation from LSP's latest resolved info\n  if H.info.lsp.status == 'received' then\n    local lines = H.normalize_item_doc(H.info.lsp.result, info)\n    H.info.lsp.status = 'done'\n    return lines\n  end\n\n  -- If server doesn't support resolve or not known, reuse first response\n  local client = vim.lsp.get_client_by_id(lsp_data.item.client_id) or {}\n  local can_resolve = H.table_get(client.server_capabilities, { 'completionProvider', 'resolveProvider' })\n  if not can_resolve or client.id == nil then\n    resolved_cache[item_id] = lsp_data.item\n    return H.normalize_item_doc(lsp_data.item, info)\n  end\n\n  -- Finally, request to resolve current completion to add more documentation\n  local bufnr = vim.api.nvim_get_current_buf()\n  local current_id = H.info.lsp.id + 1\n  H.info.lsp.id = current_id\n  H.info.lsp.status = 'sent'\n\n  local cancel_fun = H.client_request(client, 'completionItem/resolve', lsp_data.item, function(err, result, _)\n    -- Don't do anything if there is other LSP request in action\n    if not H.is_lsp_current(H.info, current_id) then return end\n\n    H.info.lsp.status = 'received'\n\n    -- Do nothing if completion item was changed\n    if H.info.id ~= info_id then return end\n\n    -- Still use original item if there was no response (usually due to error)\n    result = result or lsp_data.item\n\n    H.info.lsp.result = result\n    -- - Cache resolved item to not have to send same request on revisit.\n    --   Do this outside of `H.info.event.completed_item` because it will not\n    --   have persistent effect as it will come fresh from Vimscript `v:event`.\n    resolved_cache[item_id] = result\n    H.show_info_window(info_id)\n  end, bufnr)\n\n  H.info.lsp.cancel_fun = cancel_fun\n  return false\nend\n\nH.info_window_options = function()\n  local win_config = H.get_config().window.info\n  local default_border = (H.has_no_winborder or vim.o.winborder == '') and 'single' or nil\n  local border = win_config.border or default_border\n  local pumborder = H.has_pumborder and vim.o.pumborder or ''\n\n  -- Compute dimensions based on actually visible lines to be displayed\n  local lines = H.compute_visible_md_lines(vim.api.nvim_buf_get_lines(H.info.bufnr, 0, -1, false))\n  local info_height, info_width = H.floating_dimensions(lines, win_config.height, win_config.width)\n\n  -- Compute position\n  local event = H.info.event\n  local left_to_pum = event.col - 1\n  local offset = (pumborder == '' or pumborder == 'none') and (event.scrollbar and 1 or 0) or 2\n  local right_to_pum = event.col + event.width + offset\n\n  local border_offset = border == 'none' and 0 or 2\n  local space_left = left_to_pum - border_offset\n  local space_right = vim.o.columns - right_to_pum - border_offset\n\n  -- Decide side at which info window will be displayed\n  local anchor, col, space\n  if info_width <= space_right or space_left <= space_right then\n    anchor, col, space = 'NW', right_to_pum, space_right\n  else\n    anchor, col, space = 'NE', left_to_pum, space_left\n  end\n\n  -- Possibly adjust floating window dimensions to fit screen\n  if space < info_width then\n    info_height, info_width = H.floating_dimensions(lines, win_config.height, space)\n  end\n\n  return {\n    relative = 'editor',\n    anchor = anchor,\n    row = event.row,\n    col = col,\n    width = info_width,\n    height = info_height,\n    focusable = false,\n    style = 'minimal',\n    border = border,\n    title = H.fit_to_width(' Info ', info_width),\n  }\nend\n\n-- Signature help -------------------------------------------------------------\nH.show_signature_window = function()\n  -- If there is no received LSP result, make request and exit\n  if H.signature.lsp.status ~= 'received' then\n    local current_id = H.signature.lsp.id + 1\n    H.signature.lsp.id = current_id\n    H.signature.lsp.status = 'sent'\n\n    local bufnr = vim.api.nvim_get_current_buf()\n    local params = H.make_position_params()\n\n    local cancel_fun = vim.lsp.buf_request_all(bufnr, 'textDocument/signatureHelp', params, function(result)\n      if not H.is_lsp_current(H.signature, current_id) then return end\n\n      H.signature.lsp.status = 'received'\n      H.signature.lsp.result = result\n\n      -- Trigger `show_signature` again to take 'received' route\n      H.show_signature_window()\n    end)\n\n    -- Cache cancel function to disable requests when they are not needed\n    H.signature.lsp.cancel_fun = cancel_fun\n\n    return\n  end\n\n  -- Make lines to show in floating window\n  local lines, hl_ranges = H.signature_window_lines()\n  H.signature.lsp.status = 'done'\n\n  -- Close window and exit if there is nothing to show\n  if not lines or H.is_whitespace(lines) then return H.close_action_window(H.signature) end\n\n  -- Ensure permanent buffer with current highlighting to display signature\n  H.ensure_buffer(H.signature, 'signature-help')\n  H.ensure_highlight(H.signature, vim.bo.filetype)\n  vim.api.nvim_buf_set_lines(H.signature.bufnr, 0, -1, false, lines)\n\n  -- Add highlighting of active parameter\n  local buf_id = H.signature.bufnr\n  vim.api.nvim_buf_clear_namespace(buf_id, H.ns_id, 0, -1)\n  for i, hl_range in ipairs(hl_ranges) do\n    if hl_range[1] ~= nil and hl_range[2] ~= nil then\n      local opts = { end_row = i - 1, end_col = hl_range[2], hl_group = 'MiniCompletionActiveParameter' }\n      vim.api.nvim_buf_set_extmark(buf_id, H.ns_id, i - 1, hl_range[1], opts)\n    end\n  end\n\n  -- If window is already opened and displays the same text, don't reopen it\n  local cur_text = table.concat(lines, '\\n')\n  if H.signature.win_id and cur_text == H.signature.text then return end\n\n  -- Cache lines for later checks if window should be reopened\n  H.signature.text = cur_text\n\n  -- Ensure window is closed\n  H.close_action_window(H.signature)\n\n  -- Compute floating window options\n  local opts = H.signature_window_opts()\n\n  -- Ensure that window doesn't open when it shouldn't\n  if vim.fn.mode() == 'i' then H.ensure_action_window('signature', opts) end\nend\n\nH.signature_window_lines = function()\n  local signature_data = H.process_lsp_response(H.signature.lsp.result, H.process_signature_response)\n  -- Each line is a single-line active signature string from one attached LSP\n  -- client. Each highlight range is a table which indicates (if not empty)\n  -- what parameter to highlight for every LSP client's signature string.\n  local lines, hl_ranges = {}, {}\n  for _, t in ipairs(signature_data) do\n    -- `t` is allowed to be an empty table (in which case nothing is added) or\n    -- a table with two entries. This ensures that `hl_range`'s integer index\n    -- points to an actual line in future buffer.\n    table.insert(lines, t.label)\n    table.insert(hl_ranges, t.hl_range)\n  end\n\n  return lines, hl_ranges\nend\n\nH.process_signature_response = function(response)\n  if not response.signatures or vim.tbl_isempty(response.signatures) then return {} end\n\n  -- Get active signature (based on textDocument/signatureHelp specification)\n  local signature_id = response.activeSignature or 0\n  -- This is according to specification: \"If ... value lies outside ...\n  -- defaults to zero\"\n  local n_signatures = vim.tbl_count(response.signatures or {})\n  if signature_id < 0 or signature_id >= n_signatures then signature_id = 0 end\n  local signature = response.signatures[signature_id + 1]\n\n  -- Get displayed signature label\n  local res = { label = signature.label:gsub('\\n', ' ') }\n\n  -- Get start and end of active parameter (for highlighting)\n  local n_params = #(signature.parameters or {})\n  local has_params = type(signature.parameters) == 'table' and n_params > 0\n\n  -- Take values in this order because data inside signature takes priority\n  local parameter_id = signature.activeParameter or response.activeParameter or 0\n  local param_id_inrange = 0 <= parameter_id and parameter_id < n_params\n\n  -- Computing active parameter only when parameter id is inside bounds is not\n  -- strictly based on specification, as currently (v3.16) it says to treat\n  -- out-of-bounds value as first parameter. However, some clients seem to use\n  -- those values to indicate that nothing needs to be highlighted.\n  -- Sources:\n  -- https://github.com/microsoft/pyright/pull/1876\n  -- https://github.com/microsoft/language-server-protocol/issues/1271\n  if has_params and param_id_inrange then\n    local param_label = signature.parameters[parameter_id + 1].label\n\n    -- Compute highlight range based on type of supplied parameter label: can\n    -- be string label which should be a part of signature label or direct start\n    -- (inclusive) and end (exclusive) range values\n    local label_is_string = type(param_label) == 'string'\n    res.hl_range = label_is_string and { res.label:find(param_label, 1, true) } or (param_label or {})\n    -- - Make zero-indexed and end-exclusive\n    if res.hl_range[1] ~= nil then res.hl_range[1] = res.hl_range[1] - (label_is_string and 1 or 0) end\n  end\n\n  -- Return nested table because this will be a second argument of\n  -- `vim.list_extend()` and the whole inner table is a target value here.\n  return { res }\nend\n\nH.signature_window_opts = function()\n  local win_config = H.get_config().window.signature\n  local default_border = (H.has_no_winborder or vim.o.winborder == '') and 'single' or nil\n  local border = win_config.border or default_border\n  local lines = vim.api.nvim_buf_get_lines(H.signature.bufnr, 0, -1, false)\n  local height, width = H.floating_dimensions(lines, win_config.height, win_config.width)\n\n  -- Compute position\n  local win_line = vim.fn.winline()\n  local border_offset = border == 'none' and 0 or 2\n  local space_above = win_line - 1 - border_offset\n  local space_below = vim.api.nvim_win_get_height(0) - win_line - border_offset\n\n  local anchor, row, space\n  if height <= space_above or space_below <= space_above then\n    anchor, row, space = 'SW', 0, space_above\n  else\n    anchor, row, space = 'NW', 1, space_below\n  end\n\n  -- Possibly adjust floating window dimensions to fit screen\n  if space < height then\n    height, width = H.floating_dimensions(lines, space, win_config.width)\n  end\n\n  -- Get zero-indexed current cursor position\n  local bufpos = vim.api.nvim_win_get_cursor(0)\n  bufpos[1] = bufpos[1] - 1\n\n  return {\n    relative = 'win',\n    bufpos = bufpos,\n    anchor = anchor,\n    row = row,\n    col = 0,\n    width = width,\n    height = height,\n    focusable = false,\n    style = 'minimal',\n    border = border,\n    title = H.fit_to_width(' Signature ', width),\n  }\nend\n\n-- Helpers for floating windows -----------------------------------------------\nH.ensure_buffer = function(cache, name)\n  if H.is_valid_buf(cache.bufnr) then return end\n\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  cache.bufnr = buf_id\n  H.set_buf_name(buf_id, name)\n  vim.bo[buf_id].buftype = 'nofile'\nend\n\nH.ensure_highlight = function(cache, filetype)\n  if cache.hl_filetype == filetype then return end\n  cache.hl_filetype = filetype\n  local buf_id = cache.bufnr\n\n  local has_lang, lang = pcall(vim.treesitter.language.get_lang, filetype)\n  lang = has_lang and lang or filetype\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, lang, { error = false })\n  has_parser = has_parser and parser ~= nil\n  if has_parser then has_parser = pcall(vim.treesitter.start, buf_id, lang) end\n  if not has_parser then vim.bo[buf_id].syntax = filetype end\nend\n\n-- Returns tuple of height and width\nH.floating_dimensions = function(lines, max_height, max_width)\n  max_height, max_width = math.max(max_height, 1), math.max(max_width, 1)\n\n  -- Simulate how lines will look in window with `wrap` and `linebreak`.\n  -- This is not 100% accurate (mostly because of concealed characters and\n  -- multibyte manifest into empty space at bottom), but does the job\n  local lines_wrap = {}\n  for _, l in ipairs(lines) do\n    vim.list_extend(lines_wrap, H.wrap_line(l, max_width))\n  end\n  -- Height is a number of wrapped lines truncated to maximum height\n  local height = math.min(#lines_wrap, max_height)\n\n  -- Width is a maximum width of the first `height` wrapped lines truncated to\n  -- maximum width\n  local width = 0\n  local l_width\n  for i, l in ipairs(lines_wrap) do\n    -- Use `strdisplaywidth()` to account for 'non-UTF8' characters\n    l_width = vim.fn.strdisplaywidth(l)\n    if i <= height and width < l_width then width = l_width end\n  end\n  -- It should already be less that that because of wrapping, so this is \"just\n  -- in case\"\n  width = math.min(width, max_width)\n\n  return math.max(height, 1), math.max(width, 1)\nend\n\nH.ensure_action_window = function(window_kind, opts)\n  local cache = H[window_kind]\n  local is_shown = H.is_valid_win(cache.win_id)\n  if is_shown then vim.api.nvim_win_set_config(cache.win_id, opts) end\n  if not is_shown then cache.win_id = vim.api.nvim_open_win(cache.bufnr, false, opts) end\n\n  local win_id = cache.win_id\n  vim.wo[win_id].breakindent = false\n  vim.wo[win_id].foldenable = false\n  vim.wo[win_id].foldmethod = 'manual'\n  vim.wo[win_id].linebreak = true\n  vim.wo[win_id].winhighlight = vim.wo[win_id].winhighlight:gsub(',FloatBorder:MiniCompletionInfoBorderOutdated', '')\n  vim.wo[win_id].wrap = true\n\n  local event = 'MiniCompletionWindow' .. (is_shown and 'Update' or 'Open')\n  local data = { kind = window_kind, win_id = win_id }\n  vim.api.nvim_exec_autocmds('User', { pattern = event, data = data })\nend\n\nH.close_action_window = function(cache)\n  cache.timer:stop()\n\n  if H.is_valid_win(cache.win_id) then vim.api.nvim_win_close(cache.win_id, true) end\n  cache.win_id = nil\n\n  -- For some reason 'buftype' might be reset. Ensure that buffer is scratch.\n  if H.is_valid_buf(cache.bufnr) then vim.bo[cache.bufnr].buftype = 'nofile' end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.completion) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minicompletion://' .. buf_id .. '/' .. name) end\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.is_char_keyword = function(char)\n  -- Using Vim's `match()` and `keyword` enables respecting Cyrillic letters\n  return vim.fn.match(char, '[[:keyword:]]') >= 0\nend\n\n-- NOTE: Might return `true` even if there is no visible completion popup, but\n-- built-in completion is still \"active\" (`<BS>` will show previous completion\n-- immediately).\nH.pumvisible = function() return vim.fn.pumvisible() > 0 end\n\nH.get_completion_range = function(lsp_result)\n  local pos = vim.api.nvim_win_get_cursor(0)\n\n  -- Prefer completion start from LSP response(s)\n  for _, response_data in pairs(lsp_result or {}) do\n    local range = H.get_lsp_edit_range(response_data)\n    if range ~= nil then return { range.start.line + 1, range.start.character }, pos end\n  end\n\n  -- Fall back to start position of latest keyword\n  local line = vim.api.nvim_get_current_line()\n  return { pos[1], vim.fn.match(line:sub(1, pos[2]), '\\\\k*$') }, pos\nend\n\nH.get_lsp_edit_range = function(response_data)\n  -- TODO: Use only `.err` after compatibility with Neovim=0.10 is dropped\n  if response_data.err or response_data.error or type(response_data.result) ~= 'table' then return end\n\n  -- Try using item defaults if they contain edit range (which can be either\n  -- `Range` or contain `insert` field of `Range` type)\n  local edit_range = H.table_get(response_data.result, { 'itemDefaults', 'editRange' })\n  if type(edit_range) == 'table' then return edit_range.insert or edit_range end\n\n  -- Try using all items to find the first one with edit range\n  local items = response_data.result.items or response_data.result\n  for _, item in ipairs(items) do\n    -- Account for `textEdit` can be either `TextEdit` or `InsertReplaceEdit`\n    if type(item.textEdit) == 'table' then return item.textEdit.range or item.textEdit.insert end\n  end\nend\n\nH.del_extmark = function(extmark_id, with_text)\n  local data = vim.api.nvim_buf_get_extmark_by_id(0, H.ns_id, extmark_id, { details = true })\n  vim.api.nvim_buf_del_extmark(0, H.ns_id, extmark_id)\n  -- Possibly remove extmark's text\n  if not with_text or data[1] == nil or data[3].end_row == nil then return data end\n  local start_row, start_col, end_row, end_col = data[1], data[2], data[3].end_row, data[3].end_col\n  if start_row < end_row or (start_row == end_row and start_col < end_col) then\n    vim.api.nvim_buf_set_text(0, start_row, start_col, end_row, end_col, { '' })\n  end\n  return data\nend\n\nH.is_whitespace = function(s)\n  if type(s) == 'string' then return s:find('^%s*$') end\n  if type(s) == 'table' then\n    for _, val in ipairs(s) do\n      if not H.is_whitespace(val) then return false end\n    end\n    return true\n  end\n  return false\nend\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.str_byteindex = function(s, i) return vim.str_byteindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_byteindex = function(s, i) return vim.str_byteindex(s, i) end end\n\n-- Simulate splitting single line `l` like how it would look inside window with\n-- `wrap` and `linebreak` set to `true`\nH.wrap_line = function(l, width)\n  local res = {}\n\n  local success, width_id = true, nil\n  -- Use `strdisplaywidth()` to account for multibyte characters\n  while success and vim.fn.strdisplaywidth(l) > width do\n    -- Simulate wrap by looking at breaking character from end of current break\n    -- Use `pcall()` to handle complicated multibyte characters (like Chinese)\n    -- for which even `strdisplaywidth()` seems to return incorrect values.\n    success, width_id = pcall(H.str_byteindex, l, width)\n\n    if success then\n      local break_match = vim.fn.match(l:sub(1, width_id):reverse(), '[- \\t.,;:!?]')\n      -- If no breaking character found, wrap at whole width\n      local break_id = width_id - (break_match < 0 and 0 or break_match)\n      table.insert(res, l:sub(1, break_id))\n      l = l:sub(break_id + 1)\n    end\n  end\n  table.insert(res, l)\n\n  return res\nend\n\nH.table_get = function(t, id)\n  if type(id) ~= 'table' then return H.table_get(t, { id }) end\n  local success, res = true, t\n  for _, i in ipairs(id) do\n    --stylua: ignore start\n    success, res = pcall(function() return res[i] end)\n    if not success or res == nil then return end\n    --stylua: ignore end\n  end\n  return res\nend\n\nH.get_left_char = function()\n  local line = vim.api.nvim_get_current_line()\n  local col = vim.api.nvim_win_get_cursor(0)[2]\n\n  return string.sub(line, col, col)\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.normalize_item_doc = function(lsp_item, fallback_info)\n  local detail, doc = lsp_item.detail, lsp_item.documentation\n  -- Fall back to explicit info only of there is no data in completion item\n  -- Assume that explicit info is a code that needs highlighting\n  detail = (detail == nil and doc == nil) and fallback_info or detail\n  if detail == nil and doc == nil then return {} end\n\n  -- Extract string content. Treat markdown and plain kinds the same.\n  -- Show both `detail` and `documentation` if the first provides new info.\n  detail, doc = detail or '', type(doc) == 'table' and (doc.value or '') or (doc or '')\n  -- Wrap details in language's code block to (usually) improve highlighting\n  -- This approach seems to work in 'hrsh7th/nvim-cmp'\n  detail = (H.is_whitespace(detail) or doc:find(detail, 1, true) ~= nil) and '' or (H.wrap_in_codeblock(detail) .. '\\n')\n  local text = detail .. doc\n\n  -- Ensure consistent line separators\n  text = text:gsub('\\r\\n?', '\\n')\n  -- Remove trailing whitespace (converts blank lines to empty)\n  text = text:gsub('[ \\t]+\\n', '\\n'):gsub('[ \\t]+$', '\\n')\n  -- Collapse multiple empty lines, remove top and bottom padding\n  text = text:gsub('\\n\\n+', '\\n\\n'):gsub('^\\n+', ''):gsub('\\n+$', '')\n  -- Ensure single line pads around code blocks: on Neovim<0.11 top and bottom\n  -- lines just appear empty, on Neovim>=0.11 they disappear (account for that)\n  local pad = vim.fn.has('nvim-0.11') == 1 and '\\n' or ''\n  text = text:gsub('\\n*(\\n```%S+\\n)', pad .. '%1'):gsub('(\\n```\\n)\\n*', '%1' .. pad)\n\n  if text == '' and fallback_info ~= '' then text = H.wrap_in_codeblock(fallback_info) end\n  return text == '' and {} or vim.split(text, '\\n')\nend\n\n-- Neovim>=0.11 has visually impactful issue of TS (markdown) highlighting:\n-- sometimes concealing extmarks are not removed. Remove after 0.11.1 release.\n-- See https://github.com/neovim/neovim/issues/33333\nH.ensure_no_concealed_lines = function(buf_id)\n  local ts_ns_id = vim.api.nvim_get_namespaces()['nvim.treesitter.highlighter']\n  pcall(vim.api.nvim_buf_clear_namespace, buf_id, ts_ns_id, 0, -1)\nend\nif vim.fn.has('nvim-0.11') == 0 then H.ensure_no_concealed_lines = function(buf_id) end end\n\n-- Neovim>=0.11 has markdown codeblock delimiters hidden. Neovim<0.11 shows\n-- them as empty line (so ignore only top and bottom for more compact view).\nH.compute_visible_md_lines = function(lines)\n  return vim.tbl_filter(function(l) return l:find('^```%S*$') == nil end, lines)\nend\nif vim.fn.has('nvim-0.11') == 0 then\n  H.compute_visible_md_lines = function(lines)\n    if lines[1]:find('^```%S*$') ~= nil then table.remove(lines, 1) end\n    if lines[#lines]:find('^```$') ~= nil then table.remove(lines, #lines) end\n    return lines\n  end\nend\n\nH.wrap_in_codeblock = function(x) return string.format('```%s\\n%s\\n```', vim.bo.filetype:match('^[^%.]*'), vim.trim(x)) end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nH.get_buf_lsp_clients = function() return vim.lsp.get_clients({ bufnr = 0 }) end\nif vim.fn.has('nvim-0.10') == 0 then H.get_buf_lsp_clients = function() return vim.lsp.buf_get_clients() end end\n\n-- TODO: Remove after compatibility with Neovim=0.10 is dropped\nH.make_position_params = function(context)\n  local res = vim.lsp.util.make_position_params()\n  res.context = context\n  return res\nend\nif vim.fn.has('nvim-0.11') == 1 then\n  -- Use callable `params` to workaround mandatory non-nil `offset_encoding` in\n  -- `vim.lsp.util.make_position_params()` on Neovim>=0.11\n  H.make_position_params = function(context)\n    return function(client, _)\n      local res = vim.lsp.util.make_position_params(0, client.offset_encoding)\n      res.context = context\n      return res\n    end\n  end\nend\n\n-- TODO: Remove after compatibility with Neovim=0.10 is dropped\nH.client_request = function(client, method, params, handler, bufnr)\n  local ok, request_id = client:request(method, params, handler, bufnr)\n  return ok and function() pcall(client.cancel_request, client, request_id) end or function() end\nend\nif vim.fn.has('nvim-0.11') == 0 then\n  H.client_request = function(client, method, params, handler, bufnr)\n    local ok, request_id = client.request(method, params, handler, bufnr)\n    return ok and function() pcall(client.cancel_request, request_id) end or function() end\n  end\nend\n\nreturn MiniCompletion\n"
  },
  {
    "path": "lua/mini/cursorword.lua",
    "content": "--- *mini.cursorword* Autohighlight word under cursor\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Autohighlight word under cursor with customizable delay.\n---\n--- - Current word under cursor can be highlighted differently.\n---\n--- - Highlighting is triggered only if current cursor character is a |[:keyword:]|.\n---\n--- - Highlighting stops in insert and terminal modes.\n---\n--- - \"Word under cursor\" is meant as in Vim's |<cword>|: something user would\n---   get as 'iw' text object.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.cursorword').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniCursorword` which you can use for scripting or manually (with\n--- `:lua MiniCursorword.*`).\n---\n--- See |MiniCursorword.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minicursorword_config` which should have same structure as\n--- `MiniCursorword.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Highlight groups ~\n---\n--- - `MiniCursorword` - highlight group of a non-current cursor word.\n---   Default: plain underline.\n---\n--- - `MiniCursorwordCurrent` - highlight group of a current word under cursor.\n---   Default: links to `MiniCursorword` (so `:hi clear MiniCursorwordCurrent`\n---   will lead to showing `MiniCursorword` highlight group).\n---   Note: To not highlight it, use the following Lua code: >lua\n---\n---   vim.api.nvim_set_hl(0, 'MiniCursorwordCurrent', {})\n--- <\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.minicursorword_disable` (globally) or\n--- `vim.b.minicursorword_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes. Note: after disabling\n--- there might be highlighting left; it will be removed after next\n--- highlighting update.\n---\n--- Module-specific disabling:\n--- - Don't show highlighting if cursor is on the word that is in a blocklist\n---   of current filetype. In this example, blocklist for \"lua\" is \"local\" and\n---   \"require\" words, for \"javascript\" - \"import\": >lua\n---\n---   _G.cursorword_blocklist = function()\n---     local curword = vim.fn.expand('<cword>')\n---     local filetype = vim.bo.filetype\n---\n---     -- Add any disabling global or filetype-specific logic here\n---     local blocklist = {}\n---     if filetype == 'lua' then\n---       blocklist = { 'local', 'require' }\n---     elseif filetype == 'javascript' then\n---       blocklist = { 'import' }\n---     end\n---\n---     vim.b.minicursorword_disable = vim.tbl_contains(blocklist, curword)\n---   end\n---\n---   -- Make sure to add this autocommand *before* calling module's `setup()`.\n---   vim.cmd('au CursorMoved * lua _G.cursorword_blocklist()')\n--- <\n---@tag MiniCursorword\n\n-- Module definition ==========================================================\nlocal MiniCursorword = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniCursorword.config|.\n---\n---@usage >lua\n---   require('mini.cursorword').setup() -- use default config\n---   -- OR\n---   require('mini.cursorword').setup({}) -- replace {} with your config table\n--- <\nMiniCursorword.setup = function(config)\n  -- Export module\n  _G.MiniCursorword = MiniCursorword\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniCursorword.config = {\n  -- Delay (in ms) between when cursor moved and when highlighting appeared\n  delay = 100,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniCursorword.config)\n\n-- Delay timer\nH.timer = vim.loop.new_timer()\n\n-- Information about last match highlighting (stored *per window*):\n-- - Key: windows' unique buffer identifiers.\n-- - Value: table with:\n--     - `id` field for match id (from `vim.fn.matchadd()`).\n--     - `word` field for matched word.\nH.window_matches = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('delay', config.delay, 'number')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniCursorword.config = config\n\n  -- Make `setup()` to proper reset module\n  for _, m in ipairs(vim.fn.getmatches()) do\n    if vim.startswith(m.group, 'MiniCursorword') then vim.fn.matchdelete(m.id) end\n  end\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniCursorword', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('CursorMoved', '*', H.auto_highlight, 'Auto highlight cursorword')\n  au({ 'InsertEnter', 'TermEnter', 'QuitPre' }, '*', H.auto_unhighlight, 'Auto unhighlight cursorword')\n  au('ModeChanged', '*:[^i]', H.auto_highlight, 'Auto highlight cursorword')\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\n  au('FileType', 'TelescopePrompt', function() vim.b.minicursorword_disable = true end, 'Disable locally')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  vim.api.nvim_set_hl(0, 'MiniCursorword',        { default = true, underline = true })\n  vim.api.nvim_set_hl(0, 'MiniCursorwordCurrent', { default = true, link = 'MiniCursorword' })\nend\n\nH.is_disabled = function() return vim.g.minicursorword_disable == true or vim.b.minicursorword_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniCursorword.config, vim.b.minicursorword_config or {}, config or {})\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_highlight = function()\n  -- Stop any possible previous delayed highlighting\n  H.timer:stop()\n\n  -- Stop highlighting immediately if module is disabled when cursor is not on\n  -- 'keyword'\n  if not H.should_highlight() then return H.unhighlight() end\n\n  -- Get current information\n  local win_id = vim.api.nvim_get_current_win()\n  local win_match = H.window_matches[win_id] or {}\n  local curword = H.get_cursor_word()\n\n  -- Only immediately update highlighting of current word under cursor if\n  -- currently highlighted word equals one under cursor\n  if win_match.word == curword then\n    H.unhighlight(true)\n    H.highlight(true)\n    return\n  end\n\n  -- Stop highlighting previous match (if it exists)\n  H.unhighlight()\n\n  -- Delay highlighting\n  H.timer:start(\n    H.get_config().delay,\n    0,\n    vim.schedule_wrap(function()\n      -- Ensure that always only one word is highlighted\n      H.unhighlight()\n      H.highlight()\n    end)\n  )\nend\n\nH.auto_unhighlight = function()\n  -- Stop any possible previous delayed highlighting\n  H.timer:stop()\n  H.unhighlight()\nend\n\n-- Highlighting ---------------------------------------------------------------\n---@param only_current boolean|nil Whether to forcefully highlight only current word\n---   under cursor.\n---@private\nH.highlight = function(only_current)\n  -- A modified version of https://stackoverflow.com/a/25233145\n  -- Using `matchadd()` instead of a simpler `:match` to tweak priority of\n  -- 'current word' highlighting: with `:match` it is higher than for\n  -- `incsearch` which is not convenient.\n  local win_id = vim.api.nvim_get_current_win()\n  if not vim.api.nvim_win_is_valid(win_id) then return end\n\n  if not H.should_highlight() then return end\n\n  H.window_matches[win_id] = H.window_matches[win_id] or {}\n\n  -- Add match highlight for current word under cursor\n  local current_word_pattern = [[\\k*\\%#\\k*]]\n  local match_id_current = vim.fn.matchadd('MiniCursorwordCurrent', current_word_pattern, -1)\n  H.window_matches[win_id].id_current = match_id_current\n\n  -- Don't add main match id if not needed or if one is already present\n  if only_current or H.window_matches[win_id].id ~= nil then return end\n\n  -- Add match highlight for non-current word under cursor. NOTEs:\n  -- - Using `\\(...\\)\\@!` allows to not match current word.\n  -- - Using 'very nomagic' ('\\V') allows not escaping.\n  -- - Using `\\<` and `\\>` matches whole word (and not as part).\n  local curword = H.get_cursor_word()\n  local pattern = string.format([[\\(%s\\)\\@!\\&\\V\\<%s\\>]], current_word_pattern, curword)\n  local match_id = vim.fn.matchadd('MiniCursorword', pattern, -1)\n\n  -- Store information about highlight\n  H.window_matches[win_id].id = match_id\n  H.window_matches[win_id].word = curword\nend\n\n---@param only_current boolean|nil Whether to remove highlighting only of current\n---   word under cursor.\n---@private\nH.unhighlight = function(only_current)\n  -- Don't do anything if there is no valid information to act upon\n  local win_id = vim.api.nvim_get_current_win()\n  local win_match = H.window_matches[win_id]\n  if not vim.api.nvim_win_is_valid(win_id) or win_match == nil then return end\n\n  -- Use `pcall` because there is an error if match id is not present. It can\n  -- happen if something else called `clearmatches`.\n  pcall(vim.fn.matchdelete, win_match.id_current)\n  H.window_matches[win_id].id_current = nil\n\n  if not only_current then\n    pcall(vim.fn.matchdelete, win_match.id)\n    H.window_matches[win_id] = nil\n  end\nend\n\nH.should_highlight = function() return not H.is_disabled() and H.is_cursor_on_keyword() end\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.cursorword) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.is_cursor_on_keyword = function()\n  local col = vim.fn.col('.')\n  local curchar = vim.api.nvim_get_current_line():sub(col, col)\n\n  -- Use `pcall()` to catch `E5108` (can happen in binary files, see #112)\n  local ok, match_res = pcall(vim.fn.match, curchar, '[[:keyword:]]')\n  return ok and match_res >= 0\nend\n\nH.get_cursor_word = function() return vim.fn.escape(vim.fn.expand('<cword>'), [[\\/]]) end\n\nreturn MiniCursorword\n"
  },
  {
    "path": "lua/mini/deps.lua",
    "content": "--- *mini.deps* Plugin manager\n---\n--- MIT License Copyright (c) 2024 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Manage plugins utilizing Git and built-in |packages| with these actions:\n---     - Add plugin to current session, download if absent. See |MiniDeps.add()|.\n---     - Update with/without confirm, with/without parallel download of new data.\n---       See |MiniDeps.update()|.\n---     - Delete unused plugins with/without confirm. See |MiniDeps.clean()|.\n---     - Get / set / save / load snapshot. See `MiniDeps.snap_*()` functions.\n---\n---     All main actions are available both as Lua functions and user commands\n---     (see |MiniDeps-commands|).\n---\n--- - Minimal yet flexible plugin |MiniDeps-plugin-specification|:\n---     - Plugin source.\n---     - Name of target plugin directory.\n---     - Checkout target: branch, commit, tag, etc.\n---     - Monitor branch to track updates without checking out.\n---     - Dependencies to be set up prior to the target plugin.\n---     - Hooks to call before/after plugin is created/changed.\n---\n--- - Helpers implementing two-stage startup: |MiniDeps.now()| and |MiniDeps.later()|.\n---   See |MiniDeps-overview| for how to implement basic lazy loading with them.\n---\n--- What it doesn't do:\n---\n--- - Manage plugins which are developed without Git. The suggested approach is\n---   to create a separate package (see |packages|).\n---\n--- - Provide ways to completely remove or update plugin's functionality in\n---   current session. Although this is partially doable, it can not be done\n---   in full (yet) because plugins can have untraceable side effects\n---   (autocmmands, mappings, etc.).\n---   The suggested approach is to restart Nvim.\n---\n--- Sources with more details:\n--- - |MiniDeps-overview|\n--- - |MiniDeps-plugin-specification|\n--- - |MiniDeps-commands|\n---\n--- # Dependencies ~\n---\n--- For most of its functionality this plugin relies on `git` CLI tool.\n--- See https://git-scm.com/ for more information about how to install it.\n--- Actual knowledge of Git is not required but helpful.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.deps').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniDeps`\n--- which you can use for scripting or manually (with `:lua MiniDeps.*`).\n---\n--- See |MiniDeps.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minideps_config` which should have same structure as\n--- `MiniDeps.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [folke/lazy.nvim](https://github.com/folke/lazy.nvim):\n---     - More feature-rich and complex.\n---     - Uses table specification with dedicated functions to add plugins,\n---       while this module uses direct function call approach\n---       (calling |MiniDeps.add()| ensures that plugin is usable).\n---     - Uses version tags by default, while this module is more designed towards\n---       tracking branches. Using tags is possible too (see |MiniDeps-overview|).\n---\n--- - [savq/paq-nvim](https://github.com/savq/paq-nvim):\n---     - Overall less feature-rich than this module (by design).\n---     - Uses array of plugin specifications inside `setup()` call to define which\n---       plugins should be installed. Requires separate `:PaqInstall` call to\n---       actually install them. This module ensures installation on first load.\n---\n--- - [junegunn/vim-plug](https://github.com/junegunn/vim-plug):\n---     - Written in Vimscript, while this module is in Lua.\n---     - Similar approach to defining and installing plugins as 'savq/paq-nvim'.\n---     - Has basic lazy-loading built-in, while this module does not (by design).\n---\n--- # Highlight groups ~\n---\n--- Highlight groups are used inside confirmation buffers after\n--- default |MiniDeps.update()| and |MiniDeps.clean()|.\n---\n--- - `MiniDepsChangeAdded`   - added change (commit) during update.\n--- - `MiniDepsChangeRemoved` - removed change (commit) during update.\n--- - `MiniDepsHint`          - various hints.\n--- - `MiniDepsInfo`          - various information.\n--- - `MiniDepsMsgBreaking`   - message for (conventional commit) breaking change.\n--- - `MiniDepsPlaceholder`   - placeholder when there is no valuable information.\n--- - `MiniDepsTitle`         - various titles.\n--- - `MiniDepsTitleError`    - title when plugin had errors during update.\n--- - `MiniDepsTitleSame`     - title when plugin has no changes to update.\n--- - `MiniDepsTitleUpdate`   - title when plugin has changes to update.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---@tag MiniDeps\n\n--- # Directory structure ~\n---\n--- This module uses built-in |packages| to make plugins usable in current session.\n--- It works with \"pack/deps\" package inside `config.path.package` directory.\n---\n--- By default \"opt\" subdirectory is used to install optional plugins which are\n--- loaded on demand with |MiniDeps.add()|.\n--- Non-optional plugins in \"start\" subdirectory are supported but only if moved\n--- there manually after initial install. Use it if you know what you are doing.\n---\n--- # Add plugin ~\n---\n--- Use |MiniDeps.add()| to add plugin to current session. Supply plugin's URL\n--- source as a string or |MiniDeps-plugin-specification| in general. If plugin is\n--- not present in \"pack/deps\" package, it will be created (a.k.a. installed)\n--- before processing anything else.\n---\n--- The recommended way of adding a plugin is by calling |MiniDeps.add()| in the\n--- |init.lua| file (make sure |MiniDeps.setup()| is called prior): >lua\n---\n---   local add = MiniDeps.add\n---\n---   -- Add to current session (install if absent)\n---   add({\n---     source = 'neovim/nvim-lspconfig',\n---     -- Supply dependencies near target plugin\n---     depends = { 'williamboman/mason.nvim' },\n---   })\n---\n---   add({\n---     source = 'nvim-treesitter/nvim-treesitter',\n---     -- Use 'master' while monitoring updates in 'main'\n---     checkout = 'master',\n---     monitor = 'main',\n---     -- Perform action after every checkout\n---     hooks = { post_checkout = function() vim.cmd('TSUpdate') end },\n---   })\n---   -- Possible to immediately execute code which depends on the added plugin\n---   require('nvim-treesitter.configs').setup({\n---     ensure_installed = { 'lua', 'vimdoc' },\n---     highlight = { enable = true },\n---   })\n--- <\n--- NOTE:\n--- - To increase performance, `add()` only ensures presence on disk and\n---   nothing else. In particular, it doesn't ensure `opts.checkout` state.\n---   Update or modify plugin state explicitly (see later sections).\n---\n--- # Lazy loading ~\n---\n--- Any lazy-loading is assumed to be done manually by calling |MiniDeps.add()|\n--- at appropriate time. This module provides helpers implementing special safe\n--- two-stage loading:\n--- - |MiniDeps.now()| safely executes code immediately. Use it to load plugins\n---   with UI necessary to make initial screen draw.\n--- - |MiniDeps.later()| schedules code to be safely executed later, preserving\n---   order. Use it (with caution) for everything else which doesn't need\n---   precisely timed effect, as it will be executed some time soon on one of\n---   the next event loops. >lua\n---\n---   local now, later = MiniDeps.now, MiniDeps.later\n---\n---   -- Safely execute immediately\n---   now(function() vim.cmd('colorscheme miniwinter') end)\n---   now(function() require('mini.statusline').setup() end)\n---\n---   -- Safely execute later\n---   later(function() require('mini.pick').setup() end)\n--- <\n--- # Update ~\n---\n--- To update plugins from current session with new data from their sources,\n--- use |:DepsUpdate|. This will download updates (utilizing multiple cores) and\n--- show confirmation buffer. Follow instructions at its top to finish an update.\n---\n--- NOTE: This updates plugins on disk which most likely won't affect current\n--- session. Restart Nvim to have them properly loaded.\n---\n--- # Modify ~\n---\n--- To change plugin's specification (like set different `checkout`, etc.):\n--- - Update corresponding |MiniDeps.add()| call.\n--- - Run `:DepsUpdateOffline <plugin_name>`.\n--- - Review changes and confirm.\n--- - Restart Nvim.\n---\n--- NOTE: if `add()` prior used a single source string, make sure to convert\n--- its argument to `{ source = '<previous_argument>', checkout = '<state>'}`\n---\n--- # Snapshots ~\n---\n--- Use |:DepsSnapSave| to save state of all plugins from current session into\n--- a snapshot file (see `config.path.snapshot`).\n---\n--- Use |:DepsSnapLoad| to load snapshot. This will change (without confirmation)\n--- state on disk. Plugins present in both snapshot file and current session\n--- will be affected. Restart Nvim to see the effect.\n---\n--- NOTE: loading snapshot does not change plugin's specification defined inside\n--- |MiniDeps.add()| call. This means that next update might change plugin's state.\n--- To make it permanent, freeze plugin in target state manually.\n---\n--- # Freeze ~\n---\n--- Modify plugin's specification to have `checkout` pointing to a static\n--- target: tag, state (commit hash), or 'HEAD' (to freeze in current state).\n---\n--- Frozen plugins will not receive updates. You can monitor any new changes from\n--- its source by \"subscribing\" to `monitor` branch which will be shown inside\n--- confirmation buffer after |:DepsUpdate|.\n---\n--- Example: use `checkout = 'v0.10.0'` to freeze plugin at tag \"v0.10.0\" while\n--- monitoring new versions in the log from `monitor` (usually default) branch.\n---\n--- # Rollback ~\n---\n--- To roll back after an unfortunate update:\n--- - Get identifier of latest working state:\n---     - Use |:DepsShowLog| to see update log, look for plugin's name, and copy\n---       identifier listed as \"State before:\".\n---     - See previously saved snapshot file for plugin's name and copy\n---       identifier next to it.\n--- - Freeze plugin at that state while monitoring appropriate branch.\n---   Revert to previous shape of |MiniDeps.add()| call to resume updating.\n---\n--- # Remove ~\n---\n--- - Make sure that target plugin is not registered in current session.\n---   Usually it means removing corresponding |MiniDeps.add()| call.\n--- - Run |:DepsClean|. This will show confirmation buffer with a list of plugins to\n---   be deleted from disk. Follow instructions at its top to finish cleaning.\n---\n--- Alternatively, manually delete plugin's directory from \"pack/deps\" package.\n---@tag MiniDeps-overview\n\n--- Each plugin dependency is managed based on its specification (a.k.a. \"spec\").\n--- See |MiniDeps-overview| for some examples.\n---\n--- Specification can be a single string which is inferred as:\n--- - Plugin <name> if it doesn't contain \"/\".\n--- - Plugin <source> otherwise.\n---\n--- Primarily, specification is a table with the following fields:\n---\n--- - <source> `(string|nil)` - field with URI of plugin source used during creation\n---   or update. Can be anything allowed by `git clone`.\n---   Default: `nil` to rely on source set up during install.\n---   Notes:\n---     - It is required for creating plugin, but can be omitted afterwards.\n---     - As the most common case, URI of the format \"user/repo\" (if it contains\n---       valid characters) is transformed into \"https://github.com/user/repo\".\n---\n--- - <name> `(string|nil)` - directory basename of where to put plugin source.\n---   It is put in \"pack/deps/opt\" subdirectory of `config.path.package`.\n---   Default: basename of <source> if it is present, otherwise should be\n---   provided explicitly.\n---\n--- - <checkout> `(string|nil)` - checkout target used to set state during update.\n---   Can be anything supported by `git checkout` - branch, commit, tag, etc.\n---   Default: `nil` for default branch (usually \"main\" or \"master\").\n---\n--- - <monitor> `(string|nil)` - monitor branch used to track new changes from\n---   different target than `checkout`. Should be a name of present Git branch.\n---   Default: `nil` for default branch (usually \"main\" or \"master\").\n---\n--- - <depends> `(table|nil)` - array of plugin specifications (strings or tables)\n---   to be added prior to the target.\n---   Default: `nil` for no dependencies.\n---\n--- - <hooks> `(table|nil)` - table with callable hooks to call on certain events.\n---   Possible hook names:\n---     - <pre_install>   - before creating plugin directory.\n---     - <post_install>  - after  creating plugin directory (before |:packadd|).\n---     - <pre_checkout>  - before making change in existing plugin.\n---     - <post_checkout> - after  making change in existing plugin.\n---   Each hook is executed with the following table as an argument:\n---     - <path> (`string`)   - absolute path to plugin's directory\n---       (might not yet exist on disk).\n---     - <source> (`string`) - resolved <source> from spec.\n---     - <name> (`string`)   - resolved <name> from spec.\n---   Default: `nil` for no hooks.\n---@tag MiniDeps-plugin-specification\n\n--- Note: Most commands have a Lua function alternative which they rely on.\n--- Like |:DepsAdd| uses |MiniDeps.add()|, etc.\n---\n--- # :DepsAdd ~\n---\n--- *:DepsAdd* with `user/repo` argument makes plugin https://github.com/user/repo\n--- available in the current session (also creates it, if it is not present).\n--- `:DepsAdd name` adds already installed plugin `name` to current session.\n--- Accepts only single string compatible with |MiniDeps-plugin-specification|.\n--- To add plugin in every session, put |MiniDeps.add()| in |init.lua|.\n---\n--- # :DepsUpdate ~\n---\n--- *:DepsUpdate* synchronizes plugins with their session specifications and\n--- updates them with new changes from sources. It shows confirmation buffer in\n--- a separate |tabpage| with information about an upcoming update to review\n--- and (selectively) apply. See |MiniDeps.update()| for more info.\n---\n--- `:DepsUpdate name` updates plugin `name`. Any number of names is allowed.\n---\n--- `:DepsUpdate!` and `:DepsUpdate! name` update without confirmation.\n--- You can see what was done in the log file afterwards (|:DepsShowLog|).\n---\n--- # :DepsUpdateOffline ~\n---\n--- *:DepsUpdateOffline* is same as |:DepsUpdate| but doesn't download new updates\n--- from sources. Useful to only synchronize plugin specification in code and\n--- on disk without unnecessary downloads.\n---\n--- # :DepsShowLog ~\n---\n--- *:DepsShowLog* opens log file to review.\n---\n--- # :DepsClean ~\n---\n--- *:DepsClean* deletes plugins from disk not added to current session. It shows\n--- confirmation buffer in a separate |tabpage| with information about an upcoming\n--- deletes to review and (selectively) apply. See |MiniDeps.clean()| for more info.\n---\n--- `:DepsClean!` deletes plugins without confirmation.\n---\n--- # :DepsSnapSave ~\n---\n--- *:DepsSnapSave* creates snapshot file in default location (see |MiniDeps.config|).\n--- `:DepsSnapSave path` creates snapshot file at `path`.\n---\n--- # :DepsSnapLoad ~\n---\n--- *:DepsSnapLoad* loads snapshot file from default location (see |MiniDeps.config|).\n--- `:DepsSnapLoad path` loads snapshot file at `path`.\n---@tag MiniDeps-commands\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n-- Module definition ==========================================================\nlocal MiniDeps = {}\nlocal H = {}\n\n--- Module setup\n---\n--- Calling this function creates user commands described in |MiniDeps-commands|.\n---\n---@param config table|nil Module config table. See |MiniDeps.config|.\n---\n---@usage >lua\n---   require('mini.deps').setup() -- use default config\n---   -- OR\n---   require('mini.deps').setup({}) -- replace {} with your config table\n--- <\nMiniDeps.setup = function(config)\n  -- Export module\n  _G.MiniDeps = MiniDeps\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\n\n  -- Create user commands\n  H.create_user_commands()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Job ~\n---\n--- `config.job` defines how CLI jobs are run.\n---\n--- `job.n_threads` is a maximum number of parallel jobs used when needed.\n--- Default: 80% of all available.\n---\n--- `job.timeout` is a duration (in ms) from job start until it is forced to stop.\n--- Default: 30000.\n---\n--- # Paths ~\n---\n--- `config.path` defines main paths used in this module.\n---\n--- `path.package` is a string with path inside which \"pack/deps\" package is stored\n--- (see |MiniDeps-overview|).\n--- Default: \"site\" subdirectory of \"data\" standard path (see |stdpath()|).\n---\n--- `path.snapshot` is a string with default path for snapshot.\n--- See |:DepsSnapSave| and |:DepsSnapLoad|.\n--- Default: \"mini-deps-snap\" file in \"config\" standard path (see |stdpath()|).\n---\n--- `path.log` is a string with path containing log of operations done by module.\n--- In particular, it contains all changes done after making an update.\n--- Default: \"mini-deps.log\" file in \"log\" standard path (see |stdpath()|).\n---\n--- # Silent ~\n---\n--- `config.silent` is a boolean controlling whether to suppress non-error feedback.\n--- Default: `false`.\nMiniDeps.config = {\n  -- Parameters of CLI jobs\n  job = {\n    -- Number of parallel threads to use. Default: 80% of all available.\n    n_threads = nil,\n\n    -- Timeout (in ms) for each job before force quit\n    timeout = 30000,\n  },\n\n  -- Paths describing where to store data\n  path = {\n    -- Directory for built-in package.\n    -- All plugins are actually stored in 'pack/deps' subdirectory.\n    package = vim.fn.stdpath('data') .. '/site',\n\n    -- Default file path for a snapshot\n    snapshot = vim.fn.stdpath('config') .. '/mini-deps-snap',\n\n    -- Log file\n    --minidoc_replace_start log = vim.fn.stdpath('log') .. '/mini-deps.log'\n    log = vim.fn.stdpath('log') .. '/mini-deps.log',\n    --minidoc_replace_end\n  },\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n--minidoc_afterlines_end\n\n--- Add plugin to current session\n---\n--- - Process specification by expanding dependencies into single spec array.\n--- - Ensure plugin is present on disk along with its dependencies by installing\n---   (in parallel) absent ones:\n---     - Execute `opts.hooks.pre_install`.\n---     - Use `git clone` to clone plugin from its source URI into \"pack/deps/opt\".\n---     - Set state according to `opts.checkout`.\n---     - Execute `opts.hooks.post_install`.\n--- - Register spec(s) in current session.\n--- - Make sure plugin(s) can be used in current session (see |:packadd|).\n--- - If not during startup and is needed, source all \"after/plugin/\" scripts.\n---\n--- Notes:\n--- - Presence of plugin is checked by its name which is the same as the name\n---   of its directory inside \"pack/deps\" package (see |MiniDeps-overview|).\n--- - To increase performance, this function only ensures presence on disk and\n---   nothing else. In particular, it doesn't ensure `opts.checkout` state.\n---   Use |MiniDeps.update()| or |:DepsUpdateOffline| explicitly.\n--- - Adding plugin several times updates its session specs.\n---\n---@param spec table|string Plugin specification. See |MiniDeps-plugin-specification|.\n---@param opts table|nil Options. Possible fields:\n---   - <bang> `(boolean)` - whether to use `:packadd!` instead of plain |:packadd|.\nMiniDeps.add = function(spec, opts)\n  opts = opts or {}\n  if type(opts) ~= 'table' then H.error('`opts` should be table.') end\n  if opts.source or opts.name or opts.checkout then H.error('`add()` accepts only single spec.') end\n\n  -- Normalize\n  local plugs = {}\n  H.expand_spec(plugs, spec)\n\n  -- Process\n  local plugs_to_install = {}\n  for i, p in ipairs(plugs) do\n    local path, is_present = H.get_plugin_path(p.name)\n    p.path = path\n    if not is_present then table.insert(plugs_to_install, vim.deepcopy(p)) end\n  end\n\n  -- Install\n  if #plugs_to_install > 0 then\n    H.ensure_git_exec()\n    for _, p in ipairs(plugs_to_install) do\n      p.job = H.cli_new_job({}, vim.fn.getcwd())\n    end\n\n    H.notify(string.format('Installing `%s`', plugs[#plugs].name))\n    H.plugs_exec_hooks(plugs_to_install, 'pre_install')\n    H.plugs_install(plugs_to_install)\n    H.plugs_exec_hooks(plugs_to_install, 'post_install')\n  end\n\n  -- Add plugins to current session\n  local cmd = 'packadd' .. (opts.bang and '!' or '') .. ' '\n  for _, p in ipairs(plugs) do\n    -- Register in 'mini.deps' session\n    table.insert(H.session, p)\n\n    -- Add to 'runtimepath'\n    vim.cmd(cmd .. p.name)\n  end\n\n  -- Execute 'after/' scripts if not during startup (when they will be sourced\n  -- automatically), as `:packadd` only sources plain 'plugin/' files.\n  -- See https://github.com/vim/vim/issues/1994.\n  -- Deliberately do so after executing all currently known 'plugin/' files.\n  local should_load_after_dir = vim.v.vim_did_enter == 1 and not opts.bang and vim.o.loadplugins\n  if not should_load_after_dir then return end\n  for _, p in ipairs(plugs) do\n    -- NOTE: This sources first lua and then vim, not how it is done during\n    -- startup (`:h loadplugins`) for speed (one `glob()` instead of two).\n    local after_paths = vim.fn.glob(p.path .. '/after/plugin/**/*.{vim,lua}', false, true)\n    vim.tbl_map(H.source, after_paths)\n  end\nend\n\n--- Update plugins\n---\n--- - Synchronize specs with state of plugins on disk (set `source`, etc.).\n--- - Infer data before downloading updates.\n--- - If not offline, download updates (in parallel).\n--- - Infer data after downloading updates.\n--- - If update is forced, apply all changes immediately while updating log\n---   file (at `config.path.log`; use |:DepsShowLog| to review).\n---   Otherwise show confirmation buffer with instructions on how to proceed.\n---\n---@param names table|nil Array of plugin names to update.\n---  Default: all plugins from current session (see |MiniDeps.get_session()|).\n---@param opts table|nil Options. Possible fields:\n---   - <force> `(boolean)` - whether to force update without confirmation.\n---     Default: `false`.\n---   - <offline> `(boolean)` - whether to skip downloading updates from sources.\n---     Default: `false`.\nMiniDeps.update = function(names, opts)\n  opts = vim.tbl_deep_extend('force', { force = false, offline = false }, opts or {})\n\n  -- Compute array of plugin data to be reused in update. Each contains a CLI\n  -- job \"assigned\" to plugin's path which stops execution after first error.\n  local plugs = H.plugs_from_names(names)\n  if #plugs == 0 then return H.notify('Nothing to update') end\n\n  -- Prepare repositories and specifications\n  H.ensure_git_exec()\n  H.plugs_ensure_origin_source(plugs)\n\n  -- Preprocess before downloading\n  H.plugs_infer_head(plugs)\n  H.plugs_ensure_target_refs(plugs)\n  H.plugs_infer_commit(plugs, 'monitor', 'monitor_from')\n\n  -- Download data if asked\n  if not opts.offline then H.plugs_download_updates(plugs) end\n\n  -- Process data for update\n  H.plugs_infer_commit(plugs, 'checkout', 'checkout_to')\n  H.plugs_infer_commit(plugs, 'monitor', 'monitor_to')\n  H.plugs_infer_log(plugs, 'head', 'checkout_to', 'checkout_log')\n  H.plugs_infer_log(plugs, 'monitor_from', 'monitor_to', 'monitor_log')\n\n  -- Checkout if asked (before feedback to include possible checkout errors)\n  if opts.force then H.plugs_checkout(plugs) end\n\n  -- Make feedback\n  local lines = H.update_compute_feedback_lines(plugs)\n  local feedback = opts.force and H.update_feedback_log or H.update_feedback_confirm\n  feedback(lines)\n\n  -- Show job warnings and errors\n  H.plugs_show_job_notifications(plugs, 'update')\nend\n\n--- Clean plugins\n---\n--- - Compute absent plugins: not registered in current session\n---   (see |MiniDeps.get_session()|) but present on disk in dedicated \"pack/deps\"\n---   package (inside `config.path.package`).\n--- - If cleaning is forced, delete all absent plugins from disk.\n---   Otherwise show confirmation buffer with instructions on how to proceed.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <force> `(boolean)` - whether to force delete without confirmation.\n---     Default: `false`.\nMiniDeps.clean = function(opts)\n  opts = vim.tbl_deep_extend('force', { force = false }, opts or {})\n\n  -- Compute path candidates to delete\n  local is_in_session = {}\n  for _, s in ipairs(MiniDeps.get_session()) do\n    is_in_session[s.path] = true\n  end\n\n  local is_absent_plugin = function(x) return vim.fn.isdirectory(x) == 1 and not is_in_session[x] end\n  local absent_paths = vim.tbl_filter(is_absent_plugin, H.get_all_plugin_paths())\n\n  -- Clean\n  if #absent_paths == 0 then return H.notify('Nothing to clean') end\n  local clean_fun = opts.force and H.clean_delete or H.clean_confirm\n  clean_fun(absent_paths)\nend\n\n--- Compute snapshot\n---\n---@return table A snapshot table: plugin names as keys and state as values.\n---   All plugins in current session are processed.\nMiniDeps.snap_get = function()\n  local plugs = H.plugs_from_names()\n  H.ensure_git_exec()\n  H.plugs_infer_head(plugs)\n  H.plugs_show_job_notifications(plugs, 'computing snapshot')\n\n  local snap = {}\n  for _, p in ipairs(plugs) do\n    if p.head ~= '' then snap[p.name] = p.head end\n  end\n  return snap\nend\n\n--- Apply snapshot\n---\n--- Notes:\n--- - Checking out states from snapshot does not update session plugin spec\n---   (`checkout` field in particular). Among others, it means that next call\n---   to |MiniDeps.update()| might override the result of this function.\n---   To make changes permanent, set `checkout` spec field to state from snapshot.\n---\n---@param snap table A snapshot table: plugin names as keys and state as values.\n---   Only plugins in current session are processed.\nMiniDeps.snap_set = function(snap)\n  if type(snap) ~= 'table' then H.error('Snapshot should be a table.') end\n\n  -- Construct current session plugin data with `checkout` from snapshot\n  for k, v in pairs(snap) do\n    if not (type(k) == 'string' and type(v) == 'string') then snap[k] = nil end\n  end\n  local plugs = H.plugs_from_names(vim.tbl_keys(snap))\n  for _, p in ipairs(plugs) do\n    p.checkout = snap[p.name]\n  end\n\n  -- Checkout\n  H.ensure_git_exec()\n  H.plugs_checkout(plugs)\n  H.plugs_show_job_notifications(plugs, 'applying snapshot')\nend\n\n--- Save snapshot\n---\n---@param path string|nil A valid path on disk where to write snapshot computed\n---   with |MiniDeps.snap_get()|.\n---   Default: `config.path.snapshot`.\nMiniDeps.snap_save = function(path)\n  path = path or H.full_path(H.get_config().path.snapshot)\n  if type(path) ~= 'string' then H.error('`path` should be string.') end\n\n  -- Compute snapshot\n  local snap = MiniDeps.snap_get()\n\n  -- Write snapshot\n  local lines = vim.split(vim.inspect(snap), '\\n')\n  lines[1] = 'return ' .. lines[1]\n  vim.fn.mkdir(vim.fn.fnamemodify(path, ':h'), 'p')\n  vim.fn.writefile(lines, path)\n\n  H.notify('Created snapshot at ' .. vim.inspect(path))\nend\n\n--- Load snapshot file\n---\n--- Notes from |MiniDeps.snap_set()| also apply here.\n---\n---@param path string|nil A valid path on disk from where to read snapshot.\n---   Default: `config.path.snapshot`.\nMiniDeps.snap_load = function(path)\n  path = path or H.full_path(H.get_config().path.snapshot)\n  if vim.fn.filereadable(path) ~= 1 then H.error('`path` should be path to a readable file.') end\n\n  local ok, snap = pcall(dofile, H.full_path(path))\n  if not (ok and type(snap) == 'table') then H.error('`path` is not a path to proper snapshot.') end\n\n  MiniDeps.snap_set(snap)\nend\n\n--- Get session\n---\n--- Plugin is registered in current session if it either:\n--- - Was added with |MiniDeps.add()| (preserving order of calls).\n--- - Is a \"start\" plugin and present in 'runtimpath'.\n---\n---@return table Array with specifications of all plugins registered in\n---   current session.\nMiniDeps.get_session = function()\n  -- Normalize `H.session` allowing specs for same plugin\n  local res, plugin_ids = {}, {}\n  local add_spec = function(spec)\n    local id = plugin_ids[spec.path] or (#res + 1)\n    -- Treat `depends` differently as it is an array and direct merge is bad\n    -- Also: https://github.com/neovim/neovim/pull/15094#discussion_r671663938\n    local depends = vim.deepcopy((res[id] or {}).depends or {})\n    vim.list_extend(depends, spec.depends or {})\n    res[id] = vim.tbl_deep_extend('force', res[id] or {}, spec)\n    res[id].depends = depends\n\n    plugin_ids[spec.path] = id\n  end\n  vim.tbl_map(add_spec, H.session)\n  H.session = res\n\n  -- Add 'start/' plugins that are in 'rtp'. NOTE: not whole session concept is\n  -- built around presence in 'rtp' to 100% ensure to preserve the order in\n  -- which user called `add()`.\n  local start_path = H.full_path(H.get_package_path() .. '/pack/deps/start')\n  local pattern = string.format('^%s/([^/]+)$', vim.pesc(start_path))\n  for _, runtime_path in ipairs(vim.api.nvim_list_runtime_paths()) do\n    -- Make sure plugin path is normalized (matters on Windows)\n    local path = H.full_path(runtime_path)\n    local name = string.match(path, pattern)\n    if name ~= nil then add_spec({ path = path, name = name, hooks = {}, depends = {} }) end\n  end\n\n  -- Return copy to not allow modification in place\n  return vim.deepcopy(res)\nend\n\n--- Execute function now\n---\n--- Safely execute function immediately. Errors are shown with |vim.notify()|\n--- later, after all queued functions (including with |MiniDeps.later()|)\n--- are executed, thus not blocking execution of next code in file.\n---\n--- Assumed to be used as a first step during two-stage config execution to\n--- load plugins immediately during startup. See |MiniDeps-overview|.\n---\n---@param f function Callable to execute.\nMiniDeps.now = function(f)\n  local ok, err = pcall(f)\n  if not ok then table.insert(H.cache.exec_errors, err) end\n  H.schedule_finish()\nend\n\n--- Execute function later\n---\n--- Queue function to be safely executed later without blocking execution of\n--- next code in file. All queued functions are guaranteed to be executed in\n--- order they were added.\n--- Errors are shown with |vim.notify()| after all queued functions are executed.\n---\n--- Assumed to be used as a second step during two-stage config execution to\n--- load plugins \"lazily\" after startup. See |MiniDeps-overview|.\n---\n---@param f function Callable to execute.\nMiniDeps.later = function(f)\n  table.insert(H.cache.later_callback_queue, f)\n  H.schedule_finish()\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniDeps.config\n\n-- Array of plugin specs\nH.session = {}\n\n-- Various cache\nH.cache = {\n  -- Whether finish of `now()` or `later()` is already scheduled\n  finish_is_scheduled = false,\n\n  -- Callback queue for `later()`\n  later_callback_queue = {},\n\n  -- Errors during execution of `now()` or `later()`\n  exec_errors = {},\n\n  -- Git version\n  git_version = nil,\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('job', config.job, 'table')\n  H.check_type('job.n_threads', config.job.n_threads, 'number', true)\n  H.check_type('job.timeout', config.job.timeout, 'number')\n\n  H.check_type('path', config.path, 'table')\n  H.check_type('path.package', config.path.package, 'string')\n  H.check_type('path.snapshot', config.path.snapshot, 'string')\n  H.check_type('path.log', config.path.log, 'string')\n\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniDeps.config = config\n\n  -- Reset current session to allow resourcing script with `setup()` call\n  H.session = {}\n\n  -- Add target package path to 'packpath'\n  local pack_path = H.full_path(config.path.package)\n  vim.cmd('set packpath^=' .. vim.fn.fnameescape(pack_path))\nend\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniDeps.config, vim.b.minideps_config or {}, config or {})\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniDeps', {})\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  local has_core_diff_hl = vim.fn.has('nvim-0.10') == 1\n  hi('MiniDepsChangeAdded',   { link = has_core_diff_hl and 'Added' or 'diffAdded' })\n  hi('MiniDepsChangeRemoved', { link = has_core_diff_hl and 'Removed' or 'diffRemoved' })\n  hi('MiniDepsHint',          { link = 'DiagnosticHint' })\n  hi('MiniDepsInfo',          { link = 'DiagnosticInfo' })\n  hi('MiniDepsMsgBreaking',   { link = 'DiagnosticWarn' })\n  hi('MiniDepsPlaceholder',   { link = 'Comment' })\n  hi('MiniDepsTitle',         { link = 'Title' })\n  hi('MiniDepsTitleError',    { link = 'DiffDelete' })\n  hi('MiniDepsTitleSame',     { link = 'DiffText' })\n  hi('MiniDepsTitleUpdate',   { link = 'DiffAdd' })\nend\n\nH.create_user_commands = function()\n  -- Do not create commands immediately to increase startup time\n  local new_cmd = vim.schedule_wrap(vim.api.nvim_create_user_command)\n\n  local complete_session_names = function(arg, _, _)\n    local session_names = vim.tbl_map(function(s) return s.name end, MiniDeps.get_session())\n    return vim.tbl_filter(function(n) return vim.startswith(n, arg) end, session_names)\n  end\n  local complete_disk_names = function(arg, _, _)\n    local disk_names = vim.tbl_map(function(p) return vim.fn.fnamemodify(p, ':t') end, H.get_all_plugin_paths())\n    return vim.tbl_filter(function(n) return vim.startswith(n, arg) end, disk_names)\n  end\n\n  local add = function(input) MiniDeps.add(input.fargs[1]) end\n  new_cmd('DepsAdd', add, { nargs = '+', complete = complete_disk_names, desc = 'Add plugin to session' })\n\n  local make_update_cmd = function(name, offline, desc)\n    local callback = function(input)\n      local names\n      if #input.fargs > 0 then names = input.fargs end\n      MiniDeps.update(names, { force = input.bang, offline = offline })\n    end\n    local opts = { bang = true, complete = complete_session_names, nargs = '*', desc = desc }\n    new_cmd(name, callback, opts)\n  end\n  make_update_cmd('DepsUpdate', false, 'Update plugins')\n  make_update_cmd('DepsUpdateOffline', true, 'Update plugins without downloading from source')\n\n  local show_log = function()\n    H.edit(H.get_config().path.log)\n    H.update_add_syntax()\n    vim.cmd([[syntax match MiniDepsTitle \"^\\(==========\\).*\\1$\"]])\n  end\n  new_cmd('DepsShowLog', show_log, { desc = 'Show log' })\n\n  local clean = function(input) MiniDeps.clean({ force = input.bang }) end\n  new_cmd('DepsClean', clean, { bang = true, desc = 'Delete unused plugins' })\n\n  local snap_save = function(input) MiniDeps.snap_save(input.fargs[1]) end\n  new_cmd('DepsSnapSave', snap_save, { nargs = '*', complete = 'file', desc = 'Save plugin snapshot' })\n\n  local snap_load = function(input) MiniDeps.snap_load(input.fargs[1]) end\n  new_cmd('DepsSnapLoad', snap_load, { nargs = '*', complete = 'file', desc = 'Load plugin snapshot' })\nend\n\n-- Git commands ---------------------------------------------------------------\nH.git_cmd = function(cmd_name, ...)\n  local args = H.git_args[cmd_name](...)\n  if args == nil then return {} end\n\n  -- Use '-c gc.auto=0' to disable `stderr` \"Auto packing...\" messages\n  return { 'git', '-c', 'gc.auto=0', unpack(args) }\nend\n\n--stylua: ignore\nH.git_args = {\n  version = function()\n    return { 'version' }\n  end,\n  clone = function(source, path)\n    local res = {\n      'clone', '--quiet', '--filter=blob:none',\n      '--recurse-submodules', '--also-filter-submodules', '--origin', 'origin',\n      source, path,\n    }\n    -- Use `--also-filter-submodules` only with appropriate version\n    if not (H.cache.git_version.major >= 2 and H.cache.git_version.minor >= 36) then\n      table.remove(res, 5)\n    end\n    return res\n  end,\n  stash = function(timestamp)\n    return { 'stash', '--quiet', '--message', '(mini.deps) ' .. timestamp .. ' Stash before checkout' }\n  end,\n  checkout = function(target)\n    return { 'checkout', '--quiet', target }\n  end,\n  -- Using '--tags --force' means conflicting tags will be synced with remote\n  fetch = function()\n    return { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' }\n  end,\n  set_origin = function(source)\n    return { 'remote', 'set-url', 'origin', source }\n  end,\n  get_origin = function()\n    return { 'remote', 'get-url', 'origin' }\n  end,\n  get_default_origin_branch = function()\n    return { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }\n  end,\n  is_origin_branch = function(name)\n    -- Returns branch's name if it is present\n    return { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/' .. name }\n  end,\n  -- Using `rev-list -1` shows a commit of revision, while `rev-parse` shows\n  -- hash of revision. Those are different for annotated tags.\n  get_hash = function(rev)\n    return { 'rev-list', '-1', rev }\n  end,\n  log = function(from, to)\n    if from == nil or to == nil or from == to then return nil end\n    -- `--topo-order` makes showing divergent branches nicer\n    -- `--decorate-refs` shows only tags near commits (not `origin/main`, etc.)\n    --stylua: ignore\n    return {\n      'log', '--pretty=format:%m %h | %ai | %an%d%n  %s%n', '--topo-order', '--decorate-refs=refs/tags',\n      from .. '...' .. to,\n    }\n  end,\n}\n\nH.ensure_git_exec = function()\n  if H.cache.git_version ~= nil then return end\n  local jobs = { H.cli_new_job(H.git_cmd('version'), vim.fn.getcwd()) }\n  H.cli_run(jobs)\n  if #jobs[1].err > 0 then H.error('Could not find executable `git` CLI tool') end\n  local major, minor = string.match(H.cli_stream_tostring(jobs[1].out), '(%d+)%.(%d+)')\n  H.cache.git_version = { major = tonumber(major), minor = tonumber(minor) }\nend\n\n-- Plugin specification -------------------------------------------------------\nH.expand_spec = function(target, spec)\n  -- Prepare\n  if type(spec) == 'string' then\n    local field = string.find(spec, '/') ~= nil and 'source' or 'name'\n    spec = { [field] = spec }\n  end\n  if type(spec) ~= 'table' then H.error('Plugin spec should be table.') end\n\n  local has_min_fields = type(spec.source) == 'string' or type(spec.name) == 'string'\n  if not has_min_fields then H.error('Plugin spec should have proper `source` or `name`.') end\n\n  -- Normalize\n  spec = vim.deepcopy(spec)\n\n  if spec.source and type(spec.source) ~= 'string' then H.error('`source` in plugin spec should be string.') end\n  local is_user_repo = type(spec.source) == 'string' and spec.source:find('^[%w-]+/[%w-_.]+$') ~= nil\n  if is_user_repo then spec.source = 'https://github.com/' .. spec.source end\n\n  spec.name = spec.name or vim.fn.fnamemodify(spec.source, ':t')\n  if type(spec.name) ~= 'string' then H.error('`name` in plugin spec should be string.') end\n  if string.find(spec.name, '/') ~= nil then H.error('`name` in plugin spec should not contain \"/\".') end\n  if spec.name == '' then H.error('`name` in plugin spec should not be empty.') end\n\n  if spec.checkout and type(spec.checkout) ~= 'string' then H.error('`checkout` in plugin spec should be string.') end\n  if spec.monitor and type(spec.monitor) ~= 'string' then H.error('`monitor` in plugin spec should be string.') end\n\n  spec.hooks = vim.deepcopy(spec.hooks) or {}\n  if type(spec.hooks) ~= 'table' then H.error('`hooks` in plugin spec should be table.') end\n  local hook_names = { 'pre_install', 'post_install', 'pre_checkout', 'post_checkout' }\n  for _, hook_name in ipairs(hook_names) do\n    local is_not_hook = spec.hooks[hook_name] and not vim.is_callable(spec.hooks[hook_name])\n    if is_not_hook then H.error('`hooks.' .. hook_name .. '` in plugin spec should be callable.') end\n  end\n\n  -- Expand dependencies recursively before adding current spec to target\n  spec.depends = vim.deepcopy(spec.depends) or {}\n  if not H.islist(spec.depends) then H.error('`depends` in plugin spec should be array.') end\n  for _, dep_spec in ipairs(spec.depends) do\n    H.expand_spec(target, dep_spec)\n  end\n\n  table.insert(target, spec)\nend\n\n-- Plugin operations ----------------------------------------------------------\nH.plugs_exec_hooks = function(plugs, name)\n  for _, p in ipairs(plugs) do\n    local has_error = p.job and #p.job.err > 0\n    local should_execute = vim.is_callable(p.hooks[name]) and not has_error\n    if should_execute then\n      local ok, err = pcall(p.hooks[name], { path = p.path, source = p.source, name = p.name })\n      if not ok then\n        local msg = string.format('Error executing %s hook in `%s`:\\n%s', name, p.name, err)\n        H.notify(msg, 'ERROR')\n      end\n    end\n  end\nend\n\nH.plugs_install = function(plugs)\n  -- Clone\n  local prepare = function(p)\n    if p.source == nil and #p.job.err == 0 then p.job.err = { 'SPECIFICATION HAS NO `source` TO INSTALL PLUGIN.' } end\n    p.job.command = H.git_cmd('clone', p.source or '', p.path)\n    p.job.exit_msg = string.format('Installed `%s`', p.name)\n  end\n  H.plugs_run_jobs(plugs, prepare)\n\n  -- Checkout\n  vim.tbl_map(function(p) p.job.cwd = p.path end, plugs)\n  H.plugs_checkout(plugs, { exec_hooks = false, all_helptags = true })\n\n  -- Show warnings and errors\n  H.plugs_show_job_notifications(plugs, 'installing plugin')\nend\n\nH.plugs_download_updates = function(plugs)\n  -- Show actual target number of plugins attempted to fetch\n  local n_noerror = 0\n  for _, p in ipairs(plugs) do\n    if #p.job.err == 0 then n_noerror = n_noerror + 1 end\n  end\n  if n_noerror == 0 then return end\n  H.notify('Downloading ' .. n_noerror .. ' update' .. (n_noerror > 1 and 's' or ''))\n\n  local prepare = function(p)\n    p.job.command = H.git_cmd('fetch')\n    p.job.exit_msg = string.format('Downloaded update for `%s`', p.name)\n  end\n  H.plugs_run_jobs(plugs, prepare)\nend\n\nH.plugs_checkout = function(plugs, opts)\n  opts = vim.tbl_deep_extend('force', { exec_hooks = true, all_helptags = false }, opts or {})\n\n  H.plugs_infer_head(plugs)\n  H.plugs_ensure_target_refs(plugs)\n  H.plugs_infer_commit(plugs, 'checkout', 'checkout_to')\n\n  -- Operate only on plugins that actually need checkout\n  local checkout_plugs = vim.tbl_filter(function(p) return p.head ~= p.checkout_to end, plugs)\n\n  -- Stash changes\n  local stash_command = H.git_cmd('stash', H.get_timestamp())\n  local prepare = function(p) p.job.command = stash_command end\n  H.plugs_run_jobs(checkout_plugs, prepare)\n\n  -- Execute pre hooks\n  if opts.exec_hooks then H.plugs_exec_hooks(checkout_plugs, 'pre_checkout') end\n\n  -- Checkout\n  prepare = function(p)\n    p.job.command = H.git_cmd('checkout', p.checkout_to)\n    p.job.exit_msg = string.format('Checked out `%s` in `%s`', p.checkout, p.name)\n  end\n  H.plugs_run_jobs(checkout_plugs, prepare)\n\n  -- Execute post hooks\n  if opts.exec_hooks then H.plugs_exec_hooks(checkout_plugs, 'post_checkout') end\n\n  -- (Re)Generate help tags according to the current help files\n  local help_plugs = opts.all_helptags and plugs or checkout_plugs\n  for _, p in ipairs(help_plugs) do\n    local doc_dir = p.path .. '/doc'\n    -- Completely redo tags\n    vim.fn.delete(doc_dir .. '/tags')\n    local has_help_files = vim.fn.glob(doc_dir .. '/**') ~= ''\n    if has_help_files then pcall(vim.cmd, 'helptags ' .. vim.fn.fnameescape(doc_dir)) end\n  end\nend\n\n-- Plugin operation helpers ---------------------------------------------------\nH.plugs_from_names = function(names)\n  if names and not H.islist(names) then H.error('`names` should be array.') end\n  for _, name in ipairs(names or {}) do\n    if type(name) ~= 'string' then H.error('`names` should contain only strings.') end\n  end\n\n  local res = {}\n  for _, spec in ipairs(MiniDeps.get_session()) do\n    if names == nil or vim.tbl_contains(names, spec.name) then\n      spec.job = H.cli_new_job({}, spec.path)\n      table.insert(res, spec)\n    end\n  end\n\n  return res\nend\n\nH.plugs_run_jobs = function(plugs, prepare, process)\n  if vim.is_callable(prepare) then vim.tbl_map(prepare, plugs) end\n\n  H.cli_run(vim.tbl_map(function(p) return p.job end, plugs))\n\n  if vim.is_callable(process) then vim.tbl_map(process, plugs) end\n\n  -- Clean jobs. Preserve errors for jobs to be properly reusable.\n  for _, p in ipairs(plugs) do\n    p.job.command, p.job.exit_msg, p.job.out = {}, nil, {}\n  end\nend\n\nH.plugs_show_job_notifications = function(plugs, action_name)\n  for _, p in ipairs(plugs) do\n    local warn = H.cli_stream_tostring(p.job.warn)\n    if warn ~= '' then\n      local msg = string.format('Warnings in `%s` during %s\\n%s', p.name, action_name, warn)\n      H.notify(msg, 'WARN')\n    end\n    local err = H.cli_stream_tostring(p.job.err)\n    if err ~= '' then\n      local msg = string.format('Error in `%s` during %s\\n%s', p.name, action_name, err)\n      H.notify(msg, 'ERROR')\n    end\n  end\nend\n\nH.plugs_ensure_origin_source = function(plugs)\n  local prepare = function(p) p.job.command = p.source and H.git_cmd('set_origin', p.source) or H.git_cmd('get_origin') end\n  local process = function(p) p.source = p.source or H.cli_stream_tostring(p.job.out) end\n  H.plugs_run_jobs(plugs, prepare, process)\nend\n\nH.plugs_ensure_target_refs = function(plugs)\n  local prepare = function(p)\n    local needs_infer = p.checkout == nil or p.monitor == nil\n    p.job.command = needs_infer and H.git_cmd('get_default_origin_branch') or {}\n  end\n  local process = function(p)\n    local def_branch = H.cli_stream_tostring(p.job.out):gsub('^origin/', '')\n    p.checkout = p.checkout or def_branch\n    p.monitor = p.monitor or def_branch\n    p.has_monitor = p.checkout ~= p.monitor\n  end\n  H.plugs_run_jobs(plugs, prepare, process)\nend\n\nH.plugs_infer_head = function(plugs)\n  local prepare = function(p) p.job.command = p.head == nil and H.git_cmd('get_hash', 'HEAD') or {} end\n  local process = function(p) p.head = p.head or H.cli_stream_tostring(p.job.out) end\n  H.plugs_run_jobs(plugs, prepare, process)\nend\n\nH.plugs_infer_commit = function(plugs, field_ref, field_out)\n  -- Determine if reference points to an origin branch (to avoid error later)\n  local prepare = function(p)\n    -- Don't recompute commit if it is already computed\n    -- Don't compute commit for 'monitor' if it won't be used\n    p.should_infer = p[field_out] == nil and (field_ref ~= 'monitor' or p.has_monitor)\n    p.job.command = p.should_infer and H.git_cmd('is_origin_branch', p[field_ref]) or {}\n  end\n  local process = function(p) p.is_ref_origin_branch = H.cli_stream_tostring(p.job.out):find('%S') ~= nil end\n  H.plugs_run_jobs(plugs, prepare, process)\n\n  -- Infer commit depending on whether it points to origin branch\n  prepare = function(p)\n    -- Force `checkout = 'HEAD'` to always point to current commit to freeze\n    -- updates. This is needed because `origin/HEAD` is also present.\n    local is_from_origin = p.is_ref_origin_branch and p[field_ref] ~= 'HEAD'\n    local ref = (is_from_origin and 'origin/' or '') .. p[field_ref]\n    p.job.command = p.should_infer and H.git_cmd('get_hash', ref) or {}\n  end\n  process = function(p)\n    if p.should_infer then p[field_out] = H.cli_stream_tostring(p.job.out) end\n    p.is_ref_origin_branch, p.should_infer = nil, nil\n  end\n  H.plugs_run_jobs(plugs, prepare, process)\nend\n\nH.plugs_infer_log = function(plugs, field_from, field_to, field_out)\n  local prepare = function(p) p.job.command = H.git_cmd('log', p[field_from], p[field_to]) end\n  local process = function(p) p[field_out] = H.cli_stream_tostring(p.job.out) end\n  H.plugs_run_jobs(plugs, prepare, process)\nend\n\n-- File system ----------------------------------------------------------------\nH.get_plugin_path = function(name)\n  local package_path = H.get_package_path()\n\n  -- First check for the most common case of name present in 'pack/deps/opt'\n  local opt_path = string.format('%s/pack/deps/opt/%s', package_path, name)\n  if vim.loop.fs_stat(opt_path) ~= nil then return opt_path, true end\n\n  -- Allow processing 'pack/deps/start'\n  local start_path = string.format('%s/pack/deps/start/%s', package_path, name)\n  if vim.loop.fs_stat(start_path) ~= nil then return start_path, true end\n\n  -- Use 'opt' directory by default\n  return opt_path, false\nend\n\nH.get_all_plugin_paths = function()\n  local deps_path, res = H.get_package_path() .. '/pack/deps', {}\n  vim.list_extend(res, H.readdir(deps_path .. '/opt'))\n  vim.list_extend(res, H.readdir(deps_path .. '/start'))\n  return res\nend\n\nH.get_package_path = function() return H.full_path(H.get_config().path.package) end\n\n-- Clean ----------------------------------------------------------------------\nH.clean_confirm = function(paths)\n  -- Compute lines\n  local lines = {\n    'This is a confirmation report before a clean.',\n    '',\n    'Lines `- <plugin>` show plugins to be deleted from disk.',\n    'Remove line to not delete that plugin.',\n    '',\n    'To finish clean, write this buffer (for example, with `:write` command).',\n    'To cancel clean, close this window (for example, with `:close` command).',\n    '',\n  }\n  local n_header = #lines - 1\n  for _, p in ipairs(paths) do\n    table.insert(lines, string.format('- %s (%s)', vim.fn.fnamemodify(p, ':t'), p))\n  end\n\n  -- Show report in new buffer in separate tabpage\n  local finish_clean = function(buf_id)\n    -- Compute plugin paths to update\n    local paths_to_delete = {}\n    for _, l in ipairs(vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)) do\n      local cur_path = string.match(l, '^%- .* %((.*)%)$')\n      if cur_path ~= nil then table.insert(paths_to_delete, cur_path) end\n    end\n\n    if #paths_to_delete == 0 then return H.notify('Nothing to delete') end\n    H.clean_delete(paths_to_delete)\n  end\n  H.show_confirm_buf(lines, { name = 'confirm-clean', exec_on_write = finish_clean })\n\n  -- Define basic highlighting\n  vim.cmd('syntax region MiniDepsHint start=\"^\\\\%1l\" end=\"\\\\%' .. n_header .. 'l$\"')\n\n  -- Define conceal to show only name with whole path when cursor is on it\n  vim.cmd('syntax conceal on')\n  vim.cmd([[syntax match MiniDepsInfo \"\\s\\+(.\\{-})$\"]])\n  vim.cmd('syntax conceal off')\n  vim.cmd('setlocal conceallevel=3')\nend\n\nH.clean_delete = function(paths)\n  local n_to_delete = #paths\n  for i, p in ipairs(paths) do\n    vim.fn.delete(p, 'rf')\n    local msg = string.format('(%d/%d) Deleted `%s` from disk', i, n_to_delete, vim.fn.fnamemodify(p, ':t'))\n    H.notify(msg)\n  end\nend\n\n-- Update ---------------------------------------------------------------------\nH.update_compute_feedback_lines = function(plugs)\n  -- Construct lines with metadata for later sort\n  local plug_data = {}\n  for i, p in ipairs(plugs) do\n    local lines = H.update_compute_report_single(p)\n    --stylua: ignore\n    plug_data[i] = {\n      lines = lines, has_error = p.has_error, has_updates = p.has_updates, has_monitor = p.has_monitor, name = p.name, index = i\n    }\n  end\n\n  -- Sort to put first ones with errors, then with updates, then rest\n  local compare = function(a, b)\n    if a.has_error and not b.has_error then return true end\n    if not a.has_error and b.has_error then return false end\n    if a.has_updates and not b.has_updates then return true end\n    if not a.has_updates and b.has_updates then return false end\n    if a.has_monitor and not b.has_monitor then return true end\n    if not a.has_monitor and b.has_monitor then return false end\n    if a.name == 'mini.nvim' then return true end\n    if b.name == 'mini.nvim' then return false end\n    return a.index < b.index\n  end\n  table.sort(plug_data, compare)\n\n  local plug_lines = vim.tbl_map(function(x) return x.lines end, plug_data)\n  return vim.split(table.concat(plug_lines, '\\n\\n'), '\\n')\nend\n\nH.update_compute_report_single = function(p)\n  p.has_error, p.has_updates = #p.job.err > 0, p.head ~= p.checkout_to\n\n  local err = H.cli_stream_tostring(p.job.err)\n  if err ~= '' then return string.format('!!! %s !!!\\n\\n%s', p.name, err) end\n\n  -- Compute title surrounding based on whether plugin needs an update\n  local surrounding = p.has_updates and '+++' or '---'\n  local parts = { string.format('%s %s %s\\n', surrounding, p.name, surrounding) }\n\n  if p.head == p.checkout_to then\n    table.insert(parts, 'Path:   ' .. p.path .. '\\n')\n    table.insert(parts, 'Source: ' .. (p.source or '<None>') .. '\\n')\n    table.insert(parts, string.format('State:  %s (%s)', p.checkout_to, p.checkout))\n  else\n    table.insert(parts, 'Path:         ' .. p.path .. '\\n')\n    table.insert(parts, 'Source:       ' .. (p.source or '<None>') .. '\\n')\n    table.insert(parts, 'State before: ' .. p.head .. '\\n')\n    table.insert(parts, string.format('State after:  %s (%s)', p.checkout_to, p.checkout))\n  end\n\n  -- Show pending updates only if they are present\n  if p.has_updates then\n    table.insert(parts, string.format('\\n\\nPending updates from `%s`:\\n', p.checkout))\n    table.insert(parts, p.checkout_log)\n  end\n\n  -- Show monitor updates only if user asked for them\n  if p.has_monitor then\n    table.insert(parts, string.format('\\n\\nMonitor updates from `%s`:\\n', p.monitor))\n    table.insert(parts, p.monitor_log ~= '' and p.monitor_log or '<Nothing>')\n  end\n\n  return table.concat(parts, '')\nend\n\nH.update_feedback_confirm = function(lines)\n  -- Add helper header\n  local report = {\n    'This is a confirmation report before an update.',\n    '',\n    'Line `+++ <plugin_name> +++` means plugin will be updated.',\n    'See update details below it.',\n    'Changes starting with \">\"/\"<\" will be added/removed.',\n    'Remove the line to not update that plugin.',\n    '',\n    'Line `--- <plugin_name> ---` means plugin has nothing to update.',\n    '',\n    \"Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.\",\n    'See error details below it.',\n    '',\n    'Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.',\n    'To finish update, write this buffer (for example, with `:write` command).',\n    'To cancel update, close this window (for example, with `:close` command).',\n    '',\n  }\n  local n_header = #report - 1\n  vim.list_extend(report, lines)\n\n  -- Show report in new buffer in separate tabpage\n  local finish_update = function(buf_id)\n    -- Compute plugin names to update\n    local names = {}\n    for _, l in ipairs(vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)) do\n      local cur_name = string.match(l, '^%+%+%+ (.*) %+%+%+$')\n      if cur_name ~= nil then table.insert(names, cur_name) end\n    end\n\n    -- Update and delete buffer (in that order, to show that update is done)\n    MiniDeps.update(names, { force = true, offline = true })\n  end\n\n  H.show_confirm_buf(report, { name = 'confirm-update', exec_on_write = finish_update, setup_folds = true })\n\n  -- Define basic highlighting\n  vim.cmd('syntax region MiniDepsHint start=\"^\\\\%1l\" end=\"\\\\%' .. n_header .. 'l$\"')\n  H.update_add_syntax()\nend\n\nH.update_add_syntax = function()\n  vim.cmd([[\n    syntax match MiniDepsTitleError    \"^!!! .\\+ !!!$\"\n    syntax match MiniDepsTitleUpdate   \"^+++ .\\+ +++$\"\n    syntax match MiniDepsTitleSame     \"^--- .\\+ ---$\"\n    syntax match MiniDepsInfo          \"^Path: \\+\\zs[^ ]\\+\"\n    syntax match MiniDepsInfo          \"^Source: \\+\\zs[^ ]\\+\"\n    syntax match MiniDepsInfo          \"^State[^:]*: \\+\\zs[^ ]\\+\\ze\"\n    syntax match MiniDepsHint          \"\\(^State.\\+\\)\\@<=(.\\+)$\"\n    syntax match MiniDepsChangeAdded   \"^> .*$\"\n    syntax match MiniDepsChangeRemoved \"^< .*$\"\n    syntax match MiniDepsMsgBreaking   \"^  \\S\\+!: .*$\"\n    syntax match MiniDepsPlaceholder   \"^<.*>$\"\n  ]])\nend\n\nH.update_feedback_log = function(lines)\n  local title = string.format('========== Update %s ==========', H.get_timestamp())\n  table.insert(lines, 1, title)\n  table.insert(lines, '')\n\n  local log_path = H.get_config().path.log\n  vim.fn.mkdir(vim.fn.fnamemodify(log_path, ':h'), 'p')\n  vim.fn.writefile(lines, log_path, 'a')\nend\n\n-- Confirm --------------------------------------------------------------------\nH.show_confirm_buf = function(lines, opts)\n  -- Show buffer\n  local buf_id = vim.api.nvim_create_buf(true, true)\n  H.set_buf_name(buf_id, opts.name)\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n  vim.cmd('tab sbuffer ' .. buf_id)\n  local tab_num, win_id = vim.api.nvim_tabpage_get_number(0), vim.api.nvim_get_current_win()\n\n  local delete_buffer = vim.schedule_wrap(function()\n    pcall(vim.api.nvim_buf_delete, buf_id, { force = true })\n    pcall(function() vim.cmd('tabclose ' .. tab_num) end)\n    vim.cmd('redraw')\n  end)\n\n  -- Define folding\n  local is_title = function(l) return l:find('^%-%-%-') or l:find('^%+%+%+') or l:find('^%!%!%!') end\n  --stylua: ignore\n  MiniDeps._confirm_foldexpr = function(lnum)\n    if lnum == 1 then return 0 end\n    if is_title(vim.fn.getline(lnum - 1)) then return 1 end\n    if is_title(vim.fn.getline(lnum + 1)) then return 0 end\n    return '='\n  end\n\n  -- Possibly set up folding. Use `:setlocal` for these options to not be\n  -- inherited if some other buffer is opened in the same window.\n  if opts.setup_folds then\n    vim.cmd('setlocal foldenable foldmethod=expr foldlevel=999')\n    vim.cmd('setlocal foldexpr=v:lua.MiniDeps._confirm_foldexpr(v:lnum)')\n  end\n\n  -- Define action on accepting confirm\n  local finish = function()\n    MiniDeps._confirm_foldexpr = nil\n    opts.exec_on_write(buf_id)\n    delete_buffer()\n  end\n  -- - Use `nested` to allow other events (`WinEnter` for 'mini.statusline')\n  vim.api.nvim_create_autocmd('BufWriteCmd', { buffer = buf_id, nested = true, callback = finish })\n\n  -- Define action to cancel confirm\n  local cancel_au_id\n  local on_cancel = function(data)\n    MiniDeps._confirm_foldexpr = nil\n    if tonumber(data.match) ~= win_id then return end\n    pcall(vim.api.nvim_del_autocmd, cancel_au_id)\n    delete_buffer()\n  end\n  cancel_au_id = vim.api.nvim_create_autocmd('WinClosed', { nested = true, callback = on_cancel })\n\n  -- Set buffer-local options last (so that user autocmmands could override)\n  vim.bo.buftype, vim.bo.filetype, vim.bo.modified = 'acwrite', 'minideps-confirm', false\nend\n\n-- CLI ------------------------------------------------------------------------\nH.cli_run = function(jobs)\n  local config_job = H.get_config().job\n  local n_threads = math.max(config_job.n_threads or H.get_n_threads(), 1)\n\n  -- Use only actually runnable jobs\n  local should_run = function(job)\n    -- Run only if there is command to run and previous runs of same reusable\n    -- job did not result into error\n    return type(job.command) == 'table' and #job.command > 0 and #job.err == 0\n  end\n  jobs = vim.tbl_filter(should_run, jobs)\n\n  local n_total, id_started, n_finished = #jobs, 0, 0\n  if n_total == 0 then return end\n\n  local run_next\n  run_next = function()\n    if n_total <= id_started then return end\n    id_started = id_started + 1\n\n    local job = jobs[id_started]\n    local command, cwd, exit_msg = job.command or {}, job.cwd, job.exit_msg\n\n    -- Prepare data for `vim.loop.spawn`\n    local executable, args = command[1], vim.list_slice(command, 2, #command)\n    local process, stdout, stderr = nil, vim.loop.new_pipe(), vim.loop.new_pipe()\n\n    -- - Unset special `GIT_xxx` variables that can affect `git` commands\n    local env_map = vim.fn.environ()\n    env_map.GIT_DIR, env_map.GIT_WORK_TREE = nil, nil\n    local env = {}\n    for k, v in pairs(env_map) do\n      table.insert(env, k .. '=' .. tostring(v))\n    end\n\n    local spawn_opts = { args = args, cwd = cwd, env = env, stdio = { nil, stdout, stderr } }\n\n    local on_exit = function(code)\n      -- Process only not already closing job\n      if process:is_closing() then return end\n      process:close()\n\n      -- Process exit code: if 0 treat `stderr` as warning; error otherwise\n      if code == 0 then\n        vim.list_extend(job.warn, job.err)\n        -- NOTE: This is valid as only jobs with `err = {}` are filtered to run\n        job.err = {}\n      else\n        table.insert(job.err, 1, 'ERROR CODE ' .. code .. '\\n')\n      end\n\n      -- Finalize job\n      n_finished = n_finished + 1\n      if type(exit_msg) == 'string' and #job.err == 0 then\n        H.notify(string.format('(%d/%d) %s', n_finished, n_total, exit_msg))\n      end\n\n      -- Start next parallel job\n      run_next()\n    end\n\n    process = vim.loop.spawn(executable, spawn_opts, on_exit)\n    H.cli_read_stream(stdout, job.out)\n    H.cli_read_stream(stderr, job.err)\n    vim.defer_fn(function()\n      if not process:is_active() then return end\n      table.insert(job.err, 'PROCESS REACHED TIMEOUT.')\n      on_exit(1)\n    end, config_job.timeout)\n  end\n\n  for _ = 1, n_threads do\n    run_next()\n  end\n\n  vim.wait(config_job.timeout * n_total, function() return n_total <= n_finished end, 1)\nend\n\nH.cli_read_stream = function(stream, feed)\n  local callback = function(err, data)\n    if err then return table.insert(feed, 1, 'ERROR: ' .. err) end\n    if data ~= nil then return table.insert(feed, data) end\n    stream:close()\n  end\n  stream:read_start(callback)\nend\n\nH.cli_stream_tostring = function(stream) return (table.concat(stream):gsub('\\n+$', '')) end\n\nH.cli_new_job = function(command, cwd, exit_msg)\n  return { command = command, cwd = cwd, exit_msg = exit_msg, out = {}, warn = {}, err = {} }\nend\n\n-- Two-stage execution --------------------------------------------------------\nH.schedule_finish = function()\n  if H.cache.finish_is_scheduled then return end\n  vim.schedule(H.finish)\n  H.cache.finish_is_scheduled = true\nend\n\nH.finish = function()\n  local timer, step_delay = vim.loop.new_timer(), 1\n  local f = nil\n  f = vim.schedule_wrap(function()\n    local callback = H.cache.later_callback_queue[1]\n    if callback == nil then\n      H.cache.finish_is_scheduled, H.cache.later_callback_queue = false, {}\n      H.report_errors()\n      return\n    end\n\n    table.remove(H.cache.later_callback_queue, 1)\n    MiniDeps.now(callback)\n    timer:start(step_delay, 0, f)\n  end)\n  timer:start(step_delay, 0, f)\nend\n\nH.report_errors = function()\n  if #H.cache.exec_errors == 0 then return end\n  local error_lines = table.concat(H.cache.exec_errors, '\\n\\n')\n  H.cache.exec_errors = {}\n  H.notify('There were errors during two-stage execution:\\n\\n' .. error_lines, 'ERROR')\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.deps) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minideps://' .. buf_id .. '/' .. name) end\n\nH.notify = vim.schedule_wrap(function(msg, level)\n  level = level or 'INFO'\n  if H.get_config().silent and level ~= 'ERROR' and level ~= 'WARN' then return end\n  if type(msg) == 'table' then msg = table.concat(msg, '\\n') end\n  vim.notify(string.format('(mini.deps) %s', msg), vim.log.levels[level])\n  vim.cmd('redraw')\nend)\n\nH.edit = function(path, win_id)\n  if type(path) ~= 'string' then return end\n  local b = vim.api.nvim_win_get_buf(win_id or 0)\n  local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)\n    and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))\n  local buf_id = vim.fn.bufadd(vim.fn.fnamemodify(path, ':.'))\n  -- Showing in window also loads. Use `pcall` to not error with swap messages.\n  pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)\n  vim.bo[buf_id].buflisted = true\n  if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end\n  return buf_id\nend\n\nH.get_timestamp = function() return vim.fn.strftime('%Y-%m-%d %H:%M:%S') end\n\nH.get_n_threads = function() return math.floor(0.8 * #(vim.loop.cpu_info() or {})) end\n\nH.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('\\\\', '/'):gsub('/+', '/'):gsub('(.)/$', '%1')) end\n\nH.readdir = function(path)\n  if vim.fn.isdirectory(path) ~= 1 then return {} end\n  return vim.tbl_map(function(x) return path .. '/' .. x end, vim.fn.readdir(path))\nend\n\nH.source = function(path)\n  pcall(function() vim.cmd('source ' .. vim.fn.fnameescape(path)) end)\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniDeps\n"
  },
  {
    "path": "lua/mini/diff.lua",
    "content": "--- *mini.diff* Work with diff hunks\n---\n--- MIT License Copyright (c) 2024 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Visualize difference between buffer text and its configurable reference\n---   interactively (updates as you type). This is done per line showing whether\n---   it is inside added, changed, or deleted part of difference (called hunk).\n---   Visualization can be with customizable colored signs or line numbers.\n---\n--- - Special toggleable overlay view with more hunk details inside text area.\n---   See |MiniDiff.toggle_overlay()|.\n---\n--- - Completely configurable per buffer source(s) of reference text used to keep\n---   it up to date and define interactions with it. Can be array of sources which\n---   are attempted to attach in order. See |MiniDiff-source-specification|.\n---   By default uses Git source. See |MiniDiff.gen_source.git()|.\n---\n--- - Configurable mappings to manage diff hunks:\n---     - Apply and reset hunks inside region (selected visually or with\n---       a dot-repeatable operator).\n---     - \"Hunk range under cursor\" textobject to be used as operator target.\n---     - Navigate to first/previous/next/last hunk. See |MiniDiff.goto_hunk()|.\n---\n--- What it doesn't do:\n---\n--- - Provide functionality to work directly with Git outside of visualizing\n---   and staging (applying) hunks with (default) Git source. In particular,\n---   unstaging hunks is not supported. See |MiniDiff.gen_source.git()|.\n---\n--- Sources with more details:\n--- - |MiniDiff-overview|\n--- - |MiniDiff-source-specification|\n--- - |MiniDiff-hunk-specification|\n--- - |MiniDiff-diff-summary|\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.diff').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniDiff`\n--- which you can use for scripting or manually (with `:lua MiniDiff.*`).\n---\n--- See |MiniDiff.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minidiff_config` which should have same structure as\n--- `MiniDiff.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim):\n---     - Main inspiration for this module, so there are many similarities.\n---     - Can display only Git hunks, while this module has extensible design.\n---     - Provides more functionality to work with Git outside of hunks.\n---       This module does not (by design).\n---\n--- # Highlight groups ~\n---\n--- - `MiniDiffSignAdd`        - \"add\" hunk lines visualization.\n--- - `MiniDiffSignChange`     - \"change\" hunk lines visualization.\n--- - `MiniDiffSignDelete`     - \"delete\" hunk lines visualization.\n--- - `MiniDiffOverAdd`        - added buffer text shown in overlay.\n--- - `MiniDiffOverChange`     - changed reference text shown in overlay.\n--- - `MiniDiffOverChangeBuf`  - changed buffer text shown in overlay.\n--- - `MiniDiffOverContext`    - context of a change shown in reference overlay.\n--- - `MiniDiffOverContextBuf` - context of a change shown in buffer overlay.\n--- - `MiniDiffOverDelete`     - deleted reference text shown in overlay.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To temporarily disable features without relying on |MiniDiff.disable()|,\n--- set `vim.g.minidiff_disable` (globally) or `vim.b.minidiff_disable` (for\n--- a buffer) to `true`. Considering high number of different scenarios and\n--- customization intentions, writing exact rules for disabling module's\n--- functionality is left to user.\n--- See |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniDiff\n\n--- # Diffs and hunks ~\n---\n--- The \"diff\" (short for \"difference\") is a result of computing how two text\n--- strings differ from one another. This is done on per line basis, i.e. the\n--- goal is to compute sequences of lines common to both files, interspersed\n--- with groups of differing lines (called \"hunks\").\n---\n--- Although computing diff is a general concept (used on its own, in Git, etc.),\n--- this module computes difference between current text in a buffer and some\n--- reference text which is kept up to date specifically for that buffer.\n--- For example, default reference text is computed as file content in Git index.\n--- This can be customized in `config.source` (see |MiniDiff-source-specification|).\n---\n--- # Hunk specification ~\n--- *MiniDiff-hunk-specification*\n---\n--- Hunk describes two sets (one from buffer text, one - from reference) of\n--- consecutive lines which are different. In this module hunk is stored as\n--- a table with the following fields:\n---\n--- - <buf_start> `(number)` - start of hunk buffer lines. First line is 1.\n---   Can be 0 if first reference lines are deleted.\n---\n--- - <buf_count> `(number)` - number of consecutive buffer lines. Can be 0 in\n---   case reference lines are deleted.\n---\n--- - <ref_start> `(number)` - start of hunk reference lines. First line is 1.\n---   Can be 0 if lines are added before first reference line.\n---\n--- - <ref_count> `(number)` - number of consecutive reference lines. Can be 0 in\n---   case buffer lines are added.\n---\n--- - <type> `(string)` - hunk type. Can be one of:\n---     - \"add\" - lines are present in buffer but absent in reference.\n---     - \"change\" - lines are present in both buffer and reference.\n---     - \"delete\" - lines are absent in buffer but present in reference.\n---\n--- # Life cycle ~\n---\n--- - When entering proper (not already enabled, valid, showing text) buffer,\n---   it is attempted to be enabled for diff processing.\n--- - During enabling, attempt attaching the source. This should set up how\n---   reference text is kept up to date.\n--- - On every text change, diff computation is scheduled in debounced fashion\n---   after customizable delay (200 ms by default).\n--- - After the diff is computed, do the following:\n---     - Update visualization based on configurable style: either by placing\n---       colored text in sign column or coloring line numbers. Colors for both\n---       styles are defined per hunk type in corresponding `MiniDiffSign*`\n---       highlight group (see |mini.diff|) and sign text for \"sign\" style can\n---       be configured in `view.signs` of |MiniDiff.config|.\n---     - Update overlay view (if it is enabled).\n---     - Update `vim.b.minidiff_summary` and `vim.b.minidiff_summary_string`\n---       buffer-local variables. These can be used, for example, in statusline.\n---     - *MiniDiff-update-event* Trigger `MiniDiffUpdated` `User` event.\n---       See |MiniDiff-diff-summary| for example of how to use it.\n---\n--- Notes:\n--- - Use |:edit| to reset (disable and re-enable) current buffer.\n--- - To work with BOM bytes, set 'bomb' and have `ucs-bom` in 'fileencodings'.\n---\n--- # Overlay ~\n---\n--- Along with basic visualization, there is a special view called \"overlay\".\n--- Although it is meant for temporary overview of diff details and can be\n--- manually toggled via |MiniDiff.toggle_overlay()|, text can be changed with\n--- overlay reacting accordingly.\n---\n--- It shows more diff details inside text area:\n---\n--- - Added buffer lines are highlighted with `MiniDiffOverAdd` highlight group.\n---\n--- - Deleted reference lines are shown as virtual lines and highlighted with\n---   `MiniDiffOverDelete` highlight group.\n---\n--- - \"Change\" hunks with equal number of buffer/reference lines show \"word diff\".\n---   This is usually the case when `options.linematch` is enabled (as by default).\n---   Reference line is shown next to its buffer counterpart. Changed parts are\n---   highlighted with `MiniDiffOverChange` and `MiniDiffOverChangeBuf` in reference\n---   and buffer lines. The rest of lines have `MiniDiffOverContext`\n---   and `MiniDiffOverContextBuf` highlighting.\n---\n---   Change with unequal number of buffer/reference lines is shown with reference\n---   part as virtual lines highlighted with `MiniDiffOverChange` group.\n---   Corresponding buffer lines are treated as context for the change and are\n---   highlighted with `MiniDiffOverContextBuf` group.\n---\n--- Notes:\n--- - Word diff has non-zero context width. This means if changed characters\n---   are close enough, whole range between them is also colored. This usually\n---   reduces visual noise.\n--- - Virtual lines above line 1 (like deleted or changed lines) need manual\n---   scroll to become visible (with |CTRL-Y|).\n---\n--- # Mappings ~\n---\n--- This module provides mappings for common actions with diffs, like:\n--- - Apply and reset hunks.\n--- - \"Hunk range under cursor\" textobject.\n--- - Go to first/previous/next/last hunk range.\n---\n--- Examples:\n--- - `vip` followed by `gh` / `gH` applies/resets hunks inside current paragraph.\n---   Same can be achieved in operator form `ghip` / `gHip`, which has the\n---   advantage of being dot-repeatable (see |single-repeat|).\n--- - `gh_` / `gH_` applies/resets current line (even if it is not a full hunk).\n--- - `ghgh` / `gHgh` applies/resets hunk range under cursor.\n--- - `dgh` deletes hunk range under cursor.\n--- - `[H` / `[h` / `]h` / `]H` navigate cursor to the first / previous / next / last\n---   hunk range of the current buffer.\n---\n--- Mappings for some functionality are assumed to be done manually.\n--- See |MiniDiff.operator()|.\n---\n--- # Buffer-local variables ~\n--- *MiniDiff-diff-summary*\n---\n--- Each enabled buffer has the following buffer-local variables which can be\n--- used in custom statusline to show an overview of hunks in current buffer:\n---\n--- - `vim.b.minidiff_summary` is a table with the following fields:\n---     - `source_name` - name of the active source. This is the only present field\n---       if buffer's reference text is not (yet) set.\n---     - `n_ranges` - number of hunk ranges (sequences of contiguous hunks).\n---     - `add` - number of added lines.\n---     - `change` - number of changed lines.\n---     - `delete` - number of deleted lines.\n---\n--- - `vim.b.minidiff_summary_string` is a string representation of summary\n---   with a fixed format. Empty string if there is no reference text (yet).\n---   It is expected to be used as is. To achieve different formatting, use\n---   `vim.b.minidiff_summary` to construct one. The best way to do this is by\n---   overriding `vim.b.minidiff_summary_string` inside |MiniDiff-update-event|: >lua\n---\n---   local format_summary = function(data)\n---     local summary = vim.b[data.buf].minidiff_summary\n---     local t = {}\n---     if summary.add > 0 then table.insert(t, '+' .. summary.add) end\n---     if summary.change > 0 then table.insert(t, '~' .. summary.change) end\n---     if summary.delete > 0 then table.insert(t, '-' .. summary.delete) end\n---     vim.b[data.buf].minidiff_summary_string = table.concat(t, ' ')\n---   end\n---   local au_opts = { pattern = 'MiniDiffUpdated', callback = format_summary }\n---   vim.api.nvim_create_autocmd('User', au_opts)\n--- <\n---@tag MiniDiff-overview\n\n---@alias __diff_buf_id number Target buffer identifier. Default: 0 for current buffer.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n-- Module definition ==========================================================\nlocal MiniDiff = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniDiff.config|.\n---\n---@usage >lua\n---   require('mini.diff').setup() -- use default config\n---   -- OR\n---   require('mini.diff').setup({}) -- replace {} with your config table\n--- <\nMiniDiff.setup = function(config)\n  -- Export module\n  _G.MiniDiff = MiniDiff\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n  for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n    H.auto_enable({ buf = buf_id })\n  end\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # View ~\n---\n--- `config.view` contains settings for how diff hunks are visualized.\n--- Example of using custom signs: >lua\n---\n---   require('mini.diff').setup({\n---     view = {\n---       style = 'sign',\n---       signs = { add = '+', change = '~', delete = '-' },\n---     },\n---   })\n--- <\n--- `view.style` is a string defining visualization style. Can be one of \"sign\"\n--- (as a colored sign in a |sign-column|) or \"number\" (colored line number).\n--- Default: \"number\" if |'number'| option is enabled, \"sign\" otherwise.\n--- Note: with \"sign\" style it is better to have |'signcolumn'| always shown.\n---\n--- `view.signs` is a table with one or two character strings used as signs for\n--- corresponding (\"add\", \"change\", \"delete\") hunks.\n--- Default: all hunks use \"▒\" character resulting in a contiguous colored lines.\n---\n--- `view.priority` is a number with priority used for visualization and\n--- overlay |extmarks|.\n--- Default: 199 which is one less than `user` in |vim.hl.priorities| (on Neovim<0.11\n--- see |vim.hl.priorities|) to have higher priority than automated\n--- extmarks but not as in user enabled ones.\n---\n--- # Source ~\n--- *MiniDiff-source-specification*\n---\n--- `config.source` is a table with single source or array of them. Single source\n--- defines how reference text is managed in a particular buffer. Sources in array\n--- are attempted to attach in order; call |MiniDiff.disable()| if none attaches.\n---\n--- A single source table can have the following fields:\n---\n--- - <attach> `(function)` - callable which defines how and when reference text\n---   is updated inside a particular buffer. It is used inside |MiniDiff.enable()|\n---   with a buffer identifier as a single argument.\n---\n---   Should execute logic which results into calling |MiniDiff.set_ref_text()|\n---   when reference text for buffer needs to be updated. Like inside callback\n---   for an |autocommand| or file watcher (see |watch-file|).\n---\n---   For example, default Git source watches when \".git/index\" file is changed\n---   and computes reference text as the one from Git index for current file.\n---\n---   Can return `false` to indicate that attach has failed. If attach fail can\n---   not be inferred immediately (for example, due to asynchronous execution),\n---   should explicitly call |MiniDiff.fail_attach()| with appropriate arguments.\n---   This is important to properly process array of sources.\n---\n---   No default value, should be always supplied.\n---\n--- - <name> `(string|nil)` - source name. String `\"unknown\"` is used if not supplied.\n---\n--- - <detach> `(function|nil)` - callable with cleanup action to be done when\n---   buffer is disabled. It is called inside |MiniDiff.disable()| with a buffer\n---   identifier as a single argument.\n---\n---   If not supplied, nothing is done during detaching.\n---\n--- - <apply_hunks> `(function|nil)` - callable which defines how hunks are applied.\n---   It is called with buffer identifier as first argument and array of hunks\n---   (see |MiniDiff-hunk-specification|) as second. It should eventually update\n---   reference text: either by explicitly calling |MiniDiff.set_ref_text()| or\n---   performing action triggering its call.\n---\n---   For example, default Git source computes patch based on the hunks and\n---   applies it inside file's git repo.\n---\n---   If not supplied, applying hunks throws an error.\n---\n--- Default: a single |MiniDiff.gen_source.git()|.\n---\n--- # Delay ~\n---\n--- `config.delay` contains settings for delays in asynchronous processes.\n---\n--- `delay.text_change` is a number (in ms) defining how long to wait after latest\n--- text change (in debounced fashion) before updating diff and visualization.\n--- Default: 200.\n---\n--- # Mappings ~\n---\n--- `config.mappings` contains keys which are mapped during |MiniDiff.setup()|.\n---\n--- `mappings.apply` keys can be used to apply hunks inside visual/operator region.\n--- What exactly \"apply hunks\" means depends on the source and its `apply_hunks()`.\n--- For example, in default Git source it means stage hunks.\n---\n--- `mappings.reset` keys can be used to reset hunks inside visual/operator region.\n--- Reset means replacing buffer text in region with corresponding reference text.\n---\n--- `mappings.textobject` keys define \"hunk range under cursor\" textobject\n--- which can be used in Operator-pending mode as target for operator (like\n--- |d|, |y|, apply/reset hunks, etc.). It is also set up in Visual mode if\n--- keys do not conflict with `mappings.apply` and `mappings.reset`.\n--- \"Hunk range\" is used in a sense that contiguous (back-to-back) hunks are\n--- considered as parts of a same hunk range.\n---\n--- `mappings.goto_first` / `mappings.goto_prev` / `mappings.goto_next` /\n--- `mappings.goto_last` keys can be used to navigate to first / previous / next /\n--- last hunk range in the current buffer.\n---\n--- # Options ~\n---\n--- `config.options` contains various customization options.\n---\n--- `options.algorithm` is a string defining which diff algorithm to use.\n--- Default: \"histogram\". See |vim.diff()| for possible values.\n---\n--- `options.indent_heuristic` is a boolean defining whether to use indent\n--- heuristic for a (possibly) more naturally aligned hunks.\n--- Default: `true`.\n---\n--- `options.linematch` is a number defining hunk size for which a second\n--- stage diff is executed for a better aligned and more granular hunks.\n--- Default: 60. See |vim.diff()| and 'diffopt' for more details.\n---\n--- `options.wrap_goto` is a boolean indicating whether to wrap around edges during\n--- hunk navigation (with |MiniDiff.goto_hunk()| or `goto_*` mappings). Like if\n--- cursor is after the last hunk, going \"next\" will put cursor on the first hunk.\n--- Default: `false`.\nMiniDiff.config = {\n  -- Options for how hunks are visualized\n  view = {\n    -- Visualization style. Possible values are 'sign' and 'number'.\n    -- Default: 'number' if line numbers are enabled, 'sign' otherwise.\n    style = vim.go.number and 'number' or 'sign',\n\n    -- Signs used for hunks with 'sign' view\n    signs = { add = '▒', change = '▒', delete = '▒' },\n\n    -- Priority of used visualization extmarks\n    priority = 199,\n  },\n\n  -- Source(s) for how reference text is computed/updated/etc\n  -- Uses content from Git index by default\n  source = nil,\n\n  -- Delays (in ms) defining asynchronous processes\n  delay = {\n    -- How much to wait before update following every text change\n    text_change = 200,\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Apply hunks inside a visual/operator region\n    apply = 'gh',\n\n    -- Reset hunks inside a visual/operator region\n    reset = 'gH',\n\n    -- Hunk range textobject to be used inside operator\n    -- Works also in Visual mode if mapping differs from apply and reset\n    textobject = 'gh',\n\n    -- Go to hunk range in corresponding direction\n    goto_first = '[H',\n    goto_prev = '[h',\n    goto_next = ']h',\n    goto_last = ']H',\n  },\n\n  -- Various options\n  options = {\n    -- Diff algorithm. See `:h vim.diff()`.\n    algorithm = 'histogram',\n\n    -- Whether to use \"indent heuristic\". See `:h vim.diff()`.\n    indent_heuristic = true,\n\n    -- The amount of second-stage diff to align lines\n    linematch = 60,\n\n    -- Whether to wrap around edges during hunk navigation\n    wrap_goto = false,\n  },\n}\n--minidoc_afterlines_end\n\n--- Enable diff processing in buffer\n---\n---@param buf_id __diff_buf_id\nMiniDiff.enable = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n\n  -- Don't enable more than once\n  if H.is_buf_enabled(buf_id) or H.is_disabled(buf_id) then return end\n\n  -- Ensure buffer is loaded (to have up to date lines returned)\n  H.buf_ensure_loaded(buf_id)\n\n  -- Register enabled buffer with cached data for performance\n  H.update_buf_cache(buf_id)\n\n  -- Add buffer watchers\n  vim.api.nvim_buf_attach(buf_id, false, {\n    -- Called on every text change (`:h nvim_buf_lines_event`)\n    on_lines = function(_, _, _, from_line, _, to_line)\n      local buf_cache = H.cache[buf_id]\n      -- Properly detach if diffing is disabled\n      if buf_cache == nil then return true end\n      H.schedule_diff_update(buf_id, buf_cache.config.delay.text_change)\n    end,\n\n    -- Called when buffer content is changed outside of current session\n    on_reload = function() H.schedule_diff_update(buf_id, 0) end,\n\n    -- Called when buffer is unloaded from memory (`:h nvim_buf_detach_event`),\n    -- **including** `:edit` command\n    on_detach = function() MiniDiff.disable(buf_id) end,\n  })\n\n  -- Add buffer autocommands\n  H.setup_buf_autocommands(buf_id)\n\n  -- Try attaching source after all necessary watchers are set up. It is needed\n  -- to still have them set up if first source of many returned `false`.\n  local attach_output = H.get_active_source(H.cache[buf_id]).attach(buf_id)\n  if attach_output == false then MiniDiff.fail_attach(buf_id) end\nend\n\n--- Disable diff processing in buffer\n---\n---@param buf_id __diff_buf_id\nMiniDiff.disable = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return end\n  H.cache[buf_id] = nil\n\n  pcall(vim.api.nvim_del_augroup_by_id, buf_cache.augroup)\n  vim.b[buf_id].minidiff_summary, vim.b[buf_id].minidiff_summary_string = nil, nil\n  H.clear_all_diff(buf_id)\n  pcall(H.get_active_source(buf_cache).detach, buf_id)\nend\n\n--- Toggle diff processing in buffer\n---\n--- Enable if disabled, disable if enabled.\n---\n---@param buf_id __diff_buf_id\nMiniDiff.toggle = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n  if H.is_buf_enabled(buf_id) then return MiniDiff.disable(buf_id) end\n  return MiniDiff.enable(buf_id)\nend\n\n--- Toggle overlay view in buffer\n---\n---@param buf_id __diff_buf_id\nMiniDiff.toggle_overlay = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then H.error(string.format('Buffer %d is not enabled.', buf_id)) end\n\n  buf_cache.overlay = not buf_cache.overlay\n  H.clear_all_diff(buf_id)\n  H.schedule_diff_update(buf_id, 0)\nend\n\n--- Export hunks\n---\n--- Get and convert hunks from current/all buffers. Example of using it: >lua\n---\n---   -- Set quickfix list from all available hunks\n---   vim.fn.setqflist(MiniDiff.export('qf'))\n--- <\n---@param format string Output format. Currently only `'qf'` value is supported.\n---@param opts table|nil Options. Possible fields:\n---   - <scope> `(string)` - scope defining from which buffers to use hunks.\n---     One of \"all\" (all enabled buffers) or \"current\".\n---\n---@return table Result of export. Depends on the `format`:\n---   - If \"qf\", an array compatible with |setqflist()| and |setloclist()|.\nMiniDiff.export = function(format, opts)\n  opts = vim.tbl_deep_extend('force', { scope = 'all' }, opts or {})\n  if format == 'qf' then return H.export_qf(opts) end\n  H.error('`format` should be one of \"qf\".')\nend\n\n--- Get buffer data\n---\n---@param buf_id __diff_buf_id\n---\n---@return table|nil Table with buffer diff data or `nil` if buffer is not enabled.\n---   Table has the following fields:\n---   - <config> `(table)` - config used for this particular buffer.\n---   - <hunks> `(table)` - array of hunks. See |MiniDiff-hunk-specification|.\n---   - <overlay> `(boolean)` - whether an overlay view is shown.\n---   - <ref_text> `(string|nil)` - current value of reference text. Lines are\n---     separated with newline character (`'\\n'`). Can be `nil` indicating that\n---     reference text was not yet set (for example, if source did not yet react).\n---   - <summary> `(table)` - overall diff summary. See |MiniDiff-diff-summary|.\nMiniDiff.get_buf_data = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return nil end\n  return vim.deepcopy({\n    config = buf_cache.config,\n    hunks = buf_cache.hunks,\n    overlay = buf_cache.overlay,\n    ref_text = buf_cache.ref_text,\n    summary = buf_cache.summary,\n  })\nend\n\n--- Set reference text for the buffer\n---\n--- Note: this will call |MiniDiff.enable()| for target buffer if it is not\n--- already enabled.\n---\n---@param buf_id __diff_buf_id\n---@param text string|table New reference text. Either a string with `\\n` used to\n---   separate lines or array of lines. Use empty table to unset current\n---   reference text (results into no hunks shown). Default: `{}`.\n---   Note: newline character is appended at the end (if it is not there already)\n---   for better diffs.\nMiniDiff.set_ref_text = function(buf_id, text)\n  buf_id = H.validate_buf_id(buf_id)\n  if not (type(text) == 'table' or type(text) == 'string') then H.error('`text` should be either string or array.') end\n  if type(text) == 'table' then text = #text > 0 and table.concat(text, '\\n') or nil end\n\n  -- Enable if not already enabled\n  if not H.is_buf_enabled(buf_id) then MiniDiff.enable(buf_id) end\n  if not H.is_buf_enabled(buf_id) then H.error('Can not set reference text for not enabled buffer.') end\n\n  -- Appending '\\n' makes more intuitive diffs at end-of-file\n  if text ~= nil and string.sub(text, -1) ~= '\\n' then text = text .. '\\n' end\n  if text == nil then\n    H.clear_all_diff(buf_id)\n    vim.cmd('redraw')\n  end\n\n  -- Immediately update diff\n  H.cache[buf_id].ref_text = text\n  H.schedule_diff_update(buf_id, 0)\nend\n\n--- Generate builtin sources\n---\n--- This is a table with function elements. Call to actually get source.\n--- Examples: >lua\n---\n---   local diff = require('mini.diff')\n---\n---   -- Single `save` source\n---   diff.setup({ source = diff.gen_source.save() })\n---\n---   -- Multiple sources (attempted to attach in order)\n---   diff.setup({ source = { diff.gen_source.git(), diff.gen_source.save() } })\n--- <\nMiniDiff.gen_source = {}\n\n--- Git source\n---\n--- Default source. Uses file text from Git index as reference. This results in:\n--- - \"Add\" hunks represent text present in current buffer, but not in index.\n--- - \"Change\" hunks represent modified text already present in index.\n--- - \"Delete\" hunks represent text deleted from index.\n---\n--- Applying hunks means staging, a.k.a adding to index.\n--- Notes:\n--- - Requires Git version at least 2.38.0.\n--- - There is no capability for unstaging hunks. Use full Git client for that.\n---\n---@return table Source. See |MiniDiff-source-specification|.\nMiniDiff.gen_source.git = function()\n  local attach = function(buf_id)\n    -- Try attaching to a buffer only once\n    if H.git_cache[buf_id] ~= nil then return false end\n    -- - Possibly resolve symlinks to get data from the original repo\n    local path = H.get_buf_realpath(buf_id)\n    if path == '' then return false end\n\n    H.git_cache[buf_id] = {}\n    H.git_start_watching_index(buf_id, path)\n  end\n\n  local detach = function(buf_id)\n    local cache = H.git_cache[buf_id]\n    H.git_cache[buf_id] = nil\n    H.git_invalidate_cache(cache)\n  end\n\n  local apply_hunks = function(buf_id, hunks)\n    local path_data = H.git_get_path_data(H.get_buf_realpath(buf_id))\n    if path_data == nil or path_data.rel_path == nil then return end\n    local patch = H.git_format_patch(buf_id, hunks, path_data)\n    H.git_apply_patch(path_data, patch)\n  end\n\n  return { name = 'git', attach = attach, detach = detach, apply_hunks = apply_hunks }\nend\n\n--- \"Do nothing\" source\n---\n--- Allows buffers to be enabled while not setting any reference text.\n--- Use this if the goal is to rely on manual |MiniDiff.set_ref_text()| calls.\n---\n---@return table Source. See |MiniDiff-source-specification|.\nMiniDiff.gen_source.none = function()\n  return { name = 'none', attach = function() end }\nend\n\n--- Latest save source\n---\n--- Uses text at latest save as the reference. This results into diff showing\n--- difference after the latest save.\n---\n---@return table Source. See |MiniDiff-source-specification|.\nMiniDiff.gen_source.save = function()\n  local augroups = {}\n  local attach = function(buf_id)\n    local augroup = vim.api.nvim_create_augroup('MiniDiffSourceSaveBuffer' .. buf_id, { clear = true })\n    augroups[buf_id] = augroup\n\n    local set_ref = function()\n      if vim.bo[buf_id].modified then return end\n      MiniDiff.set_ref_text(buf_id, H.get_buftext(buf_id))\n    end\n\n    -- Autocommand are more efficient than file watcher as it doesn't read disk\n    local au_opts = { group = augroup, buffer = buf_id, callback = set_ref, desc = 'Set reference text after save' }\n    vim.api.nvim_create_autocmd({ 'BufWritePost', 'FileChangedShellPost' }, au_opts)\n    set_ref()\n  end\n\n  local detach = function(buf_id) pcall(vim.api.nvim_del_augroup_by_id, augroups[buf_id]) end\n\n  return { name = 'save', attach = attach, detach = detach }\nend\n\n--- Perform action on hunks in region\n---\n--- Compute hunks inside a target region (even for hunks only partially inside it)\n--- and perform apply/reset/yank operation on them.\n---\n--- The \"yank\" action yanks all reference lines of target hunks into\n--- a specified register (should be one of |registers|).\n---\n--- Notes:\n--- - Whether hunk is inside a region is computed based on position of its\n---   buffer lines.\n--- - If \"change\" or \"delete\" is only partially inside a target region, all\n---   reference lines are used in computed \"intersection\" hunk.\n---\n--- Used directly in `config.mappings.apply` and `config.mappings.reset`.\n--- Usually there is no need to use this function manually.\n--- See |MiniDiff.operator()| for how to set up a mapping for \"yank\".\n---\n---@param buf_id __diff_buf_id\n---@param action string One of \"apply\", \"reset\", \"yank\".\n---@param opts table|nil Options. Possible fields:\n---   - <line_start> `(number)` - start line of the region. Default: 1.\n---   - <line_end> `(number)` - start line of the region. Default: last buffer line.\n---   - <register> `(string)` - register to yank reference lines into.\n---     Default: |v:register|.\nMiniDiff.do_hunks = function(buf_id, action, opts)\n  buf_id = H.validate_buf_id(buf_id)\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then H.error(string.format('Buffer %d is not enabled.', buf_id)) end\n  if type(buf_cache.ref_text) ~= 'string' then H.error(string.format('Buffer %d has no reference text.', buf_id)) end\n\n  if not (action == 'apply' or action == 'reset' or action == 'yank') then\n    H.error('`action` should be one of \"apply\", \"reset\", \"yank\".')\n  end\n\n  local default_opts = { line_start = 1, line_end = vim.api.nvim_buf_line_count(buf_id), register = vim.v.register }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n  local line_start, line_end = H.validate_target_lines(buf_id, opts.line_start, opts.line_end)\n  if type(opts.register) ~= 'string' then H.error('`opts.register` should be string.') end\n\n  local hunks = H.get_hunks_in_range(buf_cache.hunks, line_start, line_end)\n  if #hunks == 0 then return H.notify('No hunks to ' .. action, 'INFO') end\n  if action == 'apply' then H.get_active_source(buf_cache).apply_hunks(buf_id, hunks) end\n  if action == 'reset' then H.reset_hunks(buf_id, hunks) end\n  if action == 'yank' then H.yank_hunks_ref(buf_cache.ref_text, hunks, opts.register) end\nend\n\n--- Go to hunk range in current buffer\n---\n---@param direction string One of \"first\", \"prev\", \"next\", \"last\".\n---@param opts table|nil Options. A table with fields:\n---   - <n_times> `(number)` - Number of times to advance. Default: |v:count1|.\n---   - <line_start> `(number)` - Line number to start from for directions\n---     \"prev\" and \"next\". Default: cursor line.\n---   - <wrap> `(boolean)` - Whether to wrap around edges.\n---     Default: `options.wrap` value of the config.\nMiniDiff.goto_hunk = function(direction, opts)\n  local buf_id = vim.api.nvim_get_current_buf()\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then H.error(string.format('Buffer %d is not enabled.', buf_id)) end\n\n  if not vim.tbl_contains({ 'first', 'prev', 'next', 'last' }, direction) then\n    H.error('`direction` should be one of \"first\", \"prev\", \"next\", \"last\".')\n  end\n\n  local default_wrap = buf_cache.config.options.wrap_goto\n  local default_opts = { n_times = vim.v.count1, line_start = vim.fn.line('.'), wrap = default_wrap }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n  if not (type(opts.n_times) == 'number' and opts.n_times >= 1) then\n    H.error('`opts.n_times` should be positive number.')\n  end\n  if type(opts.line_start) ~= 'number' then H.error('`opts.line_start` should be number.') end\n  if type(opts.wrap) ~= 'boolean' then H.error('`opts.wrap` should be boolean.') end\n\n  -- Prepare ranges to iterate.\n  local ranges = H.get_contiguous_hunk_ranges(buf_cache.hunks)\n  if #ranges == 0 then return H.notify('No hunks to go to', 'INFO') end\n\n  -- Iterate\n  local res_ind, did_wrap = H.iterate_hunk_ranges(ranges, direction, opts)\n  if res_ind == nil then return H.notify('No hunk ranges in direction ' .. vim.inspect(direction), 'INFO') end\n  local res_line = ranges[res_ind].from\n  if did_wrap then H.notify('Wrapped around edge in direction ' .. vim.inspect(direction), 'INFO') end\n\n  -- Add to jumplist\n  vim.cmd([[normal! m']])\n\n  -- Jump\n  local _, col = vim.fn.getline(res_line):find('^%s*')\n  vim.api.nvim_win_set_cursor(0, { res_line, col })\n\n  -- Open just enough folds\n  vim.cmd('normal! zv')\nend\n\n--- Perform action over region\n---\n--- Perform action over region defined by marks. Used in mappings.\n---\n--- Example of a mapping to yank reference lines of hunk range under cursor\n--- (assuming default 'config.mappings.textobject'): >lua\n---\n---   local rhs = function() return MiniDiff.operator('yank') .. 'gh' end\n---   vim.keymap.set('n', 'ghy', rhs, { expr = true, remap = true })\n--- <\n---@param mode string One of \"apply\", \"reset\", \"yank\", or the ones used in |g@|.\nMiniDiff.operator = function(mode)\n  local buf_id = vim.api.nvim_get_current_buf()\n  if H.is_disabled(buf_id) then return '' end\n\n  if mode == 'apply' or mode == 'reset' or mode == 'yank' then\n    H.operator_cache = { action = mode, win_view = vim.fn.winsaveview(), register = vim.v.register }\n    vim.o.operatorfunc = 'v:lua.MiniDiff.operator'\n    return 'g@'\n  end\n  local cache = H.operator_cache\n\n  -- NOTE: Using `[` / `]` marks also works in Visual mode as because it is\n  -- executed as part of `g@`, which treats visual selection as a result of\n  -- Operator-pending mode mechanics (for which visual selection is allowed to\n  -- define motion/textobject). The downside is that it sets 'operatorfunc',\n  -- but the upside is that it is \"dot-repeatable\" (for relative selection).\n  local opts = { line_start = vim.fn.line(\"'[\"), line_end = vim.fn.line(\"']\"), register = cache.register }\n  if opts.line_end < opts.line_start then return H.notify('Not a proper textobject', 'INFO') end\n  MiniDiff.do_hunks(buf_id, cache.action, opts)\n\n  -- Restore window view for \"apply\" (as buffer text should not have changed)\n  if cache.action == 'apply' and cache.win_view ~= nil then\n    vim.fn.winrestview(cache.win_view)\n    -- NOTE: Restore only once because during dot-repeat it is not up to date\n    cache.win_view = nil\n  end\n  return ''\nend\n\n--- Select hunk range textobject\n---\n--- Selects all contiguous lines adjacent to cursor line which are in any (not\n--- necessarily same) hunk (if cursor line itself is in hunk).\n--- Used in default mappings.\nMiniDiff.textobject = function()\n  local buf_id = vim.api.nvim_get_current_buf()\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil or H.is_disabled(buf_id) then H.error('Current buffer is not enabled.') end\n\n  -- Get hunk range under cursor\n  local cur_line = vim.fn.line('.')\n  local regions, cur_region = H.get_contiguous_hunk_ranges(buf_cache.hunks), nil\n  for _, r in ipairs(regions) do\n    if r.from <= cur_line and cur_line <= r.to then cur_region = r end\n  end\n  if cur_region == nil then return H.notify('No hunk range under cursor', 'INFO') end\n\n  -- Select target region\n  local is_visual = vim.tbl_contains({ 'v', 'V', '\\22' }, vim.fn.mode())\n  if is_visual then vim.cmd('normal! \\27') end\n  vim.cmd(string.format('normal! %dGV%dG', cur_region.from, cur_region.to))\nend\n\n--- Indicate source attach fail\n---\n--- Try to attach next source; if there is none - call |MiniDiff.disable()|.\n---\n---@param buf_id integer Buffer identifier for which attach has failed.\nMiniDiff.fail_attach = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n\n  -- Do nothing if there was no attempt to enable\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return end\n\n  -- If no next source, disable buffer without calling any of `detach`\n  if buf_cache.source_id >= #buf_cache.source then\n    H.cache[buf_id].source_id = math.huge\n    return MiniDiff.disable(buf_id)\n  end\n\n  -- Try attaching next source\n  buf_cache.source_id = buf_cache.source_id + 1\n  local attach_output = H.get_active_source(H.cache[buf_id]).attach(buf_id)\n  if attach_output == false then MiniDiff.fail_attach(buf_id) end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniDiff.config\n\nH.default_source = { MiniDiff.gen_source.git() }\n\n-- Timers\nH.timer_diff_update = vim.loop.new_timer()\n\n-- Namespaces per highlighter name\nH.ns_id = {\n  viz = vim.api.nvim_create_namespace('MiniDiffViz'),\n  overlay = vim.api.nvim_create_namespace('MiniDiffOverlay'),\n}\n\n-- Cache of buffers waiting for debounced diff update\nH.bufs_to_update = {}\n\n-- Cache per enabled buffer\nH.cache = {}\n\n-- Cache per buffer for attached `git` source\nH.git_cache = {}\n\n-- Cache for operator\nH.operator_cache = {}\n\n-- Common extmark data for supported styles\n--stylua: ignore\nH.style_extmark_data = {\n  sign    = { hl_group_prefix = 'MiniDiffSign', field = 'sign_hl_group' },\n  number  = { hl_group_prefix = 'MiniDiffSign', field = 'number_hl_group' },\n}\n\n-- Suffix for overlay virtual lines to be highlighted as full line\nH.overlay_suffix = string.rep(' ', vim.o.columns)\n\n-- Flag for whether to invalidate extmarks\nH.extmark_invalidate = vim.fn.has('nvim-0.10') == 1 and true or nil\n\n-- Flag for whether to handle virtual lines overflow\nH.extmark_virt_lines_overflow = vim.fn.has('nvim-0.11') == 1 and 'scroll' or nil\n\n-- Permanent `vim.diff()` options\nH.vimdiff_opts = { result_type = 'indices', ctxlen = 0, interhunkctxlen = 0 }\n\n-- Options for `vim.diff()` during word diff. Use `interhunkctxlen = 4` to\n-- reduce noisiness (chosen as slightly less than average English word length)\n--stylua: ignore\nH.worddiff_opts = {\n  algorithm = 'minimal',    result_type = 'indices',\n  ctxlen = 0,               interhunkctxlen = 4,\n  indent_heuristic = false, linematch = 0\n}\n\n-- BOM bytes prepended to buffer text if 'bomb' is enabled. See `:h bom-bytes`.\n--stylua: ignore\nH.bom_bytes = {\n  ['utf-8']    = string.char(0xef, 0xbb, 0xbf),\n  ['utf-16be'] = string.char(0xfe, 0xff),\n  ['utf-16']   = string.char(0xfe, 0xff),\n  ['utf-16le'] = string.char(0xff, 0xfe),\n  -- In 'fileencoding', 'utf-32' is transformed into 'ucs-4'\n  ['utf-32be'] = string.char(0x00, 0x00, 0xfe, 0xff),\n  ['ucs-4be']  = string.char(0x00, 0x00, 0xfe, 0xff),\n  ['utf-32']   = string.char(0x00, 0x00, 0xfe, 0xff),\n  ['ucs-4']    = string.char(0x00, 0x00, 0xfe, 0xff),\n  ['utf-32le'] = string.char(0xff, 0xfe, 0x00, 0x00),\n  ['ucs-4le']  = string.char(0xff, 0xfe, 0x00, 0x00),\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('view', config.view, 'table')\n  H.check_type('view.style', config.view.style, 'string')\n  H.check_type('view.signs', config.view.signs, 'table')\n  H.check_type('view.signs.add', config.view.signs.add, 'string')\n  H.check_type('view.signs.change', config.view.signs.change, 'string')\n  H.check_type('view.signs.delete', config.view.signs.delete, 'string')\n  H.check_type('view.priority', config.view.priority, 'number')\n\n  H.check_type('source', config.source, 'table', true)\n\n  H.check_type('delay', config.delay, 'table')\n  H.check_type('delay.text_change', config.delay.text_change, 'number')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.apply', config.mappings.apply, 'string')\n  H.check_type('mappings.reset', config.mappings.reset, 'string')\n  H.check_type('mappings.textobject', config.mappings.textobject, 'string')\n  H.check_type('mappings.goto_first', config.mappings.goto_first, 'string')\n  H.check_type('mappings.goto_prev', config.mappings.goto_prev, 'string')\n  H.check_type('mappings.goto_next', config.mappings.goto_next, 'string')\n  H.check_type('mappings.goto_last', config.mappings.goto_last, 'string')\n\n  H.check_type('options', config.options, 'table')\n  H.check_type('options.algorithm', config.options.algorithm, 'string')\n  H.check_type('options.indent_heuristic', config.options.indent_heuristic, 'boolean')\n  H.check_type('options.linematch', config.options.linematch, 'number')\n  H.check_type('options.wrap_goto', config.options.wrap_goto, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniDiff.config = config\n\n  -- Make mappings\n  local mappings = config.mappings\n\n  local rhs_apply = function() return MiniDiff.operator('apply') end\n  H.map({ 'n', 'x' }, mappings.apply, rhs_apply, { expr = true, desc = 'Apply hunks' })\n  local rhs_reset = function() return MiniDiff.operator('reset') end\n  H.map({ 'n', 'x' }, mappings.reset, rhs_reset, { expr = true, desc = 'Reset hunks' })\n\n  local is_tobj_conflict = mappings.textobject == mappings.apply or mappings.textobject == mappings.reset\n  local modes = is_tobj_conflict and { 'o' } or { 'x', 'o' }\n  H.map(modes, mappings.textobject, '<Cmd>lua MiniDiff.textobject()<CR>', { desc = 'Hunk range textobject' })\n\n  --stylua: ignore start\n  H.map({ 'n', 'x' }, mappings.goto_first,  \"<Cmd>lua MiniDiff.goto_hunk('first')<CR>\", { desc = 'First hunk' })\n  H.map('o',          mappings.goto_first, \"V<Cmd>lua MiniDiff.goto_hunk('first')<CR>\", { desc = 'First hunk' })\n  H.map({ 'n', 'x' }, mappings.goto_prev,   \"<Cmd>lua MiniDiff.goto_hunk('prev')<CR>\",  { desc = 'Previous hunk' })\n  H.map('o',          mappings.goto_prev,  \"V<Cmd>lua MiniDiff.goto_hunk('prev')<CR>\",  { desc = 'Previous hunk' })\n  H.map({ 'n', 'x' }, mappings.goto_next,   \"<Cmd>lua MiniDiff.goto_hunk('next')<CR>\",  { desc = 'Next hunk' })\n  H.map('o',          mappings.goto_next,  \"V<Cmd>lua MiniDiff.goto_hunk('next')<CR>\",  { desc = 'Next hunk' })\n  H.map({ 'n', 'x' }, mappings.goto_last,   \"<Cmd>lua MiniDiff.goto_hunk('last')<CR>\",  { desc = 'Last hunk' })\n  H.map('o',          mappings.goto_last,  \"V<Cmd>lua MiniDiff.goto_hunk('last')<CR>\",  { desc = 'Last hunk' })\n  --stylua: ignore end\n\n  -- Register decoration provider which actually makes visualization\n  local ns_id_viz, ns_id_overlay = H.ns_id.viz, H.ns_id.overlay\n  H.set_decoration_provider(ns_id_viz, ns_id_overlay)\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniDiff', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  -- NOTE: Try auto enabling buffer on every `BufEnter` to not have `:edit`\n  -- disabling buffer, as it calls `on_detach()` from buffer watcher\n  au('BufEnter', '*', H.auto_enable, 'Enable diff')\n  au('VimResized', '*', H.on_resize, 'Track Neovim resizing')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  local has_core_diff_hl = vim.fn.has('nvim-0.10') == 1\n  hi('MiniDiffSignAdd',        { link = has_core_diff_hl and 'Added' or 'diffAdded' })\n  hi('MiniDiffSignChange',     { link = has_core_diff_hl and 'Changed' or 'diffChanged' })\n  hi('MiniDiffSignDelete',     { link = has_core_diff_hl and 'Removed' or 'diffRemoved'  })\n  hi('MiniDiffOverAdd',        { link = 'DiffAdd' })\n  hi('MiniDiffOverChange',     { link = 'DiffText' })\n  hi('MiniDiffOverChangeBuf',  { link = 'MiniDiffOverChange'})\n  hi('MiniDiffOverContext',    { link = 'DiffChange' })\n  hi('MiniDiffOverContextBuf', {})\n  hi('MiniDiffOverDelete',     { link = 'DiffDelete'  })\nend\n\nH.is_disabled = function(buf_id)\n  local buf_disable = H.get_buf_var(buf_id, 'minidiff_disable')\n  return vim.g.minidiff_disable == true or buf_disable == true\nend\n\nH.get_config = function(config, buf_id)\n  local buf_config = H.get_buf_var(buf_id, 'minidiff_config') or {}\n  return vim.tbl_deep_extend('force', MiniDiff.config, buf_config, config or {})\nend\n\nH.get_buf_var = function(buf_id, name)\n  if not vim.api.nvim_buf_is_valid(buf_id) then return nil end\n  return vim.b[buf_id or 0][name]\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_enable = vim.schedule_wrap(function(data)\n  if H.is_buf_enabled(data.buf) or H.is_disabled(data.buf) then return end\n  local buf = data.buf\n  if not (vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == '' and vim.bo[buf].buflisted) then return end\n  if not H.is_buf_text(buf) then return end\n  MiniDiff.enable(buf)\nend)\n\nH.on_resize = function()\n  H.overlay_suffix = string.rep(' ', vim.o.columns)\n  for buf_id, _ in pairs(H.cache) do\n    if vim.api.nvim_buf_is_valid(buf_id) then\n      H.clear_all_diff(buf_id)\n      H.schedule_diff_update(buf_id, 0)\n    end\n  end\nend\n\n-- Validators -----------------------------------------------------------------\nH.validate_buf_id = function(x)\n  if x == nil or x == 0 then return vim.api.nvim_get_current_buf() end\n  if not (type(x) == 'number' and vim.api.nvim_buf_is_valid(x)) then\n    H.error('`buf_id` should be `nil` or valid buffer id.')\n  end\n  return x\nend\n\nH.validate_target_lines = function(buf_id, line_start, line_end)\n  local n_lines = vim.api.nvim_buf_line_count(buf_id)\n\n  if type(line_start) ~= 'number' then H.error('`line_start` should be number.') end\n  if type(line_end) ~= 'number' then H.error('`line_end` should be number.') end\n\n  -- Allow negative lines to count from last line\n  line_start = line_start < 0 and (n_lines + line_start + 1) or line_start\n  line_end = line_end < 0 and (n_lines + line_end + 1) or line_end\n\n  -- Clamp to fit the allowed range\n  line_start = math.min(math.max(line_start, 1), n_lines)\n  line_end = math.min(math.max(line_end, 1), n_lines)\n  if not (line_start <= line_end) then H.error('`line_start` should be less than or equal to `line_end`.') end\n\n  return line_start, line_end\nend\n\nH.validate_callable = function(x, name)\n  if vim.is_callable(x) then return x end\n  H.error('`' .. name .. '` should be callable.')\nend\n\n-- Enabling -------------------------------------------------------------------\nH.is_buf_enabled = function(buf_id) return H.cache[buf_id] ~= nil end\n\nH.update_buf_cache = function(buf_id)\n  local new_cache = H.cache[buf_id] or {}\n\n  local buf_config = H.get_config({}, buf_id)\n  new_cache.config = buf_config\n  new_cache.extmark_opts = H.convert_view_to_extmark_opts(buf_config.view)\n  new_cache.source = H.normalize_source(buf_config.source or H.default_source)\n  new_cache.source_id = new_cache.source_id or 1\n\n  new_cache.hunks = new_cache.hunks or {}\n  new_cache.summary = new_cache.summary or {}\n  new_cache.viz_lines = new_cache.viz_lines or {}\n\n  new_cache.overlay = false\n  new_cache.overlay_lines = new_cache.overlay_lines or {}\n\n  H.cache[buf_id] = new_cache\nend\n\nH.setup_buf_autocommands = function(buf_id)\n  local augroup = vim.api.nvim_create_augroup('MiniDiffBuffer' .. buf_id, { clear = true })\n  H.cache[buf_id].augroup = augroup\n\n  local buf_update = vim.schedule_wrap(function() H.update_buf_cache(buf_id) end)\n  local bufwinenter_opts = { group = augroup, buffer = buf_id, callback = buf_update, desc = 'Update buffer cache' }\n  vim.api.nvim_create_autocmd('BufWinEnter', bufwinenter_opts)\n\n  local reset_if_enabled = vim.schedule_wrap(function(data)\n    if not H.is_buf_enabled(data.buf) then return end\n    MiniDiff.disable(data.buf)\n    MiniDiff.enable(data.buf)\n  end)\n  local bufrename_opts = { group = augroup, buffer = buf_id, callback = reset_if_enabled, desc = 'Reset on rename' }\n  -- NOTE: `BufFilePost` does not look like a proper event, but it (yet) works\n  vim.api.nvim_create_autocmd('BufFilePost', bufrename_opts)\n\n  local buf_disable = function() MiniDiff.disable(buf_id) end\n  local bufdelete_opts = { group = augroup, buffer = buf_id, callback = buf_disable, desc = 'Disable on delete' }\n  vim.api.nvim_create_autocmd('BufDelete', bufdelete_opts)\nend\n\nH.normalize_source = function(source)\n  -- Normalize to an array of sources\n  if type(source) ~= 'table' then H.error('`source` should be table.') end\n  if source[1] == nil then source = { source } end\n\n  local res = {}\n  for i, s in ipairs(source) do\n    local cur_s = { attach = s.attach }\n    cur_s.name = s.name or 'unknown'\n    cur_s.detach = s.detach or function(_) end\n    cur_s.apply_hunks = s.apply_hunks or function(_) H.error('Current source does not support applying hunks.') end\n\n    if type(cur_s.name) ~= 'string' then H.error('`source.name` should be string.') end\n    H.validate_callable(cur_s.attach, 'source.attach')\n    H.validate_callable(cur_s.detach, 'source.detach')\n    H.validate_callable(cur_s.apply_hunks, 'source.apply_hunks')\n\n    res[i] = cur_s\n  end\n\n  return res\nend\n\nH.get_active_source = function(buf_cache) return buf_cache.source[buf_cache.source_id] or {} end\n\nH.convert_view_to_extmark_opts = function(view)\n  local extmark_data = H.style_extmark_data[view.style]\n  if extmark_data == nil then H.error('Style ' .. vim.inspect(view.style) .. ' is not supported.') end\n\n  local signs = view.style == 'sign' and view.signs or {}\n  local field, hl_group_prefix = extmark_data.field, extmark_data.hl_group_prefix\n  --stylua: ignore\n  return {\n    add =    { [field] = hl_group_prefix .. 'Add',    sign_text = signs.add,    priority = view.priority, invalidate = H.extmark_invalidate },\n    change = { [field] = hl_group_prefix .. 'Change', sign_text = signs.change, priority = view.priority, invalidate = H.extmark_invalidate },\n    delete = { [field] = hl_group_prefix .. 'Delete', sign_text = signs.delete, priority = view.priority, invalidate = H.extmark_invalidate },\n  }\nend\n\n-- Processing -----------------------------------------------------------------\nH.set_decoration_provider = function(ns_id_viz, ns_id_overlay)\n  local on_win = function(_, _, buf_id, top, bottom)\n    local buf_cache = H.cache[buf_id]\n    if buf_cache == nil then return false end\n\n    local viz_lines, overlay_lines = buf_cache.viz_lines, buf_cache.overlay_lines\n    if buf_cache.needs_clear then\n      H.clear_all_diff(buf_id)\n      buf_cache.needs_clear, buf_cache.dummy_extmark = false, nil\n      -- Ensure that sign column is visible even if hunks are outside of window\n      -- view (matters with `signcolumn=auto`)\n      if buf_cache.config.view.style == 'sign' and not vim.tbl_isempty(viz_lines) then\n        local dummy_opts = { sign_text = '  ', priority = 0, right_gravity = false }\n        dummy_opts.sign_hl_group, dummy_opts.cursorline_hl_group = 'SignColumn', 'CursorLineSign'\n        buf_cache.dummy_extmark = vim.api.nvim_buf_set_extmark(buf_id, ns_id_viz, 0, 0, dummy_opts)\n      end\n    end\n\n    local has_viz_extmarks = false\n    for i = top + 1, bottom + 1 do\n      if viz_lines[i] ~= nil then\n        H.set_extmark(buf_id, ns_id_viz, i - 1, 0, viz_lines[i])\n        viz_lines[i] = nil\n        has_viz_extmarks = true\n      end\n      if overlay_lines[i] ~= nil then\n        -- Allow several overlays at one line (like for \"delete\" and \"change\")\n        for j = 1, #overlay_lines[i] do\n          H.draw_overlay_line(buf_id, ns_id_overlay, i - 1, overlay_lines[i][j])\n        end\n        overlay_lines[i] = nil\n      end\n    end\n\n    -- Make sure to clear dummy extmark when it is not needed (otherwise it\n    -- affects signcolumn for cases like `yes:2` and `auto:2`)\n    if buf_cache.dummy_extmark ~= nil and has_viz_extmarks then\n      vim.api.nvim_buf_del_extmark(buf_id, ns_id_viz, buf_cache.dummy_extmark)\n      buf_cache.dummy_extmark = nil\n    end\n  end\n  vim.api.nvim_set_decoration_provider(ns_id_viz, { on_win = on_win })\nend\n\nH.schedule_diff_update = vim.schedule_wrap(function(buf_id, delay_ms)\n  H.bufs_to_update[buf_id] = true\n  H.timer_diff_update:stop()\n  H.timer_diff_update:start(delay_ms, 0, H.process_scheduled_buffers)\nend)\n\nH.process_scheduled_buffers = vim.schedule_wrap(function()\n  for buf_id, _ in pairs(H.bufs_to_update) do\n    H.update_buf_diff(buf_id)\n  end\n  H.bufs_to_update = {}\nend)\n\nH.update_buf_diff = vim.schedule_wrap(function(buf_id)\n  -- Make early returns\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return end\n  if not vim.api.nvim_buf_is_valid(buf_id) then\n    H.cache[buf_id] = nil\n    return\n  end\n  if type(buf_cache.ref_text) ~= 'string' or H.is_disabled(buf_id) then\n    local summary = { source_name = H.get_active_source(buf_cache).name }\n    buf_cache.hunks, buf_cache.viz_lines, buf_cache.overlay_lines, buf_cache.summary = {}, {}, {}, summary\n    vim.b[buf_id].minidiff_summary, vim.b[buf_id].minidiff_summary_string = summary, ''\n    return\n  end\n\n  -- Compute diff\n  local options = buf_cache.config.options\n  H.vimdiff_opts.algorithm = options.algorithm\n  H.vimdiff_opts.indent_heuristic = options.indent_heuristic\n  H.vimdiff_opts.linematch = options.linematch\n\n  local buf_text, buf_lines = H.get_buftext(buf_id)\n  local diff = vim.diff(buf_cache.ref_text, buf_text, H.vimdiff_opts)\n\n  -- Recompute hunks with summary and draw information\n  H.update_hunk_data(diff, buf_cache, buf_lines)\n\n  -- Set buffer-local variables with summary for easier external usage\n  local summary = buf_cache.summary\n  vim.b[buf_id].minidiff_summary = summary\n\n  local summary_string = {}\n  if summary.n_ranges > 0 then table.insert(summary_string, '#' .. summary.n_ranges) end\n  if summary.add > 0 then table.insert(summary_string, '+' .. summary.add) end\n  if summary.change > 0 then table.insert(summary_string, '~' .. summary.change) end\n  if summary.delete > 0 then table.insert(summary_string, '-' .. summary.delete) end\n  vim.b[buf_id].minidiff_summary_string = table.concat(summary_string, ' ')\n\n  -- Request highlighting clear to be done in decoration provider\n  buf_cache.needs_clear = true\n\n  -- Trigger event for users to possibly hook into. Ensure target buffer is\n  -- current (for proper `buf` in event data)\n  vim.api.nvim_buf_call(buf_id, function() vim.api.nvim_exec_autocmds('User', { pattern = 'MiniDiffUpdated' }) end)\n\n  -- Force redraw. NOTE: Using 'redraw' not always works (`<Cmd>update<CR>`\n  -- from keymap with \"save\" source will not redraw) while 'redraw!' flickers.\n  H.redraw_buffer(buf_id)\nend)\n\nH.update_hunk_data = function(diff, buf_cache, buf_lines)\n  local do_overlay = buf_cache.overlay\n  local ref_lines = do_overlay and vim.split(buf_cache.ref_text, '\\n') or nil\n\n  local extmark_opts, priority = buf_cache.extmark_opts, buf_cache.config.view.priority\n  local hunks, viz_lines, overlay_lines = {}, {}, {}\n  local n_add, n_change, n_delete = 0, 0, 0\n  local n_ranges, last_range_to = 0, -math.huge\n  for i, d in ipairs(diff) do\n    -- Hunk\n    local n_ref, n_buf = d[2], d[4]\n    local hunk_type = n_ref == 0 and 'add' or (n_buf == 0 and 'delete' or 'change')\n    local hunk = { type = hunk_type, ref_start = d[1], ref_count = n_ref, buf_start = d[3], buf_count = n_buf }\n    hunks[i] = hunk\n\n    -- Hunk summary\n    local hunk_n_change = math.min(n_ref, n_buf)\n    n_add = n_add + n_buf - hunk_n_change\n    n_change = n_change + hunk_n_change\n    n_delete = n_delete + n_ref - hunk_n_change\n\n    -- Number of contiguous ranges.\n    -- NOTE: this relies on `vim.diff()` output being sorted by `buf_start`.\n    local range_from = math.max(d[3], 1)\n    local range_to = range_from + math.max(n_buf, 1) - 1\n    n_ranges = n_ranges + ((range_from <= last_range_to + 1) and 0 or 1)\n    last_range_to = math.max(last_range_to, range_to)\n\n    -- Register lines for draw. At least one line should visualize hunk.\n    local viz_ext_opts = extmark_opts[hunk_type]\n    for l_num = range_from, range_to do\n      -- Prefer showing \"change\" hunk over other types\n      if viz_lines[l_num] == nil or hunk_type == 'change' then viz_lines[l_num] = viz_ext_opts end\n    end\n\n    if do_overlay then\n      if hunk_type == 'add' then H.append_overlay_add(overlay_lines, hunk, priority) end\n      if hunk_type == 'change' then H.append_overlay_change(overlay_lines, hunk, ref_lines, buf_lines, priority) end\n      if hunk_type == 'delete' then H.append_overlay_delete(overlay_lines, hunk, ref_lines, priority) end\n    end\n  end\n\n  buf_cache.hunks, buf_cache.viz_lines, buf_cache.overlay_lines = hunks, viz_lines, overlay_lines\n  buf_cache.summary = { add = n_add, change = n_change, delete = n_delete, n_ranges = n_ranges }\n  buf_cache.summary.source_name = H.get_active_source(buf_cache).name\nend\n\nH.clear_all_diff = function(buf_id)\n  H.clear_namespace(buf_id, H.ns_id.viz, 0, -1)\n  H.clear_namespace(buf_id, H.ns_id.overlay, 0, -1)\nend\n\n-- Overlay --------------------------------------------------------------------\nH.append_overlay = function(overlay_lines, l_num, data)\n  local t = overlay_lines[l_num] or {}\n  table.insert(t, data)\n  overlay_lines[l_num] = t\nend\n\nH.append_overlay_add = function(overlay_lines, hunk, priority)\n  local data = { type = 'add', to = hunk.buf_start + hunk.buf_count - 1, priority = priority }\n  H.append_overlay(overlay_lines, hunk.buf_start, data)\nend\n\nH.append_overlay_change = function(overlay_lines, hunk, ref_lines, buf_lines, priority)\n  -- For one-to-one change, show lines separately with word diff highlighted\n  -- This is usually the case when `linematch` is on\n  if hunk.buf_count == hunk.ref_count then\n    for i = 0, hunk.ref_count - 1 do\n      local ref_n, buf_n = hunk.ref_start + i, hunk.buf_start + i\n      -- Defer actually computing word diff until in decoration provider as it\n      -- will compute only for displayed lines\n      local data =\n        { type = 'change_worddiff', ref_line = ref_lines[ref_n], buf_line = buf_lines[buf_n], priority = priority }\n      H.append_overlay(overlay_lines, buf_n, data)\n    end\n    return\n  end\n\n  -- If not one-to-one change, show reference lines above first real one\n  local changed_lines = {}\n  for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do\n    local l = { { ref_lines[i] .. H.overlay_suffix, 'MiniDiffOverChange' } }\n    table.insert(changed_lines, l)\n  end\n  local to = hunk.buf_start + hunk.buf_count - 1\n  local data = { type = 'change', to = to, lines = changed_lines, show_above = true, priority = priority }\n  H.append_overlay(overlay_lines, hunk.buf_start, data)\nend\n\nH.append_overlay_delete = function(overlay_lines, hunk, ref_lines, priority)\n  local deleted_lines = {}\n  for i = hunk.ref_start, hunk.ref_start + hunk.ref_count - 1 do\n    table.insert(deleted_lines, { { ref_lines[i], 'MiniDiffOverDelete' }, { H.overlay_suffix, 'MiniDiffOverDelete' } })\n  end\n  local l_num, show_above = math.max(hunk.buf_start, 1), hunk.buf_start == 0\n  local data = { type = 'delete', lines = deleted_lines, show_above = show_above, priority = priority }\n  H.append_overlay(overlay_lines, l_num, data)\nend\n\nH.draw_overlay_line = function(buf_id, ns_id, row, data)\n  -- \"Change worddif\" hunk: compute word diff and show it above and over text\n  if data.type == 'change_worddiff' then return H.draw_overlay_line_worddiff(buf_id, ns_id, row, data) end\n\n  local opts = { priority = data.priority }\n\n  -- \"Add\"/\"Change\" hunks highlight whole lines in affected buffer range\n  if data.type ~= 'delete' then\n    opts.end_row, opts.end_col, opts.hl_eol = data.to, 0, true\n    opts.hl_group = data.type == 'add' and 'MiniDiffOverAdd' or 'MiniDiffOverContextBuf'\n  end\n\n  -- \"Change\"/\"Delete\" hunks show affected reference range as virtual lines\n  opts.virt_lines, opts.virt_lines_above, opts.virt_lines_overflow =\n    data.lines, data.show_above, H.extmark_virt_lines_overflow\n  H.set_extmark(buf_id, ns_id, row, 0, opts)\nend\n\nH.draw_overlay_line_worddiff = function(buf_id, ns_id, row, data)\n  local ref_line, buf_line, priority = data.ref_line, data.buf_line, data.priority\n  local ref_parts, buf_parts = H.compute_worddiff_changed_parts(ref_line, buf_line)\n\n  -- Show changes in reference as two-colored virtual line above\n  local virt_line, index = {}, 1\n  for i = 1, #ref_parts do\n    local part = ref_parts[i]\n    if index < part[1] then table.insert(virt_line, { ref_line:sub(index, part[1] - 1), 'MiniDiffOverContext' }) end\n    table.insert(virt_line, { ref_line:sub(part[1], part[2]), 'MiniDiffOverChange' })\n    index = part[2] + 1\n  end\n  if index <= ref_line:len() then table.insert(virt_line, { ref_line:sub(index), 'MiniDiffOverContext' }) end\n  table.insert(virt_line, { H.overlay_suffix, 'MiniDiffOverContext' })\n\n  --stylua: ignore\n  local ref_opts = {\n    virt_lines = { virt_line }, virt_lines_above = true, virt_lines_overflow = H.extmark_virt_lines_overflow,\n    priority = priority,\n  }\n  H.set_extmark(buf_id, ns_id, row, 0, ref_opts)\n\n  -- Show changes in buffer line as one whole-line highlighting with separate\n  -- highlighting for changed regions on top (as priority of context is lower)\n  local off = vim.bo[buf_id].bomb and (H.bom_bytes[vim.bo[buf_id].fileencoding] or ''):len() or 0\n  for i = 1, #buf_parts do\n    local part = buf_parts[i]\n    local buf_opts = { end_row = row, end_col = part[2] - off, hl_group = 'MiniDiffOverChangeBuf', priority = priority }\n    H.set_extmark(buf_id, ns_id, row, part[1] - 1 - off, buf_opts)\n  end\n  local context_opts =\n    { end_row = row + 1, end_col = 0, hl_group = 'MiniDiffOverContextBuf', hl_eol = true, priority = priority - 1 }\n  H.set_extmark(buf_id, ns_id, row, 0, context_opts)\nend\n\nH.compute_worddiff_changed_parts = function(ref_line, buf_line)\n  local ref_sliced, ref_byte_starts, ref_byte_ends = H.slice_line(ref_line)\n  local buf_sliced, buf_byte_starts, buf_byte_ends = H.slice_line(buf_line)\n  local diff = vim.diff(ref_sliced, buf_sliced, H.worddiff_opts)\n  local ref_ranges, buf_ranges = {}, {}\n  for i = 1, #diff do\n    local d = diff[i]\n    if d[2] > 0 then table.insert(ref_ranges, { ref_byte_starts[d[1]], ref_byte_ends[d[1] + d[2] - 1] }) end\n    if d[4] > 0 then table.insert(buf_ranges, { buf_byte_starts[d[3]], buf_byte_ends[d[3] + d[4] - 1] }) end\n  end\n\n  return ref_ranges, buf_ranges\nend\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.slice_line = function(line)\n  -- Intertwine every proper character with '\\n'\n  local line_len = line:len()\n  local sliced, starts, ends\n  -- Make short route for a very common case of no multibyte characters\n  if H.str_utfindex(line) == line_len then\n    sliced, starts, ends = line:gsub('(.)', '%1\\n'), {}, {}\n    for i = 1, string.len(line) do\n      starts[i], ends[i] = i, i\n    end\n  else\n    sliced, starts, ends = {}, vim.str_utf_pos(line), {}\n    for i = 1, #starts - 1 do\n      table.insert(sliced, line:sub(starts[i], starts[i + 1] - 1))\n      table.insert(ends, starts[i + 1] - 1)\n    end\n    table.insert(sliced, line:sub(starts[#starts], line_len))\n    table.insert(ends, line_len)\n    sliced = table.concat(sliced, '\\n') .. '\\n'\n  end\n\n  return sliced, starts, ends\nend\n\n-- Hunks ----------------------------------------------------------------------\nH.get_hunk_buf_range = function(hunk)\n  -- \"Change\" and \"Add\" hunks have the range `[from, from + buf_count - 1]`\n  if hunk.buf_count > 0 then return hunk.buf_start, hunk.buf_start + hunk.buf_count - 1 end\n  -- \"Delete\" hunks have `buf_count = 0` yet its range is `[from, from]`\n  -- `buf_start` can be 0 for 'delete' hunk, yet range should be real lines\n  local from = math.max(hunk.buf_start, 1)\n  return from, from\nend\n\nH.get_hunks_in_range = function(hunks, from, to)\n  local res = {}\n  for _, h in ipairs(hunks) do\n    local h_from, h_to = H.get_hunk_buf_range(h)\n\n    local left, right = math.max(from, h_from), math.min(to, h_to)\n    if left <= right then\n      -- If any `cur` hunk part is selected, its `ref` part is used fully\n      local new_h = { ref_start = h.ref_start, ref_count = h.ref_count }\n      new_h.type = h.ref_count == 0 and 'add' or (h.buf_count == 0 and 'delete' or 'change')\n\n      -- It should be possible to work with only hunk part inside target range\n      -- Also Treat \"delete\" hunks differently as they represent range differently\n      -- and can have `buf_start=0`\n      new_h.buf_start = new_h.type == 'delete' and h.buf_start or left\n      new_h.buf_count = new_h.type == 'delete' and 0 or (right - left + 1)\n\n      table.insert(res, new_h)\n    end\n  end\n\n  table.sort(res, H.hunk_order)\n  return res\nend\n\nH.reset_hunks = function(buf_id, hunks)\n  local ref_lines = vim.split(H.cache[buf_id].ref_text, '\\n')\n  local offset = 0\n  for _, h in ipairs(hunks) do\n    -- Replace current hunk lines with corresponding reference\n    local new_lines = vim.list_slice(ref_lines, h.ref_start, h.ref_start + h.ref_count - 1)\n\n    -- Compute buffer offset from parts: result of previous replaces, \"delete\"\n    -- hunk offset which starts below the `buf_start` line, zero-indexing.\n    local buf_offset = offset + (h.buf_count == 0 and 1 or 0) - 1\n    local from, to = h.buf_start + buf_offset, h.buf_start + h.buf_count + buf_offset\n    vim.api.nvim_buf_set_lines(buf_id, from, to, false, new_lines)\n\n    -- Keep track of current hunk lines shift as a result of previous replaces\n    offset = offset + (h.ref_count - h.buf_count)\n  end\nend\n\nH.yank_hunks_ref = function(ref_text, hunks, register)\n  -- Collect reference lines\n  local ref_lines, out_lines = vim.split(ref_text, '\\n'), {}\n  for _, h in ipairs(hunks) do\n    for i = h.ref_start, h.ref_start + h.ref_count - 1 do\n      out_lines[i] = ref_lines[i]\n    end\n  end\n\n  -- Construct reference lines in order\n  local hunk_ref_lines = {}\n  for i = 1, #ref_lines do\n    table.insert(hunk_ref_lines, out_lines[i])\n  end\n\n  -- Put lines into target register\n  vim.fn.setreg(register, hunk_ref_lines, 'l')\nend\n\nH.get_contiguous_hunk_ranges = function(hunks)\n  if #hunks == 0 then return {} end\n  hunks = vim.deepcopy(hunks)\n  table.sort(hunks, H.hunk_order)\n\n  local h1_from, h1_to = H.get_hunk_buf_range(hunks[1])\n  local res = { { from = h1_from, to = h1_to } }\n  for i = 2, #hunks do\n    local h, cur_region = hunks[i], res[#res]\n    local h_from, h_to = H.get_hunk_buf_range(h)\n    if h_from <= cur_region.to + 1 then\n      cur_region.to = math.max(cur_region.to, h_to)\n    else\n      table.insert(res, { from = h_from, to = h_to })\n    end\n  end\n  return res\nend\n\nH.iterate_hunk_ranges = function(ranges, direction, opts)\n  local n = #ranges\n\n  -- Compute initial index\n  local init_ind\n  if direction == 'first' then init_ind = 0 end\n  if direction == 'prev' then init_ind = H.get_range_id_prev(ranges, opts.line_start) end\n  if direction == 'next' then init_ind = H.get_range_id_next(ranges, opts.line_start) end\n  if direction == 'last' then init_ind = n + 1 end\n\n  local is_on_edge = (direction == 'prev' and init_ind == 1) or (direction == 'next' and init_ind == n)\n  if not opts.wrap and is_on_edge then return nil end\n\n  -- Compute destination index\n  local is_move_forward = direction == 'first' or direction == 'next'\n  local res_ind = init_ind + opts.n_times * (is_move_forward and 1 or -1)\n  local did_wrap = opts.wrap and (res_ind < 1 or n < res_ind)\n  res_ind = opts.wrap and ((res_ind - 1) % n + 1) or math.min(math.max(res_ind, 1), n)\n\n  return res_ind, did_wrap\nend\n\nH.get_range_id_next = function(ranges, line_start)\n  for i = #ranges, 1, -1 do\n    if ranges[i].from <= line_start then return i end\n  end\n  return 0\nend\n\nH.get_range_id_prev = function(ranges, line_start)\n  for i = 1, #ranges do\n    if line_start <= ranges[i].to then return i end\n  end\n  return #ranges + 1\nend\n\nH.hunk_order = function(a, b)\n  -- Ensure buffer order and that \"change\" hunks are listed earlier \"delete\"\n  -- ones from the same line (important for `reset_hunks()`)\n  return a.buf_start < b.buf_start or (a.buf_start == b.buf_start and a.type == 'change')\nend\n\n-- Export ---------------------------------------------------------------------\nH.export_qf = function(opts)\n  local buffers = opts.scope == 'current' and { vim.api.nvim_get_current_buf() } or vim.tbl_keys(H.cache)\n  buffers = vim.tbl_filter(vim.api.nvim_buf_is_valid, buffers)\n  table.sort(buffers)\n\n  local type_text = { add = 'Add', change = 'Change', delete = 'Delete' }\n\n  local res = {}\n  for _, buf_id in ipairs(buffers) do\n    local filename = vim.api.nvim_buf_get_name(buf_id)\n    local buf_lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)\n    for _, h in ipairs(H.cache[buf_id].hunks) do\n      local text = type_text[h.type]\n      local entry = { bufnr = buf_id, filename = filename, type = text:sub(1, 1), text = text }\n      entry.lnum, entry.end_lnum = H.get_hunk_buf_range(h)\n      -- Make 'add' and 'change' hunks represent actual buffer regions\n      entry.col, entry.end_col = 1, h.type == 'delete' and 1 or buf_lines[entry.end_lnum]:len() + 1\n      table.insert(res, entry)\n    end\n  end\n  return res\nend\n\n-- Git ------------------------------------------------------------------------\nH.git_start_watching_index = function(buf_id, path)\n  -- NOTE: Watching single 'index' file is not enough as staging by Git is done\n  -- via \"create fresh 'index.lock' file, apply modifications, change file name\n  -- to 'index'\". Hence watch the whole '.git' (first level) and react only if\n  -- change was in 'index' file.\n  local stdout = vim.loop.new_pipe()\n  local args = { 'rev-parse', '--path-format=absolute', '--git-dir' }\n  local spawn_opts = { args = args, cwd = vim.fn.fnamemodify(path, ':h'), stdio = { nil, stdout, nil } }\n\n  -- If path is not in Git, disable buffer but make sure that it will not try\n  -- to re-attach until buffer is properly disabled\n  local on_not_in_git = vim.schedule_wrap(function()\n    if not vim.api.nvim_buf_is_valid(buf_id) then\n      H.cache[buf_id] = nil\n      return\n    end\n    MiniDiff.fail_attach(buf_id)\n    H.git_cache[buf_id] = {}\n  end)\n\n  local process, stdout_feed = nil, {}\n  local on_exit = function(exit_code)\n    process:close()\n\n    -- Watch index only if there was no error retrieving path to it\n    if exit_code ~= 0 or stdout_feed[1] == nil then return on_not_in_git() end\n\n    -- Set up index watching\n    local git_dir_path = table.concat(stdout_feed, ''):gsub('\\n+$', '')\n    H.git_setup_index_watch(buf_id, git_dir_path)\n\n    -- Set reference text immediately\n    H.git_set_ref_text(buf_id)\n  end\n\n  process = vim.loop.spawn('git', spawn_opts, on_exit)\n  H.git_read_stream(stdout, stdout_feed)\nend\n\nH.git_setup_index_watch = function(buf_id, git_dir_path)\n  local buf_fs_event, timer = vim.loop.new_fs_event(), vim.loop.new_timer()\n  local buf_git_set_ref_text = function() H.git_set_ref_text(buf_id) end\n\n  local watch_index = function(_, filename, _)\n    if filename ~= 'index' then return end\n    -- Debounce to not overload during incremental staging (like in script)\n    timer:stop()\n    timer:start(50, 0, buf_git_set_ref_text)\n  end\n  buf_fs_event:start(git_dir_path, { recursive = false }, watch_index)\n\n  H.git_invalidate_cache(H.git_cache[buf_id])\n  H.git_cache[buf_id] = { fs_event = buf_fs_event, timer = timer }\nend\n\nH.git_set_ref_text = vim.schedule_wrap(function(buf_id)\n  if not vim.api.nvim_buf_is_valid(buf_id) then return end\n  local buf_set_ref_text = vim.schedule_wrap(function(text) pcall(MiniDiff.set_ref_text, buf_id, text) end)\n\n  -- NOTE: Do not cache buffer's name to react to its possible rename\n  local path = H.get_buf_realpath(buf_id)\n  if path == '' then return buf_set_ref_text({}) end\n  local cwd, basename = vim.fn.fnamemodify(path, ':h'), vim.fn.fnamemodify(path, ':t')\n\n  -- Set\n  local stdout = vim.loop.new_pipe()\n  local spawn_opts = { args = { 'show', ':0:./' .. basename }, cwd = cwd, stdio = { nil, stdout, nil } }\n\n  local process, stdout_feed = nil, {}\n  local on_exit = function(exit_code)\n    process:close()\n\n    -- Unset reference text in case of any error. This results into not showing\n    -- hunks at all. Possible reasons to do so:\n    -- - 'Not in index' files (new, ignored, etc.).\n    -- - 'Neither in index nor on disk' files (after checking out commit which\n    --   does not yet have file created).\n    -- - 'Relative can not be used outside working tree' (when opening file\n    --   inside '.git' directory).\n    if exit_code ~= 0 or stdout_feed[1] == nil then return buf_set_ref_text({}) end\n\n    -- Set reference text accounting for possible 'crlf' end of line in index\n    local text = table.concat(stdout_feed, ''):gsub('\\r\\n', '\\n')\n    buf_set_ref_text(text)\n  end\n\n  process = vim.loop.spawn('git', spawn_opts, on_exit)\n  H.git_read_stream(stdout, stdout_feed)\nend)\n\nH.git_get_path_data = function(path)\n  -- Get path data needed for proper patch header\n  local cwd, basename = vim.fn.fnamemodify(path, ':h'), vim.fn.fnamemodify(path, ':t')\n  local stdout = vim.loop.new_pipe()\n  local args = { 'ls-files', '-z', '--full-name', '--format=%(objectmode) %(eolinfo:index) %(path)', '--', basename }\n  local spawn_opts = { args = args, cwd = cwd, stdio = { nil, stdout, nil } }\n\n  local process, stdout_feed, res, did_exit = nil, {}, { cwd = cwd }, false\n  local on_exit = function(exit_code)\n    process:close()\n\n    did_exit = true\n    if exit_code ~= 0 then return end\n    -- Parse data about path\n    local out = table.concat(stdout_feed, ''):gsub('(%z\\n)+$', '')\n    res.mode_bits, res.eol, res.rel_path = string.match(out, '^(%d+) (%S+) (.*)$')\n  end\n\n  process = vim.loop.spawn('git', spawn_opts, on_exit)\n  H.git_read_stream(stdout, stdout_feed)\n  vim.wait(1000, function() return did_exit end, 1)\n  return res\nend\n\nH.git_format_patch = function(buf_id, hunks, path_data)\n  local _, buf_lines = H.get_buftext(buf_id)\n  local ref_lines = vim.split(H.cache[buf_id].ref_text, '\\n')\n\n  local res = {\n    string.format('diff --git a/%s b/%s', path_data.rel_path, path_data.rel_path),\n    'index 000000..000000 ' .. path_data.mode_bits,\n    '--- a/' .. path_data.rel_path,\n    '+++ b/' .. path_data.rel_path,\n  }\n\n  -- Take into account changing target ref region as a result of previous hunks\n  local offset = 0\n  local cr_eol = path_data.eol == 'crlf' and '\\r' or ''\n  for _, h in ipairs(hunks) do\n    -- \"Add\" hunks have reference line above target\n    local start = h.ref_start + (h.ref_count == 0 and 1 or 0)\n\n    table.insert(res, string.format('@@ -%d,%d +%d,%d @@', start, h.ref_count, start + offset, h.buf_count))\n    for i = h.ref_start, h.ref_start + h.ref_count - 1 do\n      table.insert(res, '-' .. ref_lines[i] .. cr_eol)\n    end\n    for i = h.buf_start, h.buf_start + h.buf_count - 1 do\n      table.insert(res, '+' .. buf_lines[i] .. cr_eol)\n    end\n    offset = offset + (h.buf_count - h.ref_count)\n  end\n\n  return res\nend\n\nH.git_apply_patch = function(path_data, patch)\n  local stdin = vim.loop.new_pipe()\n  local args = { 'apply', '--whitespace=nowarn', '--cached', '--unidiff-zero', '-' }\n  local spawn_opts = { args = args, cwd = path_data.cwd, stdio = { stdin, nil, nil } }\n  local process\n  process = vim.loop.spawn('git', spawn_opts, function() process:close() end)\n\n  -- Write patch, notify that writing is finished (shutdown), and close\n  for _, l in ipairs(patch) do\n    stdin:write(l)\n    stdin:write('\\n')\n  end\n  stdin:shutdown(function() stdin:close() end)\nend\n\nH.git_read_stream = function(stream, feed)\n  local callback = function(err, data)\n    if data ~= nil then return table.insert(feed, data) end\n    if err then feed[1] = nil end\n    stream:close()\n  end\n  stream:read_start(callback)\nend\n\nH.git_invalidate_cache = function(cache)\n  if cache == nil then return end\n  pcall(vim.loop.fs_event_stop, cache.fs_event)\n  pcall(vim.loop.timer_stop, cache.timer)\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.diff) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.notify = function(msg, level_name) vim.notify('(mini.diff) ' .. msg, vim.log.levels[level_name]) end\n\nH.buf_ensure_loaded = function(buf_id)\n  if type(buf_id) ~= 'number' or vim.api.nvim_buf_is_loaded(buf_id) then return end\n  local cache_eventignore = vim.o.eventignore\n  vim.o.eventignore = 'BufEnter,BufWinEnter'\n  pcall(vim.fn.bufload, buf_id)\n  vim.o.eventignore = cache_eventignore\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.set_extmark = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end\n\nH.get_extmarks = function(...)\n  local ok, res = pcall(vim.api.nvim_buf_get_extmarks, ...)\n  if not ok then return {} end\n  return res\nend\n\nH.clear_namespace = function(...) pcall(vim.api.nvim_buf_clear_namespace, ...) end\n\nH.is_buf_text = function(buf_id)\n  local n = vim.api.nvim_buf_call(buf_id, function() return vim.fn.byte2line(1024) end)\n  local lines = vim.api.nvim_buf_get_lines(buf_id, 0, n, false)\n  return table.concat(lines, ''):find('\\0') == nil\nend\n\nH.get_buftext = function(buf_id)\n  local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)\n  -- - NOTE: Appending '\\n' makes more intuitive diffs at end-of-file\n  local text = table.concat(lines, '\\n') .. '\\n'\n  if not vim.bo[buf_id].bomb then return text, lines end\n  local bytes = H.bom_bytes[vim.bo[buf_id].fileencoding] or ''\n  lines[1] = bytes .. lines[1]\n  return bytes .. text, lines\nend\n\n-- Try getting buffer's full real path (after resolving symlinks)\nH.get_buf_realpath = function(buf_id) return vim.loop.fs_realpath(vim.api.nvim_buf_get_name(buf_id)) or '' end\n\n-- nvim__redraw replaced nvim__buf_redraw_range during the 0.10 release cycle\nH.redraw_buffer = function(buf_id)\n  vim.api.nvim__buf_redraw_range(buf_id, 0, -1)\n\n  -- Redraw statusline to have possible statusline component up to date\n  vim.cmd('redrawstatus')\nend\nif vim.api.nvim__redraw ~= nil then\n  H.redraw_buffer = function(buf_id) vim.api.nvim__redraw({ buf = buf_id, valid = true, statusline = true }) end\nend\n\nreturn MiniDiff\n"
  },
  {
    "path": "lua/mini/doc.lua",
    "content": "--- *mini.doc* Generate Neovim help files\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Key design ideas:\n--- - Keep documentation next to code by writing EmmyLua-like annotation\n---   comments. They will be parsed as is, so formatting should follow built-in\n---   guide in |help-writing|. However, custom hooks are allowed at many\n---   generation stages for more granular management of output help file.\n---\n--- - Generation is done by processing a set of ordered files line by line.\n---   Each line can either be considered as a part of documentation block (if\n---   it matches certain configurable pattern) or not (considered to be an\n---   \"afterline\" of documentation block). See |MiniDoc.generate()| for more\n---   details.\n---\n--- - Processing is done by using nested data structures (section, block, file,\n---   doc) describing certain parts of help file. See |MiniDoc-data-structures|\n---   for more details.\n---\n--- - Project specific script can be written as plain Lua file with\n---   configuratble path. See |MiniDoc.generate()| for more details.\n---\n--- What it doesn't do:\n--- - It doesn't support markdown or other markup language inside annotations.\n--- - It doesn't use treesitter in favor of Lua string manipulation for basic\n---   tasks (parsing annotations, formatting, auto-generating tags, etc.). This\n---   is done to manage complexity and be dependency free.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.doc').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniDoc`\n--- which you can use for scripting or manually (with `:lua MiniDoc.*`).\n---\n--- See |MiniDoc.config| for available config settings.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minidoc_config` which should have same structure as `MiniDoc.config`.\n--- See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Tips ~\n---\n--- - Some settings tips that might make writing annotation comments easier:\n---     - Set up appropriate 'comments' for `lua` file type to respect\n---       EmmyLua-like's `---` comment leader. Value `:---,:--` seems to work.\n---     - Set up appropriate 'formatoptions' (see also |fo-table|). Consider\n---       adding `j`, `n`, `q`, and `r` flags.\n---     - Set up appropriate 'formatlistpat' to help auto-formatting lists (if\n---       `n` flag is added to 'formatoptions'). One suggestion (not entirely\n---       ideal) is a value `^\\s*[0-9\\-\\+\\*]\\+[\\.\\)]*\\s\\+`. This reads as 'at\n---       least one special character (digit, `-`, `+`, `*`) possibly followed\n---       by some punctuation (`.` or `)`) followed by at least one space is a\n---       start of list item'.\n--- - Probably one of the most reliable resources for what is considered to be\n---   best practice when using this module is this whole plugin. Look at source\n---   code for the reference.\n---\n--- # Comparisons ~\n---\n--- - [tjdevries/tree-sitter-lua](https://github.com/tjdevries/tree-sitter-lua):\n---     - Its key design is to use treesitter grammar to parse both Lua code\n---       and annotation comments. This makes it not easy to install,\n---       customize, and support.\n---     - It takes more care about automating output formatting (like auto\n---       indentation and line width fit). This plugin leans more to manual\n---       formatting with option to supply customized post-processing hooks.\n---@tag MiniDoc\n\n--- Data structures\n---\n--- Data structures are basically arrays of other structures accompanied with\n--- some fields (keys with data values) and methods (keys with function\n--- values):\n--- - `Section structure` is an array of string lines describing one aspect\n---   (determined by section id like '@param', '@return', '@text') of an\n---   annotation subject. All lines will be used directly in help file.\n--- - `Block structure` is an array of sections describing one annotation\n---   subject like function, table, concept.\n--- - `File structure` is an array of blocks describing certain file on disk.\n---   Basically, file is split into consecutive blocks: annotation lines go\n---   inside block, non-annotation - inside `block_afterlines` element of info.\n--- - `Doc structure` is an array of files describing a final help file. Each\n---   string line from section (when traversed in depth-first fashion) goes\n---   directly into output file.\n---\n--- All structures have these keys:\n--- - Fields:\n---     - `info` - contains additional information about current structure.\n---       For more details see next section.\n---     - `parent` - table of parent structure (if exists).\n---     - `parent_index` - index of this structure in its parent's array. Useful\n---       for adding to parent another structure near current one.\n---     - `type` - string with structure type (section, block, file, doc).\n--- - Methods (use them as `x:method(args)`):\n---     - `insert(self, [index,] child)` - insert `child` to `self` at position\n---       `index` (optional; if not supplied, child will be appended to end).\n---       Basically, a `table.insert()`, but adds `parent` and `parent_index`\n---       fields to `child` while properly updating `self`.\n---     - `remove(self [,index])` - remove from `self` element at position\n---       `index`. Basically, a `table.remove()`, but properly updates `self`.\n---     - `has_descendant(self, predicate)` - whether there is a descendant\n---       (structure or string) for which `predicate` returns `true`. In case of\n---       success also returns the first such descendant as second value.\n---     - `has_lines(self)` - whether structure has any lines (even empty ones)\n---       to be put in output file. For section structures this is equivalent to\n---       `#self`, but more useful for higher order structures.\n---     - `clear_lines(self)` - remove all lines from structure. As a result,\n---       this structure won't contribute to output help file.\n---\n--- Description of `info` fields per structure type:\n--- - `Section`:\n---     - `id` - captured section identifier. Can be empty string meaning no\n---       identifier is captured.\n---     - `line_begin` - line number inside file at which section begins (-1 if\n---       not generated from file).\n---     - `line_end` - line number inside file at which section ends (-1 if not\n---       generated from file).\n--- - `Block`:\n---     - `afterlines` - array of strings which were parsed from file after\n---       this annotation block (up until the next block or end of file).\n---       Useful for making automated decisions about what is being documented.\n---     - `line_begin` - line number inside file at which block begins  (-1 if\n---       not generated from file).\n---     - `line_end` - line number inside file at which block ends  (-1 if not\n---       generated from file).\n--- - `File`:\n---     - `path` - absolute path to a file (`''` if not generated from file).\n--- - `Doc`:\n---     - `input` - array of input file paths (as in |MiniDoc.generate()|).\n---     - `output` - output path (as in |MiniDoc.generate()|).\n---     - `config` - configuration used (as in |MiniDoc.generate()|).\n---@tag MiniDoc-data-structures\n\n-- Module definition ==========================================================\nlocal MiniDoc = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniDoc.config|.\n---\n---@usage >lua\n---   require('mini.doc').setup() -- use default config\n---   -- OR\n---   require('mini.doc').setup({}) -- replace {} with your config table\n--- <\nMiniDoc.setup = function(config)\n  -- Export module\n  _G.MiniDoc = MiniDoc\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Notes ~\n---\n--- - `annotation_extractor` takes single string line as input. Output\n---   describes what makes an input to be an annotation (if anything). It\n---   should be similar to `string.find` with one capture group: start and end\n---   of annotation indicator (whole part will be removed from help line) with\n---   third value being string of section id (if input describes first line of\n---   section; `nil` or empty string otherwise). Output should be `nil` if line\n---   is not part of annotation.\n---   Default value means that annotation line should:\n---     - Start with `---` at first column.\n---     - Any non-whitespace after `---` will be treated as new section id.\n---     - Single whitespace at the start of main text will be ignored.\n--- - Hooks are expected to be functions. Their default values might do many\n---   things which might change over time, so for more information please look\n---   at source code. Some more information can be found in\n---   |MiniDoc.default_hooks|.\nMiniDoc.config = {\n  -- Function which extracts part of line used to denote annotation.\n  -- For more information see 'Notes' in |MiniDoc.config|.\n  annotation_extractor = function(l) return string.find(l, '^%-%-%-(%S*) ?') end,\n\n  -- Identifier of block annotation lines until first captured identifier\n  default_section_id = '@text',\n\n  -- Hooks to be applied at certain stage of document life cycle. Should\n  -- modify its input in place (and not return new one).\n  hooks = {\n    -- Applied to block before anything else\n    --minidoc_replace_start block_pre = --<function: infers header sections (tag and/or signature)>,\n    block_pre = function(b)\n      -- Infer metadata based on afterlines\n      if b:has_lines() and #b.info.afterlines > 0 then H.infer_header(b) end\n    end,\n    --minidoc_replace_end\n\n    -- Applied to section before anything else\n    --minidoc_replace_start section_pre = --<function: replaces current aliases>,\n    section_pre = function(s) H.alias_replace(s) end,\n    --minidoc_replace_end\n\n    -- Applied if section has specified captured id\n    sections = {\n      --minidoc_replace_start ['@alias'] = --<function: registers alias in MiniDoc.current.aliases>,\n      ['@alias'] = function(s)\n        H.alias_register(s)\n        -- NOTE: don't use `s.parent:remove(s.parent_index)` here because it\n        -- disrupts iteration over block's section during hook application\n        -- (skips next section).\n        s:clear_lines()\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@class'] = --<function>,\n      ['@class'] = function(s)\n        H.enclose_var_name(s)\n        H.add_section_heading(s, 'Class')\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@diagnostic'] = --<function: ignores any section content>,\n      ['@diagnostic'] = function(s) s:clear_lines() end,\n      --minidoc_replace_end\n      -- For most typical usage see |MiniDoc.afterlines_to_code|\n      --minidoc_replace_start ['@eval'] = --<function: evaluates lines; replaces with their return>,\n      ['@eval'] = function(s)\n        local src = table.concat(s, '\\n')\n        local is_loaded, code = pcall(function() return assert(loadstring(src)) end)\n        local output\n        if is_loaded then\n          MiniDoc.current.eval_section = s\n          output = code()\n          MiniDoc.current.eval_section = nil\n        else\n          output = 'MINIDOC ERROR. Parsing Lua code gave the following error:\\n' .. code\n        end\n\n        s:clear_lines()\n\n        if output == nil then return end\n        if type(output) == 'string' then output = vim.split(output, '\\n') end\n        if type(output) ~= 'table' then\n          s[1] = 'MINIDOC ERROR. Returned value should be `nil`, `string`, or `table`.'\n          return\n        end\n        for _, x in ipairs(output) do\n          s:insert(x)\n        end\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@field'] = --<function>,\n      ['@field'] = function(s)\n        H.mark_optional(s)\n        H.enclose_var_name(s)\n        local col_past_var_name = s[1]:match('^%s*%S+%s+`%(optional%)`()') or s[1]:match('^%s*%S+()') or 1\n        H.enclose_type(s, col_past_var_name)\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@overload'] = --<function>,\n      ['@overload'] = function(s)\n        s[1] = '`' .. s[1] .. '`'\n        H.add_section_heading(s, 'Overload')\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@param'] = --<function>,\n      ['@param'] = function(s)\n        H.mark_optional(s)\n        H.enclose_var_name(s)\n        local col_past_var_name = s[1]:match('^%s*%S+%s+`%(optional%)`()') or s[1]:match('^%s*%S+()') or 1\n        H.enclose_type(s, col_past_var_name)\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@private'] = --<function: registers block for removal>,\n      ['@private'] = function(s) s.parent:clear_lines() end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@return'] = --<function>,\n      ['@return'] = function(s)\n        H.mark_optional(s)\n        H.enclose_type(s, 1)\n        H.add_section_heading(s, 'Return')\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@seealso'] = --<function>,\n      ['@seealso'] = function(s) H.add_section_heading(s, 'See also') end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@signature'] = --<function: formats signature of documented object>,\n      ['@signature'] = function(s)\n        for i, _ in ipairs(s) do\n          -- Add extra formatting to make it stand out\n          s[i] = H.format_signature(s[i])\n\n          -- Align accounting for concealed characters\n          s[i] = H.align_text(s[i], 78, 'center')\n        end\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@tag'] = --<function: turns its line in proper tag lines>,\n      ['@tag'] = function(s)\n        for i, _ in ipairs(s) do\n          -- Enclose every word in `*`\n          s[i] = s[i]:gsub('(%S+)', '%*%1%*')\n\n          -- Align to right edge accounting for concealed characters\n          s[i] = H.align_text(s[i], 78, 'right')\n        end\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@text'] = --<function: purposefully does nothing>,\n      ['@text'] = function() end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@toc'] = --<function: clears all section lines>,\n      ['@toc'] = function(s) s:clear_lines() end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@toc_entry'] = --<function: registers lines for table of contents>,\n      ['@toc_entry'] = function(s) H.toc_register(s) end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@type'] = --<function>,\n      ['@type'] = function(s)\n        H.enclose_type(s, 1)\n        H.add_section_heading(s, 'Type')\n      end,\n      --minidoc_replace_end\n      --minidoc_replace_start ['@usage'] = --<function>,\n      ['@usage'] = function(s) H.add_section_heading(s, 'Usage') end,\n      --minidoc_replace_end\n    },\n\n    -- Applied to section after all previous steps\n    --minidoc_replace_start section_post = --<function: currently does nothing>,\n    section_post = function(s) end,\n    --minidoc_replace_end\n\n    -- Applied to block after all previous steps\n    --minidoc_replace_start block_post = --<function: does many things>,\n    block_post = function(b)\n      if not b:has_lines() then return end\n\n      local found_param, found_field = false, false\n      local n_tag_sections, last_line = 0, nil\n      H.apply_recursively(function(x)\n        if not (type(x) == 'table' and x.type == 'section') then return end\n\n        -- Add headings before first occurrence of a section which type usually\n        -- appear several times\n        if not found_param and x.info.id == '@param' then\n          H.add_section_heading(x, 'Parameters')\n          found_param = true\n        end\n        if not found_field and x.info.id == '@field' then\n          H.add_section_heading(x, 'Fields')\n          found_field = true\n        end\n\n        if x.info.id == '@tag' then\n          x.parent:remove(x.parent_index)\n          n_tag_sections = n_tag_sections + 1\n          x.parent:insert(n_tag_sections, x)\n        elseif type(x[#x]) == 'string' then\n          last_line = x[#x]\n        end\n      end, b)\n\n      b:insert(1, H.as_struct({ string.rep('-', 78) }, 'section'))\n      -- Append empty line only if last line is not visibly blank (closing code\n      -- block with \"<\" is concealed)\n      if string.find(last_line, '^<?%s*$') == nil then b:insert(H.as_struct({ '' }, 'section')) end\n    end,\n    --minidoc_replace_end\n\n    -- Applied to file after all previous steps\n    --minidoc_replace_start file = --<function: adds separator>,\n    file = function(f)\n      if not f:has_lines() then return end\n\n      f:insert(1, H.as_struct({ H.as_struct({ string.rep('=', 78) }, 'section') }, 'block'))\n      f:insert(H.as_struct({ H.as_struct({ '' }, 'section') }, 'block'))\n    end,\n    --minidoc_replace_end\n\n    -- Applied to doc after all previous steps\n    --minidoc_replace_start doc = --<function: adds modeline>,\n    doc = function(d)\n      -- Render table of contents\n      H.apply_recursively(function(x)\n        if not (type(x) == 'table' and x.type == 'section' and x.info.id == '@toc') then return end\n        H.toc_insert(x)\n      end, d)\n\n      -- Insert modeline\n      d:insert(\n        H.as_struct(\n          { H.as_struct({ H.as_struct({ ' vim:tw=78:ts=8:noet:ft=help:norl:' }, 'section') }, 'block') },\n          'file'\n        )\n      )\n    end,\n    --minidoc_replace_end\n\n    -- Applied before output file is written. Takes lines array as argument.\n    --minidoc_replace_start write_pre = --<function: removes delimiters at the top>,\n    write_pre = function(l)\n      -- Remove first two lines with `======` and `------` delimiters to comply\n      -- with `:h local-additions` template\n      if l[1]:find('^=+$') ~= nil then table.remove(l, 1) end\n      if l[1]:find('^-+$') ~= nil then table.remove(l, 1) end\n      return l\n    end,\n    --minidoc_replace_end\n\n    -- Applied after output help file is written. Takes doc as argument.\n    --minidoc_replace_start write_post = --<function: various convenience actions>,\n    write_post = function(d)\n      local output = d.info.output\n\n      -- Generate help tags for directory of output file\n      vim.cmd('helptags ' .. vim.fn.fnamemodify(output, ':h'))\n\n      -- Reload buffer with output file (helps during writing annotations)\n      local output_path = H.full_path(output)\n      for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n        local buf_path = H.full_path(vim.api.nvim_buf_get_name(buf_id))\n        if buf_path == output_path then\n          vim.api.nvim_buf_call(buf_id, function() vim.cmd('noautocmd silent edit | set ft=help') end)\n        end\n      end\n\n      -- Notify\n      local msg = ('Help file %s is successfully generated.'):format(vim.inspect(output))\n      vim.notify(msg, vim.log.levels.INFO)\n    end,\n    --minidoc_replace_end\n  },\n\n  -- Path (relative to current directory) to script which handles project\n  -- specific help file generation (like custom input files, hooks, etc.).\n  script_path = 'scripts/minidoc.lua',\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module data ================================================================\n--- Table with information about current state of auto-generation\n---\n--- It is reset at the beginning and end of `MiniDoc.generate()`.\n---\n--- At least these keys are supported:\n--- - {aliases} - table with keys being alias name and values - alias\n---   description and single string (using `\\n` to separate lines).\n--- - {eval_section} - input section of `@eval` section hook. Can be used for\n---   information about current block, etc.\n--- - {toc} - array with table of contents entries. Each entry is a whole\n---   `@toc_entry` section.\nMiniDoc.current = { aliases = {}, toc = {} }\n\n--- Default hooks\n---\n--- This is default value of `MiniDoc.config.hooks`. Use it if only a little\n--- tweak is needed.\n---\n--- Some more insight about their behavior:\n--- - Default inference of documented object metadata (tag and object signature\n---   at the moment) is done in `block_pre`. Inference is based on string\n---   pattern matching, so can lead to false results, although works in most\n---   cases. It intentionally works only if first line after block has no\n---   indentation and contains all necessary information to determine if\n---   inference should happen.\n--- - Hooks for sections describing some \"variable-like\" object ('@class',\n---   '@field', '@param') automatically enclose first word in '{}'.\n--- - Hooks for sections which supposed to have \"type-like\" data ('@field',\n---   '@param', '@return', '@type') automatically enclose *first found*\n---   \"type-like\" word and its neighbor characters in '`(<type>)`' (expect\n---   false positives). Algorithm is far from being 100% correct, but seems to\n---   work with present allowed type annotation. For allowed types see\n---   https://github.com/sumneko/lua-language-server/wiki/EmmyLua-Annotations#types-and-type\n---   or, better yet, look in source code of this module.\n--- - Automated creation of table of contents (TOC) is done in the following way:\n---     - Put section with `@toc_entry` id in the annotation block. Section's\n---       lines will be registered as TOC entry.\n---     - Put `@toc` section where you want to insert rendered table of\n---       contents. TOC entries will be inserted on the left, references for\n---       their respective tag section (only first, if present) on the right.\n---       Render is done in default `doc` hook (because it should be done after\n---       processing all files).\n--- - The `write_post` hook executes some actions convenient for iterative\n---   annotations writing:\n---     - Generate `:helptags` for directory containing output file.\n---     - Silently reload buffer containing output file (if such exists).\n---     - Display notification message about result.\nMiniDoc.default_hooks = MiniDoc.config.hooks\n\n-- Module functionality =======================================================\n--- Generate help file\n---\n--- # Algorithm ~\n---\n--- - Main parameters for help generation are an array of input file paths and\n---   path to output help file.\n--- - Parse all inputs:\n---   - For each file, lines are processed top to bottom in order to create an\n---     array of documentation blocks. Each line is tested whether it is an\n---     annotation by applying `MiniDoc.config.annotation_extractor`: if\n---     anything is extracted, it is considered to be an annotation. Annotation\n---     line goes to \"current block\" after removing extracted annotation\n---     indicator, otherwise - to afterlines of \"current block\".\n---   - Each block's annotation lines are processed top to bottom. If line had\n---     captured section id, it is a first line of \"current section\" (first\n---     block lines are allowed to not specify section id; by default it is\n---     `@text`). All subsequent lines without captured section id go into\n---     \"current section\".\n--- - Apply structure hooks (they should modify its input in place, which is\n---   possible due to 'table nature' of all inputs):\n---     - Each block is processed by `MiniDoc.config.hooks.block_pre`. This is a\n---       designated step for auto-generation of sections from described\n---       annotation subject (like sections with id `@tag`, `@type`).\n---     - Each section is processed by `MiniDoc.config.hooks.section_pre`.\n---     - Each section is processed by corresponding\n---       `MiniDoc.config.hooks.sections` function (table key equals to section\n---       id). This is a step where most of formatting should happen (like\n---       wrap first word of `@param` section with `{` and `}`, append empty\n---       line to section, etc.).\n---     - Each section is processed by `MiniDoc.config.hooks.section_post`.\n---     - Each block is processed by `MiniDoc.config.hooks.block_post`. This is\n---       a step for processing block after formatting is done (like add first\n---       line with `----` delimiter).\n---     - Each file is processed by `MiniDoc.config.hooks.file`. This is a step\n---       for adding any file-related data (like add first line with `====`\n---       delimiter).\n---     - Doc is processed by `MiniDoc.config.hooks.doc`. This is a step for\n---       adding any helpfile-related data (maybe like table of contents).\n--- - Collect all strings from sections in depth-first fashion (equivalent to\n---   nested \"for all files -> for all blocks -> for all sections -> for all\n---   strings -> add string to output\"). Strings can have `\\n` character\n---   indicating start of new line.\n--- - Modify collected strings with `MiniDoc.config.write_pre`. Takes strings\n---   from previous step as input and should return array of strings.\n--- - Write modified strings to output file.\n--- - Execute `MiniDoc.config.write_post` hook. This is useful for showing some\n---   feedback and making actions involving newly updated help file (like\n---   generate tags, etc.).\n---\n--- # Project specific script ~\n---\n--- If all arguments have default `nil` values, first there is an attempt to\n--- source project specific script. This is basically a\n--- `luafile <MiniDoc.config.script_path>` with current Lua runtime while caching\n--- and restoring current `MiniDoc.config`. Its successful execution stops any\n--- further generation actions while error means proceeding generation as if no\n--- script was found.\n---\n--- Typical script content might include definition of custom hooks, input and\n--- output files with eventual call to `require('mini.doc').generate()` (with\n--- or without arguments).\n---\n---@param input table|nil Array of file paths which will be processed in supplied\n---   order. Default: all '.lua' files from current directory following by all\n---   such files in these subdirectories: 'lua/', 'after/', 'colors/'. Note:\n---   any 'init.lua' file is placed before other files from the same directory.\n---@param output string|nil Path for output help file. Default:\n---   `doc/<current_directory>.txt` (designed to be used for generating help\n---   file for plugin).\n---@param config table|nil Configuration overriding parts of |MiniDoc.config|.\n---\n---@return table Document structure which was generated and used for output\n---   help file. In case `MiniDoc.config.script_path` was successfully used,\n---   this is a return from the latest call of this function.\nMiniDoc.generate = function(input, output, config)\n  -- Try sourcing project specific script first\n  local success = H.execute_project_script(input, output, config)\n  if success then return H.generate_recent_output end\n\n  input = input or H.default_input()\n  output = output or H.default_output()\n  config = H.get_config(config)\n\n  -- Prepare table for current information\n  MiniDoc.current = {}\n\n  -- Parse input files\n  local doc = H.new_struct('doc', { input = input, output = output, config = config })\n  for _, path in ipairs(input) do\n    local lines = H.file_read(path)\n    local block_arr = H.lines_to_block_arr(lines, config)\n    local file = H.as_struct(block_arr, 'file', { path = path })\n\n    doc:insert(file)\n  end\n\n  -- Apply hooks\n  H.apply_structure_hooks(doc, config.hooks)\n\n  -- Gather string lines in depth-first fashion\n  local help_lines = H.collect_strings(doc)\n\n  -- Execute pre-write hook\n  help_lines = config.hooks.write_pre(help_lines)\n  if not H.is_array_of(help_lines, H.is_string) then H.error('Output of `write_pre` should be array of strings.') end\n\n  -- Write helpfile\n  H.file_write(output, help_lines)\n\n  -- Execute post-write hook\n  config.hooks.write_post(doc)\n\n  -- Clear current information\n  MiniDoc.current = {}\n\n  -- Stash output to allow returning value even when called from script\n  H.generate_recent_output = doc\n\n  return doc\nend\n\n--- Convert afterlines to code\n---\n--- This function is designed to be used together with `@eval` section to\n--- automate documentation of certain values (notably default values of a\n--- table). It processes afterlines based on certain directives and makes\n--- output look like a Lua code block.\n---\n--- Most common usage is by adding the following section in your annotation: >\n---\n---   ---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n--- <\n--- # Directives ~\n---\n--- Directives are special comments that are processed using Lua string pattern\n--- capabilities (so beware of false positives). Each directive should be put\n--- on its separate line. Supported directives:\n--- - `--minidoc_afterlines_end` denotes a line at afterlines end. Only all\n---   lines before it will be considered as afterlines. Useful if there is\n---   extra code in afterlines which shouldn't be used.\n--- - `--minidoc_replace_start <replacement>` and `--minidoc_replace_end`\n---   denote lines between them which should be replaced with `<replacement>`.\n---   Useful for manually changing what should be placed in output like in case\n---   of replacing function body with something else.\n---\n--- Here is an example. Suppose having these afterlines: >lua\n---\n---   --minidoc_replace_start {\n---   M.config = {\n---     --minidoc_replace_end\n---     param_one = 1,\n---     --minidoc_replace_start param_fun = --<function>\n---     param_fun = function(x)\n---       return x + 1\n---     end\n---     --minidoc_replace_end\n---   }\n---   --minidoc_afterlines_end\n---\n---   return M\n--- <\n--- After adding `@eval` section those will be formatted as: >\n---\n---   {\n---     param_one = 1,\n---     param_fun = --<function>\n---   }\n--- <\n---@param struct table Block or section structure which after lines will be\n---   converted to code.\n---\n---@return string|nil Single string (using `\\n` to separate lines) describing\n---   afterlines as Lua code block in help file. If `nil`, input is not valid.\nMiniDoc.afterlines_to_code = function(struct)\n  if not (type(struct) == 'table' and (struct.type == 'section' or struct.type == 'block')) then\n    vim.notify('Input to `MiniDoc.afterlines_to_code()` should be either section or block.', vim.log.levels.WARN)\n    return\n  end\n\n  if struct.type == 'section' then struct = struct.parent end\n  local src = table.concat(struct.info.afterlines, '\\n')\n\n  -- Process directives\n  -- Try to extract afterlines\n  src = src:match('^(.-)\\n%s*%-%-minidoc_afterlines_end') or src\n\n  -- Make replacements\n  src = src:gsub('%-%-minidoc_replace_start ?(.-)\\n.-%-%-minidoc_replace_end', '%1')\n\n  -- Convert to a standalone code. NOTE: indent is needed because of how `>`\n  -- and `<` work (any line starting in column 1 stops code block).\n  src = H.ensure_indent(src, 2)\n  return '>lua\\n' .. src .. '\\n<'\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniDoc.config)\n\n-- Alias registry. Keys are alias name, values - single string of alias\n-- description with '\\n' separating output lines.\nH.alias_registry = {}\n\n--stylua: ignore start\nH.pattern_sets = {\n  -- Patterns for working with afterlines. At the moment deliberately crafted\n  -- to work only on first line without indent.\n\n  -- Determine if line is a function definition. Captures function name and\n  -- arguments. For reference see '2.5.9 – Function Definitions' in Lua manual.\n  afterline_fundef = {\n    '^function%s+(%S-)(%b())',             -- Regular definition\n    '^local%s+function%s+(%S-)(%b())',     -- Local definition\n    '^(%S+)%s*=%s*function(%b())',         -- Regular assignment\n    '^local%s+(%S+)%s*=%s*function(%b())', -- Local assignment\n  },\n\n  -- Determine if line is a general assignment\n  afterline_assign = {\n    '^(%S-)%s*=',         -- General assignment\n    '^local%s+(%S-)%s*=', -- Local assignment\n  },\n\n  -- Patterns to work with type descriptions\n  -- (see https://github.com/sumneko/lua-language-server/wiki/EmmyLua-Annotations#types-and-type)\n  types = {\n    '%b()', -- Allow union type\n    '%b[]',\n    '%b{}',\n    'table%b<>',\n    'fun%b():%s*%b()', 'fun%b():%s*%b[]', 'fun%b():%s*%b{}', 'fun%b():%s*table%b<>', 'fun%b():%s*%S+', 'fun%b()',\n    'nil', 'any', 'boolean', 'string', 'number', 'integer', 'function', 'table', 'thread', 'userdata', 'lightuserdata',\n    '%.%.%.',\n    '[%a][%w_%.]*', -- Allow any class as a type\n  },\n}\n--stylua: ignore end\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('annotation_extractor', config.annotation_extractor, 'function')\n  H.check_type('default_section_id', config.default_section_id, 'string')\n  H.check_type('hooks', config.hooks, 'table')\n\n  H.check_type('hooks.block_pre', config.hooks.block_pre, 'function')\n  H.check_type('hooks.section_pre', config.hooks.section_pre, 'function')\n\n  H.check_type('hooks.sections', config.hooks.sections, 'table')\n  H.check_type('hooks.sections.@alias', config.hooks.sections['@alias'], 'function')\n  H.check_type('hooks.sections.@class', config.hooks.sections['@class'], 'function')\n  H.check_type('hooks.sections.@diagnostic', config.hooks.sections['@diagnostic'], 'function')\n  H.check_type('hooks.sections.@eval', config.hooks.sections['@eval'], 'function')\n  H.check_type('hooks.sections.@field', config.hooks.sections['@field'], 'function')\n  H.check_type('hooks.sections.@overload', config.hooks.sections['@overload'], 'function')\n  H.check_type('hooks.sections.@param', config.hooks.sections['@param'], 'function')\n  H.check_type('hooks.sections.@private', config.hooks.sections['@private'], 'function')\n  H.check_type('hooks.sections.@return', config.hooks.sections['@return'], 'function')\n  H.check_type('hooks.sections.@seealso', config.hooks.sections['@seealso'], 'function')\n  H.check_type('hooks.sections.@signature', config.hooks.sections['@signature'], 'function')\n  H.check_type('hooks.sections.@tag', config.hooks.sections['@tag'], 'function')\n  H.check_type('hooks.sections.@text', config.hooks.sections['@text'], 'function')\n  H.check_type('hooks.sections.@toc', config.hooks.sections['@toc'], 'function')\n  H.check_type('hooks.sections.@toc_entry', config.hooks.sections['@toc_entry'], 'function')\n  H.check_type('hooks.sections.@type', config.hooks.sections['@type'], 'function')\n  H.check_type('hooks.sections.@usage', config.hooks.sections['@usage'], 'function')\n\n  H.check_type('hooks.section_post', config.hooks.section_post, 'function')\n  H.check_type('hooks.block_post', config.hooks.block_post, 'function')\n  H.check_type('hooks.file', config.hooks.file, 'function')\n  H.check_type('hooks.doc', config.hooks.doc, 'function')\n  H.check_type('hooks.write_pre', config.hooks.write_pre, 'function')\n  H.check_type('hooks.write_post', config.hooks.write_post, 'function')\n\n  H.check_type('script_path', config.script_path, 'string')\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config) MiniDoc.config = config end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniDoc.config, vim.b.minidoc_config or {}, config or {})\nend\n\n-- Work with project specific script ==========================================\nH.execute_project_script = function(input, output, config)\n  -- Don't process script if there are more than one active `generate` calls\n  if H.generate_is_active then return end\n\n  -- Don't process script if at least one argument is not default\n  if not (input == nil and output == nil and config == nil) then return end\n\n  -- Store information\n  local global_config_cache = vim.deepcopy(MiniDoc.config)\n  local local_config_cache = vim.b.minidoc_config\n\n  -- Pass information to a possible `generate()` call inside script\n  H.generate_is_active = true\n  H.generate_recent_output = nil\n\n  -- Execute script\n  local success = pcall(vim.cmd, 'luafile ' .. H.get_config(config).script_path)\n\n  -- Restore information\n  MiniDoc.config = global_config_cache\n  vim.b.minidoc_config = local_config_cache\n  H.generate_is_active = nil\n\n  return success\nend\n\n-- Default documentation targets ----------------------------------------------\nH.default_input = function()\n  -- Search in current and recursively in other directories for Lua files\n  local res = {}\n  for _, dir in ipairs({ '.', 'lua', 'after', 'colors' }) do\n    local glob = (dir == '.' and '' or '**/') .. '*.lua'\n    local files = vim.fn.globpath(dir, glob, false, true)\n\n    -- Use full paths\n    files = vim.tbl_map(function(x) return vim.fn.fnamemodify(x, ':p') end, files)\n\n    -- Ensure consistent order\n    table.sort(files, function(a, b)\n      local a_dir, b_dir = vim.fn.fnamemodify(a, ':h'), vim.fn.fnamemodify(b, ':h')\n\n      -- Put 'init.lua' first among files from same directory\n      if a_dir == b_dir then\n        local a_basename, b_basename = vim.fn.fnamemodify(a, ':t'), vim.fn.fnamemodify(b, ':t')\n        if a_basename == 'init.lua' then return true end\n        if b_basename == 'init.lua' then return false end\n        return a_basename < b_basename\n      end\n\n      return a_dir < b_dir\n    end)\n    table.insert(res, files)\n  end\n\n  return H.tbl_flatten(res)\nend\n\nH.default_output = function()\n  local cur_dir = vim.fn.fnamemodify(vim.loop.cwd(), ':t:r')\n  return ('doc/%s.txt'):format(cur_dir)\nend\n\n-- Parsing --------------------------------------------------------------------\nH.lines_to_block_arr = function(lines, config)\n  local matched_prev, matched_cur\n\n  local res = {}\n  local block_raw = { annotation = {}, section_id = {}, afterlines = {}, line_begin = 1 }\n\n  for i, l in ipairs(lines) do\n    local from, to, section_id = config.annotation_extractor(l)\n    matched_prev, matched_cur = matched_cur, from ~= nil\n\n    if matched_cur then\n      if not matched_prev then\n        -- Finish current block\n        block_raw.line_end = i - 1\n        table.insert(res, H.raw_block_to_block(block_raw, config))\n\n        -- Start new block\n        block_raw = { annotation = {}, section_id = {}, afterlines = {}, line_begin = i }\n      end\n\n      -- Add annotation line without matched annotation pattern\n      table.insert(block_raw.annotation, ('%s%s'):format(l:sub(0, from - 1), l:sub(to + 1)))\n\n      -- Add section id (it is empty string in case of no section id capture)\n      table.insert(block_raw.section_id, section_id or '')\n    else\n      -- Add afterline\n      table.insert(block_raw.afterlines, l)\n    end\n  end\n  block_raw.line_end = #lines\n  table.insert(res, H.raw_block_to_block(block_raw, config))\n\n  return res\nend\n\n-- Raw block structure is an intermediate step added for convenience. It is\n-- a table with the following keys:\n-- - `annotation` - lines (after removing matched annotation pattern) that were\n--   parsed as annotation.\n-- - `section_id` - array with length equal to `annotation` length with strings\n--   captured as section id. Empty string of no section id was captured.\n-- - Everything else is used as block info (like `afterlines`, etc.).\nH.raw_block_to_block = function(block_raw, config)\n  if #block_raw.annotation == 0 and #block_raw.afterlines == 0 then return nil end\n\n  local block = H.new_struct('block', {\n    afterlines = block_raw.afterlines,\n    line_begin = block_raw.line_begin,\n    line_end = block_raw.line_end,\n  })\n  local block_begin = block.info.line_begin\n\n  -- Parse raw block annotation lines from top to bottom. New section starts\n  -- when section id is detected in that line.\n  local section_cur = H.new_struct('section', { id = config.default_section_id, line_begin = block_begin })\n\n  for i, annotation_line in ipairs(block_raw.annotation) do\n    local id = block_raw.section_id[i]\n    if id ~= '' then\n      -- Finish current section\n      if #section_cur > 0 then\n        section_cur.info.line_end = block_begin + i - 2\n        block:insert(section_cur)\n      end\n\n      -- Start new section\n      section_cur = H.new_struct('section', { id = id, line_begin = block_begin + i - 1 })\n    end\n\n    section_cur:insert(annotation_line)\n  end\n\n  if #section_cur > 0 then\n    section_cur.info.line_end = block_begin + #block_raw.annotation - 1\n    block:insert(section_cur)\n  end\n\n  return block\nend\n\n-- Hooks ----------------------------------------------------------------------\nH.apply_structure_hooks = function(doc, hooks)\n  for _, file in ipairs(doc) do\n    for _, block in ipairs(file) do\n      hooks.block_pre(block)\n\n      for _, section in ipairs(block) do\n        -- NOTE: Section can be empty if previous hook used `clear_lines()` on\n        -- the whole block (like default `@private`).\n        if #section > 0 then\n          hooks.section_pre(section)\n\n          local hook = hooks.sections[section.info.id]\n          if hook ~= nil then hook(section) end\n\n          hooks.section_post(section)\n        end\n      end\n\n      hooks.block_post(block)\n    end\n\n    hooks.file(file)\n  end\n\n  hooks.doc(doc)\nend\n\nH.alias_register = function(s)\n  if #s == 0 then return end\n\n  -- Remove first word (with bits of surrounding whitespace) while capturing it\n  local alias_name\n  s[1] = s[1]:gsub('%s*(%S+) ?', function(x)\n    alias_name = x\n    return ''\n  end, 1)\n  if alias_name == nil then return end\n\n  MiniDoc.current.aliases = MiniDoc.current.aliases or {}\n  MiniDoc.current.aliases[alias_name] = table.concat(s, '\\n')\nend\n\nH.alias_replace = function(s)\n  if MiniDoc.current.aliases == nil then return end\n\n  local s_type = s.info.id\n  local has_special_first_word = s_type == '@param' or s_type == '@field' or s_type == '@class'\n  local has_special_type = s_type == '@tag' or s_type == '@toc_entry'\n  for alias_name, alias_desc in pairs(MiniDoc.current.aliases) do\n    -- Escape special characters. This is done here and not while registering\n    -- alias to allow user to refer to aliases by its original name.\n    local name_escaped = vim.pesc(alias_name)\n    local desc_is_union = alias_desc:find('|') ~= nil\n    for i, _ in ipairs(s) do\n      -- Try to be accurate in which matches to replace. This avoids cases like\n      -- `@alias aaa AAA` with `aaaBBB->AAABBB` replacements or replacing\n      -- inside special places (like parameter/field/tag names, etc.)\n      s[i] = s[i]:gsub('(.?)(' .. name_escaped .. ')(.?)', function(before, match, after)\n        local before_is_empty, after_is_empty = before == '', after == ''\n        local before_is_space, after_is_space = before:find('%s') == 1, after:find('%s') == 1\n        -- Allow match to be preceded/followed by special characters that can\n        -- be used inside EmmyLua/LuaCATS annotations.\n        -- Source: https://luals.github.io/wiki/annotations/#documenting-types\n        local before_is_special, after_is_special = before:find('[|,%[%(<:]') == 1, after:find('[|,%[%])>}%?]') == 1\n\n        local is_fixed_name = i == 1 and has_special_first_word and before_is_empty\n        local before_is_valid = before_is_empty or before_is_space or before_is_special\n        local after_is_valid = after_is_empty or after_is_space or after_is_special\n        local is_valid = before_is_valid and after_is_valid\n        if not is_valid or is_fixed_name or has_special_type then return before .. match .. after end\n\n        local should_enclose = desc_is_union and (before_is_special or after_is_special)\n        return before .. (should_enclose and ('(' .. alias_desc .. ')') or alias_desc) .. after\n      end)\n    end\n  end\nend\n\nH.toc_register = function(s)\n  MiniDoc.current.toc = MiniDoc.current.toc or {}\n  table.insert(MiniDoc.current.toc, s)\nend\n\nH.toc_insert = function(s)\n  if MiniDoc.current.toc == nil then return end\n\n  -- Render table of contents\n  local toc_lines = {}\n  for _, toc_entry in ipairs(MiniDoc.current.toc) do\n    local _, tag_section = toc_entry.parent:has_descendant(\n      function(x) return type(x) == 'table' and x.type == 'section' and x.info.id == '@tag' end\n    )\n    tag_section = tag_section or {}\n\n    local lines = {}\n    for i = 1, math.max(#toc_entry, #tag_section) do\n      local left = toc_entry[i] or ''\n      -- Use tag reference instead of tag enclosure\n      local right = vim.trim((tag_section[i] or ''):gsub('%*', '|'))\n      -- Add helper line of dots in first entry (without new trailing space)\n      local filler = right == '' and '' or ' '\n      if i == 1 then\n        -- Ensure parts are padded for proper conceal\n        filler, left, right = '.', (left:gsub('(%S)$', '%1 ')), (right:gsub('^(%S)', ' %1'))\n      end\n      -- Make padding of 2 spaces at both left and right\n      local n_filler = math.max(74 - H.visual_text_width(left) - H.visual_text_width(right), 3)\n      table.insert(lines, ('  %s%s%s'):format(left, filler:rep(n_filler), right))\n    end\n\n    table.insert(toc_lines, lines)\n\n    -- Don't show `toc_entry` lines in output\n    toc_entry:clear_lines()\n  end\n\n  for _, l in ipairs(H.tbl_flatten(toc_lines)) do\n    s:insert(l)\n  end\nend\n\nH.add_section_heading = function(s, heading)\n  -- Add heading\n  s:insert(1, ('%s ~'):format(heading))\nend\n\nH.mark_optional = function(s)\n  -- Treat question mark at end of first word as \"optional\" indicator. See:\n  -- https://github.com/sumneko/lua-language-server/wiki/EmmyLua-Annotations#optional-params\n  s[1] = s[1]:gsub('^(%s-%S-)%?', '%1 `(optional)`', 1)\nend\n\nH.enclose_var_name = function(s) s[1] = s[1]:gsub('(%S+)', '{%1}', 1) end\n\n---@param init number Start of searching for first \"type-like\" string. It is\n---   needed to not detect type early. Like in `@param a_function function`.\n---@private\nH.enclose_type = function(s, init)\n  if #s == 0 or s.type ~= 'section' then return end\n  init = init or 1\n\n  local type_pattern_set = H.pattern_sets['types']\n  local type_pattern = H.find_pattern_with_first_match(s[1], type_pattern_set, init)\n  if type_pattern == nil then return end\n\n  -- Find range representing type. It can be a match for type pattern (plain,\n  -- array `[]`, or optional `?`), possibly in a union (`|`).\n  local from, to = s[1]:find(type_pattern, init)\n  for _ = 1, s[1]:len() do\n    if s[1]:sub(to + 1, to + 2) == '[]' then to = to + 2 end\n    if s[1]:sub(to + 1, to + 1) == '?' then to = to + 1 end\n\n    local new_to = s[1]:sub(to + 1):match('^%s*|%s*()')\n    if new_to == nil then break end\n    to = to + new_to - 1\n    local next_type_pattern = H.find_pattern_with_first_match(s[1], type_pattern_set, to + 1)\n    if next_type_pattern == nil then break end\n    to = s[1]:match(next_type_pattern .. '()', to + 1) - 1\n  end\n\n  -- Avoid replacing match before `init` and avoid unnecessary () enclosing\n  local avoid_brackets = s[1]:sub(from, to):find('^%b()$') ~= nil\n  local left = avoid_brackets and '`' or '`('\n  local right = avoid_brackets and '`' or ')`'\n\n  s[1] = s[1]:sub(1, from - 1) .. left .. s[1]:sub(from, to) .. right .. s[1]:sub(to + 1)\nend\n\n-- Infer data from afterlines -------------------------------------------------\nH.infer_header = function(b)\n  local has_signature = b:has_descendant(\n    function(x) return type(x) == 'table' and x.type == 'section' and x.info.id == '@signature' end\n  )\n  local has_tag = b:has_descendant(\n    function(x) return type(x) == 'table' and x.type == 'section' and x.info.id == '@tag' end\n  )\n\n  if has_signature and has_tag then return end\n\n  local l_all = table.concat(b.info.afterlines, ' ')\n  local tag, signature\n\n  -- Try function definition\n  local fun_pattern = H.find_pattern_with_first_match(l_all, H.pattern_sets['afterline_fundef'])\n  if fun_pattern ~= nil then\n    local fun_name, fun_args = l_all:match(fun_pattern)\n    tag = tag or (fun_name .. '()')\n    signature = signature or (fun_name .. fun_args)\n  end\n\n  -- Try general assignment\n  local assign_pattern = H.find_pattern_with_first_match(l_all, H.pattern_sets['afterline_assign'])\n  if assign_pattern ~= nil then\n    local obj_name = l_all:match(assign_pattern)\n    tag = tag or obj_name\n    signature = signature or obj_name\n  end\n\n  if tag ~= nil then\n    -- First insert signature (so that it will appear after tag section)\n    if not has_signature then b:insert(1, H.as_struct({ signature }, 'section', { id = '@signature' })) end\n\n    -- Insert tag\n    if not has_tag then b:insert(1, H.as_struct({ tag }, 'section', { id = '@tag' })) end\n  end\nend\n\nH.format_signature = function(line)\n  -- Try capture function signature\n  local name, args = line:match('(%S-)(%b())')\n  -- Otherwise pick first word\n  name = name or line:match('(%S+)')\n\n  if not name then return '' end\n\n  -- Tidy arguments\n  if args and args ~= '()' then\n    local arg_parts = vim.split(args:sub(2, -2), ',')\n    local arg_list = {}\n    for _, a in ipairs(arg_parts) do\n      -- Enclose argument in `{}` while controlling whitespace\n      table.insert(arg_list, ('{%s}'):format(vim.trim(a)))\n    end\n    args = ('(%s)'):format(table.concat(arg_list, ', '))\n  end\n\n  return ('`%s`%s'):format(name, args or '')\nend\n\n-- Work with structures -------------------------------------------------------\n-- Constructor\nH.new_struct = function(struct_type, info)\n  local output = {\n    info = info or {},\n    type = struct_type,\n  }\n\n  output.insert = function(self, index, child)\n    -- Allow both `x:insert(child)` and `x:insert(1, child)`\n    if child == nil then\n      child, index = index, #self + 1\n    end\n\n    if type(child) == 'table' then\n      child.parent = self\n      child.parent_index = index\n    end\n\n    table.insert(self, index, child)\n\n    H.sync_parent_index(self)\n  end\n\n  output.remove = function(self, index)\n    index = index or #self\n    table.remove(self, index)\n\n    H.sync_parent_index(self)\n  end\n\n  output.has_descendant = function(self, predicate)\n    local bool_res, descendant = false, nil\n    H.apply_recursively(function(x)\n      if not bool_res and predicate(x) then\n        bool_res = true\n        descendant = x\n      end\n    end, self)\n    return bool_res, descendant\n  end\n\n  output.has_lines = function(self)\n    return self:has_descendant(function(x) return type(x) == 'string' end)\n  end\n\n  output.clear_lines = function(self)\n    for i, x in ipairs(self) do\n      if type(x) == 'string' then\n        self[i] = nil\n      else\n        x:clear_lines()\n      end\n    end\n  end\n\n  return output\nend\n\nH.sync_parent_index = function(x)\n  for i, _ in ipairs(x) do\n    if type(x[i]) == 'table' then x[i].parent_index = i end\n  end\n  return x\nend\n\n-- Converter (this ensures that children have proper parent-related data)\nH.as_struct = function(array, struct_type, info)\n  -- Make default info `info` for cases when structure is created manually\n  local default_info = ({\n    section = { id = '@text', line_begin = -1, line_end = -1 },\n    block = { afterlines = {}, line_begin = -1, line_end = -1 },\n    file = { path = '' },\n    doc = { input = {}, output = '', config = H.get_config() },\n  })[struct_type]\n  info = vim.tbl_deep_extend('force', default_info, info or {})\n\n  local res = H.new_struct(struct_type, info)\n  for _, x in ipairs(array) do\n    res:insert(x)\n  end\n  return res\nend\n\n-- Work with text -------------------------------------------------------------\nH.ensure_indent = function(text, n_indent_target)\n  local lines = vim.split(text, '\\n')\n  local n_indent, n_indent_cur = math.huge, math.huge\n\n  -- Find number of characters in indent\n  for _, l in ipairs(lines) do\n    -- Update lines indent: minimum of all indents except empty lines\n    if n_indent > 0 then\n      _, n_indent_cur = l:find('^%s*')\n      -- Condition \"current n-indent equals line length\" detects empty line\n      if (n_indent_cur < n_indent) and (n_indent_cur < l:len()) then n_indent = n_indent_cur end\n    end\n  end\n\n  -- Ensure indent\n  local indent = string.rep(' ', n_indent_target)\n  for i, l in ipairs(lines) do\n    if l ~= '' then lines[i] = indent .. l:sub(n_indent + 1) end\n  end\n\n  return table.concat(lines, '\\n')\nend\n\nH.align_text = function(text, width, direction)\n  if type(text) ~= 'string' then return end\n  text = vim.trim(text)\n  width = width or 78\n  direction = direction or 'left'\n\n  -- Don't do anything if aligning left or line is a whitespace\n  if direction == 'left' or text:find('^%s*$') then return text end\n\n  local n_left = math.max(0, 78 - H.visual_text_width(text))\n  if direction == 'center' then n_left = math.floor(0.5 * n_left) end\n\n  return (' '):rep(n_left) .. text\nend\n\nH.visual_text_width = function(text)\n  -- Ignore concealed characters (usually \"invisible\" in 'help' filetype)\n  local _, n_concealed_chars = text:gsub('([*|`])', '%1')\n  return vim.fn.strdisplaywidth(text) - n_concealed_chars\nend\n\nH.find_pattern_with_first_match = function(text, pattern_set, init)\n  local min_start, first_pat = math.huge, nil\n  for _, pat in ipairs(pattern_set) do\n    local from = text:find(pat, init)\n    if from ~= nil and from < min_start then\n      min_start, first_pat = from, pat\n    end\n  end\n  return first_pat\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.doc) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.apply_recursively = function(f, x)\n  f(x)\n\n  if type(x) == 'table' then\n    for _, t in ipairs(x) do\n      H.apply_recursively(f, t)\n    end\n  end\nend\n\nH.collect_strings = function(x)\n  local res = {}\n  H.apply_recursively(function(y)\n    if type(y) == 'string' then\n      -- Allow `\\n` in strings\n      table.insert(res, vim.split(y, '\\n'))\n    end\n  end, x)\n  -- Flatten to only have strings and not table of strings (from `vim.split`)\n  return H.tbl_flatten(res)\nend\n\nH.file_read = function(path)\n  local file = assert(io.open(path))\n  local contents = file:read('*all')\n  file:close()\n\n  return vim.split(contents, '\\n')\nend\n\nH.file_write = function(path, lines)\n  -- Ensure target directory exists\n  local dir = vim.fn.fnamemodify(path, ':h')\n  vim.fn.mkdir(dir, 'p')\n\n  -- Write to file\n  vim.fn.writefile(lines, path, 'b')\nend\n\nH.full_path = function(path) return vim.fn.resolve(vim.fn.fnamemodify(path, ':p')) end\n\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not predicate(v) then return false end\n  end\n  return true\nend\n\nH.is_string = function(x) return type(x) == 'string' end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\nH.tbl_flatten = vim.fn.has('nvim-0.10') == 1 and function(x) return vim.iter(x):flatten(math.huge):totable() end\n  or vim.tbl_flatten\n\nreturn MiniDoc\n"
  },
  {
    "path": "lua/mini/extra.lua",
    "content": "--- *mini.extra* Extra 'mini.nvim' functionality\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Extra useful functionality which is not essential enough for other 'mini.nvim'\n--- modules to include directly.\n---\n--- Features:\n---\n--- - Various pickers for |mini.pick|:\n---     - Built-in diagnostic (|MiniExtra.pickers.diagnostic()|).\n---     - File explorer (|MiniExtra.pickers.explorer()|).\n---     - Git branches/commits/files/hunks (|MiniExtra.pickers.git_hunks()|, etc.).\n---     - Command/search/input history (|MiniExtra.pickers.history()|).\n---     - LSP references/symbols/etc. (|MiniExtra.pickers.lsp()|).\n---     - Tree-sitter nodes (|MiniExtra.pickers.treesitter()|).\n---     - And much more.\n---   See |MiniExtra.pickers| for more.\n---\n--- - Various textobject specifications for |mini.ai|. See |MiniExtra.gen_ai_spec|.\n---\n--- - Various highlighters for |mini.hipatterns|. See |MiniExtra.gen_highlighter|.\n---\n--- Notes:\n--- - This module requires only those 'mini.nvim' modules which are needed for\n---   a particular functionality: 'mini.pick' for pickers, etc.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.extra').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniExtra`\n--- which you can use for scripting or manually (with `:lua MiniExtra.*`).\n---\n--- See |MiniExtra.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.miniextra_config`\n--- will have no effect here.\n---\n--- # Comparisons ~\n---\n--- - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim):\n---     - With |MiniExtra.pickers|, 'mini.pick' is reasonably on par when it comes\n---       to built-in pickers.\n---\n--- - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua):\n---     - Same as 'nvim-telescope/telescope.nvim'.\n---@tag MiniExtra\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n---@alias __extra_ai_spec_return function Function implementing |MiniAi-textobject-specification|.\n---@alias __extra_pickers_local_opts table|nil Options defining behavior of this particular picker.\n---@alias __extra_pickers_opts table|nil Options forwarded to |MiniPick.start()|.\n---@alias __extra_pickers_return any Output of the called picker.\n---@alias __extra_pickers_git_notes Notes:\n--- - Requires executable `git`.\n--- - Requires target path to be part of git repository.\n--- - Present for exploration and navigation purposes. Doing any Git operations\n---   is suggested to be done in a dedicated Git client and is not planned.\n---@alias __extra_pickers_preserve_order - <preserve_order> `(boolean)` - whether to preserve original order\n---     during query. Default: `false`.\n---@alias __extra_pickers_git_path - <path> `(string|nil)` - target path for Git operation (if required). Also\n---     used to find Git repository inside which to construct items.\n---     Default: `nil` for root of Git repository containing |current-directory|.\n\n-- Module definition ==========================================================\nlocal MiniExtra = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniExtra.config|.\n---\n---@usage >lua\n---   require('mini.extra').setup() -- use default config\n---   -- OR\n---   require('mini.extra').setup({}) -- replace {} with your config table\n--- <\nMiniExtra.setup = function(config)\n  -- Export module\n  _G.MiniExtra = MiniExtra\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniExtra.config = {}\n--minidoc_afterlines_end\n\n--- |mini.ai| textobject specification generators\n---\n--- This is a table with function elements. Call to actually get specification.\n---\n--- Assumed to be used as part of |MiniAi.setup()|. Example: >lua\n---\n---   local gen_ai_spec = require('mini.extra').gen_ai_spec\n---   require('mini.ai').setup({\n---     custom_textobjects = {\n---       B = gen_ai_spec.buffer(),\n---       D = gen_ai_spec.diagnostic(),\n---       I = gen_ai_spec.indent(),\n---       L = gen_ai_spec.line(),\n---       N = gen_ai_spec.number(),\n---     },\n---   })\n--- <\nMiniExtra.gen_ai_spec = {}\n\n--- Current buffer textobject\n---\n--- Notes:\n--- - `a` textobject selects all lines in a buffer.\n--- - `i` textobject selects all lines except blank lines at start and end.\n---\n---@return __extra_ai_spec_return\nMiniExtra.gen_ai_spec.buffer = function()\n  return function(ai_type)\n    local start_line, end_line = 1, vim.fn.line('$')\n    if ai_type == 'i' then\n      -- Skip first and last blank lines for `i` textobject\n      local first_nonblank, last_nonblank = vim.fn.nextnonblank(start_line), vim.fn.prevnonblank(end_line)\n      -- Do nothing for buffer with all blanks\n      if first_nonblank == 0 or last_nonblank == 0 then return { from = { line = start_line, col = 1 } } end\n      start_line, end_line = first_nonblank, last_nonblank\n    end\n\n    local to_col = math.max(vim.fn.getline(end_line):len(), 1)\n    return { from = { line = start_line, col = 1 }, to = { line = end_line, col = to_col } }\n  end\nend\n\n--- Current buffer diagnostic textobject\n---\n--- Notes:\n--- - Both `a` and `i` textobjects return |vim.diagnostic.get()| output for the\n---   current buffer. It is modified to fit |MiniAi-textobject-specification|.\n---\n---@param severity any Which severity to use. Forwarded to |vim.diagnostic.get()|.\n---   Default: `nil` to use all diagnostic entries.\n---\n---@return __extra_ai_spec_return\nMiniExtra.gen_ai_spec.diagnostic = function(severity)\n  return function(ai_type)\n    local cur_diag = vim.diagnostic.get(0, { severity = severity })\n\n    local regions = {}\n    for _, diag in ipairs(cur_diag) do\n      local from = { line = diag.lnum + 1, col = diag.col + 1 }\n      local to = { line = diag.end_lnum + 1, col = diag.end_col }\n      if to.line == nil or to.col == nil then to = { line = diag.lnum + 1, col = diag.col + 1 } end\n      table.insert(regions, { from = from, to = to })\n    end\n    return regions\n  end\nend\n\n--- Current buffer indent scopes textobject\n---\n--- Indent scope is a set of consecutive lines with the following properties:\n--- - Lines above first and below last are non-blank. They are called borders.\n--- - There is at least one non-blank line in a set.\n--- - All non-blank lines between borders have strictly greater indent\n---   (perceived leading space respecting |'tabstop'|) than either of borders.\n---\n--- Notes:\n--- - `a` textobject selects scope including borders.\n--- - `i` textobject selects the scope charwise.\n--- - Differences with |MiniIndentscope.textobject()|:\n---     - This textobject always treats blank lines on top and bottom of `i`\n---       textobject as part of it, while 'mini.indentscope' can configure that.\n---     - This textobject can select non-covering scopes, while 'mini.indentscope'\n---       can not (by design).\n---     - In this textobject scope computation is done only by \"casting rays\" from\n---       top to bottom and not in both ways as in 'mini.indentscope'.\n---       This works in most common scenarios and doesn't work only if indent of\n---       of the bottom border is expected to be larger than the top.\n---\n---@return function Function implementing |MiniAi-textobject-specification|.\n---   It returns array of regions representing all indent scopes in the buffer\n---   ordered increasingly by the start line.\nMiniExtra.gen_ai_spec.indent = function() return H.ai_indent_spec end\n\n--- Current line textobject\n---\n--- Notes:\n--- - `a` textobject selects whole line.\n--- - `i` textobject selects line after initial indent.\n---\n---@return __extra_ai_spec_return\nMiniExtra.gen_ai_spec.line = function()\n  return function(ai_type)\n    local line_num = vim.fn.line('.')\n    local line = vim.fn.getline(line_num)\n    -- Ignore indentation for `i` textobject\n    local from_col = ai_type == 'a' and 1 or (line:match('^(%s*)'):len() + 1)\n    -- Don't select `\\n` past the line to operate within a line\n    local to_col = line:len()\n\n    return { from = { line = line_num, col = from_col }, to = { line = line_num, col = to_col } }\n  end\nend\n\n--- Number textobject\n---\n--- Notes:\n--- - `a` textobject selects a whole number possibly preceded with \"-\" and\n---   possibly followed by decimal part (dot and digits).\n--- - `i` textobject selects consecutive digits.\n---\n---@return __extra_ai_spec_return\nMiniExtra.gen_ai_spec.number = function()\n  local digits_pattern = '%f[%d]%d+%f[%D]'\n\n  local find_a_number = function(line, init)\n    -- First find consecutive digits\n    local from, to = line:find(digits_pattern, init)\n    if from == nil then return nil, nil end\n\n    -- Make sure that these digits were not processed before. This can happen\n    -- because 'miin.ai' does next with `init = from + 1`, meaning that\n    -- \"-12.34\" was already matched, then it would try to match starting from\n    -- \"1\": we want to avoid matching that right away and avoid matching \"34\"\n    -- from this number.\n    if from == init and line:sub(from - 1, from - 1) == '-' then\n      init = to + 1\n      from, to = line:find(digits_pattern, init)\n    end\n    if from == nil then return nil, nil end\n\n    if line:sub(from - 2):find('^%d%.') ~= nil then\n      init = to + 1\n      from, to = line:find(digits_pattern, init)\n    end\n    if from == nil then return nil, nil end\n\n    -- Match the whole number with minus and decimal part\n    if line:sub(from - 1, from - 1) == '-' then from = from - 1 end\n    local dec_part = line:sub(to + 1):match('^%.%d+()')\n    if dec_part ~= nil then to = to + dec_part - 1 end\n    return from, to\n  end\n\n  return function(ai_type)\n    if ai_type == 'i' then return { digits_pattern } end\n    return { find_a_number, { '^().*()$' } }\n  end\nend\n\n--- |mini.hipatterns| highlighter generators\n---\n--- This is a table with function elements. Call to actually get specification.\n---\n--- Assumed to be used as part of |MiniHipatterns.setup()|. Example: >lua\n---\n---   local hi_words = require('mini.extra').gen_highlighter.words\n---   require('mini.hipatterns').setup({\n---     highlighters = {\n---       todo = hi_words({ 'TODO', 'Todo', 'todo' }, 'MiniHipatternsTodo'),\n---     },\n---   })\n--- <\nMiniExtra.gen_highlighter = {}\n\n--- Highlight words\n---\n--- Notes:\n--- - Words should start and end with alphanumeric symbol (latin letter or digit).\n--- - Words will be highlighted only in full and not if part bigger word, i.e.\n---   there should not be alphanumeric symbol before and after it.\n---\n---@param words table Array of words to highlight. Will be matched as is, not\n---   as Lua pattern.\n---@param group string|function Proper `group` field for `highlighter`.\n---   See |MiniHipatterns.config|.\n---@param extmark_opts any Proper `extmark_opts` field for `highlighter`.\n---   See |MiniHipatterns.config|.\nMiniExtra.gen_highlighter.words = function(words, group, extmark_opts)\n  if not H.islist(words) then H.error('`words` should be an array.') end\n  if not (type(group) == 'string' or vim.is_callable(group)) then H.error('`group` should be string or callable.') end\n  local pattern = vim.tbl_map(function(x)\n    if type(x) ~= 'string' then H.error('All elements of `words` should be strings.') end\n    return '%f[%w]()' .. vim.pesc(x) .. '()%f[%W]'\n  end, words)\n  return { pattern = pattern, group = group, extmark_opts = extmark_opts }\nend\n\n--- |mini.pick| pickers\n---\n--- A table with 'mini.pick' pickers (which is a hard dependency).\n--- Notes:\n--- - All have the same signature:\n---     - <local_opts> - optional table with options local to picker.\n---     - <opts> - optional table with options forwarded to |MiniPick.start()|.\n--- - All of them are automatically registered in |MiniPick.registry| inside\n---   both |MiniExtra.setup()| or |MiniPick.setup()| (only one is enough).\n--- - All use default versions of |MiniPick-source.preview|, |MiniPick-source.choose|,\n---   and |MiniPick-source.choose_marked| if not stated otherwise.\n---   Shown text and |MiniPick-source.show| are targeted to the picked items.\n---\n--- Examples of usage:\n--- - As Lua code: `MiniExtra.pickers.buf_lines()`.\n--- - With |:Pick| command: `:Pick buf_lines scope='current'`\n---   Note: this requires calling |MiniExtra.setup()|.\nMiniExtra.pickers = {}\n\n--- Buffer lines picker\n---\n--- Pick from buffer lines. Notes:\n--- - Loads all target buffers which are currently unloaded.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - one of \"all\" (normal listed buffers) or \"current\".\n---     Default: \"all\".\n---   __extra_pickers_preserve_order\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.buf_lines = function(local_opts, opts)\n  local pick = H.validate_pick('buf_lines')\n  local_opts = vim.tbl_deep_extend('force', { scope = 'all', preserve_order = false }, local_opts or {})\n\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'current' }, 'buf_lines')\n  local is_scope_all = scope == 'all'\n\n  -- Define non-blocking callable `items` because getting all lines from all\n  -- buffers (plus loading them) may take visibly long time\n  local buffers = {}\n  if is_scope_all then\n    for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n      if vim.bo[buf_id].buflisted and vim.bo[buf_id].buftype == '' then table.insert(buffers, buf_id) end\n    end\n  else\n    buffers = { vim.api.nvim_get_current_buf() }\n  end\n\n  local poke_picker = pick.poke_is_picker_active\n  local f = function()\n    local items = {}\n    for _, buf_id in ipairs(buffers) do\n      if not poke_picker() then return end\n      H.buf_ensure_loaded(buf_id)\n      local buf_name = H.buf_get_name(buf_id) or ''\n      local n_digits = math.floor(math.log10(vim.api.nvim_buf_line_count(buf_id))) + 1\n      local format_pattern = '%s%' .. n_digits .. 'd\\0%s'\n      for lnum, l in ipairs(vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)) do\n        local prefix = is_scope_all and (buf_name .. '\\0') or ''\n        table.insert(items, { text = format_pattern:format(prefix, lnum, l), bufnr = buf_id, lnum = lnum })\n      end\n    end\n    pick.set_picker_items(items)\n  end\n  local items = vim.schedule_wrap(coroutine.wrap(f))\n\n  local show = H.pick_get_config().source.show\n  if is_scope_all and show == nil then show = H.show_with_icons end\n  local match_opts = { preserve_order = local_opts.preserve_order }\n  local match = function(stritems, inds, query) pick.default_match(stritems, inds, query, match_opts) end\n  local default_source = { name = string.format('Buffer lines (%s)', scope), show = show, match = match }\n  return H.pick_start(items, { source = default_source }, opts)\nend\n\n--- Color scheme picker\n---\n--- Pick and apply color scheme. Preview temporarily applies item's color scheme\n--- and shows how selected highlight groups look.\n--- Canceling reverts to color scheme before picker start:\n--- - With |MiniColors-colorscheme:apply()| if |mini.colors| was available.\n--- - With |:colorscheme| if |g:colors_name| was available.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <names> `(table)` - array of color scheme names to pick from.\n---     Default: all available color schemes.\n---   - <preview_hl_groups> `(table)` - array of highlight groups to show in preview\n---     window. Default: all defined highlight groups in alphabetical order.\n---\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.colorschemes = function(local_opts, opts)\n  local pick = H.validate_pick('colorschemes')\n  local_opts = local_opts or {}\n\n  -- Infer data to show\n  local all_cs = vim.fn.getcompletion('', 'color')\n  local items = local_opts.names or all_cs\n  if not H.islist(items) then H.error('`names` should be array of color scheme names') end\n  for _, item in ipairs(items) do\n    if not vim.tbl_contains(all_cs, item) then H.error(vim.inspect(item) .. ' is not a color scheme name') end\n  end\n\n  local hl_groups = local_opts.preview_hl_groups\n  if hl_groups ~= nil and not H.islist(hl_groups) then H.error('`preview_hl_groups` should be array') end\n\n  -- Compute original color scheme to restore\n  local bg_orig = vim.o.background\n  local has_minicolors, minicolors = pcall(require, 'mini.colors')\n  local cs_orig = has_minicolors and minicolors.get_colorscheme() or vim.g.colors_name\n  local restore = function()\n    vim.o.background = bg_orig\n    if cs_orig == nil then return end\n    if type(cs_orig) == 'string' then return vim.cmd('colorscheme ' .. cs_orig) end\n    cs_orig:apply()\n    -- Trigger to indicate actual color scheme application\n    vim.api.nvim_exec_autocmds('ColorScheme', {})\n  end\n\n  -- Define source\n  local choose = function(item) vim.cmd('colorscheme ' .. item) end\n  local choose_marked = function(items_to_mark) choose(items_to_mark[1] or '') end\n\n  local needs_restore = false\n  local preview = function(buf_id, item)\n    needs_restore = true\n    -- Ensure that previewed color scheme tries to use the initial background.\n    -- This can be not the case if previous preview forced new background.\n    vim.o.background = bg_orig\n    vim.cmd('colorscheme ' .. item)\n    H.preview_cs_hl_groups(buf_id, hl_groups)\n  end\n\n  local default_source = { name = 'Colorschemes', preview = preview, choose = choose, choose_marked = choose_marked }\n  local result = H.pick_start(items, { source = default_source }, opts)\n\n  if result == nil and needs_restore then restore() end\n  return result\nend\n\n--- Neovim commands picker\n---\n--- Pick from Neovim built-in (|Ex-commands|) and |user-commands|.\n--- Notes:\n--- - Preview shows information about the command (if available).\n--- - Choosing either executes command (if reliably known that it doesn't need\n---   arguments) or populates Command line with the command.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Not used at the moment.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.commands = function(local_opts, opts)\n  local pick = H.validate_pick('commands')\n\n  local commands = vim.tbl_deep_extend('force', vim.api.nvim_get_commands({}), vim.api.nvim_buf_get_commands(0, {}))\n\n  local preview = function(buf_id, item)\n    local data = commands[item]\n    local lines = data == nil and { string.format('No command data for `%s` is yet available.', item) }\n      or vim.split(vim.inspect(data), '\\n')\n    H.set_buflines(buf_id, lines)\n  end\n\n  local choose = function(item)\n    local data = commands[item] or {}\n    -- If no arguments needed, execute immediately\n    local keys = string.format(':%s%s', item, data.nargs == '0' and '\\r' or ' ')\n    vim.schedule(function() vim.fn.feedkeys(keys) end)\n  end\n\n  local items = vim.fn.getcompletion('', 'command')\n  local default_opts = { source = { name = 'Commands', preview = preview, choose = choose } }\n  return H.pick_start(items, default_opts, opts)\nend\n\n--- Built-in diagnostic picker\n---\n--- Pick from |vim.diagnostic| using |vim.diagnostic.get()|.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <get_opts> `(table)` - options for |vim.diagnostic.get()|. Can be used\n---     to limit severity or namespace. Default: `{}`.\n---   - <scope> `(string)` - one of \"all\" (available) or \"current\" (buffer).\n---     Default: \"all\".\n---   - <sort_by> `(string)` - sort priority. One of \"severity\", \"path\", \"none\".\n---     Default: \"severity\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.diagnostic = function(local_opts, opts)\n  local pick = H.validate_pick('diagnostic')\n  local_opts = vim.tbl_deep_extend('force', { get_opts = {}, scope = 'all', sort_by = 'severity' }, local_opts or {})\n\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'current' }, 'diagnostic')\n  local sort_by = H.pick_validate_one_of('sort_by', local_opts, { 'severity', 'path', 'none' }, 'diagnostic')\n\n  local plus_one = function(x)\n    if x == nil then return nil end\n    return x + 1\n  end\n\n  local diag_buf_id\n  if scope == 'current' then diag_buf_id = vim.api.nvim_get_current_buf() end\n  local items = vim.deepcopy(vim.diagnostic.get(diag_buf_id, local_opts.get_opts))\n\n  -- Compute final path width\n  local path_width = 0\n  for _, item in ipairs(items) do\n    item.path = H.buf_get_name(item.bufnr) or ''\n    item.severity = item.severity or 0\n    path_width = math.max(path_width, vim.fn.strchars(item.path))\n  end\n\n  -- Sort\n  local compare = H.diagnostic_make_compare(sort_by)\n  if vim.is_callable(compare) then table.sort(items, compare) end\n\n  -- Update items\n  for _, item in ipairs(items) do\n    local severity = vim.diagnostic.severity[item.severity] or ' '\n    local text = item.message:gsub('\\n', ' ')\n    item.text = string.format('%s │ %s │ %s', severity:sub(1, 1), H.ensure_text_width(item.path, path_width), text)\n    item.lnum, item.col, item.end_lnum, item.end_col =\n      plus_one(item.lnum), plus_one(item.col), plus_one(item.end_lnum), plus_one(item.end_col)\n  end\n\n  local hl_groups_ref = {\n    [vim.diagnostic.severity.ERROR] = 'DiagnosticFloatingError',\n    [vim.diagnostic.severity.WARN] = 'DiagnosticFloatingWarn',\n    [vim.diagnostic.severity.INFO] = 'DiagnosticFloatingInfo',\n    [vim.diagnostic.severity.HINT] = 'DiagnosticFloatingHint',\n  }\n\n  -- Define source\n  local show = function(buf_id, items_to_show, query)\n    pick.default_show(buf_id, items_to_show, query)\n\n    H.pick_clear_namespace(buf_id, H.ns_id.pickers)\n    for i, item in ipairs(items_to_show) do\n      H.pick_highlight_line(buf_id, i, hl_groups_ref[item.severity], 199)\n    end\n  end\n\n  local name = string.format('Diagnostic (%s)', scope)\n  return H.pick_start(items, { source = { name = name, choose = H.choose_with_buflisted, show = show } }, opts)\nend\n\n--- File explorer picker\n---\n--- Explore file system and open file.\n--- Notes:\n--- - Choosing a directory navigates inside it, changing picker's items and\n---   current working directory.\n--- - Query and preview work as usual (not only `move_next`/`move_prev` can be used).\n--- - Preview works for any item.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.explorer()`\n--- - `:Pick explorer cwd='..'` - open explorer in parent directory.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <cwd> `(string)` - initial directory to explore. Should be a valid\n---     directory path. Default: `nil` for |current-directory|.\n---   - <filter> `(function)` - callable predicate to filter items to show.\n---     Will be called for every item and should return `true` if it should be\n---     shown. Each item is a table with the following fields:\n---       - <fs_type> `(string)` - path type. One of \"directory\" or \"file\".\n---       - <path> `(string)` - item path.\n---       - <text> `(string)` - shown text (path's basename).\n---   - <sort> `(function)` - callable item sorter. Will be called with array\n---     of items (each element with structure as described above) and should\n---     return sorted array of items.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.explorer = function(local_opts, opts)\n  local pick = H.validate_pick('explorer')\n\n  local_opts = vim.tbl_deep_extend('force', { cwd = nil, filter = nil, sort = nil }, local_opts or {})\n  local cwd = local_opts.cwd or vim.fn.getcwd()\n  if vim.fn.isdirectory(cwd) == 0 then H.error('`local_opts.cwd` should be valid directory path.') end\n  -- - Call twice \"full path\" to make sure that possible '..' are collapsed\n  cwd = H.full_path(vim.fn.fnamemodify(cwd, ':p'))\n  local filter = local_opts.filter or function() return true end\n  if not vim.is_callable(filter) then H.error('`local_opts.filter` should be callable.') end\n  local sort = local_opts.sort or H.explorer_default_sort\n  if not vim.is_callable(sort) then H.error('`local_opts.sort` should be callable.') end\n\n  -- Define source\n  local choose = function(item)\n    local path = item.path\n    if vim.fn.filereadable(path) == 1 then return pick.default_choose(path) end\n    if vim.fn.isdirectory(path) == 0 then return false end\n\n    pick.set_picker_items(H.explorer_make_items(path, filter, sort))\n    pick.set_picker_opts({ source = { cwd = path } })\n    pick.set_picker_query({})\n    return true\n  end\n\n  local show = H.pick_get_config().source.show or H.show_with_icons\n\n  local items = H.explorer_make_items(cwd, filter, sort)\n  local source = { items = items, name = 'File explorer', cwd = cwd, show = show, choose = choose }\n  opts = vim.tbl_deep_extend('force', { source = source }, opts or {})\n  return pick.start(opts)\nend\n\n--- Git branches picker\n---\n--- Pick from Git branches using `git branch`.\n--- __extra_pickers_git_notes\n--- - On choose opens scratch buffer with branch's history.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.git_branches({ scope = 'local' })` - local branches of\n---   the |current-directory| parent Git repository.\n--- - `:Pick git_branches path='%'` - all branches of the current file parent\n---   Git repository.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   __extra_pickers_git_path\n---   - <scope> `(string)` - branch scope to show. One of \"all\", \"local\", \"remotes\".\n---     Default: \"all\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.git_branches = function(local_opts, opts)\n  local pick = H.validate_pick('git_branches')\n  H.validate_git('git_branches')\n\n  local_opts = vim.tbl_deep_extend('force', { path = nil, scope = 'all' }, local_opts or {})\n\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'local', 'remotes' }, 'git_branches')\n\n  -- Compute path to repo with target path (as it might differ from current)\n  local path, path_type = H.git_normalize_path(local_opts.path, 'git_branches')\n  local repo_dir = H.git_get_repo_dir(path, path_type, 'git_branches')\n\n  -- Define source\n  local preview = function(buf_id, item)\n    local branch = item:match('^%*?%s*(%S+)')\n    H.cli_show_output(buf_id, { 'git', '-C', repo_dir, 'log', branch, '--format=format:%h %s' })\n  end\n  local choose = function(item)\n    local win_target = (pick.get_picker_state().windows or {}).target\n    if win_target == nil or not H.is_valid_win(win_target) then return end\n    local buf_id = vim.api.nvim_create_buf(true, true)\n    H.set_buf_name(buf_id, item:match('^%*?%s*(%S+)'))\n    preview(buf_id, item)\n    vim.api.nvim_win_set_buf(win_target, buf_id)\n  end\n\n  local command = { 'git', 'branch', '-v', '--no-color', '--list' }\n  if scope == 'all' or scope == 'remotes' then table.insert(command, 3, '--' .. scope) end\n\n  local name = string.format('Git branches (%s)', scope)\n  local default_source = { name = name, cwd = repo_dir, preview = preview, choose = choose }\n  opts = vim.tbl_deep_extend('force', { source = default_source }, opts or {})\n  return pick.builtin.cli({ command = command }, opts)\nend\n\n--- Git commits picker\n---\n--- Pick from Git commits using `git log`.\n--- __extra_pickers_git_notes\n--- - On choose opens scratch buffer with commit's diff.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.git_commits()` - all commits from parent Git\n---   repository of |current-directory|.\n--- - `MiniExtra.pickers.git_commits({ path = 'subdir' })` - commits affecting\n---   files from 'subdir' subdirectory.\n--- - `:Pick git_commits path='%'` commits affecting current file.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   __extra_pickers_git_path\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.git_commits = function(local_opts, opts)\n  local pick = H.validate_pick('git_commits')\n  H.validate_git('git_commits')\n\n  local_opts = vim.tbl_deep_extend('force', { path = nil }, local_opts or {})\n\n  -- Compute path to repo with target path (as it might differ from current)\n  local path, path_type = H.git_normalize_path(local_opts.path, 'git_commits')\n  local repo_dir = H.git_get_repo_dir(path, path_type, 'git_commits')\n  if local_opts.path == nil then path = repo_dir end\n\n  -- Define source\n  local preview = function(buf_id, item)\n    if type(item) ~= 'string' then return end\n    local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, 'git', { error = false })\n    has_parser = has_parser and parser ~= nil\n    if has_parser then has_parser = pcall(vim.treesitter.start, buf_id, 'git') end\n    if not has_parser then vim.bo[buf_id].syntax = 'git' end\n    H.cli_show_output(buf_id, { 'git', '-C', repo_dir, '--no-pager', 'show', item:match('^(%S+)') })\n  end\n  local choose = function(item)\n    local win_target = (pick.get_picker_state().windows or {}).target\n    if win_target == nil or not H.is_valid_win(win_target) then return end\n    local buf_id = vim.api.nvim_create_buf(true, true)\n    H.set_buf_name(buf_id, item:match('^(%S+)'))\n    preview(buf_id, item)\n    -- Set filetype on opened buffer to trigger appropriate `FileType` event\n    vim.bo[buf_id].filetype = 'git'\n    vim.api.nvim_win_set_buf(win_target, buf_id)\n  end\n\n  local command = { 'git', 'log', [[--format=format:%h %s]], '--', path }\n\n  local name = string.format('Git commits (%s)', local_opts.path == nil and 'all' or 'for path')\n  local default_source = { name = name, cwd = repo_dir, preview = preview, choose = choose }\n  opts = vim.tbl_deep_extend('force', { source = default_source }, opts or {})\n  return pick.builtin.cli({ command = command }, opts)\nend\n\n--- Git files picker\n---\n--- Pick from Git files using `git ls-files`.\n--- __extra_pickers_git_notes\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.git_files({ scope = 'ignored' })` - ignored files from\n---   parent Git repository of |current-directory|.\n--- - `:Pick git_files path='subdir' scope='modified'` - files from 'subdir'\n---   subdirectory which are ignored by Git.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   __extra_pickers_git_path\n---   - <scope> `(string)` - files scope to show. One of\n---       - \"tracked\"   (`--cached`   Git flag).\n---       - \"modified\"  (`--modified` Git flag).\n---       - \"untracked\" (`--others`   Git flag).\n---       - \"ignored\"   (`--ignored`  Git flag).\n---       - \"deleted\"   (`--deleted`  Git flag).\n---     Default: \"tracked\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.git_files = function(local_opts, opts)\n  local pick = H.validate_pick('git_files')\n  H.validate_git('git_files')\n\n  local_opts = vim.tbl_deep_extend('force', { path = nil, scope = 'tracked' }, local_opts or {})\n  local allowed_scope = { 'tracked', 'modified', 'untracked', 'ignored', 'deleted' }\n  local scope = H.pick_validate_scope(local_opts, allowed_scope, 'git_files')\n\n  -- Compute path to repo with target path (as it might differ from current)\n  local path, path_type = H.git_normalize_path(local_opts.path, 'git_files')\n  local repo_dir = H.git_get_repo_dir(path, path_type, 'git_files')\n  if local_opts.path == nil then path = repo_dir end\n  local path_dir = path_type == 'directory' and path or vim.fn.fnamemodify(path, ':h')\n\n  -- Define source\n  local show = H.pick_get_config().source.show or H.show_with_icons\n\n  local args = ({\n    tracked = { '--cached' },\n    modified = { '--modified' },\n    untracked = { '--others' },\n    ignored = { '--others', '--ignored', '--exclude-standard' },\n    deleted = { '--deleted' },\n  })[local_opts.scope]\n  local command = vim.list_extend({ 'git', '-C', path_dir, '-c', 'core.quotepath=false', 'ls-files' }, args)\n\n  local name = string.format('Git files (%s)', local_opts.scope)\n  local default_source = { name = name, cwd = path_dir, show = show }\n  opts = vim.tbl_deep_extend('force', { source = default_source }, opts or {})\n  return pick.builtin.cli({ command = command }, opts)\nend\n\n--- Git hunks picker\n---\n--- Pick from Git hunks using `git diff`.\n--- __extra_pickers_git_notes\n--- - On choose navigates to hunk's first change.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.git_hunks({ scope = 'staged' })` - staged hunks from\n---   parent Git repository of |current-directory|.\n--- - `:Pick git_hunks path='%' n_context=0` - hunks from current file computed\n---   with no context.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <n_context> `(number)` - number of context lines to show in hunk's preview.\n---     Default: 3.\n---   __extra_pickers_git_path\n---   - <scope> `(string)` - hunks scope to show. One of \"unstaged\" or \"staged\".\n---     Default: \"unstaged\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.git_hunks = function(local_opts, opts)\n  local pick = H.validate_pick('git_hunks')\n  H.validate_git('git_hunks')\n\n  local default_local_opts = { n_context = 3, path = nil, scope = 'unstaged' }\n  local_opts = vim.tbl_deep_extend('force', default_local_opts, local_opts or {})\n\n  if not (type(local_opts.n_context) == 'number' and local_opts.n_context >= 0) then\n    H.error('`n_context` option in `pickers.git_hunks` picker should be non-negative number.')\n  end\n  local n_context = math.floor(local_opts.n_context)\n  local scope = H.pick_validate_scope(local_opts, { 'unstaged', 'staged' }, 'git_hunks')\n\n  -- Compute path to repo with target path (as it might differ from current)\n  local path, path_type = H.git_normalize_path(local_opts.path, 'git_hunks')\n  local repo_dir = H.git_get_repo_dir(path, path_type, 'git_hunks')\n  if local_opts.path == nil then path = repo_dir end\n\n  -- Define source\n  local show = H.pick_get_config().source.show or H.show_with_icons\n  local preview = function(buf_id, item)\n    local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, 'diff', { error = false })\n    has_parser = has_parser and parser ~= nil\n    if has_parser then has_parser = pcall(vim.treesitter.start, buf_id, 'diff') end\n    if not has_parser then vim.bo[buf_id].syntax = 'diff' end\n    local lines = vim.deepcopy(item.header)\n    vim.list_extend(lines, item.hunk)\n    H.set_buflines(buf_id, lines)\n  end\n\n  local command = { 'git', 'diff', '--patch', '--unified=' .. n_context, '--color=never', '--', path }\n  if scope == 'staged' then table.insert(command, 4, '--cached') end\n\n  local postprocess = function(lines) return H.git_difflines_to_hunkitems(lines, n_context) end\n\n  local name = string.format('Git hunks (%s %s)', scope, local_opts.path == nil and 'all' or 'for path')\n  local default_source = { name = name, cwd = repo_dir, show = show, preview = preview }\n  opts = vim.tbl_deep_extend('force', { source = default_source }, opts or {})\n  return pick.builtin.cli({ command = command, postprocess = postprocess }, opts)\nend\n\n--- Matches from 'mini.hipatterns' picker\n---\n--- Pick from |mini.hipatterns| matches using |MiniHipatterns.get_matches()|.\n--- Notes:\n--- - Requires 'mini.hipatterns'.\n--- - Highlighter identifier is highlighted with its highlight group.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - one of \"all\" (buffers with enabled 'mini.hipatterns')\n---     or \"current\" (buffer). Default: \"all\".\n---   - <highlighters> `(table|nil)` - highlighters for which to find matches.\n---     Forwarded to |MiniHipatterns.get_matches()|. Default: `nil`.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.hipatterns = function(local_opts, opts)\n  local pick = H.validate_pick('hipatterns')\n  local has_hipatterns, hipatterns = pcall(require, 'mini.hipatterns')\n  if not has_hipatterns then H.error([[`pickers.hipatterns` requires 'mini.hipatterns' which can not be found.]]) end\n\n  local_opts = vim.tbl_deep_extend('force', { highlighters = nil, scope = 'all' }, local_opts or {})\n  if local_opts.highlighters ~= nil and not H.islist(local_opts.highlighters) then\n    H.error('`local_opts.highlighters` should be an array of highlighter identifiers.')\n  end\n  local highlighters = local_opts.highlighters\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'current' }, 'hipatterns')\n\n  -- Get items\n  local buffers = scope == 'all' and hipatterns.get_enabled_buffers() or { vim.api.nvim_get_current_buf() }\n  local items, highlighter_width = {}, 0\n  for _, buf_id in ipairs(buffers) do\n    local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)\n    local buf_name = H.buf_get_name(buf_id)\n    if buf_name == '' then buf_name = 'Buffer_' .. buf_id end\n\n    for _, match in ipairs(hipatterns.get_matches(buf_id, highlighters)) do\n      match.highlighter = tostring(match.highlighter)\n      match.buf_name, match.line = buf_name, lines[match.lnum]\n      table.insert(items, match)\n      highlighter_width = math.max(highlighter_width, vim.fn.strchars(match.highlighter))\n    end\n  end\n\n  for _, item in ipairs(items) do\n    --stylua: ignore\n    item.text = string.format(\n      '%s │ %s│%d│%d│%s',\n      H.ensure_text_width(item.highlighter, highlighter_width),\n      item.buf_name, item.lnum, item.col, item.line\n    )\n    item.buf_name, item.line = nil, nil\n  end\n\n  local show = function(buf_id, items_to_show, query)\n    pick.default_show(buf_id, items_to_show, query)\n\n    H.pick_clear_namespace(buf_id, H.ns_id.pickers)\n    for i, item in ipairs(items_to_show) do\n      local end_col = string.len(item.highlighter)\n      local extmark_opts = { hl_group = item.hl_group, end_row = i - 1, end_col = end_col, priority = 1 }\n      vim.api.nvim_buf_set_extmark(buf_id, H.ns_id.pickers, i - 1, 0, extmark_opts)\n    end\n  end\n\n  local name = string.format('Mini.hipatterns matches (%s)', scope)\n  return H.pick_start(items, { source = { name = name, show = show } }, opts)\nend\n\n--- Neovim history picker\n---\n--- Pick from output of |:history|. Use `<C-e>` to edit current match in\n--- Command line.\n---\n--- Notes:\n--- - Has no preview.\n--- - Choosing action depends on scope:\n---     - For \"cmd\" / \":\" scopes, the command is executed.\n---     - For \"search\" / \"/\" / \"?\" scopes, search is redone.\n---     - For other scopes nothing is done (but chosen item is still returned).\n--- - `<C-e>` only works for \"cmd\" / \":\" / \"search\" / \"/\" / \"?\" scopes.\n---\n--- Examples:\n---\n--- - Command history: `MiniExtra.pickers.history({ scope = ':' })`\n--- - Search history: `:Pick history scope='/'`\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - any allowed {name} flag of |:history| command.\n---     Note: word abbreviations are not allowed. Default: \"all\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.history = function(local_opts, opts)\n  local pick = H.validate_pick('history')\n  local_opts = vim.tbl_deep_extend('force', { scope = 'all' }, local_opts or {})\n\n  local allowed_scope = { 'all', 'cmd', 'search', 'expr', 'input', 'debug', ':', '/', '?', '=', '@', '>' }\n  local scope = H.pick_validate_scope(local_opts, allowed_scope, 'history')\n\n  --stylua: ignore\n  local type_ids = {\n    cmd = ':',   search = '/', expr  = '=', input = '@', debug = '>',\n    [':'] = ':', ['/']  = '/', ['='] = '=', ['@'] = '@', ['>'] = '>',\n    ['?'] = '?',\n  }\n\n  -- Construct items\n  local items = {}\n  local names = scope == 'all' and { 'cmd', 'search', 'expr', 'input', 'debug' } or { scope }\n  for _, cur_name in ipairs(names) do\n    local id = type_ids[cur_name]\n    for i = 1, vim.fn.histnr(cur_name) do\n      local hist_entry = vim.fn.histget(cur_name, -i)\n      if hist_entry == '' then break end\n      table.insert(items, string.format('%s %s', id, hist_entry))\n    end\n  end\n\n  -- Define source\n  local preview = H.pick_make_no_preview('history')\n\n  local choose = function(item)\n    if not (type(item) == 'string' and vim.fn.mode() == 'n') then return end\n    local id, entry = item:match('^(.) (.*)$')\n    if id == ':' or id == '/' or id == '?' then\n      vim.schedule(function() vim.fn.feedkeys(id .. entry .. '\\r', 'nxt') end)\n    end\n  end\n\n  local edit_command = function()\n    local cur_match = MiniPick.get_picker_matches().current\n    local cur_scope, cur_item = cur_match:match('^(.) (.*)$')\n    if not (cur_scope == ':' or cur_scope == '/' or cur_scope == '?') then return end\n    vim.schedule(function() vim.api.nvim_input(cur_scope .. cur_item) end)\n    return true\n  end\n  local mappings = { edit_command = { char = '<C-e>', func = edit_command } }\n\n  opts = vim.tbl_deep_extend('force', opts or {}, { mappings = mappings })\n  local default_source = { name = string.format('History (%s)', scope), preview = preview, choose = choose }\n  return H.pick_start(items, { source = default_source }, opts)\nend\n\n--- Highlight groups picker\n---\n--- Pick and preview highlight groups.\n--- Notes:\n--- - Item line is colored with same highlight group it represents.\n--- - Preview shows highlight's definition (as in |:highlight| with {group-name}).\n--- - Choosing places highlight definition in Command line to update and apply.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Not used at the moment.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.hl_groups = function(local_opts, opts)\n  local pick = H.validate_pick('hl_groups')\n\n  -- Construct items\n  local group_data = vim.split(vim.api.nvim_exec('highlight', true), '\\n')\n  local items = {}\n  for _, l in ipairs(group_data) do\n    local group = l:match('^(%S+)')\n    if group ~= nil then table.insert(items, group) end\n  end\n\n  local show = function(buf_id, items_to_show, query)\n    H.set_buflines(buf_id, items_to_show)\n    H.pick_clear_namespace(buf_id, H.ns_id.pickers)\n    -- Highlight line with highlight group of its item\n    for i = 1, #items_to_show do\n      H.pick_highlight_line(buf_id, i, items_to_show[i], 300)\n    end\n  end\n\n  -- Define source\n  local preview = function(buf_id, item)\n    local lines = vim.split(vim.api.nvim_exec('hi ' .. item, true), '\\n')\n    H.set_buflines(buf_id, lines)\n  end\n\n  local choose = function(item)\n    local hl_def = vim.split(vim.api.nvim_exec('hi ' .. item, true), '\\n')[1]\n    hl_def = hl_def:gsub('^(%S+)%s+xxx%s+', '%1 ')\n    vim.schedule(function() vim.fn.feedkeys(':hi ' .. hl_def, 'n') end)\n  end\n\n  local default_source = { name = 'Highlight groups', show = show, preview = preview, choose = choose }\n  return H.pick_start(items, { source = default_source }, opts)\nend\n\n--- Neovim keymaps picker\n---\n--- Pick and preview data about Neovim keymaps.\n--- Notes:\n--- - Item line contains data about keymap mode, whether it is buffer local, its\n---   left hand side, and inferred description.\n--- - Preview shows keymap data or callback source (if present and reachable).\n--- - Choosing emulates pressing the left hand side of the keymap.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <mode> `(string)` - modes to show. One of \"all\" or appropriate mode\n---     for |nvim_set_keymap()|. Default: \"all\".\n---   - <scope> `(string)` - scope to show. One of \"all\", \"global\", \"buf\".\n---     Default: \"all\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.keymaps = function(local_opts, opts)\n  local pick = H.validate_pick('keymaps')\n  local_opts = vim.tbl_deep_extend('force', { mode = 'all', scope = 'all' }, local_opts or {})\n\n  local mode = H.pick_validate_one_of('mode', local_opts, { 'all', 'n', 'x', 's', 'o', 'i', 'l', 'c', 't' }, 'keymaps')\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'global', 'buf' }, 'keymaps')\n\n  -- Create items\n  local items = {}\n  local populate_modes = mode == 'all' and { 'n', 'x', 's', 'o', 'i', 'l', 'c', 't' } or { mode }\n  local max_lhs_width = 0\n  local populate_items = function(source)\n    for _, m in ipairs(populate_modes) do\n      for _, maparg in ipairs(source(m)) do\n        local desc = maparg.desc ~= nil and vim.inspect(maparg.desc) or maparg.rhs\n        local lhs = vim.fn.keytrans(maparg.lhsraw or maparg.lhs)\n        max_lhs_width = math.max(vim.fn.strchars(lhs), max_lhs_width)\n        table.insert(items, { lhs = lhs, desc = desc, maparg = maparg })\n      end\n    end\n  end\n\n  if scope == 'all' or scope == 'buf' then populate_items(function(m) return vim.api.nvim_buf_get_keymap(0, m) end) end\n  if scope == 'all' or scope == 'global' then populate_items(vim.api.nvim_get_keymap) end\n\n  for _, item in ipairs(items) do\n    local buf_map_indicator = item.maparg.buffer == 0 and ' ' or '@'\n    local lhs_text = H.ensure_text_width(item.lhs, max_lhs_width)\n    item.text = string.format('%s %s │ %s │ %s', item.maparg.mode, buf_map_indicator, lhs_text, item.desc or '')\n  end\n\n  -- Define source\n  local get_callback_pos = function(maparg)\n    if type(maparg.callback) ~= 'function' then return nil, nil end\n    local info = debug.getinfo(maparg.callback)\n    local path = info.source:gsub('^@', '')\n    if vim.fn.filereadable(path) == 0 then return nil, nil end\n    return path, info.linedefined\n  end\n\n  local preview = function(buf_id, item)\n    local path, lnum = get_callback_pos(item.maparg)\n    if path ~= nil then\n      item.path, item.lnum = path, lnum\n      return pick.default_preview(buf_id, item)\n    end\n    local lines = vim.split(vim.inspect(item.maparg), '\\n')\n    H.set_buflines(buf_id, lines)\n  end\n\n  local choose = function(item)\n    local keys = vim.api.nvim_replace_termcodes(item.maparg.lhs, true, true, true)\n    -- Restore Visual mode (should be active previously at least once)\n    if item.maparg.mode == 'x' then keys = 'gv' .. keys end\n    vim.schedule(function() vim.api.nvim_input(keys) end)\n  end\n\n  local default_opts = { source = { name = string.format('Keymaps (%s)', scope), preview = preview, choose = choose } }\n  return H.pick_start(items, default_opts, opts)\nend\n\n--- Neovim lists picker\n---\n--- Pick and navigate to elements of the following Neovim lists:\n--- - |quickfix| list.\n--- - |location-list| of current window.\n--- - |jumplist|.\n--- - |changelist|.\n---\n--- Note: it requires explicit `scope`.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.list({ scope = 'quickfix' })` - quickfix list.\n--- - `:Pick list scope='jump'` - jump list.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - type of list to show. One of \"quickfix\", \"location\",\n---     \"jump\", \"change\". Default: `nil` which means explicit scope is needed.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.list = function(local_opts, opts)\n  local pick = H.validate_pick('list')\n  local_opts = vim.tbl_deep_extend('force', { scope = nil }, local_opts or {})\n\n  if local_opts.scope == nil then H.error('`pickers.list` needs an explicit scope.') end\n  local allowed_scopes = { 'quickfix', 'location', 'jump', 'change' }\n  local scope = H.pick_validate_scope(local_opts, allowed_scopes, 'list')\n\n  local has_items, items = pcall(H.list_get[scope])\n  if not has_items then items = {} end\n\n  items = vim.tbl_filter(function(x) return H.is_valid_buf(x.bufnr) end, items)\n  items = vim.tbl_map(H.list_enhance_item, items)\n\n  local name = string.format('List (%s)', scope)\n  local show = H.pick_get_config().source.show or H.show_with_icons\n  return H.pick_start(items, { source = { name = name, show = show, choose = H.choose_with_buflisted } }, opts)\nend\n\n--- LSP picker\n---\n--- Pick and navigate with LSP methods.\n--- Notes:\n--- - Needs an explicit scope from a list of supported ones:\n---     - \"declaration\".\n---     - \"definition\".\n---     - \"document_symbol\".\n---     - \"implementation\".\n---     - \"references\".\n---     - \"type_definition\".\n---     - \"workspace_symbol\".\n---     - \"workspace_symbol_live\" - same as \"workspace_symbol\", but with live\n---       feedback treating picker's prompt as LSP server query. Similar to\n---       how |MiniPick.builtin.grep_live()| and |MiniPick.builtin.grep()| are\n---       related. To use regular matching, activate |MiniPick-actions-refine|.\n--- - Relies on `vim.lsp.buf` methods supporting |vim.lsp.LocationOpts.OnList|.\n---   In particular, it means that picker is started only if LSP server returns\n---   list of locations and not a single location.\n--- - Doesn't return anything due to async nature of `vim.lsp.buf` methods.\n--- - Requires set up |mini.icons| to show extra icons and highlighting in\n---   \"document_symbol\", \"workspace_symbol\", \"workspace_symbol_live\" scopes.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.lsp({ scope = 'references' })` - references of the symbol\n---   under cursor.\n--- - `:Pick lsp scope='document_symbol'` - symbols in current file.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - LSP method to use. One of the supported ones (see\n---     list above). Default: `nil` which means explicit scope is needed.\n---   - <symbol_query> `(string)` - query for `\"workspace_symbol\"` scope.\n---     Default: empty string for all symbols (according to LSP specification).\n---@param opts __extra_pickers_opts\n---\n---@return nil Nothing is returned.\nMiniExtra.pickers.lsp = function(local_opts, opts)\n  local pick = H.validate_pick('lsp')\n  local_opts = vim.tbl_deep_extend('force', { scope = nil, symbol_query = '' }, local_opts or {})\n\n  if local_opts.scope == nil then H.error('`pickers.lsp` needs an explicit scope.') end\n  --stylua: ignore\n  local allowed_scopes = {\n    'declaration', 'definition',      'document_symbol',  'implementation',\n    'references',  'type_definition', 'workspace_symbol', 'workspace_symbol_live'\n  }\n  local scope = H.pick_validate_scope(local_opts, allowed_scopes, 'lsp')\n\n  local buf_lsp_opts, picker_opts = H.lsp_make_opts(scope, opts)\n  if scope == 'references' then return vim.lsp.buf[scope](nil, buf_lsp_opts) end\n  if scope == 'workspace_symbol' then\n    local query = tostring(local_opts.symbol_query)\n    return vim.lsp.buf[scope](query, buf_lsp_opts)\n  end\n  if scope == 'workspace_symbol_live' then\n    picker_opts.source.match = function(_, _, query)\n      if #query == 0 then return MiniPick.set_picker_items({}, { do_match = false }) end\n      local win_id = MiniPick.get_picker_state().windows.target\n      local buf_id = vim.api.nvim_win_get_buf(win_id)\n      vim.api.nvim_buf_call(buf_id, function() vim.lsp.buf.workspace_symbol(table.concat(query), buf_lsp_opts) end)\n    end\n\n    return H.pick_start({}, picker_opts, opts)\n  end\n  vim.lsp.buf[scope](buf_lsp_opts)\nend\n\n--- Manual pages\n---\n--- Pick manual page (like described in |ft-man-plugin|).\n--- Notes:\n--- - Depends on |:Man| command to preview and choose items.\n--- - Shows page in the target window. Use |MiniPick-actions-choose| to split.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Not used at the moment.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.manpages = function(local_opts, opts)\n  local pick = H.validate_pick('manpages')\n  if vim.fn.exists(':Man') ~= 2 then H.error('`manpages` picker needs `:Man` command') end\n\n  local latest_man_buf_id\n  local show_man = function(win_id, item, is_preview)\n    -- table.insert(_G.log, { item, name, section })\n    local name, section = (item or ''):match('^(.-)%s-%((.-)%)')\n    if name == nil or section == nil then return end\n    -- - Use first command\n    name = name:gsub(',.*$', '')\n    -- - Extract first valid section. NOTE: using only digits is not enough\n    --   (for example, `man 1 man` and `man 1p man` are different).\n    section = section:match('%w+') or ''\n\n    -- Show man page directly in the target window\n    vim.api.nvim_win_call(win_id, function() vim.cmd('hide Man ' .. section .. ' ' .. name) end)\n\n    -- Ensure proper choose. Possibly undo `buflisted=false` from preview.\n    if not is_preview then\n      vim.bo.buflisted = true\n      return\n    end\n\n    -- Ensure proper preview buffer\n    vim.bo.buflisted, vim.bo.bufhidden, vim.bo.matchpairs = false, 'wipe', ''\n    vim.b.minicursorword_disable = true\n    vim.b.miniindentscope_disable = true\n    -- - Modify after `:Man` to not have \"Buffer with this name already exists\"\n    vim.api.nvim_buf_set_name(0, 'minipick://' .. vim.api.nvim_get_current_buf() .. '/preview')\n  end\n\n  local preview = function(buf_id, item) show_man(vim.fn.win_findbuf(buf_id)[1], item, true) end\n  local choose = function(item) show_man(MiniPick.get_picker_state().windows.target, item) end\n\n  -- Set necessary environment variables for `vim.loop.spawn` (as it doesn't\n  -- inherit environment variables)\n  local env = { 'MANWIDTH=999' }\n  table.insert(env, vim.env.PATH ~= nil and ('PATH=' .. vim.env.PATH) or nil)\n  table.insert(env, vim.env.MANPATH ~= nil and ('MANPATH=' .. vim.env.MANPATH) or nil)\n  local source = { name = 'Manpages', choose = choose, preview = preview }\n  opts = vim.tbl_deep_extend('force', { source = source }, opts or {})\n  return pick.builtin.cli({ command = { 'man', '-k', '.' }, spawn_opts = { env = env } }, opts)\nend\n\n--- Neovim marks picker\n---\n--- Pick and preview position of Neovim |mark|s.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - scope to show. One of \"all\", \"global\", \"buf\".\n---     Default: \"all\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.marks = function(local_opts, opts)\n  local pick = H.validate_pick('marks')\n  local_opts = vim.tbl_deep_extend('force', { scope = 'all' }, local_opts or {})\n\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'global', 'buf' }, 'marks')\n\n  -- Create items\n  local items = {}\n  local populate_items = function(mark_list)\n    for _, info in ipairs(mark_list) do\n      local path\n      if type(info.file) == 'string' then path = vim.fn.fnamemodify(info.file, ':.') end\n      local buf_id\n      if path == nil then buf_id = info.pos[1] end\n\n      local line, col = info.pos[2], math.abs(info.pos[3])\n      local text = string.format('%s │ %s%s│%s', info.mark:sub(2), path == nil and '' or (path .. '│'), line, col)\n      table.insert(items, { text = text, bufnr = buf_id, path = path, lnum = line, col = col })\n    end\n  end\n\n  if scope == 'all' or scope == 'buf' then populate_items(vim.fn.getmarklist(vim.api.nvim_get_current_buf())) end\n  if scope == 'all' or scope == 'global' then populate_items(vim.fn.getmarklist()) end\n\n  local default_opts = { source = { name = string.format('Marks (%s)', scope) } }\n  return H.pick_start(items, default_opts, opts)\nend\n\n--- Old files picker\n---\n--- Pick from |v:oldfiles| entries representing readable files.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <current_dir> `(boolean)` - whether to return files only from current\n---     working directory and its subdirectories. Default: `false`.\n---   __extra_pickers_preserve_order\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.oldfiles = function(local_opts, opts)\n  local pick = H.validate_pick('oldfiles')\n  local_opts = vim.tbl_deep_extend('force', { current_dir = false, preserve_order = false }, local_opts or {})\n  local oldfiles = vim.v.oldfiles\n  if not H.islist(oldfiles) then H.error('`pickers.oldfiles` picker needs valid `v:oldfiles`.') end\n\n  local show_all = not local_opts.current_dir\n  local items = vim.schedule_wrap(function()\n    local cwd = H.normalize_path(pick.get_picker_opts().source.cwd) .. '/'\n    local res = {}\n    for _, path in ipairs(oldfiles) do\n      path = H.normalize_path(path)\n      if vim.fn.filereadable(path) == 1 and (show_all or vim.startswith(path, cwd)) then\n        table.insert(res, H.short_path(path, cwd))\n      end\n    end\n    pick.set_picker_items(res)\n  end)\n\n  local show = H.pick_get_config().source.show or H.show_with_icons\n  local match_opts = { preserve_order = local_opts.preserve_order }\n  local match = function(stritems, inds, query) pick.default_match(stritems, inds, query, match_opts) end\n  return H.pick_start(items, { source = { name = 'Old files', show = show, match = match } }, opts)\nend\n\n--- Neovim options picker\n---\n--- Pick and preview data about Neovim options.\n--- Notes:\n--- - Item line is colored based on whether it was set (dimmed if wasn't).\n--- - Preview shows option value in target window and its general information.\n--- - Choosing places option name in Command line to update and apply.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <scope> `(string)` - options to show. One of \"all\", \"global\", \"win\", \"buf\".\n---     Default: \"all\".\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.options = function(local_opts, opts)\n  local pick = H.validate_pick('options')\n  local_opts = vim.tbl_deep_extend('force', { scope = 'all' }, local_opts or {})\n\n  local scope = H.pick_validate_scope(local_opts, { 'all', 'global', 'win', 'buf' }, 'options')\n\n  local items = {}\n  for name, info in pairs(vim.api.nvim_get_all_options_info()) do\n    if scope == 'all' or scope == info.scope then table.insert(items, { text = name, info = info }) end\n  end\n  table.sort(items, function(a, b) return a.text < b.text end)\n\n  local show = function(buf_id, items_to_show, query)\n    pick.default_show(buf_id, items_to_show, query)\n\n    H.pick_clear_namespace(buf_id, H.ns_id.pickers)\n    for i, item in ipairs(items_to_show) do\n      if not item.info.was_set then H.pick_highlight_line(buf_id, i, 'Comment', 199) end\n    end\n  end\n\n  local preview = function(buf_id, item)\n    local pick_windows = pick.get_picker_state().windows\n    local target_win_id = pick_windows.target\n    if not H.is_valid_win(target_win_id) then target_win_id = pick_windows.main end\n    local value_source = ({ global = 'o', win = 'wo', buf = 'bo' })[item.info.scope]\n    local has_value, value = pcall(function()\n      return vim.api.nvim_win_call(target_win_id, function() return vim[value_source][item.info.name] end)\n    end)\n    -- TODO: consider removing after Neovim<=0.10 compatibility is dropped\n    if not has_value then value = '<Option is deprecated (will be removed in later Neovim versions)>' end\n\n    local lines = { 'Value:', unpack(vim.split(vim.inspect(value), '\\n')), '', 'Info:' }\n    local hl_lines = { 1, #lines }\n    lines = vim.list_extend(lines, vim.split(vim.inspect(item.info), '\\n'))\n\n    H.set_buflines(buf_id, lines)\n    H.pick_highlight_line(buf_id, hl_lines[1], 'MiniPickHeader', 200)\n    H.pick_highlight_line(buf_id, hl_lines[2], 'MiniPickHeader', 200)\n  end\n\n  local choose = function(item)\n    local keys = string.format(':set %s%s', item.info.name, item.info.type == 'boolean' and '' or '=')\n    vim.schedule(function() vim.fn.feedkeys(keys) end)\n  end\n\n  local name = string.format('Options (%s)', scope)\n  local default_source = { name = name, show = show, preview = preview, choose = choose }\n  return H.pick_start(items, { source = default_source }, opts)\nend\n\n--- Neovim registers picker\n---\n--- Pick from Neovim |registers|.\n--- Notes:\n--- - There is no preview (all information is in the item's text).\n--- - Choosing pastes content of a register: with |i_CTRL-R| in Insert mode,\n---   |c_CTRL-R| in Command-line mode, and |P| otherwise.\n---   Expression register |quote=| is reevaluated (if present) and pasted.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Not used at the moment.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.registers = function(local_opts, opts)\n  local pick = H.validate_pick('registers')\n\n  local describe_register = function(regname)\n    local ok, value = pcall(vim.fn.getreg, regname, 1)\n    if not ok then return '' end\n    return value\n  end\n\n  local all_registers = vim.split('\"*+:.%/#=-0123456789abcdefghijklmnopqrstuvwxyz', '')\n\n  local items = {}\n  for _, regname in ipairs(all_registers) do\n    local regcontents = describe_register(regname)\n    local text = string.format('%s │ %s', regname, regcontents)\n    table.insert(items, { regname = regname, regcontents = regcontents, text = text })\n  end\n\n  local choose = vim.schedule_wrap(function(item)\n    local reg, regcontents, mode = item.regname, item.regcontents, vim.fn.mode()\n    if reg == '=' and regcontents ~= '' then reg = reg .. item.regcontents .. '\\r' end\n    local keys = string.format('\"%s%s', reg, reg == '=' and '' or 'P')\n    -- In Insert and Command-line modes use `<C-r><regname>`\n    if mode == 'i' or mode == 'c' then keys = '\\18' .. reg end\n    vim.fn.feedkeys(keys)\n  end)\n\n  local preview = function(buf_id, item) H.set_buflines(buf_id, vim.split(item.regcontents, '\\n')) end\n\n  return H.pick_start(items, { source = { name = 'Registers', preview = preview, choose = choose } }, opts)\nend\n\n--- Neovim spell suggestions picker\n---\n--- Pick and apply spell suggestions.\n--- Notes:\n--- - No preview is available.\n--- - Choosing replaces current word (|<cword>|) with suggestion.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <n_suggestions> `(number)` - number of spell suggestions. Default: 25.\n---\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.spellsuggest = function(local_opts, opts)\n  local pick = H.validate_pick('spellsuggest')\n  local_opts = vim.tbl_deep_extend('force', { n_suggestions = 25 }, local_opts or {})\n\n  local n_suggestions = local_opts.n_suggestions\n  if not (type(n_suggestions) == 'number' and n_suggestions > 0) then\n    H.error('`local_opts.n_suggestions` should be a positive number.')\n  end\n\n  local word = vim.fn.expand('<cword>')\n  local suggestions = vim.fn.spellsuggest(word, n_suggestions)\n  local items = {}\n  for i, sugg in ipairs(suggestions) do\n    table.insert(items, { text = sugg, index = i })\n  end\n\n  -- Define scope\n  local preview = H.pick_make_no_preview('spellsuggest')\n  local choose = vim.schedule_wrap(function(item) vim.cmd('normal! ' .. item.index .. 'z=') end)\n\n  local name = 'Spell suggestions for ' .. vim.inspect(word)\n  return H.pick_start(items, { source = { name = name, preview = preview, choose = choose } }, opts)\nend\n\n--- Tree-sitter nodes picker\n---\n--- Pick and navigate to |treesitter| nodes of current buffer.\n--- Notes:\n--- - Requires active tree-sitter parser in the current buffer.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Not used at the moment.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.treesitter = function(local_opts, opts)\n  local pick = H.validate_pick('treesitter')\n\n  local buf_id = vim.api.nvim_get_current_buf()\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, nil, { error = false })\n  if not has_parser or parser == nil then H.error('`pickers.treesitter` requires active tree-sitter parser.') end\n\n  -- Make items by traversing roots of all trees (including injections)\n  local items, traverse = {}, nil\n  traverse = function(node, depth)\n    if depth >= 1000 then return end\n    for child in node:iter_children() do\n      if child:named() then\n        local lnum, col, end_lnum, end_col = child:range()\n        lnum, col, end_lnum, end_col = lnum + 1, col + 1, end_lnum + 1, end_col + 1\n        local indent = string.rep(' ', depth)\n        local text = string.format('%s%s (%s│%s - %s│%s)', indent, child:type() or '', lnum, col, end_lnum, end_col)\n        local item = { text = text, bufnr = buf_id, lnum = lnum, col = col, end_lnum = end_lnum, end_col = end_col }\n        table.insert(items, item)\n\n        traverse(child, depth + 1)\n      end\n    end\n  end\n\n  parser:for_each_tree(function(ts_tree, _) traverse(ts_tree:root(), 0) end)\n\n  return H.pick_start(items, { source = { name = 'Tree-sitter nodes' } }, opts)\nend\n\n--- Visit paths from 'mini.visits' picker\n---\n--- Pick paths from |mini.visits| using |MiniVisits.list_paths()|.\n--- Notes:\n--- - Requires 'mini.visits'.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.visit_paths()` - visits registered for |current-directory|\n---   and ordered by \"robust frecency\".\n--- - `:Pick visit_paths cwd='' recency_weight=1 filter='core'` - all visits with\n---   \"core\" label ordered from most to least recent.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <cwd> `(string)` - forwarded to |MiniVisits.list_paths()|.\n---     Default: `nil` to get paths registered for |current-directory|.\n---   - <filter> `(function|string)` - forwarded to |MiniVisits.list_paths()|.\n---     Default: `nil` to use all paths.\n---   __extra_pickers_preserve_order\n---   - <recency_weight> `(number)` - forwarded to |MiniVisits.gen_sort.default()|.\n---     Default: 0.5 to use \"robust frecency\" sorting.\n---   - <sort> `(function)` - forwarded to |MiniVisits.list_paths()|.\n---     Default: `nil` to use \"robust frecency\".\n---     Note: if supplied, has precedence over `recency_weight`.\n---@param opts __extra_pickers_opts\n---\n---@return __extra_pickers_return\nMiniExtra.pickers.visit_paths = function(local_opts, opts)\n  local pick = H.validate_pick('visit_paths')\n  local has_visits, visits = pcall(require, 'mini.visits')\n  if not has_visits then H.error([[`pickers.visit_paths` requires 'mini.visits' which can not be found.]]) end\n\n  local default_local_opts = { cwd = nil, filter = nil, preserve_order = false, recency_weight = 0.5, sort = nil }\n  local_opts = vim.tbl_deep_extend('force', default_local_opts, local_opts or {})\n\n  local cwd = local_opts.cwd or vim.fn.getcwd()\n  -- NOTE: Use separate cwd to allow `cwd = ''` to not mean \"current directory\"\n  local is_for_cwd = cwd ~= ''\n  local picker_cwd = H.normalize_path(cwd == '' and vim.fn.getcwd() or H.full_path(cwd))\n\n  -- Define source\n  local filter = local_opts.filter or visits.gen_filter.default()\n  local sort = local_opts.sort or visits.gen_sort.default({ recency_weight = local_opts.recency_weight })\n  local items = vim.schedule_wrap(function()\n    local paths = visits.list_paths(cwd, { filter = filter, sort = sort })\n    paths = vim.tbl_map(function(x) return H.normalize_path(H.short_path(x, picker_cwd)) end, paths)\n    pick.set_picker_items(paths)\n  end)\n\n  local show = H.pick_get_config().source.show or H.show_with_icons\n  local match_opts = { preserve_order = local_opts.preserve_order }\n  local match = function(stritems, inds, query) pick.default_match(stritems, inds, query, match_opts) end\n\n  local name = string.format('Visit paths (%s)', is_for_cwd and 'cwd' or 'all')\n  local default_source = { name = name, cwd = picker_cwd, match = match, show = show }\n  return H.pick_start(items, { source = default_source }, opts)\nend\n\n--- Visit labels from 'mini.visits' picker\n---\n--- Pick labels from |mini.visits| using |MiniVisits.list_labels()|\n--- and |MiniVisits.list_paths()|.\n--- Notes:\n--- - Requires 'mini.visits'.\n--- - Preview shows target visit paths filtered to those having previewed label.\n--- - Choosing essentially starts |MiniExtra.pickers.visit_paths()| for paths\n---   with the chosen label.\n---\n--- Examples:\n---\n--- - `MiniExtra.pickers.visit_labels()` - labels from visits registered\n---   for |current-directory|.\n--- - `:Pick visit_labels cwd=''` - labels from all visits.\n---\n---@param local_opts __extra_pickers_local_opts\n---   Possible fields:\n---   - <cwd> `(string)` - forwarded to |MiniVisits.list_labels()|.\n---     Default: `nil` to get labels from visits registered for |current-directory|.\n---   - <filter> `(function|string)` - forwarded to |MiniVisits.list_labels()|.\n---     Default: `nil` to use all visits.\n---   - <path> `(string)` - forwarded to |MiniVisits.list_labels()|.\n---     Default: `\"\"` to get labels from all visits for target `cwd`.\n---   - <sort> `(function)` - forwarded to |MiniVisits.list_paths()| for\n---     preview and choose. Default: `nil` to use \"robust frecency\".\n---@param opts __extra_pickers_opts\n---\n---@return ... Chosen path.\nMiniExtra.pickers.visit_labels = function(local_opts, opts)\n  local pick = H.validate_pick('visit_labels')\n  local has_visits, visits = pcall(require, 'mini.visits')\n  if not has_visits then H.error([[`pickers.visit_labels` requires 'mini.visits' which can not be found.]]) end\n\n  local default_local_opts = { cwd = nil, filter = nil, path = '', sort = nil }\n  local_opts = vim.tbl_deep_extend('force', default_local_opts, local_opts or {})\n\n  local cwd = local_opts.cwd or vim.fn.getcwd()\n  -- NOTE: Use separate cwd to allow `cwd = ''` to not mean \"current directory\"\n  local is_for_cwd = cwd ~= ''\n  local picker_cwd = H.normalize_path(cwd == '' and vim.fn.getcwd() or H.full_path(cwd))\n\n  local filter = local_opts.filter or visits.gen_filter.default()\n  local items = visits.list_labels(local_opts.path, local_opts.cwd, { filter = filter })\n\n  -- Define source\n  local list_label_paths = function(label)\n    local new_filter = function(path_data)\n      return filter(path_data) and type(path_data.labels) == 'table' and path_data.labels[label]\n    end\n    local all_paths = visits.list_paths(local_opts.cwd, { filter = new_filter, sort = local_opts.sort })\n    return vim.tbl_map(function(x) return H.normalize_path(H.short_path(x, picker_cwd)) end, all_paths)\n  end\n\n  local preview = function(buf_id, label) vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, list_label_paths(label)) end\n  local choose = function(label)\n    if label == nil then return end\n\n    pick.set_picker_items(list_label_paths(label), { do_match = false })\n    pick.set_picker_query({})\n    local name = string.format('Paths for %s label', vim.inspect(label))\n    local show = H.pick_get_config().source.show or H.show_with_icons\n    pick.set_picker_opts({ source = { name = name, show = show, choose = pick.default_choose } })\n    return true\n  end\n\n  local name = string.format('Visit labels (%s)', is_for_cwd and 'cwd' or 'all')\n  local default_source = { name = name, cwd = picker_cwd, preview = preview, choose = choose }\n  return H.pick_start(items, { source = default_source }, opts)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniExtra.config\n\n-- Namespaces\nH.ns_id = {\n  pickers = vim.api.nvim_create_namespace('MiniExtraPickers'),\n}\n\n-- Various cache\nH.cache = {}\n\n-- File system information\nH.is_windows = vim.loop.os_uname().sysname == 'Windows_NT'\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  return config\nend\n\nH.apply_config = function(config)\n  MiniExtra.config = config\n\n  -- Register pickers in 'mini.pick'\n  if type(_G.MiniPick) == 'table' then\n    for name, f in pairs(MiniExtra.pickers) do\n      _G.MiniPick.registry[name] = _G.MiniPick.registry[name] or function(local_opts) return f(local_opts) end\n    end\n  end\nend\n\n-- Mini.ai specifications -----------------------------------------------------\nH.ai_indent_spec = function(ai_type)\n  -- Compute buffer data\n  local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)\n  local tab_spaces = string.rep(' ', vim.bo.tabstop)\n\n  -- Traverse lines from top to bottom casting rays\n  local indents, rays, rays_final = {}, {}, {}\n  for i, l in ipairs(lines) do\n    indents[i] = l:match('^([ \\t]*)')\n\n    -- Ray can be updated only on non-blank line\n    local is_blank = indents[i]:len() ~= l:len()\n    if is_blank then H.ai_indent_update_rays(i, indents[i]:gsub('\\t', tab_spaces):len(), rays, rays_final) end\n  end\n\n  -- The `rays` stack can be not empty at this point which means that there are\n  -- non-empty lines at buffer end without \"closing\". Ignore them.\n\n  -- Sort for better output\n  table.sort(rays_final, function(a, b) return a.from_line < b.from_line end)\n\n  -- Compute regions:\n  -- - `a` is as if linewise from start to end.\n  -- - `i` is as if charwise not including edge whitespace on start and end.\n  local from_offset, to_offset, to_col_offset = 0, 0, 1\n  if ai_type == 'i' then\n    from_offset, to_offset, to_col_offset = 1, -1, 0\n  end\n  local res = {}\n  for i, ray in ipairs(rays_final) do\n    local from_line, to_line = ray.from_line + from_offset, ray.to_line + to_offset\n    local from_col = ai_type == 'a' and 1 or (indents[from_line]:len() + 1)\n    local to_col = lines[to_line]:len() + to_col_offset\n    res[i] = { from = { line = from_line, col = from_col }, to = { line = to_line, col = to_col } }\n  end\n  return res\nend\n\nH.ai_indent_update_rays = function(line_num, indent, rays, rays_final)\n  -- Update rays with finite indent\n  -- `rays` is a stack of cast rays (sorted by increasing start indent).\n  -- Each ray has `from_line` and `to_line` indicating start of `a` textobject.\n  for i = #rays, 1, -1 do\n    local ray = rays[i]\n    -- If current indent is bigger, then ray is cast over non-blank region.\n    -- This assumes that line at `line_num` is not blank.\n    if ray.indent < indent then\n      ray.is_empty = false\n      -- All previously cast rays are already marked as non-blank if they are\n      break\n    end\n\n    -- If ray was cast from bigger indent then current and spans over\n    -- non-empty region, finalize it as it has hit its limit\n    if not ray.is_empty then\n      ray.to_line = line_num\n      table.insert(rays_final, ray)\n    end\n    rays[i] = nil\n  end\n\n  -- Start new ray\n  table.insert(rays, { indent = indent, from_line = line_num, is_empty = true })\nend\n\n-- Pickers --------------------------------------------------------------------\nH.validate_pick = function(fun_name)\n  local has_pick, pick = pcall(require, 'mini.pick')\n  if not has_pick then\n    H.error(string.format([[`pickers.%s()` requires 'mini.pick' which can not be found.]], fun_name))\n  end\n  return pick\nend\n\nH.pick_start = function(items, default_opts, opts)\n  local pick = H.validate_pick()\n  local opts_final = vim.tbl_deep_extend('force', default_opts, opts or {}, { source = { items = items } })\n  return pick.start(opts_final)\nend\n\nH.pick_highlight_line = function(buf_id, line, hl_group, priority)\n  local opts = { end_row = line, end_col = 0, hl_mode = 'blend', hl_group = hl_group, priority = priority }\n  vim.api.nvim_buf_set_extmark(buf_id, H.ns_id.pickers, line - 1, 0, opts)\nend\n\nH.pick_prepend_position = function(item)\n  local path\n  if item.path ~= nil then\n    path = item.path\n  elseif H.is_valid_buf(item.bufnr) then\n    local name = vim.api.nvim_buf_get_name(item.bufnr)\n    path = name == '' and ('Buffer_' .. item.bufnr) or name\n  end\n  if path == nil then return item end\n\n  path = vim.fn.fnamemodify(path, ':p:.')\n  local text = item.text or ''\n  local suffix = text == '' and '' or ('│ ' .. text)\n  item.text = string.format('%s│%s│%s%s', path, item.lnum or 1, item.col or 1, suffix)\n  return item\nend\n\nH.pick_clear_namespace = function(buf_id, ns_id) pcall(vim.api.nvim_buf_clear_namespace, buf_id, ns_id, 0, -1) end\n\nH.pick_make_no_preview = function(picker_name)\n  local lines = { string.format('No preview available for `%s` picker', picker_name) }\n  return function(buf_id, _) H.set_buflines(buf_id, lines) end\nend\n\nH.pick_validate_one_of = function(target, opts, values, picker_name)\n  if vim.tbl_contains(values, opts[target]) then return opts[target] end\n  local msg = string.format(\n    '`pickers.%s` has wrong \"%s\" local option (%s). Should be one of %s.',\n    picker_name,\n    target,\n    vim.inspect(opts[target]),\n    table.concat(vim.tbl_map(vim.inspect, values), ', ')\n  )\n  H.error(msg)\nend\n\nH.pick_validate_scope = function(...) return H.pick_validate_one_of('scope', ...) end\n\nH.pick_get_config = function()\n  return vim.tbl_deep_extend('force', (require('mini.pick') or {}).config or {}, vim.b.minipick_config or {})\nend\n\nH.show_with_icons = function(buf_id, items, query)\n  require('mini.pick').default_show(buf_id, items, query, { show_icons = true })\nend\n\nH.choose_with_buflisted = function(item)\n  local pick = require('mini.pick')\n  pick.default_choose(item)\n\n  -- Force 'buflisted' on opened item\n  local win_target = pick.get_picker_state().windows.target\n  local buf_id = vim.api.nvim_win_get_buf(win_target)\n  vim.bo[buf_id].buflisted = true\nend\n\n-- Colorscheme picker ----------------------------------------------------------\nH.preview_cs_hl_groups = function(buf_id, hl_groups)\n  local lines = hl_groups\n  if lines == nil then\n    lines = vim.tbl_keys(vim.api.nvim_get_hl(0, {}))\n    table.sort(lines)\n  end\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n\n  local ns_id = H.ns_id.pickers\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n  for i, hl in ipairs(lines) do\n    pcall(vim.api.nvim_buf_set_extmark, buf_id, ns_id, i - 1, 0, { end_row = i, end_col = 0, hl_group = hl })\n  end\nend\n\n-- Diagnostic picker ----------------------------------------------------------\nH.diagnostic_make_compare = function(sort_by)\n  if sort_by == 'severity' then\n    return function(a, b)\n      if a.severity < b.severity then return true end\n      if a.severity > b.severity then return false end\n      if a.path < b.path then return true end\n      if a.path > b.path then return false end\n      if a.lnum < b.lnum then return true end\n      if a.lnum > b.lnum then return false end\n      return a.col < b.col\n    end\n  end\n  if sort_by == 'path' then\n    return function(a, b)\n      if a.path < b.path then return true end\n      if a.path > b.path then return false end\n      if a.severity < b.severity then return true end\n      if a.severity > b.severity then return false end\n      if a.lnum < b.lnum then return true end\n      if a.lnum > b.lnum then return false end\n      return a.col < b.col\n    end\n  end\n\n  return nil\nend\n\n-- Git pickers ----------------------------------------------------------------\nH.validate_git = function(picker_name)\n  if vim.fn.executable('git') == 1 then return true end\n  local msg = string.format('`pickers.%s` requires executable `git`.', picker_name)\n  H.error(msg)\nend\n\nH.git_normalize_path = function(path, picker_name)\n  path = type(path) == 'string' and path or vim.fn.getcwd()\n  if path == '' then H.error(string.format('Path in `%s` is empty.', picker_name)) end\n  path = H.full_path(path)\n  local path_is_dir, path_is_file = vim.fn.isdirectory(path) == 1, vim.fn.filereadable(path) == 1\n  if not (path_is_dir or path_is_file) then H.error('Path ' .. path .. ' is not a valid path.') end\n  return path, path_is_dir and 'directory' or 'file'\nend\n\nH.git_get_repo_dir = function(path, path_type, picker_name)\n  local path_dir = path_type == 'directory' and path or vim.fn.fnamemodify(path, ':h')\n  local repo_dir = vim.fn.systemlist({ 'git', '-C', path_dir, 'rev-parse', '--show-toplevel' })[1]\n  if vim.v.shell_error ~= 0 then\n    local msg = string.format('`pickers.%s` could not find Git repo for %s.', picker_name, path)\n    H.error(msg)\n  end\n  return repo_dir\nend\n\nH.git_difflines_to_hunkitems = function(lines, n_context)\n  local header_pattern = '^diff %-%-git'\n  local hunk_pattern = '^@@ %-%d+,?%d* %+(%d+),?%d* @@'\n  -- NOTE: Account for possible `diff.mnemonicPrefix=true` Git config. In that\n  -- case the destination can also be `w`. If won't work for some reason, more\n  -- robust solution is to modify `git diff`: `--src-prefix=a/ --dst-prefix=b/`\n  local from_path_pattern = '^%-%-%- [ai]/(.*)$'\n  local to_path_pattern = '^%+%+%+ [bw]/(.*)$'\n\n  -- Parse diff lines\n  local cur_header, cur_path, is_in_hunk = {}, nil, false\n  local items = {}\n  for _, l in ipairs(lines) do\n    -- Separate path header and hunk for better granularity\n    if l:find(header_pattern) ~= nil then\n      is_in_hunk = false\n      cur_header = {}\n    end\n\n    local path_match = l:match(to_path_pattern) or l:match(from_path_pattern)\n    if path_match ~= nil and not is_in_hunk then cur_path = path_match end\n\n    local hunk_start = l:match(hunk_pattern)\n    if hunk_start ~= nil then\n      is_in_hunk = true\n      local item = { path = cur_path, lnum = tonumber(hunk_start), header = vim.deepcopy(cur_header), hunk = {} }\n      table.insert(items, item)\n    end\n\n    if is_in_hunk then\n      table.insert(items[#items].hunk, l)\n    else\n      table.insert(cur_header, l)\n    end\n  end\n\n  -- Correct line number to point at the first change\n  local try_correct_lnum = function(item, i)\n    if item.hunk[i]:find('^[+-]') == nil then return false end\n    item.lnum = item.lnum + i - 2\n    return true\n  end\n  for _, item in ipairs(items) do\n    for i = 2, #item.hunk do\n      if try_correct_lnum(item, i) then break end\n    end\n  end\n\n  -- Construct aligned text from path and hunk header\n  local text_parts, path_width, coords_width = {}, 0, 0\n  for i, item in ipairs(items) do\n    local coords, title = item.hunk[1]:match('@@ (.-) @@ ?(.*)$')\n    coords, title = coords or '', title or ''\n    text_parts[i] = { item.path, coords, title }\n    path_width = math.max(path_width, vim.fn.strchars(item.path))\n    coords_width = math.max(coords_width, vim.fn.strchars(coords))\n  end\n\n  for i, item in ipairs(items) do\n    local parts = text_parts[i]\n    local path, coords = H.ensure_text_width(parts[1], path_width), H.ensure_text_width(parts[2], coords_width)\n    item.text = string.format('%s │ %s │ %s', path, coords, parts[3])\n  end\n\n  return items\nend\n\n-- LSP picker -----------------------------------------------------------------\nH.lsp_make_opts = function(source, opts)\n  local is_symbol = source:find('symbol') ~= nil\n\n  -- Prepend file position info to item, add decortion, and sort\n  local add_decor_data = function() end\n  if is_symbol and _G.MiniIcons == nil then\n    -- Try using '@...' style highlight group with same name as \"kind\"\n    add_decor_data = function(item) item.hl = string.format('@%s', string.lower(item.kind or 'unknown')) end\n  end\n  if is_symbol and _G.MiniIcons ~= nil then\n    add_decor_data = function(item)\n      if type(item.kind) ~= 'string' then return end\n      local icon, hl = MiniIcons.get('lsp', item.kind)\n      -- If kind is not original, assume it already contains an icon\n      local icon_prefix = item.kind_orig == item.kind and (icon .. ' ') or ''\n      item.text, item.hl = icon_prefix .. item.text, hl\n    end\n  end\n\n  local process = function(items)\n    if source ~= 'document_symbol' then items = vim.tbl_map(H.pick_prepend_position, items) end\n    -- Input `item.kind` is a string (resolved before `on_list`). Account for\n    -- possibly tweaked symbol map (like after `MiniIcons.tweak_lsp_kind`).\n    local kind_map = H.get_symbol_kind_map()\n    for _, item in ipairs(items) do\n      item.kind_orig, item.kind = item.kind, kind_map[item.kind]\n      add_decor_data(item)\n      item.kind_orig = nil\n    end\n    table.sort(items, H.lsp_items_compare)\n    return items\n  end\n\n  local pick = H.validate_pick()\n  local picker_opts = { source = { name = string.format('LSP (%s)', source) } }\n\n  local show_explicit = H.pick_get_config().source.show\n  picker_opts.source.show = function(buf_id, items_to_show, query)\n    if show_explicit ~= nil then return show_explicit(buf_id, items_to_show, query) end\n    -- Show with icons as the non-symbol scopes should have paths\n    if not is_symbol then return H.show_with_icons(buf_id, items_to_show, query) end\n\n    -- Highlight whole lines with pre-computed symbol kind highlight groups\n    pick.default_show(buf_id, items_to_show, query)\n\n    H.pick_clear_namespace(buf_id, H.ns_id.pickers)\n    for i, item in ipairs(items_to_show) do\n      H.pick_highlight_line(buf_id, i, item.hl, 199)\n    end\n  end\n\n  picker_opts.source.choose = function(item)\n    pick.default_choose(item)\n    -- Ensure relative path in `:buffers` output with hacky workaround.\n    -- `default_choose` ensures it with `bufadd(fnamemodify(path, ':.'))`, but\n    -- somehow that doesn't work inside `on_list` of `vim.lsp.buf` methods.\n    vim.fn.chdir(vim.fn.getcwd())\n  end\n\n  local on_list = function(data)\n    local items = data.items\n    for _, item in ipairs(data.items) do\n      item.text, item.path = item.text or '', item.filename or nil\n    end\n    items = process(items)\n\n    if MiniPick.is_picker_active() and source == 'workspace_symbol_live' then\n      return MiniPick.set_picker_items(items, { do_match = false })\n    end\n\n    return H.pick_start(items, picker_opts, opts)\n  end\n\n  return { on_list = on_list }, picker_opts\nend\n\nH.get_symbol_kind_map = function()\n  -- Compute symbol kind map from \"resolved\" string kind to its \"original\" (as in\n  -- LSP protocol). Those can be different after `MiniIcons.tweak_lsp_kind()`.\n  local res = {}\n  local double_map = vim.lsp.protocol.SymbolKind\n  for k, v in pairs(double_map) do\n    if type(k) == 'string' and type(v) == 'number' then res[double_map[v]] = k end\n  end\n  return res\nend\n\nH.lsp_items_compare = function(a, b)\n  local a_path, b_path = a.path or '', b.path or ''\n  if a_path < b_path then return true end\n  if a_path > b_path then return false end\n\n  local a_lnum, b_lnum = a.lnum or 1, b.lnum or 1\n  if a_lnum < b_lnum then return true end\n  if a_lnum > b_lnum then return false end\n\n  local a_col, b_col = a.col or 1, b.col or 1\n  if a_col < b_col then return true end\n  if a_col > b_col then return false end\n\n  return tostring(a) < tostring(b)\nend\n\n-- List picker ----------------------------------------------------------------\nH.list_get = {\n  quickfix = function() return vim.tbl_map(H.list_enhance_qf_loc, vim.fn.getqflist()) end,\n\n  location = function() return vim.tbl_map(H.list_enhance_qf_loc, vim.fn.getloclist(0)) end,\n\n  jump = function()\n    local raw = vim.fn.getjumplist()[1]\n    -- Tweak output: reverse for more relevance; make 1-based column\n    local res, n = {}, #raw\n    for i, x in ipairs(raw) do\n      x.col = x.col + 1\n      res[n - i + 1] = x\n    end\n    return res\n  end,\n\n  change = function()\n    local cur_buf = vim.api.nvim_get_current_buf()\n    local res = vim.fn.getchangelist(cur_buf)[1]\n    for _, x in ipairs(res) do\n      x.col = x.col + 1\n      x.bufnr = cur_buf\n    end\n    return res\n  end,\n}\n\nH.list_enhance_qf_loc = function(item)\n  if item.end_lnum == 0 then item.end_lnum = nil end\n  if item.end_col == 0 then item.end_col = nil end\n  if H.is_valid_buf(item.bufnr) then\n    local filename = vim.api.nvim_buf_get_name(item.bufnr)\n    if filename ~= '' then item.filename = filename end\n  end\n  return item\nend\n\nH.list_enhance_item = function(item)\n  if vim.fn.filereadable(item.filename) == 1 then item.path = item.filename end\n  return H.pick_prepend_position(item)\nend\n\n-- Explorer picker ------------------------------------------------------------\nH.explorer_make_items = function(path, filter, sort)\n  if vim.fn.isdirectory(path) == 0 then return {} end\n  local res = { { fs_type = 'directory', path = vim.fn.fnamemodify(path, ':h'), text = '..' } }\n  for _, basename in ipairs(vim.fn.readdir(path)) do\n    local subpath = string.format('%s/%s', path, basename)\n    local fs_type = vim.fn.isdirectory(subpath) == 1 and 'directory' or 'file'\n    table.insert(res, { fs_type = fs_type, path = subpath, text = basename .. (fs_type == 'directory' and '/' or '') })\n  end\n\n  return sort(vim.tbl_filter(filter, res))\nend\n\nH.explorer_default_sort = function(items)\n  -- Sort ignoring case\n  local res = vim.tbl_map(function(x)\n      --stylua: ignore\n      return {\n        fs_type = x.fs_type, path = x.path, text = x.text,\n        is_dir = x.fs_type == 'directory', lower_name = x.text:lower(),\n      }\n  end, items)\n\n  local compare = function(a, b)\n    -- Put directory first\n    if a.is_dir and not b.is_dir then return true end\n    if not a.is_dir and b.is_dir then return false end\n\n    -- Otherwise order alphabetically ignoring case\n    return a.lower_name < b.lower_name\n  end\n\n  table.sort(res, compare)\n\n  return vim.tbl_map(function(x) return { fs_type = x.fs_type, path = x.path, text = x.text } end, res)\nend\n\n-- CLI ------------------------------------------------------------------------\nH.cli_run = function(command, stdout_hook)\n  stdout_hook = stdout_hook or function() end\n  local executable, args = command[1], vim.list_slice(command, 2, #command)\n  local process, stdout, stderr = nil, vim.loop.new_pipe(), vim.loop.new_pipe()\n  local spawn_opts = { args = args, stdio = { nil, stdout, stderr } }\n  process = vim.loop.spawn(executable, spawn_opts, function() process:close() end)\n\n  H.cli_read_stream(stdout, stdout_hook)\n  H.cli_read_stream(stderr, function(lines)\n    local msg = table.concat(lines, '\\n')\n    if msg == '' then return end\n    H.error(msg)\n  end)\nend\n\nH.cli_show_output = function(buf_id, command)\n  local stdout_hook = vim.schedule_wrap(function(lines)\n    if not H.is_valid_buf(buf_id) then return end\n    H.set_buflines(buf_id, lines)\n  end)\n  H.cli_run(command, stdout_hook)\nend\n\nH.cli_read_stream = function(stream, post_hook)\n  local data_feed = {}\n  local callback = function(err, data)\n    assert(not err, err)\n    if data ~= nil then return table.insert(data_feed, data) end\n\n    local lines = vim.split(table.concat(data_feed), '\\n')\n    data_feed = nil\n    stream:close()\n    post_hook(lines)\n  end\n  stream:read_start(callback)\nend\n\n-- Buffers --------------------------------------------------------------------\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.buf_ensure_loaded = function(buf_id)\n  if type(buf_id) ~= 'number' or vim.api.nvim_buf_is_loaded(buf_id) then return end\n  local cache_eventignore = vim.o.eventignore\n  vim.o.eventignore = 'BufEnter'\n  pcall(vim.fn.bufload, buf_id)\n  vim.o.eventignore = cache_eventignore\nend\n\nH.buf_get_name = function(buf_id)\n  if not H.is_valid_buf(buf_id) then return nil end\n  local buf_name = vim.api.nvim_buf_get_name(buf_id)\n  if buf_name ~= '' then buf_name = vim.fn.fnamemodify(buf_name, ':~:.') end\n  return buf_name\nend\n\nH.set_buflines = function(buf_id, lines) vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines) end\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.extra) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'miniextra://' .. buf_id .. '/' .. name) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.ensure_text_width = function(text, width)\n  local text_width = vim.fn.strchars(text)\n  if text_width <= width then return text .. string.rep(' ', width - text_width) end\n  return '…' .. vim.fn.strcharpart(text, text_width - width + 1, width - 1)\nend\n\nH.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('(.)/$', '%1')) end\nH.normalize_path = function(path) return path end\nif H.is_windows then\n  H.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('(.)[\\\\/]$', '%1')) end\n  H.normalize_path = function(path) return path:gsub('\\\\', '/') end\nend\n\nH.short_path = function(path, cwd)\n  cwd = cwd or vim.fn.getcwd()\n  -- Ensure `cwd` is treated as directory path (to not match similar prefix)\n  cwd = cwd:sub(-1) == '/' and cwd or (cwd .. '/')\n  return vim.startswith(path, cwd) and path:sub(cwd:len() + 1) or vim.fn.fnamemodify(path, ':~')\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniExtra\n"
  },
  {
    "path": "lua/mini/files.lua",
    "content": "--- *mini.files* Navigate and manipulate file system\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Navigate file system using column view (Miller columns) to display nested\n---   directories. See |MiniFiles-navigation| for overview.\n---\n--- - Opt-in preview of file or directory under cursor.\n---\n--- - Manipulate files and directories by editing text buffers: create, delete,\n---   copy, rename, move. See |MiniFiles-manipulation| for overview.\n---\n--- - Use as default file explorer instead of `netrw`.\n---\n--- - Configurable:\n---     - Filter/prefix/sort of file system entries.\n---     - Mappings used for common explorer actions.\n---     - UI options: whether to show preview of file/directory under cursor, etc.\n---     - Bookmarks for quicker navigation.\n---\n--- What it doesn't do:\n--- - Try to be replacement of system file explorer. It is mostly designed to\n---   be used within Neovim to quickly explore file system structure, open\n---   files, and perform some quick file system edits.\n---\n--- - Work on remote locations. Only local file system is supported.\n---\n--- - Provide built-in interactive toggle of content `filter` and `sort`.\n---   See |MiniFiles-examples| for some common examples.\n---\n--- - Provide out of the box extra information like git or diagnostic status.\n---   This can be achieved by setting |extmarks| on appropriate event(s)\n---   (see |MiniFiles-events|)\n---\n--- Notes:\n--- - This module is written and thoroughly tested on Linux. Support for other\n---   platform/OS (like Windows or MacOS) is a goal, but there is no guarantee.\n---\n--- - This module silently reacts to not enough permissions:\n---     - In case of missing file, check its or its parent read permissions.\n---     - In case of no manipulation result, check write permissions.\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies (provide extra functionality, will work without them):\n---\n--- - Enabled |mini.icons| module to show icons near file/directory names.\n---   Falls back to [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n---   plugin or uses default icons.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.files').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniFiles`\n--- which you can use for scripting or manually (with `:lua MiniFiles.*`).\n---\n--- See |MiniFiles.config| for available config settings.\n---\n--- You can override runtime config settings (like mappings or window options)\n--- locally to buffer inside `vim.b.minifiles_config` which should have same\n--- structure as `MiniFiles.config`. See |mini.nvim-buffer-local-config| for\n--- more details.\n---\n--- # Comparisons ~\n---\n--- - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua):\n---     - Provides tree view of file system, while this module uses column view.\n---     - File system manipulation is done with custom set of mappings for each\n---       action, while this module is designed to do that by editing text.\n---     - Has more out of the box functionality with extra configuration, while\n---       this module has not (by design).\n---\n--- - [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim):\n---     - Uses single window to show information only about currently explored\n---       directory, while this module uses column view to show whole currently\n---       explored branch.\n---     - Also uses text editing to manipulate file system entries.\n---     - Can work for remote file systems, while this module can not (by design).\n---\n--- - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim):\n---     - Compares to this module mostly the same as 'nvim-tree/nvim-tree.lua'.\n---\n--- # Highlight groups ~\n---\n--- - `MiniFilesBorder` - border of regular windows.\n--- - `MiniFilesBorderModified` - border of windows showing modified buffer.\n--- - `MiniFilesCursorLine` - cursor line in explorer windows.\n--- - `MiniFilesDirectory` - text and icon representing directory.\n--- - `MiniFilesFile` - text representing file.\n--- - `MiniFilesNormal` - basic foreground/background highlighting.\n--- - `MiniFilesTitle` - title of regular windows.\n--- - `MiniFilesTitleFocused` - title of focused window.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- This plugin provides only manually started functionality, so no disabling\n--- is available.\n---@tag MiniFiles\n\n--- Every navigation starts by calling |MiniFiles.open()|, either directly or via\n--- mapping (see its help for examples of some common scenarios). It will show\n--- an explorer consisting of side-by-side floating windows with the following\n--- principles:\n---\n--- - Explorer shows one branch of nested directories at a time.\n---\n--- - Explorer consists from several windows:\n---\n---     - Each window displays entries of a single directory in a modifiable\n---       scratch buffer.\n---\n---     - Windows are organized left to right: for any particular window the left\n---       neighbor is its parent directory and right neighbor - its child.\n---\n--- - Explorer windows are the viewport to some part of current branch, meaning\n---   that their opening/closing does not affect the branch. This matters, for\n---   example, if there are more elements in the branch than can be shown windows.\n---\n--- - Every buffer line represents separate file system entry following certain\n---   format (not visible for users by default; set |'conceallevel'| to 0 to see it)\n---\n--- - Once directory is shown, its buffer is not updated automatically following\n---   external file system changes. Manually use |MiniFiles.synchronize()| for that.\n---\n--- After opening explorer, in-buffer navigation is done the same way as any\n--- regular buffer, except without some keys reserved for built-in actions.\n---\n--- Most common ways to navigate are:\n---\n--- - Press `j` to move cursor onto next (lower) entry in current directory.\n--- - Press `k` to move cursor onto previous (higher) entry in current directory.\n--- - Press `l` to expand entry under cursor (see \"Go in\" action).\n--- - Press `h` to focus on parent directory (see \"Go out\" action).\n---\n--- Cursor positions in each directory buffer are tracked and saved during\n--- navigation. This allows for more convenient repeated navigation to some\n--- previously visited branch.\n---\n--- Available built-in actions (see \"Details\" for more information): >\n---\n---  | Action      | Keys | Description                                    |\n---  |-------------|------|------------------------------------------------|\n---  | Close       |  q   | Close explorer                                 |\n---  |-------------|------|------------------------------------------------|\n---  | Go in       |  l   | Expand entry (show directory or open file)     |\n---  |-------------|------|------------------------------------------------|\n---  | Go in plus  |  L   | Expand entry plus extra action                 |\n---  |-------------|------|------------------------------------------------|\n---  | Go out      |  h   | Focus on parent directory                      |\n---  |-------------|------|------------------------------------------------|\n---  | Go out plus |  H   | Focus on parent directory plus extra action    |\n---  |-------------|------|------------------------------------------------|\n---  | Go to mark  |  '   | Jump to bookmark (waits for single key id)     |\n---  |-------------|------|------------------------------------------------|\n---  | Set mark    |  m   | Set bookmark (waits for single key id)         |\n---  |-------------|------|------------------------------------------------|\n---  | Reset       | <BS> | Reset current explorer                         |\n---  |-------------|------|------------------------------------------------|\n---  | Reveal cwd  |  @   | Reset current current working directory        |\n---  |-------------|------|------------------------------------------------|\n---  | Show help   |  g?  | Show help window                               |\n---  |-------------|------|------------------------------------------------|\n---  | Synchronize |  =   | Synchronize user edits and/or external changes |\n---  |-------------|------|------------------------------------------------|\n---  | Trim left   |  <   | Trim left part of branch                       |\n---  |-------------|------|------------------------------------------------|\n---  | Trim right  |  >   | Trim right part of branch                      |\n---  |-------------|------|------------------------------------------------|\n--- <\n--- Details:\n---\n--- - \"Go in\":\n---     - Always opens file in the latest window before `MiniFiles.open()` call.\n---     - Never closes explorer.\n---     - Works in linewise Visual mode to expand multiple entries.\n---\n--- - \"Go in plus\" is regular \"Go in\" but closes explorer after opening a file.\n---\n--- - \"Go out plus\" is regular \"Go out\" but trims right part of branch.\n---\n--- - \"Set mark\" and \"Go to mark\" both wait for user to press a single character\n---   of a bookmark id. Example: `ma` sets directory path of focused window as\n---   bookmark \"a\"; `'a` jumps (sets as whole branch) to bookmark \"a\".\n---   Special bookmark \"'\" always points to path before the latest bookmark jump.\n---\n--- - \"Reset\" focuses only on \"anchor\" directory (the one used to open current\n---   explorer) and resets all stored directory cursor positions.\n---\n--- - \"Reveal cwd\" extends branch to include |current-directory|.\n---   If it is not an ancestor of the current branch, nothing is done.\n---\n--- - \"Show help\" results into new window with helpful information about current\n---   explorer (like buffer mappings and bookmarks). Press `q` to close it.\n---\n--- - \"Synchronize\" parses user edits in directory buffers, applies them (after\n---   confirmation), and updates all directory buffers with the most relevant\n---   file system information. Can also be used without user edits to show up\n---   to date file system entries.\n---   See |MiniFiles-manipulation| for more info about file system manipulation.\n---\n--- - \"Trim left\" and \"Trim right\" trim parts of the whole branch, not only its\n---   currently visible parts.\n---\n--- Notes:\n---\n--- - Each action has exported function with more details about it.\n---\n--- - Keys can be configured with `mappings` table of |MiniFiles.config|.\n---@tag MiniFiles-navigation\n\n--- File system manipulation is done by editing text inside directory buffers,\n--- which are shown inside dedicated window(s). See |MiniFiles-navigation| for\n--- more information about navigating to a particular directory.\n---\n--- General workflow:\n---\n--- - Navigate to the directory in which manipulation should be done.\n---\n--- - Edit buffer in the way representing file system action.\n---\n--- - Repeat previous steps until all necessary file system actions are recorded.\n---   Note: even if directory buffer is hidden, its modifications are preserved,\n---   so you can navigate in and out of directory with modified buffer.\n---\n--- - Execute |MiniFiles.synchronize()| (default key is `=`). This will prompt\n---   confirmation dialog listing all file system actions (per directory) it is\n---   about to perform. READ IT CAREFULLY.\n---\n--- - Confirm by pressing `y` / `<CR>` (apply edits and update buffers) or\n---   don't confirm by pressing `n` / `<Esc>` (update buffers without applying edits).\n---\n--- Note: prefer small and not related steps with more frequent synchronization\n--- over single complex manipulation. There are (known) cases which won't work.\n---\n--- # How does it work ~\n---\n--- All manipulation functionality is powered by creating and keeping track of\n--- path indexes: text of the form `/xxx` (`xxx` is the number path index) placed\n--- at the start of every line representing file system entry.\n---\n--- By default they are hidden as concealed text (along with prefix separators)\n--- for more convenience but you can see them by setting |'conceallevel'| to 0.\n--- DO NOT modify text to the left of entry name.\n---\n--- During synchronization, actual text for entry name is compared to path index\n--- at that line (if present) to deduce which file system action to perform.\n--- Note that order of text manipulation steps does not affect performed actions.\n---\n--- # Supported file system actions ~\n---\n--- ## Create ~\n---\n--- - Create file by creating new line with file name (including extension).\n---\n--- - Create directory by creating new line with directory name followed by `/`.\n---\n--- - Create file or directory inside nested directories by creating new line\n---   with text like 'dir/nested-dir/' or 'dir/nested-dir/file'.\n---   Always use `/` on any OS.\n---\n--- ## Delete ~\n---\n--- - Delete file or directory by deleting **whole line** describing it.\n---\n--- - If `options.permanent_delete` is `true`, delete is permanent. Otherwise\n---   file system entry is moved to a module-specific trash directory\n---   (see |MiniFiles.config| for more details).\n---\n--- ## Rename ~\n---\n--- - Rename file or directory by editing its name (not icon or path index to\n---   the left of it).\n---\n--- - With default mappings for `h` / `l` it might be not convenient to rename\n---   only part of an entry. You can adopt any of the following approaches:\n---     - Use different motions, like |$|, |e|, |f|, etc.\n---     - Go into Insert mode and navigate inside it.\n---     - Change mappings to be more suited for manipulation and not navigation.\n---       See \"Mappings\" section in |MiniFiles.config|.\n---\n--- - It is not needed to end directory name with `/`.\n---\n--- - Appending `/` to a file name will delete it and create empty directory\n---   with the same name.\n---\n--- - Cyclic renames (\"a\" to \"b\" and \"b\" to \"a\") are not supported.\n---\n--- ## Copy ~\n---\n--- - Copy file or directory by copying **whole line** describing it and pasting\n---   it inside buffer of target directory.\n---\n--- - Change of target path is allowed. Edit only entry name in target location\n---   (not icon or path index to the left of it).\n---\n--- - Copying inside same parent directory is supported only if target path has\n---   different name.\n---\n--- - Copying inside child directory is supported.\n---\n--- ## Move ~\n---\n--- - Move file or directory by cutting **whole line** describing it and then\n---   pasting it inside target directory.\n---\n--- - Change of target path is allowed. Edit only entry name in target location\n---   (not icon or path index to the left of it).\n---\n--- - Moving directory inside itself is not supported.\n---@tag MiniFiles-manipulation\n\n--- To allow user customization and integration of external tools, certain |User|\n--- autocommand events are triggered under common circumstances.\n---\n--- # UI events ~\n---\n--- - `MiniFilesExplorerOpen` - just after explorer finishes opening.\n---\n--- - `MiniFilesExplorerClose` - just before explorer starts closing.\n---\n--- - `MiniFilesBufferCreate` - when buffer is created to show a particular\n---   directory/file. Triggered once per path during explorer session.\n---   Can be used to create buffer-local mappings.\n---\n--- - `MiniFilesBufferUpdate` - when path buffer is updated with new content.\n---   Can be used for integrations to set useful |extmarks|.\n---\n--- - `MiniFilesWindowOpen` - when new window is opened. Can be used to set\n---   window-local settings (like border, 'winblend', etc.)\n---\n--- - `MiniFilesWindowUpdate` - when a window is updated. Triggers VERY frequently.\n---   At least after every cursor movement and \"go in\" / \"go out\" action.\n---\n--- Callback for each buffer/window UI event will receive <data> field\n--- (see |nvim_create_autocmd()|) with the following information:\n---\n--- - <buf_id> - index of target buffer.\n--- - <win_id> - index of target window. Can be `nil`, like in\n---   `MiniFilesBufferCreate` and buffer's first `MiniFilesBufferUpdate` as\n---   they are triggered before window is created.\n---\n--- # File action events ~\n---\n--- - `MiniFilesActionCreate` - after entry is successfully created.\n---\n--- - `MiniFilesActionDelete` - after entry is successfully deleted.\n---\n--- - `MiniFilesActionRename` - after entry is successfully renamed.\n---\n--- - `MiniFilesActionCopy` - after entry is successfully copied.\n---\n--- - `MiniFilesActionMove` - after entry is successfully moved.\n---\n--- Callback for each file action event will receive `data` field\n--- (see |nvim_create_autocmd()|) with the following information:\n---\n--- - <action> - string with action name.\n--- - <from> - full path of entry before action (`nil` for \"create\" action).\n--- - <to> - full path of entry after action (`nil` for permanent \"delete\" action).\n---@tag MiniFiles-events\n\n--- # Toggle explorer ~\n---\n--- Use a combination of |MiniFiles.open()| and |MiniFiles.close()|: >lua\n---\n---   local minifiles_toggle = function(...)\n---     if not MiniFiles.close() then MiniFiles.open(...) end\n---   end\n--- <\n--- # Customize windows ~\n---\n--- For most of the common customizations using `MiniFilesWindowOpen` event\n--- autocommand is the suggested approach: >lua\n---\n---   vim.api.nvim_create_autocmd('User', {\n---     pattern = 'MiniFilesWindowOpen',\n---     callback = function(args)\n---       local win_id = args.data.win_id\n---\n---       -- Customize window-local settings\n---       vim.wo[win_id].winblend = 50\n---       local config = vim.api.nvim_win_get_config(win_id)\n---       config.border, config.title_pos = 'double', 'right'\n---       vim.api.nvim_win_set_config(win_id, config)\n---     end,\n---   })\n--- <\n--- However, some parts (like window title and height) of window config are later\n--- updated internally. Use `MiniFilesWindowUpdate` event for them: >lua\n---\n---   vim.api.nvim_create_autocmd('User', {\n---     pattern = 'MiniFilesWindowUpdate',\n---     callback = function(args)\n---       local config = vim.api.nvim_win_get_config(args.data.win_id)\n---\n---       -- Ensure fixed height\n---       config.height = 10\n---\n---       -- Ensure no title padding\n---       local n = #config.title\n---       config.title[1][1] = config.title[1][1]:gsub('^ ', '')\n---       config.title[n][1] = config.title[n][1]:gsub(' $', '')\n---\n---       vim.api.nvim_win_set_config(args.data.win_id, config)\n---     end,\n---   })\n--- <\n--- # Customize icons ~\n---\n--- Use different directory icon (if you don't use |mini.icons|): >lua\n---\n---   local my_prefix = function(fs_entry)\n---     if fs_entry.fs_type == 'directory' then\n---       -- NOTE: it is usually a good idea to use icon followed by space\n---       return ' ', 'MiniFilesDirectory'\n---     end\n---     return MiniFiles.default_prefix(fs_entry)\n---   end\n---\n---   require('mini.files').setup({ content = { prefix = my_prefix } })\n--- <\n--- Show no icons: >lua\n---\n---   require('mini.files').setup({ content = { prefix = function() end } })\n--- <\n--- # Create mapping to show/hide dot-files ~\n---\n--- Create an autocommand for `MiniFilesBufferCreate` event which calls\n--- |MiniFiles.refresh()| with explicit `content.filter` functions: >lua\n---\n---   local show_dotfiles = true\n---\n---   local filter_show = function(fs_entry) return true end\n---\n---   local filter_hide = function(fs_entry)\n---     return not vim.startswith(fs_entry.name, '.')\n---   end\n---\n---   local toggle_dotfiles = function()\n---     show_dotfiles = not show_dotfiles\n---     local new_filter = show_dotfiles and filter_show or filter_hide\n---     MiniFiles.refresh({ content = { filter = new_filter } })\n---   end\n---\n---   vim.api.nvim_create_autocmd('User', {\n---     pattern = 'MiniFilesBufferCreate',\n---     callback = function(args)\n---       local buf_id = args.data.buf_id\n---       -- Tweak left-hand side of mapping to your liking\n---       vim.keymap.set('n', 'g.', toggle_dotfiles, { buffer = buf_id })\n---     end,\n---   })\n--- <\n--- # Create mappings to modify target window via split ~\n---\n--- Combine |MiniFiles.get_explorer_state()| and |MiniFiles.set_target_window()|: >lua\n---\n---   local map_split = function(buf_id, lhs, direction)\n---     local rhs = function()\n---       -- Make new window and set it as target\n---       local cur_target = MiniFiles.get_explorer_state().target_window\n---       local new_target = vim.api.nvim_win_call(cur_target, function()\n---         vim.cmd(direction .. ' split')\n---         return vim.api.nvim_get_current_win()\n---       end)\n---\n---       MiniFiles.set_target_window(new_target)\n---\n---       -- This intentionally doesn't act on file under cursor in favor of\n---       -- explicit \"go in\" action (`l` / `L`). To immediately open file,\n---       -- add appropriate `MiniFiles.go_in()` call instead of this comment.\n---     end\n---\n---     -- Adding `desc` will result into `show_help` entries\n---     local desc = 'Split ' .. direction\n---     vim.keymap.set('n', lhs, rhs, { buffer = buf_id, desc = desc })\n---   end\n---\n---   vim.api.nvim_create_autocmd('User', {\n---     pattern = 'MiniFilesBufferCreate',\n---     callback = function(args)\n---       local buf_id = args.data.buf_id\n---       -- Tweak keys to your liking\n---       map_split(buf_id, '<C-s>', 'belowright horizontal')\n---       map_split(buf_id, '<C-v>', 'belowright vertical')\n---       map_split(buf_id, '<C-t>', 'tab')\n---     end,\n---   })\n--- <\n--- # Create mappings which use data from entry under cursor ~\n---\n--- Use |MiniFiles.get_fs_entry()|: >lua\n---\n---   -- Set focused directory as current working directory\n---   local set_cwd = function()\n---     local path = (MiniFiles.get_fs_entry() or {}).path\n---     if path == nil then return vim.notify('Cursor is not on valid entry') end\n---     vim.fn.chdir(vim.fs.dirname(path))\n---   end\n---\n---   -- Yank in register full path of entry under cursor\n---   local yank_path = function()\n---     local path = (MiniFiles.get_fs_entry() or {}).path\n---     if path == nil then return vim.notify('Cursor is not on valid entry') end\n---     vim.fn.setreg(vim.v.register, path)\n---   end\n---\n---   -- Open path with system default handler (useful for non-text files)\n---   local ui_open = function() vim.ui.open(MiniFiles.get_fs_entry().path) end\n---\n---   vim.api.nvim_create_autocmd('User', {\n---     pattern = 'MiniFilesBufferCreate',\n---     callback = function(args)\n---       local b = args.data.buf_id\n---       vim.keymap.set('n', 'g~', set_cwd,   { buffer = b, desc = 'Set cwd' })\n---       vim.keymap.set('n', 'gX', ui_open,   { buffer = b, desc = 'OS open' })\n---       vim.keymap.set('n', 'gy', yank_path, { buffer = b, desc = 'Yank path' })\n---     end,\n---   })\n--- <\n--- # Set custom bookmarks ~\n---\n--- Use |MiniFiles.set_bookmark()| inside `MiniFilesExplorerOpen` event: >lua\n---\n---   local set_mark = function(id, path, desc)\n---     MiniFiles.set_bookmark(id, path, { desc = desc })\n---   end\n---   vim.api.nvim_create_autocmd('User', {\n---     pattern = 'MiniFilesExplorerOpen',\n---     callback = function()\n---       set_mark('c', vim.fn.stdpath('config'), 'Config') -- path\n---       set_mark('w', vim.fn.getcwd, 'Working directory') -- callable\n---       set_mark('~', '~', 'Home directory')\n---     end,\n---   })\n--- <\n---@tag MiniFiles-examples\n\n---@diagnostic disable:luadoc-miss-type-name\n---@alias __minifiles_fs_entry_data_fields   - <fs_type> `(string)` - one of \"file\" or \"directory\".\n---   - <name> `(string)` - basename of an entry (including extension).\n---   - <path> `(string)` - full path of an entry.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n\n-- Module definition ==========================================================\nlocal MiniFiles = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniFiles.config|.\n---\n---@usage >lua\n---   require('mini.files').setup() -- use default config\n---   -- OR\n---   require('mini.files').setup({}) -- replace {} with your config table\n--- <\nMiniFiles.setup = function(config)\n  -- Export module\n  _G.MiniFiles = MiniFiles\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Content ~\n---\n--- `content.filter` is a predicate which takes file system entry data as input\n--- and returns `true`-ish value if it should be shown.\n--- Uses |MiniFiles.default_filter()| by default.\n---\n--- A file system entry data is a table with the following fields:\n--- __minifiles_fs_entry_data_fields\n---\n--- `content.highlight` describes how file system entry name should be highlighted.\n--- Takes file system entry data as input and returns a highlight group name.\n--- Uses |MiniFiles.default_highlight()| by default.\n---\n--- `content.prefix` describes what text (prefix) to show to the left of file\n--- system entry name (if any) and how to highlight it. It also takes file\n--- system entry data as input and returns tuple of text and highlight group\n--- name to be used to highlight prefix. See |MiniFiles-examples| for common\n--- examples of how to use it.\n--- Note: due to how lines are parsed to detect user edits for file system\n--- manipulation, output of `content.prefix` should not contain `/` character.\n--- Uses |MiniFiles.default_prefix()| by default.\n---\n--- `content.sort` describes in which order directory entries should be shown\n--- in directory buffer. Takes as input and returns as output an array of file\n--- system entry data. Note: technically, it can be used to filter and modify\n--- its elements as well.\n--- Uses |MiniFiles.default_sort()| by default.\n---\n--- # Mappings ~\n---\n--- `mappings` table can be used to customize buffer-local mappings created in each\n--- directory buffer for built-in actions. Entry name corresponds to the function\n--- name of the action, value - right hand side of the mapping. Supply empty\n--- string to not create a particular mapping.\n---\n--- Default mappings are mostly designed for consistent navigation experience.\n--- Here are some alternatives: >lua\n---\n---   -- Close explorer after opening file with `l`\n---   mappings = {\n---     go_in = 'L',\n---     go_in_plus = 'l',\n---   }\n---\n---   -- Don't use `h`/`l` for easier cursor navigation during text edit\n---   mappings = {\n---     go_in = 'L',\n---     go_in_plus = '',\n---     go_out = 'H',\n---     go_out_plus = '',\n---   }\n--- <\n--- # Options ~\n---\n--- `options.use_as_default_explorer` is a boolean indicating whether this module\n--- will be used as a default file explorer to edit directory (instead of `netrw`).\n--- Note: to work with directory in |arglist|, do not lazy load this module.\n---\n--- `options.permanent_delete` is a boolean indicating whether to perform\n--- permanent delete or move into special trash directory.\n--- This is a module-specific variant of \"remove to trash\".\n--- Target directory is 'mini.files/trash' inside standard path of Neovim data\n--- directory (execute `:echo stdpath('data')` to see its path in your case).\n---\n--- # Windows ~\n---\n--- `windows.max_number` is a maximum number of windows allowed to be open\n--- simultaneously. For example, use value 1 to always show single window.\n--- There is no constraint by default.\n---\n--- `windows.preview` is a boolean indicating whether to show preview of\n--- file/directory under cursor. Notes:\n--- - It is always shown, even if current line is for not yet existing path.\n--- - File preview is highlighted if its size is small enough (less than 1K\n---   bytes per line or 1M bytes in total).\n---\n--- `windows.width_focus` and `windows.width_nofocus` are number of columns used\n--- as `width` for focused and non-focused windows respectively.\nMiniFiles.config = {\n  -- Customization of shown content\n  content = {\n    -- Predicate for which file system entries to show\n    filter = nil,\n    -- Highlight group to use for a file system entry\n    highlight = nil,\n    -- Prefix text and highlight to show to the left of file system entry\n    prefix = nil,\n    -- Order in which to show file system entries\n    sort = nil,\n  },\n\n  -- Module mappings created only inside explorer.\n  -- Use `''` (empty string) to not create one.\n  mappings = {\n    close       = 'q',\n    go_in       = 'l',\n    go_in_plus  = 'L',\n    go_out      = 'h',\n    go_out_plus = 'H',\n    mark_goto   = \"'\",\n    mark_set    = 'm',\n    reset       = '<BS>',\n    reveal_cwd  = '@',\n    show_help   = 'g?',\n    synchronize = '=',\n    trim_left   = '<',\n    trim_right  = '>',\n  },\n\n  -- General options\n  options = {\n    -- Whether to delete permanently or move into module-specific trash\n    permanent_delete = true,\n    -- Whether to use for editing directories\n    use_as_default_explorer = true,\n  },\n\n  -- Customization of explorer windows\n  windows = {\n    -- Maximum number of windows to show side by side\n    max_number = math.huge,\n    -- Whether to show preview of file/directory under cursor\n    preview = false,\n    -- Width of focused window\n    width_focus = 50,\n    -- Width of non-focused window\n    width_nofocus = 15,\n    -- Width of preview window\n    width_preview = 25,\n  },\n}\n--minidoc_afterlines_end\n\n--- Open file explorer\n---\n--- Common ways to use this function: >lua\n---\n---   -- Open current working directory in a last used state\n---   MiniFiles.open()\n---\n---   -- Fresh explorer in current working directory\n---   MiniFiles.open(nil, false)\n---\n---   -- Open directory of current file (in last used state) focused on the file\n---   MiniFiles.open(vim.api.nvim_buf_get_name(0))\n---\n---   -- Fresh explorer in directory of current file\n---   MiniFiles.open(vim.api.nvim_buf_get_name(0), false)\n---\n---   -- Open last used `path` (per tabpage)\n---   -- Current working directory for the first time\n---   MiniFiles.open(MiniFiles.get_latest_path())\n--- <\n---@param path string|nil A valid file system path used as anchor.\n---   If it is a path to directory, used directly.\n---   If it is a path to file, its parent directory is used as anchor while\n---   explorer will focus on the supplied file.\n---   Default: path of |current-directory|.\n---@param use_latest boolean|nil Whether to load explorer state from history\n---   (based on the supplied anchor path). Default: `true`.\n---@param opts table|nil Table of options overriding |MiniFiles.config| and\n---   `vim.b.minifiles_config` for this particular explorer session.\nMiniFiles.open = function(path, use_latest, opts)\n  -- Validate path: allow only valid file system path\n  path = H.fs_full_path(path or vim.fn.getcwd())\n\n  local fs_type = H.fs_get_type(path)\n  if fs_type == nil then H.error('`path` is not a valid path (\"' .. path .. '\")') end\n\n  -- - Allow file path to use its parent while focusing on file\n  local entry_name\n  if fs_type == 'file' then\n    path, entry_name = H.fs_get_parent(path), H.fs_get_basename(path)\n  end\n\n  -- Validate rest of the arguments\n  if use_latest == nil then use_latest = true end\n\n  -- Properly close possibly opened in the tabpage explorer\n  local did_close = MiniFiles.close()\n  if did_close == false then return end\n\n  -- Get explorer to open\n  local explorer\n  if use_latest then explorer = H.explorer_path_history[path] end\n  explorer = explorer or H.explorer_new(path)\n\n  -- Update explorer data. Don't use current explorer's data to allow more\n  -- interactive config change by modifying global/local configs.\n  explorer.opts = H.normalize_opts(nil, opts)\n  explorer.target_window = vim.api.nvim_get_current_win()\n\n  -- Possibly focus on file entry\n  explorer = H.explorer_focus_on_entry(explorer, path, entry_name)\n\n  -- Refresh and register as opened\n  H.explorer_refresh(explorer)\n\n  -- Register latest used path\n  H.latest_paths[vim.api.nvim_get_current_tabpage()] = path\n\n  -- Track lost focus\n  H.explorer_track_lost_focus()\n\n  -- Trigger appropriate event\n  H.trigger_event('MiniFilesExplorerOpen')\nend\n\n--- Refresh explorer\n---\n--- Notes:\n--- - If in `opts` at least one of `content` entry is not `nil`, all directory\n---   buffers are forced to update.\n---\n---@param opts table|nil Table of options to update.\nMiniFiles.refresh = function(opts)\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  -- Decide whether buffers should be forcefully updated\n  local content_opts = (opts or {}).content or {}\n  local force_update = #vim.tbl_keys(content_opts) > 0\n\n  -- Confirm refresh if there is modified buffer\n  if force_update then force_update = H.explorer_ignore_pending_fs_actions(explorer, 'Update buffers') end\n\n  -- Respect explorer local options supplied inside its `open()` call but give\n  -- current `opts` higher precedence\n  explorer.opts = H.normalize_opts(explorer.opts, opts)\n\n  H.explorer_refresh(explorer, { force_update = force_update })\nend\n\n--- Synchronize explorer\n---\n--- - Parse user edits in directory buffers.\n--- - Convert edits to file system actions and apply them after confirmation.\n---   Choosing \"No\" skips application while \"Cancel\" stops synchronization.\n--- - Update all directory buffers with the most relevant file system information.\n---   Can be used without user edits to account for external file system changes.\n---\n---@return boolean Whether synchronization was done.\nMiniFiles.synchronize = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  -- Parse and apply file system operations\n  local fs_actions = H.explorer_compute_fs_actions(explorer)\n  if fs_actions ~= nil then\n    local msg = table.concat(H.fs_actions_to_lines(fs_actions), '\\n')\n    local confirm_res = vim.fn.confirm(msg, '&Yes\\n&No\\n&Cancel', 1, 'Question')\n    if confirm_res == 3 then return false end\n    if confirm_res == 1 then H.fs_actions_apply(fs_actions) end\n  end\n\n  H.explorer_refresh(explorer, { force_update = true })\n  return true\nend\n\n--- Reset explorer\n---\n--- - Show single window focused on anchor directory (which was used as first\n---   argument for |MiniFiles.open()|).\n--- - Reset all tracked directory cursors to point at first entry.\nMiniFiles.reset = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  -- Reset branch\n  explorer.branch = { explorer.anchor }\n  explorer.depth_focus = 1\n\n  -- Reset views\n  for _, view in pairs(explorer.views) do\n    view.cursor = { 1, 0 }\n  end\n\n  -- Skip update cursors, as they are already set\n  H.explorer_refresh(explorer, { skip_update_cursor = true })\nend\n\n--- Close explorer\n---\n---@return boolean|nil Whether closing was done or `nil` if there was nothing to close.\nMiniFiles.close = function()\n  -- Stop possible tracking lost focus\n  pcall(vim.loop.timer_stop, H.timers.focus)\n\n  -- Act if there is explorer to close (even invisible after improper quit)\n  local explorer = H.explorer_get(nil, true)\n  if explorer == nil then return nil end\n\n  -- Confirm close if there is modified buffer\n  if not H.explorer_ignore_pending_fs_actions(explorer, 'Close') then return false end\n\n  -- Trigger appropriate event\n  H.trigger_event('MiniFilesExplorerClose')\n\n  -- Focus on target window\n  explorer = H.explorer_ensure_target_window(explorer)\n  -- - Use `pcall()` because window might still be invalid\n  pcall(vim.api.nvim_set_current_win, explorer.target_window)\n\n  -- Update currently shown cursors\n  explorer = H.explorer_update_cursors(explorer)\n\n  -- Close shown explorer windows\n  for i, win_id in pairs(explorer.windows) do\n    H.window_close(win_id)\n    explorer.windows[i] = nil\n  end\n\n  -- Close possibly visible help window\n  for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do\n    local buf_id = vim.api.nvim_win_get_buf(win_id)\n    if vim.bo[buf_id].filetype == 'minifiles-help' then vim.api.nvim_win_close(win_id, true) end\n  end\n\n  -- Invalidate views\n  for path, view in pairs(explorer.views) do\n    explorer.views[path] = H.view_invalidate_buffer(H.view_encode_cursor(view))\n  end\n\n  -- Update histories and unmark as opened\n  local tabpage_id, anchor = vim.api.nvim_get_current_tabpage(), explorer.anchor\n  H.explorer_path_history[anchor] = explorer\n  H.opened_explorers[tabpage_id] = nil\n\n  -- Return `true` indicating success in closing\n  return true\nend\n\n--- Go in entry under cursor\n---\n--- Depends on entry under cursor:\n--- - If directory, focus on it in the window to the right.\n--- - If file, open it in the window which was current during |MiniFiles.open()|.\n---   Explorer is not closed after that.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <close_on_file> `(boolean)` - whether to close explorer after going\n---     inside a file. Powers the `go_in_plus` mapping.\n---     Default: `false`.\nMiniFiles.go_in = function(opts)\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  opts = vim.tbl_deep_extend('force', { close_on_file = false }, opts or {})\n\n  local should_close = opts.close_on_file\n  if should_close then\n    local fs_entry = MiniFiles.get_fs_entry()\n    should_close = fs_entry ~= nil and fs_entry.fs_type == 'file'\n  end\n\n  local cur_line = vim.fn.line('.')\n  explorer = H.explorer_go_in_range(explorer, vim.api.nvim_get_current_buf(), cur_line, cur_line)\n\n  H.explorer_refresh(explorer)\n\n  if should_close then MiniFiles.close() end\nend\n\n--- Go out to parent directory\n---\n--- - Focus on window to the left showing parent of current directory.\nMiniFiles.go_out = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  if explorer.depth_focus == 1 then\n    explorer = H.explorer_open_root_parent(explorer)\n  else\n    explorer.depth_focus = explorer.depth_focus - 1\n  end\n\n  H.explorer_refresh(explorer)\nend\n\n--- Trim left part of branch\n---\n--- - Remove all branch paths to the left of currently focused one. This also\n---   results into current window becoming the most left one.\nMiniFiles.trim_left = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  explorer = H.explorer_trim_branch_left(explorer)\n  H.explorer_refresh(explorer)\nend\n\n--- Trim right part of branch\n---\n--- - Remove all branch paths to the right of currently focused one. This also\n---   results into current window becoming the most right one.\nMiniFiles.trim_right = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  explorer = H.explorer_trim_branch_right(explorer)\n  H.explorer_refresh(explorer)\nend\n\n--- Reveal current working directory\n---\n--- - Prepend branch with parent paths until current working directory is reached.\n---   Do nothing if not inside it.\nMiniFiles.reveal_cwd = function()\n  local state = MiniFiles.get_explorer_state()\n  if state == nil then return end\n  local branch, depth_focus = state.branch, state.depth_focus\n\n  local cwd = H.fs_full_path(vim.fn.getcwd())\n  local cwd_ancestor_pattern = string.format('^%s/.', vim.pesc(cwd))\n  while branch[1]:find(cwd_ancestor_pattern) ~= nil do\n    table.insert(branch, 1, H.fs_get_parent(branch[1]))\n    depth_focus = depth_focus + 1\n  end\n\n  MiniFiles.set_branch(branch, { depth_focus = depth_focus })\nend\n\n--- Show help window\n---\n--- - Open window with helpful information about currently shown explorer and\n---   focus on it. To close it, press `q`.\nMiniFiles.show_help = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  local buf_id = vim.api.nvim_get_current_buf()\n  if not H.is_opened_buffer(buf_id) then return end\n\n  H.explorer_show_help(explorer, buf_id, vim.api.nvim_get_current_win())\nend\n\n--- Get file system entry data\n---\n---@param buf_id number|nil Buffer identifier of valid directory buffer.\n---   Default: current buffer.\n---@param line number|nil Line number of entry for which to return information.\n---   Default: cursor line.\n---\n---@return table|nil Table of file system entry data with the following fields:\n--- __minifiles_fs_entry_data_fields\n---\n--- Returns `nil` if there is no proper file system entry path at the line.\nMiniFiles.get_fs_entry = function(buf_id, line)\n  buf_id = H.validate_opened_buffer(buf_id)\n  line = H.validate_line(buf_id, line)\n\n  local path_id = H.match_line_path_id(H.get_bufline(buf_id, line))\n  return H.get_fs_entry_from_path_index(path_id)\nend\n\n--- Get state of active explorer\n---\n---@return table|nil Table with explorer state data or `nil` if no active explorer.\n---   State data is a table with the following fields:\n---   - <anchor> `(string)` - anchor directory path (see |MiniFiles.open()|).\n---   - <bookmarks> `(table)` - map from bookmark id (single character) to its data:\n---     table with <path> and <desc> fields (see |MiniFiles.set_bookmark()|).\n---   - <branch> `(table)` - array of nested paths for currently opened branch.\n---   - <depth_focus> `(number)` - an index in <branch> for currently focused path.\n---   - <target_window> `(number)` - identifier of target window.\n---   - <windows> `(table)` - array with data about currently opened windows.\n---     Each element is a table with <win_id> (window identifier) and <path> (path\n---     shown in the window) fields.\n---\n---@seealso - |MiniFiles.set_bookmark()|\n--- - |MiniFiles.set_branch()|\n--- - |MiniFiles.set_target_window()|\nMiniFiles.get_explorer_state = function()\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  H.explorer_ensure_target_window(explorer)\n  local windows = {}\n  for _, win_id in ipairs(explorer.windows) do\n    local buf_id = vim.api.nvim_win_get_buf(win_id)\n    local path = (H.opened_buffers[buf_id] or {}).path\n    table.insert(windows, { win_id = win_id, path = path })\n  end\n\n  return {\n    anchor = explorer.anchor,\n    bookmarks = vim.deepcopy(explorer.bookmarks),\n    branch = vim.deepcopy(explorer.branch),\n    depth_focus = explorer.depth_focus,\n    target_window = explorer.target_window,\n    windows = windows,\n  }\nend\n\n--- Set target window\n---\n---@param win_id number Window identifier inside which file will be opened.\nMiniFiles.set_target_window = function(win_id)\n  if not H.is_valid_win(win_id) then H.error('`win_id` should be valid window identifier.') end\n\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  explorer.target_window = win_id\nend\n\n--- Set branch\n---\n--- Set which paths to display. Preview (if enabled) is applied afterwards.\n---\n---@param branch table Array of strings representing actually present on disk paths.\n---   Each consecutive pair should represent direct parent-child paths.\n---   Should contain at least one directory path.\n---   May end with file path (will be previwed).\n---   Relative paths are resolved using |current-directory|.\n---@param opts table|nil Options. Possible fields:\n---   - <depth_focus> `(number)` - an index in `branch` for path to focus. Will\n---     be normalized to fit inside `branch`. Default: index of deepest directory.\n---\n---@seealso |MiniFiles.get_explorer_state()|\nMiniFiles.set_branch = function(branch, opts)\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  -- Validate and normalize input\n  branch = H.validate_branch(branch)\n  opts = opts or {}\n  local depth_focus = opts.depth_focus or math.huge\n  if type(depth_focus) ~= 'number' then H.error('`depth_focus` should be a number') end\n  local max_depth = #branch - (H.fs_get_type(branch[#branch]) == 'file' and 1 or 0)\n  depth_focus = math.min(math.max(math.floor(depth_focus), 1), max_depth)\n\n  -- Set data and ensure cursors are on child entries\n  explorer.branch, explorer.depth_focus = branch, depth_focus\n  for i = 1, #branch - 1 do\n    local parent, child = branch[i], H.fs_get_basename(branch[i + 1])\n    local parent_view = explorer.views[parent] or {}\n    parent_view.cursor = child\n    explorer.views[parent] = parent_view\n  end\n\n  -- Skip update cursors, as they are already set\n  H.explorer_refresh(explorer, { skip_update_cursor = true })\n  -- Refresh second time to ensure that preview is shown. Doing that in other\n  -- way is not really feasible, as it requires knowing cursor at deepest path,\n  -- which might not yet be set before first refresh.\n  H.explorer_refresh(explorer)\nend\n\n--- Set bookmark\n---\n---@param id string Single character bookmark id.\n---@param path string|function Path of a present on disk directory to set as\n---   a bookmark's path. If callable, should return such path.\n---@param opts table|nil Options. Possible fields:\n---   - <desc> `(string)` - bookmark description (used in help window).\nMiniFiles.set_bookmark = function(id, path, opts)\n  local explorer = H.explorer_get()\n  if explorer == nil then return end\n\n  if not (type(id) == 'string' and id:len() == 1) then H.error('Bookmark id should be single character') end\n  local is_valid_path = vim.is_callable(path)\n    or (type(path) == 'string' and H.fs_get_type(vim.fn.expand(path)) == 'directory')\n  if not is_valid_path then H.error('Bookmark path should be a valid path to directory or a callable.') end\n  opts = opts or {}\n  if not (opts.desc == nil or type(opts.desc) == 'string') then H.error('Bookmark description should be string') end\n\n  explorer.bookmarks[id] = { path = path, desc = opts.desc }\nend\n\n--- Get latest used anchor path\n---\n--- Note: if latest used `path` argument for |MiniFiles.open()| was for file,\n--- this will return its parent (as it was used as anchor path).\nMiniFiles.get_latest_path = function() return H.latest_paths[vim.api.nvim_get_current_tabpage()] end\n\n--- Default filter of file system entries\n---\n--- Currently does not filter anything out.\n---\n---@param fs_entry table Table with the following fields:\n--- __minifiles_fs_entry_data_fields\n---\n---@return boolean Always `true`.\nMiniFiles.default_filter = function(fs_entry) return true end\n\n--- Default prefix of file system entries\n---\n--- - If set up |mini.icons|, use |MiniIcons.get()| for \"directory\"/\"file\" category.\n--- - Otherwise:\n---     - For directory return fixed icon and \"MiniFilesDirectory\" group name.\n---     - For file try to use `get_icon()` from 'nvim-tree/nvim-web-devicons'.\n---       If missing, return fixed icon and 'MiniFilesFile' group name.\n---\n---@param fs_entry table Table with the following fields:\n--- __minifiles_fs_entry_data_fields\n---\n---@return ... Icon and highlight group name. For more details, see |MiniFiles.config|\n---   and |MiniFiles-examples|.\nMiniFiles.default_prefix = function(fs_entry)\n  -- Prefer 'mini.icons'\n  if _G.MiniIcons ~= nil then\n    local category = fs_entry.fs_type == 'directory' and 'directory' or 'file'\n    local icon, hl = _G.MiniIcons.get(category, fs_entry.path)\n    return icon .. ' ', hl\n  end\n\n  -- Try falling back to 'nvim-web-devicons'\n  if fs_entry.fs_type == 'directory' then return ' ', 'MiniFilesDirectory' end\n  local has_devicons, devicons = pcall(require, 'nvim-web-devicons')\n  if not has_devicons then return ' ', 'MiniFilesFile' end\n\n  local icon, hl = devicons.get_icon(fs_entry.name, nil, { default = false })\n  return (icon or '') .. ' ', hl or 'MiniFilesFile'\nend\n\n--- Default sort of file system entries\n---\n--- Sort directories and files separately (alphabetically ignoring case) and\n--- put directories first.\n---\n---@param fs_entries table Array of file system entry data.\n---   Each one is a table with the following fields:\n--- __minifiles_fs_entry_data_fields\n---\n---@return table Sorted array of file system entries.\nMiniFiles.default_sort = function(fs_entries)\n  -- Sort ignoring case\n  local res = vim.tbl_map(\n    function(x)\n      return {\n        fs_type = x.fs_type,\n        name = x.name,\n        path = x.path,\n        lower_name = x.name:lower(),\n        is_dir = x.fs_type == 'directory',\n      }\n    end,\n    fs_entries\n  )\n\n  -- Sort based on default order\n  table.sort(res, H.compare_fs_entries)\n\n  return vim.tbl_map(function(x) return { name = x.name, fs_type = x.fs_type, path = x.path } end, res)\nend\n\n--- Default file system entry highlight\n---\n--- Returns `'MiniFilesDirectory'` for directory and `'MiniFilesFile'` otherwise.\n---\n---@param fs_entry table Table with the following fields:\n--- __minifiles_fs_entry_data_fields\n---\n---@return string Highlight group name.\nMiniFiles.default_highlight = function(fs_entry)\n  return fs_entry.fs_type == 'directory' and 'MiniFilesDirectory' or 'MiniFilesFile'\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniFiles.config)\n\n-- Namespaces\nH.ns_id = {\n  highlight = vim.api.nvim_create_namespace('MiniFilesHighlight'),\n}\n\n-- Timers\nH.timers = {\n  focus = vim.loop.new_timer(),\n}\n\n-- Index of all visited files\nH.path_index = {}\n\n-- History of explorers per root directory\nH.explorer_path_history = {}\n\n-- Register of opened explorers per tabpage\nH.opened_explorers = {}\n\n-- Register of latest used paths per tabpage\nH.latest_paths = {}\n\n-- Register of opened buffer data for quick access. Tables per buffer id:\n-- - <path> - path which contents this buffer displays.\n-- - <children_path_ids> - array of shown children path ids.\n-- - <win_id> - id of window this buffer is shown. Can be `nil`.\n-- - <n_modified> - number of modifications since last update from this module.\n--   Values bigger than 0 can be treated as if buffer was modified by user.\n--   It uses number instead of boolean to overcome `TextChanged` event on\n--   initial `buf_set_lines` (`noautocmd` doesn't quick work for this event).\nH.opened_buffers = {}\n\n-- File system information\nH.is_windows = vim.loop.os_uname().sysname == 'Windows_NT'\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('content', config.content, 'table')\n  H.check_type('content.filter', config.content.filter, 'function', true)\n  H.check_type('content.highlight', config.content.highlight, 'function', true)\n  H.check_type('content.prefix', config.content.prefix, 'function', true)\n  H.check_type('content.sort', config.content.sort, 'function', true)\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.close', config.mappings.close, 'string')\n  H.check_type('mappings.go_in', config.mappings.go_in, 'string')\n  H.check_type('mappings.go_in_plus', config.mappings.go_in_plus, 'string')\n  H.check_type('mappings.go_out', config.mappings.go_out, 'string')\n  H.check_type('mappings.go_out_plus', config.mappings.go_out_plus, 'string')\n  H.check_type('mappings.mark_goto', config.mappings.mark_goto, 'string')\n  H.check_type('mappings.mark_set', config.mappings.mark_set, 'string')\n  H.check_type('mappings.reset', config.mappings.reset, 'string')\n  H.check_type('mappings.reveal_cwd', config.mappings.reveal_cwd, 'string')\n  H.check_type('mappings.show_help', config.mappings.show_help, 'string')\n  H.check_type('mappings.synchronize', config.mappings.synchronize, 'string')\n  H.check_type('mappings.trim_left', config.mappings.trim_left, 'string')\n  H.check_type('mappings.trim_right', config.mappings.trim_right, 'string')\n\n  H.check_type('options', config.options, 'table')\n  H.check_type('options.use_as_default_explorer', config.options.use_as_default_explorer, 'boolean')\n  H.check_type('options.permanent_delete', config.options.permanent_delete, 'boolean')\n\n  H.check_type('windows', config.windows, 'table')\n  H.check_type('windows.max_number', config.windows.max_number, 'number')\n  H.check_type('windows.preview', config.windows.preview, 'boolean')\n  H.check_type('windows.width_focus', config.windows.width_focus, 'number')\n  H.check_type('windows.width_nofocus', config.windows.width_nofocus, 'number')\n  H.check_type('windows.width_preview', config.windows.width_preview, 'number')\n\n  return config\nend\n\nH.apply_config = function(config) MiniFiles.config = config end\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniFiles', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  if config.options.use_as_default_explorer then\n    -- Stop 'netrw' from showing. Needs `VimEnter` event autocommand if\n    -- this is called prior 'netrw' is set up\n    vim.cmd('silent! autocmd! FileExplorer *')\n    vim.cmd('autocmd VimEnter * ++once silent! autocmd! FileExplorer *')\n\n    au('BufEnter', '*', H.track_dir_edit, 'Track directory edit')\n  end\n\n  au('VimResized', '*', MiniFiles.refresh, 'Refresh on resize')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  hi('MiniFilesBorder',         { link = 'FloatBorder' })\n  hi('MiniFilesBorderModified', { link = 'DiagnosticFloatingWarn' })\n  hi('MiniFilesCursorLine',     { link = 'CursorLine' })\n  hi('MiniFilesDirectory',      { link = 'Directory'   })\n  hi('MiniFilesFile',           {})\n  hi('MiniFilesNormal',         { link = 'NormalFloat' })\n  hi('MiniFilesTitle',          { link = 'FloatTitle'  })\n  hi('MiniFilesTitleFocused',   { link = 'FloatTitle' })\nend\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniFiles.config, vim.b.minifiles_config or {}, config or {})\nend\n\nH.normalize_opts = function(explorer_opts, opts)\n  opts = vim.tbl_deep_extend('force', H.get_config(), explorer_opts or {}, opts or {})\n  opts.content.filter = opts.content.filter or MiniFiles.default_filter\n  opts.content.highlight = opts.content.highlight or MiniFiles.default_highlight\n  opts.content.prefix = opts.content.prefix or MiniFiles.default_prefix\n  opts.content.sort = opts.content.sort or MiniFiles.default_sort\n\n  return opts\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.track_dir_edit = function(data)\n  -- Make early returns\n  if vim.api.nvim_get_current_buf() ~= data.buf then return end\n\n  if vim.b.minifiles_processed_dir then\n    -- Smartly delete directory buffer if already visited\n    local alt_buf = vim.fn.bufnr('#')\n    -- - Setting alternative buffer is enough for the \"directory buffer\" to be\n    -- wiped out, as it has `bufhidden=wipe`. Forcing delete after showing alt\n    -- buffer might result in hard-to-track errors (like when opening directory\n    -- in 'mini.pick' when there is an altbuf for the buffer in target window).\n    if alt_buf ~= data.buf and vim.fn.buflisted(alt_buf) == 1 then return vim.api.nvim_win_set_buf(0, alt_buf) end\n    return vim.api.nvim_buf_delete(data.buf, { force = true })\n  end\n\n  local path = vim.api.nvim_buf_get_name(0)\n  if vim.fn.isdirectory(path) ~= 1 then return end\n\n  -- Make directory buffer disappear when it is not needed\n  vim.bo.bufhidden = 'wipe'\n  vim.b.minifiles_processed_dir = true\n\n  -- Open directory without history\n  vim.schedule(function() MiniFiles.open(path, false) end)\nend\n\n-- Explorers ------------------------------------------------------------------\n---@class Explorer\n---\n---@field bookmarks table Map from single characters to bookmark data: table\n---   with <path> and <desc> fields.\n---@field branch table Array of absolute directory paths from parent to child.\n---   Its ids are called depth.\n---@field depth_focus number Depth to focus.\n---@field views table Views for paths. Each view is a table with:\n---   - <buf_id> where to show directory content.\n---   - <was_focused> - whether buffer was focused during current session.\n---   - <cursor> to position cursor; can be:\n---       - `{ line, col }` table to set cursor when buffer changes window.\n---       - `entry_name` string entry name to find inside directory buffer.\n---@field windows table Array of currently opened window ids (left to right).\n---@field anchor string Anchor directory of the explorer. Used as index in\n---   history and for `reset()` operation.\n---@field target_window number Id of window in which files will be opened.\n---@field opts table Options used for this particular explorer.\n---@field is_corrupted boolean Whether this particular explorer can not be\n---   normalized and should be closed.\n---@private\nH.explorer_new = function(path)\n  return {\n    branch = { path },\n    depth_focus = 1,\n    views = {},\n    windows = {},\n    anchor = path,\n    target_window = vim.api.nvim_get_current_win(),\n    bookmarks = {},\n    opts = {},\n  }\nend\n\nH.explorer_get = function(tabpage_id, ignore_visibility)\n  tabpage_id = tabpage_id or vim.api.nvim_get_current_tabpage()\n  local res = H.opened_explorers[tabpage_id]\n\n  if ignore_visibility or H.explorer_is_visible(res) then return res end\n\n  H.opened_explorers[tabpage_id] = nil\n  return nil\nend\n\nH.explorer_is_visible = function(explorer)\n  if explorer == nil then return nil end\n  for _, win_id in ipairs(explorer.windows) do\n    if H.is_valid_win(win_id) then return true end\n  end\n  return false\nend\n\nH.explorer_refresh = function(explorer, opts)\n  explorer = H.explorer_normalize(explorer)\n  if explorer.is_corrupted then\n    -- Make sure that same explorer can be opened later from history\n    explorer.is_corrupted = false\n    MiniFiles.close()\n    return\n  end\n  if #explorer.branch == 0 then return end\n  opts = opts or {}\n\n  -- Update cursor data in shown views. Do this prior to buffer updates for\n  -- cursors to \"stick\" to current items.\n  if not opts.skip_update_cursor then explorer = H.explorer_update_cursors(explorer) end\n\n  -- Ensure no outdated views\n  for path, view in pairs(explorer.views) do\n    if not H.fs_is_present_path(path) then\n      H.buffer_delete(view.buf_id)\n      explorer.views[path] = nil\n    end\n  end\n\n  -- Possibly force content updates on all explorer buffers. Doing it for *all*\n  -- of them and not only on modified ones to allow sync changes from outside.\n  if opts.force_update then\n    for path, view in pairs(explorer.views) do\n      -- Encode cursors to allow them to \"stick\" to current entry\n      view = H.view_encode_cursor(view)\n      -- Force update of shown path ids\n      if H.opened_buffers[view.buf_id] then H.opened_buffers[view.buf_id].children_path_ids = nil end\n      H.buffer_update(view.buf_id, path, explorer.opts, not view.was_focused)\n      explorer.views[path] = view\n    end\n  end\n\n  -- Make sure that cursors point at paths to their right.\n  -- NOTE: Doing this here and not relying on `CursorMoved` autocommand ensures\n  -- that no more windows are opened than necessary (reduces flickering).\n  for depth = 1, #explorer.branch do\n    explorer = H.explorer_sync_cursor_and_branch(explorer, depth)\n  end\n\n  -- Unregister windows from showed buffers, as they might get outdated\n  for _, win_id in ipairs(explorer.windows) do\n    -- NOTE: window can be invalid if it was showing buffer that was deleted\n    if H.is_valid_win(win_id) then\n      local buf_id = vim.api.nvim_win_get_buf(win_id)\n      H.opened_buffers[buf_id].win_id = nil\n    end\n  end\n\n  -- Compute depth range which is possible to show in current window\n  local depth_range = H.compute_visible_depth_range(explorer, explorer.opts)\n\n  -- Refresh window for every target depth keeping track of position column\n  local cur_win_col, cur_win_count = 0, 0\n  for depth = depth_range.from, depth_range.to do\n    cur_win_count = cur_win_count + 1\n    local cur_width = H.explorer_refresh_depth_window(explorer, depth, cur_win_count, cur_win_col)\n\n    -- Add 2 to account for left and right borders\n    cur_win_col = cur_win_col + cur_width + 2\n  end\n\n  -- Close possibly opened window that don't fit (like after `VimResized`)\n  for depth = cur_win_count + 1, #explorer.windows do\n    H.window_close(explorer.windows[depth])\n    explorer.windows[depth] = nil\n  end\n\n  -- Focus on proper window\n  local win_focus_count = explorer.depth_focus - depth_range.from + 1\n  local win_id_focused = explorer.windows[win_focus_count]\n  H.window_focus(win_id_focused)\n\n  -- Register as currently opened\n  local tabpage_id = vim.api.nvim_win_get_tabpage(win_id_focused)\n  H.opened_explorers[tabpage_id] = explorer\n\n  return explorer\nend\n\nH.explorer_track_lost_focus = function()\n  local track = vim.schedule_wrap(function()\n    local ft = vim.bo.filetype\n    if ft == 'minifiles' or ft == 'minifiles-help' then return end\n    local cur_win_id = vim.api.nvim_get_current_win()\n    MiniFiles.close()\n    pcall(vim.api.nvim_set_current_win, cur_win_id)\n  end)\n  H.timers.focus:start(1000, 1000, track)\nend\n\nH.explorer_normalize = function(explorer)\n  -- Ensure that all paths from branch are valid present paths\n  local norm_branch = {}\n  for _, path in ipairs(explorer.branch) do\n    if not H.fs_is_present_path(path) then break end\n    table.insert(norm_branch, path)\n  end\n\n  local cur_max_depth = #norm_branch\n\n  explorer.branch = norm_branch\n  explorer.depth_focus = math.min(math.max(explorer.depth_focus, 1), cur_max_depth)\n\n  -- Close all guaranteed to be unnecessary windows. NOTE: some windows might\n  -- still get outdated later if branch is too deep to fit into Neovim's width.\n  for i = cur_max_depth + 1, #explorer.windows do\n    H.window_close(explorer.windows[i])\n    explorer.windows[i] = nil\n  end\n\n  -- Compute if explorer is corrupted and should not operate further\n  for _, win_id in pairs(explorer.windows) do\n    if not H.is_valid_win(win_id) then explorer.is_corrupted = true end\n  end\n\n  return explorer\nend\n\nH.explorer_sync_cursor_and_branch = function(explorer, depth)\n  -- Compute helper data while making early returns\n  if #explorer.branch < depth then return explorer end\n\n  local path, path_to_right = explorer.branch[depth], explorer.branch[depth + 1]\n  local view = explorer.views[path]\n  if view == nil then return explorer end\n\n  local buf_id, cursor = view.buf_id, view.cursor\n  if cursor == nil then return explorer end\n\n  -- Compute if path at cursor and path to the right are equal (in sync)\n  local cursor_path\n  if type(cursor) == 'table' and H.is_valid_buf(buf_id) then\n    local l = H.get_bufline(buf_id, cursor[1])\n    -- Fall back to treating current line as full basename, but for not yet\n    -- existing (a.k.a. \"imaginary\") path keep showing preview.\n    cursor_path = H.path_index[H.match_line_path_id(l)] or H.fs_child_path(path, l .. '\\000')\n  elseif type(cursor) == 'string' then\n    cursor_path = H.fs_child_path(path, cursor)\n  else\n    return explorer\n  end\n\n  if cursor_path == path_to_right then return explorer end\n\n  -- Trim branch if cursor path is not in sync with path to the right\n  for i = depth + 1, #explorer.branch do\n    explorer.branch[i] = nil\n  end\n  explorer.depth_focus = math.min(explorer.depth_focus, #explorer.branch)\n\n  -- Show preview to the right of current buffer if needed\n  local show_preview = explorer.opts.windows.preview\n  local is_cur_buf = explorer.depth_focus == depth\n  if show_preview and is_cur_buf then table.insert(explorer.branch, cursor_path) end\n\n  return explorer\nend\n\nH.explorer_go_in_range = function(explorer, buf_id, from_line, to_line)\n  -- Compute which entries to go in: all files and only last directory\n  local files, path, line = {}, nil, nil\n  for i = from_line, to_line do\n    local fs_entry = MiniFiles.get_fs_entry(buf_id, i) or {}\n    if fs_entry.fs_type == 'file' then table.insert(files, fs_entry.path) end\n    if fs_entry.fs_type == 'directory' then\n      path, line = fs_entry.path, i\n    end\n    if fs_entry.fs_type == nil and fs_entry.path == nil then\n      local entry = vim.inspect(H.get_bufline(buf_id, i))\n      H.notify('Line ' .. entry .. ' does not have proper format. Did you modify without synchronization?', 'WARN')\n    end\n    if fs_entry.fs_type == nil and fs_entry.path ~= nil then\n      local path_resolved = vim.fn.resolve(fs_entry.path)\n      local symlink_info = path_resolved == fs_entry.path and ''\n        or (' Looks like miscreated symlink (resolved to ' .. path_resolved .. ').')\n      H.notify('Path ' .. fs_entry.path .. ' is not present on disk.' .. symlink_info, 'WARN')\n    end\n  end\n\n  for _, file_path in ipairs(files) do\n    explorer = H.explorer_open_file(explorer, file_path)\n  end\n\n  if path ~= nil then\n    explorer = H.explorer_open_directory(explorer, path, explorer.depth_focus + 1)\n\n    -- Ensure that cursor points to the directory in current window (can be not\n    -- the case if cursor is not on the actually opened directory)\n    local win_id = H.opened_buffers[buf_id].win_id\n    if H.is_valid_win(win_id) then vim.api.nvim_win_set_cursor(win_id, { line, 0 }) end\n  end\n\n  return explorer\nend\n\nH.explorer_focus_on_entry = function(explorer, path, entry_name)\n  if entry_name == nil then return explorer end\n\n  -- Set focus on directory. Reset if it is not in current branch.\n  explorer.depth_focus = H.explorer_get_path_depth(explorer, path)\n  if explorer.depth_focus == nil then\n    explorer.branch, explorer.depth_focus = { path }, 1\n  end\n\n  -- Set cursor on entry\n  local path_view = explorer.views[path] or {}\n  path_view.cursor = entry_name\n  explorer.views[path] = path_view\n\n  return explorer\nend\n\nH.explorer_compute_fs_actions = function(explorer)\n  -- Compute differences\n  local fs_diffs = {}\n  for _, view in pairs(explorer.views) do\n    local dir_fs_diff = H.buffer_compute_fs_diff(view.buf_id)\n    if #dir_fs_diff > 0 then vim.list_extend(fs_diffs, dir_fs_diff) end\n  end\n  if #fs_diffs == 0 then return nil end\n\n  -- Convert differences into actions\n  local create, delete_map, raw_copy = {}, {}, {}\n\n  -- - Differentiate between create, delete, and copy\n  for _, diff in ipairs(fs_diffs) do\n    if diff.from == nil then\n      table.insert(create, { action = 'create', dir = diff.dir, to = diff.to })\n    elseif diff.to == nil then\n      delete_map[diff.from] = true\n    else\n      table.insert(raw_copy, diff)\n    end\n  end\n\n  -- - Narrow down copy action into rename or move: `delete + copy` is `rename`\n  --   if in same directory and `move` otherwise\n  local rename, move, copy = {}, {}, {}\n  for _, diff in pairs(raw_copy) do\n    local action, target = 'copy', copy\n    if delete_map[diff.from] then\n      -- Treat appending `/` to file name as file -> directory conversion\n      -- (i.e. delete file + create directory)\n      if diff.to == (diff.from .. '/') and H.fs_get_type(diff.from) == 'file' then\n        target, action, diff.from = create, 'create', nil\n      else\n        action = H.fs_get_parent(diff.from) == H.fs_get_parent(diff.to) and 'rename' or 'move'\n        target = action == 'rename' and rename or move\n        -- NOTE: Use map instead of array to ensure single move/rename per path\n        delete_map[diff.from] = nil\n      end\n    end\n    table.insert(target, { action = action, dir = diff.dir, from = diff.from, to = diff.to })\n  end\n\n  -- Compute delete actions accounting for (non) permanent delete\n  local delete, is_trash = {}, not explorer.opts.options.permanent_delete\n  local trash_dir = H.fs_child_path(vim.fn.stdpath('data'), 'mini.files/trash')\n  for p, _ in pairs(delete_map) do\n    local to = is_trash and H.fs_child_path(trash_dir, H.fs_get_basename(p)) or nil\n    table.insert(delete, { action = 'delete', from = p, to = to })\n  end\n\n  -- Construct final array with proper order of actions:\n  -- - If action depends on the path which will be deleted, perform it first.\n  -- - \"Delete\"/\"move\"/\"rename\" before \"copy\"/\"create\" to free space for them.\n  -- - Move/rename (if successful) will later adjust next steps at execution.\n  local before_delete, after_delete = {}, {}\n  for _, arr in ipairs({ move, rename, copy, create }) do\n    for _, diff in ipairs(arr) do\n      local will_be_deleted = false\n      for _, del in ipairs(delete) do\n        local del_from_dir = del.from .. '/'\n        local from_is_affected = del.from == diff.from or vim.startswith(diff.from or '', del_from_dir)\n        -- Don't directly account for deleted path to allow \"act on freed path\"\n        -- But make \"append `/` to file\" work as \"delete file\" + \"create dir\"\n        local to_is_affected = vim.startswith(diff.to, del_from_dir) and diff.to ~= del_from_dir\n        will_be_deleted = will_be_deleted or from_is_affected or to_is_affected\n      end\n      table.insert(will_be_deleted and before_delete or after_delete, diff)\n    end\n  end\n\n  local res = {}\n  vim.list_extend(res, before_delete)\n  vim.list_extend(res, delete)\n  vim.list_extend(res, after_delete)\n  return res\nend\n\nH.explorer_update_cursors = function(explorer)\n  for _, win_id in ipairs(explorer.windows) do\n    if H.is_valid_win(win_id) then\n      local buf_id = vim.api.nvim_win_get_buf(win_id)\n      local path = H.opened_buffers[buf_id].path\n      explorer.views[path].cursor = vim.api.nvim_win_get_cursor(win_id)\n    end\n  end\n\n  return explorer\nend\n\nH.explorer_refresh_depth_window = function(explorer, depth, win_count, win_col)\n  local path = explorer.branch[depth]\n  local views, windows, opts = explorer.views, explorer.windows, explorer.opts\n\n  -- Compute width based on window role\n  local win_is_focused = depth == explorer.depth_focus\n  local win_is_preview = opts.windows.preview and (depth == (explorer.depth_focus + 1))\n  local cur_width = win_is_focused and opts.windows.width_focus\n    or (win_is_preview and opts.windows.width_preview or opts.windows.width_nofocus)\n\n  -- Prepare target view\n  local view = views[path] or {}\n  view = H.view_ensure_proper(view, path, opts, win_is_focused, win_is_preview)\n  views[path] = view\n\n  -- Create relevant window config\n  local config = {\n    col = win_col,\n    height = vim.api.nvim_buf_line_count(view.buf_id),\n    width = cur_width,\n    -- Use shortened full path in left most window\n    title = win_count == 1 and H.fs_shorten_path(H.fs_full_path(path)) or H.fs_get_basename(path),\n  }\n  config.title = ' ' .. H.sanitize_string(config.title) .. ' '\n\n  -- Prepare and register window\n  local win_id = windows[win_count]\n  if not H.is_valid_win(win_id) then\n    H.window_close(win_id)\n    win_id = H.window_open(view.buf_id, config)\n    windows[win_count] = win_id\n  end\n\n  H.window_update(win_id, config)\n\n  -- Show view in window\n  H.window_set_view(win_id, view)\n\n  -- Trigger dedicated event\n  H.trigger_event('MiniFilesWindowUpdate', { buf_id = vim.api.nvim_win_get_buf(win_id), win_id = win_id })\n\n  -- Update explorer data\n  explorer.views = views\n  explorer.windows = windows\n\n  -- Return width of current window to keep track of window column\n  return cur_width\nend\n\nH.explorer_get_path_depth = function(explorer, path)\n  for depth, depth_path in pairs(explorer.branch) do\n    if path == depth_path then return depth end\n  end\nend\n\nH.explorer_ignore_pending_fs_actions = function(explorer, action_name)\n  -- Exit if nothing to ignore\n  if H.explorer_compute_fs_actions(explorer) == nil then return true end\n\n  local msg = string.format('There are pending file system actions\\n\\n%s without synchronization?', action_name)\n  local confirm_res = vim.fn.confirm(msg, '&Yes\\n&No', 1, 'Question')\n  return confirm_res == 1\nend\n\nH.explorer_open_file = function(explorer, path)\n  explorer = H.explorer_ensure_target_window(explorer)\n  H.edit(path, explorer.target_window)\n  return explorer\nend\n\nH.explorer_ensure_target_window = function(explorer)\n  if not H.is_valid_win(explorer.target_window) then explorer.target_window = H.get_first_valid_normal_window() end\n  return explorer\nend\n\nH.explorer_open_directory = function(explorer, path, target_depth)\n  -- Update focused depth\n  explorer.depth_focus = target_depth\n\n  -- Truncate rest of the branch if opening another path at target depth\n  local show_new_path_at_depth = path ~= explorer.branch[target_depth]\n  if show_new_path_at_depth then\n    explorer.branch[target_depth] = path\n    explorer = H.explorer_trim_branch_right(explorer)\n  end\n\n  return explorer\nend\n\nH.explorer_open_root_parent = function(explorer)\n  local root = explorer.branch[1]\n  local root_parent = H.fs_get_parent(root)\n  if root_parent == nil then return explorer end\n\n  -- Update branch data\n  table.insert(explorer.branch, 1, root_parent)\n\n  -- Focus on previous root entry in its parent\n  return H.explorer_focus_on_entry(explorer, root_parent, H.fs_get_basename(root))\nend\n\nH.explorer_trim_branch_right = function(explorer)\n  for i = explorer.depth_focus + 1, #explorer.branch do\n    explorer.branch[i] = nil\n  end\n  return explorer\nend\n\nH.explorer_trim_branch_left = function(explorer)\n  local new_branch = {}\n  for i = explorer.depth_focus, #explorer.branch do\n    table.insert(new_branch, explorer.branch[i])\n  end\n  explorer.branch = new_branch\n  explorer.depth_focus = 1\n  return explorer\nend\n\nH.explorer_show_help = function(explorer, explorer_buf_id, explorer_win_id)\n  -- Compute lines\n  local buf_mappings = vim.api.nvim_buf_get_keymap(explorer_buf_id, 'n')\n  local map_data, desc_width = {}, 0\n  for _, data in ipairs(buf_mappings) do\n    if data.desc ~= nil then\n      map_data[data.desc] = data.lhs:lower() == '<lt>' and '<' or data.lhs\n      desc_width = math.max(desc_width, data.desc:len())\n    end\n  end\n\n  local desc_arr = vim.tbl_keys(map_data)\n  table.sort(desc_arr)\n  local map_format = string.format('%%-%ds │ %%s', desc_width)\n\n  local lines = { 'Buffer mappings:', '' }\n  for _, desc in ipairs(desc_arr) do\n    table.insert(lines, string.format(map_format, desc, map_data[desc]))\n  end\n  table.insert(lines, '')\n\n  local bookmark_ids = vim.tbl_keys(explorer.bookmarks)\n  if #bookmark_ids > 0 then\n    table.insert(lines, 'Bookmarks:')\n    table.insert(lines, '')\n    table.sort(bookmark_ids)\n    for _, id in ipairs(bookmark_ids) do\n      local data = explorer.bookmarks[id]\n      local desc = data.desc or (vim.is_callable(data.path) and data.path() or data.path)\n      table.insert(lines, id .. ' │ ' .. desc)\n    end\n    table.insert(lines, '')\n  end\n\n  table.insert(lines, '(Press `q` to close)')\n\n  -- Create buffer\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  H.set_buflines(buf_id, lines)\n  H.set_buf_name(buf_id, 'help')\n\n  vim.keymap.set('n', 'q', '<Cmd>close<CR>', { buffer = buf_id, desc = 'Close this window' })\n\n  vim.b[buf_id].minicursorword_disable = true\n  vim.b[buf_id].miniindentscope_disable = true\n\n  vim.bo[buf_id].filetype = 'minifiles-help'\n  vim.bo[buf_id].bufhidden = 'wipe'\n\n  -- Compute window data\n  local line_widths = vim.tbl_map(vim.fn.strdisplaywidth, lines)\n  local max_line_width = math.max(unpack(line_widths))\n\n  local config = vim.api.nvim_win_get_config(explorer_win_id)\n  config.relative = 'win'\n  config.row = 0\n  config.col = 0\n  config.width = max_line_width\n  config.height = #lines\n  config.title = \" 'mini.files' help \"\n  config.zindex = config.zindex + 1\n  local default_border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil\n  config.border = config.border or default_border\n  config.style = 'minimal'\n\n  -- Open window\n  local win_id = vim.api.nvim_open_win(buf_id, false, config)\n  H.window_update_highlight(win_id, 'NormalFloat', 'MiniFilesNormal')\n  H.window_update_highlight(win_id, 'FloatTitle', 'MiniFilesTitle')\n  H.window_update_highlight(win_id, 'CursorLine', 'MiniFilesCursorLine')\n  vim.wo[win_id].cursorline = true\n  local culopt = vim.wo[win_id].cursorlineopt\n  if culopt:find('line') == nil then vim.wo[win_id].cursorlineopt = culopt .. ',line' end\n\n  vim.api.nvim_set_current_win(win_id)\n  return win_id\nend\n\nH.compute_visible_depth_range = function(explorer, opts)\n  -- Compute maximum number of windows possible to fit in current Neovim width\n  -- Add 2 to widths to take into account width of left and right borders\n  local width_focus, width_nofocus = opts.windows.width_focus + 2, opts.windows.width_nofocus + 2\n\n  local has_preview = explorer.opts.windows.preview and explorer.depth_focus < #explorer.branch\n  local width_preview = has_preview and (opts.windows.width_preview + 2) or width_nofocus\n\n  local max_number = 1\n  if (width_focus + width_preview) <= vim.o.columns then max_number = max_number + 1 end\n  if (width_focus + width_preview + width_nofocus) <= vim.o.columns then\n    max_number = max_number + math.floor((vim.o.columns - width_focus - width_preview) / width_nofocus)\n  end\n\n  -- - Account for dedicated option\n  max_number = math.min(math.max(max_number, 1), opts.windows.max_number)\n\n  -- Compute which branch entries to show with the following idea:\n  -- - Always show focused depth as centered as possible.\n  -- - Show as much as possible.\n  -- Logic is similar to how text for 'mini.tabline' is computed.\n  local branch_depth, depth_focus = #explorer.branch, explorer.depth_focus\n  local n_panes = math.min(branch_depth, max_number)\n\n  local to = math.min(branch_depth, math.floor(depth_focus + 0.5 * n_panes))\n  local from = math.max(1, to - n_panes + 1)\n  to = from + math.min(n_panes, branch_depth) - 1\n\n  return { from = from, to = to }\nend\n\n-- Views ----------------------------------------------------------------------\nH.view_ensure_proper = function(view, path, opts, is_focused, is_preview)\n  -- Ensure proper buffer\n  local needs_recreate, needs_reprocess = not H.is_valid_buf(view.buf_id), not view.was_focused and is_focused\n  if needs_recreate then\n    H.buffer_delete(view.buf_id)\n    view.buf_id = H.buffer_create(path, opts.mappings)\n  end\n  if needs_recreate or needs_reprocess then\n    -- Make sure that pressing `u` in new buffer does nothing\n    local cache_undolevels = vim.bo[view.buf_id].undolevels\n    vim.bo[view.buf_id].undolevels = -1\n    H.buffer_update(view.buf_id, path, opts, is_preview)\n    vim.bo[view.buf_id].undolevels = cache_undolevels\n  end\n  view.was_focused = view.was_focused or is_focused\n\n  -- Ensure proper cursor. If string, find it as line in current buffer.\n  view.cursor = view.cursor or { 1, 0 }\n  if type(view.cursor) == 'string' then view = H.view_decode_cursor(view) end\n\n  return view\nend\n\nH.view_encode_cursor = function(view)\n  local buf_id, cursor = view.buf_id, view.cursor\n  if not H.is_valid_buf(buf_id) or type(cursor) ~= 'table' then return view end\n\n  -- Replace exact cursor coordinates with entry name to try and find later.\n  -- This allows more robust opening explorer from history (as directory\n  -- content may have changed and exact cursor position would be not valid).\n  local l = H.get_bufline(buf_id, cursor[1])\n  view.cursor = H.match_line_entry_name(l)\n  return view\nend\n\nH.view_decode_cursor = function(view)\n  local buf_id, cursor = view.buf_id, view.cursor\n  if not H.is_valid_buf(buf_id) or type(cursor) ~= 'string' then return view end\n\n  -- Find entry name named as stored in `cursor`. If not - use {1, 0}.\n  local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)\n  for i, l in ipairs(lines) do\n    if cursor == H.match_line_entry_name(l) then view.cursor = { i, 0 } end\n  end\n\n  if type(view.cursor) ~= 'table' then view.cursor = { 1, 0 } end\n\n  return view\nend\n\nH.view_invalidate_buffer = function(view)\n  H.buffer_delete(view.buf_id)\n  view.buf_id = nil\n  return view\nend\n\nH.view_track_cursor = vim.schedule_wrap(function(data)\n  -- Schedule this in order to react *after* all pending changes are applied\n  local buf_id = data.buf\n  local buf_data = H.opened_buffers[buf_id]\n  if buf_data == nil then return end\n\n  local win_id = buf_data.win_id\n  if not H.is_valid_win(win_id) then return end\n\n  -- Ensure cursor doesn't go over path id and icon\n  local cur_cursor = H.window_tweak_cursor(win_id, buf_id)\n\n  -- Ensure cursor line doesn't contradict window on the right\n  local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n  local explorer = H.explorer_get(tabpage_id)\n  if explorer == nil then return end\n\n  local buf_depth = H.explorer_get_path_depth(explorer, buf_data.path)\n  if buf_depth == nil then return end\n\n  -- Update cursor in view and sync it with branch\n  local view = explorer.views[buf_data.path]\n  if view ~= nil then\n    view.cursor = cur_cursor\n    explorer.views[buf_data.path] = view\n  end\n\n  explorer = H.explorer_sync_cursor_and_branch(explorer, buf_depth)\n\n  H.explorer_refresh(explorer)\nend)\n\nH.view_track_text_change = function(data)\n  -- Track 'modified'\n  local buf_id = data.buf\n  local new_n_modified = H.opened_buffers[buf_id].n_modified + 1\n  H.opened_buffers[buf_id].n_modified = new_n_modified\n  local win_id = H.opened_buffers[buf_id].win_id\n  if new_n_modified > 0 and H.is_valid_win(win_id) then H.window_update_border_hl(win_id) end\n\n  -- Track window height\n  if not H.is_valid_win(win_id) then return end\n\n  local cur_height = vim.api.nvim_win_get_height(win_id)\n  local n_lines = vim.api.nvim_buf_line_count(buf_id)\n  local new_height = math.min(n_lines, H.window_get_max_height())\n  vim.api.nvim_win_set_height(win_id, new_height)\n\n  -- Trigger appropriate event if window height has changed\n  if cur_height ~= new_height then\n    H.trigger_event('MiniFilesWindowUpdate', { buf_id = buf_id, win_id = win_id })\n    new_height = vim.api.nvim_win_get_height(win_id)\n  end\n\n  -- Ensure that only buffer lines are shown. This can be not the case if after\n  -- text edit cursor moved past previous last line.\n  local last_visible_line = vim.fn.line('w0', win_id) + new_height - 1\n  local out_of_buf_lines = last_visible_line - n_lines\n  -- - Possibly scroll window upward (`\\25` is an escaped `<C-y>`)\n  if out_of_buf_lines > 0 then\n    -- Preserve cursor as scrolling might affect it (like in Insert mode)\n    local cursor = vim.api.nvim_win_get_cursor(win_id)\n    vim.cmd('normal! ' .. out_of_buf_lines .. '\\25')\n    vim.api.nvim_win_set_cursor(win_id, cursor)\n  end\nend\n\n-- Buffers --------------------------------------------------------------------\nH.buffer_create = function(path, mappings)\n  -- Create buffer\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  H.set_buf_name(buf_id, path)\n\n  -- Register buffer\n  H.opened_buffers[buf_id] = { path = path }\n\n  -- Set buffer options\n  vim.bo[buf_id].filetype = 'minifiles'\n\n  -- Do not set up tracking behavior for imaginary paths\n  if H.fs_is_imaginary_path(path) then return buf_id end\n\n  -- Make buffer mappings\n  H.buffer_make_mappings(buf_id, mappings)\n\n  -- Make buffer autocommands\n  local augroup = vim.api.nvim_create_augroup('MiniFiles', { clear = false })\n  local au = function(events, desc, callback)\n    vim.api.nvim_create_autocmd(events, { group = augroup, buffer = buf_id, desc = desc, callback = callback })\n  end\n\n  au({ 'CursorMoved', 'CursorMovedI', 'TextChangedP' }, 'Tweak cursor position', H.view_track_cursor)\n  au({ 'TextChanged', 'TextChangedI', 'TextChangedP' }, 'Track buffer modification', H.view_track_text_change)\n\n  -- Tweak buffer to be used nicely with other 'mini.nvim' modules\n  vim.b[buf_id].minicursorword_disable = true\n\n  -- Trigger dedicated event\n  H.trigger_event('MiniFilesBufferCreate', { buf_id = buf_id })\n\n  return buf_id\nend\n\nH.buffer_make_mappings = function(buf_id, mappings)\n  local go_in_with_count = function()\n    for _ = 1, vim.v.count1 do\n      MiniFiles.go_in()\n    end\n  end\n\n  local go_in_plus = function()\n    for _ = 1, vim.v.count1 do\n      MiniFiles.go_in({ close_on_file = true })\n    end\n  end\n\n  local go_out_with_count = function()\n    for _ = 1, vim.v.count1 do\n      MiniFiles.go_out()\n    end\n  end\n\n  local go_out_plus = function()\n    go_out_with_count()\n    MiniFiles.trim_right()\n  end\n\n  local go_in_visual = function()\n    -- React only on linewise mode, as others can be used for editing\n    if vim.fn.mode() ~= 'V' then return mappings.go_in end\n\n    -- Schedule actions because they are not allowed inside expression mapping\n    local line_1, line_2 = vim.fn.line('v'), vim.fn.line('.')\n    local from_line, to_line = math.min(line_1, line_2), math.max(line_1, line_2)\n    vim.schedule(function()\n      local explorer = H.explorer_get()\n      explorer = H.explorer_go_in_range(explorer, buf_id, from_line, to_line)\n      H.explorer_refresh(explorer)\n    end)\n\n    -- Go to Normal mode. '\\28\\14' is an escaped version of `<C-\\><C-n>`.\n    return [[<C-\\><C-n>]]\n  end\n\n  local mark_goto = function()\n    local id = H.getcharstr()\n    if id == nil then return end\n    local data = MiniFiles.get_explorer_state().bookmarks[id]\n    if data == nil then return H.notify('No bookmark with id ' .. vim.inspect(id), 'WARN') end\n\n    local path = data.path\n    if vim.is_callable(path) then path = path() end\n    local is_valid_path = type(path) == 'string' and H.fs_get_type(vim.fn.expand(path)) == 'directory'\n    if not is_valid_path then return H.notify('Bookmark path should be a valid path to directory', 'WARN') end\n\n    local state = MiniFiles.get_explorer_state()\n    MiniFiles.set_bookmark(\"'\", state.branch[state.depth_focus], { desc = 'Before latest jump' })\n    MiniFiles.set_branch({ path })\n  end\n\n  local mark_set = function()\n    local id = H.getcharstr()\n    if id == nil then return end\n    local state = MiniFiles.get_explorer_state()\n    MiniFiles.set_bookmark(id, state.branch[state.depth_focus])\n    H.notify('Bookmark ' .. vim.inspect(id) .. ' is set', 'INFO')\n  end\n\n  local buf_map = function(mode, lhs, rhs, desc)\n    -- Use `nowait` to account for non-buffer mappings starting with `lhs`\n    H.map(mode, lhs, rhs, { buffer = buf_id, desc = desc, nowait = true })\n  end\n\n  --stylua: ignore start\n  buf_map('n', mappings.close,       MiniFiles.close,       'Close')\n  buf_map('n', mappings.go_in,       go_in_with_count,      'Go in entry')\n  buf_map('n', mappings.go_in_plus,  go_in_plus,            'Go in entry plus')\n  buf_map('n', mappings.go_out,      go_out_with_count,     'Go out of directory')\n  buf_map('n', mappings.go_out_plus, go_out_plus,           'Go out of directory plus')\n  buf_map('n', mappings.mark_goto,   mark_goto,             'Go to bookmark')\n  buf_map('n', mappings.mark_set,    mark_set,              'Set bookmark')\n  buf_map('n', mappings.reset,       MiniFiles.reset,       'Reset')\n  buf_map('n', mappings.reveal_cwd,  MiniFiles.reveal_cwd,  'Reveal cwd')\n  buf_map('n', mappings.show_help,   MiniFiles.show_help,   'Show Help')\n  buf_map('n', mappings.synchronize, MiniFiles.synchronize, 'Synchronize')\n  buf_map('n', mappings.trim_left,   MiniFiles.trim_left,   'Trim branch left')\n  buf_map('n', mappings.trim_right,  MiniFiles.trim_right,  'Trim branch right')\n\n  H.map('x', mappings.go_in, go_in_visual, { buffer = buf_id, desc = 'Go in selected entries', expr = true })\n  --stylua: ignore end\nend\n\nH.buffer_update = function(buf_id, path, opts, is_preview)\n  if not H.is_valid_buf(buf_id) then return end\n\n  -- Perform entry type specific updates\n  local fs_type = H.fs_get_type(path)\n  if fs_type == 'directory' then H.buffer_update_directory(buf_id, path, opts, is_preview) end\n  if fs_type == 'file' then H.buffer_update_file(buf_id, path, opts, is_preview) end\n  if fs_type == nil then H.set_buflines(buf_id, { '-No-fs-entry-' .. string.rep('-', opts.windows.width_preview) }) end\n\n  -- Trigger dedicated event\n  local data = { buf_id = buf_id, win_id = H.opened_buffers[buf_id].win_id }\n  if fs_type ~= nil then H.trigger_event('MiniFilesBufferUpdate', data) end\n\n  -- Reset buffer as not modified\n  H.opened_buffers[buf_id].n_modified = -1\nend\n\nH.buffer_update_directory = function(buf_id, path, opts, is_preview)\n  -- Compute and cache (to use during sync) shown file system entries\n  local children_path_ids = H.opened_buffers[buf_id].children_path_ids\n  local fs_entries = children_path_ids == nil and H.fs_read_dir(path, opts.content)\n    or vim.tbl_map(H.get_fs_entry_from_path_index, children_path_ids)\n  H.opened_buffers[buf_id].children_path_ids = children_path_ids\n    or vim.tbl_map(function(x) return x.path_id end, fs_entries)\n\n  -- Compute format expression resulting into same width path ids\n  local path_width = math.floor(math.log10(#H.path_index)) + 1\n  local line_format = '/%0' .. path_width .. 'd/%s/%s'\n\n  -- Compute lines\n  local lines, icon_hl, name_hl = {}, {}, {}\n  local prefix_fun, hl_fun = opts.content.prefix, opts.content.highlight\n  local n_computed_prefixes = is_preview and vim.o.lines or math.huge\n  for i, entry in ipairs(fs_entries) do\n    local prefix, hl, name\n    -- Compute prefix only in visible preview (for performance).\n    -- NOTE: limiting entries in `fs_read_dir()` is not possible because all\n    -- entries are needed for a proper filter and sort.\n    if i <= n_computed_prefixes then\n      prefix, hl = prefix_fun(entry)\n    end\n    prefix, hl, name = prefix or '', hl or '', H.sanitize_string(entry.name)\n    table.insert(lines, string.format(line_format, H.path_index[entry.path], prefix, name))\n    table.insert(icon_hl, hl)\n    table.insert(name_hl, hl_fun(entry) or 'MiniFilesNormal')\n  end\n\n  -- Set lines\n  H.set_buflines(buf_id, lines)\n\n  -- Add highlighting\n  local ns_id = H.ns_id.highlight\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n\n  local set_hl = function(line, col, hl_opts) H.set_extmark(buf_id, ns_id, line, col, hl_opts) end\n\n  for i, l in ipairs(lines) do\n    local icon_start, name_start = l:match('^/%d+/().-()/')\n\n    -- NOTE: Use `right_gravity = false` for persistent highlights during edit\n    local icon_opts = { hl_group = icon_hl[i], end_col = name_start - 1, right_gravity = false }\n    set_hl(i - 1, icon_start - 1, icon_opts)\n\n    local name_opts = { hl_group = name_hl[i], end_row = i, end_col = 0, right_gravity = false }\n    set_hl(i - 1, name_start - 1, name_opts)\n  end\nend\n\nH.buffer_update_file = function(buf_id, path, opts, _)\n  -- Work only with readable text file. This is not 100% proof, but good enough.\n  -- Source: https://github.com/sharkdp/content_inspector\n  local fd, width_preview = vim.loop.fs_open(path, 'r', 1), opts.windows.width_preview\n  if fd == nil then return H.set_buflines(buf_id, { '-No-access' .. string.rep('-', width_preview) }) end\n  local is_text = vim.loop.fs_read(fd, 1024):find('\\0') == nil\n  vim.loop.fs_close(fd)\n  if not is_text then return H.set_buflines(buf_id, { '-Non-text-file' .. string.rep('-', width_preview) }) end\n\n  -- Compute lines. Limit number of read lines to work better on large files.\n  local has_lines, read_res = pcall(vim.fn.readfile, path, '', vim.o.lines)\n  -- - Make sure that lines don't contain '\\n' (might happen in binary files).\n  local lines = has_lines and vim.split(table.concat(read_res, '\\n'), '\\n') or {}\n\n  -- Set lines\n  H.set_buflines(buf_id, lines)\n\n  -- Add highlighting if reasonable (for performance or functionality reasons)\n  if H.buffer_should_highlight(buf_id) then\n    local ft = vim.filetype.match({ buf = buf_id, filename = path })\n    local has_lang, lang = pcall(vim.treesitter.language.get_lang, ft)\n    lang = has_lang and lang or ft\n    -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n    local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, lang, { error = false })\n    has_parser = has_parser and parser ~= nil\n    if has_parser then has_parser = pcall(vim.treesitter.start, buf_id, lang) end\n    if not has_parser then vim.bo[buf_id].syntax = ft end\n  end\nend\n\nH.buffer_delete = function(buf_id)\n  if buf_id == nil then return end\n  pcall(vim.api.nvim_buf_delete, buf_id, { force = true })\n  H.opened_buffers[buf_id] = nil\nend\n\nH.buffer_compute_fs_diff = function(buf_id)\n  if not H.is_modified_buffer(buf_id) then return {} end\n\n  local path = H.opened_buffers[buf_id].path\n  local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)\n  local res, present_path_ids = {}, {}\n\n  -- Process present file system entries\n  for _, l in ipairs(lines) do\n    local path_id = H.match_line_path_id(l)\n    local path_from = H.path_index[path_id]\n\n    -- Use whole line as name if no path id is detected\n    local name_to = path_id ~= nil and l:sub(H.match_line_offset(l)) or l\n\n    -- Preserve trailing '/' to distinguish between creating file or directory\n    local path_to = H.fs_child_path(path, name_to) .. (vim.endswith(name_to, '/') and '/' or '')\n\n    -- Ignore blank lines and already synced entries (even several user-copied)\n    if l:find('^%s*$') == nil and H.sanitize_string(path_from) ~= H.sanitize_string(path_to) then\n      table.insert(res, { from = path_from, to = path_to, dir = path })\n    elseif path_id ~= nil then\n      present_path_ids[path_id] = true\n    end\n  end\n\n  -- Detect missing file system entries\n  local ref_path_ids = H.opened_buffers[buf_id].children_path_ids\n  for _, ref_id in ipairs(ref_path_ids) do\n    if not present_path_ids[ref_id] then table.insert(res, { from = H.path_index[ref_id], to = nil, dir = path }) end\n  end\n\n  return res\nend\n\nH.buffer_should_highlight = function(buf_id)\n  -- Highlight if buffer size is not too big, both in total and per line\n  local buf_size = vim.api.nvim_buf_call(buf_id, function() return vim.fn.line2byte(vim.fn.line('$') + 1) end)\n  return buf_size <= 1000000 and buf_size <= 1000 * vim.api.nvim_buf_line_count(buf_id)\nend\n\nH.is_opened_buffer = function(buf_id) return H.opened_buffers[buf_id] ~= nil end\n\nH.is_modified_buffer = function(buf_id)\n  local data = H.opened_buffers[buf_id]\n  return data ~= nil and data.n_modified > 0\nend\n\nH.match_line_entry_name = function(l)\n  if l == nil then return nil end\n  local offset = H.match_line_offset(l)\n  -- Go up until first occurrence of path separator allowing to track entries\n  -- like `a/b.lua` when creating nested structure\n  local res = l:sub(offset):gsub('/.*$', '')\n  return res\nend\n\nH.match_line_offset = function(l)\n  if l == nil then return nil end\n  return l:match('^/.-/.-/()') or 1\nend\n\nH.match_line_path_id = function(l)\n  if l == nil then return nil end\n\n  local id_str = l:match('^/(%d+)')\n  local ok, res = pcall(tonumber, id_str)\n  if not ok then return nil end\n  return res\nend\n\n-- Windows --------------------------------------------------------------------\nH.window_open = function(buf_id, config)\n  -- Add always the same extra data\n  config.anchor = 'NW'\n  config.border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil\n  config.focusable = true\n  config.relative = 'editor'\n  config.style = 'minimal'\n  -- - Use 99 to allow built-in completion to be on top\n  config.zindex = 99\n\n  -- Add temporary data which will be updated later\n  config.row = 1\n\n  -- Open without entering\n  local win_id = vim.api.nvim_open_win(buf_id, false, config)\n\n  -- Set permanent window options\n  vim.wo[win_id].concealcursor = 'nvic'\n  vim.wo[win_id].foldenable = false\n  vim.wo[win_id].foldmethod = 'manual'\n  vim.wo[win_id].wrap = false\n\n  -- Conceal path id and prefix separators\n  vim.api.nvim_win_call(win_id, function()\n    vim.fn.matchadd('Conceal', [[^/\\d\\+/]])\n    vim.fn.matchadd('Conceal', [[^/\\d\\+/[^/]*\\zs/\\ze]])\n  end)\n\n  -- Set permanent window highlights\n  H.window_update_highlight(win_id, 'NormalFloat', 'MiniFilesNormal')\n  H.window_update_highlight(win_id, 'FloatTitle', 'MiniFilesTitle')\n  H.window_update_highlight(win_id, 'CursorLine', 'MiniFilesCursorLine')\n\n  -- Trigger dedicated event\n  H.trigger_event('MiniFilesWindowOpen', { buf_id = buf_id, win_id = win_id })\n\n  return win_id\nend\n\nH.window_update = function(win_id, config)\n  -- Preserve some config values\n  local win_config = vim.api.nvim_win_get_config(win_id)\n  config.border, config.title_pos = win_config.border, win_config.title_pos\n\n  -- Compute helper data\n  local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)\n  local max_height = H.window_get_max_height()\n  local max_width = vim.o.columns - (config.border == 'none' and 0 or 2)\n\n  -- Ensure proper fit\n  config.row = has_tabline and 1 or 0\n  config.height = config.height ~= nil and math.min(config.height, max_height) or nil\n  config.width = config.width ~= nil and math.min(config.width, max_width) or nil\n\n  -- Ensure proper title\n  if type(config.title) == 'string' then config.title = H.fit_to_width(config.title, config.width) end\n\n  -- Update config\n  config.relative = 'editor'\n  vim.api.nvim_win_set_config(win_id, config)\n\n  -- Reset basic highlighting (removes possible \"focused\" highlight group)\n  H.window_update_highlight(win_id, 'FloatTitle', 'MiniFilesTitle')\n\n  -- Make sure proper `conceallevel` (can be not the case with 'noice.nvim')\n  vim.wo[win_id].conceallevel = 3\nend\n\nH.window_update_highlight = function(win_id, new_from, new_to)\n  local new_entry = new_from .. ':' .. new_to\n  local replace_pattern = string.format('(%s:[^,]*)', vim.pesc(new_from))\n  local new_winhighlight, n_replace = vim.wo[win_id].winhighlight:gsub(replace_pattern, new_entry)\n  if n_replace == 0 then new_winhighlight = new_winhighlight .. ',' .. new_entry end\n\n  vim.wo[win_id].winhighlight = new_winhighlight\nend\n\nH.window_focus = function(win_id)\n  vim.api.nvim_set_current_win(win_id)\n  H.window_update_highlight(win_id, 'FloatTitle', 'MiniFilesTitleFocused')\nend\n\nH.window_close = function(win_id)\n  if win_id == nil then return end\n  local has_buffer, buf_id = pcall(vim.api.nvim_win_get_buf, win_id)\n  if has_buffer then H.opened_buffers[buf_id].win_id = nil end\n  pcall(vim.api.nvim_win_close, win_id, true)\nend\n\nH.window_set_view = function(win_id, view)\n  -- Set buffer\n  local buf_id, buf_data = view.buf_id, H.opened_buffers[view.buf_id]\n  H.win_set_buf(win_id, buf_id)\n  -- - Update buffer register. No need to update previous buffer data, as it\n  --   should already be invalidated.\n  buf_data.win_id = win_id\n\n  -- Set cursor (if defined), visible only in directories\n  pcall(H.window_set_cursor, win_id, view.cursor)\n  -- NOTE: set 'cursorline[opt]' here because changing buffer might remove it\n  vim.wo[win_id].cursorline = H.fs_get_type(buf_data.path) == 'directory'\n  local culopt = vim.wo[win_id].cursorlineopt\n  if culopt:find('line') == nil then vim.wo[win_id].cursorlineopt = culopt .. ',line' end\n\n  -- Respect global 'list' option, as it is disabled in floating windows\n  -- TODO: Use vim.wo[win_id][0] after compatibility with Neovim=0.9 is dropped\n  local opts_scope = { scope = 'local', win = win_id }\n  vim.api.nvim_set_option_value('list', vim.go.list, opts_scope)\n  vim.api.nvim_set_option_value('listchars', vim.go.listchars, opts_scope)\n\n  -- Update border highlight based on buffer status\n  H.window_update_border_hl(win_id)\nend\n\nH.window_set_cursor = function(win_id, cursor)\n  if type(cursor) ~= 'table' then return end\n\n  vim.api.nvim_win_set_cursor(win_id, cursor)\n\n  -- Tweak cursor here and don't rely on `CursorMoved` event to reduce flicker\n  H.window_tweak_cursor(win_id, vim.api.nvim_win_get_buf(win_id))\nend\n\nH.window_tweak_cursor = function(win_id, buf_id)\n  local cursor = vim.api.nvim_win_get_cursor(win_id)\n  local l = H.get_bufline(buf_id, cursor[1])\n\n  local cur_offset = H.match_line_offset(l)\n  if cursor[2] < (cur_offset - 1) then\n    cursor[2] = cur_offset - 1\n    vim.api.nvim_win_set_cursor(win_id, cursor)\n    -- Ensure icons are shown (may be not the case after horizontal scroll)\n    vim.cmd('normal! 1000zh')\n  end\n\n  return cursor\nend\n\nH.window_update_border_hl = function(win_id)\n  if not H.is_valid_win(win_id) then return end\n  local buf_id = vim.api.nvim_win_get_buf(win_id)\n\n  local border_hl = H.is_modified_buffer(buf_id) and 'MiniFilesBorderModified' or 'MiniFilesBorder'\n  H.window_update_highlight(win_id, 'FloatBorder', border_hl)\nend\n\nH.window_get_max_height = function()\n  local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)\n  local has_statusline = vim.o.laststatus > 0\n  -- Remove 2 from maximum height to account for top and bottom borders\n  return vim.o.lines - vim.o.cmdheight - (has_tabline and 1 or 0) - (has_statusline and 1 or 0) - 2\nend\n\n-- File system ----------------------------------------------------------------\n---@class fs_entry\n---@field name string Base name.\n---@field fs_type string One of \"directory\" or \"file\".\n---@field path string Full path.\n---@field path_id number Id of full path.\n---@private\nH.fs_read_dir = function(path, content_opts)\n  local fs = vim.loop.fs_scandir(path)\n  local res = {}\n  if not fs then return res end\n\n  -- Read all entries\n  local name, fs_type = vim.loop.fs_scandir_next(fs)\n  while name do\n    if not (fs_type == 'file' or fs_type == 'directory') then fs_type = H.fs_get_type(H.fs_child_path(path, name)) end\n    table.insert(res, { fs_type = fs_type, name = name, path = H.fs_child_path(path, name) })\n    name, fs_type = vim.loop.fs_scandir_next(fs)\n  end\n\n  -- Filter and sort entries\n  res = content_opts.sort(vim.tbl_filter(content_opts.filter, res))\n\n  -- Add new data: absolute file path and its index\n  for _, entry in ipairs(res) do\n    entry.path_id = H.add_path_to_index(entry.path)\n  end\n\n  return res\nend\n\nH.add_path_to_index = function(path)\n  local cur_id = H.path_index[path]\n  if cur_id ~= nil then return cur_id end\n\n  local new_id = #H.path_index + 1\n  H.path_index[new_id] = path\n  H.path_index[path] = new_id\n\n  return new_id\nend\n\nH.get_fs_entry_from_path_index = function(path_id)\n  local path = H.path_index[path_id]\n  if path == nil then return nil end\n  return { fs_type = H.fs_get_type(path), name = H.fs_get_basename(path), path = path }\nend\n\nH.replace_path_in_index = function(from, to)\n  local from_id, to_id = H.path_index[from], H.path_index[to]\n  H.path_index[from_id], H.path_index[to] = to, from_id\n  if to_id then H.path_index[to_id] = nil end\n  -- Remove `from` from index assuming it doesn't exist anymore (no duplicates)\n  H.path_index[from] = nil\nend\n\nH.compare_fs_entries = function(a, b)\n  -- Put directory first\n  if a.is_dir and not b.is_dir then return true end\n  if not a.is_dir and b.is_dir then return false end\n\n  -- Otherwise order alphabetically ignoring case\n  return a.lower_name < b.lower_name\nend\n\nH.fs_normalize_path = function(path) return (path:gsub('/+', '/'):gsub('(.)/$', '%1')) end\nif H.is_windows then\n  H.fs_normalize_path = function(path)\n    return (path:gsub('\\\\', '/'):gsub('([^/:])/+', '%1/'):gsub('([^:])/+$', '%1'):gsub('^(%a):/+([^/])', '%1://%2'))\n  end\nend\n\nH.fs_is_imaginary_path = function(path) return path:sub(-1) == '\\000' end\n\nH.fs_is_present_path = function(path) return vim.loop.fs_stat(path) ~= nil and not H.fs_is_imaginary_path(path) end\n\nH.fs_child_path = function(dir, name) return H.fs_normalize_path(string.format('%s/%s', dir, name)) end\n\nH.fs_full_path = function(path) return H.fs_normalize_path(vim.fn.fnamemodify(path, ':p')) end\n\nH.fs_shorten_path = function(path)\n  -- Replace home directory with '~'\n  path = H.fs_normalize_path(path)\n  local home_dir = H.fs_normalize_path(vim.loop.os_homedir() or '~')\n  return (path:gsub('^' .. vim.pesc(home_dir), '~'))\nend\n\nH.fs_relcwd_path = function(path) return vim.fn.fnamemodify(path, ':.') end\nif H.is_windows then\n  -- Make manually because `C://dir/file` paths conflict with `C:/dir` cwd path\n  H.fs_relcwd_path = function(path)\n    local cwd = H.fs_normalize_path(vim.fn.getcwd())\n    return (H.fs_normalize_path(path):gsub('^' .. vim.pesc(cwd) .. '/', ''))\n  end\nend\n\nH.fs_get_basename = function(path) return H.fs_normalize_path(path):match('[^/]+$') end\n\nH.fs_get_parent = function(path)\n  path = H.fs_full_path(path)\n\n  -- Deal with top root paths\n  local is_top = H.fs_is_windows_top(path) or path == '/'\n  if is_top then return nil end\n\n  -- Compute parent\n  local res = H.fs_normalize_path(path:match('^.*/'))\n  -- - Deal with Windows top directory separately\n  local suffix = H.fs_is_windows_top(res) and '/' or ''\n  return res .. suffix\nend\n\nH.fs_is_windows_top = function(path) return H.is_windows and path:find('^%w:[\\\\/]?$') ~= nil end\n\nH.fs_get_type = function(path)\n  if not (not H.fs_is_imaginary_path(path) and H.fs_is_present_path(path)) then return nil end\n  return vim.fn.isdirectory(path) == 1 and 'directory' or 'file'\nend\n\n-- File system actions --------------------------------------------------------\nH.fs_actions_to_lines = function(fs_actions)\n  -- Gather actions per source directory\n  local short = H.fs_shorten_path\n  local dir\n  local rel = function(p) return vim.startswith(p, dir .. '/') and p:sub(#dir + 2):gsub('/$', '') or short(p) end\n\n  local actions_per_dir = {}\n  --stylua: ignore\n  for _, diff in ipairs(fs_actions) do\n    -- Set grouping directory to also be used to compute relative paths\n    dir = diff.action == 'create' and diff.dir or H.fs_get_parent(diff.from)\n\n    -- Compute line depending on action\n    local action, l = diff.action, nil\n    local to_type = (diff.to or ''):sub(-1) == '/' and 'directory' or 'file'\n    local del_type = diff.to == nil and 'permanently' or 'to trash'\n    if action == 'create' then l = string.format(\"CREATE │ %s (%s)\",  rel(diff.to), to_type) end\n    if action == 'delete' then l = string.format(\"DELETE │ %s (%s)\",  rel(diff.from), del_type) end\n    if action == 'copy'   then l = string.format(\"COPY   │ %s => %s\", rel(diff.from), rel(diff.to)) end\n    if action == 'move'   then l = string.format(\"MOVE   │ %s => %s\", rel(diff.from), rel(diff.to)) end\n    if action == 'rename' then l = string.format(\"RENAME │ %s => %s\", rel(diff.from), rel(diff.to)) end\n\n    -- Add to per directory lines\n    local dir_actions = actions_per_dir[dir] or {}\n    table.insert(dir_actions, '  ' .. H.sanitize_string(l))\n    actions_per_dir[dir] = dir_actions\n  end\n\n  -- Convert to final lines\n  local res = { 'CONFIRM FILE SYSTEM ACTIONS', '' }\n  for path, dir_actions in pairs(actions_per_dir) do\n    table.insert(res, short(path))\n    vim.list_extend(res, dir_actions)\n    table.insert(res, '')\n  end\n\n  return res\nend\n\nH.fs_actions_apply = function(fs_actions)\n  for i = 1, #fs_actions do\n    local diff, action = fs_actions[i], fs_actions[i].action\n    local ok, success = pcall(H.fs_do[action], diff.from, diff.to)\n    if ok and success then\n      -- Trigger event\n      local to = action == 'create' and diff.to:gsub('/$', '') or diff.to\n      local data = { action = action, from = diff.from, to = to }\n      local action_titlecase = action:sub(1, 1):upper() .. action:sub(2)\n      H.trigger_event('MiniFilesAction' .. action_titlecase, data)\n\n      -- Modify later actions to account for file movement\n      local has_moved = to ~= nil and not (action == 'copy' or action == 'create')\n      if has_moved then H.adjust_after_move(diff.from, to, fs_actions, i + 1) end\n    end\n  end\nend\n\nH.fs_do = {}\n\nH.fs_do.create = function(_, path)\n  -- Don't override existing path\n  if H.fs_is_present_path(path) then return H.warn_existing_path(path, 'create') end\n\n  -- Create parent directory allowing nested names\n  vim.fn.mkdir(H.fs_get_parent(path), 'p')\n\n  -- Create\n  local fs_type = path:sub(-1) == '/' and 'directory' or 'file'\n  if fs_type == 'directory' then return vim.fn.mkdir(path) == 1 end\n  return vim.fn.writefile({}, path) == 0\nend\n\nH.fs_do.copy = function(from, to)\n  -- Don't override existing path\n  if H.fs_is_present_path(to) then return H.warn_existing_path(from, 'copy') end\n\n  local from_type = H.fs_get_type(from)\n  if from_type == nil then return false end\n\n  -- Allow copying inside non-existing directory\n  vim.fn.mkdir(H.fs_get_parent(to), 'p')\n\n  -- Copy file directly\n  if from_type == 'file' then return vim.loop.fs_copyfile(from, to) end\n\n  -- Recursively copy a directory\n  local fs_entries = H.fs_read_dir(from, { filter = function() return true end, sort = function(x) return x end })\n  -- NOTE: Create directory *after* reading entries to allow copy inside itself\n  vim.fn.mkdir(to)\n\n  local success = true\n  for _, entry in ipairs(fs_entries) do\n    success = success and H.fs_do.copy(entry.path, H.fs_child_path(to, entry.name))\n  end\n\n  return success\nend\n\nH.fs_do.delete = function(from, to)\n  -- Act based on whether delete is permanent or not\n  if to == nil then return vim.fn.delete(from, 'rf') == 0 end\n  pcall(vim.fn.delete, to, 'rf')\n  -- Move to trash but skip renaming loaded buffer (same as with permanent\n  -- delete). This also skips triggering extra autocommands that can have\n  -- unwanted side effects (like loading LSP in the new \"trash\" project).\n  return H.fs_do.move(from, to, true)\nend\n\nH.fs_do.move = function(from, to, skip_buf_rename)\n  -- Don't override existing path\n  if H.fs_is_present_path(to) then return H.warn_existing_path(from, 'move or rename') end\n\n  -- Move while allowing to create directory\n  vim.fn.mkdir(H.fs_get_parent(to), 'p')\n  local success, _, err_code = vim.loop.fs_rename(from, to)\n\n  if err_code == 'EXDEV' then\n    -- Handle cross-device move separately as `loop.fs_rename` does not work\n    success = H.fs_do.copy(from, to)\n    if success then success = pcall(vim.fn.delete, from, 'rf') end\n    if not success then pcall(vim.fn.delete, to, 'rf') end\n  end\n\n  if not success then return success end\n\n  -- Update path index to allow consecutive moves after undo (which also\n  -- restores previous concealed path index)\n  H.replace_path_in_index(from, to)\n\n  -- Rename in loaded buffers\n  if not skip_buf_rename then\n    for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n      H.rename_loaded_buffer(buf_id, from, to)\n    end\n  end\n\n  return success\nend\n\nH.fs_do.rename = H.fs_do.move\n\nH.rename_loaded_buffer = function(buf_id, from, to)\n  if not (vim.api.nvim_buf_is_loaded(buf_id) and vim.bo[buf_id].buftype == '') then return end\n  -- Make sure buffer name is normalized (same as `from` and `to`)\n  local cur_name = H.fs_normalize_path(vim.api.nvim_buf_get_name(buf_id))\n\n  -- Use `gsub('^' ...)` to also take into account directory renames\n  local new_name = cur_name:gsub('^' .. vim.pesc(from), to)\n  if cur_name == new_name then return end\n\n  -- Rename buffer using relative form (for nicer `:buffers` output)\n  vim.api.nvim_buf_set_name(buf_id, H.fs_relcwd_path(new_name))\n\n  -- Force write to avoid the 'overwrite existing file' error message on write\n  -- for normal files\n  vim.api.nvim_buf_call(buf_id, function() vim.cmd('silent! write! | edit') end)\nend\n\nH.warn_existing_path = function(path, action)\n  H.notify(string.format('Can not %s %s. Target path already exists.', action, path), 'WARN')\n  return false\nend\n\nH.adjust_after_move = function(from, to, fs_actions, start_ind)\n  local from_dir_pattern, to_dir = '^' .. vim.pesc(from .. '/'), to .. '/'\n  for i = start_ind, #fs_actions do\n    local diff = fs_actions[i]\n    -- Adjust completely to use entry at new location\n    if diff.from ~= nil then diff.from = diff.from == from and to or diff.from:gsub(from_dir_pattern, to_dir) end\n    -- Adjust only parent directory to correctly compute target\n    if diff.to ~= nil then diff.to = diff.to:gsub(from_dir_pattern, to_dir) end\n  end\nend\n\n-- Validators -----------------------------------------------------------------\nH.validate_opened_buffer = function(x)\n  if x == nil or x == 0 then x = vim.api.nvim_get_current_buf() end\n  if not H.is_opened_buffer(x) then H.error('`buf_id` should be an identifier of an opened directory buffer.') end\n  return x\nend\n\nH.validate_line = function(buf_id, x)\n  x = x or vim.fn.line('.')\n  if not (type(x) == 'number' and 1 <= x and x <= vim.api.nvim_buf_line_count(buf_id)) then\n    H.error('`line` should be a valid line number in buffer ' .. buf_id .. '.')\n  end\n  return x\nend\n\nH.validate_branch = function(x)\n  if not (H.islist(x) and x[1] ~= nil) then H.error('`branch` should be array with at least one element') end\n  local res = {}\n  for i, p in ipairs(x) do\n    if type(p) ~= 'string' then H.error('`branch` contains not string: ' .. vim.inspect(p)) end\n    p = H.fs_full_path(p)\n    if not H.fs_is_present_path(p) then H.error('`branch` contains not present path: ' .. vim.inspect(p)) end\n    res[i] = p\n  end\n  for i = 2, #res do\n    local parent, child = res[i - 1], res[i]\n    if (parent .. '/' .. child:match('[^/]+$')) ~= res[i] then\n      H.error('`branch` contains not a parent-child pair: ' .. vim.inspect(parent) .. ' and ' .. vim.inspect(child))\n    end\n  end\n  if #res == 1 and H.fs_get_type(res[1]) == 'file' then H.error('`branch` should contain at least one directory') end\n  return res\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.files) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minifiles://' .. buf_id .. '/' .. name) end\n\nH.notify = function(msg, level_name) vim.notify('(mini.files) ' .. msg, vim.log.levels[level_name]) end\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.edit = function(path, win_id)\n  if type(path) ~= 'string' then return end\n  local b = vim.api.nvim_win_get_buf(win_id or 0)\n  local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)\n    and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))\n  local buf_id = vim.fn.bufadd(H.fs_relcwd_path(path))\n  -- Showing in window also loads. Use `pcall` to not error with swap messages.\n  pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)\n  vim.bo[buf_id].buflisted = true\n  if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end\n  return buf_id\nend\n\nH.trigger_event = function(event_name, data) vim.api.nvim_exec_autocmds('User', { pattern = event_name, data = data }) end\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.get_bufline = function(buf_id, line) return vim.api.nvim_buf_get_lines(buf_id, line - 1, line, false)[1] end\n\nH.set_buflines = function(buf_id, lines)\n  local cmd =\n    string.format('lockmarks lua vim.api.nvim_buf_set_lines(%d, 0, -1, false, %s)', buf_id, vim.inspect(lines))\n  vim.cmd(cmd)\nend\n\nH.set_extmark = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end\n\nH.win_set_buf = function(win_id, buf_id)\n  vim.wo[win_id].winfixbuf = false\n  -- Prevent `BufEnter,BufLeave` that come from `nvim_win_set_buf` and conflict\n  -- with other modules (like 'mini.jump'). Use 'mini.files' events if needed.\n  local cmd = string.format('noautocmd call nvim_win_set_buf(%d, %d)', win_id, buf_id)\n  vim.cmd(cmd)\n  vim.wo[win_id].winfixbuf = true\nend\nif vim.fn.has('nvim-0.10') == 0 then H.win_set_buf = vim.api.nvim_win_set_buf end\n\nH.get_first_valid_normal_window = function()\n  for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do\n    if vim.api.nvim_win_get_config(win_id).relative == '' then return win_id end\n  end\nend\n\nH.getcharstr = function()\n  local ok, char = pcall(vim.fn.getcharstr)\n  if not ok or char == '\\27' or char == '' then return end\n  return char\nend\n\nH.sanitize_string = function(x) return ((x or ''):gsub('\\n', '<NL>'):gsub('%z', '')) end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniFiles\n"
  },
  {
    "path": "lua/mini/fuzzy.lua",
    "content": "--- *mini.fuzzy* Fuzzy matching\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Minimal and fast fuzzy matching algorithm which prioritizes match width.\n---\n--- - Functions to for common fuzzy matching operations:\n---     - |MiniFuzzy.match()|.\n---     - |MiniFuzzy.filtersort()|.\n---     - |MiniFuzzy.process_lsp_items()|.\n---\n--- - Generator of sorter (|MiniFuzzy.get_telescope_sorter()|) for\n---   [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n---\n--- # Setup ~\n---\n--- This module doesn't need setup, but it can be done to improve usability.\n--- Setup with `require('mini.fuzzy').setup({})` (replace `{}` with your\n--- `config` table). It will create global Lua table `MiniFuzzy` which you can\n--- use for scripting or manually (with `:lua MiniFuzzy.*`).\n---\n--- See |MiniFuzzy.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minifuzzy_config` which should have same structure as\n--- `MiniFuzzy.config`.\n--- See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Notes ~\n---\n--- 1. Currently there is no explicit design to work with multibyte symbols,\n---    but simple examples should work.\n--- 2. Smart case is used: case insensitive if input word (which is usually a\n---    user input) is all lower case. Case sensitive otherwise.\n---@tag MiniFuzzy\n\n--- General design uses only width of found match and index of first letter\n--- match. No special characters or positions (like in fzy and fzf) are used.\n---\n--- Given non-empty input `word` and target `candidate`:\n--- - The goal is to find matching between `word`'s letters and letters in\n---   `candidate` which minimizes certain score. It is assumed that order of\n---   letters in `word` and those matched in `candidate` should be the same.\n---\n--- - Matching is represented by matched positions: an array `positions` of\n---   integers with length equal to number of letters in `word`. The following\n---   should be always true in case of a match: `candidate`'s letter at index\n---   `positions[i]` is letters[i]` for all valid `i`.\n---\n--- - Matched positions are evaluated based only on two features: their width\n---   (number of indexes between first and last positions) and first match\n---   (index of first letter match). There is a global setting `cutoff` for\n---   which all feature values greater than it can be considered \"equally bad\".\n---\n--- - Score of matched positions is computed with following explicit formula:\n---   `cutoff * min(width, cutoff) + min(first, cutoff)`. It is designed to be\n---   equivalent to first comparing widths (lower is better) and then comparing\n---   first match (lower is better). For example, if `word = 'time'`:\n---     - '_time' (width 4) will have a better match than 't_ime' (width 5).\n---     - 'time_a' (width 4, first 1) will have a better match than 'a_time'\n---       (width 4, first 3).\n---\n--- - Final matched positions are those which minimize score among all possible\n---   matched positions of `word` and `candidate`.\n---@tag MiniFuzzy-algorithm\n\n-- Module definition ==========================================================\nlocal MiniFuzzy = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniFuzzy.config|.\n---\n---@usage >lua\n---   require('mini.fuzzy').setup() -- use default config\n---   -- OR\n---   require('mini.fuzzy').setup({}) -- replace {} with your config table\n--- <\nMiniFuzzy.setup = function(config)\n  -- Export module\n  _G.MiniFuzzy = MiniFuzzy\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniFuzzy.config = {\n  -- Maximum allowed value of match features (width and first match). All\n  -- feature values greater than cutoff can be considered \"equally bad\".\n  cutoff = 100,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Compute match data\n---\n---@param word string Input word (usually user input).\n---@param candidate string Target word (usually with which matching is done).\n---\n---@return table Matching information:\n---   - <positions> `(table|nil)` - array with letter indexes inside `candidate`\n---     which matched to corresponding letters in `word`. It is empty array if\n---     `word` is empty string and `nil` if no match.\n---   - <score> `number` - positive number representing how good the match is\n---     (lower is better). It is `-1` if no match or word is empty string.\nMiniFuzzy.match = function(word, candidate)\n  -- Use 'smart case'\n  candidate = word == word:lower() and candidate:lower() or candidate\n  local positions = H.find_best_positions(H.string_to_letters(word), candidate)\n  return { positions = positions, score = H.score_positions(positions) }\nend\n\n--- Filter string array\n---\n--- - Keep only input elements which match `word`.\n--- - Sort from best to worst matches (based on score and index in original\n---   array, both lower is better).\n---\n---@param word string String which will be searched.\n---@param candidate_array table Lua array of strings inside which word will be\n---   searched.\n---\n---@return ... Arrays of matched candidates and their indexes in original input.\nMiniFuzzy.filtersort = function(word, candidate_array)\n  -- Use 'smart case'. Create new array to preserve input for later filtering\n  local cand_array = word == word:lower() and vim.tbl_map(string.lower, candidate_array) or candidate_array\n  local filter_ids = H.make_filter_indexes(word, cand_array)\n  table.sort(filter_ids, H.compare_filter_indexes)\n\n  return H.filter_by_indexes(candidate_array, filter_ids)\nend\n\n--- Fuzzy matching for `lsp_completion.process_items` of |MiniCompletion.config|\n---\n---@param items table Array with LSP 'textDocument/completion' response items.\n---@param base string Word to complete.\n---\n---@return table Array of items with text (`filterText` or `label`) fuzzy matching `base`.\nMiniFuzzy.process_lsp_items = function(items, base)\n  local words = vim.tbl_map(function(x) return x.filterText or x.label end, items)\n  local _, match_inds = MiniFuzzy.filtersort(base, words)\n  return vim.tbl_map(function(i) return items[i] end, match_inds)\nend\n\n--- Custom getter for `telescope.nvim` sorter\n---\n--- Designed as a value for file and generic sorter of 'telescope.nvim'.\n---\n---@param opts table|nil Options (currently not used).\n---\n---@usage >lua\n---   require('telescope').setup({\n---     defaults = {\n---       generic_sorter = require('mini.fuzzy').get_telescope_sorter\n---     }\n---   })\n--- <\nMiniFuzzy.get_telescope_sorter = function(opts)\n  opts = opts or {}\n\n  return require('telescope.sorters').Sorter:new({\n    start = function(self, prompt)\n      -- Cache prompt's letters\n      self.letters = H.string_to_letters(prompt)\n\n      -- Use 'smart case': insensitive if `prompt` is lowercase\n      self.case_sensitive = prompt ~= prompt:lower()\n    end,\n\n    -- @param self\n    -- @param prompt (which is the text on the line)\n    -- @param line (entry.ordinal)\n    -- @param entry (the whole entry)\n    scoring_function = function(self, _, line, _)\n      if #self.letters == 0 then return 1 end\n      line = self.case_sensitive and line or line:lower()\n      local positions = H.find_best_positions(self.letters, line)\n      return H.score_positions(positions)\n    end,\n\n    -- Currently there doesn't seem to be a proper way to cache matched\n    -- positions from inside of `scoring_function` (see `highlighter` code of\n    -- `get_fzy_sorter`'s output). Besides, it seems that `display` and `line`\n    -- arguments might be different. So, extra calls to `match` are made.\n    highlighter = function(self, _, display)\n      if #self.letters == 0 or #display == 0 then return {} end\n      display = self.case_sensitive and display or display:lower()\n      return H.find_best_positions(self.letters, display)\n    end,\n  })\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniFuzzy.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  if not (type(config.cutoff) == 'number' and config.cutoff >= 1) then\n    H.error('`cutoff` should be number not less than 1, not ' .. type(config.cutoff))\n  end\n\n  return config\nend\n\nH.apply_config = function(config) MiniFuzzy.config = config end\n\nH.is_disabled = function() return vim.g.minifuzzy_disable == true or vim.b.minifuzzy_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniFuzzy.config, vim.b.minifuzzy_config or {}, config or {})\nend\n\n-- Fuzzy matching -------------------------------------------------------------\n---@param letters table Array of letters from input word\n---@param candidate string String of interest\n---\n---@return table|nil Table with matched positions (in `candidate`) if there is a\n---   match, `nil` otherwise.\n---@private\nH.find_best_positions = function(letters, candidate)\n  local n_candidate, n_letters = #candidate, #letters\n  if n_letters == 0 then return {} end\n  if n_candidate < n_letters then return nil end\n\n  -- Search forward to find matching positions with left-most last letter match\n  local pos_last = 0\n  for let_i = 1, #letters do\n    pos_last = candidate:find(letters[let_i], pos_last + 1)\n    if not pos_last then break end\n  end\n\n  -- Candidate is matched only if word's last letter is found\n  if not pos_last then return nil end\n\n  -- If there is only one letter, it is already the best match (there will not\n  -- be better width and it has lowest first match)\n  if n_letters == 1 then return { pos_last } end\n\n  -- Compute best match positions by iteratively checking all possible last\n  -- letter matches (at and after initial one). At end of each iteration\n  -- `best_pos_last` holds best match for last letter among all previously\n  -- checked such matches.\n  local best_pos_last, best_width = pos_last, math.huge\n  local rev_candidate = candidate:reverse()\n\n  local cutoff = H.get_config().cutoff\n  while pos_last do\n    -- Simulate computing best match positions ending exactly at `pos_last` by\n    -- going backwards from current last letter match. This works because it\n    -- minimizes width which is the only way to find match with lower score.\n    -- Not actually creating table with positions and then directly computing\n    -- score increases speed by up to 40% (on small frequent input word with\n    -- relatively wide candidate, such as file paths of nested directories).\n    local rev_first = n_candidate - pos_last + 1\n    for i = #letters - 1, 1, -1 do\n      rev_first = rev_candidate:find(letters[i], rev_first + 1)\n    end\n    local first = n_candidate - rev_first + 1\n    local width = math.min(pos_last - first + 1, cutoff)\n\n    -- Using strict sign is crucial because when two last letter matches result\n    -- into positions with similar width, the one which was created earlier\n    -- (i.e. with smaller last letter match) will have smaller first letter\n    -- match (hence better score).\n    if width < best_width then\n      best_pos_last, best_width = pos_last, width\n    end\n\n    -- Advance iteration\n    pos_last = candidate:find(letters[n_letters], pos_last + 1)\n  end\n\n  -- Actually compute best matched positions from best last letter match\n  local best_positions = { best_pos_last }\n  local rev_pos = n_candidate - best_pos_last + 1\n  for i = #letters - 1, 1, -1 do\n    rev_pos = rev_candidate:find(letters[i], rev_pos + 1)\n    -- For relatively small number of letters (around 10, which is main use\n    -- case) inserting to front seems to have better performance than\n    -- inserting at end and then reversing.\n    table.insert(best_positions, 1, n_candidate - rev_pos + 1)\n  end\n\n  return best_positions\nend\n\n-- Compute score of matched positions. Smaller values indicate better match\n-- (i.e. like distance). Reasoning behind the score is for it to produce the\n-- same ordering as with sequential comparison of match's width and first\n-- position. So it shouldn't really be perceived as linear distance (difference\n-- between scores don't really matter, only their comparison with each other).\n--\n-- Reasoning behind comparison logic (based on 'time' input):\n-- - '_time' is better than 't_ime' (width is smaller).\n-- - 'time_aa' is better than 'aa_time' (same width, first match is smaller).\n--\n-- Returns -1 if `positions` is `nil` or empty.\nH.score_positions = function(positions)\n  if positions == nil or #positions == 0 then return -1 end\n  local first, last = positions[1], positions[#positions]\n  local cutoff = H.get_config().cutoff\n  return cutoff * math.min(last - first + 1, cutoff) + math.min(first, cutoff)\nend\n\nH.make_filter_indexes = function(word, candidate_array)\n  local res, letters = {}, H.string_to_letters(word)\n  for i, cand in ipairs(candidate_array) do\n    local positions = H.find_best_positions(letters, cand)\n    if positions ~= nil then table.insert(res, { index = i, score = H.score_positions(positions) }) end\n  end\n  return res\nend\n\nH.compare_filter_indexes = function(a, b) return a.score < b.score or (a.score == b.score and a.index < b.index) end\n\nH.filter_by_indexes = function(candidate_array, ids)\n  local res, res_ids = {}, {}\n  for _, id in pairs(ids) do\n    table.insert(res, candidate_array[id.index])\n    table.insert(res_ids, id.index)\n  end\n  return res, res_ids\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.fuzzy) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.string_to_letters = function(s) return vim.tbl_map(vim.pesc, vim.split(s, '')) end\n\nreturn MiniFuzzy\n"
  },
  {
    "path": "lua/mini/git.lua",
    "content": "--- *mini.git* Git integration\n---\n--- MIT License Copyright (c) 2024 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Automated tracking of Git related data: root path, status, HEAD, etc.\n---   Exposes buffer-local variables for convenient use in statusline.\n---   See |MiniGit.enable()| and |MiniGit.get_buf_data()| for more information.\n---\n--- - |:Git| command for executing any `git` call inside file's repository root with\n---   deeper current instance integration (show output as notification/buffer,\n---   use to edit commit messages, etc.).\n---\n--- - Helper functions to inspect Git history:\n---     - |MiniGit.show_range_history()| shows how certain line range evolved.\n---     - |MiniGit.show_diff_source()| shows file state as it was at diff entry.\n---     - |MiniGit.show_at_cursor()| shows Git related data depending on context.\n---\n--- What it doesn't do:\n---\n--- - Replace fully featured Git client. Rule of thumb: if feature does not rely\n---   on a state of current Neovim (opened buffers, etc.), it is out of scope.\n---   For more functionality, use either |mini.diff| or fully featured Git client.\n---\n--- Sources with more details:\n--- - |:Git|\n--- - |MiniGit-examples|\n--- - |MiniGit.enable()|\n--- - |MiniGit.get_buf_data()|\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.git').setup({})` (replace `{}` with\n--- your `config` table). It will create global Lua table `MiniGit` which you can use\n--- for scripting or manually (with `:lua MiniGit.*`).\n---\n--- See |MiniGit.config| for `config` structure and default values.\n---\n--- # Comparisons ~\n---\n--- - [tpope/vim-fugitive](https://github.com/tpope/vim-fugitive):\n---     - Mostly a dedicated Git client, while this module is not (by design).\n---     - Provides buffer-local Git data only through fixed statusline component,\n---       while this module has richer data in the form of a Lua table.\n---     - Both provide |:Git| command with 'vim-fugitive' treating some cases\n---       extra specially (like `:Git blame`, etc.), while this module mostly\n---       treats all cases the same. See |MiniGit-examples| for how they can be\n---       manually customized.\n---       Also this module provides slightly different (usually richer)\n---       completion suggestions.\n---\n--- - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit):\n---     - Similar to 'tpope/vim-fugitive', but without `:Git` command.\n---\n--- - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim):\n---     - Provides buffer-local Git data with emphasis on granular diff status,\n---       while this module is more oriented towards repository and file level\n---       data (root, HEAD, file status, etc.). Use |mini.diff| for diff tracking.\n---\n--- # Disabling ~\n---\n--- To prevent buffer(s) from being tracked, set `vim.g.minigit_disable` (globally)\n--- or `vim.b.minigit_disable` (for a buffer) to `true`. Considering high number of\n--- different scenarios and customization intentions, writing exact rules for\n--- disabling module's functionality is left to user.\n--- See |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniGit\n\n--- # Statusline component ~\n---\n--- Tracked buffer data can be used in statusline via `vim.b.minigit_summary_string`\n--- buffer-local variable. It is expected to be used as is. To show another info,\n--- tweak buffer-local variable directly inside `MiniGitUpdated` `User` event: >lua\n---\n---   -- Use only HEAD name as summary string\n---   local format_summary = function(data)\n---     -- Utilize buffer-local table summary\n---     local summary = vim.b[data.buf].minigit_summary\n---     vim.b[data.buf].minigit_summary_string = summary.head_name or ''\n---   end\n---\n---   local au_opts = { pattern = 'MiniGitUpdated', callback = format_summary }\n---   vim.api.nvim_create_autocmd('User', au_opts)\n--- <\n--- # Tweaking command output ~\n---\n--- Buffer output of |:Git| command can be tweaked inside autocommand for\n--- `MiniGitCommandSplit` `User` event (see |MiniGit-command-events|).\n--- For example, to make `:vertical Git blame -- %` align blame output with the\n--- current window state, use the following code: >lua\n---\n---   local align_blame = function(au_data)\n---     if au_data.data.git_subcommand ~= 'blame' then return end\n---\n---     -- Align blame output with source\n---     local win_src = au_data.data.win_source\n---     vim.wo.wrap = false\n---     vim.fn.winrestview({ topline = vim.fn.line('w0', win_src) })\n---     vim.api.nvim_win_set_cursor(0, { vim.fn.line('.', win_src), 0 })\n---\n---     -- Bind both windows so that they scroll together\n---     vim.wo[win_src].scrollbind, vim.wo.scrollbind = true, true\n---   end\n---\n---   local au_opts = { pattern = 'MiniGitCommandSplit', callback = align_blame }\n---   vim.api.nvim_create_autocmd('User', au_opts)\n--- <\n--- # History navigation ~\n---\n--- Function |MiniGit.show_at_cursor()| is specifically exported to make Git\n--- history navigation easier. Here are some different ways it can be used:\n---\n--- - Call inside buffer for already committed file to show the evolution of\n---   the current line (or visually selected range) through history.\n---   It is essentially a `:Git log HEAD` with proper `-L` flag.\n---   This also works inside output of |MiniGit.show_diff_source()|.\n---\n--- - Call with cursor on commit hash to inspect that commit in full.\n---   This is usually helpful in the output of `:Git log`.\n---\n--- - Call with cursor inside diff entry to inspect its file in the state how it\n---   was at certain commit. By default it shows state after commit, unless cursor\n---   is on the \"deleted\" line (i.e. line starting with \"-\") in which case\n---   state before commit is shown.\n---\n--- This workflow can be made more interactive when used with mapping, like this: >lua\n---\n---   local rhs = '<Cmd>lua MiniGit.show_at_cursor()<CR>'\n---   vim.keymap.set({ 'n', 'x' }, '<Leader>gs', rhs, { desc = 'Show at cursor' })\n--- <\n---@tag MiniGit-examples\n\n--- The `:Git` user command runs `git` CLI call with extra integration for currently\n--- opened Neovim process:\n--- - Command is executed inside repository root of the currently active file\n---   (or |current-directory| if file is not tracked by this module).\n---\n--- - Command output is shown either in dedicated buffer in window split or as\n---   notification via |vim.notify()|. Which method is used depends on whether\n---   particular Git subcommand is supposed to show data for user to inspect\n---   (like `log`, `status`, etc.) or not (like `commit`, `push`, etc.). This is\n---   determined automatically based on the data Git itself provides.\n---   Split window is made current after command execution.\n---\n---   Use split-related |:command-modifiers| (|:vertical|, |:horizontal|, or |:tab|)\n---   to force output in a particular type of split. Default split direction is\n---   controlled by `command.split` in |MiniGit.config|.\n---\n---   Use |:silent| command modifier to not show any output.\n---\n---   Errors and warnings are always shown as notifications.\n---\n---   See |MiniGit-examples| for the example of tweaking command output.\n---\n--- - Editor for tasks that require interactive user input (like `:Git commit` or\n---   `:Git rebase --interactive`) is opened inside current session in a separate\n---   split. Make modifications as in regular buffer, |:write| changes followed by\n---   |:close| / |:quit| for Git CLI command to resume.\n---\n--- Examples of usage:\n--- - `:Git log --oneline` - show compact log of current repository.\n--- - `:vert Git blame -- %` - show latest commits per line in vertical split.\n--- - `:Git help rebase` - show help page for `rebase` subcommand.\n--- - `:Git -C <cwd> status` - execute `git status` inside |current-directory|.\n---\n--- There is also a context aware completion which can be invoked with `<Tab>`:\n--- - If completed word starts with \"-\", options for the current Git subcommand\n---   are shown. Like completion at `:Git log -` will suggest `-L`, `--oneline`, etc.\n--- - If there is an explicit \" -- \" to the cursor's left, incremental path\n---   suggestions will be shown.\n--- - If there is no recognized Git subcommand yet, show list of subcommands.\n---   Otherwise for some common subcommands list of its targets will be suggested:\n---   like for `:Git branch` it will be list of branches, etc.\n---\n--- Notes:\n--- - Paths are always treated as relative to command's execution directory\n---   (file's repository root or |current-directory| if absent).\n--- - Don't use quotes for entries containing space, escape it with `\\` directly.\n---   Like `:Git commit -m Hello\\ world` and not `:Git commit -m 'Hello world'`\n---   (which treats `'Hello` and `world'` as separate arguments).\n---\n--- # Events ~\n--- *MiniGit-command-events*\n---\n--- There are several `User` events triggered during command execution:\n---\n--- - `MiniGitCommandDone` - after command is done executing. For Lua callbacks it\n---   provides a special `data` table with the following fields:\n---     - <cmd_input> `(table)` - structured data about executed command.\n---       Has same structure as Lua function input in |nvim_create_user_command()|.\n---     - <cwd> `(string)` - directory path inside which Git command was executed.\n---     - <exit_code> `(number)` - exit code of CLI process.\n---     - <git_command> `(table)` - array with arguments of full executed command.\n---     - <git_subcommand> `(string)` - detected Git subcommand (like \"log\", etc.).\n---     - <stderr> `(string)` - `stderr` process output.\n---     - <stdout> `(string)` - `stdout` process output.\n---\n--- - `MiniGitCommandSplit` - after command showed its output in a split. Triggered\n---   after `MiniGitCommandDone` and provides similar `data` table with extra fields:\n---     - <win_source> `(number)` - window identifier of \"source\" window (current at\n---       the moment before command execution).\n---     - <win_stdout> `(number)` - window identifier of command output.\n---@tag :Git\n\n---@alias __git_buf_id number Target buffer identifier. Default: 0 for current buffer.\n---@alias __git_split_field <split> `(string)` - split direction. One of \"horizontal\", \"vertical\",\n---     \"tab\", or \"auto\" (default). Value \"auto\" uses |:vertical| if only 'mini.git'\n---     buffers are shown in the tabpage and |:tab| otherwise.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n-- Module definition ==========================================================\nlocal MiniGit = {}\nlocal H = {}\n\n--- Module setup\n---\n--- Besides general side effects (see |mini.nvim|), it also:\n--- - Sets up auto enabling in every normal buffer for an actual file on disk.\n--- - Creates |:Git| command.\n---\n---@param config table|nil Module config table. See |MiniGit.config|.\n---\n---@usage >lua\n---   require('mini.git').setup() -- use default config\n---   -- OR\n---   require('mini.git').setup({}) -- replace {} with your config table\n--- <\nMiniGit.setup = function(config)\n  -- Export module\n  _G.MiniGit = MiniGit\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Ensure proper Git executable\n  local exec = config.job.git_executable\n  H.has_git = vim.fn.executable(exec) == 1\n  if not H.has_git then H.notify('There is no `' .. exec .. '` executable', 'WARN') end\n\n  -- Define behavior\n  H.create_autocommands()\n  for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n    H.auto_enable({ buf = buf_id })\n  end\n\n  -- Create user commands\n  H.create_user_commands()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Job ~\n---\n--- `config.job` contains options for customizing CLI executions.\n---\n--- `job.git_executable` defines a full path to Git executable. Default: \"git\".\n---\n--- `job.timeout` is a duration (in ms) from job start until it is forced to stop.\n--- Default: 30000.\n---\n--- # Command ~\n---\n--- `config.command` contains options for customizing |:Git| command.\n---\n--- `command.split` defines default split direction for |:Git| command output. Can be\n--- one of \"horizontal\", \"vertical\", \"tab\", or \"auto\". Value \"auto\" uses |:vertical|\n--- if only 'mini.git' buffers are shown in the tabpage and |:tab| otherwise.\n--- Default: \"auto\".\nMiniGit.config = {\n  -- General CLI execution\n  job = {\n    -- Path to Git executable\n    git_executable = 'git',\n\n    -- Timeout (in ms) for each job before force quit\n    timeout = 30000,\n  },\n\n  -- Options for `:Git` command\n  command = {\n    -- Default split direction\n    split = 'auto',\n  },\n}\n--minidoc_afterlines_end\n\n--- Show Git related data at cursor\n---\n--- - If inside |mini.deps| confirmation buffer, show in split relevant commit data.\n--- - If there is a commit-like |<cword>|, show it in split.\n--- - If possible, show diff source via |MiniGit.show_diff_source()|.\n--- - If possible, show range history via |MiniGit.show_range_history()|.\n--- - Otherwise throw an error.\n---\n---@param opts table|nil Options. Possible values:\n---   - __git_split_field\n---   - Fields appropriate for forwarding to other functions.\nMiniGit.show_at_cursor = function(opts)\n  -- Try showing commit data at cursor\n  local commit, cwd\n  if vim.bo.filetype == 'minideps-confirm' then\n    commit, cwd = H.deps_pos_to_source()\n  else\n    local cword = vim.fn.expand('<cword>')\n    local is_commit = string.find(cword, '^%x%x%x%x%x%x%x+$') ~= nil and string.lower(cword) == cword\n    commit = is_commit and cword or nil\n    cwd = is_commit and H.get_git_cwd() or nil\n  end\n\n  if commit ~= nil and cwd ~= nil then\n    local split = H.normalize_split_opt((opts or {}).split or 'auto', 'opts.split')\n    local args = { 'show', '--stat', '--patch', commit }\n    local lines = H.git_cli_output(args, cwd)\n    if #lines == 0 then return H.notify('Can not show commit ' .. commit .. ' in repo ' .. cwd, 'WARN') end\n    H.show_in_split(split, lines, 'show', table.concat(args, ' '))\n    vim.bo.filetype = 'git'\n    return\n  end\n\n  -- Try showing diff source\n  if H.diff_pos_to_source() ~= nil then return MiniGit.show_diff_source(opts) end\n\n  -- Try showing range history if possible: either in Git repo (tracked or not;\n  -- after resolving symlinks) or diff source output.\n  local buf_id, buf_name = vim.api.nvim_get_current_buf(), vim.api.nvim_buf_get_name(0)\n  local path = vim.loop.fs_realpath(buf_name)\n  local path_dir = path == nil and '' or vim.fn.fnamemodify(path, ':h')\n\n  local is_in_git = H.is_buf_enabled(buf_id) or #H.git_cli_output({ 'rev-parse', '--show-toplevel' }, path_dir) > 0\n  local is_diff_source_output = H.parse_diff_source_buf_name(buf_name) ~= nil\n  if is_in_git or is_diff_source_output then return MiniGit.show_range_history(opts) end\n\n  H.notify('Nothing Git-related to show at cursor', 'WARN')\nend\n\n--- Show diff source\n---\n--- When buffer contains text formatted as unified patch (like after\n--- `:Git log --patch`, `:Git diff`, or |MiniGit.show_range_history()|),\n--- show state of the file at the particular state. Target commit/state, path,\n--- and line number are deduced from cursor position.\n---\n--- Notes:\n--- - Needs |current-directory| to be the Git root for relative paths to work.\n--- - Needs cursor to be inside hunk lines or on \"---\" / \"+++\" lines with paths.\n--- - Only basic forms of `:Git diff` output is supported: `:Git diff`,\n---   `:Git diff --cached`, and `:Git diff <commit>`.\n---\n---@param opts table|nil Options. Possible values:\n---   - __git_split_field\n---   - <target> `(string)` - which file state to show. One of \"before\", \"after\",\n---     \"both\" (both states in vertical split), \"auto\" (default). Value \"auto\"\n---     shows \"before\" state if cursor line starts with \"-\", otherwise - \"after\".\nMiniGit.show_diff_source = function(opts)\n  opts = vim.tbl_deep_extend('force', { split = 'auto', target = 'auto' }, opts or {})\n  local split = H.normalize_split_opt(opts.split, 'opts.split')\n  local target = opts.target\n  if not (target == 'auto' or target == 'before' or target == 'after' or target == 'both') then\n    H.error('`opts.target` should be one of \"auto\", \"before\", \"after\", \"both\".')\n  end\n\n  local src = H.diff_pos_to_source()\n  if src == nil then\n    return H.notify('Could not find diff source. Ensure that cursor is inside a valid diff lines of git log.', 'WARN')\n  end\n  if target == 'auto' then target = src.init_prefix == '-' and 'before' or 'after' end\n\n  local cwd = H.get_git_cwd()\n  local show = function(commit, path, mods)\n    local is_worktree, args, lines = commit == true, nil, nil\n    if is_worktree then\n      args, lines = { 'edit', vim.fn.fnameescape(path) }, vim.fn.readfile(path)\n    else\n      args = { 'show', commit .. ':' .. path }\n      lines = H.git_cli_output(args, cwd)\n    end\n    if #lines == 0 and not is_worktree then\n      return H.notify('Can not show ' .. path .. ' at commit ' .. commit, 'WARN')\n    end\n    H.show_in_split(mods, lines, 'show', table.concat(args, ' '))\n  end\n\n  local has_before_shown = false\n  if target ~= 'after' then\n    if src.path_before == nil then\n      H.notify('No \"before\" as file was created', 'WARN')\n    else\n      show(src.commit_before, src.path_before, split)\n      vim.api.nvim_win_set_cursor(0, { src.lnum_before, 0 })\n      has_before_shown = true\n    end\n  end\n\n  if target ~= 'before' then\n    if src.path_after == nil then\n      H.notify('No \"after\" as file was deleted', 'WARN')\n    else\n      local mods_after = has_before_shown and 'belowright vertical' or split\n      show(src.commit_after, src.path_after, mods_after)\n      vim.api.nvim_win_set_cursor(0, { src.lnum_after, 0 })\n    end\n  end\nend\n\n--- Show range history\n---\n--- Compute and show in split data about how particular line range in current\n--- buffer evolved through Git history. Essentially a `git log` with `-L` flag.\n---\n--- Notes:\n--- - Works well with |MiniGit.diff_foldexpr()|.\n--- - Does not work if there are uncommited changes, as there is no easy way to\n---   compute effective range line numbers.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <line_start> `(number)` - range start line.\n---   - <line_end> `(number)` - range end line.\n---     If both <line_start> and <line_end> are not supplied, they default to\n---     current line in Normal mode and visual selection in Visual mode.\n---   - <log_args> `(table)` - array of options to append to `git log` call.\n---   - __git_split_field\nMiniGit.show_range_history = function(opts)\n  local default_opts = { line_start = nil, line_end = nil, log_args = nil, split = 'auto' }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n  local line_start, line_end = H.normalize_range_lines(opts.line_start, opts.line_end)\n  local log_args = opts.log_args or {}\n  if not H.islist(log_args) then H.error('`opts.log_args` should be an array.') end\n  local split = H.normalize_split_opt(opts.split, 'opts.split')\n\n  -- Construct `:Git log` command that works both with regular files and\n  -- buffers from `show_diff_source()`\n  local buf_name, cwd = vim.api.nvim_buf_get_name(0), H.get_git_cwd()\n  local commit, rel_path = H.parse_diff_source_buf_name(buf_name)\n  if commit == nil then\n    commit = 'HEAD'\n    local cwd_pattern = '^' .. vim.pesc(cwd:gsub('\\\\', '/')) .. '/'\n    rel_path = H.get_buf_realpath(0):gsub('\\\\', '/'):gsub(cwd_pattern, '')\n  end\n\n  -- Ensure no uncommitted changes as they might result into improper `-L` arg\n  local diff = commit == 'HEAD' and H.git_cli_output({ 'diff', '-U0', 'HEAD', '--', rel_path }, cwd) or {}\n  if #diff ~= 0 then\n    return H.notify('Current file has uncommitted lines. Commit or stash before exploring history.', 'WARN')\n  end\n\n  -- Show log in split\n  local range_flag = string.format('-L%d,%d:%s', line_start, line_end, rel_path)\n  local args = { 'log', range_flag, commit, unpack(log_args) }\n  local history = H.git_cli_output(args, cwd)\n  if #history == 0 then return H.notify('Could not get range history', 'WARN') end\n  H.show_in_split(split, history, 'log', table.concat(args, ' '))\nend\n\n--- Fold expression for Git logs\n---\n--- Folds contents of hunks, file patches, and log entries in unified diff.\n--- Useful for filetypes \"diff\" (like after `:Git diff`) and \"git\" (like after\n--- `:Git log --patch` or `:Git show` for commit).\n--- Works well with |MiniGit.show_range_history()|.\n---\n--- General idea of folding levels (use |zr| and |zm| to adjust interactively):\n--- - At level 0 there is one line per whole patch or log entry.\n--- - At level 1 there is one line per patched file.\n--- - At level 2 there is one line per hunk.\n--- - At level 3 there is no folds.\n---\n--- For automated setup, set the following for \"git\" and \"diff\" filetypes (either\n--- inside |FileType| autocommand or |ftplugin|): >vim\n---\n---   setlocal foldmethod=expr foldexpr=v:lua.MiniGit.diff_foldexpr()\n--- <\n---@param lnum number|nil Line number for which fold level is computed.\n---   Default: |v:lnum|.\n---\n---@return number|string Line fold level. See |fold-expr|.\nMiniGit.diff_foldexpr = function(lnum)\n  lnum = lnum or vim.v.lnum\n  if H.is_log_entry_header(lnum + 1) or H.is_log_entry_header(lnum) then return 0 end\n  if H.is_file_entry_header(lnum) then return 1 end\n  if H.is_hunk_header(lnum) then return 2 end\n  if H.is_hunk_header(lnum - 1) then return 3 end\n  return '='\nend\n\n--- Enable Git tracking in a file buffer\n---\n--- Tracking is done by reacting to changes in file content or file's repository\n--- in the form of keeping buffer data up to date. The data can be used via:\n--- - |MiniGit.get_buf_data()|. See its help for a list of actually tracked data.\n--- - `vim.b.minigit_summary` (table) and `vim.b.minigit_summary_string` (string)\n---   buffer-local variables which are more suitable for statusline.\n---   `vim.b.minigit_summary_string` contains information about HEAD, file status,\n---   and in progress action (see |MiniGit.get_buf_data()| for more details).\n---   See |MiniGit-examples| for how it can be tweaked and used in statusline.\n---\n--- Note: this function is called automatically for all new normal buffers.\n--- Use it explicitly if buffer was disabled.\n---\n--- `User` event `MiniGitUpdated` is triggered whenever tracking data is updated.\n--- Note that not all data listed in |MiniGit.get_buf_data()| can be present (yet)\n--- at the point of event being triggered.\n---\n---@param buf_id __git_buf_id\nMiniGit.enable = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n\n  -- Don't enable more than once\n  if H.is_buf_enabled(buf_id) or H.is_disabled(buf_id) or not H.has_git then return end\n\n  -- Enable only in buffers which *can* be part of Git repo\n  local path = H.get_buf_realpath(buf_id)\n  if path == '' or vim.fn.filereadable(path) ~= 1 then return end\n\n  -- Start tracking\n  H.cache[buf_id] = {}\n  H.setup_buf_behavior(buf_id)\n  H.start_tracking(buf_id, path)\nend\n\n--- Disable Git tracking in buffer\n---\n---@param buf_id __git_buf_id\nMiniGit.disable = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return end\n  H.cache[buf_id] = nil\n\n  -- Cleanup\n  pcall(vim.api.nvim_del_augroup_by_id, buf_cache.augroup)\n  vim.b[buf_id].minigit_summary, vim.b[buf_id].minigit_summary_string = nil, nil\n\n  -- - Unregister buffer from repo watching with possibly more cleanup\n  local repo = buf_cache.repo\n  if H.repos[repo] == nil then return end\n  H.repos[repo].buffers[buf_id] = nil\n  if vim.tbl_count(H.repos[repo].buffers) == 0 then\n    H.teardown_repo_watch(repo)\n    H.repos[repo] = nil\n  end\nend\n\n--- Toggle Git tracking in buffer\n---\n--- Enable if disabled, disable if enabled.\n---\n---@param buf_id __git_buf_id\nMiniGit.toggle = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n  if H.is_buf_enabled(buf_id) then return MiniGit.disable(buf_id) end\n  return MiniGit.enable(buf_id)\nend\n\n--- Get buffer data\n---\n---@param buf_id __git_buf_id\n---\n---@return table|nil Table with buffer Git data or `nil` if buffer is not enabled.\n---   If the file is not part of Git repo, table will be empty.\n---   Table has the following fields:\n---   - <repo> `(string)` - full path to '.git' directory.\n---   - <root> `(string)` - full path to worktree root.\n---   - <head> `(string)` - full commit of current HEAD.\n---   - <head_name> `(string)` - short name of current HEAD (like \"master\").\n---     For detached HEAD it is \"HEAD\".\n---   - <status> `(string)` - two character file status as returned by `git status`.\n---   - <in_progress> `(string)` - name of action(s) currently in progress\n---     (bisect, merge, etc.). Can be a combination of those separated by \",\".\nMiniGit.get_buf_data = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return nil end\n  --stylua: ignore\n  return {\n    repo   = buf_cache.repo,   root        = buf_cache.root,\n    head   = buf_cache.head,   head_name   = buf_cache.head_name,\n    status = buf_cache.status, in_progress = buf_cache.in_progress,\n  }\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniGit.config\n\n-- Cache per enabled buffer. Values are tables with fields:\n-- - <augroup> - identifier of augroup defining buffer behavior.\n-- - <repo> - path to buffer's repo ('.git' directory).\n-- - <root> - path to worktree root.\n-- - <head> - full commit of `HEAD`.\n-- - <head_name> - short name of `HEAD` (`'HEAD'` for detached head).\n-- - <status> - current file status.\n-- - <in_progress> - string name of action in progress (bisect, merge, etc.)\nH.cache = {}\n\n-- Cache per repo (git directory) path. Values are tables with fields:\n-- - <fs_event> - `vim.loop` event for watching repo dir.\n-- - <timer> - timer to debounce repo changes.\n-- - <buffers> - map of buffers which should are part of repo.\nH.repos = {}\n\n-- Termporary file used as config for `GIT_EDITOR`\nH.git_editor_config = nil\n\n-- Data about supported Git subcommands. Initialized lazily. Fields:\n-- - <supported> - array of supported one word commands.\n-- - <complete> - array of commands to complete directly after `:Git`.\n-- - <info> - map with fields as commands which show something to user.\n-- - <options> - map of cached options per command; initialized lazily.\n-- - <alias> - map of alias command name to command it implements.\nH.git_subcommands = nil\n\n-- Whether to temporarily skip some checks (like when inside `GIT_EDITOR`)\nH.skip_timeout = false\nH.skip_sync = false\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('job', config.job, 'table')\n  H.check_type('command', config.command, 'table')\n\n  H.check_type('job.git_executable', config.job.git_executable, 'string')\n  H.check_type('job.timeout', config.job.timeout, 'number')\n  if not pcall(H.normalize_split_opt, config.command.split) then\n    H.error('`command.split` should be one of \"auto\", \"horizontal\", \"vertical\", \"tab\"')\n  end\n\n  return config\nend\n\nH.apply_config = function(config) MiniGit.config = config end\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniGit', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  -- NOTE: Try auto enabling buffer on every `BufEnter` to not have `:edit`\n  -- disabling buffer, as it calls `on_detach()` from buffer watcher\n  au('BufEnter', '*', H.auto_enable, 'Enable Git tracking')\nend\n\nH.is_disabled = function(buf_id) return vim.g.minigit_disable == true or vim.b[buf_id or 0].minigit_disable == true end\n\nH.create_user_commands = function()\n  local opts = { bang = true, nargs = '+', complete = H.command_complete, desc = 'Execute Git command' }\n  vim.api.nvim_create_user_command('Git', H.command_impl, opts)\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_enable = vim.schedule_wrap(function(data)\n  local buf = data.buf\n  if not (vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == '' and vim.bo[buf].buflisted) then return end\n  MiniGit.enable(data.buf)\nend)\n\n-- Command --------------------------------------------------------------------\nH.command_impl = function(input)\n  if not H.has_git then\n    return H.notify('There is no `' .. MiniGit.config.job.git_executable .. '` executable', 'ERROR')\n  end\n\n  H.ensure_git_subcommands()\n\n  -- Define Git editor to be used if needed. The way it works is: execute\n  -- command, wait for it to exit, use content of edited file. So to properly\n  -- wait for user to finish edit, start fresh headless process which opens\n  -- file in current session/process. It exits after the user is done editing\n  -- (deletes the buffer or closes the window).\n  H.ensure_git_editor(input.mods)\n  -- NOTE: use `vim.v.progpath` to have same runtime\n  local editor = H.cli_escape(vim.v.progpath) .. ' --clean --headless -u ' .. H.cli_escape(H.git_editor_config)\n\n  -- Setup custom environment variables for better reproducibility\n  local env_vars = {}\n  -- - Use Git related variables to use instance for editing\n  env_vars.GIT_EDITOR, env_vars.GIT_SEQUENCE_EDITOR, env_vars.GIT_PAGER = editor, editor, ''\n  -- - Make output as much machine readable as possible\n  env_vars.NO_COLOR, env_vars.TERM = 1, 'dumb'\n  local env = H.make_spawn_env(env_vars)\n\n  -- Setup spawn arguments\n  local args = vim.tbl_map(H.expandcmd, input.fargs)\n  local command = { MiniGit.config.job.git_executable, unpack(args) }\n  local cwd = H.get_git_cwd()\n\n  local cmd_data = { cmd_input = input, git_command = command, cwd = cwd }\n  local is_done_track = { done = false }\n  local on_done = H.command_make_on_done(cmd_data, is_done_track)\n\n  H.cli_run(command, cwd, on_done, { env = env })\n\n  -- If needed, synchronously wait for job to finish\n  local sync_check = function() return H.skip_sync or is_done_track.done end\n  if not input.bang then vim.wait(MiniGit.config.job.timeout + 10, sync_check, 1) end\nend\n\n--stylua: ignore\nH.ensure_git_subcommands = function()\n  if H.git_subcommands ~= nil then return end\n  local git_subcommands = {}\n\n  -- Compute all supported commands. All 'list-' are taken from Git source\n  -- 'command-list.txt' file. Be so granular and not just `main,nohelpers` in\n  -- order to not include purely man-page worthy items (like \"remote-ext\").\n  local lists_all = {\n    'list-mainporcelain',\n    'list-ancillarymanipulators', 'list-ancillaryinterrogators',\n    'list-foreignscminterface',\n    'list-plumbingmanipulators', 'list-plumbinginterrogators',\n    'others', 'alias',\n  }\n  local supported = H.git_cli_output({ '--list-cmds=' .. table.concat(lists_all, ',') })\n  if #supported == 0 then\n    -- Fall back only on basics if previous one failed for some reason\n    supported = {\n      'add', 'bisect', 'branch', 'clone', 'commit', 'diff', 'fetch', 'grep', 'init', 'log', 'merge',\n      'mv', 'pull', 'push', 'rebase', 'reset', 'restore', 'rm', 'show', 'status', 'switch', 'tag',\n    }\n  end\n  table.sort(supported)\n  git_subcommands.supported = supported\n\n  -- Compute complete list for commands by enhancing with two word commands.\n  -- Keep those lists manual as there is no good way to compute lazily.\n  local complete = vim.deepcopy(supported)\n  local add_twoword = function(prefix, suffixes)\n    if not vim.tbl_contains(supported, prefix) then return end\n    for _, suf in ipairs(suffixes) do table.insert(complete, prefix .. ' ' .. suf) end\n  end\n  add_twoword('bundle',           { 'create', 'list-heads', 'unbundle', 'verify' })\n  add_twoword('bisect',           { 'bad', 'good', 'log', 'replay', 'reset', 'run', 'skip', 'start', 'terms', 'view', 'visualize' })\n  add_twoword('commit-graph',     { 'verify', 'write' })\n  add_twoword('maintenance',      { 'run', 'start', 'stop', 'register', 'unregister' })\n  add_twoword('multi-pack-index', { 'expire', 'repack', 'verify', 'write' })\n  add_twoword('notes',            { 'add', 'append', 'copy', 'edit', 'get-ref', 'list', 'merge', 'prune', 'remove', 'show' })\n  add_twoword('p4',               { 'clone', 'rebase', 'submit', 'sync' })\n  add_twoword('reflog',           { 'delete', 'exists', 'expire', 'show' })\n  add_twoword('remote',           { 'add', 'get-url', 'prune', 'remove', 'rename', 'rm', 'set-branches', 'set-head', 'set-url', 'show', 'update' })\n  add_twoword('rerere',           { 'clear', 'diff', 'forget', 'gc', 'remaining', 'status' })\n  add_twoword('sparse-checkout',  { 'add', 'check-rules', 'disable', 'init', 'list', 'reapply', 'set' })\n  add_twoword('stash',            { 'apply', 'branch', 'clear', 'create', 'drop', 'list', 'pop', 'save', 'show', 'store' })\n  add_twoword('submodule',        { 'absorbgitdirs', 'add', 'deinit', 'foreach', 'init', 'set-branch', 'set-url', 'status', 'summary', 'sync', 'update' })\n  add_twoword('subtree',          { 'add', 'merge', 'pull', 'push', 'split' })\n  add_twoword('worktree',         { 'add', 'list', 'lock', 'move', 'prune', 'remove', 'repair', 'unlock' })\n  git_subcommands.complete = complete\n\n  -- Compute commands which are meant to show information. These will show CLI\n  -- output in separate buffer opposed to `vim.notify`.\n  local info_args = { '--list-cmds=list-info,list-ancillaryinterrogators,list-plumbinginterrogators' }\n  local info_commands = H.git_cli_output(info_args)\n  if #info_commands == 0 then info_commands = { 'bisect', 'diff', 'grep', 'log', 'show', 'status' } end\n  local info = {}\n  for _, cmd in ipairs(info_commands) do\n    info[cmd] = true\n  end\n  git_subcommands.info = info\n\n  -- Compute commands which aliases rely on\n  local alias_data = H.git_cli_output({ 'config', '--get-regexp', 'alias.*' })\n  local alias = {}\n  for _, l in ipairs(alias_data) do\n    -- Assume simple alias of the form `alias.xxx subcommand ...`\n    local alias_cmd, cmd = string.match(l, '^alias%.(%S+) (%S+)')\n    if vim.tbl_contains(supported, cmd) then alias[alias_cmd] = cmd end\n  end\n  git_subcommands.alias = alias\n\n  -- Initialize cache for command options. Initialize with `false` so that\n  -- actual values are computed lazily when needed for a command.\n  local options = { git = false }\n  for _, command in ipairs(supported) do\n    options[command] = false\n  end\n  git_subcommands.options = options\n\n  -- Cache results\n  H.git_subcommands = git_subcommands\nend\n\nH.ensure_git_editor = function(mods)\n  if H.git_editor_config == nil or not vim.fn.filereadable(H.git_editor_config) == 0 then\n    H.git_editor_config = vim.fn.tempname()\n  end\n\n  -- Create a private function responsible for editing Git file\n  MiniGit._edit = function(path, servername)\n    -- Define editor state before and after editing path\n    H.skip_timeout, H.skip_sync = true, true\n    local cleanup = function()\n      local _, channel = pcall(vim.fn.sockconnect, 'pipe', servername, { rpc = true })\n      pcall(vim.rpcnotify, channel, 'nvim_exec2', 'quitall!', {})\n      H.skip_timeout, H.skip_sync = false, false\n    end\n\n    -- Start file edit with proper modifiers in a special window\n    mods = H.ensure_mods_is_split(mods)\n    vim.cmd(mods .. ' split ' .. vim.fn.fnameescape(path))\n    H.define_minigit_window(cleanup)\n  end\n\n  -- Start editing file from first argument (as how `GIT_EDITOR` works) in\n  -- current instance and don't close until explicitly closed later from this\n  -- instance as set up in `MiniGit._edit()`\n  local lines = {\n    'lua << EOF',\n    string.format('local channel = vim.fn.sockconnect(\"pipe\", %s, { rpc = true })', vim.inspect(vim.v.servername)),\n    'local ins = vim.inspect',\n    'local lua_cmd = string.format(\"MiniGit._edit(%s, %s)\", ins(vim.fn.argv(0)), ins(vim.v.servername))',\n    'vim.rpcrequest(channel, \"nvim_exec_lua\", lua_cmd, {})',\n    'EOF',\n  }\n  vim.fn.writefile(lines, H.git_editor_config)\nend\n\nH.get_git_cwd = function()\n  local buf_cache = H.cache[vim.api.nvim_get_current_buf()] or {}\n  return buf_cache.root or vim.fn.getcwd()\nend\n\nH.command_make_on_done = function(cmd_data, is_done_track)\n  return vim.schedule_wrap(function(code, out, err)\n    -- Register that command is done executing (to enable sync execution)\n    is_done_track.done = true\n\n    -- Trigger \"done\" event\n    cmd_data.git_subcommand = H.command_parse_subcommand(cmd_data.git_command)\n    cmd_data.exit_code, cmd_data.stdout, cmd_data.stderr = code, out, err\n    H.trigger_event('MiniGitCommandDone', cmd_data)\n\n    -- Show stderr and stdout\n    if H.cli_err_notify(code, out, err) then return end\n    H.command_show_stdout(cmd_data)\n\n    -- Ensure that all buffers are up to date (avoids \"The file has been\n    -- changed since reading it\" warning)\n    vim.tbl_map(function(buf_id) vim.cmd('checktime ' .. buf_id) end, vim.api.nvim_list_bufs())\n  end)\nend\n\nH.command_show_stdout = function(cmd_data)\n  local stdout, mods, subcommand = cmd_data.stdout, cmd_data.cmd_input.mods, cmd_data.git_subcommand\n  if stdout == '' or (mods:find('silent') ~= nil and mods:find('unsilent') == nil) then return end\n\n  -- Show in split if explicitly forced or the command shows info.\n  -- Use `vim.notify` otherwise.\n  local should_split = H.mods_is_split(mods) or H.git_subcommands.info[subcommand]\n  if not should_split then return H.notify(stdout, 'INFO') end\n\n  local lines = vim.split(stdout, '\\n')\n  local name = table.concat(cmd_data.git_command, ' ')\n  cmd_data.win_source, cmd_data.win_stdout = H.show_in_split(mods, lines, subcommand, name)\n\n  -- Trigger \"split\" event\n  H.trigger_event('MiniGitCommandSplit', cmd_data)\nend\n\nH.command_parse_subcommand = function(command)\n  local res\n  for _, cmd in ipairs(command) do\n    if res == nil and vim.tbl_contains(H.git_subcommands.supported, cmd) then res = cmd end\n  end\n  return H.git_subcommands.alias[res] or res\nend\n\nH.command_complete = function(_, line, col)\n  -- Compute completion base manually to be \"at cursor\" and respect `\\ `\n  local base = H.get_complete_base(line:sub(1, col))\n  local candidates, compl_type = H.command_get_complete_candidates(line, col, base)\n  -- Allow several \"//\" at the end for path completion for easier \"chaining\"\n  if compl_type == 'path' then base = base:gsub('/+$', '/') end\n  return vim.tbl_filter(function(x) return vim.startswith(x, base) end, candidates)\nend\n\nH.get_complete_base = function(line)\n  local from, _, res = line:find('(%S*)$')\n  while from ~= nil do\n    local cur_from, _, cur_res = line:sub(1, from - 1):find('(%S*\\\\ )$')\n    if cur_res ~= nil then res = cur_res .. res end\n    from = cur_from\n  end\n  return (res:gsub([[\\ ]], ' '))\nend\n\nH.command_get_complete_candidates = function(line, col, base)\n  H.ensure_git_subcommands()\n\n  -- Determine current Git subcommand as the earliest present supported one\n  local subcmd, subcmd_end = nil, math.huge\n  for _, cmd in pairs(H.git_subcommands.supported) do\n    local _, ind = line:find(' ' .. cmd .. ' ', 1, true)\n    if ind ~= nil and ind < subcmd_end then\n      subcmd, subcmd_end = cmd, ind\n    end\n  end\n\n  subcmd = subcmd or 'git'\n  local cwd = H.get_git_cwd()\n\n  -- Determine command candidates:\n  -- - Commannd options if complete base starts with \"-\".\n  -- - Paths if after explicit \"--\".\n  -- - Git commands if there is none fully formed yet or cursor is at the end\n  --   of the command (to also suggest subcommands).\n  -- - Command targets specific for each command (if present).\n  if vim.startswith(base, '-') then return H.command_complete_option(subcmd) end\n  if line:sub(1, col):find(' -- ') ~= nil then return H.command_complete_path(cwd, base) end\n  if subcmd_end == math.huge or (subcmd_end - 1) == col then return H.git_subcommands.complete, 'subcommand' end\n\n  subcmd = H.git_subcommands.alias[subcmd] or subcmd\n  local complete_targets = H.command_complete_subcommand_targets[subcmd]\n  if complete_targets == nil then return {}, nil end\n  return complete_targets(cwd, base, line)\nend\n\nH.command_complete_option = function(command)\n  local cached_candidates = H.git_subcommands.options[command]\n  if cached_candidates == nil then return {} end\n  if type(cached_candidates) == 'table' then return cached_candidates end\n\n  -- Use alias's command to compute the options but store cache for alias\n  local orig_command = command\n  command = H.git_subcommands.alias[command] or command\n\n  -- Find command's flag options by parsing its help page. Needs a bit\n  -- heuristic approach and ensuring proper `git help` output (as it is done\n  -- through `man`), but seems to work good enough.\n  -- Alternative is to call command with `--git-completion-helper-all` flag (as\n  -- is done in bash and vim-fugitive completion). This has both pros and cons:\n  -- - Pros: faster; more targeted suggestions (like for two word subcommands);\n  --         presumably more reliable.\n  -- - Cons: works on smaller number of commands (for example, `rev-parse` or\n  --         pure `git` do not work); does not provide single dash suggestions;\n  --         does not work when not inside Git repo; needs recognizing two word\n  --         commands before asking for completion.\n  local env = H.make_spawn_env({ MANPAGER = 'cat', NO_COLOR = 1, PAGER = 'cat' })\n  local lines = H.git_cli_output({ 'help', '--man', command }, nil, env)\n  -- - Exit early before caching to try again later\n  if #lines == 0 then return {} end\n  -- - On some systems (like Mac), output still might contain formatting\n  --   sequences, like \"a\\ba\" and \"_\\ba\" meaning bold and italic.\n  --   See https://github.com/nvim-mini/mini.nvim/issues/918\n  lines = vim.tbl_map(function(l) return l:gsub('.\\b', '') end, lines)\n\n  -- Construct non-duplicating candidates by parsing lines of help page\n  local candidates_map = {}\n\n  -- Options are assumed to be listed inside \"OPTIONS\" or \"XXX OPTIONS\" (like\n  -- \"MODE OPTIONS\" of `git rebase`) section on dedicated lines. Whether a line\n  -- contains only options is determined heuristically: it is assumed to start\n  -- exactly with \"       -\" indicating proper indent for subsection start.\n  -- Known not parsable options:\n  -- - `git reset <mode>` (--soft, --hard, etc.): not listed in \"OPTIONS\".\n  -- - All -<number> options, as they are not really completeable.\n  local is_in_options_section = false\n  for _, l in ipairs(lines) do\n    if is_in_options_section and l:find('^%u[%u ]+$') ~= nil then is_in_options_section = false end\n    if not is_in_options_section and l:find('^%u?[%u ]*OPTIONS$') ~= nil then is_in_options_section = true end\n    if is_in_options_section and l:find('^       %-') ~= nil then H.parse_options(candidates_map, l) end\n  end\n\n  -- Finalize candidates. Should not contain \"almost duplicates\".\n  -- Should also be sorted by relevance: short flags before regular flags.\n  -- Inside groups sort alphabetically ignoring case.\n  candidates_map['--'] = nil\n  for cmd, _ in pairs(candidates_map) do\n    -- There can be two explicitly documented options \"--xxx\" and \"--xxx=\".\n    -- Use only one of them (without \"=\").\n    if cmd:sub(-1, -1) == '=' and candidates_map[cmd:sub(1, -2)] ~= nil then candidates_map[cmd] = nil end\n  end\n\n  local res = vim.tbl_keys(candidates_map)\n  table.sort(res, function(a, b)\n    local a2, b2 = a:sub(2, 2) == '-', b:sub(2, 2) == '-'\n    if a2 and not b2 then return false end\n    if not a2 and b2 then return true end\n    local a_low, b_low = a:lower(), b:lower()\n    return a_low < b_low or (a_low == b_low and a < b)\n  end)\n\n  -- Cache and return\n  H.git_subcommands.options[orig_command] = res\n  return res, 'option'\nend\n\nH.parse_options = function(map, line)\n  -- Options are standalone words starting as \"-xxx\" or \"--xxx\"\n  -- Include possible \"=\" at the end indicating mandatory value\n  line:gsub('%s(%-[-%w][-%w]*=?)', function(match) map[match] = true end)\n\n  -- Make exceptions for commonly documented \"--[no-]xxx\" two options\n  line:gsub('%s%-%-%[no%-%]([-%w]+=?)', function(match)\n    map['--' .. match], map['--no-' .. match] = true, true\n  end)\nend\n\nH.command_complete_path = function(cwd, base)\n  -- Treat base only as path relative to the command's cwd\n  cwd = cwd:gsub('/+$', '') .. '/'\n  local cwd_len = cwd:len()\n\n  -- List elements from (absolute) target directory\n  local target_dir = vim.fn.fnamemodify(base, ':h')\n  target_dir = (cwd .. target_dir:gsub('^%.$', '')):gsub('/+$', '') .. '/'\n  local ok, fs_entries = pcall(vim.fn.readdir, target_dir)\n  if not ok then return {} end\n\n  -- List directories and files separately\n  local dirs, files = {}, {}\n  for _, entry in ipairs(fs_entries) do\n    local entry_abs = target_dir .. entry\n    local arr = vim.fn.isdirectory(entry_abs) == 1 and dirs or files\n    table.insert(arr, entry_abs)\n  end\n  dirs = vim.tbl_map(function(x) return x .. '/' end, dirs)\n\n  -- List ordered directories first followed by ordered files\n  local order_ignore_case = function(a, b) return a:lower() < b:lower() end\n  table.sort(dirs, order_ignore_case)\n  table.sort(files, order_ignore_case)\n\n  -- Return candidates relative to command's cwd\n  local all = dirs\n  vim.list_extend(all, files)\n  local res = vim.tbl_map(function(x) return x:sub(cwd_len + 1) end, all)\n  return res, 'path'\nend\n\nH.command_complete_pullpush = function(cwd, _, line)\n  -- Suggest remotes at `Git push |` and `Git push or|`, otherwise - references\n  -- Ignore options when deciding which suggestion to compute\n  local _, n_words = line:gsub(' (%-%S+)', ''):gsub('%S+ ', '')\n  if n_words <= 2 then return H.git_cli_output({ 'remote' }, cwd), 'remote' end\n  return H.git_cli_output({ 'rev-parse', '--symbolic', '--branches', '--tags' }, cwd), 'ref'\nend\n\nH.make_git_cli_complete = function(args, complete_type)\n  return function(cwd, _) return H.git_cli_output(args, cwd), complete_type end\nend\n\n-- Cover at least all subcommands listed in `git help`\n--stylua: ignore\nH.command_complete_subcommand_targets = {\n  -- clone - no targets\n  -- init  - no targets\n\n  -- Worktree\n  add     = H.command_complete_path,\n  mv      = H.command_complete_path,\n  restore = H.command_complete_path,\n  rm      = H.command_complete_path,\n\n  -- Examine history\n  -- bisect - no targets\n  diff = H.command_complete_path,\n  grep = H.command_complete_path,\n  log  = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches', '--tags' }, 'ref'),\n  show = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches', '--tags' }, 'ref'),\n  -- status - no targets\n\n  -- Modify history\n  branch = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches' },           'branch'),\n  commit = H.command_complete_path,\n  merge  = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches' },           'branch'),\n  rebase = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches' },           'branch'),\n  reset  = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches', '--tags' }, 'ref'),\n  switch = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches' },           'branch'),\n  tag    = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--tags' },               'tag'),\n\n  -- Collaborate\n  fetch = H.make_git_cli_complete({ 'remote' }, 'remote'),\n  push = H.command_complete_pullpush,\n  pull = H.command_complete_pullpush,\n\n  -- Miscellaneous\n  checkout = H.make_git_cli_complete({ 'rev-parse', '--symbolic', '--branches', '--tags', '--remotes' }, 'checkout'),\n  config = H.make_git_cli_complete({ 'help', '--config-for-completion' }, 'config'),\n  help = function()\n    local res = { 'git', 'everyday' }\n    vim.list_extend(res, H.git_subcommands.supported)\n    return res, 'help'\n  end,\n}\n\nH.ensure_mods_is_split = function(mods)\n  if not H.mods_is_split(mods) then\n    local split_val = H.normalize_split_opt(MiniGit.config.command.split, '`config.command.split`')\n    mods = split_val .. ' ' .. mods\n  end\n  return mods\nend\n\n-- NOTE: `mods` is already expanded, so this also covers abbreviated mods\nH.mods_is_split = function(mods) return mods:find('vertical') or mods:find('horizontal') or mods:find('tab') end\n\n-- Show stdout ----------------------------------------------------------------\nH.show_in_split = function(mods, lines, subcmd, name)\n  -- Create a target window split\n  mods = H.ensure_mods_is_split(mods)\n  local win_source = vim.api.nvim_get_current_win()\n  vim.cmd(mods .. ' split')\n  local win_stdout = vim.api.nvim_get_current_win()\n\n  -- Prepare buffer\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  H.set_buf_name(buf_id, name)\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n\n  vim.api.nvim_set_current_buf(buf_id)\n  H.define_minigit_window()\n\n  -- NOTE: set filetype when buffer is in window to allow setting window-local\n  -- options in autocommands for `FileType` events\n  local filetype\n  if subcmd == 'diff' then filetype = 'diff' end\n  if subcmd == 'log' or subcmd == 'blame' then filetype = 'git' end\n  if subcmd == 'show' then\n    -- Try detecting 'git' filetype by content first, as filetype detection can\n    -- rely on the buffer name (i.e. command) having proper extension. It isn't\n    -- good for cases like `:Git show HEAD file.lua` (which should be 'git').\n    local l = lines[1]\n    local is_diff = l:find(string.rep('%x', 40)) or l:find('ref:')\n    filetype = is_diff and 'git' or vim.filetype.match({ buf = buf_id })\n  end\n\n  local has_filetype = not (filetype == nil or filetype == '')\n  if has_filetype then vim.bo[buf_id].filetype = filetype end\n\n  -- Completely unfold for no filetype output (like `:Git help`)\n  if not has_filetype then vim.wo[win_stdout].foldlevel = 999 end\n\n  return win_source, win_stdout\nend\n\nH.define_minigit_window = function(cleanup)\n  local buf_id, win_id = vim.api.nvim_get_current_buf(), vim.api.nvim_get_current_win()\n  vim.bo.swapfile, vim.bo.buflisted = false, false\n\n  -- Define action to finish editing Git related file\n  local finish_au_id\n  local finish = function(data)\n    local should_close = data.buf == buf_id or (data.event == 'WinClosed' and tonumber(data.match) == win_id)\n    if not should_close then return end\n\n    pcall(vim.api.nvim_del_autocmd, finish_au_id)\n    pcall(vim.api.nvim_win_close, win_id, true)\n    vim.schedule(function() pcall(vim.api.nvim_buf_delete, buf_id, { force = true }) end)\n\n    if vim.is_callable(cleanup) then vim.schedule(cleanup) end\n  end\n  -- - Use `nested` to allow other events (`WinEnter` for 'mini.statusline')\n  local events = { 'WinClosed', 'BufDelete', 'BufWipeout', 'VimLeave' }\n  local opts = { nested = true, callback = finish, desc = 'Cleanup window and buffer' }\n  finish_au_id = vim.api.nvim_create_autocmd(events, opts)\nend\n\nH.git_cli_output = function(args, cwd, env)\n  if cwd ~= nil and (vim.fn.isdirectory(cwd) ~= 1 or cwd == '') then return {} end\n  local command = { MiniGit.config.job.git_executable, '--no-pager', unpack(args) }\n  local res = H.cli_run(command, cwd, nil, { env = env }).out\n  if res == '' then return {} end\n  return vim.split(res, '\\n')\nend\n\n-- Validators -----------------------------------------------------------------\nH.validate_buf_id = function(x)\n  if x == nil or x == 0 then return vim.api.nvim_get_current_buf() end\n  if not (type(x) == 'number' and vim.api.nvim_buf_is_valid(x)) then\n    H.error('`buf_id` should be `nil` or valid buffer id.')\n  end\n  return x\nend\n\nH.normalize_split_opt = function(x, x_name)\n  if x == 'auto' then\n    -- Show in same tabpage if only minigit buffers visible. Otherwise in new.\n    for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do\n      local win_buf_id = vim.api.nvim_win_get_buf(win_id)\n      local win_buf_name = vim.api.nvim_buf_get_name(win_buf_id)\n      local is_minigit_win = win_buf_name:find('^minigit://%d+/') ~= nil\n      local is_normal_win = vim.api.nvim_win_get_config(win_id).relative == ''\n      if not is_minigit_win and is_normal_win then return 'tab' end\n    end\n    return 'vertical'\n  end\n  if x == 'horizontal' or x == 'vertical' or x == 'tab' then return x end\n  H.error('`' .. x_name .. '` should be one of \"auto\", \"horizontal\", \"vertical\", \"tab\"')\nend\n\nH.normalize_range_lines = function(line_start, line_end)\n  if line_start == nil and line_end == nil then\n    line_start = vim.fn.line('.')\n    local is_visual = vim.tbl_contains({ 'v', 'V', '\\22' }, vim.fn.mode())\n    line_end = is_visual and vim.fn.line('v') or vim.fn.line('.')\n    line_start, line_end = math.min(line_start, line_end), math.max(line_start, line_end)\n  end\n\n  if not (type(line_start) == 'number' and type(line_end) == 'number' and line_start <= line_end) then\n    H.error('`line_start` and `line_end` should be non-decreasing numbers.')\n  end\n  return line_start, line_end\nend\n\n-- Enabling -------------------------------------------------------------------\nH.is_buf_enabled = function(buf_id) return H.cache[buf_id] ~= nil and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.setup_buf_behavior = function(buf_id)\n  local augroup = vim.api.nvim_create_augroup('MiniGitBuffer' .. buf_id, { clear = true })\n  H.cache[buf_id].augroup = augroup\n\n  vim.api.nvim_buf_attach(buf_id, false, {\n    -- Called when buffer content is changed outside of current session\n    -- Needed as otherwise `on_detach()` is called without later auto enabling\n    on_reload = function()\n      local buf_cache = H.cache[buf_id]\n      if buf_cache == nil or buf_cache.root == nil then return end\n      -- Don't upate repo/root as it is tracked in 'BufFilePost' autocommand\n      H.update_git_head(buf_cache.root, { buf_id })\n      H.update_git_in_progress(buf_cache.repo, { buf_id })\n      -- Don't upate status as it is tracked in file watcher\n    end,\n\n    -- Called when buffer is unloaded from memory (`:h nvim_buf_detach_event`),\n    -- **including** `:edit` command. Together with auto enabling it makes\n    -- `:edit` command serve as \"restart\".\n    on_detach = function() MiniGit.disable(buf_id) end,\n  })\n\n  local reset_if_enabled = vim.schedule_wrap(function(data)\n    if not H.is_buf_enabled(data.buf) then return end\n    MiniGit.disable(data.buf)\n    MiniGit.enable(data.buf)\n  end)\n  local bufrename_opts = { group = augroup, buffer = buf_id, callback = reset_if_enabled, desc = 'Reset on rename' }\n  -- NOTE: `BufFilePost` does not look like a proper event, but it (yet) works\n  vim.api.nvim_create_autocmd('BufFilePost', bufrename_opts)\n\n  local buf_disable = function() MiniGit.disable(buf_id) end\n  local bufdelete_opts = { group = augroup, buffer = buf_id, callback = buf_disable, desc = 'Disable on delete' }\n  vim.api.nvim_create_autocmd('BufDelete', bufdelete_opts)\nend\n\n-- Tracking -------------------------------------------------------------------\nH.start_tracking = function(buf_id, path)\n  local command = H.git_cmd({ 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' })\n\n  -- If path is not in Git, disable buffer but make sure that it will not try\n  -- to re-attach until buffer is properly disabled\n  local on_not_in_git = function()\n    if H.is_buf_enabled(buf_id) then MiniGit.disable(buf_id) end\n    H.cache[buf_id] = {}\n  end\n\n  local on_done = vim.schedule_wrap(function(code, out, err)\n    -- Watch git directory only if there was no error retrieving path to it\n    if code ~= 0 then return on_not_in_git() end\n    H.cli_err_notify(code, out, err)\n\n    -- Update buf data\n    local repo, root = string.match(out, '^(.-)\\n(.*)$')\n    if repo == nil or root == nil then return H.notify('No initial data for buffer ' .. buf_id, 'WARN') end\n    H.update_buf_data(buf_id, { repo = repo, root = root })\n\n    -- Set up repo watching to react to Git index changes\n    H.setup_repo_watch(buf_id, repo)\n\n    -- Set up worktree watching to react to file changes\n    H.setup_path_watch(buf_id)\n\n    -- Immediately update buffer tracking data\n    H.update_git_head(root, { buf_id })\n    H.update_git_in_progress(repo, { buf_id })\n    H.update_git_status(root, { buf_id })\n  end)\n\n  H.cli_run(command, vim.fn.fnamemodify(path, ':h'), on_done)\nend\n\nH.setup_repo_watch = function(buf_id, repo)\n  local repo_cache = H.repos[repo] or {}\n\n  -- Ensure repo is watched\n  local is_set_up = repo_cache.fs_event ~= nil and repo_cache.fs_event:is_active()\n  if not is_set_up then\n    H.teardown_repo_watch(repo)\n    local fs_event, timer = vim.loop.new_fs_event(), vim.loop.new_timer()\n\n    local on_change = vim.schedule_wrap(function() H.on_repo_change(repo) end)\n    local watch = function(_, filename, _)\n      -- Ignore temporary changes\n      if vim.endswith(filename or '', 'lock') then return end\n\n      -- Debounce to not overload during incremental staging (like in script)\n      timer:stop()\n      timer:start(50, 0, on_change)\n    end\n    -- Watch only '.git' dir (non-recursively), as this seems to be both enough\n    -- and not supported by libuv (`recursive` flag does nothing,\n    -- see https://github.com/libuv/libuv/issues/1778)\n    fs_event:start(repo, {}, watch)\n\n    repo_cache.fs_event, repo_cache.timer = fs_event, timer\n    H.repos[repo] = repo_cache\n  end\n\n  -- Register buffer to be updated on repo change\n  local repo_buffers = repo_cache.buffers or {}\n  repo_buffers[buf_id] = true\n  repo_cache.buffers = repo_buffers\nend\n\nH.teardown_repo_watch = function(repo)\n  if H.repos[repo] == nil then return end\n  pcall(vim.loop.fs_event_stop, H.repos[repo].fs_event)\n  pcall(vim.loop.timer_stop, H.repos[repo].timer)\nend\n\nH.setup_path_watch = function(buf_id, repo)\n  if not H.is_buf_enabled(buf_id) then return end\n\n  local on_file_change = function(data) H.update_git_status(H.cache[buf_id].root, { buf_id }) end\n  local opts =\n    { desc = 'Update Git status', group = H.cache[buf_id].augroup, buffer = buf_id, callback = on_file_change }\n  vim.api.nvim_create_autocmd({ 'BufWritePost', 'FileChangedShellPost' }, opts)\nend\n\nH.on_repo_change = function(repo)\n  if H.repos[repo] == nil then return end\n\n  -- Collect repo's worktrees with their buffers while doing cleanup\n  local repo_bufs, root_bufs = H.repos[repo].buffers, {}\n  for buf_id, _ in pairs(repo_bufs) do\n    if H.is_buf_enabled(buf_id) then\n      local root = H.cache[buf_id].root\n      local bufs = root_bufs[root] or {}\n      table.insert(bufs, buf_id)\n      root_bufs[root] = bufs\n    else\n      repo_bufs[buf_id] = nil\n      MiniGit.disable(buf_id)\n    end\n  end\n\n  -- Update Git data\n  H.update_git_in_progress(repo, vim.tbl_keys(repo_bufs))\n  for root, bufs in pairs(root_bufs) do\n    H.update_git_head(root, bufs)\n    -- Status could have also changed as it depends on the index\n    H.update_git_status(root, bufs)\n  end\nend\n\nH.update_git_head = function(root, bufs)\n  local command = H.git_cmd({ 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' })\n\n  local on_done = vim.schedule_wrap(function(code, out, err)\n    -- Ensure proper data\n    if code ~= 0 then return end\n    H.cli_err_notify(code, out, err)\n\n    local head, head_name = string.match(out, '^(.-)\\n(.*)$')\n    if head == nil or head_name == nil then\n      return H.notify('Could not parse HEAD data for root ' .. root .. '\\n' .. out, 'WARN')\n    end\n\n    -- Update data for all buffers from target `root`\n    local new_data = { head = head, head_name = head_name }\n    for _, buf_id in ipairs(bufs) do\n      H.update_buf_data(buf_id, new_data)\n    end\n\n    -- Redraw statusline to have possible statusline component up to date\n    H.redrawstatus()\n  end)\n\n  H.cli_run(command, root, on_done)\nend\n\nH.update_git_in_progress = function(repo, bufs)\n  -- Get data about what process is in progress\n  local in_progress = {}\n  if H.is_fs_present(repo .. '/BISECT_LOG') then table.insert(in_progress, 'bisect') end\n  if H.is_fs_present(repo .. '/CHERRY_PICK_HEAD') then table.insert(in_progress, 'cherry-pick') end\n  if H.is_fs_present(repo .. '/MERGE_HEAD') then table.insert(in_progress, 'merge') end\n  if H.is_fs_present(repo .. '/REVERT_HEAD') then table.insert(in_progress, 'revert') end\n  if H.is_fs_present(repo .. '/rebase-apply') then table.insert(in_progress, 'apply') end\n  if H.is_fs_present(repo .. '/rebase-merge') then table.insert(in_progress, 'rebase') end\n\n  -- Update data for all buffers from target `root`\n  local new_data = { in_progress = table.concat(in_progress, ',') }\n  for _, buf_id in ipairs(bufs) do\n    H.update_buf_data(buf_id, new_data)\n  end\n\n  -- Redraw statusline to have possible statusline component up to date\n  H.redrawstatus()\nend\n\nH.update_git_status = function(root, bufs)\n  --stylua: ignore\n  local command = H.git_cmd({\n    -- NOTE: Use `--no-optional-locks` to reduce conflicts with other Git tasks\n    '--no-optional-locks', 'status',\n    '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n    '--',\n  })\n  local root_len, path_data = string.len(root), {}\n  for _, buf_id in ipairs(bufs) do\n    -- Use paths relative to the root as in `git status --porcelain` output\n    local rel_path = H.get_buf_realpath(buf_id):sub(root_len + 2)\n    table.insert(command, rel_path)\n    -- Completely not modified paths should be the only ones missing in the\n    -- output. Use this status as default.\n    path_data[rel_path] = { status = '  ', buf_id = buf_id }\n  end\n\n  local on_done = vim.schedule_wrap(function(code, out, err)\n    if code ~= 0 then return end\n    H.cli_err_notify(code, out, err)\n\n    -- Parse CLI output, which is separated by `\\0` to not escape \"bad\" paths\n    for _, l in ipairs(vim.split(out, '\\0')) do\n      local status, rel_path = string.match(l, '^(..) (.*)$')\n      if path_data[rel_path] ~= nil then path_data[rel_path].status = status end\n    end\n\n    -- Update data for all buffers\n    for _, data in pairs(path_data) do\n      local new_data = { status = data.status }\n      H.update_buf_data(data.buf_id, new_data)\n    end\n\n    -- Redraw statusline to have possible statusline component up to date\n    H.redrawstatus()\n  end)\n\n  H.cli_run(command, root, on_done)\nend\n\nH.update_buf_data = function(buf_id, new_data)\n  if not H.is_buf_enabled(buf_id) then return end\n\n  local summary = vim.b[buf_id].minigit_summary or {}\n  for key, val in pairs(new_data) do\n    H.cache[buf_id][key], summary[key] = val, val\n  end\n  vim.b[buf_id].minigit_summary = summary\n\n  -- Format summary string\n  local head = summary.head_name or ''\n  head = head == 'HEAD' and summary.head:sub(1, 7) or head\n\n  local in_progress = summary.in_progress or ''\n  if in_progress ~= '' then head = head .. '|' .. in_progress end\n\n  local summary_string = head\n  local status = summary.status or ''\n  if status ~= '  ' and status ~= '' then summary_string = string.format('%s (%s)', head, status) end\n  vim.b[buf_id].minigit_summary_string = summary_string\n\n  -- Trigger dedicated event with target current buffer (for proper `data.buf`)\n  vim.api.nvim_buf_call(buf_id, function() H.trigger_event('MiniGitUpdated') end)\nend\n\n-- History navigation ---------------------------------------------------------\n-- Assuming buffer contains unified combined diff (with \"commit\" header),\n-- compute path, line number, and commit of both \"before\" and \"after\" files.\n-- Allow cursor to be between \"--- a/xxx\" line and last line of a hunk.\nH.diff_pos_to_source = function()\n  local lines, lnum = vim.api.nvim_buf_get_lines(0, 0, -1, false), vim.fn.line('.')\n\n  local res = { init_prefix = lines[lnum]:sub(1, 1) }\n  local paths_lnum = H.diff_parse_paths(res, lines, lnum)\n  local hunk_lnum = H.diff_parse_hunk(res, lines, lnum)\n  local commit_lnum = H.diff_parse_commits(res, lines, lnum)\n\n  -- Try fall back to inferring target commits from 'mini.git' buffer name\n  if res.commit_before == nil or res.commit_after == nil then H.diff_parse_bufname(res) end\n\n  local all_present = (res.lnum_before and res.path_before and res.commit_before)\n    or (res.lnum_after and res.path_after and res.commit_after)\n  local is_in_order = commit_lnum <= paths_lnum and paths_lnum <= hunk_lnum\n  if not (all_present and is_in_order) then return nil end\n\n  return res\nend\n\nH.diff_parse_paths = function(out, lines, lnum)\n  -- NOTE: with `diff.mnemonicPrefix=true` source and destination prefixes can\n  -- be not only `a`/`b`, but other characters or none (if added/deleted file)\n  local pattern_before, pattern_after = '^%-%-%- ([acio]?)/(.*)$', '^%+%+%+ ([biw]?)/(.*)$'\n\n  -- Allow placing cursor directly on path defining lines\n  local cur_line = lines[lnum]\n  local prefix_before, path_before = string.match(cur_line, pattern_before)\n  local prefix_after, path_after = string.match(cur_line, pattern_after)\n  if path_before ~= nil then\n    out.path_before = path_before\n    prefix_after, out.path_after = string.match(lines[lnum + 1] or '', pattern_after)\n    out.lnum_before, out.lnum_after = 1, 1\n  elseif path_after ~= nil then\n    prefix_before, out.path_before = string.match(lines[lnum - 1] or '', pattern_before)\n    out.path_after = path_after\n    out.lnum_before, out.lnum_after = 1, 1\n  else\n    -- Iterate lines upward to find path patterns\n    while out.path_after == nil and lnum > 0 do\n      prefix_after, out.path_after = string.match(lines[lnum] or '', pattern_after)\n      lnum = lnum - 1\n    end\n    prefix_before, out.path_before = string.match(lines[lnum] or '', pattern_before)\n  end\n\n  -- - Don't treat '--- /dev/null' and '+++ /dev/null' matches as paths\n  --   Need to check prefix to work in cases like '--- a/dev/null'\n  if prefix_before == '' then out.path_before = nil end\n  if prefix_after == '' then out.path_after = nil end\n\n  return lnum\nend\n\nH.diff_parse_hunk = function(out, lines, lnum)\n  if out.lnum_after ~= nil then return lnum end\n\n  local offsets = { [' '] = 0, ['-'] = 0, ['+'] = 0 }\n  while lnum > 0 do\n    local prefix = lines[lnum]:sub(1, 1)\n    if not (prefix == ' ' or prefix == '-' or prefix == '+') then break end\n    offsets[prefix] = offsets[prefix] + 1\n    lnum = lnum - 1\n  end\n\n  local hunk_start_before, hunk_start_after = string.match(lines[lnum] or '', '^@@ %-(%d+),?%d* %+(%d+),?%d* @@')\n  if hunk_start_before ~= nil then\n    out.lnum_before = math.max(1, tonumber(hunk_start_before) + offsets[' '] + offsets['-'] - 1)\n    out.lnum_after = math.max(1, tonumber(hunk_start_after) + offsets[' '] + offsets['+'] - 1)\n  end\n  return lnum\nend\n\nH.diff_parse_commits = function(out, lines, lnum)\n  while out.commit_after == nil and lnum > 0 do\n    out.commit_after = string.match(lines[lnum], '^commit (%x+)$')\n    lnum = lnum - 1\n  end\n  if out.commit_after ~= nil then out.commit_before = out.commit_after .. '~' end\n  return lnum + 1\nend\n\nH.diff_parse_bufname = function(out)\n  local buf_name = vim.api.nvim_buf_get_name(0)\n  local diff_command = string.match(buf_name, '^minigit://%d+/.* diff ?(.*)$')\n  if diff_command == nil then return end\n\n  -- Work with output of common `:Git diff` commands\n  diff_command = vim.trim(diff_command)\n  -- `Git diff` - compares index and work tree\n  if diff_command == '' then\n    out.commit_before, out.commit_after = ':0', true\n  end\n  -- `Git diff --cached` - compares HEAD and index\n  if diff_command == '--cached' then\n    out.commit_before, out.commit_after = 'HEAD', ':0'\n  end\n  -- `Git diff HEAD` - compares commit and work tree\n  if diff_command:find('^[^-]%S*$') ~= nil then\n    out.commit_before, out.commit_after = diff_command, true\n  end\nend\n\nH.parse_diff_source_buf_name = function(buf_name) return string.match(buf_name, '^minigit://%d+/.*show (%x+~?):(.*)$') end\n\nH.deps_pos_to_source = function()\n  local lines = vim.api.nvim_buf_get_lines(0, 0, vim.fn.line('.'), false)\n  -- Do nothing if on the title (otherwise it operates on previous plugin info)\n  if lines[#lines]:find('^[%+%-!]') ~= nil then return end\n\n  -- Locate lines with commit and repo path data\n  local commit, commit_lnum = nil, #lines\n  while commit == nil and commit_lnum >= 1 do\n    local l = lines[commit_lnum]\n    commit = l:match('^[><] (%x%x%x%x%x%x%x%x*) |') or l:match('^State[^:]*: %s*(%x+)')\n    commit_lnum = commit_lnum - 1\n  end\n\n  local cwd, cwd_lnum = nil, #lines\n  while cwd == nil and cwd_lnum >= 1 do\n    cwd, cwd_lnum = lines[cwd_lnum]:match('^Path: %s*(%S+)$'), cwd_lnum - 1\n  end\n\n  -- Do nothing if something is not found or path corresponds to next repo\n  if commit == nil or cwd == nil or commit_lnum <= cwd_lnum then return end\n  return commit, cwd\nend\n\n-- Folding --------------------------------------------------------------------\nH.is_hunk_header = function(lnum) return vim.fn.getline(lnum):find('^@@.*@@') ~= nil end\n\nH.is_log_entry_header = function(lnum) return vim.fn.getline(lnum):find('^commit ') ~= nil end\n\nH.is_file_entry_header = function(lnum) return vim.fn.getline(lnum):find('^diff %-%-git') ~= nil end\n\n-- CLI ------------------------------------------------------------------------\nH.git_cmd = function(args)\n  -- Use '-c gc.auto=0' to disable `stderr` \"Auto packing...\" messages\n  return { MiniGit.config.job.git_executable, '-c', 'gc.auto=0', unpack(args) }\nend\n\nH.make_spawn_env = function(env_vars)\n  -- Setup all environment variables (`vim.loop.spawn()` by default has none)\n  local environ = vim.tbl_deep_extend('force', vim.loop.os_environ(), env_vars)\n  local res = {}\n  for k, v in pairs(environ) do\n    table.insert(res, string.format('%s=%s', k, tostring(v)))\n  end\n  return res\nend\n\nH.cli_run = function(command, cwd, on_done, opts)\n  local spawn_opts = opts or {}\n  local executable, args = command[1], vim.list_slice(command, 2, #command)\n  local process, stdout, stderr = nil, vim.loop.new_pipe(), vim.loop.new_pipe()\n  spawn_opts.args, spawn_opts.cwd, spawn_opts.stdio = args, cwd or vim.fn.getcwd(), { nil, stdout, stderr }\n\n  -- Allow `on_done = nil` to mean synchronous execution\n  local is_sync, res = false, nil\n  if on_done == nil then\n    is_sync = true\n    on_done = function(code, out, err) res = { code = code, out = out, err = err } end\n  end\n\n  local out, err, is_done = {}, {}, false\n  local on_exit = function(code)\n    -- Ensure calling this only once\n    if is_done then return end\n    is_done = true\n\n    if process:is_closing() then return end\n    process:close()\n\n    -- Convert to strings appropriate for notifications\n    out = H.cli_stream_tostring(out)\n    err = H.cli_stream_tostring(err):gsub('\\r+', '\\n'):gsub('\\n%s+\\n', '\\n\\n')\n    on_done(code, out, err)\n  end\n\n  process = vim.loop.spawn(executable, spawn_opts, on_exit)\n  H.cli_read_stream(stdout, out)\n  H.cli_read_stream(stderr, err)\n  vim.defer_fn(function()\n    if H.skip_timeout or not process:is_active() then return end\n    H.notify('PROCESS REACHED TIMEOUT', 'WARN')\n    on_exit(1)\n  end, MiniGit.config.job.timeout)\n\n  if is_sync then vim.wait(MiniGit.config.job.timeout + 10, function() return is_done end, 1) end\n  return res\nend\n\nH.cli_read_stream = function(stream, feed)\n  local callback = function(err, data)\n    if err then return table.insert(feed, 1, 'ERROR: ' .. err) end\n    if data ~= nil then return table.insert(feed, data) end\n    stream:close()\n  end\n  stream:read_start(callback)\nend\n\nH.cli_stream_tostring = function(stream) return (table.concat(stream):gsub('\\n+$', '')) end\n\nH.cli_err_notify = function(code, out, err)\n  local should_stop = code ~= 0\n  if should_stop then H.notify(err .. (out == '' and '' or ('\\n' .. out)), 'ERROR') end\n  if not should_stop and err ~= '' then H.notify(err, 'WARN') end\n  return should_stop\nend\n\nH.cli_escape = function(x) return (string.gsub(x, '([ \\\\])', '\\\\%1')) end\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.git) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minigit://' .. buf_id .. '/' .. name) end\n\nH.notify = function(msg, level_name) vim.notify('(mini.git) ' .. msg, vim.log.levels[level_name]) end\n\nH.trigger_event = function(event_name, data) vim.api.nvim_exec_autocmds('User', { pattern = event_name, data = data }) end\n\nH.is_fs_present = function(path) return vim.loop.fs_stat(path) ~= nil end\n\nH.expandcmd = function(x)\n  if x == '<cwd>' then return vim.fn.getcwd() end\n  local ok, res = pcall(vim.fn.expandcmd, x)\n  return ok and res or x\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\n-- Try getting buffer's full real path (after resolving symlinks)\nH.get_buf_realpath = function(buf_id) return vim.loop.fs_realpath(vim.api.nvim_buf_get_name(buf_id)) or '' end\n\nH.redrawstatus = function() vim.cmd('redrawstatus') end\nif vim.api.nvim__redraw ~= nil then H.redrawstatus = function() vim.api.nvim__redraw({ statusline = true }) end end\n\nreturn MiniGit\n"
  },
  {
    "path": "lua/mini/hipatterns.lua",
    "content": "--- *mini.hipatterns* Highlight patterns in text\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Highlight text with configurable patterns and highlight groups (can be\n---   string or callable).\n---\n--- - Highlighting is updated asynchronously with configurable debounce delay.\n---\n--- - Function to get matches in a buffer (see |MiniHipatterns.get_matches()|).\n---\n--- See |MiniHipatterns-examples| for common configuration examples.\n---\n--- Notes:\n--- - It does not define any highlighters by default. Add to `config.highlighters`\n---   to have a visible effect.\n---\n--- - Sometimes (especially during frequent buffer updates on same line numbers)\n---   highlighting can be outdated or not applied when it should be. This is due\n---   to asynchronous nature of updates reacting to text changes (via\n---   `on_lines` of |nvim_buf_attach()|).\n---   To make them up to date, use one of the following:\n---     - Scroll window (for example, with |CTRL-E| / |CTRL-Y|). This will ensure\n---       up to date highlighting inside window view.\n---     - Hide and show buffer.\n---     - Execute `:edit` (if you enabled highlighting with |MiniHipatterns.setup()|).\n---     - Manually call |MiniHipatterns.update()|.\n---\n--- - If you experience flicker when typing near highlighted pattern in Insert\n---   mode, it might be due to `delay` configuration of |mini.completion| or\n---   using built-in completion.\n---   For better experience with 'mini.completion', make sure that its\n---   `delay.completion` is less than this module's `delay.text_change` (which\n---   it is by default).\n---   The reason for this is (currently unresolvable) limitations of Neovim's\n---   built-in completion implementation.\n---\n--- # Setup ~\n---\n--- Setting up highlights can be done in two ways:\n--- - Manually for every buffer with `require('mini.hipatterns').enable()`.\n---   This will enable highlighting only in one particular buffer until it is\n---   unloaded (which also includes calling `:edit` on current file).\n---\n--- - Globally with `require('mini.hipatterns').setup({})` (replace `{}` with\n---   your `config` table). This will auto-enable highlighting in \"normal\"\n---   buffers (see 'buftype'). Use |MiniHipatterns.enable()| to manually enable\n---   in other buffers.\n---   It will also create global Lua table `MiniHipatterns` which you can use\n---   for scripting or manually (with `:lua MiniHipatterns.*`).\n---\n--- See |MiniHipatterns.config| for `config` structure and default values.\n---\n--- You can override runtime config settings (like highlighters and delays)\n--- locally to buffer inside `vim.b.minihipatterns_config` which should have\n--- same structure as `MiniHipatterns.config`.\n--- See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [folke/todo-comments](https://github.com/folke/todo-comments):\n---     - Oriented for \"TODO\", \"NOTE\", \"FIXME\" like patterns, while this module\n---       can work with any Lua patterns and computable highlight groups.\n---     - Has functionality beyond text highlighting (sign placing,\n---       \"telescope.nvim\" extension, etc.), while this module only focuses on\n---       highlighting text.\n--- - [folke/paint.nvim](https://github.com/folke/paint.nvim):\n---     - Mostly similar to this module, but with slightly less functionality,\n---       such as computed pattern and highlight group, asynchronous delay, etc.\n--- - [NvChad/nvim-colorizer.lua](https://github.com/NvChad/nvim-colorizer.lua):\n---     - Oriented for color highlighting, while this module can work with any\n---       Lua patterns and computable highlight groups.\n---     - Has more built-in color spaces to highlight, while this module out of\n---       the box provides only hex color highlighting\n---       (see |MiniHipatterns.gen_highlighter.hex_color()|). Other types are\n---       also possible to implement.\n--- - [uga-rosa/ccc.nvim](https://github.com/uga-rosa/ccc.nvim):\n---     - Has more than color highlighting functionality, which is compared to\n---       this module in the same way as 'NvChad/nvim-colorizer.lua'.\n---\n--- # Highlight groups ~\n---\n--- - `MiniHipatternsFixme` - suggested group to use for `FIXME`-like patterns.\n--- - `MiniHipatternsHack` - suggested group to use for `HACK`-like patterns.\n--- - `MiniHipatternsTodo` - suggested group to use for `TODO`-like patterns.\n--- - `MiniHipatternsNote` - suggested group to use for `NOTE`-like patterns.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- This module can be disabled in three ways:\n--- - Globally: set `vim.g.minihipatterns_disable` to `true`.\n--- - Locally for buffer permanently: set `vim.b.minihipatterns_disable` to `true`.\n--- - Locally for buffer temporarily (until next auto-enabling event if set up\n---   with |MiniHipatterns.setup()|): call |MiniHipatterns.disable()|.\n---\n--- Considering high number of different scenarios and customization\n--- intentions, writing exact rules for disabling module's functionality is\n--- left to user. See |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniHipatterns\n\n--- # Common configuration examples ~\n---\n--- - Special words used to convey different level of attention: >lua\n---\n---   require('mini.hipatterns').setup({\n---     highlighters = {\n---       fixme = { pattern = 'FIXME', group = 'MiniHipatternsFixme' },\n---       hack  = { pattern = 'HACK',  group = 'MiniHipatternsHack'  },\n---       todo  = { pattern = 'TODO',  group = 'MiniHipatternsTodo'  },\n---       note  = { pattern = 'NOTE',  group = 'MiniHipatternsNote'  },\n---     }\n---   })\n--- <\n--- - To match only when pattern appears as a standalone word, use frontier\n---   patterns `%f`. For example, instead of `'TODO'` pattern use\n---   `'%f[%w]()TODO()%f[%W]'`. In this case, for example, 'TODOING' or 'MYTODO'\n---   won't match, but 'TODO' and 'TODO:' will.\n---\n--- - Color hex (like `#rrggbb`) highlighting: >lua\n---\n---   local hipatterns = require('mini.hipatterns')\n---   hipatterns.setup({\n---     highlighters = {\n---       hex_color = hipatterns.gen_highlighter.hex_color(),\n---     }\n---   })\n--- <\n---   You can customize which part of hex color is highlighted by using `style`\n---   field of input options. See |MiniHipatterns.gen_highlighter.hex_color()|.\n---\n--- - Colored words: >lua\n---\n---   local words = { red = '#ff0000', green = '#00ff00', blue = '#0000ff' }\n---   local word_color_group = function(_, match)\n---     local hex = words[match]\n---     if hex == nil then return nil end\n---     return MiniHipatterns.compute_hex_color_group(hex, 'bg')\n---   end\n---\n---   local hipatterns = require('mini.hipatterns')\n---   hipatterns.setup({\n---     highlighters = {\n---       word_color = { pattern = '%S+', group = word_color_group },\n---     },\n---   })\n--- <\n--- - Trailing whitespace (if don't want to use more specific |mini.trailspace|): >lua\n---\n---   { pattern = '%f[%s]%s*$', group = 'Error' }\n--- <\n--- - Censor certain sensitive information: >lua\n---\n---   local censor_extmark_opts = function(_, match, _)\n---     local mask = string.rep('x', vim.fn.strchars(match))\n---     return {\n---       virt_text = { { mask, 'Comment' } }, virt_text_pos = 'overlay',\n---       priority = 200, right_gravity = false,\n---     }\n---   end\n---\n---   require('mini.hipatterns').setup({\n---     highlighters = {\n---       censor = {\n---         pattern = 'password: ()%S+()',\n---         group = '',\n---         extmark_opts = censor_extmark_opts,\n---       },\n---     },\n---   })\n--- <\n--- - Enable only in certain filetypes. There are at least these ways to do it:\n---     - (Suggested) With `vim.b.minihipatterns_config` in |filetype-plugin|.\n---       Basically, create \"after/ftplugin/<filetype>.lua\" file in your config\n---       directory (see |$XDG_CONFIG_HOME|) and define `vim.b.minihipatterns_config`\n---       there with filetype specific highlighters.\n---\n---       This assumes `require('mini.hipatterns').setup()` call.\n---\n---       For example, to highlight keywords in EmmyLua comments in Lua files,\n---       create \"after/ftplugin/lua.lua\" with the following content: >lua\n---\n---         vim.b.minihipatterns_config = {\n---           highlighters = {\n---             emmylua = { pattern = '^%s*%-%-%-()@%w+()', group = 'Special' }\n---           }\n---         }\n--- <\n---     - Use callable `pattern` with condition. For example: >lua\n---\n---       require('mini.hipatterns').setup({\n---         highlighters = {\n---           emmylua = {\n---             pattern = function(buf_id)\n---               if vim.bo[buf_id].filetype ~= 'lua' then return nil end\n---               return '^%s*%-%-%-()@%w+()'\n---             end,\n---             group = 'Special',\n---           },\n---         },\n---       })\n--- <\n--- - Disable only in certain filetypes. Enable with |MiniHipatterns.setup()|\n---   and set `vim.b.minihipatterns_disable` buffer-local variable to `true` for\n---   buffer you want disabled. See |mini.nvim-disabling-recipes| for more examples.\n---@tag MiniHipatterns-examples\n\n---@alias __hipatterns_buf_id number|nil Buffer identifier in which to enable highlighting.\n---   Default: 0 for current buffer.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniHipatterns = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniHipatterns.config|.\n---\n---@usage >lua\n---   require('mini.hipatterns').setup({}) -- replace {} with your config table\n---                                        -- needs `highlighters` field present\n--- <\nMiniHipatterns.setup = function(config)\n  -- Export module\n  _G.MiniHipatterns = MiniHipatterns\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n  for _, win_id in ipairs(vim.api.nvim_list_wins()) do\n    H.auto_enable({ buf = vim.api.nvim_win_get_buf(win_id) })\n  end\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Highlighters ~\n---\n--- `highlighters` table defines which patterns will be highlighted by placing\n--- |extmark| at the match start. It might or might not have explicitly named\n--- fields, but having them is recommended and is required for proper use of\n--- `vim.b.minihipatterns_config` as buffer-local config. By default it is\n--- empty expecting user definition.\n---\n--- Each entry defines single highlighter as a table with the following fields:\n--- - <pattern> `(string|function|table)` - Lua pattern to highlight. Can be\n---   either string, callable returning the string, or an array of those.\n---   If string:\n---     - It can have submatch delimited by placing `()` on start and end, NOT\n---       by surrounding it with parenthesis (results in an error containing\n---       `number expected, got string`). Example: `xx()abcd()xx` will match\n---       `abcd` only if `xx` is placed before and after it.\n---\n---   If callable:\n---     - It will be called for every enabled buffer with its identifier as input.\n---       Should return single string pattern or `nil` (meaning this particular\n---       highlighter will not work in this particular buffer).\n---\n---   If array:\n---     - Each element is matched and highlighted with the same highlight group.\n---\n---     Note: matching does not result in overlapping (sub)matches (similarly\n---     to how |cpo-c| works). For example, with line `xxxxxxx`:\n---     - Pattern `xxx` matches columns 1-3, 4-6.\n---     - Pattern `()xx()x` matches columns 1-2, 3-4, 5-6.\n---     - Pattern `x()xx()` matches columns 2-3, 5-6.\n---     - Pattern `x()x()x` matches columns 2-2, 4-4, 6-6.\n---\n--- - <group> `(string|function)` - name of highlight group to use. Can be either\n---   string or callable returning the string.\n---   If callable:\n---     - It will be called for every pattern match with the following arguments:\n---         - `buf_id` - buffer identifier.\n---         - `match` - string pattern match to be highlighted.\n---         - `data` - extra table with information about the match.\n---           It has at least these fields:\n---             - <full_match> - string with full pattern match.\n---             - <line> - match line number (1-indexed).\n---             - <from_col> - match starting byte column (1-indexed).\n---             - <to_col> - match ending byte column (1-indexed, inclusive).\n---\n---     - It can return `nil` meaning this particular match will not be highlighted.\n---\n--- - <extmark_opts> `(table|function|nil)` - optional extra options\n---   for |nvim_buf_set_extmark()|. If callable, will be called in the same way\n---   as callable <group> (`data` will also contain `hl_group` key with <group>\n---   value) and should return a table with all options for extmark (including\n---   `end_row`, `end_col`, `hl_group`, and `priority`).\n---\n--- See \"Common use cases\" section for the examples.\n---\n--- # Delay ~\n---\n--- `delay` is a table defining delays in milliseconds used for asynchronous\n--- highlighting process.\n---\n--- `delay.text_change` is used to delay highlighting updates by accumulating\n--- them (in debounce fashion). Smaller values will lead to faster response but\n--- more frequent updates. Bigger - slower response but less frequent updates.\n---\n--- `delay.scroll` is used to delay updating highlights in current window view\n--- during scrolling (see |WinScrolled| event). These updates are present to\n--- ensure up to date highlighting after scroll.\nMiniHipatterns.config = {\n  -- Table with highlighters (see |MiniHipatterns.config| for more details).\n  -- Nothing is defined by default. Add manually for visible effect.\n  highlighters = {},\n\n  -- Delays (in ms) defining asynchronous highlighting process\n  delay = {\n    -- How much to wait for update after every text change\n    text_change = 200,\n\n    -- How much to wait for update after window scroll\n    scroll = 50,\n  },\n}\n--minidoc_afterlines_end\n\n--- Enable highlighting in buffer\n---\n--- Notes:\n--- - With default config it will highlight nothing, as there are no default\n---   highlighters.\n---\n--- - Buffer highlighting is enabled until buffer is unloaded from memory\n---   or |MiniHipatterns.disable()| on this buffer is called.\n---\n--- - `:edit` disables this, as it is mostly equivalent to closing and opening\n---   buffer. In order for highlighting to persist after `:edit`, call\n---   |MiniHipatterns.setup()|.\n---\n---@param buf_id __hipatterns_buf_id\n---@param config table|nil Optional buffer-local config. Should have the same\n---   structure as |MiniHipatterns.config|. Values will be taken in this order:\n---   - From this `config` argument (if supplied).\n---   - From buffer-local config in `vim.b.minihipatterns_config` (if present).\n---   - From global config (if |MiniHipatterns.setup()| was called).\n---   - From default values.\nMiniHipatterns.enable = function(buf_id, config)\n  buf_id = H.validate_buf_id(buf_id)\n  config = H.validate_config_arg(config)\n\n  -- Don't enable more than once\n  if H.is_buf_enabled(buf_id) then return end\n\n  -- Register enabled buffer with cached data for performance\n  H.update_cache(buf_id, config)\n\n  -- Add buffer watchers\n  vim.api.nvim_buf_attach(buf_id, false, {\n    -- Called on every text change (`:h nvim_buf_lines_event`)\n    on_lines = function(_, _, _, from_line, _, to_line)\n      local buf_cache = H.cache[buf_id]\n      -- Properly detach if highlighting is disabled\n      if buf_cache == nil then return true end\n      H.process_lines(buf_id, from_line + 1, to_line, buf_cache.delay.text_change)\n    end,\n\n    -- Called when buffer content is changed outside of current session\n    on_reload = function() pcall(MiniHipatterns.update, buf_id) end,\n\n    -- Called when buffer is unloaded from memory (`:h nvim_buf_detach_event`),\n    -- **including** `:edit` command\n    on_detach = function() MiniHipatterns.disable(buf_id) end,\n  })\n\n  -- Add buffer autocommands\n  local augroup = vim.api.nvim_create_augroup('MiniHipatternsBuffer' .. buf_id, { clear = true })\n  H.cache[buf_id].augroup = augroup\n\n  local update_buf = vim.schedule_wrap(function()\n    if not H.is_buf_enabled(buf_id) then return end\n\n    H.update_cache(buf_id, config)\n\n    local delay_ms = H.cache[buf_id].delay.text_change\n    H.process_lines(buf_id, 1, vim.api.nvim_buf_line_count(buf_id), delay_ms)\n  end)\n\n  vim.api.nvim_create_autocmd(\n    { 'BufWinEnter', 'FileType' },\n    { group = augroup, buffer = buf_id, callback = update_buf, desc = 'Update highlighting for whole buffer' }\n  )\n\n  vim.api.nvim_create_autocmd(\n    'WinScrolled',\n    { group = augroup, buffer = buf_id, callback = H.update_view, desc = 'Update highlighting in view' }\n  )\n\n  -- Add highlighting to whole buffer\n  H.process_lines(buf_id, 1, vim.api.nvim_buf_line_count(buf_id), 0)\nend\n\n--- Disable highlighting in buffer\n---\n--- Note that if |MiniHipatterns.setup()| was called, the effect is present\n--- until the next auto-enabling event. To permanently disable highlighting in\n--- buffer, set `vim.b.minihipatterns_disable` to `true`\n---\n---@param buf_id __hipatterns_buf_id\nMiniHipatterns.disable = function(buf_id)\n  buf_id = H.validate_buf_id(buf_id)\n\n  local buf_cache = H.cache[buf_id]\n  if buf_cache == nil then return end\n  H.cache[buf_id] = nil\n\n  vim.api.nvim_del_augroup_by_id(buf_cache.augroup)\n  for _, ns in pairs(H.ns_id) do\n    H.clear_namespace(buf_id, ns, 0, -1)\n  end\nend\n\n--- Toggle highlighting in buffer\n---\n--- Call |MiniHipatterns.disable()| if enabled; |MiniHipatterns.enable()| otherwise.\n---\n---@param buf_id __hipatterns_buf_id\n---@param config table|nil Forwarded to |MiniHipatterns.enable()|.\nMiniHipatterns.toggle = function(buf_id, config)\n  buf_id = H.validate_buf_id(buf_id)\n  config = H.validate_config_arg(config)\n\n  if H.is_buf_enabled(buf_id) then\n    MiniHipatterns.disable(buf_id)\n  else\n    MiniHipatterns.enable(buf_id, config)\n  end\nend\n\n--- Update highlighting in range\n---\n--- Works only in buffer with enabled highlighting. Effect takes immediately\n--- without delay.\n---\n---@param buf_id __hipatterns_buf_id\n---@param from_line number|nil Start line from which to update (1-indexed).\n---@param to_line number|nil End line from which to update (1-indexed, inclusive).\nMiniHipatterns.update = function(buf_id, from_line, to_line)\n  buf_id = H.validate_buf_id(buf_id)\n\n  if not H.is_buf_enabled(buf_id) then H.error(string.format('Buffer %d is not enabled.', buf_id)) end\n\n  from_line = from_line or 1\n  if type(from_line) ~= 'number' then H.error('`from_line` should be a number.') end\n  to_line = to_line or vim.api.nvim_buf_line_count(buf_id)\n  if type(to_line) ~= 'number' then H.error('`to_line` should be a number.') end\n\n  -- Process lines immediately without delay\n  H.process_lines(buf_id, from_line, to_line, 0)\nend\n\n--- Get an array of enabled buffers\n---\n---@return table Array of buffer identifiers with enabled highlighting.\nMiniHipatterns.get_enabled_buffers = function()\n  local res = {}\n  for buf_id, _ in pairs(H.cache) do\n    if vim.api.nvim_buf_is_valid(buf_id) then\n      table.insert(res, buf_id)\n    else\n      -- Clean up if buffer is invalid and for some reason is still enabled\n      H.cache[buf_id] = nil\n    end\n  end\n\n  -- Ensure consistent order\n  table.sort(res)\n\n  return res\nend\n\n--- Get buffer matches\n---\n---@param buf_id number|nil Buffer identifier for which to return matches.\n---   Default: `nil` for current buffer.\n---@param highlighters table|nil Array of highlighter identifiers (as in\n---   `highlighters` field of |MiniHipatterns.config|) for which to return matches.\n---   Default: all available highlighters (ordered by string representation).\n---\n---@return table Array of buffer matches which are tables with following fields:\n---   - <bufnr> `(number)` - buffer identifier of a match.\n---   - <highlighter> `(any)` - highlighter identifier which produced the match.\n---   - <lnum> `(number)` - line number of the match start (starts with 1).\n---   - <col> `(number)` - column number of the match start (starts with 1).\n---   - <end_lnum> `(number|nil)` - line number of the match end (starts with 1).\n---   - <end_col> `(number|nil)` - column number next to the match end\n---     (implements end-exclusive region; starts with 1).\n---   - <hl_group> `(string|nil)` - name of match's highlight group.\n---\n---   Matches are ordered first by supplied `highlighters`, then by line and\n---   column of match start.\nMiniHipatterns.get_matches = function(buf_id, highlighters)\n  buf_id = (buf_id == nil or buf_id == 0) and vim.api.nvim_get_current_buf() or buf_id\n  if not (type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id)) then\n    H.error('`buf_id` is not valid buffer identifier.')\n  end\n\n  local all_highlighters = H.get_all_highlighters()\n  highlighters = highlighters or all_highlighters\n  if not H.islist(highlighters) then H.error('`highlighters` should be an array.') end\n  highlighters = vim.tbl_filter(function(x) return vim.tbl_contains(all_highlighters, x) end, highlighters)\n\n  local position_compare = function(a, b) return a[2] < b[2] or (a[2] == b[2] and a[3] < b[3]) end\n  local res = {}\n  for _, hi_id in ipairs(highlighters) do\n    local extmarks = H.get_extmarks(buf_id, H.ns_id[hi_id], 0, -1, { details = true })\n    table.sort(extmarks, position_compare)\n\n    for _, extmark in ipairs(extmarks) do\n      local end_lnum, end_col = extmark[4].end_row, extmark[4].end_col\n      end_lnum = type(end_lnum) == 'number' and (end_lnum + 1) or end_lnum\n      end_col = type(end_col) == 'number' and (end_col + 1) or end_col\n      --stylua: ignore\n      local entry = {\n        bufnr = buf_id,        highlighter = hi_id,\n        lnum = extmark[2] + 1, col = extmark[3] + 1,\n        end_lnum = end_lnum,   end_col = end_col,\n        hl_group = extmark[4].hl_group,\n      }\n      table.insert(res, entry)\n    end\n  end\n  return res\nend\n\n--- Generate builtin highlighters\n---\n--- This is a table with function elements. Call to actually get highlighter.\nMiniHipatterns.gen_highlighter = {}\n\n--- Highlight hex color string\n---\n--- This will match color hex string in format `#rrggbb` and highlight it\n--- according to `opts.style` displaying matched color.\n---\n--- Highlight group is computed using |MiniHipatterns.compute_hex_color_group()|,\n--- so all its usage notes apply here.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <style> `(string)` - one of:\n---       - `'full'` -  highlight background of whole hex string with it. Default.\n---       - `'#'` - highlight background of only `#`.\n---       - `'line'` - highlight underline with that color.\n---       - `'inline'` - highlight text of <inline_text>.\n---         Note: requires Neovim>=0.10.\n---   - <priority> `(number)` - priority of highlighting. Default: 200.\n---   - <filter> `(function)` - callable object used to filter buffers in which\n---     highlighting will take place. It should take buffer identifier as input\n---     and return `false` or `nil` to not highlight inside this buffer.\n---   - <inline_text> `(string)` - string to be placed and highlighted with color\n---     to the right of match in case <style> is \"inline\". Default: \"█\".\n---\n---@return table Highlighter table ready to be used as part of `config.highlighters`.\n---   Both `pattern` and `group` are callable.\n---\n---@usage >lua\n---   local hipatterns = require('mini.hipatterns')\n---   hipatterns.setup({\n---     highlighters = {\n---       hex_color = hipatterns.gen_highlighter.hex_color(),\n---     }\n---   })\n--- <\nMiniHipatterns.gen_highlighter.hex_color = function(opts)\n  local default_opts = { style = 'full', priority = 200, filter = H.always_true, inline_text = '█' }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  local style = opts.style\n  if style == 'inline' and vim.fn.has('nvim-0.10') == 0 then\n    H.error('Style \"inline\" in `gen_highlighter.hex_color()` requires Neovim>=0.10.')\n  end\n\n  local pattern = style == '#' and '()#()%x%x%x%x%x%x%f[%X]' or '#%x%x%x%x%x%x%f[%X]'\n  local hl_style = ({ full = 'bg', ['#'] = 'bg', line = 'line', inline = 'fg' })[style] or 'bg'\n\n  local extmark_opts = { priority = opts.priority }\n  if opts.style == 'inline' then\n    local priority, inline_text = opts.priority, opts.inline_text\n    ---@diagnostic disable:cast-local-type\n    extmark_opts = function(_, _, data)\n      local virt_text = { { inline_text, data.hl_group } }\n      return { virt_text = virt_text, virt_text_pos = 'inline', priority = priority, right_gravity = false }\n    end\n  end\n\n  return {\n    pattern = H.wrap_pattern_with_filter(pattern, opts.filter),\n    group = function(_, _, data) return MiniHipatterns.compute_hex_color_group(data.full_match, hl_style) end,\n    extmark_opts = extmark_opts,\n  }\nend\n\n--- Compute and create group to highlight hex color string\n---\n--- Notes:\n--- - This works properly only with enabled |'termguicolors'|.\n---\n--- - To increase performance, it caches highlight groups per `hex_color` and\n---   `style` combination. Needs a call to |MiniHipatterns.setup()| to have\n---   these groups be persistent across color scheme changes.\n---\n---@param hex_color string Hex color string in format `#rrggbb`.\n---@param style|nil string One of:\n---   - `'bg'` - highlight background with `hex_color` and foreground with black or\n---     white (whichever is more visible). Default.\n---   - `'fg'` - highlight foreground with `hex_color`.\n---   - `'line'` - highlight underline with `hex_color`.\n---\n---@return string Name of created highlight group appropriate to show `hex_color`.\nMiniHipatterns.compute_hex_color_group = function(hex_color, style)\n  style = style or 'bg'\n  local hex = hex_color:lower():sub(2)\n  local group_name = string.format('MiniHipatterns_%s_%s', hex, style)\n\n  -- Use manually tracked table instead of `vim.fn.hlexists()` because the\n  -- latter still returns true for cleared highlights\n  if H.hex_color_groups[group_name] then return group_name end\n\n  -- Define highlight group if it is not already defined\n  if style == 'bg' then\n    -- Compute opposite color based on Oklab lightness (for better contrast)\n    local opposite = H.compute_opposite_color(hex)\n    vim.api.nvim_set_hl(0, group_name, { fg = opposite, bg = hex_color })\n  end\n\n  if style == 'fg' then vim.api.nvim_set_hl(0, group_name, { fg = hex_color }) end\n\n  if style == 'line' then vim.api.nvim_set_hl(0, group_name, { sp = hex_color, underline = true }) end\n\n  -- Keep track of created groups to properly react on `:hi clear`\n  H.hex_color_groups[group_name] = true\n\n  return group_name\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniHipatterns.config)\n\n-- Timers\nH.timer_debounce = vim.loop.new_timer()\nH.timer_view = vim.loop.new_timer()\n\n-- Namespaces per highlighter name\nH.ns_id = {}\n\n-- Cache of queued changes used for debounced highlighting\nH.change_queue = {}\n\n-- Cache per enabled buffer\nH.cache = {}\n\n-- Data about created highlight groups for hex colors\nH.hex_color_groups = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('highlighters', config.highlighters, 'table')\n\n  H.check_type('delay', config.delay, 'table')\n  H.check_type('delay.text_change', config.delay.text_change, 'number')\n  H.check_type('delay.scroll', config.delay.scroll, 'number')\n\n  return config\nend\n\nH.apply_config = function(config) MiniHipatterns.config = config end\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniHipatterns', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('BufEnter', '*', H.auto_enable, 'Enable highlighting')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\n  au('ColorScheme', '*', H.on_colorscheme, 'Reload all enabled pattern highlighters')\nend\n\nH.create_default_hl = function()\n  local hi_link_bold_reverse = function(to, from)\n    local data = vim.api.nvim_get_hl(0, { name = from, link = false })\n    data.default, data.bold, data.reverse = true, true, true\n    data.cterm = { bold = true, reverse = true }\n    vim.api.nvim_set_hl(0, to, data)\n  end\n  hi_link_bold_reverse('MiniHipatternsFixme', 'DiagnosticError')\n  hi_link_bold_reverse('MiniHipatternsHack', 'DiagnosticWarn')\n  hi_link_bold_reverse('MiniHipatternsTodo', 'DiagnosticInfo')\n  hi_link_bold_reverse('MiniHipatternsNote', 'DiagnosticHint')\nend\n\nH.is_disabled = function(buf_id)\n  local buf_disable = H.get_buf_var(buf_id, 'minihipatterns_disable')\n  return vim.g.minihipatterns_disable == true or buf_disable == true\nend\n\nH.get_config = function(config, buf_id)\n  local buf_config = H.get_buf_var(buf_id, 'minihipatterns_config') or {}\n  return vim.tbl_deep_extend('force', MiniHipatterns.config, buf_config, config or {})\nend\n\nH.get_buf_var = function(buf_id, name)\n  if not vim.api.nvim_buf_is_valid(buf_id) then return nil end\n  return vim.b[buf_id or 0][name]\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_enable = vim.schedule_wrap(function(data)\n  local buf = data.buf\n  if not (vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == '') then return end\n  MiniHipatterns.enable(buf)\nend)\n\nH.update_view = vim.schedule_wrap(function(data)\n  -- Update view only in enabled buffers\n  local buf_cache = H.cache[data.buf]\n  if buf_cache == nil then return end\n\n  -- NOTE: due to scheduling (which is necessary for better performance),\n  -- current buffer can be not the target one. But as there is no proper (easy\n  -- and/or fast) way to get the view of certain buffer (except the current)\n  -- accept this approach. The main problem of current buffer having not\n  -- enabled highlighting is solved during processing buffer highlighters.\n\n  -- Debounce without aggregating redraws (only last view should be updated)\n  H.timer_view:stop()\n  H.timer_view:start(buf_cache.delay.scroll, 0, H.process_view)\nend)\n\nH.on_colorscheme = function()\n  -- Reset created highlight groups for hex colors, as they are probably\n  -- cleared after `:hi clear`\n  H.hex_color_groups = {}\n\n  -- Reload all currently enabled buffers\n  for buf_id, _ in pairs(H.cache) do\n    MiniHipatterns.disable(buf_id)\n    MiniHipatterns.enable(buf_id)\n  end\nend\n\n-- Validators -----------------------------------------------------------------\nH.validate_buf_id = function(x)\n  if x == nil or x == 0 then return vim.api.nvim_get_current_buf() end\n\n  if not (type(x) == 'number' and vim.api.nvim_buf_is_valid(x)) then\n    H.error('`buf_id` should be `nil` or valid buffer id.')\n  end\n\n  return x\nend\n\nH.validate_config_arg = function(x)\n  if x == nil or type(x) == 'table' then return x or {} end\n  H.error('`config` should be `nil` or table.')\nend\n\nH.validate_string = function(x, name)\n  if type(x) == 'string' then return x end\n  H.error(string.format('`%s` should be string.'))\nend\n\n-- Enabling -------------------------------------------------------------------\nH.is_buf_enabled = function(buf_id) return H.cache[buf_id] ~= nil end\n\nH.update_cache = function(buf_id, config)\n  local buf_cache = H.cache[buf_id] or {}\n  local buf_config = H.get_config(config, buf_id)\n  buf_cache.highlighters = H.normalize_highlighters(buf_config.highlighters)\n  buf_cache.delay = buf_config.delay\n\n  H.cache[buf_id] = buf_cache\nend\n\nH.normalize_highlighters = function(highlighters)\n  local res = {}\n  for hi_name, hi in pairs(highlighters) do\n    -- Allow pattern to be string, callable, or array of those. Convert all\n    -- valid cases into array of callables.\n    local pattern = type(hi.pattern) == 'string' and function() return hi.pattern end or hi.pattern\n    if vim.is_callable(pattern) then pattern = { pattern } end\n    local is_pattern_ok = H.islist(pattern)\n    if is_pattern_ok then\n      for i, pat in ipairs(pattern) do\n        pattern[i] = type(pat) == 'string' and function() return pat end or pat\n        is_pattern_ok = is_pattern_ok and vim.is_callable(pattern[i])\n      end\n    end\n\n    local group = type(hi.group) == 'string' and function() return hi.group end or hi.group\n\n    local extmark_opts = hi.extmark_opts or { priority = 200 }\n    if type(extmark_opts) == 'table' then\n      local t = extmark_opts\n      ---@diagnostic disable:cast-local-type\n      extmark_opts = function(_, _, data)\n        local opts = vim.deepcopy(t)\n        opts.hl_group = opts.hl_group or data.hl_group\n        opts.end_row = opts.end_row or (data.line - 1)\n        opts.end_col = opts.end_col or data.to_col\n        return opts\n      end\n    end\n\n    if is_pattern_ok and vim.is_callable(group) and vim.is_callable(extmark_opts) then\n      res[hi_name] = { pattern = pattern, group = group, extmark_opts = extmark_opts }\n      H.ns_id[hi_name] = vim.api.nvim_create_namespace('MiniHipatterns-' .. hi_name)\n    end\n  end\n\n  return res\nend\n\nH.get_all_highlighters = function()\n  local hi_arr = vim.tbl_map(function(x) return { x, tostring(x) } end, vim.tbl_keys(H.ns_id))\n  table.sort(hi_arr, function(a, b) return a[2] < b[2] end)\n  return vim.tbl_map(function(x) return x[1] end, hi_arr)\nend\n\n-- Processing -----------------------------------------------------------------\nH.process_lines = vim.schedule_wrap(function(buf_id, from_line, to_line, delay_ms)\n  -- Make sure that that at least one line is processed (important to react\n  -- after deleting line with extmark non-trivial `extmark_opts`)\n  table.insert(H.change_queue, { buf_id, math.min(from_line, to_line), math.max(from_line, to_line) })\n\n  -- Debounce\n  H.timer_debounce:stop()\n  H.timer_debounce:start(delay_ms, 0, H.process_change_queue)\nend)\n\nH.process_view = vim.schedule_wrap(function()\n  table.insert(H.change_queue, { vim.api.nvim_get_current_buf(), vim.fn.line('w0'), vim.fn.line('w$') })\n\n  -- Process immediately assuming debouncing should be already done\n  H.process_change_queue()\nend)\n\nH.process_change_queue = vim.schedule_wrap(function()\n  local queue = H.normalize_change_queue()\n\n  for buf_id, lines_to_process in pairs(queue) do\n    H.process_buffer_changes(buf_id, lines_to_process)\n  end\n\n  H.change_queue = {}\nend)\n\nH.normalize_change_queue = function()\n  local res = {}\n  for _, change in ipairs(H.change_queue) do\n    -- `change` is { buf_id, from_line, to_line }; lines are already 1-indexed\n    local buf_id = change[1]\n\n    local buf_lines_to_process = res[buf_id] or {}\n    for i = change[2], change[3] do\n      buf_lines_to_process[i] = true\n    end\n\n    res[buf_id] = buf_lines_to_process\n  end\n\n  return res\nend\n\nH.process_buffer_changes = vim.schedule_wrap(function(buf_id, lines_to_process)\n  -- Return early if buffer is not proper.\n  -- Also check if buffer is enabled here mostly for better resilience. It\n  -- might be actually needed due to various `schedule_wrap`s leading to change\n  -- queue entry with not target (and improper) buffer.\n  local buf_cache = H.cache[buf_id]\n  if not vim.api.nvim_buf_is_valid(buf_id) or H.is_disabled(buf_id) or buf_cache == nil then return end\n\n  -- Optimizations are done assuming small-ish number of highlighters and\n  -- large-ish number of lines to process\n\n  -- Process highlighters\n  for hi_name, hi in pairs(buf_cache.highlighters) do\n    -- Remove current highlights\n    local ns = H.ns_id[hi_name]\n    for l_num, _ in pairs(lines_to_process) do\n      H.clear_namespace(buf_id, ns, l_num - 1, l_num)\n    end\n\n    -- Add new highlights\n    for _, pattern in ipairs(hi.pattern) do\n      H.apply_highlighter_pattern(pattern(buf_id), hi, buf_id, ns, lines_to_process)\n    end\n  end\nend)\n\nH.apply_highlighter_pattern = vim.schedule_wrap(function(pattern, hi, buf_id, ns, lines_to_process)\n  -- Check again because buffer might have become invalid since latest check\n  if not vim.api.nvim_buf_is_valid(buf_id) then return end\n\n  if type(pattern) ~= 'string' then return end\n  local group, extmark_opts = hi.group, hi.extmark_opts\n  local pattern_has_line_start = pattern:sub(1, 1) == '^'\n\n  -- Apply per proper line\n  for l_num, _ in pairs(lines_to_process) do\n    local line = H.get_line(buf_id, l_num)\n    local from, to, sub_from, sub_to = line:find(pattern)\n\n    while from and (from <= to) do\n      -- Compute full pattern match\n      local full_match = line:sub(from, to)\n\n      -- Compute (possibly inferred) submatch\n      sub_from, sub_to = sub_from or from, sub_to or (to + 1)\n      -- - Make last column end-inclusive\n      sub_to = sub_to - 1\n      local match = line:sub(sub_from, sub_to)\n\n      -- Set extmark based on submatch\n      local data = { full_match = full_match, line = l_num, from_col = sub_from, to_col = sub_to }\n      local hl_group = group(buf_id, match, data)\n      if hl_group ~= nil then\n        data.hl_group = hl_group\n        H.set_extmark(buf_id, ns, l_num - 1, sub_from - 1, extmark_opts(buf_id, match, data))\n      end\n\n      -- Overcome an issue that `string.find()` doesn't recognize `^` when\n      -- `init` is more than 1\n      if pattern_has_line_start then break end\n\n      from, to, sub_from, sub_to = line:find(pattern, sub_to + 1)\n    end\n  end\nend)\n\n-- Built-in highlighters ------------------------------------------------------\nH.wrap_pattern_with_filter = function(pattern, filter)\n  return function(...)\n    if not filter(...) then return nil end\n    return pattern\n  end\nend\n\nH.compute_opposite_color = function(hex)\n  local dec = tonumber(hex, 16)\n  local b = H.correct_channel(math.fmod(dec, 256) / 255)\n  local g = H.correct_channel(math.fmod((dec - b) / 256, 256) / 255)\n  local r = H.correct_channel(math.floor(dec / 65536) / 255)\n\n  local l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b\n  local m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b\n  local s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b\n\n  local l_, m_, s_ = H.cuberoot(l), H.cuberoot(m), H.cuberoot(s)\n\n  local L = H.correct_lightness(0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_)\n\n  return L < 0.5 and '#ffffff' or '#000000'\nend\n\n-- Function for RGB channel correction. Assumes input in [0; 1] range\n-- https://bottosson.github.io/posts/colorwrong/#what-can-we-do%3F\nH.correct_channel = function(x) return 0.04045 < x and math.pow((x + 0.055) / 1.055, 2.4) or (x / 12.92) end\n\n-- Function for lightness correction\n-- https://bottosson.github.io/posts/colorpicker/#intermission---a-new-lightness-estimate-for-oklab\nH.correct_lightness = function(x)\n  local k1, k2 = 0.206, 0.03\n  local k3 = (1 + k1) / (1 + k2)\n\n  return 0.5 * (k3 * x - k1 + math.sqrt((k3 * x - k1) ^ 2 + 4 * k2 * k3 * x))\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.hipatterns) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.get_line = function(buf_id, line_num)\n  return vim.api.nvim_buf_get_lines(buf_id, line_num - 1, line_num, false)[1] or ''\nend\n\nH.set_extmark = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end\n\nH.get_extmarks = function(...)\n  local ok, res = pcall(vim.api.nvim_buf_get_extmarks, ...)\n  if not ok then return {} end\n  return res\nend\n\nH.clear_namespace = function(...) pcall(vim.api.nvim_buf_clear_namespace, ...) end\n\nH.always_true = function() return true end\n\nH.cuberoot = function(x) return math.pow(x, 0.333333) end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniHipatterns\n"
  },
  {
    "path": "lua/mini/hues.lua",
    "content": "--- *mini.hues* Generate configurable color scheme\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Required to set two base colors: background and foreground.\n---   Their shades and other non-base colors are computed to be as much\n---   perceptually different as reasonably possible.\n---   See |MiniHues.config| for setup inspiration.\n---\n--- - Configurable:\n---     - Number of hues used for non-base colors (from 0 to 8).\n---     - Saturation level (\"low\", \"lowmedium\", \"medium\", \"mediumhigh\", \"high\").\n---     - Accent color used for some selected UI elements.\n---     - Plugin integration (can be selectively enabled for faster startup).\n---\n--- - Random generator for base colors. See |MiniHues.gen_random_base_colors()|.\n---   Powers |randomhue| color scheme.\n---\n--- - Lua function to compute palette used in color scheme.\n---   See |MiniHues.make_palette()|.\n---\n--- - Bundled color schemes. See |MiniHues-color-schemes|.\n---\n--- Supported highlight groups:\n--- - All built-in UI and syntax groups.\n---\n--- - Built-in Neovim LSP and diagnostic.\n---\n--- - Tree-sitter (|treesitter-highlight-groups|).\n---\n--- - LSP semantic tokens (|lsp-semantic-highlight|).\n---\n--- - Plugins (either with explicit definition or by verification that default\n---   highlighting works appropriately):\n---     - [nvim-mini/mini.nvim](https://nvim-mini.org/mini.nvim)\n---     - [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n---     - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n---     - [DanilaMihailov/beacon.nvim](https://github.com/DanilaMihailov/beacon.nvim)\n---     - [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n---     - [folke/noice.nvim](https://github.com/folke/noice.nvim)\n---     - [folke/snacks.nvim](https://github.com/folke/snacks.nvim)\n---     - [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n---     - [folke/trouble.nvim](https://github.com/folke/trouble.nvim)\n---     - [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n---     - [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n---     - [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n---     - [glepnir/lspsaga.nvim](https://github.com/glepnir/lspsaga.nvim)\n---     - [HiPhish/rainbow-delimiters.nvim](https://github.com/HiPhish/rainbow-delimiters.nvim)\n---     - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n---     - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n---     - [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n---     - [kevinhwang91/nvim-bqf](https://github.com/kevinhwang91/nvim-bqf)\n---     - [kevinhwang91/nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n---     - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n---     - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n---     - [MeanderingProgrammer/render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)\n---     - [neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)\n---     - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n---     - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n---     - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n---     - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n---     - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n---     - [OXY2DEV/helpview.nvim](https://github.com/OXY2DEV/helpview.nvim)\n---     - [OXY2DEV/markview.nvim](https://github.com/OXY2DEV/markview.nvim)\n---     - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim)\n---     - [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)\n---     - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n---     - [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n---     - [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n---     - [stevearc/aerial.nvim](https://github.com/stevearc/aerial.nvim)\n---     - [williamboman/mason.nvim](https://github.com/williamboman/mason.nvim)\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.hues').setup({})` and\n--- **mandatory `background` and `foreground` fields** (add more fields to fit\n--- your taste). It will create global Lua table `MiniHues` which you can use\n--- for scripting or manually (with `:lua MiniHues.*`).\n---\n--- See |MiniHues.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minihues_config`\n--- will have no effect here.\n---\n--- Example:\n--- >\n---   require('mini.hues').setup({\n---     background = '#11262d',\n---     foreground = '#c0c8cc',\n---     plugins = {\n---       default = false,\n---       ['nvim-mini/mini.nvim'] = true,\n---     },\n---   })\n--- <\n--- # Notes ~\n---\n--- - This is used to create some of plugin's color schemes\n---   (see |MiniHues-color-schemes|).\n---\n--- - Using `setup()` doesn't actually create a colorscheme. It basically\n---   creates a coordinated set of |highlight-groups|. To create your own scheme:\n---     - Put \"myscheme.lua\" file (name after your chosen theme name) inside\n---       any \"colors\" directory reachable from 'runtimepath' (\"colors\" inside\n---       your Neovim config directory is usually enough).\n---     - Inside \"myscheme.lua\" call `require('mini.hues').setup()` with your\n---       palette and only after that set |g:colors_name| to \"myscheme\".\n---\n--- - This module doesn't define |cterm-colors| for implementation simplicity.\n---   Use |mini.colors| module, |MiniColors-colorscheme:add_cterm_attributes()|\n---   in particular.\n---@tag MiniHues\n\n--- Bundled color schemes\n---\n--- - *miniwinter* : \"icy winter\" palette with azure background.\n--- - *minispring* : \"blooming spring\" palette with green background.\n--- - *minisummer* : \"hot summer\" palette with brown/yellow background.\n--- - *miniautumn* : \"cooling autumn\" palette with purple background.\n---\n--- - *randomhue* : uses randomly generated same hue background and foreground.\n---   Every `:colorscheme randomhue` call results in a different (randomly yet\n---   carefully selected) colors.\n---\n---   It is essentially a combination of calls to |MiniHues.setup()| and\n---   |MiniHues.gen_random_base_colors()| with a slight adjustments for\n---   'background' value.\n---\n---   Activate it as regular |:colorscheme|. Get currently active config with\n---   `:lua print(vim.inspect(MiniHues.config))`.\n---@tag MiniHues-color-schemes\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniHues = {}\nlocal H = {}\n\n--- Module setup\n---\n--- Main side effect is to create palette and apply it. Essentially, a combination\n--- of |MiniHues.make_palette()| and |MiniHues.apply_palette()|.\n---\n---@usage >lua\n---   require('mini.hues').setup({\n---     -- Use config table as you like\n---     -- Needs both `background` and `foreground` fields present\n---     background = '#11262d',\n---     foreground = '#c0c8cc',\n---   })\n--- <\nMiniHues.setup = function(config)\n  -- Export module\n  _G.MiniHues = MiniHues\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text See |MiniHues.make_palette()| for more information about how certain settings\n--- affect output color scheme.\n---\n--- # Plugin integrations ~\n---\n--- `config.plugins` defines for which supported plugins highlight groups will\n--- be created. Limiting number of integrations slightly decreases startup time.\n--- It is a table with boolean (`true`/`false`) values which are applied as follows:\n--- - If plugin name (as listed in |mini.hues|) has entry, it is used.\n--- - Otherwise `config.plugins.default` is used.\n---\n--- Example which will load only \"mini.nvim\" integration: >lua\n---\n---   require('mini.hues').setup({\n---     background = '#11262d',\n---     foreground = '#c0c8cc',\n---     plugins = {\n---       default = false,\n---       ['nvim-mini/mini.nvim'] = true,\n---     },\n---   })\n--- <\n--- # Auto adjust ~\n---\n--- `config.autoadjust` defines whether to adjust some highlight groups based on\n--- events relevant to them. Currently adjusted groups:\n---\n--- - |hl-MsgSeparator| is adjusted based on `msgsep` flag in |'fillchars'|.\n---   If it is whitespace - highlight background, otherwise - foreground.\n---\n--- - |hl-Pmenu| is adjusted based on |'pumborder'| value (on Neovim>=0.12).\n---   If it results in a border - same as floating window (but with no accent\n---   foreground in border), otherwise - same as |hl-CursorLine|. This design\n---   makes |ins-completion-menu| stand out from regular floating windows.\n---\n--- # Examples ~\n--- *MiniHues-examples*\n---\n--- Here are some possible setup configurations (copy first line and then use\n--- only one `setup` call): >lua\n---\n---   local setup = require('mini.hues').setup\n---\n---   -- Choose background and foreground\n---   setup({ background = '#2f1c22', foreground = '#cdc4c6' }) -- red\n---   setup({ background = '#2f1e16', foreground = '#cdc5c1' }) -- orange\n---   setup({ background = '#282211', foreground = '#c9c6c0' }) -- yellow\n---   setup({ background = '#1c2617', foreground = '#c4c8c2' }) -- green\n---   setup({ background = '#112723', foreground = '#c0c9c7' }) -- cyan\n---   setup({ background = '#11262d', foreground = '#c0c8cc' }) -- azure\n---   setup({ background = '#1d2231', foreground = '#c4c6cd' }) -- blue\n---   setup({ background = '#281e2c', foreground = '#c9c5cb' }) -- purple\n---\n---   -- Choose number of accent colors\n---   setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 6 })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 4 })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 2 })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', n_hues = 0 })\n---\n---   -- Choose saturation of colored text\n---   setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'low' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'lowmedium' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'medium' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'mediumhigh' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', saturation = 'high' })\n---\n---   -- Choose accent color\n---   setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'bg' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'red' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'yellow' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'cyan' })\n---   setup({ background = '#11262d', foreground = '#c0c8cc', accent = 'blue' })\n--- <\nMiniHues.config = {\n  -- **Required** base colors as '#rrggbb' hex strings\n  background = nil,\n  foreground = nil,\n\n  -- Number of hues used for non-base colors\n  n_hues = 8,\n\n  -- Saturation. One of 'low', 'lowmedium', 'medium', 'mediumhigh', 'high'.\n  saturation = 'medium',\n\n  -- Accent color. One of: 'bg', 'fg', 'red', 'orange', 'yellow', 'green',\n  -- 'cyan', 'azure', 'blue', 'purple'\n  accent = 'bg',\n\n  -- Plugin integrations. Use `default = false` to disable all integrations.\n  -- Also can be set per plugin (see |MiniHues.config|).\n  plugins = { default = true },\n\n  -- Whether to auto adjust highlight groups based on certain events\n  autoadjust = true,\n}\n--minidoc_afterlines_end\n\n--- # Make palette ~\n---\n--- General idea of palette generation is that it is mostly based on color channel\n--- information extracted from base colors (background and foreground).\n---\n--- All operations are done inside `Oklch` color space, meaning that each color\n--- is defined by three numbers:\n--- - Lightness (`l`) - number between 0 (black) and 100 (white) describing how\n---   light is a color.\n--- - Chroma (`c`) - positive number describing how colorful is a color (bigger\n---   values - more colorful; 0 is gray).\n--- - Hue (`h`) - periodic number in [0, 360) describing a value of \"true color\"\n---   on color circle/wheel.\n---\n--- For more details about `Oklch` see |MiniColors-color-spaces| or\n--- https://bottosson.github.io/posts/oklab/.\n---\n--- ## Algorithm overview ~\n---\n--- - Extract lightness, chroma, and hue of base colors.\n---\n--- - Generate reference lightness values:\n---     - Background edge: 0 or 100, whichever is closest to background lightness.\n---     - Foreground edge: 0 or 100, different from background edge.\n---     - Middle: arithmetic mean of background and foreground lightness values.\n---\n--- - Compute background and foreground tints and shades by changing lightness\n---   of background color: two colors closer to background lightness edge and\n---   two closer to middle.\n---\n--- - Pick chroma value for non-base colors based on `config.saturation`.\n---\n--- - Generate hues for non-base colors:\n---     - Fit an equidistant circular grid with `config.n_hues` points to be as\n---       far from both background and foreground hues. This will ensure that\n---       non-base colors are as different as possible from base ones (for\n---       better visual perception).\n---       Example: for background hue 0, foreground hue 180, and `config.n_hues` 2\n---       the output grid will be `{ 90, 270 }`.\n---\n---     - For each hue of reference color (which itself is an equidistant grid\n---       of 8 hues) compute the closest value from the grid. This allows\n---       operating in same terms (like \"red\", \"green\") despite maybe actually\n---       having less different hues.\n---\n--- - Compute for each hue two variants of non-base colors: with background and\n---   foreground lightness values.\n---\n--- - Compute two variants of accent color (with background and foreground\n---   lightness) based on `config.accent`.\n---\n--- Notes:\n--- - Some output colors can have not exact values of generated Oklch channels.\n---   This is due to actually computed colors being impossible to represent via\n---   '#rrggbb' hex string. In this case a process called gamut clipping is done\n---   to reduce lightness and chroma in optimal way while maintaining same hue.\n---   For more information see |MiniColors-gamut-clip|.\n---\n--- - Not all colors are actually used in highlight groups and are present for the\n---   sake of completeness.\n---\n---@param config table Configuration for palette. Same structure as |MiniHues.config|.\n---   Needs to have <background> and <foreground> fields.\n---\n---@return table Palette with the following fields:\n---   - <bg> and <fg> with supplied `background` and `foreground` colors.\n---   - Fields like <bg_xxx> and <fg_xxx> are essentially <bg> and <fg> but with\n---     different lightness values: `_edge`/`_edge2` - closer to edge lightness,\n---     `_mid`/`_mid2` - closer to middle lightness.\n---   - Fields for non-base colors (<red>, <orange>, <yellow>, <green>, <cyan>,\n---     <azure>, <blue>, <purple>) have the same lightness as foreground.\n---   - Fields for non-base colors with <_bg> suffix have the same lightness as\n---     background.\n---   - <accent> and <accent_bg> represent accent colors with foreground and\n---     background lightness values.\n---\n---@seealso |MiniHues.get_palette()|\nMiniHues.make_palette = function(config)\n  config = vim.tbl_deep_extend('force', MiniHues.config, config or {})\n  local bg = H.validate_hex(config.background, 'background')\n  local fg = H.validate_hex(config.foreground, 'foreground')\n  local n_hues = H.validate_n_hues(config.n_hues)\n  local saturation = H.validate_one_of(config.saturation, H.saturation_values, 'saturation')\n  local accent = H.validate_one_of(config.accent, H.accent_values, 'accent')\n\n  local bg_lch, fg_lch = H.hex2oklch(bg), H.hex2oklch(fg)\n  local bg_l, fg_l = bg_lch.l, fg_lch.l\n  if not ((bg_l <= 50 and 50 < fg_l) or (fg_l <= 50 and 50 < bg_l)) then\n    H.error('`background` and `foreground` should have opposite lightness.')\n  end\n\n  -- Reference lightness levels\n  local is_dark = bg_l <= 50\n  local l_bg_edge = is_dark and 0 or 100\n  local l_fg_edge = is_dark and 100 or 0\n  local l_mid = 0.5 * (bg_l + fg_l)\n\n  -- Configurable chroma level\n  local chroma = ({ low = 4, lowmedium = 6, medium = 8, mediumhigh = 12, high = 16 })[saturation]\n\n  -- Hues\n  local hues = H.make_hues(bg_lch.h, fg_lch.h, n_hues)\n\n  -- Compute result\n  --stylua: ignore\n  local res = {\n    -- `_edge`/`_mid` are third of the way towards reference (edge/middle)\n    -- `_edge2`/`_mid2` are two thirds\n    bg_edge2  = H.oklch2hex({ l = 0.33 * bg_l + 0.67 * l_bg_edge, c = bg_lch.c, h = bg_lch.h }),\n    bg_edge   = H.oklch2hex({ l = 0.67 * bg_l + 0.33 * l_bg_edge, c = bg_lch.c, h = bg_lch.h }),\n    bg        = bg,\n    bg_mid    = H.oklch2hex({ l = 0.67 * bg_l + 0.33 * l_mid,     c = bg_lch.c, h = bg_lch.h }),\n    bg_mid2   = H.oklch2hex({ l = 0.33 * bg_l + 0.67 * l_mid,     c = bg_lch.c, h = bg_lch.h }),\n\n    fg_edge2  = H.oklch2hex({ l = 0.33 * fg_l + 0.67 * l_fg_edge, c = fg_lch.c, h = fg_lch.h }),\n    fg_edge   = H.oklch2hex({ l = 0.67 * fg_l + 0.33 * l_fg_edge, c = fg_lch.c, h = fg_lch.h }),\n    fg        = fg,\n    fg_mid    = H.oklch2hex({ l = 0.67 * fg_l + 0.33 * l_mid,     c = fg_lch.c, h = fg_lch.h }),\n    fg_mid2   = H.oklch2hex({ l = 0.33 * fg_l + 0.67 * l_mid,     c = fg_lch.c, h = fg_lch.h }),\n\n    red       = H.oklch2hex({ l = fg_l, c = chroma, h = hues.red }),\n    red_bg    = H.oklch2hex({ l = bg_l, c = chroma, h = hues.red }),\n\n    orange    = H.oklch2hex({ l = fg_l, c = chroma, h = hues.orange }),\n    orange_bg = H.oklch2hex({ l = bg_l, c = chroma, h = hues.orange }),\n\n    yellow    = H.oklch2hex({ l = fg_l, c = chroma, h = hues.yellow }),\n    yellow_bg = H.oklch2hex({ l = bg_l, c = chroma, h = hues.yellow }),\n\n    green     = H.oklch2hex({ l = fg_l, c = chroma, h = hues.green }),\n    green_bg  = H.oklch2hex({ l = bg_l, c = chroma, h = hues.green }),\n\n    cyan      = H.oklch2hex({ l = fg_l, c = chroma, h = hues.cyan }),\n    cyan_bg   = H.oklch2hex({ l = bg_l, c = chroma, h = hues.cyan }),\n\n    azure     = H.oklch2hex({ l = fg_l, c = chroma, h = hues.azure }),\n    azure_bg  = H.oklch2hex({ l = bg_l, c = chroma, h = hues.azure }),\n\n    blue      = H.oklch2hex({ l = fg_l, c = chroma, h = hues.blue }),\n    blue_bg   = H.oklch2hex({ l = bg_l, c = chroma, h = hues.blue }),\n\n    purple    = H.oklch2hex({ l = fg_l, c = chroma, h = hues.purple }),\n    purple_bg = H.oklch2hex({ l = bg_l, c = chroma, h = hues.purple }),\n  }\n\n  -- Manage 'bg' and 'fg' accents separately to ensure that corresponding\n  -- background and foreground colors match exactly\n  --stylua: ignore\n  if accent == 'bg' then\n    res.accent     = H.oklch2hex({ l = fg_l, c = chroma, h = bg_lch.h })\n    res.accent_bg  = bg\n  elseif accent == 'fg' then\n    res.accent     = fg\n    res.accent_bg  = H.oklch2hex({ l = bg_l, c = chroma, h = fg_lch.h })\n  else\n    res.accent     = H.oklch2hex({ l = fg_l, c = chroma, h = hues[accent] })\n    res.accent_bg  = H.oklch2hex({ l = bg_l, c = chroma, h = hues[accent] })\n  end\n\n  return res\nend\n\n-- stylua: ignore\n--- Apply palette\n---\n--- Create color scheme highlight groups and terminal colors based on supplied\n--- palette. This is useful if you want to tweak palette colors.\n--- For regular usage prefer |MiniHues.setup()|.\n---\n---@param palette table Table with structure as |MiniHues.make_palette()| output.\n---@param plugins table|nil Table with boolean values indicating whether to create\n---   highlight groups for specific plugins. See |MiniHues.config| for more details.\n---   Default: the value from |MiniHues.config|.\n---@param opts table|nil Options. Possible fields:\n---   - <autoadjust> - whether to auto adjust some highlight groups when needed.\n---     Default: value of `autoadjust` in |MiniHues.config|.\n---\n---@usage >lua\n---   local palette = require('mini.hues').make_palette({\n---     background = '#11262d',\n---     foreground = '#c0c8cc',\n---   })\n---   palette.cyan = '#76e0a6'\n---   palette.cyan_bg = '#004629'\n---   require('mini.hues').apply_palette(palette)\n--- <\n---@seealso |MiniHues.get_palette()|\nMiniHues.apply_palette = function(palette, plugins, opts)\n  if type(palette) ~= 'table' then H.error('`palette` should be table with palette colors.') end\n  plugins = plugins or MiniHues.config.plugins\n  if type(plugins) ~= 'table' then H.error('`plugins` should be table with plugin integrations data.') end\n  opts = vim.tbl_extend('force', { autoadjust = MiniHues.config.autoadjust }, opts or {})\n\n  H.palette = vim.deepcopy(palette)\n\n  -- Prepare highlighting application. Notes:\n  -- - Clear current highlight only if other theme was loaded previously.\n  -- - No need to `syntax reset` because *all* syntax groups are defined later.\n  if vim.g.colors_name then vim.cmd('highlight clear') end\n\n  -- As this doesn't create colorscheme, don't store any name. Not doing it\n  -- might cause some issues with `syntax on`.\n  vim.g.colors_name = nil\n\n  local p, autoadjust = palette, opts.autoadjust\n  local hi = function(name, data) vim.api.nvim_set_hl(0, name, data) end\n  local has_integration = function(name)\n    local entry = plugins[name]\n    if entry == nil then return plugins.default end\n    return entry\n  end\n\n  -- Special autoadjustable highlight groups\n  if autoadjust then H.setup_autoadjust(p) end\n\n  -- NOTE: recommendations for adding new highlight groups:\n  -- - Put all related groups (like for new plugin) in single paragraph.\n  -- - Sort within group alphabetically (by hl-group name) ignoring case.\n  -- - Link all repeated groups within paragraph (lowers execution time).\n  -- - Align by commas.\n\n  -- Builtin highlighting groups\n  hi('ColorColumn',    { fg=nil,       bg=p.bg_mid2 })\n  hi('ComplMatchIns',  { fg=nil,       bg=nil })\n  hi('Conceal',        { fg=p.azure,   bg=nil })\n  hi('CurSearch',      { fg=p.bg,      bg=p.yellow })\n  hi('Cursor',         { fg=p.bg,      bg=p.fg })\n  hi('CursorColumn',   { fg=nil,       bg=p.bg_mid })\n  hi('CursorIM',       { link='Cursor' })\n  hi('CursorLine',     { fg=nil,       bg=p.bg_mid })\n  hi('CursorLineFold', { fg=p.bg_mid2, bg=nil })\n  hi('CursorLineNr',   { fg=p.accent,  bg=nil,       bold=true })\n  hi('CursorLineSign', { fg=p.bg_mid2, bg=nil })\n  hi('DiffAdd',        { fg=nil,       bg=p.green_bg })\n  hi('DiffChange',     { fg=nil,       bg=p.cyan_bg })\n  hi('DiffDelete',     { fg=nil,       bg=p.red_bg })\n  hi('DiffText',       { fg=nil,       bg=p.yellow_bg })\n  hi('DiffTextAdd',    { link='DiffAdd' })\n  hi('Directory',      { fg=p.azure,   bg=nil })\n  hi('EndOfBuffer',    { fg=p.bg_mid2, bg=nil })\n  hi('ErrorMsg',       { fg=p.red,     bg=nil })\n  hi('FloatBorder',    { fg=p.accent,  bg=p.bg_edge })\n  hi('FloatTitle',     { fg=p.accent,  bg=p.bg_edge, bold=true })\n  hi('FoldColumn',     { fg=p.bg_mid2, bg=nil })\n  hi('Folded',         { fg=p.fg_mid2, bg=p.bg_edge })\n  hi('IncSearch',      { fg=p.bg,      bg=p.yellow })\n  hi('lCursor',        { fg=p.bg,      bg=p.fg })\n  hi('LineNr',         { fg=p.bg_mid2, bg=nil })\n  hi('LineNrAbove',    { link='LineNr' })\n  hi('LineNrBelow',    { link='LineNr' })\n  hi('MatchParen',     { fg=nil,       bg=p.bg_mid2, bold=true })\n  hi('ModeMsg',        { fg=p.green,   bg=nil })\n  hi('MoreMsg',        { fg=p.azure,   bg=nil })\n  hi('MsgArea',        { link='Normal' })\n  hi('MsgSeparator',   H.attr_msgseparator(p, autoadjust))\n  hi('NonText',        { fg=p.bg_mid2, bg=nil })\n  hi('Normal',         { fg=p.fg,      bg=p.bg })\n  hi('NormalFloat',    { fg=p.fg,      bg=p.bg_edge })\n  hi('NormalNC',       { link='Normal' })\n  hi('OkMsg',          { fg=p.green,   bg=nil })\n  hi('Pmenu',          H.attr_pmenu(p, autoadjust))\n  hi('PmenuBorder',    { link='Pmenu' })\n  hi('PmenuExtra',     { link='Pmenu' })\n  hi('PmenuExtraSel',  { link='PmenuSel' })\n  hi('PmenuKind',      { link='Pmenu' })\n  hi('PmenuKindSel',   { link='PmenuSel' })\n  hi('PmenuMatch',     { fg=nil,       bg=nil,       bold=true })\n  hi('PmenuMatchSel',  { fg=nil,       bg=nil,       bold=true,   blend=0, reverse=true })\n  hi('PmenuSbar',      { link='Pmenu' })\n  hi('PmenuSel',       { fg=nil,       bg=nil,       blend=0,     reverse=true })\n  hi('PmenuThumb',     { fg=nil,       bg=p.bg_mid2 })\n  hi('Question',       { fg=p.azure,   bg=nil })\n  hi('QuickFixLine',   { fg=nil,       bg=nil,       bold=true })\n  hi('Search',         { fg=p.bg,      bg=p.accent })\n  hi('SignColumn',     { fg=p.bg_mid2, bg=nil })\n  hi('SpecialKey',     { fg=p.accent,  bg=nil })\n  hi('SpellBad',       { fg=nil,       bg=nil,       sp=p.red,    undercurl=true })\n  hi('SpellCap',       { fg=nil,       bg=nil,       sp=p.cyan,   undercurl=true })\n  hi('SpellLocal',     { fg=nil,       bg=nil,       sp=p.yellow, undercurl=true })\n  hi('SpellRare',      { fg=nil,       bg=nil,       sp=p.blue,   undercurl=true })\n  hi('StatusLine',     { fg=p.fg_mid,  bg=p.accent_bg })\n  hi('StatusLineNC',   { fg=p.fg_mid,  bg=p.bg_edge })\n  hi('StderrMsg',      { link='ErrorMsg' })\n  hi('StdoutMsg',      { link='MsgArea' })\n  hi('Substitute',     { fg=p.bg,      bg=p.blue })\n  hi('TabLine',        { fg=p.fg_mid,  bg=p.bg_edge })\n  hi('TabLineFill',    { link='Tabline' })\n  hi('TabLineSel',     { fg=p.accent,  bg=p.bg_edge })\n  hi('TermCursor',     { fg=nil,       bg=nil,       reverse=true })\n  hi('TermCursorNC',   { fg=nil,       bg=nil,       reverse=true })\n  hi('Title',          { fg=p.accent,  bg=nil })\n  hi('VertSplit',      { fg=p.accent,  bg=nil })\n  hi('Visual',         { fg=nil,       bg=p.bg_mid2 })\n  hi('VisualNOS',      { fg=nil,       bg=p.bg_mid })\n  hi('WarningMsg',     { fg=p.yellow,  bg=nil })\n  hi('Whitespace',     { fg=p.bg_mid2, bg=nil })\n  hi('WildMenu',       { link='PmenuSel' })\n  hi('WinBar',         { link='StatusLine' })\n  hi('WinBarNC',       { link='StatusLineNC' })\n  hi('WinSeparator',   { fg=p.accent,  bg=nil })\n\n  -- Standard syntax (affects treesitter)\n  hi('Boolean',        { link='Constant' })\n  hi('Character',      { link='Constant' })\n  hi('Comment',        { fg=p.fg_mid2, bg=nil })\n  hi('Conditional',    { link='Statement' })\n  hi('Constant',       { fg=p.purple,  bg=nil })\n  hi('Debug',          { link='Special' })\n  hi('Define',         { link='PreProc' })\n  hi('Delimiter',      { fg=p.orange,  bg=nil })\n  hi('Error',          { fg=nil,       bg=p.red_bg })\n  hi('Exception',      { link='Statement' })\n  hi('Float',          { link='Constant' })\n  hi('Function',       { fg=p.azure,   bg=nil })\n  hi('Identifier',     { fg=p.yellow,  bg=nil })\n  hi('Ignore',         { fg=nil,       bg=nil })\n  hi('Include',        { link='PreProc' })\n  hi('Keyword',        { link='Statement' })\n  hi('Label',          { link='Statement' })\n  hi('Macro',          { link='PreProc' })\n  hi('Number',         { link='Constant' })\n  hi('Operator',       { fg=p.fg,      bg=nil })\n  hi('PreCondit',      { link='PreProc' })\n  hi('PreProc',        { fg=p.blue,    bg=nil })\n  hi('Repeat',         { link='Statement' })\n  hi('Special',        { fg=p.cyan,    bg=nil })\n  hi('SpecialChar',    { link='Special' })\n  hi('SpecialComment', { link='Special' })\n  hi('Statement',      { fg=p.fg,      bg=nil,         bold=true })\n  hi('StorageClass',   { link='Type' })\n  hi('String',         { fg=p.green,   bg=nil })\n  hi('Structure',      { link='Type' })\n  hi('Tag',            { link='Special' })\n  hi('Todo',           { fg=p.accent,  bg=p.accent_bg, bold=true })\n  hi('Type',           { fg=p.fg,      bg=nil })\n  hi('Typedef',        { link='Type' })\n\n  -- Other community standard\n  hi('Bold',       { fg=nil, bg=nil, bold=true })\n  hi('Italic',     { fg=nil, bg=nil, italic=true })\n  hi('Underlined', { fg=nil, bg=nil, underline=true })\n\n  -- Patch diff\n  hi('diffAdded',   { fg=p.green,  bg=nil })\n  hi('diffChanged', { fg=p.cyan,   bg=nil })\n  hi('diffFile',    { fg=p.yellow, bg=nil })\n  hi('diffLine',    { fg=p.blue,   bg=nil })\n  hi('diffRemoved', { fg=p.red,    bg=nil })\n  hi('Added',       { fg=p.green,  bg=nil })\n  hi('Changed',     { fg=p.cyan,   bg=nil })\n  hi('Removed',     { fg=p.red,    bg=nil })\n\n  -- Git commit\n  hi('gitcommitBranch',        { fg=p.orange, bg=nil, bold=true })\n  hi('gitcommitComment',       { link='Comment' })\n  hi('gitcommitDiscarded',     { link='Comment' })\n  hi('gitcommitDiscardedFile', { fg=p.yellow, bg=nil, bold=true })\n  hi('gitcommitDiscardedType', { fg=p.azure,  bg=nil })\n  hi('gitcommitHeader',        { link='Title' })\n  hi('gitcommitOverflow',      { fg=p.yellow, bg=nil })\n  hi('gitcommitSelected',      { link='Comment' })\n  hi('gitcommitSelectedFile',  { fg=p.green,  bg=nil, bold=true })\n  hi('gitcommitSelectedType',  { link='gitcommitDiscardedType' })\n  hi('gitcommitSummary',       { fg=p.green,  bg=nil })\n  hi('gitcommitUnmergedFile',  { link='gitcommitDiscardedFile' })\n  hi('gitcommitUnmergedType',  { link='gitcommitDiscardedType' })\n  hi('gitcommitUntracked',     { link='Comment' })\n  hi('gitcommitUntrackedFile', { fg=p.cyan,   bg=nil })\n\n  -- Built-in diagnostic\n  -- Logic:\n  -- - Error is red.\n  -- - Distance from hue to error hue should increase the less important it is\n  --   (warning - info - ok - hint).\n  hi('DiagnosticError', { fg=p.red,    bg=nil })\n  hi('DiagnosticHint',  { fg=p.cyan,   bg=nil })\n  hi('DiagnosticInfo',  { fg=p.blue,   bg=nil })\n  hi('DiagnosticOk',    { fg=p.green,  bg=nil })\n  hi('DiagnosticWarn',  { fg=p.yellow, bg=nil })\n\n  hi('DiagnosticUnderlineError', { fg=nil, bg=nil, sp=p.red,    underline=true })\n  hi('DiagnosticUnderlineHint',  { fg=nil, bg=nil, sp=p.cyan,   underline=true })\n  hi('DiagnosticUnderlineInfo',  { fg=nil, bg=nil, sp=p.blue,   underline=true })\n  hi('DiagnosticUnderlineOk',    { fg=nil, bg=nil, sp=p.green,  underline=true })\n  hi('DiagnosticUnderlineWarn',  { fg=nil, bg=nil, sp=p.yellow, underline=true })\n\n  hi('DiagnosticFloatingError', { fg=p.red,    bg=p.bg_edge })\n  hi('DiagnosticFloatingHint',  { fg=p.cyan,   bg=p.bg_edge })\n  hi('DiagnosticFloatingInfo',  { fg=p.blue,   bg=p.bg_edge })\n  hi('DiagnosticFloatingOk',    { fg=p.green,  bg=p.bg_edge })\n  hi('DiagnosticFloatingWarn',  { fg=p.yellow, bg=p.bg_edge })\n\n  hi('DiagnosticVirtualTextError', { link='DiagnosticError' })\n  hi('DiagnosticVirtualTextWarn',  { link='DiagnosticWarn' })\n  hi('DiagnosticVirtualTextInfo',  { link='DiagnosticInfo' })\n  hi('DiagnosticVirtualTextHint',  { link='DiagnosticHint' })\n  hi('DiagnosticVirtualTextOk',    { link='DiagnosticOk' })\n\n  hi('DiagnosticSignError', { link='DiagnosticError' })\n  hi('DiagnosticSignWarn',  { link='DiagnosticWarn' })\n  hi('DiagnosticSignInfo',  { link='DiagnosticInfo' })\n  hi('DiagnosticSignHint',  { link='DiagnosticHint' })\n  hi('DiagnosticSignOk',    { link='DiagnosticOk' })\n\n  hi('DiagnosticDeprecated',  { fg=nil, bg=nil, sp=p.red, strikethrough=true })\n  hi('DiagnosticUnnecessary', { link='Comment' })\n\n  -- Built-in LSP\n  hi('LspReferenceText',  { fg=nil, bg=p.bg_mid2 })\n  hi('LspReferenceRead',  { link='LspReferenceText' })\n  hi('LspReferenceWrite', { link='LspReferenceText' })\n\n  hi('LspSignatureActiveParameter', { link='LspReferenceText' })\n\n  hi('LspCodeLens',          { link='Comment' })\n  hi('LspCodeLensSeparator', { link='Comment' })\n\n  -- Built-in snippets\n  hi('SnippetTabstop',       { fg=nil, bg=p.yellow_bg })\n  hi('SnippetTabstopActive', { fg=nil, bg=p.green_bg })\n\n  -- Built-in markdown syntax\n  hi('markdownH1', { link='@markup.heading.1' })\n  hi('markdownH2', { link='@markup.heading.2' })\n  hi('markdownH3', { link='@markup.heading.3' })\n  hi('markdownH4', { link='@markup.heading.4' })\n  hi('markdownH5', { link='@markup.heading.5' })\n  hi('markdownH6', { link='@markup.heading.6' })\n\n  -- Tree-sitter\n  -- Sources:\n  -- - `:h treesitter-highlight-groups`\n  -- - https://github.com/nvim-treesitter/nvim-treesitter/blob/master/CONTRIBUTING.md#highlights\n  hi('@text.literal',   { link='Special' })\n  hi('@text.reference', { link='Identifier' })\n  hi('@text.title',     { link='Title' })\n  hi('@text.uri',       { link='Underlined' })\n  hi('@text.todo',      { link='Todo' })\n  hi('@text.note',      { link='MoreMsg' })\n  hi('@text.warning',   { link='WarningMsg' })\n  hi('@text.danger',    { link='ErrorMsg' })\n  hi('@text.strong',    { fg=nil, bg=nil, bold=true          })\n  hi('@text.emphasis',  { fg=nil, bg=nil, italic=true        })\n  hi('@text.strike',    { fg=nil, bg=nil, strikethrough=true })\n  hi('@text.underline', { link='Underlined' })\n\n  hi('@comment',     { link='Comment' })\n  hi('@punctuation', { link='Delimiter' })\n\n  hi('@constant',          { link='Constant' })\n  hi('@constant.builtin',  { link='Special' })\n  hi('@constant.macro',    { link='Macro' })\n  hi('@define',            { link='Define' })\n  hi('@macro',             { link='Macro' })\n  hi('@string',            { link='String' })\n  hi('@string.escape',     { link='SpecialChar' })\n  hi('@string.special',    { link='SpecialChar' })\n  hi('@character',         { link='Character' })\n  hi('@character.special', { link='SpecialChar' })\n  hi('@number',            { link='Number' })\n  hi('@boolean',           { link='Boolean' })\n  hi('@float',             { link='Float' })\n\n  hi('@function',         { link='Function' })\n  hi('@function.builtin', { link='Special' })\n  hi('@function.call',    { link='Function' })\n  hi('@function.macro',   { link='Macro' })\n  hi('@parameter',        { fg=p.blue, bg=nil })\n  hi('@method',           { link='Function' })\n  hi('@method.call',      { link='Function' })\n  hi('@field',            { link='Identifier' })\n  hi('@property',         { link='Identifier' })\n  hi('@constructor',      { link='Special' })\n\n  hi('@conditional',    { link='Conditional' })\n  hi('@repeat',         { link='Repeat' })\n  hi('@label',          { link='Label' })\n  hi('@operator',       { link='Operator' })\n  hi('@keyword',        { link='Keyword' })\n  hi('@keyword.return', { fg=p.orange, bg=nil, bold=true })\n  hi('@exception',      { link='Exception' })\n\n  hi('@variable',         { fg=p.fg, bg=nil })\n  hi('@variable.builtin', { link='Special' })\n  hi('@type',             { link='Type' })\n  hi('@type.builtin',     { link='Special' })\n  hi('@type.definition',  { link='Typedef' })\n  hi('@storageclass',     { link='StorageClass' })\n  hi('@structure',        { link='Structure' })\n  hi('@namespace',        { link='Identifier' })\n  hi('@include',          { link='Include' })\n  hi('@preproc',          { link='PreProc' })\n  hi('@debug',            { link='Debug' })\n  hi('@tag',              { link='Tag' })\n\n  hi('@symbol', { link='Keyword' })\n  hi('@none',   {})\n\n  -- Semantic tokens. Source: `:h lsp-semantic-highlight`.\n  hi('@lsp.type.class',         { link='@structure' })\n  hi('@lsp.type.decorator',     { link='@function' })\n  hi('@lsp.type.enum',          { link='@type' })\n  hi('@lsp.type.enumMember',    { link='@constant' })\n  hi('@lsp.type.function',      { link='@function' })\n  hi('@lsp.type.interface',     { link='@type' })\n  hi('@lsp.type.macro',         { link='@macro' })\n  hi('@lsp.type.method',        { link='@method' })\n  hi('@lsp.type.namespace',     { link='@namespace' })\n  hi('@lsp.type.parameter',     { link='@parameter' })\n  hi('@lsp.type.property',      { link='@property' })\n  hi('@lsp.type.struct',        { link='@structure' })\n  hi('@lsp.type.type',          { link='@type' })\n  hi('@lsp.type.typeParameter', { link='@type.definition' })\n  hi('@lsp.type.variable',      { link='@variable' })\n\n  hi('@lsp.mod.deprecated',     { fg=p.red, bg=nil })\n\n  -- New tree-sitter groups\n  if vim.fn.has('nvim-0.10') == 1 then\n    -- Sources:\n    -- - `:h treesitter-highlight-groups`\n    -- - https://github.com/nvim-treesitter/nvim-treesitter/commit/1ae9b0e4558fe7868f8cda2db65239cfb14836d0\n    -- NOTE: commented groups are the same as in Neovim<0.10 defined earlier\n\n    -- @variable\n    -- @variable.builtin\n    hi('@variable.parameter', { link='@parameter' })\n    hi('@variable.member',    { link='@field' })\n\n    -- @constant\n    -- @constant.builtin\n    -- @constant.macro\n\n    hi('@module',         { link='@namespace' })\n    hi('@module.builtin', { link='@variable.builtin' })\n    -- @label\n\n    -- @string\n    hi('@string.documentation',  { link='@string' })\n    hi('@string.regexp',         { link='SpecialChar' })\n    -- @string.escape\n    -- @string.special\n    hi('@string.special.symbol', { link='@constant' })\n    hi('@string.special.path',   { link='Directory' })\n    hi('@string.special.url',    { link='@markup.link.url' })\n    hi('@string.special.vimdoc', { link='@constant' })\n\n    -- @character\n    -- @character.special\n\n    -- @boolean\n    -- @number\n    hi('@number.float', { link='@float' })\n\n    -- @type\n    -- @type.builtin\n    -- @type.definition\n    hi('@type.qualifier', { link='StorageClass' })\n\n    hi('@attribute', { link='Macro' })\n    -- @property\n\n    -- @function\n    -- @function.builtin\n    -- @function.call\n    -- @function.macro\n\n    hi('@function.method',      { link='@method' })\n    hi('@function.method.call', { link='@method.call' })\n\n    -- @constructor\n    -- @operator\n\n    -- @keyword\n    hi('@keyword.coroutine', { link='@keyword' })\n    hi('@keyword.function',  { link='@keyword' })\n    hi('@keyword.operator',  { link='@keyword' })\n    hi('@keyword.import',    { fg=p.blue, bg=nil, bold=true })\n    hi('@keyword.storage',   { fg=p.fg,   bg=nil, bold=true })\n    hi('@keyword.repeat',    { link='@keyword' })\n    -- @keyword.return\n    hi('@keyword.debug',     { fg=p.cyan, bg=nil, bold=true })\n    hi('@keyword.exception', { link='@keyword' })\n\n    hi('@keyword.conditional',         { link='@keyword' })\n    hi('@keyword.conditional.ternary', { link='keyword' })\n\n    hi('@keyword.directive',        { fg=p.blue, bg=nil, bold=true })\n    hi('@keyword.directive.define', { link='@keyword.directive' })\n\n    hi('@punctuation.delimiter', { link='@punctuation' })\n    hi('@punctuation.bracket',   { link='@punctuation' })\n    hi('@punctuation.special',   { link='Special' })\n\n    -- @comment\n    hi('@comment.documentation', { link='@comment' })\n\n    hi('@comment.error',   { link='@text.danger' })\n    hi('@comment.warning', { link='@text.warning' })\n    hi('@comment.todo',    { link='@text.todo' })\n    hi('@comment.note',    { link='@text.note' })\n\n    hi('@markup.strong',        { link='@text.strong' })\n    hi('@markup.italic',        { link='@text.emphasis' })\n    hi('@markup.strikethrough', { link='@text.strike' })\n    hi('@markup.underline',     { link='@text.underline' })\n\n    hi('@markup.heading',   { link='@text.title' })\n    hi('@markup.heading.1', { fg=p.orange, bg=nil })\n    hi('@markup.heading.2', { fg=p.yellow, bg=nil })\n    hi('@markup.heading.3', { fg=p.green,  bg=nil })\n    hi('@markup.heading.4', { fg=p.cyan,   bg=nil })\n    hi('@markup.heading.5', { fg=p.azure,  bg=nil })\n    hi('@markup.heading.6', { fg=p.blue,   bg=nil })\n\n    hi('@markup.heading.1.delimiter.vimdoc', { fg=p.bg_mid2, bg=nil, bold=true })\n    hi('@markup.heading.2.delimiter.vimdoc', { fg=p.bg_mid2, bg=nil, bold=true })\n    hi('@markup.heading.4.vimdoc', { link='Title' })\n\n    hi('@markup.quote',       { link='@string.special' })\n    hi('@markup.math',        { link='@string.special' })\n    hi('@markup.environment', { link='@module' })\n\n    hi('@markup.link',       { link='@text.reference' })\n    hi('@markup.link.label', { link='@markup.link' })\n    hi('@markup.link.url',   { fg=p.fg, bg=nil, underline=true })\n\n    hi('@markup.raw',       { link='@text.literal' })\n    hi('@markup.raw.block', { link='@markup.raw' })\n\n    hi('@markup.list',           { link='@punctuation.special' })\n    hi('@markup.list.checked',   { link='DiagnosticOk' })\n    hi('@markup.list.unchecked', { link='DiagnosticWarn' })\n\n    hi('@diff.plus',  { link='diffAdded' })\n    hi('@diff.minus', { link='diffRemoved' })\n    hi('@diff.delta', { link='diffChanged' })\n\n    -- @tag\n    hi('@tag.attribute', { link='@tag' })\n    hi('@tag.delimiter', { link='@punctuation' })\n  end\n\n  -- Plugins\n  -- nvim-mini/mini.nvim\n  -- TODO: Remove 'echasnovski/mini.nvim' fallback after September 2026\n  if has_integration('nvim-mini/mini.nvim') or has_integration('echasnovski/mini.nvim') then\n    hi('MiniAnimateCursor',      { fg=nil, bg=nil, reverse=true, nocombine=true })\n    hi('MiniAnimateNormalFloat', { link='NormalFloat' })\n\n    hi('MiniClueBorder',              { link='FloatBorder' })\n    hi('MiniClueDescGroup',           { link='DiagnosticFloatingWarn' })\n    hi('MiniClueDescSingle',          { link='NormalFloat' })\n    hi('MiniClueNextKey',             { link='DiagnosticFloatingHint' })\n    hi('MiniClueNextKeyWithPostkeys', { link='DiagnosticFloatingError' })\n    hi('MiniClueSeparator',           { link='DiagnosticFloatingInfo' })\n    hi('MiniClueTitle',               { link='FloatTitle' })\n\n    hi('MiniCmdlinePeekBorder', { link='FloatBorder' })\n    hi('MiniCmdlinePeekLineNr', { link='DiagnosticSignWarn' })\n    hi('MiniCmdlinePeekNormal', { link='NormalFloat' })\n    hi('MiniCmdlinePeekSep',    { link='SignColumn' })\n    hi('MiniCmdlinePeekSign',   { link='DiagnosticSignHint' })\n    hi('MiniCmdlinePeekTitle',  { link='FloatTitle' })\n\n    hi('MiniCompletionActiveParameter',    { link='LspSignatureActiveParameter' })\n    hi('MiniCompletionDeprecated',         { link='DiagnosticDeprecated' })\n    hi('MiniCompletionInfoBorderOutdated', { link='DiagnosticFloatingWarn' })\n\n    hi('MiniCursorword',        { fg=nil, bg=nil, underline=true })\n    hi('MiniCursorwordCurrent', { fg=nil, bg=nil, underline=true })\n\n    hi('MiniDepsChangeAdded',   { link='diffAdded' })\n    hi('MiniDepsChangeRemoved', { link='diffRemoved' })\n    hi('MiniDepsHint',          { link='DiagnosticHint' })\n    hi('MiniDepsInfo',          { link='DiagnosticInfo' })\n    hi('MiniDepsMsgBreaking',   { link='DiagnosticWarn' })\n    hi('MiniDepsPlaceholder',   { link='Comment' })\n    hi('MiniDepsTitle',         { link='Title' })\n    hi('MiniDepsTitleError',    { link='DiffDelete' })\n    hi('MiniDepsTitleSame',     { link='DiffText' })\n    hi('MiniDepsTitleUpdate',   { link='DiffAdd' })\n\n    hi('MiniDiffSignAdd',        { link='diffAdded' })\n    hi('MiniDiffSignChange',     { link='diffChanged' })\n    hi('MiniDiffSignDelete',     { link='diffRemoved' })\n    hi('MiniDiffOverAdd',        { link='DiffAdd' })\n    hi('MiniDiffOverChange',     { link='DiffText' })\n    hi('MiniDiffOverChangeBuf',  { link='MiniDiffOverChange' })\n    hi('MiniDiffOverContext',    { link='DiffChange' })\n    hi('MiniDiffOverContextBuf', {})\n    hi('MiniDiffOverDelete',     { link='DiffDelete' })\n\n    hi('MiniFilesBorder',         { link='FloatBorder' })\n    hi('MiniFilesBorderModified', { link='DiagnosticFloatingWarn' })\n    hi('MiniFilesCursorLine',     { link='CursorLine' })\n    hi('MiniFilesDirectory',      { link='Directory'   })\n    hi('MiniFilesFile',           { fg=p.fg, bg=nil })\n    hi('MiniFilesNormal',         { link='NormalFloat' })\n    hi('MiniFilesTitle',          { link='FloatTitle'  })\n    hi('MiniFilesTitleFocused',   { fg=p.fg, bg=p.bg_edge, bold=true })\n\n    hi('MiniHipatternsFixme', { fg=p.bg, bg=p.red,    bold=true })\n    hi('MiniHipatternsHack',  { fg=p.bg, bg=p.yellow, bold=true })\n    hi('MiniHipatternsNote',  { fg=p.bg, bg=p.cyan,   bold=true })\n    hi('MiniHipatternsTodo',  { fg=p.bg, bg=p.blue,   bold=true })\n\n    hi('MiniIconsAzure',  { fg=p.azure,   bg=nil })\n    hi('MiniIconsBlue',   { fg=p.blue,    bg=nil })\n    hi('MiniIconsCyan',   { fg=p.cyan,    bg=nil })\n    hi('MiniIconsGreen',  { fg=p.green,   bg=nil })\n    hi('MiniIconsGrey',   { fg=p.fg_edge, bg=nil })\n    hi('MiniIconsOrange', { fg=p.orange,  bg=nil })\n    hi('MiniIconsPurple', { fg=p.purple,  bg=nil })\n    hi('MiniIconsRed',    { fg=p.red,     bg=nil })\n    hi('MiniIconsYellow', { fg=p.yellow,  bg=nil })\n\n    hi('MiniIndentscopeSymbol',    { fg=p.accent, bg=nil })\n    hi('MiniIndentscopeSymbolOff', { fg=p.red,    bg=nil })\n\n    hi('MiniJump', { fg=nil, bg=nil, sp=p.accent, undercurl=true })\n\n    hi('MiniJump2dDim',        { fg=p.bg_mid2,  bg=nil })\n    hi('MiniJump2dSpot',       { fg=p.fg_edge2, bg=p.bg_edge2, bold=true, nocombine=true })\n    hi('MiniJump2dSpotAhead',  { fg=p.fg_edge,  bg=p.bg_edge2, nocombine=true })\n    hi('MiniJump2dSpotUnique', { link='MiniJump2dSpot' })\n\n    hi('MiniMapNormal',      { fg=p.fg_mid2, bg=p.bg_edge })\n    hi('MiniMapSymbolCount', { fg=p.fg_mid2, bg=nil })\n    hi('MiniMapSymbolLine',  { fg=p.accent,  bg=nil })\n    hi('MiniMapSymbolView',  { fg=p.accent,  bg=nil })\n\n    hi('MiniNotifyBorder',      { link='FloatBorder' })\n    hi('MiniNotifyLspProgress', { link='MiniNotifyNormal' })\n    hi('MiniNotifyNormal',      { link='NormalFloat' })\n    hi('MiniNotifyTitle',       { link='FloatTitle' })\n\n    hi('MiniOperatorsExchangeFrom', { link='IncSearch' })\n\n    hi('MiniPickBorder',        { link='FloatBorder' })\n    hi('MiniPickBorderBusy',    { link='DiagnosticFloatingWarn' })\n    hi('MiniPickBorderText',    { link='FloatTitle' })\n    hi('MiniPickCursor',        { blend=100, nocombine=true })\n    hi('MiniPickIconDirectory', { link='Directory' })\n    hi('MiniPickIconFile',      { link='MiniPickNormal' })\n    hi('MiniPickHeader',        { link='DiagnosticFloatingHint' })\n    hi('MiniPickMatchCurrent',  { link='CursorLine' })\n    hi('MiniPickMatchMarked',   { link='Visual' })\n    hi('MiniPickMatchRanges',   { link='DiagnosticFloatingHint' })\n    hi('MiniPickNormal',        { link='NormalFloat' })\n    hi('MiniPickPreviewLine',   { link='CursorLine' })\n    hi('MiniPickPreviewRegion', { link='IncSearch' })\n    hi('MiniPickPrompt',        { link='MiniPickMatchRanges' })\n    hi('MiniPickPromptCaret',   { link='DiagnosticFloatingInfo' })\n    hi('MiniPickPromptPrefix',  { link='DiagnosticFloatingInfo' })\n\n    hi('MiniSnippetsCurrent',        { fg=nil, bg=nil, sp=p.yellow, underdouble=true })\n    hi('MiniSnippetsCurrentReplace', { fg=nil, bg=nil, sp=p.red,    underdouble=true })\n    hi('MiniSnippetsFinal',          { fg=nil, bg=nil, sp=p.green,  underdouble=true })\n    hi('MiniSnippetsUnvisited',      { fg=nil, bg=nil, sp=p.cyan,   underdouble=true })\n    hi('MiniSnippetsVisited',        { fg=nil, bg=nil, sp=p.blue,   underdouble=true })\n\n    hi('MiniStarterCurrent',    { link='MiniStarterItem' })\n    hi('MiniStarterFooter',     { link='Comment' })\n    hi('MiniStarterHeader',     { fg=p.accent,  bg=nil, bold=true })\n    hi('MiniStarterInactive',   { link='Comment' })\n    hi('MiniStarterItem',       { link='Normal' })\n    hi('MiniStarterItemBullet', { fg=p.fg_mid2, bg=nil })\n    hi('MiniStarterItemPrefix', { fg=p.yellow,  bg=nil, bold=true })\n    hi('MiniStarterSection',    { fg=p.purple,  bg=nil })\n    hi('MiniStarterQuery',      { fg=p.green,   bg=nil, bold=true })\n\n    hi('MiniStatuslineDevinfo',     { fg=p.fg_mid, bg=p.bg_mid })\n    hi('MiniStatuslineFileinfo',    { link='MiniStatuslineDevinfo' })\n    hi('MiniStatuslineFilename',    { fg=p.fg_mid, bg=p.accent_bg })\n    hi('MiniStatuslineInactive',    { link='StatusLineNC' })\n    hi('MiniStatuslineModeCommand', { fg=p.bg,     bg=p.yellow, bold=true })\n    hi('MiniStatuslineModeInsert',  { fg=p.bg,     bg=p.azure,  bold=true })\n    hi('MiniStatuslineModeNormal',  { fg=p.bg,     bg=p.fg,     bold=true })\n    hi('MiniStatuslineModeOther',   { fg=p.bg,     bg=p.cyan,   bold=true })\n    hi('MiniStatuslineModeReplace', { fg=p.bg,     bg=p.red,    bold=true })\n    hi('MiniStatuslineModeVisual',  { fg=p.bg,     bg=p.green,  bold=true })\n\n    hi('MiniSurround', { link='IncSearch' })\n\n    hi('MiniTablineCurrent',         { fg=p.accent,  bg=p.bg,      bold=true })\n    hi('MiniTablineFill',            { link='MiniTablineHidden' })\n    hi('MiniTablineHidden',          { fg=p.fg_mid,  bg=p.bg_edge })\n    hi('MiniTablineModifiedCurrent', { fg=p.bg,      bg=p.accent,  bold=true })\n    hi('MiniTablineModifiedHidden',  { fg=p.bg_edge, bg=p.fg_mid })\n    hi('MiniTablineModifiedVisible', { fg=p.bg_edge, bg=p.fg_mid,  bold=true })\n    hi('MiniTablineTabpagesection',  { fg=p.bg,      bg=p.green,   bold=true })\n    hi('MiniTablineTrunc',           { fg=p.accent,  bg=p.bg_edge, bold=true })\n    hi('MiniTablineVisible',         { fg=p.fg_mid,  bg=p.bg_edge, bold=true })\n\n    hi('MiniTestEmphasis', { fg=nil,     bg=nil, bold=true })\n    hi('MiniTestFail',     { fg=p.red,   bg=nil, bold=true })\n    hi('MiniTestPass',     { fg=p.green, bg=nil, bold=true })\n\n    hi('MiniTrailspace', { fg=nil, bg=p.red_bg })\n  end\n\n  if has_integration('akinsho/bufferline.nvim') then\n    hi('BufferLineBuffer',              { fg=p.fg_mid2, bg=nil })\n    hi('BufferLineBufferSelected',      { fg=p.fg,      bg=nil,     bold=true })\n    hi('BufferLineBufferVisible',       { fg=p.fg,      bg=nil })\n    hi('BufferLineCloseButton',         { link='BufferLineBackground' })\n    hi('BufferLineCloseButtonSelected', { link='BufferLineBufferSelected' })\n    hi('BufferLineCloseButtonVisible',  { link='BufferLineBufferVisible' })\n    hi('BufferLineFill',                { link='Normal' })\n    hi('BufferLineTab',                 { fg=p.bg,      bg=p.green })\n    hi('BufferLineTabSelected',         { fg=p.bg,      bg=p.green, bold=true })\n  end\n\n  if has_integration('anuvyklack/hydra.nvim') then\n    hi('HydraRed',      { fg=p.red,    bg=nil })\n    hi('HydraBlue',     { fg=p.azure,  bg=nil })\n    hi('HydraAmaranth', { fg=p.purple, bg=nil })\n    hi('HydraTeal',     { fg=p.cyan,   bg=nil })\n    hi('HydraPink',     { fg=p.orange, bg=nil })\n    hi('HydraHint',     { link='NormalFloat' })\n  end\n\n  if has_integration('DanilaMihailov/beacon.nvim') then\n    hi('Beacon', { fg=nil, bg=p.fg_edge2 })\n  end\n\n  if has_integration('folke/lazy.nvim') then\n    hi('LazyButton',       { fg=nil,      bg=p.bg_mid })\n    hi('LazyButtonActive', { fg=nil,      bg=p.bg_mid2 })\n    hi('LazyDimmed',       { link='Comment' })\n    hi('LazyH1',           { fg=p.accent, bg=p.bg_mid2, bold=true })\n  end\n\n  if has_integration('folke/noice.nvim') then\n    hi('NoiceCmdlinePopupBorder', { fg=p.azure,  bg=nil })\n    hi('NoiceConfirmBorder',      { fg=p.yellow, bg=nil })\n  end\n\n  if has_integration('folke/snacks.nvim') then\n    hi('SnacksPickerBufFlags',           { link='Comment' })\n    hi('SnacksPickerDir',                { link='Comment' })\n    hi('SnacksPickerGitStatusIgnored',   { link='Comment' })\n    hi('SnacksPickerGitStatusUntracked', { link='Comment' })\n    hi('SnacksPickerKeymapRhs',          { link='Comment' })\n    hi('SnacksPickerListCursorLine',     { link='CursorLine' })\n    hi('SnacksPickerPathHidden',         { link='Comment' })\n    hi('SnacksPickerPathIgnored',        { link='Comment' })\n    hi('SnacksPickerTotals',             { link='Comment' })\n    hi('SnacksPickerUnselected',         { link='Comment' })\n  end\n\n  -- folke/trouble.nvim\n  if has_integration('folke/trouble.nvim') then\n    hi('TroubleCount',           { fg=p.accent,  bg=nil, bold=true })\n    hi('TroubleFoldIcon',        { fg=p.accent,  bg=nil, bold=true })\n    hi('TroubleIndent',          { fg=p.bg_mid2, bg=nil })\n    hi('TroubleLocation',        { fg=p.fg_mid,  bg=nil })\n    hi('TroubleSignError',       { link='DiagnosticError' })\n    hi('TroubleSignHint',        { link='DiagnosticHint' })\n    hi('TroubleSignInformation', { link='DiagnosticInfo' })\n    hi('TroubleSignOther',       { link='DiagnosticInfo' })\n    hi('TroubleSignWarning',     { link='DiagnosticWarn' })\n    hi('TroubleText',            { fg=p.fg,      bg=nil })\n    hi('TroubleTextError',       { link='TroubleText' })\n    hi('TroubleTextHint',        { link='TroubleText' })\n    hi('TroubleTextInformation', { link='TroubleText' })\n    hi('TroubleTextWarning',     { link='TroubleText' })\n  end\n\n  -- folke/todo-comments.nvim\n  -- Everything works correctly out of the box\n\n  if has_integration('folke/which-key.nvim') then\n    hi('WhichKey',          { fg=p.cyan,  bg=nil })\n    hi('WhichKeyBorder',    { link='FloatBorder' })\n    hi('WhichKeyDesc',      { fg=p.fg,    bg=nil })\n    hi('WhichKeyFloat',     { fg=p.fg,    bg=p.bg_edge })\n    hi('WhichKeyGroup',     { fg=p.red,   bg=nil })\n    hi('WhichKeySeparator', { fg=p.green, bg=nil })\n    hi('WhichKeyValue',     { link='Comment' })\n  end\n\n  if has_integration('ggandor/leap.nvim') then\n    hi('LeapMatch',          { fg=p.green,  bg=nil, bold=true, nocombine=true, underline=true })\n    hi('LeapLabel',          { fg=p.yellow, bg=nil, bold=true, nocombine=true })\n    hi('LeapLabelSelected',  { fg=p.cyan,   bg=nil, bold=true, nocombine=true })\n    hi('LeapBackdrop',       { link='Comment' })\n  end\n\n  if has_integration('glepnir/dashboard-nvim') then\n    hi('DashboardCenter',   { link='Delimiter' })\n    hi('DashboardFooter',   { link='Comment' })\n    hi('DashboardHeader',   { link='Title' })\n    hi('DashboardShortCut', { link='WarningMsg' })\n  end\n\n  if has_integration('glepnir/lspsaga.nvim') then\n    hi('LspSagaCodeActionBorder',  { fg=p.accent, bg=nil })\n    hi('LspSagaCodeActionContent', { fg=p.fg,     bg=nil })\n    hi('LspSagaCodeActionTitle',   { fg=p.azure,  bg=nil, bold=true })\n\n    hi('Definitions',            { fg=p.green,  bg=nil })\n    hi('DefinitionsIcon',        { fg=p.azure,  bg=nil })\n    hi('FinderParam',            { fg=p.yellow, bg=nil })\n    hi('FinderVirtText',         { fg=p.orange, bg=nil })\n    hi('LspSagaAutoPreview',     { fg=p.blue,   bg=nil })\n    hi('LspSagaFinderSelection', { fg=p.cyan,   bg=nil })\n    hi('LspSagaLspFinderBorder', { fg=p.accent, bg=nil })\n    hi('References',             { fg=p.green,  bg=nil })\n    hi('ReferencesIcon',         { fg=p.azure,  bg=nil })\n    hi('TargetFileName',         { fg=p.fg,     bg=nil })\n\n    hi('FinderSpinner',       { fg=p.green,  bg=nil })\n    hi('FinderSpinnerBorder', { fg=p.accent, bg=nil })\n    hi('FinderSpinnerTitle',  { link='Title' })\n\n    hi('LspSagaDefPreviewBorder', { fg=p.accent, bg=nil })\n\n    hi('LspSagaHoverBorder', { fg=p.accent, bg=nil })\n\n    hi('LspSagaRenameBorder', { fg=p.accent, bg=nil })\n\n    hi('LspSagaDiagnosticBorder', { fg=p.accent, bg=nil })\n    hi('LspSagaDiagnosticHeader', { link='Title' })\n    hi('LspSagaDiagnosticSource', { fg=p.orange, bg=nil })\n\n    hi('LspSagaBorderTitle', { link='FloatTitle' })\n\n    hi('LspSagaSignatureHelpBorder', { fg=p.accent, bg=nil })\n\n    hi('LSOutlinePreviewBorder', { fg=p.accent,  bg=nil })\n    hi('OutlineDetail',          { fg=p.bg_mid2, bg=nil })\n    hi('OutlineFoldPrefix',      { fg=p.yellow,  bg=nil })\n    hi('OutlineIndentEvn',       { fg=p.fg_mid2, bg=nil })\n    hi('OutlineIndentOdd',       { fg=p.fg,      bg=nil })\n  end\n\n  if has_integration('HiPhish/rainbow-delimiters.nvim') then\n    hi('RainbowDelimiterBlue',   { fg=p.azure,  bg=nil })\n    hi('RainbowDelimiterCyan',   { fg=p.cyan,   bg=nil })\n    hi('RainbowDelimiterGreen',  { fg=p.green,  bg=nil })\n    hi('RainbowDelimiterOrange', { fg=p.orange, bg=nil })\n    hi('RainbowDelimiterRed',    { fg=p.red,    bg=nil })\n    hi('RainbowDelimiterViolet', { fg=p.purple, bg=nil })\n    hi('RainbowDelimiterYellow', { fg=p.yellow, bg=nil })\n  end\n\n  if has_integration('hrsh7th/nvim-cmp') then\n    hi('CmpItemAbbr',           { fg=p.fg, bg=nil })\n    hi('CmpItemAbbrDeprecated', { link='Comment' })\n    hi('CmpItemAbbrMatch',      { fg=nil,  bg=nil, bold=true })\n    hi('CmpItemAbbrMatchFuzzy', { fg=nil,  bg=nil, bold=true })\n    hi('CmpItemKind',           { fg=p.fg, bg=nil })\n    hi('CmpItemMenu',           { fg=p.fg, bg=nil })\n\n    hi('CmpItemKindClass',         { link='Type' })\n    hi('CmpItemKindColor',         { link='Special' })\n    hi('CmpItemKindConstant',      { link='Constant' })\n    hi('CmpItemKindConstructor',   { link='Type' })\n    hi('CmpItemKindEnum',          { link='Structure' })\n    hi('CmpItemKindEnumMember',    { link='Structure' })\n    hi('CmpItemKindEvent',         { link='Exception' })\n    hi('CmpItemKindField',         { link='Structure' })\n    hi('CmpItemKindFile',          { link='Tag' })\n    hi('CmpItemKindFolder',        { link='Directory' })\n    hi('CmpItemKindFunction',      { link='Function' })\n    hi('CmpItemKindInterface',     { link='Structure' })\n    hi('CmpItemKindKeyword',       { link='Keyword' })\n    hi('CmpItemKindMethod',        { link='Function' })\n    hi('CmpItemKindModule',        { link='Structure' })\n    hi('CmpItemKindOperator',      { link='Operator' })\n    hi('CmpItemKindProperty',      { link='Structure' })\n    hi('CmpItemKindReference',     { link='Tag' })\n    hi('CmpItemKindSnippet',       { link='Special' })\n    hi('CmpItemKindStruct',        { link='Structure' })\n    hi('CmpItemKindText',          { link='Normal' })\n    hi('CmpItemKindTypeParameter', { link='Type' })\n    hi('CmpItemKindUnit',          { link='Special' })\n    hi('CmpItemKindValue',         { link='Identifier' })\n    hi('CmpItemKindVariable',      { link='Delimiter' })\n  end\n\n  if has_integration('ibhagwan/fzf-lua') then\n    hi('FzfLuaBufFlagAlt', { link='Special' })\n    hi('FzfLuaBufFlagCur', { link='CursorLineNr' })\n    hi('FzfLuaBufNr',      { link='DiagnosticHint' })\n    hi('FzfLuaHeaderBind', { link='DiagnosticWarn' })\n    hi('FzfLuaHeaderText', { link='DiagnosticInfo' })\n    hi('FzfLuaLiveSym',    { link='DiagnosticHint' })\n    hi('FzfLuaPathColNr',  { link='DiagnosticHint' })\n    hi('FzfLuaPathLineNr', { link='DiagnosticInfo' })\n    hi('FzfLuaTabMarker',  { link='DiagnosticHint' })\n    hi('FzfLuaTabTitle',   { link='Title' })\n    hi('FzfLuaTitle',      { link='FloatTitle' })\n  end\n\n  if has_integration('justinmk/vim-sneak') then\n    hi('Sneak',      { fg=p.bg, bg=p.orange })\n    hi('SneakScope', { fg=p.bg, bg=p.fg_edge2 })\n    hi('SneakLabel', { fg=p.bg, bg=p.orange, bold=true })\n  end\n\n  -- 'kevinhwang91/nvim-bqf'\n  if has_integration('kevinhwang91/nvim-bqf') then\n    hi('BqfPreviewFloat', { link='NormalFloat' })\n    hi('BqfPreviewTitle', { link='FloatTitle' })\n    hi('BqfSign',         { fg=p.cyan })\n  end\n\n  -- 'kevinhwang91/nvim-ufo'\n  -- Everything works correctly out of the box\n\n  if has_integration('lewis6991/gitsigns.nvim') then\n    hi('GitSignsAdd',             { fg=p.green,  bg=nil })\n    hi('GitSignsAddLn',           { link='GitSignsAdd' })\n    hi('GitSignsAddInline',       { link='GitSignsAdd' })\n\n    hi('GitSignsChange',          { fg=p.yellow, bg=nil })\n    hi('GitSignsChangeLn',        { link='GitSignsChange' })\n    hi('GitSignsChangeInline',    { link='GitSignsChange' })\n\n    hi('GitSignsDelete',          { fg=p.red,    bg=nil })\n    hi('GitSignsDeleteLn',        { link='GitSignsDelete' })\n    hi('GitSignsDeleteInline',    { link='GitSignsDelete' })\n\n    hi('GitSignsUntracked',       { fg=p.azure,  bg=nil })\n    hi('GitSignsUntrackedLn',     { link='GitSignsUntracked' })\n    hi('GitSignsUntrackedInline', { link='GitSignsUntracked' })\n  end\n\n  if has_integration('lukas-reineke/indent-blankline.nvim') then\n    hi('IndentBlanklineChar',         { fg=p.bg_mid2, bg=nil, nocombine=true })\n    hi('IndentBlanklineContextChar',  { fg=p.accent,  bg=nil, nocombine=true })\n    hi('IndentBlanklineContextStart', { fg=nil,       bg=nil, sp=p.accent, underline=true, nocombine=true })\n    hi('IndentBlanklineIndent1',      { fg=p.blue,    bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent2',      { fg=p.cyan,    bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent3',      { fg=p.yellow,  bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent4',      { fg=p.red,     bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent5',      { fg=p.azure,   bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent6',      { fg=p.green,   bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent7',      { fg=p.orange,  bg=nil, nocombine=true })\n    hi('IndentBlanklineIndent8',      { fg=p.purple,  bg=nil, nocombine=true })\n  end\n\n  if has_integration('MeanderingProgrammer/render-markdown.nvim') then\n    hi('RenderMarkdownBullet',     { fg=p.accent, bg=nil })\n    hi('RenderMarkdownChecked',    { link='DiagnosticOk' })\n    hi('RenderMarkdownCode',       { fg=nil,      bg=p.bg_edge })\n    hi('RenderMarkdownCodeInline', { fg=nil,      bg=p.bg_edge })\n    hi('RenderMarkdownDash',       { fg=p.accent, bg=nil })\n    hi('RenderMarkdownH1',         { fg=p.orange, bg=nil })\n    hi('RenderMarkdownH1Bg',       { fg=nil,      bg=p.orange_bg })\n    hi('RenderMarkdownH2',         { fg=p.yellow, bg=nil })\n    hi('RenderMarkdownH2Bg',       { fg=nil,      bg=p.yellow_bg })\n    hi('RenderMarkdownH3',         { fg=p.green,  bg=nil })\n    hi('RenderMarkdownH3Bg',       { fg=nil,      bg=p.green_bg })\n    hi('RenderMarkdownH4',         { fg=p.cyan,   bg=nil })\n    hi('RenderMarkdownH4Bg',       { fg=nil,      bg=p.cyan_bg })\n    hi('RenderMarkdownH5',         { fg=p.azure,  bg=nil })\n    hi('RenderMarkdownH5Bg',       { fg=nil,      bg=p.azure_bg })\n    hi('RenderMarkdownH6',         { fg=p.blue,   bg=nil })\n    hi('RenderMarkdownH6Bg',       { fg=nil,      bg=p.blue_bg })\n    hi('RenderMarkdownTodo',       { link='Todo' })\n    hi('RenderMarkdownUnchecked',  { link='DiagnosticWarn' })\n  end\n\n  if has_integration('neoclide/coc.nvim') then\n    hi('CocCodeLens',             { link='LspCodeLens' })\n    hi('CocDisabled',             { link='Comment' })\n    hi('CocFadeOut',              { link='Comment' })\n    hi('CocMarkdownLink',         { fg=p.blue,   bg=nil })\n    hi('CocMenuSel',              { fg=nil,      bg=p.bg_mid2 })\n    hi('CocNotificationProgress', { link='CocMarkdownLink' })\n    hi('CocPumVirtualText',       { link='CocMarkdownLink' })\n    hi('CocSearch',               { fg=p.blue,   bg=nil })\n    hi('CocSelectedText',         { fg=p.yellow, bg=nil })\n  end\n\n  -- NeogitOrg/neogit\n  if has_integration('NeogitOrg/neogit') then\n    hi('NeogitCommitViewHeader',    { link='Special' })\n    hi('NeogitDiffAddHighlight',    { link='DiffAdd' })\n    hi('NeogitDiffAdd',             { link='DiffAdd' })\n    hi('NeogitDiffDeleteHighlight', { link='DiffDelete' })\n    hi('NeogitDiffDelete',          { link='DiffDelete' })\n    hi('NeogitFold',                { link='FoldColumn' })\n    hi('NeogitHunkHeader',          { fg=p.accent, bg=nil })\n    hi('NeogitHunkHeaderHighlight', { fg=p.accent, bg=nil, bold=true })\n    hi('NeogitNotificationError',   { link='DiagnosticError' })\n    hi('NeogitNotificationInfo',    { link='DiagnosticInfo' })\n    hi('NeogitNotificationWarning', { link='DiagnosticWarn' })\n  end\n\n  -- nvim-lualine/lualine.nvim\n  -- Everything works correctly out of the box\n\n  if has_integration('nvim-neo-tree/neo-tree.nvim') then\n    hi('NeoTreeDimText',              { fg=p.bg_mid2, bg=nil })\n    hi('NeoTreeDotfile',              { fg=p.fg_mid,  bg=nil })\n    hi('NeoTreeFadeText1',            { link='NeoTreeDimText' })\n    hi('NeoTreeFadeText2',            { fg=p.bg_mid2, bg=nil })\n    hi('NeoTreeGitAdded',             { fg=p.green,   bg=nil })\n    hi('NeoTreeGitConflict',          { fg=p.orange,  bg=nil, bold=true })\n    hi('NeoTreeGitDeleted',           { fg=p.red,     bg=nil })\n    hi('NeoTreeGitModified',          { fg=p.yellow,  bg=nil })\n    hi('NeoTreeGitUnstaged',          { fg=p.purple,  bg=nil })\n    hi('NeoTreeGitUntracked',         { fg=p.cyan,    bg=nil })\n    hi('NeoTreeMessage',              { fg=p.fg,      bg=p.bg_mid })\n    hi('NeoTreeModified',             { fg=p.fg_edge, bg=nil })\n    hi('NeoTreeRootName',             { fg=p.accent,  bg=nil, bold=true })\n    hi('NeoTreeTabInactive',          { fg=p.fg_mid2, bg=nil })\n    hi('NeoTreeTabSeparatorActive',   { fg=p.fg_mid2, bg=p.bg_mid2 })\n    hi('NeoTreeTabSeparatorInactive', { fg=p.bg_mid,  bg=p.bg_mid })\n  end\n\n  if has_integration('nvim-telescope/telescope.nvim') then\n    hi('TelescopeBorder',         { fg=p.accent, bg=nil })\n    hi('TelescopeMatching',       { fg=nil,      bg=nil, bold=true })\n    hi('TelescopeMultiSelection', { fg=nil,      bg=p.bg_mid2 })\n    hi('TelescopeSelection',      { fg=nil,      bg=p.bg_mid })\n  end\n\n  if has_integration('nvim-tree/nvim-tree.lua') then\n    hi('NvimTreeExecFile',     { fg=p.green,   bg=nil,       bold=true })\n    hi('NvimTreeFolderIcon',   { fg=p.fg_mid2, bg=nil })\n    hi('NvimTreeGitDeleted',   { fg=p.red,     bg=nil })\n    hi('NvimTreeGitDirty',     { fg=p.yellow,  bg=nil })\n    hi('NvimTreeGitMerge',     { fg=p.orange,  bg=nil })\n    hi('NvimTreeGitNew',       { fg=p.cyan,    bg=nil })\n    hi('NvimTreeGitRenamed',   { fg=p.purple,  bg=nil })\n    hi('NvimTreeGitStaged',    { fg=p.green,   bg=nil })\n    hi('NvimTreeImageFile',    { fg=p.orange,  bg=nil })\n    hi('NvimTreeIndentMarker', { link='NvimTreeFolderIcon' })\n    hi('NvimTreeOpenedFile',   { link='NvimTreeExecFile' })\n    hi('NvimTreeRootFolder',   { fg=p.accent,  bg=nil,       bold=true })\n    hi('NvimTreeSpecialFile',  { fg=p.accent,  bg=nil,       underline=true })\n    hi('NvimTreeSymlink',      { fg=p.blue,    bg=nil,       bold=true })\n    hi('NvimTreeWindowPicker', { fg=p.fg,      bg=p.bg_mid2, bold=true })\n  end\n\n  if has_integration('OXY2DEV/helpview.nvim') then\n    hi('HelpviewCode',         { fg=nil,      bg=p.bg_edge })\n    hi('HelpviewCodeLanguage', { fg=nil,      bg=p.bg_edge })\n    hi('HelpviewHeading1',     { link='@markup.heading.1' })\n    hi('HelpviewHeading2',     { link='@markup.heading.2' })\n    hi('HelpviewHeading3',     { link='@markup.heading.3' })\n    hi('HelpviewHeading4',     { link='@markup.heading.4' })\n    hi('HelpviewInlineCode',   { fg=nil,      bg=p.bg_edge })\n    hi('HelpviewMentionlink',  { fg=p.accent, bg=nil,      underline=true })\n    hi('HelpviewOptionlink',   { fg=p.yellow, bg=nil,      underline=true })\n    hi('HelpviewTaglink',      { fg=p.accent, bg=nil,      bold=true })\n    hi('HelpviewTitle',        { link='Title' })\n  end\n\n  if has_integration('OXY2DEV/markview.nvim') then\n    hi('MarkviewPalette0',     { fg=p.accent, bg=p.accent_bg })\n    hi('MarkviewPalette0Fg',   { fg=p.accent, bg=nil })\n    hi('MarkviewPalette0Bg',   { fg=nil,      bg=p.accent_bg })\n    hi('MarkviewPalette0Sign', { fg=p.accent, bg=nil })\n    hi('MarkviewPalette1',     { fg=p.red,    bg=p.red_bg })\n    hi('MarkviewPalette1Fg',   { fg=p.red,    bg=nil })\n    hi('MarkviewPalette1Bg',   { fg=nil,      bg=p.red_bg })\n    hi('MarkviewPalette1Sign', { fg=p.red,    bg=nil })\n    hi('MarkviewPalette2',     { fg=p.orange, bg=p.orange_bg })\n    hi('MarkviewPalette2Fg',   { fg=p.orange, bg=nil })\n    hi('MarkviewPalette2Bg',   { fg=nil,      bg=p.orange_bg })\n    hi('MarkviewPalette2Sign', { fg=p.orange, bg=nil })\n    hi('MarkviewPalette3',     { fg=p.yellow, bg=p.yellow_bg })\n    hi('MarkviewPalette3Fg',   { fg=p.yellow, bg=nil })\n    hi('MarkviewPalette3Bg',   { fg=nil,      bg=p.yellow_bg })\n    hi('MarkviewPalette3Sign', { fg=p.yellow, bg=nil })\n    hi('MarkviewPalette4',     { fg=p.green,  bg=p.green_bg })\n    hi('MarkviewPalette4Fg',   { fg=p.green,  bg=nil })\n    hi('MarkviewPalette4Bg',   { fg=nil,      bg=p.green_bg })\n    hi('MarkviewPalette4Sign', { fg=p.green,  bg=nil })\n    hi('MarkviewPalette5',     { fg=p.cyan,   bg=p.cyan_bg })\n    hi('MarkviewPalette5Fg',   { fg=p.cyan,   bg=nil })\n    hi('MarkviewPalette5Bg',   { fg=nil,      bg=p.cyan_bg })\n    hi('MarkviewPalette5Sign', { fg=p.cyan,   bg=nil })\n    hi('MarkviewPalette6',     { fg=p.azure,  bg=p.azure_bg })\n    hi('MarkviewPalette6Fg',   { fg=p.azure,  bg=nil })\n    hi('MarkviewPalette6Bg',   { fg=nil,      bg=p.azure_bg })\n    hi('MarkviewPalette6Sign', { fg=p.azure,  bg=nil })\n    hi('MarkviewPalette7',     { fg=p.blue,   bg=p.blue_bg })\n    hi('MarkviewPalette7Fg',   { fg=p.blue,   bg=nil })\n    hi('MarkviewPalette7Bg',   { fg=nil,      bg=p.blue_bg })\n    hi('MarkviewPalette7Sign', { fg=p.blue,   bg=nil })\n  end\n\n  if has_integration('phaazon/hop.nvim') then\n    hi('HopNextKey',   { fg=p.green,   bg=nil, bold=true, nocombine=true })\n    hi('HopNextKey1',  { fg=p.orange,  bg=nil, bold=true, nocombine=true })\n    hi('HopNextKey2',  { fg=p.fg_mid,  bg=nil, bold=true, nocombine=true })\n    hi('HopPreview',   { fg=p.yellow,  bg=nil, bold=true, nocombine=true })\n    hi('HopUnmatched', { fg=p.bg_mid2, bg=nil })\n  end\n\n  if has_integration('rcarriga/nvim-dap-ui') then\n    hi('DapUIScope',                   { link='Title' })\n    hi('DapUIType',                    { link='Type' })\n    hi('DapUIModifiedValue',           { fg=p.orange, bg=nil, bold=true })\n    hi('DapUIDecoration',              { link='Title' })\n    hi('DapUIThread',                  { link='String' })\n    hi('DapUIStoppedThread',           { link='Title' })\n    hi('DapUISource',                  { link='Directory' })\n    hi('DapUILineNumber',              { link='Title' })\n    hi('DapUIFloatBorder',             { link='SpecialChar' })\n    hi('DapUIWatchesEmpty',            { link='ErrorMsg' })\n    hi('DapUIWatchesValue',            { link='String' })\n    hi('DapUIWatchesError',            { link='DiagnosticError' })\n    hi('DapUIBreakpointsPath',         { link='Directory' })\n    hi('DapUIBreakpointsInfo',         { link='DiagnosticInfo' })\n    hi('DapUIBreakpointsCurrentLine',  { fg=p.green,  bg=nil, bold=true })\n    hi('DapUIBreakpointsDisabledLine', { link='Comment' })\n  end\n\n  if has_integration('rcarriga/nvim-notify') then\n    hi('NotifyDEBUGBorder', { fg=p.green,  bg=nil })\n    hi('NotifyDEBUGIcon',   { link='NotifyDEBUGBorder' })\n    hi('NotifyDEBUGTitle',  { link='NotifyDEBUGBorder' })\n    hi('NotifyERRORBorder', { fg=p.red,    bg=nil })\n    hi('NotifyERRORIcon',   { link='NotifyERRORBorder' })\n    hi('NotifyERRORTitle',  { link='NotifyERRORBorder' })\n    hi('NotifyINFOBorder',  { fg=p.blue,   bg=nil })\n    hi('NotifyINFOIcon',    { link='NotifyINFOBorder' })\n    hi('NotifyINFOTitle',   { link='NotifyINFOBorder' })\n    hi('NotifyTRACEBorder', { fg=p.cyan,   bg=nil })\n    hi('NotifyTRACEIcon',   { link='NotifyTRACEBorder' })\n    hi('NotifyTRACETitle',  { link='NotifyTRACEBorder' })\n    hi('NotifyWARNBorder',  { fg=p.yellow, bg=nil })\n    hi('NotifyWARNIcon',    { link='NotifyWARNBorder' })\n    hi('NotifyWARNTitle',   { link='NotifyWARNBorder' })\n  end\n\n  if has_integration('rlane/pounce.nvim') then\n    hi('PounceMatch',      { fg=p.bg, bg=p.fg,      bold=true, nocombine=true })\n    hi('PounceGap',        { fg=p.bg, bg=p.bg_mid2, bold=true, nocombine=true })\n    hi('PounceAccept',     { fg=p.bg, bg=p.yellow,  bold=true, nocombine=true })\n    hi('PounceAcceptBest', { fg=p.bg, bg=p.green,   bold=true, nocombine=true })\n  end\n\n  if has_integration('romgrk/barbar.nvim') then\n    hi('BufferCurrent',        { fg=p.accent, bg=p.bg,      bold=true })\n    hi('BufferCurrentIcon',    { fg=nil,      bg=p.bg })\n    hi('BufferCurrentIndex',   { link='BufferCurrentIcon' })\n    hi('BufferCurrentMod',     { fg=p.accent, bg=p.bg_mid,  bold=true })\n    hi('BufferCurrentSign',    { link='BufferCurrent' })\n    hi('BufferCurrentTarget',  { fg=p.accent, bg=p.bg_mid2, bold=true })\n\n    hi('BufferInactive',       { fg=p.fg,     bg=p.bg_edge })\n    hi('BufferInactiveIcon',   { fg=nil,      bg=p.bg_edge })\n    hi('BufferInactiveIndex',  { link='BufferInactiveIcon' })\n    hi('BufferInactiveMod',    { fg=p.fg,     bg=p.bg_mid })\n    hi('BufferInactiveSign',   { link='BufferInactive' })\n    hi('BufferInactiveTarget', { fg=p.fg,     bg=p.bg_mid2 })\n\n    hi('BufferOffset',         { link='Normal' })\n    hi('BufferTabpages',       { fg=p.bg,     bg=p.green,   bold=true })\n    hi('BufferTabpageFill',    { link='Normal' })\n\n    hi('BufferVisible',        { fg=p.fg,     bg=p.bg,      bold=true })\n    hi('BufferVisibleIcon',    { fg=nil,      bg=p.bg })\n    hi('BufferVisibleIndex',   { link='BufferVisibleIcon' })\n    hi('BufferVisibleMod',     { fg=p.fg,     bg=p.bg_mid,  bold=true })\n    hi('BufferVisibleSign',    { link='BufferVisible' })\n    hi('BufferVisibleTarget',  { fg=p.fg,     bg=p.bg_mid2, bold=true })\n  end\n\n  -- stevearc/aerial.nvim\n  -- Everything works correctly out of the box\n\n  if has_integration('williamboman/mason.nvim') then\n    hi('MasonError',                       { fg=p.red,    bg=nil })\n    hi('MasonHeader',                      { fg=p.bg,     bg=p.azure,   bold=true })\n    hi('MasonHeaderSecondary',             { fg=p.bg,     bg=p.blue,    bold=true })\n    hi('MasonHeading',                     { link='Bold' })\n    hi('MasonHighlight',                   { fg=p.accent, bg=nil })\n    hi('MasonHighlightBlock',              { fg=p.bg,     bg=p.accent })\n    hi('MasonHighlightBlockBold',          { link='MasonHeaderSecondary' })\n    hi('MasonHighlightBlockBoldSecondary', { link='MasonHeader' })\n    hi('MasonHighlightBlockSecondary',     { fg=p.bg,     bg=p.azure })\n    hi('MasonHighlightSecondary',          { fg=p.azure,  bg=nil })\n    hi('MasonLink',                        { link='MasonHighlight' })\n    hi('MasonMuted',                       { link='Comment' })\n    hi('MasonMutedBlock',                  { fg=p.bg,     bg=p.bg_mid2 })\n    hi('MasonMutedBlockBold',              { fg=p.bg,     bg=p.bg_mid2, bold=true })\n  end\n\n  -- Terminal colors\n  local is_bg_dark = H.hex2oklch(p.bg).l < H.hex2oklch(p.fg).l\n  local black = is_bg_dark and 'bg' or 'fg'\n  local white = is_bg_dark and 'fg' or 'bg'\n  vim.g.terminal_color_0  = p[black .. '_edge2']\n  vim.g.terminal_color_1  = p.red\n  vim.g.terminal_color_2  = p.green\n  vim.g.terminal_color_3  = p.yellow\n  vim.g.terminal_color_4  = p.azure\n  vim.g.terminal_color_5  = p.purple\n  vim.g.terminal_color_6  = p.cyan\n  vim.g.terminal_color_7  = p[white .. '_mid2']\n  vim.g.terminal_color_8  = p[black .. '_mid2']\n  vim.g.terminal_color_9  = p.red\n  vim.g.terminal_color_10 = p.green\n  vim.g.terminal_color_11 = p.yellow\n  vim.g.terminal_color_12 = p.azure\n  vim.g.terminal_color_13 = p.purple\n  vim.g.terminal_color_14 = p.cyan\n  vim.g.terminal_color_15 = p[white .. '_edge2']\nend\n\n--- Get latest applied palette\n---\n---@return table Table with structure as |MiniHues.make_palette()| output that was\n---   the latest applied (via |MiniHues.apply_palette()|) palette.\nMiniHues.get_palette = function() return vim.deepcopy(H.palette) end\n\n--- Generate random base colors\n---\n--- Compute background and foreground colors based on randomly generated hue\n--- and heuristically picked lightness-chroma values.\n---\n--- You can recreate a similar functionality but tweaked to your taste\n--- using |mini.colors|: >\n---\n---   local convert = require('mini.colors').convert\n---   local hue = math.random(0, 359)\n---   return {\n---     background = convert({ l = 15, c = 3, h = hue }, 'hex'),\n---     foreground = convert({ l = 80, c = 1, h = hue }, 'hex'),\n---   }\n---\n--- Notes:\n--- - Respects 'background' (uses different lightness and chroma values for\n---   \"dark\" and \"light\" backgrounds).\n---\n--- - When used during startup, might require usage of `math.randomseed()` for\n---   proper random generation. For example: >\n---\n---   local hues = require('mini.hues')\n---   math.randomseed(vim.loop.hrtime())\n---   hues.setup(hues.gen_random_base_colors())\n---\n---@param opts table|nil Options. Possible values:\n---   - <gen_hue> `(function)` - callable which will return single number for\n---     output hue. Can be used to limit which hues will be generated.\n---     Default: random integer between 0 and 359.\n---\n---@return table Table with <background> and <foreground> fields containing\n---   color hex strings.\nMiniHues.gen_random_base_colors = function(opts)\n  opts = opts or {}\n  local gen_hue = opts.gen_hue or function() return math.random(0, 359) end\n  if not vim.is_callable(gen_hue) then H.error('`gen_hue` should be callable.') end\n\n  local is_dark = vim.o.background == 'dark'\n  local bg_l = is_dark and 15 or 90\n  local fg_l = is_dark and 80 or 20\n  local bg_c = is_dark and 3 or 1\n\n  local hue = gen_hue() % 360\n  --stylua: ignore\n  return {\n    background = H.oklch2hex({ l = bg_l, c = bg_c, h = hue }),\n    foreground = H.oklch2hex({ l = fg_l, c = 1,    h = hue }),\n  }\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniHues.config)\n\n-- Color conversion constants\nH.tau = 2 * math.pi\n\nH.saturation_values = { 'low', 'lowmedium', 'medium', 'mediumhigh', 'high' }\n\nH.accent_values = { 'bg', 'fg', 'red', 'orange', 'yellow', 'green', 'cyan', 'azure', 'blue', 'purple' }\n\n-- Cusps for Oklch color space. See 'mini.colors' for more details.\n--stylua: ignore start\n---@diagnostic disable\n---@private\nH.cusps = {\n  [0] = {26.23,64.74},\n  {26.14,64.65},{26.06,64.56},{25.98,64.48},{25.91,64.39},{25.82,64.29},{25.76,64.21},{25.70,64.13},{25.65,64.06},\n  {25.59,63.97},{25.55,63.90},{25.52,63.83},{25.48,63.77},{25.45,63.69},{25.43,63.63},{25.41,63.55},{25.40,63.50},\n  {25.39,63.43},{25.40,63.33},{25.40,63.27},{25.42,63.22},{25.44,63.15},{25.46,63.11},{25.50,63.05},{25.53,63.00},\n  {25.58,62.95},{25.63,62.90},{25.69,62.85},{25.75,62.81},{25.77,62.80},{25.34,63.25},{24.84,63.79},{24.37,64.32},\n  {23.92,64.83},{23.48,65.35},{23.08,65.85},{22.65,66.38},{22.28,66.86},{21.98,67.27},{21.67,67.70},{21.36,68.14},\n  {21.05,68.60},{20.74,69.08},{20.50,69.45},{20.27,69.83},{20.04,70.22},{19.82,70.62},{19.60,71.03},{19.38,71.44},\n  {19.17,71.87},{19.03,72.16},{18.83,72.59},{18.71,72.89},{18.52,73.34},{18.40,73.64},{18.28,73.95},{18.17,74.26},\n  {18.01,74.74},{17.91,75.05},{17.82,75.38},{17.72,75.70},{17.64,76.03},{17.56,76.36},{17.48,76.69},{17.41,77.03},\n  {17.35,77.36},{17.29,77.71},{17.24,78.05},{17.19,78.39},{17.15,78.74},{17.12,79.09},{17.09,79.45},{17.07,79.80},\n  {17.05,80.16},{17.04,80.52},{17.04,81.06},{17.04,81.42},{17.05,81.79},{17.07,82.16},{17.08,82.53},{17.11,82.72},\n  {17.14,83.09},{17.18,83.46},{17.22,83.84},{17.27,84.22},{17.33,84.60},{17.39,84.98},{17.48,85.56},{17.56,85.94},\n  {17.64,86.33},{17.73,86.72},{17.81,87.10},{17.91,87.50},{18.04,88.09},{18.16,88.48},{18.27,88.88},{18.40,89.48},\n  {18.57,89.87},{18.69,90.27},{18.88,90.87},{19.03,91.48},{19.22,91.88},{19.44,92.49},{19.66,93.10},{19.85,93.71},\n  {20.04,94.33},{20.33,94.94},{20.60,95.56},{20.85,96.18},{21.10,96.80},{21.19,96.48},{21.27,96.24},{21.38,95.93},\n  {21.47,95.70},{21.59,95.40},{21.72,95.10},{21.86,94.80},{21.97,94.58},{22.12,94.30},{22.27,94.02},{22.43,93.74},\n  {22.64,93.40},{22.81,93.14},{23.04,92.81},{23.22,92.56},{23.45,92.25},{23.68,91.95},{23.92,91.65},{24.21,91.31},\n  {24.45,91.04},{24.74,90.72},{25.08,90.36},{25.37,90.07},{25.70,89.74},{26.08,89.39},{26.44,89.07},{26.87,88.69},\n  {27.27,88.34},{27.72,87.98},{28.19,87.61},{28.68,87.23},{29.21,86.84},{29.48,86.64},{28.99,86.70},{28.13,86.81},\n  {27.28,86.92},{26.56,87.02},{25.83,87.12},{25.18,87.22},{24.57,87.32},{24.01,87.41},{23.53,87.49},{23.03,87.58},\n  {22.53,87.68},{22.10,87.76},{21.68,87.84},{21.26,87.93},{20.92,88.01},{20.58,88.08},{20.25,88.16},{19.92,88.24},\n  {19.59,88.33},{19.35,88.39},{19.12,88.46},{18.81,88.55},{18.58,88.61},{18.36,88.68},{18.14,88.76},{17.93,88.83},\n  {17.79,88.88},{17.59,88.95},{17.39,89.03},{17.26,89.08},{17.08,89.16},{16.96,89.21},{16.79,89.29},{16.68,89.35},\n  {16.58,89.41},{16.43,89.49},{16.33,89.55},{16.24,89.60},{16.16,89.66},{16.04,89.75},{15.96,89.81},{15.89,89.87},\n  {15.83,89.93},{15.77,89.99},{15.71,90.05},{15.66,90.12},{15.61,90.18},{15.57,90.24},{15.54,90.31},{15.51,90.37},\n  {15.48,90.44},{15.46,90.51},{15.40,90.30},{15.30,89.83},{15.21,89.36},{15.12,88.89},{15.03,88.67},{14.99,88.18},\n  {14.92,87.71},{14.85,87.24},{14.78,86.77},{14.75,86.53},{14.70,86.06},{14.65,85.59},{14.61,85.12},{14.60,84.89},\n  {14.57,84.42},{14.54,83.94},{14.53,83.71},{14.52,83.24},{14.51,82.77},{14.52,82.30},{14.52,81.83},{14.53,81.60},\n  {14.55,81.13},{14.58,80.66},{14.59,80.43},{14.63,79.96},{14.68,79.49},{14.70,79.26},{14.76,78.79},{14.82,78.32},\n  {14.85,78.09},{14.93,77.62},{15.01,77.16},{15.10,76.69},{15.19,76.23},{15.24,76.00},{15.34,75.54},{15.45,75.07},\n  {15.57,74.61},{15.69,74.15},{15.82,73.69},{15.96,73.23},{16.10,72.77},{16.24,72.31},{16.39,71.86},{16.55,71.40},\n  {16.71,70.95},{16.96,70.26},{17.14,69.81},{17.32,69.36},{17.59,68.69},{17.88,68.02},{18.07,67.57},{18.37,66.90},\n  {18.67,66.24},{18.99,65.58},{19.30,64.93},{19.74,64.06},{20.07,63.42},{20.51,62.57},{20.97,61.73},{21.54,60.69},\n  {22.00,59.87},{22.70,58.66},{23.39,57.49},{24.19,56.16},{25.20,54.52},{26.38,52.66},{28.55,49.32},{31.32,45.20},\n  {31.15,45.42},{30.99,45.64},{30.85,45.85},{30.72,46.06},{30.57,46.31},{30.47,46.50},{30.34,46.75},{30.23,46.97},\n  {30.13,47.20},{30.03,47.45},{29.93,47.71},{29.86,47.91},{29.77,48.20},{29.71,48.43},{29.65,48.66},{29.58,48.98},\n  {29.53,49.23},{29.48,49.48},{29.44,49.74},{29.41,50.01},{29.37,50.29},{29.35,50.57},{29.33,50.86},{29.31,51.16},\n  {29.30,51.56},{29.29,51.87},{29.29,52.39},{29.30,52.72},{29.31,53.05},{29.33,53.38},{29.35,53.72},{29.37,54.06},\n  {29.40,54.41},{29.43,54.76},{29.47,55.12},{29.52,55.60},{29.56,55.97},{29.61,56.34},{29.66,56.72},{29.73,57.22},\n  {29.79,57.61},{29.84,57.99},{29.93,58.52},{29.99,58.91},{30.08,59.44},{30.15,59.84},{30.24,60.38},{30.34,60.93},\n  {30.42,61.34},{30.52,61.90},{30.63,62.45},{30.73,63.02},{30.85,63.58},{30.96,64.15},{31.08,64.72},{31.19,65.30},\n  {31.31,65.88},{31.44,66.46},{31.59,67.20},{31.72,67.79},{31.88,68.53},{32.01,69.12},{32.18,69.87},{32.25,70.17},\n  {32.06,69.99},{31.76,69.70},{31.45,69.42},{31.21,69.20},{30.97,68.98},{30.68,68.71},{30.44,68.50},{30.21,68.29},\n  {29.98,68.09},{29.75,67.89},{29.53,67.69},{29.31,67.50},{29.09,67.31},{28.88,67.12},{28.72,66.98},{28.52,66.80},\n  {28.31,66.63},{28.16,66.50},{27.97,66.33},{27.78,66.17},{27.64,66.05},{27.49,65.94},{27.33,65.77},{27.20,65.66},\n  {27.04,65.51},{26.92,65.40},{26.81,65.30},{26.66,65.16},{26.55,65.06},{26.45,64.96},{26.35,64.87},\n}\n--stylua: ignore end\n\n-- Latest applied palette\nH.palette = nil\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  if config.background == nil or config.foreground == nil then\n    H.error('`setup()` needs both `background` and `foreground`.')\n  end\n\n  H.validate_hex(config.background, 'background')\n  H.validate_hex(config.foreground, 'foreground')\n  H.validate_n_hues(config.n_hues)\n  if not vim.tbl_contains(H.saturation_values, config.saturation) then\n    H.error('`saturation` should be one of ' .. table.concat(vim.tbl_map(vim.inspect, H.saturation_values), ', '))\n  end\n  if not vim.tbl_contains(H.accent_values, config.accent) then\n    H.error('`accent` should be one of ' .. table.concat(vim.tbl_map(vim.inspect, H.accent_values), ', '))\n  end\n  H.check_type('plugins', config.plugins, 'table')\n  H.check_type('autoadjust', config.autoadjust, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniHues.config = config\n\n  -- Apply palette\n  local opts = { autoadjust = config.autoadjust }\n  MiniHues.apply_palette(MiniHues.make_palette(config), config.plugins, opts)\nend\n\n-- Palette --------------------------------------------------------------------\nH.make_hues = function(bg_h, fg_h, n_hues)\n  local res = { bg = bg_h, fg = fg_h }\n  if n_hues == 0 then return res end\n\n  -- Generate equidistant circular grid of hues which is the most distant from\n  -- background and foreground hues. Distance between two sets is assumed as\n  -- minimum distance between all pairs of points.\n  local period = 360 / n_hues\n  local half_period = 0.5 * period\n\n  -- - Compute delta which determines the furthest grid\n  local d\n  if bg_h == nil and fg_h == nil then d = 0 end\n  if bg_h ~= nil and fg_h == nil then d = (bg_h % period + half_period) % period end\n  if bg_h == nil and fg_h ~= nil then d = (fg_h % period + half_period) % period end\n  if bg_h ~= nil and fg_h ~= nil then\n    local ref_bg, ref_fg = bg_h % period, fg_h % period\n    local mid = 0.5 * (ref_bg + ref_fg)\n    local mid_alt = (mid + half_period) % period\n\n    d = H.dist_period(mid, ref_bg, period) < H.dist_period(mid_alt, ref_bg, period) and mid_alt or mid\n  end\n\n  local grid = {}\n  for i = 0, n_hues - 1 do\n    table.insert(grid, i * period + d)\n  end\n\n  -- Normalize equidistant grid to be base 8 colors\n  local dist_fun = function(x, y) return H.dist_period(x, y, 360) end\n  local approx = function(ref_hue) return H.get_closest(ref_hue, grid, dist_fun) end\n\n  --stylua: ignore start\n  res.red    = approx(0)\n  res.orange = approx(45)\n  res.yellow = approx(90)\n  res.green  = approx(135)\n  res.cyan   = approx(180)\n  res.azure  = approx(225)\n  res.blue   = approx(270)\n  res.purple = approx(315)\n  --stylua: ignore end\n\n  return res\nend\n\nH.validate_hex = function(x, name)\n  if type(x) == 'string' and x:find('^#%x%x%x%x%x%x$') ~= nil then return x end\n  local msg = string.format('`%s` should be hex color string in the form \"#rrggbb\", not %s', name, vim.inspect(x))\n  H.error(msg)\nend\n\nH.validate_n_hues = function(x)\n  if type(x) == 'number' and 0 <= x and x <= 8 then return x end\n  local msg = string.format('`n_hues` should be a number between 0 and 8', name)\n  H.error(msg)\nend\n\nH.validate_one_of = function(x, choices, name)\n  if vim.tbl_contains(choices, x) then return x end\n  local choices_string = table.concat(vim.tbl_map(vim.inspect, choices), ', ')\n  local msg = string.format('`%s` should be one of %s', name, choices_string)\n  H.error(msg)\nend\n\n-- Color conversion -----------------------------------------------------------\nH.hex2oklch = function(hex) return H.oklab2oklch(H.rgb2oklab(H.hex2rgb(hex))) end\n\nH.oklch2hex = function(lch) return H.rgb2hex(H.oklab2rgb(H.oklch2oklab(H.clip_to_gamut(lch)))) end\n\n-- HEX <-> RGB in [0; 255]\nH.hex2rgb = function(hex)\n  local dec = tonumber(hex:sub(2), 16)\n\n  local b = math.fmod(dec, 256)\n  local g = math.fmod((dec - b) / 256, 256)\n  local r = math.floor(dec / 65536)\n\n  return { r = r, g = g, b = b }\nend\n\nH.rgb2hex = function(rgb)\n  -- Use straightforward clipping to [0; 255] here to ensure correctness.\n  -- Modify `rgb` prior to this to ensure only a small distortion.\n  local r = H.clip(H.round(rgb.r), 0, 255)\n  local g = H.clip(H.round(rgb.g), 0, 255)\n  local b = H.clip(H.round(rgb.b), 0, 255)\n\n  return string.format('#%02x%02x%02x', r, g, b)\nend\n\n-- RGB in [0; 255] <-> Oklab\n-- https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab\nH.rgb2oklab = function(rgb)\n  -- Convert to linear RGB\n  local r, g, b = H.correct_channel(rgb.r / 255), H.correct_channel(rgb.g / 255), H.correct_channel(rgb.b / 255)\n\n  -- Convert to Oklab\n  local l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b\n  local m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b\n  local s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b\n\n  local l_, m_, s_ = H.cuberoot(l), H.cuberoot(m), H.cuberoot(s)\n\n  local L = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_\n  local A = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_\n  local B = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_\n\n  -- Explicitly convert to gray for nearly achromatic colors\n  if math.abs(A) < 1e-4 then A = 0 end\n  if math.abs(B) < 1e-4 then B = 0 end\n\n  -- Normalize to appropriate range\n  return { l = H.correct_lightness(100 * L), a = 100 * A, b = 100 * B }\nend\n\nH.oklab2rgb = function(lab)\n  local L, A, B = 0.01 * H.correct_lightness_inv(lab.l), 0.01 * lab.a, 0.01 * lab.b\n\n  local l_ = L + 0.3963377774 * A + 0.2158037573 * B\n  local m_ = L - 0.1055613458 * A - 0.0638541728 * B\n  local s_ = L - 0.0894841775 * A - 1.2914855480 * B\n\n  local l = l_ * l_ * l_\n  local m = m_ * m_ * m_\n  local s = s_ * s_ * s_\n\n  --stylua: ignore\n  local r =  4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s\n  local g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s\n  local b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s\n\n  return { r = 255 * H.correct_channel_inv(r), g = 255 * H.correct_channel_inv(g), b = 255 * H.correct_channel_inv(b) }\nend\n\n-- Oklab <-> Oklch\nH.oklab2oklch = function(lab)\n  local c = math.sqrt(lab.a ^ 2 + lab.b ^ 2)\n  -- Treat grays specially\n  local h = nil\n  if c > 0 then h = H.rad2degree(math.atan2(lab.b, lab.a)) end\n  return { l = lab.l, c = c, h = h }\nend\n\nH.oklch2oklab = function(lch)\n  -- Treat grays specially\n  if lch.c <= 0 or lch.h == nil then return { l = lch.l, a = 0, b = 0 } end\n\n  local a = lch.c * math.cos(H.degree2rad(lch.h))\n  local b = lch.c * math.sin(H.degree2rad(lch.h))\n  return { l = lch.l, a = a, b = b }\nend\n\n-- Degree in [0; 360] <-> Radian in [0; 2*pi]\nH.rad2degree = function(x) return (x % H.tau) * 360 / H.tau end\n\nH.degree2rad = function(x) return (x % 360) * H.tau / 360 end\n\n-- Functions for RGB channel correction. Assumes input in [0; 1] range\n-- https://bottosson.github.io/posts/colorwrong/#what-can-we-do%3F\nH.correct_channel = function(x) return 0.04045 < x and math.pow((x + 0.055) / 1.055, 2.4) or (x / 12.92) end\n\nH.correct_channel_inv = function(x)\n  return (0.0031308 >= x) and (12.92 * x) or (1.055 * math.pow(x, 0.416666667) - 0.055)\nend\n\n-- Functions for lightness correction\n-- https://bottosson.github.io/posts/colorpicker/#intermission---a-new-lightness-estimate-for-oklab\nH.correct_lightness = function(x)\n  x = 0.01 * x\n  local k1, k2 = 0.206, 0.03\n  local k3 = (1 + k1) / (1 + k2)\n\n  local res = 0.5 * (k3 * x - k1 + math.sqrt((k3 * x - k1) ^ 2 + 4 * k2 * k3 * x))\n  return 100 * res\nend\n\nH.correct_lightness_inv = function(x)\n  x = 0.01 * x\n  local k1, k2 = 0.206, 0.03\n  local k3 = (1 + k1) / (1 + k2)\n  local res = (x / k3) * (x + k1) / (x + k2)\n  return 100 * res\nend\n\n-- Get gamut ranges for Lch point. More info in 'mini.colors'.\nH.get_gamut_points = function(lch)\n  local c, l = lch.c, H.clip(lch.l, 0, 100)\n  l = H.correct_lightness_inv(l)\n  local cusp = H.cusps[math.floor(lch.h % 360)]\n  local c_cusp, l_cusp = cusp[1], cusp[2]\n\n  -- Maximum allowed chroma. Used for computing saturation.\n  local c_upper = l <= l_cusp and (c_cusp * l / l_cusp) or (c_cusp * (100 - l) / (100 - l_cusp))\n  c_upper = H.clip(c_upper, 0, math.huge)\n\n  -- Other points can be computed only in presence of actual chroma\n  if c == nil then return { c_upper = c_upper } end\n\n  -- Intersection of segment between (c, l) and (0, l_cusp) with gamut boundary\n  -- Used for gamut clipping\n  local c_cusp_clip, l_cusp_clip\n  if c <= 0 then\n    c_cusp_clip, l_cusp_clip = c, l\n  elseif l <= l_cusp then\n    -- Intersection with lower segment\n    local prop = 1 - l / l_cusp\n    c_cusp_clip = c_cusp * c / (c_cusp * prop + c)\n    l_cusp_clip = l_cusp * c_cusp_clip / c_cusp\n  else\n    -- Intersection with upper segment\n    local prop = 1 - (l - 100) / (l_cusp - 100)\n    c_cusp_clip = c_cusp * c / (c_cusp * prop + c)\n    l_cusp_clip = 100 + c_cusp_clip * (l_cusp - 100) / c_cusp\n  end\n\n  return {\n    c_upper = c_upper,\n    l_cusp_clip = H.correct_lightness(l_cusp_clip),\n    c_cusp_clip = c_cusp_clip,\n  }\nend\n\nH.clip_to_gamut = function(lch)\n  local res = vim.deepcopy(lch)\n\n  -- Gray is always in gamut\n  if res.h == nil then return res end\n\n  local gamut_points = H.get_gamut_points(lch)\n\n  local is_inside_gamut = lch.c <= gamut_points.c_upper\n  if is_inside_gamut then return res end\n\n  -- Clip by going towards (0, l_cusp) until in gamut\n  res.l, res.c = gamut_points.l_cusp_clip, gamut_points.c_cusp_clip\n\n  return res\nend\n\n-- Auto adjusting -------------------------------------------------------------\nH.setup_autoadjust = function(palette)\n  local gr = vim.api.nvim_create_augroup('MiniHuesAdjust', {})\n  local hi = function(name, data) vim.api.nvim_set_hl(0, name, data) end\n  local adjust = function(ev)\n    local adjust_all = ev.event == 'VimEnter'\n    if adjust_all or ev.match == 'fillchars' then hi('MsgSeparator', H.attr_msgseparator(palette, true)) end\n    if adjust_all or ev.match == 'pumborder' then hi('Pmenu', H.attr_pmenu(palette, true)) end\n  end\n\n  -- Use single autocommand without pattern for performance (skips Neovim doing\n  -- pattern matching on the option name). Use 'VimEnter' to work when option\n  -- is set during startup, as 'OptionSet' is not triggered.\n  local au_opts = { group = gr, callback = adjust, desc = 'Autoadjust highlight groups' }\n  vim.api.nvim_create_autocmd({ 'VimEnter', 'OptionSet' }, au_opts)\nend\n\nH.attr_msgseparator = function(p, autoadjust)\n  if not autoadjust then return { fg = p.accent, bg = p.bg_mid } end\n  return vim.o.fillchars:find('msgsep:%S') ~= nil and { fg = p.accent } or { bg = p.bg_mid }\nend\n\nH.attr_pmenu = function(p, autoadjust)\n  local is_pumborder = vim.fn.exists('+pumborder') == 1 and not (vim.o.pumborder == '' or vim.o.pumborder == 'none')\n  return (autoadjust and is_pumborder) and { link = 'NormalFloat' } or { fg = p.fg, bg = p.bg_mid }\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.hues) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.round = function(x)\n  if x == nil then return nil end\n  return math.floor(x + 0.5)\nend\n\nH.clip = function(x, from, to) return math.min(math.max(x, from), to) end\n\nH.cuberoot = function(x) return math.pow(x, 0.333333) end\n\nH.dist_period = function(x, y, period)\n  period = period or 360\n  local d = math.abs((x % period) - (y % period))\n  return math.min(d, period - d)\nend\n\nH.get_closest = function(x, values, dist_fun)\n  local best_val, best_key, best_dist = nil, nil, math.huge\n  for key, val in pairs(values) do\n    local cur_dist = dist_fun(x, val)\n    if cur_dist <= best_dist then\n      best_val, best_key, best_dist = val, key, cur_dist\n    end\n  end\n\n  return best_val, best_key\nend\n\nreturn MiniHues\n"
  },
  {
    "path": "lua/mini/icons.lua",
    "content": "--- *mini.icons* Icon provider\n---\n--- MIT License Copyright (c) 2024 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Provide icons with their highlighting via a single |MiniIcons.get()| for\n---   various categories: filetype, file/directory path, extension, operating\n---   system, LSP kind values. Icons and category defaults can be overridden.\n---\n--- - Configurable styles: \"glyph\" (icon glyphs) or \"ascii\" (non-glyph fallback).\n---\n--- - Fixed set of highlight groups (linked to built-in groups by default) for\n---   better blend with color scheme.\n---\n--- - Caching for maximum performance.\n---\n--- - Integration with |vim.filetype.add()| and |vim.filetype.match()|.\n---\n--- - Mocking methods of 'nvim-tree/nvim-web-devicons' for better integrations\n---   with plugins outside 'mini.nvim'. See |MiniIcons.mock_nvim_web_devicons()|.\n---\n--- - Tweaking built-in maps for \"LSP kind\" to include icons. In particular, this\n---   makes |mini.completion| use icons in LSP step. See |MiniIcons.tweak_lsp_kind()|.\n---\n--- Notes:\n---\n--- - It is not a goal to become a collection of icons for as much use cases as\n---   possible. There are specific criteria for icon data to be included as\n---   built-in in each category (see |MiniIcons.get()|).\n---   The main supported category is \"filetype\".\n---\n--- Recommendations for plugin authors using 'mini.icons' as a dependency:\n---\n--- - Check if `_G.MiniIcons` table is present (which means that user explicitly\n---   enabled 'mini.icons') and provide icons only if it is.\n---\n--- - Use |MiniIcons.get()| function to get icon string and more data about it.\n---\n--- - For file icons prefer using full path instead of relative or only basename.\n---   It makes a difference if path matches pattern that uses parent directories.\n---   The |MiniIcons.config| has an example of that.\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies:\n---\n--- - Terminal emulator that supports showing special utf8 glyphs, possibly with\n---   \"overflow\" view (displaying is done not in one but two visual cells).\n---   Most modern feature-rich terminal emulators support this out of the box:\n---   WezTerm, Kitty, Alacritty, iTerm2, Ghostty.\n---   Not having \"overflow\" feature only results into smaller icons.\n---   Not having support for special utf8 glyphs will result into seemingly\n---   random symbols (or question mark squares) instead of icon glyphs.\n---\n--- - Font that supports Nerd Fonts (https://www.nerdfonts.com) icons from\n---   version 3.0.0+ (in particular `nf-md-*` class).\n---   This should be configured on terminal emulator level either by using font\n---   patched with Nerd Fonts icons or using `NerdFontsSymbolsOnly` font as\n---   a fallback for glyphs that are not supported in main font.\n---\n--- If using terminal emulator and/or font with icon support is impossible, use\n--- `config.style = 'ascii'`. It will use a (less visually appealing) set of\n--- non-glyph icons.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.icons').setup({})` (replace `{}`\n--- with your `config` table). It will create global Lua table `MiniIcons` which you\n--- can use for scripting or manually (with `:lua MiniIcons.*`).\n---\n--- See |MiniIcons.config| for `config` structure and default values.\n---\n--- # Comparisons ~\n---\n--- - [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) (for users):\n---     - Sets individual colors to each icon with separate specific highlight\n---       groups, while this modules uses fixed set of highlight groups.\n---       This makes it easier to customize in bulk and actually blend with any\n---       color scheme.\n---\n---     - This module prefers richer set of `nf-md-*` (from \"Material design\" set)\n---       Nerd Fonts icons while 'nvim-web-devicons' mostly prefers `nf-dev-*`\n---       (from \"devicons\" set).\n---\n---     - Supported categories are slightly different (with much overlap).\n---\n---     - Both support customization of any icon. Only this module supports\n---       customization of default ones per supported category.\n---\n---     - Using this module can occasionally result in small delays when used\n---       synchronously for many times to get icons for not typical files (like\n---       in |mini.files|). This is due to using |vim.filetype.match()| fallback and\n---       is present only during first call, as value is cached for later uses.\n---\n---     - This module supports different icon styles (like \"ascii\" for when using\n---       glyphs is not possible), while 'nvim-web-devicons' does not.\n---\n---     - This module provides |MiniIcons.mock_nvim_web_devicons()| function which\n---       when called imitates installed 'nvim-web-devicons' plugin to support\n---       other plugins which do not provide 'mini.icons' yet.\n---\n--- - [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) (for plugin developers):\n---     - Both have main \"get icon\" type of function:\n---         - Both return tuple of icon and highlight group strings.\n---\n---         - This module always returns icon data possibly falling back to\n---           user's configured default, while 'nvim-web-devicons' is able to\n---           return `nil`. This module's approach is more aligned with the most\n---           common use case of always showing an icon instead or near some data.\n---           There is a third returned value indicating if output is a result of\n---           a fallback (see |MiniIcons.get()|).\n---\n---         - This module uses |vim.filetype.match()| as a fallback for \"file\"\n---           and \"extension\" categories, while 'nvim-web-devicons' completely\n---           relies on the manually maintained tables of supported filenames\n---           and extensions.\n---           Using fallback results in a wider support and deeper integration\n---           with Neovim's filetype detection at the cost of occasional slower\n---           first call. The difference is reduced as much as is reasonable by\n---           preferring faster file extension resolution over filetype matching.\n---\n---         - This module caches all its return values resulting in really fast\n---           next same argument calls, while 'nvim-web-devicons' doesn't do that.\n---\n---         - This module works with full file/directory paths as input.\n---\n---     - Different sets of supported categories (see |MiniIcons.config|):\n---         - Both support \"file\", \"extension\", \"filetype\", \"operating system\".\n---           Albeit in different volumes: 'nvim-web-devicons' covers more\n---           cases for \"operating system\", while this module has better eventual\n---           coverage for other cases.\n---\n---         - This module supports \"directory\" and \"lsp\" categories.\n---\n---         - 'nvim-web-devicons' covers \"desktop environment\" and \"window\n---           management\" categories. This modules does not include them due to\n---           relatively low demand.\n---\n--- - [onsails/lspkind.nvim](https://github.com/onsails/lspkind.nvim):\n---     - Provides icons only for `CompletionItemKind`, while this module also has\n---       icons for `SymbolKind` and other non-LSP categories.\n---     - Provides dedicated formatting function for 'hrsh7th/nvim-cmp' while this\n---       module intentionally does not (adding icons should be straightforward\n---       to manually implement while anything else is out of scope).\n---\n--- # Highlight groups ~\n---\n--- Only the following set of highlight groups is used as icon highlight.\n--- It is recommended that they all only define colored foreground:\n---\n--- - `MiniIconsAzure`  - azure.\n--- - `MiniIconsBlue`   - blue.\n--- - `MiniIconsCyan`   - cyan.\n--- - `MiniIconsGreen`  - green.\n--- - `MiniIconsGrey`   - grey.\n--- - `MiniIconsOrange` - orange.\n--- - `MiniIconsPurple` - purple.\n--- - `MiniIconsRed`    - red.\n--- - `MiniIconsYellow` - yellow.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---@tag MiniIcons\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n-- Module definition ==========================================================\nlocal MiniIcons = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniIcons.config|.\n---\n---@usage >lua\n---   require('mini.icons').setup() -- use default config\n---   -- OR\n---   require('mini.icons').setup({}) -- replace {} with your config table\n--- <\nMiniIcons.setup = function(config)\n  -- Export module\n  _G.MiniIcons = MiniIcons\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Style ~\n---\n--- `config.style` is a string defining which icon style to use. It can be:\n--- - `'glyph'` (default) - use glyph icons (like 󰈔 and 󰉋 ).\n--- - `'ascii'` - use fallback ASCII-compatible icons. Those are computed as\n---   an upper first character of the icon's resolved name inside its category.\n---   Examples: >lua\n---\n---     MiniIcons.get('file', 'Makefile') -- Has `'M'` as icon\n---     MiniIcons.get('extension', 'lua') -- Has `'L'` as icon\n---     MiniIcons.get('file', 'file.lua') -- Has `'L'` as icon; it is resolved to\n---                                       -- come from 'lua' 'extension' category\n---     MiniIcons.get('file', 'myfile')   -- Has `'F'` as icon; it is resolved to\n---                                       -- come from 'file' 'default' category\n--- <\n--- # Customization per category ~\n---\n--- The following entries can be used to customize icons for supported categories:\n--- - `config.default`\n--- - `config.directory`\n--- - `config.extension`\n--- - `config.file`\n--- - `config.filetype`\n--- - `config.lsp`\n--- - `config.os`\n---\n--- Customization should be done by supplying a table with <glyph> (icon glyph)\n--- and/or <hl> (name of highlight group) string fields as a value for an icon\n--- name entry. Example: >lua\n---\n---   require('mini.icons').setup({\n---     default = {\n---       -- Override default glyph for \"file\" category (reuse highlight group)\n---       file = { glyph = '󰈤' },\n---     },\n---     extension = {\n---       -- Override highlight group (not necessary from 'mini.icons')\n---       lua = { hl = 'Special' },\n---\n---       -- Add icons for custom extension. This will also be used in\n---       -- 'file' category for input like 'file.my.ext'.\n---       ['my.ext'] = { glyph = '󰻲', hl = 'MiniIconsRed' },\n---     },\n---   })\n--- <\n--- Notes:\n--- - These customizations only take effect inside |MiniIcons.setup()| call.\n---   Changing interactively via `:lua MiniIcons.config.xxx = { ... }` does not work\n---   for performance reasons.\n--- - Use lower case names for categories which are matched ignoring case.\n---   See |MiniIcons.get()| for more details.\n---\n--- # Using extension during file resolution ~\n---\n--- `config.use_file_extension` is a function which can be used to control which\n--- extensions will be considered as a source of icon data during \"file\" category\n--- resolution (see |MiniIcons.get()| for more details).\n--- Default: function which always returns `true` (i.e. consider all extensions).\n---\n--- Will be called once for the biggest suffix after dot found in the file name.\n--- The arguments will be `ext` (found extension; lowercase) and `file` (input for\n--- which icon is computed; as is). Should explicitly return `true` if `ext` is to\n--- be considered (i.e. call `MiniIcons.get('extension', ext)` and use its\n--- output if it is not default). Otherwise extension won't be even considered.\n---\n--- The primary use case for this setting is to ensure that some extensions are\n--- ignored in order for resolution to reach |vim.filetype.match()| stage. This\n--- is needed if there is a set up filetype detection for files with recognizable\n--- extension and conflicting icons (which you want to use). Note: if problematic\n--- filetype detection involves only known in advance file names, prefer using\n--- `config.file` customization.\n---\n--- Example: >lua\n---\n---   -- Built-in filetype detection recognizes files like \"queries/.*%.scm\"\n---   -- as \"query\" filetype. However, without special setup, 'mini.icons' will\n---   -- use \"scm\" extension to resolve as Scheme file. Here is a setup to ignore\n---   -- \"scm\" extension and completely rely on `vim.filetype.match()` fallback.\n---   require('mini.icons').setup({\n---     -- Check last letters explicitly to account for dots in file name\n---     use_file_extension = function(ext) return ext:sub(-3) ~= 'scm' end\n---   })\n---\n---   -- Another common choices for extensions to ignore: \"yml\", \"json\", \"txt\".\n--- <\nMiniIcons.config = {\n  -- Icon style: 'glyph' or 'ascii'\n  style = 'glyph',\n\n  -- Customize per category. See `:h MiniIcons.config` for details.\n  default   = {},\n  directory = {},\n  extension = {},\n  file      = {},\n  filetype  = {},\n  lsp       = {},\n  os        = {},\n\n  -- Control which extensions will be considered during \"file\" resolution\n  use_file_extension = function(ext, file) return true end,\n}\n--minidoc_afterlines_end\n\n--- Get icon data\n---\n--- Usage example: >lua\n---\n---   -- Results into `icon='󰢱'`, `hl='MiniIconsAzure'`, `is_default=false`\n---   local icon, hl, is_default = MiniIcons.get('file', 'file.lua')\n--- <\n--- Notes:\n--- - Always returns some data, even if icon name is not explicitly supported\n---   within target category. Category \"default\" is used as a fallback. Use third\n---   output value to check if this particular case is a result of a fallback.\n---\n--- - Glyphs are explicitly preferred (when reasonable) from a richer set of\n---   `nf-md-*` class  (\"Material design\" set) of Nerd Fonts icons.\n---\n--- - Output is cached after the first call to increase performance of next calls\n---   with same arguments. To reset cache, call |MiniIcons.setup()|.\n---\n--- - To increase first call performance for \"extension\" and \"file\" categories,\n---   add frequently used values in |MiniIcons.config|. They will be preferred\n---   over executing |vim.filetype.match()|.\n---\n--- - Matching icon name for \"file\" and \"directory\" categories is done exactly\n---   and respecting case. Others are done ignoring case.\n---\n---@param category string Category name. Supported categories:\n---   - `'default'` - icon data used as fallback for any category.\n---     Icon names:\n---       - <Input>: any supported category name.\n---       - <Built-in>: only supported category names.\n---\n---     Examples: >lua\n---\n---       MiniIcons.get('default', 'file')\n--- <\n---   - `'directory'` - icon data for directory path.\n---     Icon names:\n---       - <Input>: any string, but only basename is used. Works with not present\n---         paths (no check is done).\n---       - <Built-in>: popular directory names not tied to language/software\n---         (with few notable exceptions like Neovim, Git, etc.).\n---\n---     Examples: >lua\n---\n---       -- All of these will result in the same output\n---       MiniIcons.get('directory', '.config')\n---       MiniIcons.get('directory', '~/.config')\n---       MiniIcons.get('directory', '/home/user/.config')\n---\n---       -- Results in different output\n---       MiniIcons.get('directory', '.Config')\n--- <\n---   - `'extension'` - icon data for extension.\n---     Icon names:\n---       - <Input>: any string (without extra dot prefix).\n---       - <Built-in>: popular extensions without associated filetype plus a set\n---         for which filetype detection gives not good enough result.\n---\n---     Icon data is attempted to be resolved in the following order:\n---       - List of user configured and built-in extensions (for better results).\n---         Run `:=MiniIcons.list('extension')` to see them.\n---         Used also if present as suffix after the dot (widest one preferred).\n---       - Filetype as a result of |vim.filetype.match()| with placeholder\n---         file name. Uses icon data from \"filetype\" category.\n---\n---     Examples: >lua\n---\n---       -- All of these will result in the same output\n---       MiniIcons.get('extension', 'lua')\n---       MiniIcons.get('extension', 'LUA')\n---       MiniIcons.get('extension', 'my.lua')\n--- <\n---   - `'file'` - icon data for file path.\n---     Icon names:\n---       - <Input>: any string. Works with not present paths (no check is done).\n---       - <Built-in>: popular file names not tied to language/software\n---         (with few notable exceptions like Neovim, Git, etc.) plus a set which\n---         has recognizable extension but has special detectable filetype.\n---\n---     Icon data is attempted to be resolved in the following order:\n---       - List of user configured and built-in file names (matched to basename\n---         of the input exactly). Run `:=MiniIcons.list('file')` to see them.\n---       - Basename extension:\n---           - Matched directly as `get('extension', ext)`, where `ext` is the\n---             widest suffix after the dot.\n---           - Considered only if `config.use_file_extension` returned `true`.\n---           - Only recognizable extensions (i.e. not default fallback) are used.\n---       - Filetype as a result of |vim.filetype.match()| with full input (not\n---         basename) as `filename`. Uses icon data from \"filetype\" category.\n---\n---     Examples: >lua\n---\n---       -- All of these will result in the same output\n---       MiniIcons.get('file', 'init.lua')\n---       MiniIcons.get('file', '~/.config/nvim/init.lua')\n---       MiniIcons.get('file', '/home/user/.config/nvim/init.lua')\n---\n---       -- Results in different output\n---       MiniIcons.get('file', 'Init.lua')\n---       MiniIcons.get('file', 'init.LUA')\n---\n---       -- Respects full path input in `vim.filetype.match()`\n---       MiniIcons.get('file', '.git/info/attributes')\n--- <\n---   - `'filetype'` - icon data for 'filetype' values.\n---     Icon names:\n---       - <Input>: any string.\n---       - <Built-in>: any filetype that is reasonably used in Neovim ecosystem.\n---         This category is intended as a widest net for supporting use cases.\n---         Users are encouraged to have a specific filetype detection set up.\n---\n---     Examples: >lua\n---\n---       MiniIcons.get('filetype', 'lua')\n---       MiniIcons.get('filetype', 'help')\n---       MiniIcons.get('filetype', 'minifiles')\n--- <\n---   - `'lsp'` - icon data for various \"LSP kind\" values.\n---     Icon names:\n---       - <Input>: any string.\n---       - <Built-in>: only namesspace entries from LSP specification that are\n---         can be displayed to user. Like `CompletionItemKind`, `SymbolKind`, etc.\n---\n---     Examples: >lua\n---\n---       MiniIcons.get('lsp', 'array')\n---       MiniIcons.get('lsp', 'keyword')\n--- <\n---   - `'os'` - icon data for popular operating systems.\n---     Icon names:\n---       - <Input>: any string.\n---       - <Built-in>: only operating systems which have `nf-md-*` class icon.\n---\n---     Examples: >lua\n---\n---       MiniIcons.get('os', 'linux')\n---       MiniIcons.get('os', 'arch')\n---       MiniIcons.get('os', 'macos')\n--- <\n---@param name string Icon name within category. Use |MiniIcons.list()| to get icon\n---   names which are explicitly supported for specific category.\n---\n---@return ... Tuple of icon string, highlight group name it is suggested to be\n---   highlighted with, and boolean indicating whether this icon was returned\n---   as a result of fallback to default. Example: >lua\n---\n---   -- Results into `icon='󰢱'`, `hl='MiniIconsAzure'`, `is_default=false`\n---   local icon, hl, is_default = MiniIcons.get('file', 'file.lua')\n---\n---   -- Results into `icon='󰈔'`, `hl='MiniIconsGrey'`, `is_default=true`\n---   local icon, hl, is_default = MiniIcons.get('file', 'not-supported')\n--- <\nMiniIcons.get = function(category, name)\n  if not (type(category) == 'string' and type(name) == 'string') then\n    H.error('Both `category` and `name` should be string.')\n  end\n\n  -- Get \"get\" implementation now to show informative message for bad category\n  local getter = H.get_impl[category]\n  if getter == nil then H.error(vim.inspect(category) .. ' is not a supported category.') end\n\n  -- Try cache first\n  name = category == 'file' and name or (category == 'directory' and H.fs_basename(name) or name:lower())\n  local cached = H.cache_get(category, name)\n  if cached ~= nil then return cached[1], cached[2], cached[3] == true end\n\n  -- Get icon. Assume `nil` value to mean \"fall back to category default\".\n  local icon, hl = getter(name)\n  if type(icon) == 'table' then\n    icon, hl = H.style_icon(icon.glyph, name), icon.hl\n  end\n\n  -- Save to cache and return\n  return H.cache_set(category, name, icon, hl)\nend\n\n--- List explicitly supported icon names\n---\n---@param category string Category name supported by |MiniIcons.get()|.\n---\n---@return table Array of icon names which are explicitly supported for category.\n---   Note, that `'file'` and `'extension'` categories support much more icon names\n---   via their fallback to using |vim.filetype.match()| with `'filetype'` category.\nMiniIcons.list = function(category)\n  local category_icons = H[category .. '_icons']\n  if category_icons == nil then H.error(vim.inspect(category) .. ' is not a supported category.') end\n\n  -- Output is a union of explicit built-in and custom icons\n  local res_map = {}\n  for k, _ in pairs(category_icons) do\n    res_map[k] = true\n  end\n  for k, _ in pairs(MiniIcons.config[category]) do\n    res_map[k] = true\n  end\n\n  local res = vim.tbl_keys(res_map)\n  table.sort(res)\n  return res\nend\n\n--- Mock 'nvim-web-devicons' module\n---\n--- Call this function to mock exported functions of 'nvim-tree/nvim-web-devicons'\n--- plugin. It will mock all its functions which return icon data by\n--- using |MiniIcons.get()| equivalent.\n---\n--- This function is useful if any plugins relevant to you depend solely on\n--- 'nvim-web-devicons' and have not yet added an integration with 'mini.icons'.\n---\n--- Full example of usage: >lua\n---\n---   require('mini.icons').setup()\n---   MiniIcons.mock_nvim_web_devicons()\n--- <\n--- Works without installed 'nvim-web-devicons' and even with it installed (needs\n--- to be called after 'nvim-web-devicons' is set up).\nMiniIcons.mock_nvim_web_devicons = function()\n  local M = {}\n\n  -- Main functions which get icon and highlight group\n  M.get_icon = function(name, ext, opts)\n    -- Preferring 'name' first leads to a slightly different behavior compared to\n    -- the original in case both `name` and `ext` is supplied:\n    -- - Original: try exact `name`, then `ext`, then extensions in `name`.\n    -- - This: use 'file' category and ignore `ext` completely.\n    -- In practice this seems like a better choice because it accounts for\n    -- special file names at the cost of ignoring `ext` if it conflicts with\n    -- `name` (which rarely happens) and very small overhead of recomputing\n    -- extension (which assumed to already be computed by the caller).\n    local is_file = type(name) == 'string'\n    local category = is_file and 'file' or 'extension'\n    local icon, hl, is_default = MiniIcons.get(category, is_file and name or ext)\n    if is_default and not (opts or {}).default then return nil, nil end\n    return icon, hl\n  end\n\n  M.get_icon_by_filetype = function(ft, opts)\n    local icon, hl, is_default = MiniIcons.get('filetype', ft)\n    if is_default and not (opts or {}).default then return nil, nil end\n    return icon, hl\n  end\n\n  -- Use default colors of default icon (#6d8086 and 66) by default\n  local get_hl_data = function(...) return vim.api.nvim_get_hl_by_name(...) end\n  local get_hex = function(hl)\n    if hl == nil then return nil end\n    return string.format('#%06x', get_hl_data(hl, true).foreground or 7176326)\n  end\n  local get_cterm = function(hl)\n    if hl == nil then return nil end\n    return get_hl_data(hl, false).foreground or 66\n  end\n  local with_hex = function(icon, hl) return icon, get_hex(hl) end\n  local with_cterm = function(icon, hl) return icon, get_cterm(hl) end\n  local with_hex_cterm = function(icon, hl) return icon, get_hex(hl), get_cterm(hl) end\n\n  M.get_icon_color = function(...) return with_hex(M.get_icon(...)) end\n  M.get_icon_cterm_color = function(...) return with_cterm(M.get_icon(...)) end\n  M.get_icon_colors = function(...) return with_hex_cterm(M.get_icon(...)) end\n\n  M.get_icon_color_by_filetype = function(...) return with_hex(M.get_icon_by_filetype(...)) end\n  M.get_icon_cterm_color_by_filetype = function(...) return with_cterm(M.get_icon_by_filetype(...)) end\n  M.get_icon_colors_by_filetype = function(...) return with_hex_cterm(M.get_icon_by_filetype(...)) end\n\n  M.get_icon_name_by_filetype = function(ft) return ft end\n\n  -- Mock `get_icons_*()` to the extent they are compatible with this module\n  local make_icon_tbl = function(category, name, output_name)\n    local icon, hl = MiniIcons.get(category, name)\n    return { icon = icon, color = get_hex(hl), cterm_color = tostring(get_cterm(hl)), name = output_name }\n  end\n  local make_category_tbl = function(category)\n    local res = {}\n    -- This won't list all supported names (due to fallback), but at least some\n    for _, name in ipairs(MiniIcons.list(category)) do\n      res[name] = make_icon_tbl(category, name, name)\n    end\n    return res\n  end\n\n  M.get_default_icon = function() return make_icon_tbl('default', 'file', 'Default') end\n\n  M.get_icons = function()\n    return vim.tbl_deep_extend(\n      'force',\n      { [1] = M.get_default_icon() },\n      make_category_tbl('os'),\n      make_category_tbl('file'),\n      make_category_tbl('extension')\n    )\n  end\n  M.get_icons_by_desktop_environment = function() return {} end\n  M.get_icons_by_extension = function() return make_category_tbl('extension') end\n  M.get_icons_by_filename = function() return make_category_tbl('file') end\n  M.get_icons_by_operating_system = function() return make_category_tbl('os') end\n  M.get_icons_by_window_manager = function() return {} end\n\n  -- Should be no need in the these. Suggest using `MiniIcons.setup()`.\n  M.has_loaded = function() return true end\n  M.refresh = function() end\n  M.set_default_icon = function() end\n  M.set_icon = function() end\n  M.set_icon_by_filetype = function() end\n  M.set_up_highlights = function() end\n  M.setup = function() end\n\n  -- Mock. Prefer `package.preload` as it seems to be a better practice.\n  local modname = 'nvim-web-devicons'\n  if package.loaded[modname] == nil then\n    package.preload[modname] = function() return M end\n  else\n    package.loaded[modname] = M\n  end\n  vim.g.nvim_web_devicons = 1\nend\n\n--- Tweak built-in LSP kind names\n---\n--- Update in place appropriate maps in |vim.lsp.protocol| (`CompletionItemKind`\n--- and `SymbolKind`) by using icon strings from \"lsp\" category. Only \"numeric\n--- id to kind name\" part is updated (to preserve data from original map).\n---\n--- Updating is done in one of these modes:\n--- - Append:  add icon after text.\n--- - Prepend: add icon before text (default).\n--- - Replace: use icon instead of text.\n---\n--- Notes:\n--- - Makes |mini.completion| show icons, as it uses built-in protocol map.\n--- - Results in loading whole `vim.lsp` module, so might add significant amount\n---   of time on startup. Call it lazily. For example, with |MiniDeps.later()|: >lua\n---\n---     require('mini.icons').setup()\n---     MiniDeps.later(MiniIcons.tweak_lsp_kind)\n--- <\n---@param mode string|nil One of \"prepend\" (default), \"append\", \"replace\".\nMiniIcons.tweak_lsp_kind = function(mode)\n  mode = mode or 'prepend'\n  local format\n  if mode == 'append' then format = function(kind) return kind .. ' ' .. MiniIcons.get('lsp', kind) end end\n  if mode == 'prepend' then format = function(kind) return MiniIcons.get('lsp', kind) .. ' ' .. kind end end\n  if mode == 'replace' then format = function(kind) return MiniIcons.get('lsp', kind) end end\n  if format == nil then H.error('`mode` should be one of \"append\", \"prepend\", \"replace\".') end\n\n  local protocol = vim.lsp.protocol\n  for i, kind in ipairs(protocol.CompletionItemKind) do\n    protocol.CompletionItemKind[i] = format(kind)\n  end\n  for i, kind in ipairs(protocol.SymbolKind) do\n    protocol.SymbolKind[i] = format(kind)\n  end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniIcons.config\n\n-- Cache tables organized to reduce memory footprint by reducing duplication:\n-- - `cache` is nested and indexed by `category-name` pair with values being\n--   number id in `cache_index`. Its purpose is to quickly get cache. Special\n--   field `true` in each `category` table is made to contain an id of category\n--   fallback icon data.\n-- - `cache_index` is an array of \"icon-hl-is_default\" unique tables. Its\n--   purpose is to store all unique return tuples per category.\n-- - `cache_index_lookup` is nested and indexed by `hl-icon` with values being\n--   number id in `cache_index`. Its purpose is to quickly add new \"icon-hl\"\n--   tuple to cache.\nH.cache = {}\nH.cache_index = {}\nH.cache_index_lookup = {}\n\n-- Default icons per supported category\n--stylua: ignore\nH.default_icons = {\n  default   = { glyph = '󰟢', hl = 'MiniIconsGrey'   },\n  directory = { glyph = '󰉋', hl = 'MiniIconsAzure'  },\n  extension = { glyph = '󰈔', hl = 'MiniIconsGrey'   },\n  file      = { glyph = '󰈔', hl = 'MiniIconsGrey'   },\n  filetype  = { glyph = '󰈔', hl = 'MiniIconsGrey'   },\n  lsp       = { glyph = '󰞋', hl = 'MiniIconsRed'    },\n  os        = { glyph = '󰟀', hl = 'MiniIconsPurple' },\n}\n\n-- Directory icons. Keys are some popular *language-agnostic* directory\n-- basenames. Use only \"folder-shaped\" glyphs while prefering `nf-md-folder-*`\n-- classes (unless glyph is designed specifically for the directory name)\n-- Common sets:\n-- - Use `MiniIconsOrange` for typical HOME directories.\n-- - Use green '󱁽' for Neovim runtime directories (if name isn't too general).\n-- - Use `MiniIconsRed` only for 'mini.nvim' directory.\n--stylua: ignore\nH.directory_icons = {\n  ['.cache']    = { glyph = '󰪺', hl = 'MiniIconsCyan'   },\n  ['.config']   = { glyph = '󱁿', hl = 'MiniIconsCyan'   },\n  ['.git']      = { glyph = '', hl = 'MiniIconsOrange' },\n  ['.github']   = { glyph = '', hl = 'MiniIconsAzure'  },\n  ['.local']    = { glyph = '󰉌', hl = 'MiniIconsCyan'   },\n  ['.vim']      = { glyph = '󰉋', hl = 'MiniIconsGreen'  },\n  AppData       = { glyph = '󰉌', hl = 'MiniIconsOrange' },\n  Applications  = { glyph = '󱧺', hl = 'MiniIconsOrange' },\n  Desktop       = { glyph = '󰚝', hl = 'MiniIconsOrange' },\n  Documents     = { glyph = '󱧶', hl = 'MiniIconsOrange' },\n  Downloads     = { glyph = '󰉍', hl = 'MiniIconsOrange' },\n  Favorites     = { glyph = '󱃪', hl = 'MiniIconsOrange' },\n  Library       = { glyph = '󰲂', hl = 'MiniIconsOrange' },\n  Music         = { glyph = '󱍙', hl = 'MiniIconsOrange' },\n  Network       = { glyph = '󰡰', hl = 'MiniIconsOrange' },\n  Pictures      = { glyph = '󰉏', hl = 'MiniIconsOrange' },\n  ProgramData   = { glyph = '󰉌', hl = 'MiniIconsOrange' },\n  Public        = { glyph = '󱧰', hl = 'MiniIconsOrange' },\n  System        = { glyph = '󱧼', hl = 'MiniIconsOrange' },\n  Templates     = { glyph = '󱋣', hl = 'MiniIconsOrange' },\n  Trash         = { glyph = '󱧴', hl = 'MiniIconsOrange' },\n  Users         = { glyph = '󰉌', hl = 'MiniIconsOrange' },\n  Videos        = { glyph = '󱞊', hl = 'MiniIconsOrange' },\n  Volumes       = { glyph = '󰉓', hl = 'MiniIconsOrange' },\n  autoload      = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  bin           = { glyph = '󱧺', hl = 'MiniIconsYellow' },\n  build         = { glyph = '󱧼', hl = 'MiniIconsGrey'   },\n  boot          = { glyph = '󰴋', hl = 'MiniIconsYellow' },\n  colors        = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  compiler      = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  dev           = { glyph = '󱧼', hl = 'MiniIconsYellow' },\n  doc           = { glyph = '󱂷', hl = 'MiniIconsPurple' },\n  docs          = { glyph = '󱂷', hl = 'MiniIconsPurple' },\n  etc           = { glyph = '󱁿', hl = 'MiniIconsYellow' },\n  ftdetect      = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  ftplugin      = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  home          = { glyph = '󱂵', hl = 'MiniIconsYellow' },\n  indent        = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  keymap        = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  lang          = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  lib           = { glyph = '󰲂', hl = 'MiniIconsYellow' },\n  lsp           = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  lua           = { glyph = '󰉋', hl = 'MiniIconsBlue'   },\n  media         = { glyph = '󱧺', hl = 'MiniIconsYellow' },\n  mnt           = { glyph = '󰉓', hl = 'MiniIconsYellow' },\n  ['mini.nvim'] = { glyph = '󰚝', hl = 'MiniIconsRed'    },\n  node_modules  = { glyph = '', hl = 'MiniIconsGreen'  },\n  nvim          = { glyph = '󰉋', hl = 'MiniIconsGreen'  },\n  opt           = { glyph = '󰉗', hl = 'MiniIconsYellow' },\n  pack          = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  parser        = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  plugin        = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  proc          = { glyph = '󰢬', hl = 'MiniIconsYellow' },\n  queries       = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  rplugin       = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  root          = { glyph = '󰷌', hl = 'MiniIconsYellow' },\n  sbin          = { glyph = '󱧺', hl = 'MiniIconsYellow' },\n  spell         = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  src           = { glyph = '󰴉', hl = 'MiniIconsPurple' },\n  srv           = { glyph = '󱋣', hl = 'MiniIconsYellow' },\n  snippets      = { glyph = '󱁽', hl = 'MiniIconsYellow' },\n  syntax        = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  tmp           = { glyph = '󰪺', hl = 'MiniIconsYellow' },\n  test          = { glyph = '󱞊', hl = 'MiniIconsBlue'   },\n  tests         = { glyph = '󱞊', hl = 'MiniIconsBlue'   },\n  tutor         = { glyph = '󱁽', hl = 'MiniIconsGreen'  },\n  usr           = { glyph = '󰉌', hl = 'MiniIconsYellow' },\n  var           = { glyph = '󱋣', hl = 'MiniIconsYellow' },\n}\n\n-- Extension icons\n-- Value may be string with filetype's name to inherit from its icon data\n--stylua: ignore\nH.extension_icons = {\n  -- Extensions for which `vim.filetype.match()` mismatches or doesn't work.\n  -- Usually because matching depends on an actual buffer content.\n  h     = { glyph = '󰫵', hl = 'MiniIconsPurple' },\n  ipynb = { glyph = '󰠮', hl = 'MiniIconsOrange' },\n  exs   = { glyph = '', hl = 'MiniIconsPurple' },\n  purs  = 'purescript',\n  tf    = 'terraform',\n\n  -- Video\n  ['3gp'] = { glyph = '󰈫', hl = 'MiniIconsYellow' },\n  avi     = { glyph = '󰈫', hl = 'MiniIconsGrey'   },\n  cast    = { glyph = '󰈫', hl = 'MiniIconsRed'    },\n  m4v     = { glyph = '󰈫', hl = 'MiniIconsOrange' },\n  mkv     = { glyph = '󰈫', hl = 'MiniIconsGreen'  },\n  mov     = { glyph = '󰈫', hl = 'MiniIconsCyan'   },\n  mp4     = { glyph = '󰈫', hl = 'MiniIconsAzure'  },\n  mpeg    = { glyph = '󰈫', hl = 'MiniIconsPurple' },\n  mpg     = { glyph = '󰈫', hl = 'MiniIconsPurple' },\n  webm    = { glyph = '󰈫', hl = 'MiniIconsGrey'   },\n  wmv     = { glyph = '󰈫', hl = 'MiniIconsBlue'   },\n\n  -- Audio\n  aac  = { glyph = '󰈣', hl = 'MiniIconsYellow' },\n  aif  = { glyph = '󰈣', hl = 'MiniIconsCyan'   },\n  flac = { glyph = '󰈣', hl = 'MiniIconsOrange' },\n  m4a  = { glyph = '󰈣', hl = 'MiniIconsPurple' },\n  mp3  = { glyph = '󰈣', hl = 'MiniIconsAzure'  },\n  ogg  = { glyph = '󰈣', hl = 'MiniIconsGrey'   },\n  snd  = { glyph = '󰈣', hl = 'MiniIconsRed'    },\n  wav  = { glyph = '󰈣', hl = 'MiniIconsGreen'  },\n  wma  = { glyph = '󰈣', hl = 'MiniIconsBlue'   },\n\n  -- Image\n  bmp  = { glyph = '󰈟', hl = 'MiniIconsGreen'  },\n  eps  = { glyph = '', hl = 'MiniIconsRed'    },\n  gif  = { glyph = '󰵸', hl = 'MiniIconsAzure'  },\n  jpeg = { glyph = '󰈥', hl = 'MiniIconsOrange' },\n  jpg  = { glyph = '󰈥', hl = 'MiniIconsOrange' },\n  png  = { glyph = '󰸭', hl = 'MiniIconsPurple' },\n  tif  = { glyph = '󰈟', hl = 'MiniIconsYellow' },\n  tiff = { glyph = '󰈟', hl = 'MiniIconsYellow' },\n  webp = { glyph = '󰈟', hl = 'MiniIconsBlue'   },\n\n  -- Archives\n  ['7z'] = { glyph = '󰗄', hl = 'MiniIconsBlue'   },\n  bz     = { glyph = '󰗄', hl = 'MiniIconsOrange' },\n  bz2    = { glyph = '󰗄', hl = 'MiniIconsOrange' },\n  bz3    = { glyph = '󰗄', hl = 'MiniIconsOrange' },\n  gz     = { glyph = '󰗄', hl = 'MiniIconsGrey'   },\n  rar    = { glyph = '󰗄', hl = 'MiniIconsGreen'  },\n  rpm    = { glyph = '󰗄', hl = 'MiniIconsRed'    },\n  sit    = { glyph = '󰗄', hl = 'MiniIconsRed'    },\n  tar    = { glyph = '󰗄', hl = 'MiniIconsCyan'   },\n  tgz    = { glyph = '󰗄', hl = 'MiniIconsGrey'   },\n  txz    = { glyph = '󰗄', hl = 'MiniIconsPurple' },\n  xz     = { glyph = '󰗄', hl = 'MiniIconsGreen'  },\n  z      = { glyph = '󰗄', hl = 'MiniIconsGrey'   },\n  zip    = { glyph = '󰗄', hl = 'MiniIconsAzure'  },\n  zst    = { glyph = '󰗄', hl = 'MiniIconsYellow' },\n\n  -- Software\n  doc  = { glyph = '󱎒', hl = 'MiniIconsAzure'  },\n  docm = { glyph = '󱎒', hl = 'MiniIconsAzure'  },\n  docx = { glyph = '󱎒', hl = 'MiniIconsAzure'  },\n  dot  = { glyph = '󱎒', hl = 'MiniIconsAzure'  },\n  dotx = { glyph = '󱎒', hl = 'MiniIconsAzure'  },\n  exe  = { glyph = '󰖳', hl = 'MiniIconsRed'    },\n  pps  = { glyph = '󱎐', hl = 'MiniIconsRed'    },\n  ppsm = { glyph = '󱎐', hl = 'MiniIconsRed'    },\n  ppsx = { glyph = '󱎐', hl = 'MiniIconsRed'    },\n  ppt  = { glyph = '󱎐', hl = 'MiniIconsRed'    },\n  pptm = { glyph = '󱎐', hl = 'MiniIconsRed'    },\n  pptx = { glyph = '󱎐', hl = 'MiniIconsRed'    },\n  xls  = { glyph = '󱎏', hl = 'MiniIconsGreen'  },\n  xlsm = { glyph = '󱎏', hl = 'MiniIconsGreen'  },\n  xlsx = { glyph = '󱎏', hl = 'MiniIconsGreen'  },\n  xlt  = { glyph = '󱎏', hl = 'MiniIconsGreen'  },\n  xltm = { glyph = '󱎏', hl = 'MiniIconsGreen'  },\n  xltx = { glyph = '󱎏', hl = 'MiniIconsGreen'  },\n\n  ['code-snippets'] = 'json',\n}\n\n-- File icons\n-- Value may be string with filetype's name to inherit from its icon data\n--stylua: ignore\nH.file_icons = {\n  -- Popular special (mostly) language-agnostic file basenames\n  ['.DS_Store']          = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  ['.bash_profile']      = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  ['.bashrc']            = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  ['.git']               = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  ['.gitlab-ci.yml']     = { glyph = '󰮠', hl = 'MiniIconsOrange' },\n  ['.gitkeep']           = { glyph = '󰊢', hl = 'MiniIconsRed'    },\n  ['.mailmap']           = { glyph = '󰊢', hl = 'MiniIconsCyan'   },\n  ['.nvmrc']             = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  ['.xinitrc']           = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  ['.zshrc']             = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  CHANGELOG              = { glyph = '󰉻', hl = 'MiniIconsBlue'   },\n  ['CHANGELOG.md']       = { glyph = '󰉻', hl = 'MiniIconsBlue'   },\n  CODE_OF_CONDUCT        = { glyph = '󱃱', hl = 'MiniIconsRed'    },\n  ['CODE_OF_CONDUCT.md'] = { glyph = '󱃱', hl = 'MiniIconsRed'    },\n  CODEOWNERS             = { glyph = '󰜻', hl = 'MiniIconsPurple' },\n  CONTRIBUTING           = { glyph = '󰺾', hl = 'MiniIconsAzure'  },\n  ['CONTRIBUTING.md']    = { glyph = '󰺾', hl = 'MiniIconsAzure'  },\n  ['FUNDING.yml']        = { glyph = '󰇁', hl = 'MiniIconsGreen'  },\n  LICENSE                = { glyph = '', hl = 'MiniIconsCyan'   },\n  ['LICENSE.md']         = { glyph = '', hl = 'MiniIconsCyan'   },\n  ['LICENSE.txt']        = { glyph = '', hl = 'MiniIconsCyan'   },\n  NEWS                   = { glyph = '󰎕', hl = 'MiniIconsBlue'   },\n  ['NEWS.md']            = { glyph = '󰎕', hl = 'MiniIconsBlue'   },\n  PKGBUILD               = { glyph = '󱁤', hl = 'MiniIconsPurple' },\n  README                 = { glyph = '', hl = 'MiniIconsYellow' },\n  ['README.md']          = { glyph = '', hl = 'MiniIconsYellow' },\n  ['README.txt']         = { glyph = '', hl = 'MiniIconsYellow' },\n  TODO                   = { glyph = '󰝖', hl = 'MiniIconsPurple' },\n  ['TODO.md']            = { glyph = '󰝖', hl = 'MiniIconsPurple' },\n  ['init.lua']           = { glyph = '', hl = 'MiniIconsGreen'  },\n\n  -- Supported by `vim.filetype.match` but conflict with using extension first\n  ['build.xml']           = 'ant',\n  ['GNUmakefile.am']      = 'automake',\n  ['Makefile.am']         = 'automake',\n  ['makefile.am']         = 'automake',\n  ['CMakeLists.txt']      = 'cmake',\n  ['CMakeCache.txt']      = 'cmakecache',\n  ['auto.master']         = 'conf',\n  ['.oelint.cfg']         = 'dosini',\n  ['.wakatime.cfg']       = 'dosini',\n  ['pudb.cfg']            = 'dosini',\n  ['setup.cfg']           = 'dosini',\n  ['lltxxxxx.txt']        = 'gedcom',\n  ['go.sum']              = 'gosum',\n  ['go.work.sum']         = 'gosum',\n  ['.indent.pro']         = 'indent',\n  ['indent.pro']          = 'indent',\n  ['ipf.rules']           = 'ipfilter',\n  ['config.ld']           = 'lua',\n  ['lynx.cfg']            = 'lynx',\n  ['cm3.cfg']             = 'm3quake',\n  ['maxima-init.mac']     = 'maxima',\n  ['meson_options.txt']   = 'meson',\n  ['.gitolite.rc']        = 'perl',\n  ['example.gitolite.rc'] = 'perl',\n  ['gitolite.rc']         = 'perl',\n  ['main.cf.proto']       = 'pfmain',\n  ['constraints.txt']     = 'requirements',\n  ['requirements.txt']    = 'requirements',\n  ['robots.txt']          = 'robots',\n  ['tclsh.rc']            = 'tcl',\n\n  -- Supported by `vim.filetype.match` but result in confusing glyph\n  ['.containerignore'] = { glyph = '󰒓', hl = 'MiniIconsGrey' },\n  ['.dockerignore']    = { glyph = '󰡨', hl = 'MiniIconsOrange' },\n  ['.fdignore']        = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  ['.ignore']          = { glyph = '󰒓', hl = 'MiniIconsGrey' },\n  ['.npmignore']       = { glyph = '󰒓', hl = 'MiniIconsGrey' },\n  ['.prettierignore']  = { glyph = '', hl = 'MiniIconsOrange' },\n  ['.rgignore']        = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  ['.vscodeignore']    = { glyph = '', hl = 'MiniIconsAzure' },\n}\n\n-- Filetype icons. Keys are filetypes explicitly supported by Neovim core\n-- (i.e. present in `getcompletion('', 'filetype')` except technical ones)\n-- and filetypes from some popular plugins.\n-- Track filetypes that are newly added to Neovim core by looking at changes of\n-- 'runtime/lua/vim/filetype.lua' and 'runtime/lua/vim/filetype/detect.lua'.\n-- Latest date of sync: 2026-02-13.\n-- Rough process of how glyphs and icons are chosen:\n-- - Try to balance usage of highlight groups.\n-- - Prefer using the following Nerd Fonts classes (from best to worst):\n--     - `nf-md-*` (UTF codes seem to be more thought through). It also has\n--       correct double width in Kitty.\n--     - `nf-dev-*` (more supported devicons).\n--     - `nf-seti-*` (more up to date extensions).\n--     - `nf-custom-*` (niche Nerd Fonts only glyphs).\n-- - If filetype is present in 'nvim-web-devicons', use highlight group with\n--   most similar hue (based on OKLCH color space with equally spaced grid as\n--   in 'mini.hues' and chroma=3 for grey cutoff; adjust manually if needed).\n-- - Sets that have same/close glyphs but maybe different highlights:\n--     - Generic configuration filetypes (\".*conf.*\", \".*rc\", if stated in\n--       filetype file description, etc.) have same glyph.\n--     - Similar language: assembly (\"asm\"), SQL, Perl, HTML, CSV, shell.\n--     - Log files.\n--     - Make / build system.\n--     - Related to Internet/Web.\n-- - For newly assigned icons use semantically close (first by filetype origin,\n--   then by name) abstract icons with `nf-md-*` Nerd Fonts class.\n-- - If no semantically close abstract icon present, use plain letter/digit\n--   icon (based on the first filetype character) with highlight groups picked\n--   randomly to achieve overall balance (trying to minimize maximum number of\n--   glyph-hl duplicates).\n--stylua: ignore\nH.filetype_icons = {\n  -- Neovim filetype plugins (i.e. recognized with vanilla Neovim)\n  ['8th']                = { glyph = '󰭁', hl = 'MiniIconsYellow' },\n  a2ps                   = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  a65                    = { glyph = '', hl = 'MiniIconsRed'    },\n  aap                    = { glyph = '󰫮', hl = 'MiniIconsOrange' },\n  abap                   = { glyph = '󰫮', hl = 'MiniIconsGreen'  },\n  abaqus                 = { glyph = '󰫮', hl = 'MiniIconsGreen'  },\n  abc                    = { glyph = '󰝚', hl = 'MiniIconsAzure'  },\n  abel                   = { glyph = '󰫮', hl = 'MiniIconsAzure'  },\n  abnf                   = { glyph = '󰫮', hl = 'MiniIconsYellow' },\n  acedb                  = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  ada                    = { glyph = '󱁷', hl = 'MiniIconsAzure'  },\n  aflex                  = { glyph = '󰫮', hl = 'MiniIconsCyan'   },\n  ahdl                   = { glyph = '󰫮', hl = 'MiniIconsRed'    },\n  aidl                   = { glyph = '󰫮', hl = 'MiniIconsYellow' },\n  alsaconf               = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  amiga                  = { glyph = '󰫮', hl = 'MiniIconsCyan'   },\n  aml                    = { glyph = '󰫮', hl = 'MiniIconsPurple' },\n  ampl                   = { glyph = '󰫮', hl = 'MiniIconsOrange' },\n  ant                    = { glyph = '󰫮', hl = 'MiniIconsRed'    },\n  antlr                  = { glyph = '󰫮', hl = 'MiniIconsCyan'   },\n  antlr4                 = { glyph = '󰫮', hl = 'MiniIconsYellow' },\n  apache                 = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  apachestyle            = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  apkbuild               = { glyph = '󱁤', hl = 'MiniIconsBlue'   },\n  applescript            = { glyph = '󰀵', hl = 'MiniIconsYellow' },\n  aptconf                = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  arch                   = { glyph = '󰣇', hl = 'MiniIconsBlue'   },\n  arduino                = { glyph = '', hl = 'MiniIconsAzure'  },\n  art                    = { glyph = '󰫮', hl = 'MiniIconsPurple' },\n  asciidoc               = { glyph = '󰪶', hl = 'MiniIconsYellow' },\n  asm                    = { glyph = '', hl = 'MiniIconsPurple' },\n  asm68k                 = { glyph = '', hl = 'MiniIconsRed'    },\n  asmh8300               = { glyph = '', hl = 'MiniIconsOrange' },\n  asn                    = { glyph = '󰫮', hl = 'MiniIconsBlue'   },\n  aspperl                = { glyph = '', hl = 'MiniIconsBlue'   },\n  aspvbs                 = { glyph = '󰫮', hl = 'MiniIconsGreen'  },\n  asterisk               = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  asteriskvm             = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  astro                  = { glyph = '', hl = 'MiniIconsOrange' },\n  asy                    = { glyph = '󰫮', hl = 'MiniIconsAzure'  },\n  atlas                  = { glyph = '󰫮', hl = 'MiniIconsAzure'  },\n  authzed                = { glyph = '󰫮', hl = 'MiniIconsYellow' },\n  autodoc                = { glyph = '󰪶', hl = 'MiniIconsGreen'  },\n  autohotkey             = { glyph = '󰫮', hl = 'MiniIconsYellow' },\n  autoit                 = { glyph = '󰫮', hl = 'MiniIconsCyan'   },\n  automake               = { glyph = '󱁤', hl = 'MiniIconsPurple' },\n  autopkgtest            = { glyph = '󰣚', hl = 'MiniIconsRed'    },\n  ave                    = { glyph = '󰫮', hl = 'MiniIconsGrey'   },\n  avra                   = { glyph = '', hl = 'MiniIconsPurple' },\n  awk                    = { glyph = '', hl = 'MiniIconsGrey'   },\n  ayacc                  = { glyph = '󰫮', hl = 'MiniIconsCyan'   },\n  b                      = { glyph = '󰫯', hl = 'MiniIconsYellow' },\n  baan                   = { glyph = '󰫯', hl = 'MiniIconsOrange' },\n  bash                   = { glyph = '', hl = 'MiniIconsGreen'  },\n  basic                  = { glyph = '󰫯', hl = 'MiniIconsPurple' },\n  bass                   = { glyph = '󰋄', hl = 'MiniIconsBlue'   },\n  bat                    = { glyph = '󰭟', hl = 'MiniIconsGrey'   },\n  bc                     = { glyph = '󰫯', hl = 'MiniIconsCyan'   },\n  bdf                    = { glyph = '󰛖', hl = 'MiniIconsRed'    },\n  beancount              = { glyph = '󰫯', hl = 'MiniIconsAzure'  },\n  bib                    = { glyph = '󱉟', hl = 'MiniIconsYellow' },\n  bicep                  = { glyph = '', hl = 'MiniIconsCyan'   },\n  ['bicep-params']       = { glyph = '', hl = 'MiniIconsPurple' },\n  bindzone               = { glyph = '󰫯', hl = 'MiniIconsCyan'   },\n  bitbake                = { glyph = '󰃫', hl = 'MiniIconsOrange' },\n  blade                  = { glyph = '󰫐', hl = 'MiniIconsRed'    },\n  blank                  = { glyph = '󰫯', hl = 'MiniIconsPurple' },\n  blueprint              = { glyph = '󰠡', hl = 'MiniIconsBlue'   },\n  bp                     = { glyph = '󰫯', hl = 'MiniIconsYellow' },\n  bpftrace               = { glyph = '󰾡', hl = 'MiniIconsYellow' },\n  brighterscript         = { glyph = '󰫯', hl = 'MiniIconsAzure'  },\n  brightscript           = { glyph = '󰫯', hl = 'MiniIconsPurple' },\n  bsdl                   = { glyph = '󰫯', hl = 'MiniIconsPurple' },\n  bst                    = { glyph = '󰫯', hl = 'MiniIconsCyan'   },\n  btm                    = { glyph = '󰫯', hl = 'MiniIconsGreen'  },\n  bzl                    = { glyph = '', hl = 'MiniIconsGreen'  },\n  bzr                    = { glyph = '󰜘', hl = 'MiniIconsRed'    },\n  c                      = { glyph = '󰙱', hl = 'MiniIconsBlue'   },\n  c3                     = { glyph = '󰙱', hl = 'MiniIconsPurple' },\n  cabal                  = { glyph = '󰲒', hl = 'MiniIconsBlue'   },\n  cabalconfig            = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  cabalproject           = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  cairo                  = { glyph = '󰫰', hl = 'MiniIconsOrange' },\n  calendar               = { glyph = '󰃵', hl = 'MiniIconsRed'    },\n  cangjie                = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  capnp                  = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  catalog                = { glyph = '󰕲', hl = 'MiniIconsGrey'   },\n  cdc                    = { glyph = '󰻫', hl = 'MiniIconsRed'    },\n  cdl                    = { glyph = '󰫰', hl = 'MiniIconsOrange' },\n  cdrdaoconf             = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  cdrtoc                 = { glyph = '󰠶', hl = 'MiniIconsRed'    },\n  cedar                  = { glyph = '󰐅', hl = 'MiniIconsGreen'  },\n  cf                     = { glyph = '󰫰', hl = 'MiniIconsRed'    },\n  cfengine               = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  cfg                    = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  cgdbrc                 = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  ch                     = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  chaiscript             = { glyph = '󰶞', hl = 'MiniIconsOrange' },\n  change                 = { glyph = '󰹳', hl = 'MiniIconsYellow' },\n  changelog              = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  chaskell               = { glyph = '󰲒', hl = 'MiniIconsGreen'  },\n  chatito                = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  checkhealth            = { glyph = '󰓙', hl = 'MiniIconsBlue'   },\n  cheetah                = { glyph = '󰫰', hl = 'MiniIconsGrey'   },\n  chicken                = { glyph = '󰫰', hl = 'MiniIconsRed'    },\n  chill                  = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  chordpro               = { glyph = '󰫰', hl = 'MiniIconsGreen'  },\n  chuck                  = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  cl                     = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  clean                  = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  clipper                = { glyph = '󰫰', hl = 'MiniIconsPurple' },\n  clojure                = { glyph = '', hl = 'MiniIconsGreen'  },\n  cmake                  = { glyph = '󱁤', hl = 'MiniIconsOrange' },\n  cmakecache             = { glyph = '󱁤', hl = 'MiniIconsRed'    },\n  cmod                   = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  cmusrc                 = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  cobol                  = { glyph = '󱌼', hl = 'MiniIconsBlue'   },\n  coco                   = { glyph = '󰫰', hl = 'MiniIconsRed'    },\n  codeowners             = { glyph = '󰈮', hl = 'MiniIconsBlue'   },\n  conaryrecipe           = { glyph = '󰫰', hl = 'MiniIconsGrey'   },\n  conf                   = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  config                 = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  confini                = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  context                = { glyph = '', hl = 'MiniIconsGreen'  },\n  cook                   = { glyph = '󰆘', hl = 'MiniIconsBlue'   },\n  coq                    = { glyph = '󱍓', hl = 'MiniIconsAzure'  },\n  corn                   = { glyph = '󰞸', hl = 'MiniIconsYellow' },\n  cpon                   = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  cpp                    = { glyph = '󰙲', hl = 'MiniIconsAzure'  },\n  cqlang                 = { glyph = '󰫰', hl = 'MiniIconsYellow' },\n  crm                    = { glyph = '󰫰', hl = 'MiniIconsGreen'  },\n  crontab                = { glyph = '󰔠', hl = 'MiniIconsAzure'  },\n  crystal                = { glyph = '', hl = 'MiniIconsGrey'   },\n  cs                     = { glyph = '󰌛', hl = 'MiniIconsGreen'  },\n  csc                    = { glyph = '󰫰', hl = 'MiniIconsBlue'   },\n  csdl                   = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  csh                    = { glyph = '', hl = 'MiniIconsGrey'   },\n  csp                    = { glyph = '󰫰', hl = 'MiniIconsAzure'  },\n  css                    = { glyph = '󰌜', hl = 'MiniIconsAzure'  },\n  csv                    = { glyph = '', hl = 'MiniIconsGreen'  },\n  csv_pipe               = { glyph = '', hl = 'MiniIconsAzure'  },\n  csv_semicolon          = { glyph = '', hl = 'MiniIconsRed'    },\n  csv_whitespace         = { glyph = '', hl = 'MiniIconsPurple' },\n  cterm                  = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  ctrlh                  = { glyph = '󰫰', hl = 'MiniIconsOrange' },\n  cucumber               = { glyph = '󰫰', hl = 'MiniIconsPurple' },\n  cuda                   = { glyph = '', hl = 'MiniIconsGreen'  },\n  cue                    = { glyph = '󰝚', hl = 'MiniIconsYellow' },\n  cupl                   = { glyph = '󰫰', hl = 'MiniIconsOrange' },\n  cuplsim                = { glyph = '󰫰', hl = 'MiniIconsPurple' },\n  cvs                    = { glyph = '󰜘', hl = 'MiniIconsGreen'  },\n  cvsrc                  = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  cweb                   = { glyph = '󰫰', hl = 'MiniIconsCyan'   },\n  cynlib                 = { glyph = '󰙲', hl = 'MiniIconsPurple' },\n  cynpp                  = { glyph = '󰙲', hl = 'MiniIconsYellow' },\n  cypher                 = { glyph = '󰫰', hl = 'MiniIconsOrange' },\n  d                      = { glyph = '', hl = 'MiniIconsGreen'  },\n  dafny                  = { glyph = '󰫱', hl = 'MiniIconsYellow' },\n  dart                   = { glyph = '', hl = 'MiniIconsBlue'   },\n  datascript             = { glyph = '󰫱', hl = 'MiniIconsGreen'  },\n  dax                    = { glyph = '󰫱', hl = 'MiniIconsBlue'   },\n  dcd                    = { glyph = '󰫱', hl = 'MiniIconsCyan'   },\n  dcl                    = { glyph = '󰫱', hl = 'MiniIconsAzure'  },\n  deb822sources          = { glyph = '󰫱', hl = 'MiniIconsCyan'   },\n  debchangelog           = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  debcontrol             = { glyph = '󰣚', hl = 'MiniIconsOrange' },\n  debcopyright           = { glyph = '󰣚', hl = 'MiniIconsRed'    },\n  debsources             = { glyph = '󰫱', hl = 'MiniIconsYellow' },\n  def                    = { glyph = '󰫱', hl = 'MiniIconsGrey'   },\n  denyhosts              = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  dep3patch              = { glyph = '󰫱', hl = 'MiniIconsCyan'   },\n  desc                   = { glyph = '󰫱', hl = 'MiniIconsCyan'   },\n  desktop                = { glyph = '󰍹', hl = 'MiniIconsPurple' },\n  dhall                  = { glyph = '󰏪', hl = 'MiniIconsOrange' },\n  dictconf               = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  dictdconf              = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  diff                   = { glyph = '󰦓', hl = 'MiniIconsRed'    },\n  dircolors              = { glyph = '󰫱', hl = 'MiniIconsRed'    },\n  dirpager               = { glyph = '󰙅', hl = 'MiniIconsYellow' },\n  diva                   = { glyph = '󰫱', hl = 'MiniIconsRed'    },\n  django                 = { glyph = '', hl = 'MiniIconsGreen'  },\n  djot                   = { glyph = '󰫱', hl = 'MiniIconsYellow' },\n  dns                    = { glyph = '󰫱', hl = 'MiniIconsOrange' },\n  dnsmasq                = { glyph = '󰫱', hl = 'MiniIconsGrey'   },\n  docbk                  = { glyph = '󰫱', hl = 'MiniIconsYellow' },\n  docbksgml              = { glyph = '󰫱', hl = 'MiniIconsGrey'   },\n  docbkxml               = { glyph = '󰫱', hl = 'MiniIconsGrey'   },\n  dockerfile             = { glyph = '󰡨', hl = 'MiniIconsBlue'   },\n  dosbatch               = { glyph = '󰯂', hl = 'MiniIconsGreen'  },\n  dosini                 = { glyph = '󰯂', hl = 'MiniIconsAzure'  },\n  dot                    = { glyph = '󱁉', hl = 'MiniIconsAzure'  },\n  doxygen                = { glyph = '󰋘', hl = 'MiniIconsBlue'   },\n  dracula                = { glyph = '󰭟', hl = 'MiniIconsGrey'   },\n  dsl                    = { glyph = '󰫱', hl = 'MiniIconsAzure'  },\n  dtd                    = { glyph = '󰫱', hl = 'MiniIconsCyan'   },\n  dtml                   = { glyph = '󰫱', hl = 'MiniIconsRed'    },\n  dtrace                 = { glyph = '󰫱', hl = 'MiniIconsRed'    },\n  dts                    = { glyph = '󰫱', hl = 'MiniIconsRed'    },\n  dune                   = { glyph = '', hl = 'MiniIconsGreen'  },\n  dylan                  = { glyph = '󰫱', hl = 'MiniIconsRed'    },\n  dylanintr              = { glyph = '󰫱', hl = 'MiniIconsGrey'   },\n  dylanlid               = { glyph = '󰫱', hl = 'MiniIconsOrange' },\n  earthfile              = { glyph = '󰫲', hl = 'MiniIconsAzure'  },\n  ecd                    = { glyph = '󰫲', hl = 'MiniIconsPurple' },\n  edif                   = { glyph = '󰫲', hl = 'MiniIconsCyan'   },\n  editorconfig           = { glyph = '', hl = 'MiniIconsGrey'   },\n  eelixir                = { glyph = '', hl = 'MiniIconsYellow' },\n  eiffel                 = { glyph = '󱕫', hl = 'MiniIconsYellow' },\n  elf                    = { glyph = '󰫲', hl = 'MiniIconsGreen'  },\n  elinks                 = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  elixir                 = { glyph = '', hl = 'MiniIconsPurple' },\n  elm                    = { glyph = '', hl = 'MiniIconsAzure'  },\n  elmfilt                = { glyph = '󰫲', hl = 'MiniIconsBlue'   },\n  elsa                   = { glyph = '󰘧', hl = 'MiniIconsGreen'  },\n  elvish                 = { glyph = '', hl = 'MiniIconsGreen'  },\n  epuppet                = { glyph = '', hl = 'MiniIconsYellow' },\n  erlang                 = { glyph = '', hl = 'MiniIconsRed'    },\n  eruby                  = { glyph = '󰴭', hl = 'MiniIconsOrange' },\n  esdl                   = { glyph = '󰆼', hl = 'MiniIconsCyan'   },\n  esmtprc                = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  esqlc                  = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  esterel                = { glyph = '󰫲', hl = 'MiniIconsAzure'  },\n  eterm                  = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  euphoria3              = { glyph = '󰫲', hl = 'MiniIconsRed'    },\n  euphoria4              = { glyph = '󰫲', hl = 'MiniIconsYellow' },\n  eviews                 = { glyph = '󰫲', hl = 'MiniIconsCyan'   },\n  execline               = { glyph = '󰫲', hl = 'MiniIconsAzure'  },\n  exim                   = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  expect                 = { glyph = '󰫲', hl = 'MiniIconsGrey'   },\n  exports                = { glyph = '󰈇', hl = 'MiniIconsPurple' },\n  factor                 = { glyph = '󰫳', hl = 'MiniIconsAzure'  },\n  falcon                 = { glyph = '󱗆', hl = 'MiniIconsOrange' },\n  fan                    = { glyph = '󰫳', hl = 'MiniIconsAzure'  },\n  fasm                   = { glyph = '', hl = 'MiniIconsPurple' },\n  faust                  = { glyph = '󰫳', hl = 'MiniIconsYellow' },\n  fdcc                   = { glyph = '󰫳', hl = 'MiniIconsBlue'   },\n  fennel                 = { glyph = '', hl = 'MiniIconsYellow' },\n  fetchmail              = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  fgl                    = { glyph = '󰫳', hl = 'MiniIconsCyan'   },\n  firrtl                 = { glyph = '󰫳', hl = 'MiniIconsGreen'  },\n  fish                   = { glyph = '', hl = 'MiniIconsGrey'   },\n  flexwiki               = { glyph = '󰖬', hl = 'MiniIconsPurple' },\n  flix                   = { glyph = '󰫳', hl = 'MiniIconsGreen'  },\n  fluent                 = { glyph = '󰫳', hl = 'MiniIconsAzure'  },\n  foam                   = { glyph = '󰫳', hl = 'MiniIconsBlue'   },\n  focexec                = { glyph = '󰫳', hl = 'MiniIconsPurple' },\n  form                   = { glyph = '󰫳', hl = 'MiniIconsCyan'   },\n  forth                  = { glyph = '󰬽', hl = 'MiniIconsRed'    },\n  fortran                = { glyph = '󱈚', hl = 'MiniIconsPurple' },\n  foxpro                 = { glyph = '󰫳', hl = 'MiniIconsGreen'  },\n  fpcmake                = { glyph = '󱁤', hl = 'MiniIconsRed'    },\n  framescript            = { glyph = '󰫳', hl = 'MiniIconsCyan'   },\n  freebasic              = { glyph = '󰫳', hl = 'MiniIconsOrange' },\n  fsh                    = { glyph = '󰫳', hl = 'MiniIconsOrange' },\n  fsharp                 = { glyph = '', hl = 'MiniIconsBlue'   },\n  fstab                  = { glyph = '󰋊', hl = 'MiniIconsGrey'   },\n  func                   = { glyph = '󰫳', hl = 'MiniIconsCyan'   },\n  fusion                 = { glyph = '󰫳', hl = 'MiniIconsYellow' },\n  fvwm                   = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  fvwm2m4                = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  gdb                    = { glyph = '󰈺', hl = 'MiniIconsGrey'   },\n  gdmo                   = { glyph = '󰫴', hl = 'MiniIconsBlue'   },\n  gdresource             = { glyph = '', hl = 'MiniIconsGreen'  },\n  gdscript               = { glyph = '', hl = 'MiniIconsYellow' },\n  gdshader               = { glyph = '', hl = 'MiniIconsPurple' },\n  gedcom                 = { glyph = '󰫴', hl = 'MiniIconsRed'    },\n  gel                    = { glyph = '󰫴', hl = 'MiniIconsCyan'   },\n  gemtext                = { glyph = '󰪁', hl = 'MiniIconsAzure'  },\n  gift                   = { glyph = '󰹄', hl = 'MiniIconsRed'    },\n  git                    = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  gitattributes          = { glyph = '󰊢', hl = 'MiniIconsYellow' },\n  gitcommit              = { glyph = '󰊢', hl = 'MiniIconsGreen'  },\n  gitconfig              = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  gitignore              = { glyph = '󰊢', hl = 'MiniIconsPurple' },\n  gitolite               = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  gitrebase              = { glyph = '󰊢', hl = 'MiniIconsAzure'  },\n  gitsendemail           = { glyph = '󰊢', hl = 'MiniIconsBlue'   },\n  gkrellmrc              = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  gleam                  = { glyph = '󰦥', hl = 'MiniIconsPurple' },\n  glsl                   = { glyph = '󰫴', hl = 'MiniIconsCyan'   },\n  gn                     = { glyph = '󰫴', hl = 'MiniIconsGrey'   },\n  gnash                  = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  gnuplot                = { glyph = '󰺒', hl = 'MiniIconsPurple' },\n  go                     = { glyph = '󰟓', hl = 'MiniIconsAzure'  },\n  goaccess               = { glyph = '󰫴', hl = 'MiniIconsPurple' },\n  godoc                  = { glyph = '󰟓', hl = 'MiniIconsOrange' },\n  gomod                  = { glyph = '󰟓', hl = 'MiniIconsAzure'  },\n  gosum                  = { glyph = '󰟓', hl = 'MiniIconsCyan'   },\n  gowork                 = { glyph = '󰟓', hl = 'MiniIconsPurple' },\n  gp                     = { glyph = '󰫴', hl = 'MiniIconsCyan'   },\n  gpg                    = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  gprof                  = { glyph = '󰫴', hl = 'MiniIconsAzure'  },\n  grads                  = { glyph = '󰫴', hl = 'MiniIconsPurple' },\n  graphql                = { glyph = '󰡷', hl = 'MiniIconsRed'    },\n  gretl                  = { glyph = '󰫴', hl = 'MiniIconsCyan'   },\n  groff                  = { glyph = '󰫴', hl = 'MiniIconsYellow' },\n  groovy                 = { glyph = '', hl = 'MiniIconsAzure'  },\n  group                  = { glyph = '󰫴', hl = 'MiniIconsCyan'   },\n  grub                   = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  gsp                    = { glyph = '󰫴', hl = 'MiniIconsYellow' },\n  gtkrc                  = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  gvpr                   = { glyph = '󰫴', hl = 'MiniIconsBlue'   },\n  gyp                    = { glyph = '󰫴', hl = 'MiniIconsPurple' },\n  hack                   = { glyph = '󰫵', hl = 'MiniIconsPurple' },\n  haml                   = { glyph = '󰅴', hl = 'MiniIconsGrey'   },\n  hamster                = { glyph = '󰫵', hl = 'MiniIconsCyan'   },\n  handlebars             = { glyph = '󰌞', hl = 'MiniIconsGreen'  },\n  hare                   = { glyph = '󰫵', hl = 'MiniIconsRed'    },\n  haredoc                = { glyph = '󰪶', hl = 'MiniIconsGrey'   },\n  haskell                = { glyph = '󰲒', hl = 'MiniIconsPurple' },\n  haskellpersistent      = { glyph = '󰲒', hl = 'MiniIconsAzure'  },\n  haste                  = { glyph = '󰫵', hl = 'MiniIconsYellow' },\n  hastepreproc           = { glyph = '󰫵', hl = 'MiniIconsCyan'   },\n  haxe                   = { glyph = '󰫵', hl = 'MiniIconsGrey'   },\n  hb                     = { glyph = '󰫵', hl = 'MiniIconsGreen'  },\n  hcl                    = { glyph = '󰫵', hl = 'MiniIconsAzure'  },\n  heex                   = { glyph = '', hl = 'MiniIconsRed'    },\n  help                   = { glyph = '󰋖', hl = 'MiniIconsPurple' },\n  hercules               = { glyph = '󰫵', hl = 'MiniIconsRed'    },\n  hex                    = { glyph = '󰋘', hl = 'MiniIconsYellow' },\n  hgcommit               = { glyph = '󰜘', hl = 'MiniIconsGrey'   },\n  hjson                  = { glyph = '󰘦', hl = 'MiniIconsGreen'  },\n  hlsplaylist            = { glyph = '󰲸', hl = 'MiniIconsOrange' },\n  hog                    = { glyph = '󰫵', hl = 'MiniIconsOrange' },\n  hollywood              = { glyph = '󰓎', hl = 'MiniIconsYellow' },\n  hoon                   = { glyph = '󰫵', hl = 'MiniIconsCyan'   },\n  hostconf               = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  hostsaccess            = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  html                   = { glyph = '󰌝', hl = 'MiniIconsOrange' },\n  htmlangular            = { glyph = '󰚲', hl = 'MiniIconsRed'    },\n  htmlcheetah            = { glyph = '󰌝', hl = 'MiniIconsYellow' },\n  htmldjango             = { glyph = '󰌝', hl = 'MiniIconsGreen'  },\n  htmlm4                 = { glyph = '󰌝', hl = 'MiniIconsRed'    },\n  htmlos                 = { glyph = '󰌝', hl = 'MiniIconsAzure'  },\n  httest                 = { glyph = '󰫵', hl = 'MiniIconsGrey'   },\n  http                   = { glyph = '󰌷', hl = 'MiniIconsOrange' },\n  hurl                   = { glyph = '󰫵', hl = 'MiniIconsGreen'  },\n  hy                     = { glyph = '󰫵', hl = 'MiniIconsGrey'   },\n  hylo                   = { glyph = '󰫵', hl = 'MiniIconsYellow' },\n  hyprlang               = { glyph = '', hl = 'MiniIconsCyan'   },\n  i3config               = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  ia64                   = { glyph = '', hl = 'MiniIconsPurple' },\n  ibasic                 = { glyph = '󰫶', hl = 'MiniIconsOrange' },\n  icemenu                = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  icon                   = { glyph = '󰫶', hl = 'MiniIconsGreen'  },\n  idl                    = { glyph = '󰫶', hl = 'MiniIconsRed'    },\n  idlang                 = { glyph = '󱗿', hl = 'MiniIconsAzure'  },\n  idris2                 = { glyph = '󰫶', hl = 'MiniIconsGrey'   },\n  indent                 = { glyph = '󰉶', hl = 'MiniIconsGreen'  },\n  info                   = { glyph = '󰫶', hl = 'MiniIconsAzure'  },\n  inform                 = { glyph = '󰫶', hl = 'MiniIconsOrange' },\n  initex                 = { glyph = '', hl = 'MiniIconsGreen'  },\n  initng                 = { glyph = '󰫶', hl = 'MiniIconsAzure'  },\n  inittab                = { glyph = '󰫶', hl = 'MiniIconsBlue'   },\n  inko                   = { glyph = '󱗆', hl = 'MiniIconsGreen'  },\n  ipfilter               = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  ipkg                   = { glyph = '󰫶', hl = 'MiniIconsGrey'   },\n  ishd                   = { glyph = '󰫶', hl = 'MiniIconsYellow' },\n  iss                    = { glyph = '󰏗', hl = 'MiniIconsBlue'   },\n  ist                    = { glyph = '󰫶', hl = 'MiniIconsCyan'   },\n  j                      = { glyph = '󰫷', hl = 'MiniIconsAzure'  },\n  jal                    = { glyph = '󰫷', hl = 'MiniIconsCyan'   },\n  jam                    = { glyph = '󰫷', hl = 'MiniIconsCyan'   },\n  janet                  = { glyph = '󰫷', hl = 'MiniIconsOrange' },\n  jargon                 = { glyph = '󰫷', hl = 'MiniIconsCyan'   },\n  java                   = { glyph = '󰬷', hl = 'MiniIconsOrange' },\n  javacc                 = { glyph = '󰬷', hl = 'MiniIconsRed'    },\n  javascript             = { glyph = '󰌞', hl = 'MiniIconsYellow' },\n  ['javascript.glimmer'] = { glyph = '󰌞', hl = 'MiniIconsRed'    },\n  javascriptreact        = { glyph = '', hl = 'MiniIconsAzure'  },\n  jess                   = { glyph = '󰫷', hl = 'MiniIconsPurple' },\n  jgraph                 = { glyph = '󰫷', hl = 'MiniIconsGrey'   },\n  jinja                  = { glyph = '', hl = 'MiniIconsRed'    },\n  jjdescription          = { glyph = '󱨎', hl = 'MiniIconsYellow' },\n  jovial                 = { glyph = '󰫷', hl = 'MiniIconsGrey'   },\n  jproperties            = { glyph = '󰬷', hl = 'MiniIconsGreen'  },\n  jq                     = { glyph = '󰘦', hl = 'MiniIconsBlue'   },\n  json                   = { glyph = '󰘦', hl = 'MiniIconsYellow' },\n  json5                  = { glyph = '󰘦', hl = 'MiniIconsOrange' },\n  jsonc                  = { glyph = '󰘦', hl = 'MiniIconsYellow' },\n  jsonl                  = { glyph = '󰘦', hl = 'MiniIconsYellow' },\n  jsonnet                = { glyph = '󰫷', hl = 'MiniIconsYellow' },\n  jsp                    = { glyph = '󰫷', hl = 'MiniIconsAzure'  },\n  julia                  = { glyph = '', hl = 'MiniIconsPurple' },\n  just                   = { glyph = '󰖷', hl = 'MiniIconsOrange' },\n  karel                  = { glyph = '󰚩', hl = 'MiniIconsGrey'   },\n  kconfig                = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  kdl                    = { glyph = '󰫸', hl = 'MiniIconsGrey'   },\n  kerml                  = { glyph = '󰫸', hl = 'MiniIconsGreen'  },\n  kitty                  = { glyph = '󰄛', hl = 'MiniIconsGrey'   },\n  kivy                   = { glyph = '󰫸', hl = 'MiniIconsBlue'   },\n  kix                    = { glyph = '󰫸', hl = 'MiniIconsRed'    },\n  koka                   = { glyph = '󰫸', hl = 'MiniIconsGreen'  },\n  kos                    = { glyph = '󰫸', hl = 'MiniIconsPurple' },\n  kotlin                 = { glyph = '󱈙', hl = 'MiniIconsBlue'   },\n  krl                    = { glyph = '󰚩', hl = 'MiniIconsGrey'   },\n  kscript                = { glyph = '󰫸', hl = 'MiniIconsGrey'   },\n  kwt                    = { glyph = '󰫸', hl = 'MiniIconsOrange' },\n  lace                   = { glyph = '󰫹', hl = 'MiniIconsCyan'   },\n  lalrpop                = { glyph = '󱘗', hl = 'MiniIconsGreen'  },\n  larch                  = { glyph = '󱎦', hl = 'MiniIconsOrange' },\n  latte                  = { glyph = '󰅶', hl = 'MiniIconsOrange' },\n  lc                     = { glyph = '󰫹', hl = 'MiniIconsRed'    },\n  ld                     = { glyph = '󰫹', hl = 'MiniIconsPurple' },\n  ldapconf               = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  ldif                   = { glyph = '󰫹', hl = 'MiniIconsPurple' },\n  lean                   = { glyph = '󱎦', hl = 'MiniIconsPurple' },\n  ledger                 = { glyph = '󱪹', hl = 'MiniIconsBlue'   },\n  leex                   = { glyph = '󰫹', hl = 'MiniIconsYellow' },\n  leo                    = { glyph = '󰪂', hl = 'MiniIconsYellow' },\n  less                   = { glyph = '󰌜', hl = 'MiniIconsPurple' },\n  lex                    = { glyph = '󰫹', hl = 'MiniIconsOrange' },\n  lf                     = { glyph = '󰫹', hl = 'MiniIconsPurple' },\n  lftp                   = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  lhaskell               = { glyph = '', hl = 'MiniIconsPurple' },\n  libao                  = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  lidris2                = { glyph = '󰫹', hl = 'MiniIconsPurple' },\n  lifelines              = { glyph = '󰫹', hl = 'MiniIconsCyan'   },\n  lilo                   = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  lilypond               = { glyph = '󱎦', hl = 'MiniIconsOrange' },\n  limits                 = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  liquid                 = { glyph = '', hl = 'MiniIconsGreen'  },\n  liquidsoap             = { glyph = '󰐹', hl = 'MiniIconsPurple' },\n  lisp                   = { glyph = '', hl = 'MiniIconsGrey'   },\n  lite                   = { glyph = '󰫹', hl = 'MiniIconsCyan'   },\n  litestep               = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  livebook               = { glyph = '󰂾', hl = 'MiniIconsGreen'  },\n  llvm                   = { glyph = '', hl = 'MiniIconsCyan'   },\n  lnk                    = { glyph = '󰫹', hl = 'MiniIconsPurple' },\n  lnkmap                 = { glyph = '󰫹', hl = 'MiniIconsCyan'   },\n  logcheck               = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  loginaccess            = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  logindefs              = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  logtalk                = { glyph = '󰫹', hl = 'MiniIconsOrange' },\n  lotos                  = { glyph = '󰴈', hl = 'MiniIconsGrey'   },\n  lout                   = { glyph = '󰫹', hl = 'MiniIconsCyan'   },\n  lpc                    = { glyph = '󰫹', hl = 'MiniIconsGrey'   },\n  lprolog                = { glyph = '󰘧', hl = 'MiniIconsOrange' },\n  lscript                = { glyph = '󰫹', hl = 'MiniIconsCyan'   },\n  lsl                    = { glyph = '󰫹', hl = 'MiniIconsYellow' },\n  lsp_markdown           = { glyph = '󰍔', hl = 'MiniIconsGrey'   },\n  lss                    = { glyph = '󰫹', hl = 'MiniIconsAzure'  },\n  lua                    = { glyph = '󰢱', hl = 'MiniIconsAzure'  },\n  luau                   = { glyph = '󰢱', hl = 'MiniIconsGreen'  },\n  lynx                   = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  lyrics                 = { glyph = '󰫹', hl = 'MiniIconsOrange' },\n  m17ndb                 = { glyph = '󰫺', hl = 'MiniIconsAzure'  },\n  m3build                = { glyph = '󰫺', hl = 'MiniIconsGrey'   },\n  m3quake                = { glyph = '󰫺', hl = 'MiniIconsGreen'  },\n  m4                     = { glyph = '󰫺', hl = 'MiniIconsYellow' },\n  mail                   = { glyph = '󰇮', hl = 'MiniIconsRed'    },\n  mailaliases            = { glyph = '󰇮', hl = 'MiniIconsOrange' },\n  mailcap                = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  make                   = { glyph = '󱁤', hl = 'MiniIconsGrey'   },\n  mallard                = { glyph = '󰫺', hl = 'MiniIconsGrey'   },\n  man                    = { glyph = '󰗚', hl = 'MiniIconsYellow' },\n  manconf                = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  manual                 = { glyph = '󰗚', hl = 'MiniIconsYellow' },\n  map                    = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  maple                  = { glyph = '󰲓', hl = 'MiniIconsRed'    },\n  markdown               = { glyph = '󰍔', hl = 'MiniIconsGrey'   },\n  masm                   = { glyph = '', hl = 'MiniIconsPurple' },\n  master                 = { glyph = '󰫺', hl = 'MiniIconsOrange' },\n  matlab                 = { glyph = '󰿈', hl = 'MiniIconsOrange' },\n  maxima                 = { glyph = '󰫺', hl = 'MiniIconsGrey'   },\n  mbsyncrc               = { glyph = '󰫺', hl = 'MiniIconsPurple' },\n  mediawiki              = { glyph = '󰖬', hl = 'MiniIconsBlue'   },\n  mel                    = { glyph = '󰫺', hl = 'MiniIconsAzure'  },\n  mermaid                = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  meson                  = { glyph = '󰫺', hl = 'MiniIconsBlue'   },\n  messages               = { glyph = '󰍡', hl = 'MiniIconsBlue'   },\n  mf                     = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  mgl                    = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  mgp                    = { glyph = '󰫺', hl = 'MiniIconsAzure'  },\n  mib                    = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  mix                    = { glyph = '󰫺', hl = 'MiniIconsRed'    },\n  mlir                   = { glyph = '󰫺', hl = 'MiniIconsGreen'  },\n  mma                    = { glyph = '󰘨', hl = 'MiniIconsAzure'  },\n  mmix                   = { glyph = '󰫺', hl = 'MiniIconsRed'    },\n  mmp                    = { glyph = '󰫺', hl = 'MiniIconsGrey'   },\n  modconf                = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  model                  = { glyph = '󰫺', hl = 'MiniIconsGreen'  },\n  modsim3                = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  modula2                = { glyph = '󰫺', hl = 'MiniIconsOrange' },\n  modula3                = { glyph = '󰫺', hl = 'MiniIconsRed'    },\n  mojo                   = { glyph = '󰈸', hl = 'MiniIconsRed'    },\n  monk                   = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  moo                    = { glyph = '󰫺', hl = 'MiniIconsYellow' },\n  moonscript             = { glyph = '󰽥', hl = 'MiniIconsGrey'   },\n  move                   = { glyph = '󰆾', hl = 'MiniIconsBlue'   },\n  mp                     = { glyph = '󰫺', hl = 'MiniIconsAzure'  },\n  mplayerconf            = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  mrxvtrc                = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  msidl                  = { glyph = '󰫺', hl = 'MiniIconsPurple' },\n  msmessages             = { glyph = '󰍡', hl = 'MiniIconsAzure'  },\n  msmtp                  = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  msql                   = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  mss                    = { glyph = '󰫺', hl = 'MiniIconsGrey'   },\n  mupad                  = { glyph = '󰫺', hl = 'MiniIconsCyan'   },\n  murphi                 = { glyph = '󰫺', hl = 'MiniIconsAzure'  },\n  mush                   = { glyph = '󰫺', hl = 'MiniIconsPurple' },\n  mustache               = { glyph = '󱗞', hl = 'MiniIconsAzure'  },\n  muttrc                 = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  mysql                  = { glyph = '󰆼', hl = 'MiniIconsOrange' },\n  n1ql                   = { glyph = '󰫻', hl = 'MiniIconsYellow' },\n  named                  = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  nanorc                 = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  nasm                   = { glyph = '', hl = 'MiniIconsPurple' },\n  nastran                = { glyph = '󰫻', hl = 'MiniIconsRed'    },\n  natural                = { glyph = '󰫻', hl = 'MiniIconsBlue'   },\n  ncf                    = { glyph = '󰫻', hl = 'MiniIconsYellow' },\n  neomuttlog             = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  neomuttrc              = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  netlinx                = { glyph = '󰫻', hl = 'MiniIconsBlue'   },\n  netrc                  = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  netrw                  = { glyph = '󰙅', hl = 'MiniIconsBlue'   },\n  nginx                  = { glyph = '󰰓', hl = 'MiniIconsGreen'  },\n  nickel                 = { glyph = '󰫻', hl = 'MiniIconsRed'    },\n  nim                    = { glyph = '', hl = 'MiniIconsYellow' },\n  ninja                  = { glyph = '󰝴', hl = 'MiniIconsGrey'   },\n  nix                    = { glyph = '󱄅', hl = 'MiniIconsAzure'  },\n  norg                   = { glyph = '', hl = 'MiniIconsBlue'   },\n  nq                     = { glyph = '󱁉', hl = 'MiniIconsGrey'   },\n  nqc                    = { glyph = '󱊈', hl = 'MiniIconsYellow' },\n  nroff                  = { glyph = '󰫻', hl = 'MiniIconsCyan'   },\n  nsis                   = { glyph = '󰫻', hl = 'MiniIconsAzure'  },\n  ntriples               = { glyph = '󱁉', hl = 'MiniIconsGreen'  },\n  nu                     = { glyph = '', hl = 'MiniIconsPurple' },\n  numbat                 = { glyph = '󰫻', hl = 'MiniIconsAzure'  },\n  obj                    = { glyph = '󰆧', hl = 'MiniIconsGrey'   },\n  objc                   = { glyph = '󰀵', hl = 'MiniIconsOrange' },\n  objcpp                 = { glyph = '󰀵', hl = 'MiniIconsOrange' },\n  objdump                = { glyph = '󰫼', hl = 'MiniIconsCyan'   },\n  obse                   = { glyph = '󰫼', hl = 'MiniIconsBlue'   },\n  ocaml                  = { glyph = '', hl = 'MiniIconsOrange' },\n  occam                  = { glyph = '󱦗', hl = 'MiniIconsGrey'   },\n  octave                 = { glyph = '󱥸', hl = 'MiniIconsBlue'   },\n  odin                   = { glyph = '󰮔', hl = 'MiniIconsBlue'   },\n  omnimark               = { glyph = '󰫼', hl = 'MiniIconsPurple' },\n  ondir                  = { glyph = '󰫼', hl = 'MiniIconsCyan'   },\n  opam                   = { glyph = '󰫼', hl = 'MiniIconsBlue'   },\n  opencl                 = { glyph = '', hl = 'MiniIconsGreen'  },\n  openroad               = { glyph = '󰫼', hl = 'MiniIconsOrange' },\n  openscad               = { glyph = '', hl = 'MiniIconsYellow' },\n  openvpn                = { glyph = '󰖂', hl = 'MiniIconsPurple' },\n  opl                    = { glyph = '󰫼', hl = 'MiniIconsPurple' },\n  ora                    = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  org                    = { glyph = '', hl = 'MiniIconsCyan'   },\n  pacmanlog              = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  pamconf                = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  pamenv                 = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  pandoc                 = { glyph = '󰍔', hl = 'MiniIconsYellow' },\n  papp                   = { glyph = '', hl = 'MiniIconsAzure'  },\n  pascal                 = { glyph = '󱤊', hl = 'MiniIconsRed'    },\n  passwd                 = { glyph = '󰟵', hl = 'MiniIconsGrey'   },\n  pbtxt                  = { glyph = '󰈚', hl = 'MiniIconsRed'    },\n  pcap                   = { glyph = '󰐪', hl = 'MiniIconsRed'    },\n  pccts                  = { glyph = '󰫽', hl = 'MiniIconsRed'    },\n  pcmk                   = { glyph = '󰫽', hl = 'MiniIconsRed'    },\n  pdf                    = { glyph = '󰈦', hl = 'MiniIconsRed'    },\n  pem                    = { glyph = '󰌇', hl = 'MiniIconsYellow' },\n  perl                   = { glyph = '', hl = 'MiniIconsAzure'  },\n  pf                     = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  pfmain                 = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  php                    = { glyph = '󰌟', hl = 'MiniIconsPurple' },\n  phtml                  = { glyph = '󰌟', hl = 'MiniIconsOrange' },\n  pic                    = { glyph = '', hl = 'MiniIconsPurple' },\n  pike                   = { glyph = '󰈺', hl = 'MiniIconsGrey'   },\n  pilrc                  = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  pine                   = { glyph = '󰇮', hl = 'MiniIconsRed'    },\n  pinfo                  = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  pkl                    = { glyph = '󰫽', hl = 'MiniIconsBlue'   },\n  plaintex               = { glyph = '', hl = 'MiniIconsGreen'  },\n  pli                    = { glyph = '󰫽', hl = 'MiniIconsRed'    },\n  plm                    = { glyph = '󰫽', hl = 'MiniIconsBlue'   },\n  plp                    = { glyph = '', hl = 'MiniIconsBlue'   },\n  plsql                  = { glyph = '󰆼', hl = 'MiniIconsOrange' },\n  po                     = { glyph = '󰗊', hl = 'MiniIconsAzure'  },\n  pod                    = { glyph = '', hl = 'MiniIconsPurple' },\n  poefilter              = { glyph = '󰫽', hl = 'MiniIconsAzure'  },\n  poke                   = { glyph = '󰫽', hl = 'MiniIconsPurple' },\n  pony                   = { glyph = '󱖿', hl = 'MiniIconsGrey'   },\n  postscr                = { glyph = '', hl = 'MiniIconsYellow' },\n  pov                    = { glyph = '󰫽', hl = 'MiniIconsPurple' },\n  povini                 = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  ppd                    = { glyph = '', hl = 'MiniIconsPurple' },\n  ppwiz                  = { glyph = '󰫽', hl = 'MiniIconsGrey'   },\n  pq                     = { glyph = '󰫽', hl = 'MiniIconsAzure'  },\n  prescribe              = { glyph = '󰜆', hl = 'MiniIconsYellow' },\n  prisma                 = { glyph = '', hl = 'MiniIconsBlue'   },\n  privoxy                = { glyph = '󰫽', hl = 'MiniIconsOrange' },\n  proc                   = { glyph = '󰆼', hl = 'MiniIconsRed'    },\n  procmail               = { glyph = '󰇮', hl = 'MiniIconsBlue'   },\n  progress               = { glyph = '󰫽', hl = 'MiniIconsGreen'  },\n  prolog                 = { glyph = '', hl = 'MiniIconsYellow' },\n  promela                = { glyph = '󰫽', hl = 'MiniIconsRed'    },\n  proto                  = { glyph = '', hl = 'MiniIconsRed'    },\n  protocols              = { glyph = '󰖟', hl = 'MiniIconsOrange' },\n  prql                   = { glyph = '󱘻', hl = 'MiniIconsYellow' },\n  ps1                    = { glyph = '󰨊', hl = 'MiniIconsBlue'   },\n  ps1xml                 = { glyph = '󰨊', hl = 'MiniIconsAzure'  },\n  psf                    = { glyph = '󰫽', hl = 'MiniIconsPurple' },\n  psl                    = { glyph = '󰫽', hl = 'MiniIconsAzure'  },\n  ptcap                  = { glyph = '󰐪', hl = 'MiniIconsRed'    },\n  ptx                    = { glyph = '󰫽', hl = 'MiniIconsGreen'  },\n  pug                    = { glyph = '', hl = 'MiniIconsPurple' },\n  puppet                 = { glyph = '', hl = 'MiniIconsOrange' },\n  purescript             = { glyph = '', hl = 'MiniIconsGrey'   },\n  purifylog              = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  pymanifest             = { glyph = '󰌠', hl = 'MiniIconsAzure'  },\n  pyret                  = { glyph = '󰫽', hl = 'MiniIconsBlue'   },\n  pyrex                  = { glyph = '󰫽', hl = 'MiniIconsYellow' },\n  python                 = { glyph = '󰌠', hl = 'MiniIconsYellow' },\n  python2                = { glyph = '󰌠', hl = 'MiniIconsGrey'   },\n  qb64                   = { glyph = '󰫾', hl = 'MiniIconsCyan'   },\n  qf                     = { glyph = '󰝖', hl = 'MiniIconsAzure'  },\n  ql                     = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  qml                    = { glyph = '󰫾', hl = 'MiniIconsAzure'  },\n  qmldir                 = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  quake                  = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  quarto                 = { glyph = '󰐗', hl = 'MiniIconsAzure'  },\n  query                  = { glyph = '󰐅', hl = 'MiniIconsGreen'  },\n  quickbms               = { glyph = '󰫾', hl = 'MiniIconsGrey'   },\n  r                      = { glyph = '󰟔', hl = 'MiniIconsBlue'   },\n  racc                   = { glyph = '󰫿', hl = 'MiniIconsYellow' },\n  racket                 = { glyph = '󰘧', hl = 'MiniIconsRed'    },\n  radiance               = { glyph = '󰫿', hl = 'MiniIconsGrey'   },\n  raku                   = { glyph = '󱖉', hl = 'MiniIconsYellow' },\n  raml                   = { glyph = '󰫿', hl = 'MiniIconsCyan'   },\n  rapid                  = { glyph = '󰫿', hl = 'MiniIconsCyan'   },\n  rasi                   = { glyph = '󰫿', hl = 'MiniIconsOrange' },\n  ratpoison              = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  rbs                    = { glyph = '󰁯', hl = 'MiniIconsBlue'   },\n  rc                     = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  rcs                    = { glyph = '󰫿', hl = 'MiniIconsYellow' },\n  rcslog                 = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  readline               = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  rebol                  = { glyph = '󰫿', hl = 'MiniIconsBlue'   },\n  redif                  = { glyph = '󰫿', hl = 'MiniIconsOrange' },\n  registry               = { glyph = '󰪶', hl = 'MiniIconsRed'    },\n  rego                   = { glyph = '󰫿', hl = 'MiniIconsPurple' },\n  remind                 = { glyph = '󰢌', hl = 'MiniIconsPurple' },\n  requirements           = { glyph = '󱘎', hl = 'MiniIconsPurple' },\n  rescript               = { glyph = '󰫿', hl = 'MiniIconsAzure'  },\n  resolv                 = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  reva                   = { glyph = '󰫿', hl = 'MiniIconsGrey'   },\n  rexx                   = { glyph = '󰫿', hl = 'MiniIconsGreen'  },\n  rfc_csv                = { glyph = '', hl = 'MiniIconsOrange' },\n  rfc_semicolon          = { glyph = '', hl = 'MiniIconsRed'    },\n  rhelp                  = { glyph = '󰟔', hl = 'MiniIconsAzure'  },\n  rib                    = { glyph = '󰫿', hl = 'MiniIconsGreen'  },\n  rmarkdown              = { glyph = '󰍔', hl = 'MiniIconsAzure'  },\n  rmd                    = { glyph = '󰍔', hl = 'MiniIconsAzure'  },\n  rnc                    = { glyph = '󰫿', hl = 'MiniIconsGreen'  },\n  rng                    = { glyph = '󰫿', hl = 'MiniIconsCyan'   },\n  rnoweb                 = { glyph = '󰟔', hl = 'MiniIconsGreen'  },\n  robot                  = { glyph = '󰚩', hl = 'MiniIconsYellow' },\n  robots                 = { glyph = '󰚩', hl = 'MiniIconsGrey'   },\n  roc                    = { glyph = '󱗆', hl = 'MiniIconsPurple' },\n  ron                    = { glyph = '󱘗', hl = 'MiniIconsCyan'   },\n  routeros               = { glyph = '󱂇', hl = 'MiniIconsGrey'   },\n  rpcgen                 = { glyph = '󰫿', hl = 'MiniIconsCyan'   },\n  rpgle                  = { glyph = '󰫿', hl = 'MiniIconsGreen'  },\n  rpl                    = { glyph = '󰫿', hl = 'MiniIconsCyan'   },\n  rrst                   = { glyph = '󰫿', hl = 'MiniIconsGreen'  },\n  rst                    = { glyph = '󰊄', hl = 'MiniIconsYellow' },\n  rtf                    = { glyph = '󰚞', hl = 'MiniIconsAzure'  },\n  ruby                   = { glyph = '󰴭', hl = 'MiniIconsRed'    },\n  rust                   = { glyph = '󱘗', hl = 'MiniIconsOrange' },\n  sage                   = { glyph = '󰘨', hl = 'MiniIconsPurple' },\n  salt                   = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  samba                  = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  sas                    = { glyph = '󰱐', hl = 'MiniIconsAzure'  },\n  sass                   = { glyph = '󰟬', hl = 'MiniIconsRed'    },\n  sather                 = { glyph = '󰬀', hl = 'MiniIconsAzure'  },\n  sbt                    = { glyph = '', hl = 'MiniIconsOrange' },\n  scala                  = { glyph = '', hl = 'MiniIconsRed'    },\n  scdoc                  = { glyph = '󰪶', hl = 'MiniIconsAzure'  },\n  scheme                 = { glyph = '󰘧', hl = 'MiniIconsGrey'   },\n  scilab                 = { glyph = '󰂓', hl = 'MiniIconsYellow' },\n  screen                 = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  scss                   = { glyph = '󰟬', hl = 'MiniIconsRed'    },\n  sd                     = { glyph = '󰬀', hl = 'MiniIconsGrey'   },\n  sdc                    = { glyph = '󰬀', hl = 'MiniIconsGreen'  },\n  sdl                    = { glyph = '󰬀', hl = 'MiniIconsRed'    },\n  sed                    = { glyph = '󰟥', hl = 'MiniIconsRed'    },\n  sendpr                 = { glyph = '󰆨', hl = 'MiniIconsBlue'   },\n  sensors                = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  services               = { glyph = '󰖟', hl = 'MiniIconsGreen'  },\n  setserial              = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  sexplib                = { glyph = '', hl = 'MiniIconsYellow' },\n  sgml                   = { glyph = '󰬀', hl = 'MiniIconsRed'    },\n  sgmldecl               = { glyph = '󰬀', hl = 'MiniIconsYellow' },\n  sgmllnx                = { glyph = '󰬀', hl = 'MiniIconsGrey'   },\n  sh                     = { glyph = '', hl = 'MiniIconsGrey'   },\n  shada                  = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  shaderslang            = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  sicad                  = { glyph = '󰬀', hl = 'MiniIconsPurple' },\n  sieve                  = { glyph = '󰈲', hl = 'MiniIconsOrange' },\n  sil                    = { glyph = '󰛥', hl = 'MiniIconsOrange' },\n  sile                   = { glyph = '󰬀', hl = 'MiniIconsGreen'  },\n  simula                 = { glyph = '󰬀', hl = 'MiniIconsPurple' },\n  sinda                  = { glyph = '󰬀', hl = 'MiniIconsYellow' },\n  sindacmp               = { glyph = '󱒒', hl = 'MiniIconsRed'    },\n  sindaout               = { glyph = '󰬀', hl = 'MiniIconsBlue'   },\n  sisu                   = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  skhd                   = { glyph = '󰬀', hl = 'MiniIconsAzure'  },\n  skill                  = { glyph = '󰬀', hl = 'MiniIconsGrey'   },\n  sl                     = { glyph = '󰟽', hl = 'MiniIconsRed'    },\n  slang                  = { glyph = '󰬀', hl = 'MiniIconsYellow' },\n  slice                  = { glyph = '󰧻', hl = 'MiniIconsGrey'   },\n  slint                  = { glyph = '󰬀', hl = 'MiniIconsAzure'  },\n  slpconf                = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  slpreg                 = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  slpspi                 = { glyph = '󰬀', hl = 'MiniIconsPurple' },\n  slrnrc                 = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  slrnsc                 = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  sm                     = { glyph = '󱃜', hl = 'MiniIconsBlue'   },\n  smali                  = { glyph = '', hl = 'MiniIconsGrey'   },\n  smarty                 = { glyph = '', hl = 'MiniIconsYellow' },\n  smcl                   = { glyph = '󰄨', hl = 'MiniIconsRed'    },\n  smil                   = { glyph = '󰬀', hl = 'MiniIconsOrange' },\n  smith                  = { glyph = '󰬀', hl = 'MiniIconsRed'    },\n  smithy                 = { glyph = '󰬀', hl = 'MiniIconsGrey'   },\n  sml                    = { glyph = '󰘧', hl = 'MiniIconsOrange' },\n  snakemake              = { glyph = '󱔎', hl = 'MiniIconsGreen'  },\n  snnsnet                = { glyph = '󰖟', hl = 'MiniIconsGreen'  },\n  snnspat                = { glyph = '󰬀', hl = 'MiniIconsGreen'  },\n  snnsres                = { glyph = '󰬀', hl = 'MiniIconsBlue'   },\n  snobol4                = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  solidity               = { glyph = '', hl = 'MiniIconsAzure'  },\n  solution               = { glyph = '󰘐', hl = 'MiniIconsBlue'   },\n  soy                    = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  spajson                = { glyph = '󰘦', hl = 'MiniIconsPurple' },\n  sparql                 = { glyph = '󰬀', hl = 'MiniIconsRed'    },\n  spec                   = { glyph = '', hl = 'MiniIconsBlue'   },\n  specman                = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  spice                  = { glyph = '󰬀', hl = 'MiniIconsOrange' },\n  splint                 = { glyph = '󰙱', hl = 'MiniIconsGreen'  },\n  spup                   = { glyph = '󰬀', hl = 'MiniIconsOrange' },\n  spyce                  = { glyph = '󰬀', hl = 'MiniIconsRed'    },\n  sql                    = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  sqlanywhere            = { glyph = '󰆼', hl = 'MiniIconsAzure'  },\n  sqlforms               = { glyph = '󰆼', hl = 'MiniIconsOrange' },\n  sqlhana                = { glyph = '󰆼', hl = 'MiniIconsPurple' },\n  sqlinformix            = { glyph = '󰆼', hl = 'MiniIconsBlue'   },\n  sqlj                   = { glyph = '󰆼', hl = 'MiniIconsGrey'   },\n  sqloracle              = { glyph = '󰆼', hl = 'MiniIconsOrange' },\n  sqr                    = { glyph = '󰬀', hl = 'MiniIconsGrey'   },\n  squid                  = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  squirrel               = { glyph = '', hl = 'MiniIconsGrey'   },\n  srec                   = { glyph = '󰍛', hl = 'MiniIconsAzure'  },\n  srt                    = { glyph = '󰨖', hl = 'MiniIconsYellow' },\n  ssa                    = { glyph = '󰨖', hl = 'MiniIconsOrange' },\n  sshconfig              = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  sshdconfig             = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  st                     = { glyph = '󰄚', hl = 'MiniIconsOrange' },\n  starlark               = { glyph = '', hl = 'MiniIconsRed'    },\n  stata                  = { glyph = '󰝫', hl = 'MiniIconsRed'    },\n  stp                    = { glyph = '󰬀', hl = 'MiniIconsYellow' },\n  strace                 = { glyph = '󰬀', hl = 'MiniIconsPurple' },\n  structurizr            = { glyph = '󰬀', hl = 'MiniIconsBlue'   },\n  stylus                 = { glyph = '󰴒', hl = 'MiniIconsGrey'   },\n  sudoers                = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  supercollider          = { glyph = '󰆦', hl = 'MiniIconsGrey'   },\n  superhtml              = { glyph = '󰌝', hl = 'MiniIconsPurple' },\n  surface                = { glyph = '󰬀', hl = 'MiniIconsRed'    },\n  svelte                 = { glyph = '', hl = 'MiniIconsOrange' },\n  svg                    = { glyph = '󰜡', hl = 'MiniIconsYellow' },\n  svn                    = { glyph = '󰜘', hl = 'MiniIconsOrange' },\n  sway                   = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  swayconfig             = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  swift                  = { glyph = '󰛥', hl = 'MiniIconsOrange' },\n  swiftgyb               = { glyph = '󰛥', hl = 'MiniIconsYellow' },\n  swig                   = { glyph = '󰬀', hl = 'MiniIconsGreen'  },\n  sysctl                 = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  sysml                  = { glyph = '󰬀', hl = 'MiniIconsCyan'   },\n  systemd                = { glyph = '', hl = 'MiniIconsGrey'   },\n  systemverilog          = { glyph = '󰍛', hl = 'MiniIconsGreen'  },\n  tablegen               = { glyph = '󰬁', hl = 'MiniIconsGrey'   },\n  tads                   = { glyph = '󱩼', hl = 'MiniIconsAzure'  },\n  tags                   = { glyph = '󰓻', hl = 'MiniIconsGreen'  },\n  tak                    = { glyph = '󰔏', hl = 'MiniIconsRed'    },\n  takcmp                 = { glyph = '󰔏', hl = 'MiniIconsGreen'  },\n  takout                 = { glyph = '󰔏', hl = 'MiniIconsBlue'   },\n  tal                    = { glyph = '󰬁', hl = 'MiniIconsBlue'   },\n  tap                    = { glyph = '󰬁', hl = 'MiniIconsAzure'  },\n  tar                    = { glyph = '󰬁', hl = 'MiniIconsCyan'   },\n  taskdata               = { glyph = '󱒋', hl = 'MiniIconsPurple' },\n  taskedit               = { glyph = '󰬁', hl = 'MiniIconsAzure'  },\n  tasm                   = { glyph = '', hl = 'MiniIconsPurple' },\n  tcl                    = { glyph = '󰛓', hl = 'MiniIconsRed'    },\n  tcsh                   = { glyph = '', hl = 'MiniIconsAzure'  },\n  teal                   = { glyph = '󰢱', hl = 'MiniIconsCyan'   },\n  templ                  = { glyph = '󰬁', hl = 'MiniIconsAzure'  },\n  template               = { glyph = '󰬁', hl = 'MiniIconsGreen'  },\n  tera                   = { glyph = '󰬁', hl = 'MiniIconsAzure'  },\n  teraterm               = { glyph = '󰅭', hl = 'MiniIconsGreen'  },\n  terminfo               = { glyph = '', hl = 'MiniIconsGrey'   },\n  terraform              = { glyph = '󱁢', hl = 'MiniIconsBlue'   },\n  ['terraform-vars']     = { glyph = '󱁢', hl = 'MiniIconsAzure'  },\n  tex                    = { glyph = '', hl = 'MiniIconsGreen'  },\n  texinfo                = { glyph = '', hl = 'MiniIconsAzure'  },\n  texmf                  = { glyph = '󰒓', hl = 'MiniIconsPurple' },\n  text                   = { glyph = '󰦪', hl = 'MiniIconsYellow' },\n  tf                     = { glyph = '󰬁', hl = 'MiniIconsRed'    },\n  thrift                 = { glyph = '󰬁', hl = 'MiniIconsPurple' },\n  tiasm                  = { glyph = '', hl = 'MiniIconsCyan'   },\n  tidy                   = { glyph = '󰌝', hl = 'MiniIconsBlue'   },\n  tiger                  = { glyph = '󰄛', hl = 'MiniIconsOrange' },\n  tilde                  = { glyph = '󰜥', hl = 'MiniIconsRed'    },\n  tiltfile               = { glyph = '󰬁', hl = 'MiniIconsYellow' },\n  tla                    = { glyph = '󰬁', hl = 'MiniIconsAzure'  },\n  tli                    = { glyph = '󰬁', hl = 'MiniIconsCyan'   },\n  tmux                   = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  toml                   = { glyph = '', hl = 'MiniIconsOrange' },\n  tpp                    = { glyph = '󰐨', hl = 'MiniIconsPurple' },\n  trace32                = { glyph = '󰬁', hl = 'MiniIconsCyan'   },\n  trasys                 = { glyph = '󰬁', hl = 'MiniIconsBlue'   },\n  treetop                = { glyph = '󰔱', hl = 'MiniIconsGreen'  },\n  trig                   = { glyph = '󱁉', hl = 'MiniIconsYellow' },\n  trustees               = { glyph = '󰬁', hl = 'MiniIconsPurple' },\n  tsalt                  = { glyph = '󰬁', hl = 'MiniIconsPurple' },\n  tsscl                  = { glyph = '󱣖', hl = 'MiniIconsGreen'  },\n  tssgm                  = { glyph = '󱣖', hl = 'MiniIconsYellow' },\n  tssop                  = { glyph = '󱣖', hl = 'MiniIconsGrey'   },\n  tsv                    = { glyph = '', hl = 'MiniIconsBlue'   },\n  tt2                    = { glyph = '', hl = 'MiniIconsAzure'  },\n  tt2html                = { glyph = '', hl = 'MiniIconsOrange' },\n  tt2js                  = { glyph = '', hl = 'MiniIconsYellow' },\n  turtle                 = { glyph = '󰳗', hl = 'MiniIconsGreen'  },\n  tutor                  = { glyph = '󱆀', hl = 'MiniIconsPurple' },\n  twig                   = { glyph = '', hl = 'MiniIconsGreen'  },\n  typescript             = { glyph = '󰛦', hl = 'MiniIconsAzure'  },\n  ['typescript.glimmer'] = { glyph = '󰛦', hl = 'MiniIconsRed'    },\n  typescriptreact        = { glyph = '', hl = 'MiniIconsBlue'   },\n  typespec               = { glyph = '󰬁', hl = 'MiniIconsPurple' },\n  typst                  = { glyph = '󰬛', hl = 'MiniIconsAzure'  },\n  uc                     = { glyph = '󰬂', hl = 'MiniIconsGrey'   },\n  uci                    = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  udevconf               = { glyph = '󰒓', hl = 'MiniIconsOrange' },\n  udevperm               = { glyph = '󰬂', hl = 'MiniIconsOrange' },\n  udevrules              = { glyph = '󰬂', hl = 'MiniIconsBlue'   },\n  uil                    = { glyph = '󰬂', hl = 'MiniIconsGrey'   },\n  ungrammar              = { glyph = '󱘎', hl = 'MiniIconsYellow' },\n  unison                 = { glyph = '󰡉', hl = 'MiniIconsYellow' },\n  updatedb               = { glyph = '󰒓', hl = 'MiniIconsGrey'   },\n  upstart                = { glyph = '󰬂', hl = 'MiniIconsCyan'   },\n  upstreamdat            = { glyph = '󰬂', hl = 'MiniIconsGreen'  },\n  upstreaminstalllog     = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  upstreamlog            = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  upstreamrpt            = { glyph = '󰬂', hl = 'MiniIconsYellow' },\n  urlshortcut            = { glyph = '󰌷', hl = 'MiniIconsPurple' },\n  usd                    = { glyph = '󰻇', hl = 'MiniIconsAzure'  },\n  usserverlog            = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  usw2kagtlog            = { glyph = '󰷐', hl = 'MiniIconsBlue'   },\n  v                      = { glyph = '', hl = 'MiniIconsBlue'   },\n  vala                   = { glyph = '󰬝', hl = 'MiniIconsPurple' },\n  valgrind               = { glyph = '󰍛', hl = 'MiniIconsGrey'   },\n  vb                     = { glyph = '󰛤', hl = 'MiniIconsPurple' },\n  vdf                    = { glyph = '󰬃', hl = 'MiniIconsCyan'   },\n  vdmpp                  = { glyph = '󱂌', hl = 'MiniIconsYellow' },\n  vdmrt                  = { glyph = '󱂌', hl = 'MiniIconsGreen'  },\n  vdmsl                  = { glyph = '󱂌', hl = 'MiniIconsAzure'  },\n  vento                  = { glyph = '󱂌', hl = 'MiniIconsPurple' },\n  vera                   = { glyph = '󰬃', hl = 'MiniIconsCyan'   },\n  verilog                = { glyph = '󰍛', hl = 'MiniIconsGreen'  },\n  verilogams             = { glyph = '󰍛', hl = 'MiniIconsGreen'  },\n  vgrindefs              = { glyph = '󰬃', hl = 'MiniIconsPurple' },\n  vhdl                   = { glyph = '󰍛', hl = 'MiniIconsGreen'  },\n  vhs                    = { glyph = '󰨛', hl = 'MiniIconsBlue'   },\n  vim                    = { glyph = '', hl = 'MiniIconsGreen'  },\n  viminfo                = { glyph = '', hl = 'MiniIconsBlue'   },\n  virata                 = { glyph = '󰒓', hl = 'MiniIconsCyan'   },\n  vmasm                  = { glyph = '', hl = 'MiniIconsPurple' },\n  voscm                  = { glyph = '󰬃', hl = 'MiniIconsCyan'   },\n  vrml                   = { glyph = '󰬃', hl = 'MiniIconsBlue'   },\n  vroom                  = { glyph = '', hl = 'MiniIconsOrange' },\n  vsejcl                 = { glyph = '󰬃', hl = 'MiniIconsCyan'   },\n  vue                    = { glyph = '󰡄', hl = 'MiniIconsGreen'  },\n  wat                    = { glyph = '', hl = 'MiniIconsPurple' },\n  wdiff                  = { glyph = '󰦓', hl = 'MiniIconsBlue'   },\n  wdl                    = { glyph = '󰬄', hl = 'MiniIconsGrey'   },\n  web                    = { glyph = '󰯊', hl = 'MiniIconsGrey'   },\n  webmacro               = { glyph = '󰬄', hl = 'MiniIconsCyan'   },\n  wget                   = { glyph = '󰒓', hl = 'MiniIconsYellow' },\n  wget2                  = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  wgsl                   = { glyph = '󰬄', hl = 'MiniIconsBlue'   },\n  winbatch               = { glyph = '󰯂', hl = 'MiniIconsBlue'   },\n  wit                    = { glyph = '', hl = 'MiniIconsCyan'   },\n  wml                    = { glyph = '󰖟', hl = 'MiniIconsGreen'  },\n  wsh                    = { glyph = '󰯂', hl = 'MiniIconsPurple' },\n  wsml                   = { glyph = '󰬄', hl = 'MiniIconsAzure'  },\n  wvdial                 = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  xbl                    = { glyph = '󰬅', hl = 'MiniIconsAzure'  },\n  xcompose               = { glyph = '󰌌', hl = 'MiniIconsOrange' },\n  xdefaults              = { glyph = '󰒓', hl = 'MiniIconsBlue'   },\n  xf86conf               = { glyph = '󰒓', hl = 'MiniIconsAzure'  },\n  xhtml                  = { glyph = '󰌝', hl = 'MiniIconsOrange' },\n  xinetd                 = { glyph = '󰒓', hl = 'MiniIconsGreen'  },\n  xkb                    = { glyph = '󰌌', hl = 'MiniIconsPurple' },\n  xmath                  = { glyph = '󰬅', hl = 'MiniIconsYellow' },\n  xml                    = { glyph = '󰗀', hl = 'MiniIconsOrange' },\n  xmodmap                = { glyph = '󰬅', hl = 'MiniIconsCyan'   },\n  xpm                    = { glyph = '󰍹', hl = 'MiniIconsYellow' },\n  xpm2                   = { glyph = '󰍹', hl = 'MiniIconsGreen'  },\n  xquery                 = { glyph = '󰗀', hl = 'MiniIconsAzure'  },\n  xs                     = { glyph = '', hl = 'MiniIconsRed'    },\n  xsd                    = { glyph = '󰗀', hl = 'MiniIconsYellow' },\n  xslt                   = { glyph = '󰗀', hl = 'MiniIconsGreen'  },\n  xxd                    = { glyph = '󰬅', hl = 'MiniIconsBlue'   },\n  yacc                   = { glyph = '󰬆', hl = 'MiniIconsOrange' },\n  yaml                   = { glyph = '', hl = 'MiniIconsPurple' },\n  yang                   = { glyph = '󰬆', hl = 'MiniIconsCyan'   },\n  yuck                   = { glyph = '󰬆', hl = 'MiniIconsYellow' },\n  z8a                    = { glyph = '', hl = 'MiniIconsGrey'   },\n  zathurarc              = { glyph = '󰒓', hl = 'MiniIconsRed'    },\n  zig                    = { glyph = '', hl = 'MiniIconsOrange' },\n  ziggy                  = { glyph = '󰬇', hl = 'MiniIconsBlue'   },\n  ziggy_schema           = { glyph = '󰬇', hl = 'MiniIconsAzure'  },\n  zimbu                  = { glyph = '󰬇', hl = 'MiniIconsGreen'  },\n  zimbutempl             = { glyph = '󰬇', hl = 'MiniIconsOrange' },\n  zip                    = { glyph = '󰗄', hl = 'MiniIconsGreen'  },\n  zir                    = { glyph = '', hl = 'MiniIconsOrange' },\n  zserio                 = { glyph = '󰬇', hl = 'MiniIconsGrey'   },\n  zsh                    = { glyph = '', hl = 'MiniIconsGreen'  },\n\n  -- Popular filetype which require user configuration\n  helm                    = { glyph = '󰠳', hl = 'MiniIconsBlue'   },\n  ['yaml.ansible']        = { glyph = '󱂚', hl = 'MiniIconsGrey'   },\n  ['yaml.docker-compose'] = { glyph = '󰡨', hl = 'MiniIconsYellow' },\n\n  -- 'mini.nvim'\n  ['minideps-confirm']   = { glyph = '', hl = 'MiniIconsOrange' },\n  minifiles              = { glyph = '', hl = 'MiniIconsGreen'  },\n  ['minifiles-help']     = { glyph = '', hl = 'MiniIconsGreen'  },\n  mininotify             = { glyph = '', hl = 'MiniIconsYellow' },\n  ['mininotify-history'] = { glyph = '', hl = 'MiniIconsYellow' },\n  minipick               = { glyph = '', hl = 'MiniIconsCyan'   },\n  ministarter            = { glyph = '', hl = 'MiniIconsAzure'  },\n\n  -- Popular Lua plugins which have a dedicated \"current window\" workflow (i.e.\n  -- when displaying filetype might make sense, especially with 'laststatus=3')\n  aerial                   = { glyph = '󱘎', hl = 'MiniIconsPurple' },\n  alpha                    = { glyph = '󰀫', hl = 'MiniIconsOrange' },\n  dapui_breakpoints        = { glyph = '󰃤', hl = 'MiniIconsRed'    },\n  dapui_console            = { glyph = '󰃤', hl = 'MiniIconsRed'    },\n  dapui_hover              = { glyph = '󰃤', hl = 'MiniIconsRed'    },\n  dapui_scopes             = { glyph = '󰃤', hl = 'MiniIconsRed'    },\n  dapui_stacks             = { glyph = '󰃤', hl = 'MiniIconsRed'    },\n  dapui_watches            = { glyph = '󰃤', hl = 'MiniIconsRed'    },\n  dashboard                = { glyph = '󰕮', hl = 'MiniIconsOrange' },\n  edgy                     = { glyph = '󰛺', hl = 'MiniIconsGrey'   },\n  fzf                      = { glyph = '󱡠', hl = 'MiniIconsAzure'  },\n  harpoon                  = { glyph = '󱡀', hl = 'MiniIconsCyan'   },\n  lazy                     = { glyph = '󰒲', hl = 'MiniIconsBlue'   },\n  mason                    = { glyph = '󱌢', hl = 'MiniIconsGrey'   },\n  ['neo-tree']             = { glyph = '󰙅', hl = 'MiniIconsYellow' },\n  ['neo-tree-popup']       = { glyph = '󰙅', hl = 'MiniIconsYellow' },\n  neogitcommitselectview   = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitcommitview         = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitconsole            = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitdiffview           = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitgitcommandhistory  = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitlogview            = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitpopup              = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitrebasetodo         = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitreflogview         = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitrefsview           = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  neogitstatus             = { glyph = '󰊢', hl = 'MiniIconsOrange' },\n  ['neotest-output-panel'] = { glyph = '󰱑', hl = 'MiniIconsRed'    },\n  ['neotest-summary']      = { glyph = '󰱑', hl = 'MiniIconsRed'    },\n  nvimtree                 = { glyph = '󰙅', hl = 'MiniIconsGreen'  },\n  oil                      = { glyph = '󰙅', hl = 'MiniIconsPurple' },\n  overseerform             = { glyph = '󰜎', hl = 'MiniIconsBlue'   },\n  overseerlist             = { glyph = '󰜎', hl = 'MiniIconsBlue'   },\n  telescopeprompt          = { glyph = '󰭎', hl = 'MiniIconsAzure'  },\n  trouble                  = { glyph = '󰙅', hl = 'MiniIconsRed'    },\n}\n\n-- LSP kind values (completion item, symbol, etc.) icons.\n-- Use only `nf-cod-*` classes with \"outline\" look. Balance colors.\n--stylua: ignore\nH.lsp_icons = {\n  array         = { glyph = '', hl = 'MiniIconsOrange' },\n  boolean       = { glyph = '', hl = 'MiniIconsOrange' },\n  class         = { glyph = '', hl = 'MiniIconsPurple' },\n  color         = { glyph = '', hl = 'MiniIconsRed'    },\n  constant      = { glyph = '', hl = 'MiniIconsOrange' },\n  constructor   = { glyph = '', hl = 'MiniIconsAzure'  },\n  enum          = { glyph = '', hl = 'MiniIconsPurple' },\n  enummember    = { glyph = '', hl = 'MiniIconsYellow' },\n  event         = { glyph = '', hl = 'MiniIconsRed'    },\n  field         = { glyph = '', hl = 'MiniIconsYellow' },\n  file          = { glyph = '', hl = 'MiniIconsBlue'   },\n  folder        = { glyph = '', hl = 'MiniIconsBlue'   },\n  ['function']  = { glyph = '', hl = 'MiniIconsAzure'  },\n  interface     = { glyph = '', hl = 'MiniIconsPurple' },\n  key           = { glyph = '', hl = 'MiniIconsYellow' },\n  keyword       = { glyph = '', hl = 'MiniIconsCyan'   },\n  method        = { glyph = '', hl = 'MiniIconsAzure'  },\n  module        = { glyph = '', hl = 'MiniIconsPurple' },\n  namespace     = { glyph = '', hl = 'MiniIconsRed'    },\n  null          = { glyph = '', hl = 'MiniIconsGrey'   },\n  number        = { glyph = '', hl = 'MiniIconsOrange' },\n  object        = { glyph = '', hl = 'MiniIconsGrey'   },\n  operator      = { glyph = '', hl = 'MiniIconsCyan'   },\n  package       = { glyph = '', hl = 'MiniIconsPurple' },\n  property      = { glyph = '', hl = 'MiniIconsYellow' },\n  reference     = { glyph = '', hl = 'MiniIconsCyan'   },\n  snippet       = { glyph = '', hl = 'MiniIconsGreen'  },\n  string        = { glyph = '', hl = 'MiniIconsGreen'  },\n  struct        = { glyph = '', hl = 'MiniIconsPurple' },\n  text          = { glyph = '', hl = 'MiniIconsGreen'  },\n  typeparameter = { glyph = '', hl = 'MiniIconsCyan'   },\n  unit          = { glyph = '', hl = 'MiniIconsCyan'   },\n  value         = { glyph = '', hl = 'MiniIconsBlue'   },\n  variable      = { glyph = '', hl = 'MiniIconsCyan'   },\n}\n\n-- OS icons. Keys are for operating systems present as `md-*` class icons, as\n-- this feels representative of \"popular\" operating systems.\n--stylua: ignore\nH.os_icons = {\n  android      = { glyph = '󰀲', hl = 'MiniIconsGreen'  },\n  arch         = { glyph = '󰣇', hl = 'MiniIconsAzure'  },\n  centos       = { glyph = '󱄚', hl = 'MiniIconsRed'    },\n  debian       = { glyph = '󰣚', hl = 'MiniIconsRed'    },\n  fedora       = { glyph = '󰣛', hl = 'MiniIconsBlue'   },\n  freebsd      = { glyph = '󰣠', hl = 'MiniIconsRed'    },\n  gentoo       = { glyph = '󰣨', hl = 'MiniIconsPurple' },\n  ios          = { glyph = '󰀷', hl = 'MiniIconsYellow' },\n  linux        = { glyph = '󰌽', hl = 'MiniIconsCyan'   },\n  macos        = { glyph = '󰀵', hl = 'MiniIconsGrey'   },\n  manjaro      = { glyph = '󱘊', hl = 'MiniIconsGreen'  },\n  mint         = { glyph = '󰣭', hl = 'MiniIconsGreen'  },\n  nixos        = { glyph = '󱄅', hl = 'MiniIconsAzure'  },\n  raspberry_pi = { glyph = '󰐿', hl = 'MiniIconsRed'    },\n  redhat       = { glyph = '󱄛', hl = 'MiniIconsRed'    },\n  ubuntu       = { glyph = '󰕈', hl = 'MiniIconsOrange' },\n  windows      = { glyph = '󰖳', hl = 'MiniIconsBlue'   },\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('style', config.style, 'string')\n  H.check_type('default', config.default, 'table')\n  H.check_type('directory', config.directory, 'table')\n  H.check_type('extension', config.extension, 'table')\n  H.check_type('file', config.file, 'table')\n  H.check_type('filetype', config.filetype, 'table')\n  H.check_type('lsp', config.lsp, 'table')\n  H.check_type('os', config.os, 'table')\n  H.check_type('use_file_extension', config.use_file_extension, 'function')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniIcons.config = config\n\n  -- Initialize cache for quicker `get()`\n  H.init_cache(config)\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniIcons', {})\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  hi('MiniIconsAzure', { link = 'Function' })\n  hi('MiniIconsBlue', { link = 'DiagnosticInfo' })\n  hi('MiniIconsCyan', { link = 'DiagnosticHint' })\n  hi('MiniIconsGreen', { link = 'DiagnosticOk' })\n  hi('MiniIconsGrey', {})\n  hi('MiniIconsOrange', { link = 'DiagnosticWarn' })\n  hi('MiniIconsPurple', { link = 'Constant' })\n  hi('MiniIconsRed', { link = 'DiagnosticError' })\n  hi('MiniIconsYellow', { link = 'DiagnosticWarn' })\nend\n\n-- Cache ----------------------------------------------------------------------\nH.init_cache = function(config)\n  -- NOTE: process in 'filetype' - 'extension' - 'file' order because previous\n  -- might be used to infer missing data in the next\n  local categories = { 'directory', 'filetype', 'extension', 'file', 'lsp', 'os' }\n\n  H.cache, H.cache_index, H.cache_index_lookup = { default = {} }, {}, {}\n  for _, cat in ipairs(categories) do\n    -- Set \"default\" category\n    local icon_def, hl_def = H.resolve_icon_data('default', cat, config.default[cat])\n    H.cache_set('default', cat, icon_def, hl_def)\n\n    -- Set custom icons while ensuring proper \"fallback\" category index entry\n    table.insert(H.cache_index, { icon_def, hl_def, true })\n    H.cache[cat] = { [true] = #H.cache_index }\n    for name, icon_data in pairs(config[cat]) do\n      local icon, hl = H.resolve_icon_data(cat, name, icon_data)\n      H.cache_set(cat, name, icon, hl)\n    end\n  end\n  local icon_def_def, hl_def_def = H.resolve_icon_data('default', 'default', config.default.default)\n  H.cache_set('default', 'default', icon_def_def, hl_def_def)\nend\n\nH.resolve_icon_data = function(category, name, icon_data)\n  if type(name) ~= 'string' then return nil end\n\n  icon_data = type(icon_data) == 'table' and icon_data or {}\n  local glyph, hl = icon_data.glyph, icon_data.hl\n\n  -- Allow customizing only one characteristic with proper fallback\n  local has_glyph, has_hl = type(glyph) == 'string', type(hl) == 'string'\n  local builtin_glyph, builtin_hl = '', ''\n  if not (has_glyph and has_hl) then\n    if category == 'default' then\n      builtin_glyph, builtin_hl = H.default_icons[name].glyph, H.default_icons[name].hl\n    else\n      builtin_glyph, builtin_hl = MiniIcons.get(category, name)\n    end\n  end\n  return H.style_icon(has_glyph and glyph or builtin_glyph, name), has_hl and hl or builtin_hl\nend\n\nH.cache_get = function(cat, name) return H.cache_index[H.cache[cat][name]] end\n\nH.cache_set = function(cat, name, icon, hl)\n  -- Process category fallback icon separatly\n  if icon == nil then\n    local fallback_id = H.cache[cat][true]\n    H.cache[cat][name] = fallback_id\n    local t = H.cache_index[fallback_id]\n    return t[1], t[2], true\n  end\n\n  -- Compute/ensure cache index\n  local id = (H.cache_index_lookup[hl] or {})[icon]\n  if id == nil then\n    -- Add new unique 'icon-hl'\n    table.insert(H.cache_index, { icon, hl })\n    id = #H.cache_index\n\n    -- Add corresponding lookup entry\n    local hl_icons = H.cache_index_lookup[hl] or {}\n    hl_icons[icon] = id\n    H.cache_index_lookup[hl] = hl_icons\n  end\n\n  -- Add to cache and return result tuple\n  H.cache[cat][name] = id\n  return icon, hl, false\nend\n\n-- Getters --------------------------------------------------------------------\nH.get_impl = {\n  default = function(name) H.error(vim.inspect(name) .. ' is not a supported category.') end,\n  directory = function(name) return H.directory_icons[name] end,\n  extension = function(name)\n    -- Built-in extensions\n    local icon_data = H.extension_icons[name]\n    if type(icon_data) == 'string' then return MiniIcons.get('filetype', icon_data) end\n    if icon_data ~= nil then return icon_data end\n\n    -- Parts of complex extension (if can be recognized)\n    local dot = string.find(name, '%..')\n    while dot ~= nil do\n      local ext = name:sub(dot + 1)\n      if H.extension_icons[ext] or MiniIcons.config.extension[ext] then return MiniIcons.get('extension', ext) end\n      dot = string.find(name, '%..', dot + 1)\n    end\n\n    -- Fall back to built-in filetype matching using generic filename\n    local ft = H.filetype_match('aaa.' .. name)\n    if ft ~= nil then return MiniIcons.get('filetype', ft) end\n  end,\n  file = function(name)\n    local basename = H.fs_basename(name)\n\n    -- User configured file names\n    if MiniIcons.config.file[basename] ~= nil and name ~= basename then return MiniIcons.get('file', basename) end\n\n    -- Built-in file names\n    local icon_data = H.file_icons[basename]\n    if type(icon_data) == 'string' then return MiniIcons.get('filetype', icon_data) end\n    -- - Style icon based on the basename and not full name\n    if icon_data ~= nil then return H.style_icon(icon_data.glyph, basename), icon_data.hl end\n\n    -- Basename extensions. Prefer this before `vim.filetype.match()` for speed\n    -- (as the latter is slow-ish; like 0.1 ms in Neovim<0.11)\n    local dot = string.find(basename, '%..', 2)\n    if dot ~= nil then\n      local ext = basename:sub(dot + 1):lower()\n      if MiniIcons.config.use_file_extension(ext, name) == true then\n        local icon, hl, is_default = MiniIcons.get('extension', ext)\n        if not is_default then return icon, hl end\n      end\n    end\n\n    -- Fall back to built-in filetype matching with full supplied name (matters\n    -- when full path is supplied to match complex filetype patterns)\n    local ft = H.filetype_match(name)\n    if ft ~= nil then return MiniIcons.get('filetype', ft) end\n  end,\n  filetype = function(name) return H.filetype_icons[name] end,\n  lsp = function(name) return H.lsp_icons[name] end,\n  os = function(name) return H.os_icons[name] end,\n}\n\nH.str_byteindex = function(s, i) return vim.str_byteindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_byteindex = function(s, i) return vim.str_byteindex(s, i) end end\n\nH.style_icon = function(glyph, name)\n  if MiniIcons.config.style ~= 'ascii' then return glyph end\n  -- Use `vim.str_byteindex()` and `vim.fn.toupper()` for multibyte characters\n  return vim.fn.toupper(name:sub(1, H.str_byteindex(name, 1)))\nend\n\nH.filetype_match = function(filename)\n  -- Ensure always present scratch buffer to be used in `vim.filetype.match()`\n  -- (needed because the function in many ambiguous cases prefers to return\n  -- nothing if there is no buffer supplied)\n  local buf_id = H.scratch_buf_id\n  if buf_id == nil or not vim.api.nvim_buf_is_valid(buf_id) then\n    buf_id = vim.api.nvim_create_buf(false, true)\n    H.set_buf_name(buf_id, 'filetype-match-scratch')\n    H.scratch_buf_id = buf_id\n  end\n  return vim.filetype.match({ filename = filename, buf = H.scratch_buf_id })\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.icons) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'miniicons://' .. buf_id .. '/' .. name) end\n\nH.notify = function(msg, level_name) vim.notify('(mini.icons) ' .. msg, vim.log.levels[level_name]) end\n\nH.fs_basename = function(x) return vim.fn.fnamemodify(x:sub(-1, -1) == '/' and x:sub(1, -2) or x, ':t') end\nif vim.loop.os_uname().sysname == 'Windows_NT' then\n  H.fs_basename = function(x)\n    local last = x:sub(-1, -1)\n    return vim.fn.fnamemodify((last == '/' or last == '\\\\') and x:sub(1, -2) or x, ':t')\n  end\nend\n\n-- Initialize cache right away to allow using `get()` without `setup()`\nH.init_cache(MiniIcons.config)\n\nreturn MiniIcons\n"
  },
  {
    "path": "lua/mini/indentscope.lua",
    "content": "--- *mini.indentscope* Visualize and work with indent scope\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Indent scope (or just \"scope\") is a maximum set of consecutive lines which\n--- contains certain reference line (cursor line by default) and every member\n--- has indent not less than certain reference indent (\"indent at cursor\" by\n--- default: minimum between cursor column and indent of cursor line).\n---\n--- Features:\n--- - Visualize scope with animated vertical line. It is very fast and done\n---   automatically in a non-blocking way (other operations can be performed,\n---   like moving cursor). You can customize debounce delay and animation rule.\n---\n--- - Customization of scope computation options can be done on global level\n---   (in |MiniIndentscope.config|), for a certain buffer (using\n---   `vim.b.miniindentscope_config` buffer variable), or within a call (using\n---   `opts` variable in |MiniIndentscope.get_scope()|).\n---\n--- - Customizable notion of a border: which adjacent lines with strictly lower\n---   indent are recognized as such. This is useful for a certain filetypes\n---   (for example, Python or plain text).\n---\n--- - Customizable way of line to be considered \"border first\". This is useful\n---   if you want to place cursor on function header and get scope of its body.\n---\n--- - There are textobjects and motions to operate on scope. Support |count|\n---   and dot-repeat (in operator pending mode).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.indentscope').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniIndentscope` which you can use for scripting or manually (with `:lua\n--- MiniIndentscope.*`).\n---\n--- See |MiniIndentscope.config| for available config settings.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.miniindentscope_config` which should have same structure as\n--- `MiniIndentscope.config`. See |mini.nvim-buffer-local-config| for more\n--- details.\n---\n--- # Comparisons ~\n---\n--- - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim):\n---     - Its main functionality is about showing static guides of indent levels.\n---     - Implementation of 'mini.indentscope' is similar to\n---       'indent-blankline.nvim' (using |extmarks| on first column to be shown\n---       even on blank lines). They can be used simultaneously, but it will\n---       lead to one of the visualizations being on top (hiding) of another.\n---\n--- # Highlight groups ~\n---\n--- - `MiniIndentscopeSymbol` - symbol showing on every line of scope if its\n---   indent is multiple of 'shiftwidth'.\n--- - `MiniIndentscopeSymbolOff` - symbol showing on every line of scope if its\n---   indent is not multiple of 'shiftwidth'.\n---   Default: links to `MiniIndentscopeSymbol`.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable autodrawing, set `vim.g.miniindentscope_disable` (globally) or\n--- `vim.b.miniindentscope_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniIndentscope\n\n--- Draw of scope indicator is done as iterative animation. It has the\n--- following design:\n--- - Draw indicator on origin line (where cursor is at) immediately. Indicator\n---   is visualized as `MiniIndentscope.config.symbol` placed to the right of\n---   scope's border indent. This creates a line from top to bottom scope edges.\n--- - Draw upward and downward concurrently per one line. Progression by one\n---   line in both direction is considered to be one step of animation.\n--- - Before each step wait certain amount of time, which is decided by\n---   \"animation function\". It takes next and total step numbers (both are one\n---   or bigger) and returns number of milliseconds to wait before drawing next\n---   step. Comparing to a more popular \"easing functions\" in animation (input:\n---   duration since animation start; output: percent of animation done), it is\n---   a discrete inverse version of its derivative. Such interface proved to be\n---   more appropriate for kind of task at hand.\n---\n--- # Special cases ~\n---\n--- - When scope to be drawn intersects (same indent, ranges overlap) currently\n---   visible one (at process or finished drawing), drawing is done immediately\n---   without animation. With most common example being typing new text, this\n---   feels more natural.\n--- - Scope for the whole buffer is not drawn as it is isually redundant.\n---   Technically, it can be thought as drawn at column 0 (because border\n---   indent is -1) which is not visible.\n---@tag MiniIndentscope-drawing\n\n-- Module definition ==========================================================\nlocal MiniIndentscope = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniIndentscope.config|.\n---\n---@usage >lua\n---   require('mini.indentscope').setup() -- use default config\n---   -- OR\n---   require('mini.indentscope').setup({}) -- replace {} with your config table\n--- <\nMiniIndentscope.setup = function(config)\n  -- Export module\n  _G.MiniIndentscope = MiniIndentscope\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Options ~\n---\n--- ## Border ~\n---\n--- Field `border` controls which line(s) with smaller indent to categorize\n--- as border. This matters for textobjects and motions.\n--- It also controls how empty lines are treated: they are included in scope\n--- only if followed by a border. Another way of looking at it is that indent\n--- of blank line is computed based on value of `border` option.\n--- Here is an illustration of how `border` works in presence of empty lines: >\n---\n---                              |both|bottom|top|none|\n---   1|function foo()           | 0  |  0   | 0 | 0  |\n---   2|                         | 4  |  0   | 4 | 0  |\n---   3|    print('Hello world') | 4  |  4   | 4 | 4  |\n---   4|                         | 4  |  4   | 2 | 2  |\n---   5|  end                    | 2  |  2   | 2 | 2  |\n--- <\n--- Numbers inside a table are indent values of a line computed with certain\n--- value of `border`. So, for example, a scope with reference line 3 and\n--- right-most column has body range depending on value of `border` option:\n--- - `border` is \"both\":   range is 2-4, border is 1 and 5 with indent 2.\n--- - `border` is \"top\":    range is 2-3, border is 1 with indent 0.\n--- - `border` is \"bottom\": range is 3-4, border is 5 with indent 0.\n--- - `border` is \"none\":   range is 3-3, border is empty with indent `nil`.\n---\n--- ## Indent at cursor ~\n---\n--- Field `indent_at_cursor` controls if cursor position should affect computation\n--- of scope. If `true`, reference indent is a minimum of reference line's indent\n--- and cursor column. In main example, here how scope's body range differs\n--- depending on cursor column and `indent_at_cursor` value (assuming cursor is\n--- on line 3 and it is whole buffer): >\n---\n---   Column\\Option true|false\n---      1 and 2    2-5 | 2-4\n---    3 and more   2-4 | 2-4\n--- <\n--- ## Number of lines ~\n---\n--- Field `n_lines` defines |MiniIndentscope.get_scope()| behavior for how many\n--- lines above/below to check before iteration is stopped. Scope that reached\n--- computation limit has <is_incomplete> field set to `true`. It will also not\n--- be auto drawn with default `config.draw.predicate`.\n---\n--- Lower values will result in better overall performance in exchange for more\n--- frequent incomplete scope computation. Set to `math.huge` for no restriction.\n---\n--- ## Try as border ~\n---\n--- Field `try_as_border` controls how to act when input line can be recognized\n--- as a border of some neighbor indent scope. In main example, when input line\n--- is 1 and can be recognized as border for inner scope, value `try_as_border=true`\n--- means that inner scope will be returned. Similar, for input line 5 inner scope\n--- will be returned if it is recognized as border.\nMiniIndentscope.config = {\n  -- Draw options\n  draw = {\n    -- Delay (in ms) between event and start of drawing scope indicator\n    delay = 100,\n\n    -- Animation rule for scope's first drawing. A function which, given\n    -- next and total step numbers, returns wait time (in ms). See\n    -- |MiniIndentscope.gen_animation| for builtin options. To disable\n    -- animation, use `require('mini.indentscope').gen_animation.none()`.\n    --minidoc_replace_start animation = --<function: implements constant 20ms between steps>,\n    animation = function(s, n) return 20 end,\n    --minidoc_replace_end\n\n    -- Whether to auto draw scope: return `true` to draw, `false` otherwise.\n    -- Default draws only fully computed scope (see `options.n_lines`).\n    predicate = function(scope) return not scope.body.is_incomplete end,\n\n    -- Symbol priority. Increase to display on top of more symbols.\n    priority = 2,\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Textobjects\n    object_scope = 'ii',\n    object_scope_with_border = 'ai',\n\n    -- Motions (jump to respective border line; if not present - body line)\n    goto_top = '[i',\n    goto_bottom = ']i',\n  },\n\n  -- Options which control scope computation\n  options = {\n    -- Type of scope's border: which line(s) with smaller indent to\n    -- categorize as border. Can be one of: 'both', 'top', 'bottom', 'none'.\n    border = 'both',\n\n    -- Whether to use cursor column when computing reference indent.\n    -- Useful to see incremental scopes with horizontal cursor movements.\n    indent_at_cursor = true,\n\n    -- Maximum number of lines above or below within which scope is computed\n    n_lines = 10000,\n\n    -- Whether to first check input line to be a border of adjacent scope.\n    -- Use it if you want to place cursor on function header to get scope of\n    -- its body.\n    try_as_border = false,\n  },\n\n  -- Which character to use for drawing scope indicator\n  symbol = '╎',\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Compute indent scope\n---\n--- Indent scope (or just \"scope\") is a maximum set of consecutive lines which\n--- contains certain reference line (cursor line by default) and every member\n--- has indent not less than certain reference indent (\"indent at column\" by\n--- default). Here \"indent at column\" means minimum between input column value\n--- and indent of reference line. When using cursor column, this allows for a\n--- useful interactive view of nested indent scopes by making horizontal\n--- movements within line.\n---\n--- Options controlling actual computation is taken from these places in order:\n--- - Argument `opts`. Use it to ensure independence from other sources.\n--- - Buffer local variable `vim.b.miniindentscope_config` (`options` field).\n---   Useful to define local behavior (for example, for a certain filetype).\n--- - Global options from |MiniIndentscope.config|.\n---\n--- # Algorithm overview ~\n---\n--- - Compute reference \"indent at column\". Reference line is an input `line`\n---   which might be modified to one of its neighbors if `try_as_border` option\n---   is `true`: if it can be viewed as border of some neighbor scope, it will.\n--- - Process upwards and downwards from reference line searching for line with\n---   indent strictly less than reference one. This is like casting rays up and\n---   down from reference line and reference indent until meeting \"a wall\"\n---   (character to the right of indent or buffer edge). Latest line before\n---   meeting a wall is a respective end of scope body. It always exists because\n---   reference line is a such one.\n---   Casting ray is forced to stop if it goes over `opts.n_lines` lines.\n--- - Based on top and bottom lines with strictly lower indent, construct\n---   scopes's border. The way it is computed is decided based on `border`\n---   option (see |MiniIndentscope.config| for more information).\n--- - Compute border indent as maximum indent of border lines (or reference\n---   indent minus one in case of no border). This is used during drawing\n---   visual indicator.\n---\n--- # Indent computation ~\n---\n--- For every line indent is intended to be computed unambiguously:\n--- - For \"normal\" lines indent is an output of |indent()|.\n--- - Indent is `-1` for imaginary lines 0 and past last line.\n--- - For blank and empty lines indent is computed based on previous\n---   (|prevnonblank()|) and next (|nextnonblank()|) non-blank lines. The way\n---   it is computed is decided based on `border` in order to not include blank\n---   lines at edge of scope's body if there is no border there. See\n---   |MiniIndentscope.config| for a details example.\n---\n---@param line number|nil Input line number (starts from 1). Can be modified to a\n---   neighbor if `try_as_border` is `true`. Default: cursor line.\n---@param col number|nil Column number (starts from 1). Default: if\n---   `indent_at_cursor` option is `true` - cursor column from `curswant` of\n---   |getcurpos()| (allows for more natural behavior on empty lines);\n---   `math.huge` otherwise in order to not incorporate cursor in computation.\n---@param opts table|nil Options to override global or buffer local ones (see\n---   |MiniIndentscope.config|).\n---\n---@return table Table with scope information:\n---   - <body> - table with <top> (top line of scope, inclusive), <bottom>\n---     (bottom line of scope, inclusive), and <indent> (minimum indent within\n---     scope) keys. Line numbers start at 1. Can also have <is_incomplete> key\n---     set to `true` if computation was stopped due to `opts.n_lines` restriction.\n---   - <border> - table with <top> (line of top border, might be `nil`),\n---     <bottom> (line of bottom border, might be `nil`), and <indent> (indent\n---     of border) keys. Line numbers start at 1.\n---   - <buf_id> - identifier of current buffer.\n---   - <reference> - table with <line> (reference line), <column> (reference\n---     column), and <indent> (\"indent at column\") keys.\nMiniIndentscope.get_scope = function(line, col, opts)\n  opts = H.get_config({ options = opts }).options\n\n  -- Compute default `line` and\\or `col`\n  if not (line and col) then\n    local curpos = vim.fn.getcurpos()\n\n    line = line or curpos[2]\n    line = opts.try_as_border and H.border_correctors[opts.border](line, opts) or line\n\n    -- Use `curpos[5]` (`curswant`, see `:h getcurpos()`) to account for blank\n    -- and empty lines.\n    col = col or (opts.indent_at_cursor and curpos[5] or math.huge)\n  end\n\n  -- Compute \"indent at column\"\n  local line_indent = H.get_line_indent(line, opts)\n  local indent = math.min(col, line_indent)\n\n  -- Make early return\n  local body = { indent = indent }\n  if indent <= 0 then\n    body.top, body.bottom, body.indent = 1, vim.fn.line('$'), line_indent\n  else\n    local up_line, up_min_indent, up_is_incomplete = H.cast_ray(line, indent, 'up', opts)\n    local down_line, down_min_indent, down_is_incomplete = H.cast_ray(line, indent, 'down', opts)\n    body.top, body.bottom = up_line, down_line\n    body.indent = math.min(line_indent, up_min_indent, down_min_indent)\n    body.is_incomplete = up_is_incomplete or down_is_incomplete\n  end\n\n  return {\n    body = body,\n    border = H.border_from_body[opts.border](body, opts),\n    buf_id = vim.api.nvim_get_current_buf(),\n    reference = { line = line, column = col, indent = indent },\n  }\nend\n\n--- Draw scope manually\n---\n--- Scope is visualized as a vertical line within scope's body range at column\n--- equal to border indent plus one (or body indent if border is absent).\n--- Numbering starts from one.\n---\n---@param scope table|nil Scope. Default: output of |MiniIndentscope.get_scope()|\n---   with default arguments.\n---@param opts table|nil Options. Currently supported:\n---    - <animation_fun> - animation function for drawing. See\n---      |MiniIndentscope-drawing| and |MiniIndentscope.gen_animation|.\n---    - <priority> - priority number for visualization. See `priority` option\n---      for |nvim_buf_set_extmark()|.\nMiniIndentscope.draw = function(scope, opts)\n  scope = scope or MiniIndentscope.get_scope()\n  local config = H.get_config()\n  local draw_opts =\n    vim.tbl_deep_extend('force', { animation_fun = config.draw.animation, priority = config.draw.priority }, opts or {})\n\n  H.undraw_scope()\n\n  H.current.scope = scope\n  H.draw_scope(scope, draw_opts)\nend\n\n--- Undraw currently visible scope manually\nMiniIndentscope.undraw = function() H.undraw_scope() end\n\n--- Generate builtin animation function\n---\n--- This is a builtin source to generate animation function for usage in\n--- `MiniIndentscope.config.draw.animation`. Most of them are variations of\n--- common easing functions, which provide certain type of progression for\n--- revealing scope visual indicator.\n---\n--- Each field corresponds to one family of progression which can be customized\n--- further by supplying appropriate arguments.\n---\n--- Examples:\n--- - Don't use animation: `MiniIndentscope.gen_animation.none()`\n--- - Use quadratic \"out\" easing with total duration of 1000 ms: >lua\n---\n---   gen_animation.quadratic({ easing = 'out', duration = 1000, unit = 'total' })\n--- <\n---@seealso |MiniIndentscope-drawing| for more information about how drawing is done.\nMiniIndentscope.gen_animation = {}\n\n---@alias __indentscope_animation_opts table|nil Options that control progression. Possible keys:\n---   - <easing> `(string)` - a subtype of progression. One of \"in\"\n---     (accelerating from zero speed), \"out\" (decelerating to zero speed),\n---     \"in-out\" (default; accelerating halfway, decelerating after).\n---   - <duration> `(number)` - duration (in ms) of a unit. Default: 20.\n---   - <unit> `(string)` - which unit's duration `opts.duration` controls. One\n---     of \"step\" (default; ensures average duration of step to be `opts.duration`)\n---     or \"total\" (ensures fixed total duration regardless of scope's range).\n---@alias __indentscope_animation_return function Animation function (see |MiniIndentscope-drawing|).\n\n--- Generate no animation\n---\n--- Show indicator immediately. Same as animation function always returning 0.\nMiniIndentscope.gen_animation.none = function()\n  return function() return 0 end\nend\n\n--- Generate linear progression\n---\n---@param opts __indentscope_animation_opts\n---\n---@return __indentscope_animation_return\nMiniIndentscope.gen_animation.linear = function(opts)\n  return H.animation_arithmetic_powers(0, H.normalize_animation_opts(opts))\nend\n\n--- Generate quadratic progression\n---\n---@param opts __indentscope_animation_opts\n---\n---@return __indentscope_animation_return\nMiniIndentscope.gen_animation.quadratic = function(opts)\n  return H.animation_arithmetic_powers(1, H.normalize_animation_opts(opts))\nend\n\n--- Generate cubic progression\n---\n---@param opts __indentscope_animation_opts\n---\n---@return __indentscope_animation_return\nMiniIndentscope.gen_animation.cubic = function(opts)\n  return H.animation_arithmetic_powers(2, H.normalize_animation_opts(opts))\nend\n\n--- Generate quartic progression\n---\n---@param opts __indentscope_animation_opts\n---\n---@return __indentscope_animation_return\nMiniIndentscope.gen_animation.quartic = function(opts)\n  return H.animation_arithmetic_powers(3, H.normalize_animation_opts(opts))\nend\n\n--- Generate exponential progression\n---\n---@param opts __indentscope_animation_opts\n---\n---@return __indentscope_animation_return\nMiniIndentscope.gen_animation.exponential = function(opts)\n  return H.animation_geometrical_powers(H.normalize_animation_opts(opts))\nend\n\n--- Move cursor within scope\n---\n--- Cursor is placed on a first non-blank character of target line.\n---\n---@param side string One of \"top\" or \"bottom\".\n---@param use_border boolean|nil Whether to move to border or within scope's body.\n---   If particular border is absent, body is used.\n---@param scope table|nil Scope to use. Default: output of |MiniIndentscope.get_scope()|.\nMiniIndentscope.move_cursor = function(side, use_border, scope)\n  scope = scope or MiniIndentscope.get_scope()\n\n  -- This defaults to body's side if it is not present in border\n  local target_line = use_border and scope.border[side] or scope.body[side]\n  target_line = math.min(math.max(target_line, 1), vim.fn.line('$'))\n\n  vim.api.nvim_win_set_cursor(0, { target_line, 0 })\n  -- Move to first non-blank character to allow chaining scopes\n  vim.cmd('normal! ^')\nend\n\n--- Function for motion mappings\n---\n--- Move to a certain side of border. Respects |count| and dot-repeat (in\n--- operator-pending mode). Doesn't move cursor for scope that is not shown\n--- (drawing indent less that zero).\n---\n---@param side string One of \"top\" or \"bottom\".\n---@param add_to_jumplist boolean|nil Whether to add movement to jump list. It is\n---   `true` only for Normal mode mappings.\nMiniIndentscope.operator = function(side, add_to_jumplist)\n  local scope = MiniIndentscope.get_scope()\n\n  -- Don't support scope that can't be shown\n  if H.scope_get_draw_indent(scope) < 0 then return end\n\n  -- Add movement to jump list. Needs remembering `count1` before that because\n  -- it seems to reset it to 1.\n  local count = vim.v.count1\n  if add_to_jumplist then vim.cmd('normal! m`') end\n\n  -- Make sequence of jumps\n  for _ = 1, count do\n    MiniIndentscope.move_cursor(side, true, scope)\n    -- Use `try_as_border = false` to enable chaining\n    scope = MiniIndentscope.get_scope(nil, nil, { try_as_border = false })\n\n    -- Don't support scope that can't be shown\n    if H.scope_get_draw_indent(scope) < 0 then return end\n  end\nend\n\n--- Function for textobject mappings\n---\n--- Respects |count| and dot-repeat (in operator-pending mode). Doesn't work\n--- for scope that is not shown (drawing indent less that zero).\n---\n---@param use_border boolean|nil Whether to include border in textobject. When\n---   `true` and `try_as_border` option is `false`, allows \"chaining\" calls for\n---   incremental selection.\nMiniIndentscope.textobject = function(use_border)\n  local scope = MiniIndentscope.get_scope()\n\n  -- Don't support scope that can't be shown\n  if H.scope_get_draw_indent(scope) < 0 then return end\n\n  -- Allow chaining only if using border\n  local count = use_border and vim.v.count1 or 1\n\n  -- Make sequence of incremental selections\n  for _ = 1, count do\n    -- Try finish cursor on border\n    local start, finish = 'top', 'bottom'\n    if use_border and scope.border.bottom == nil then\n      start, finish = 'bottom', 'top'\n    end\n\n    H.exit_visual_mode()\n    MiniIndentscope.move_cursor(start, use_border, scope)\n    vim.cmd('normal! V')\n    MiniIndentscope.move_cursor(finish, use_border, scope)\n\n    -- Use `try_as_border = false` to enable chaining\n    scope = MiniIndentscope.get_scope(nil, nil, { try_as_border = false })\n\n    -- Don't support scope that can't be shown\n    if H.scope_get_draw_indent(scope) < 0 then return end\n  end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniIndentscope.config)\n\n-- Namespace for drawing vertical line\nH.ns_id = vim.api.nvim_create_namespace('MiniIndentscope')\n\n-- Timer for doing animation\nH.timer = vim.loop.new_timer()\n\n-- Table with current relevalnt data:\n-- - `event_id` - counter for events.\n-- - `scope` - latest drawn scope.\n-- - `draw_status` - status of current drawing.\nH.current = { event_id = 0, scope = {}, draw_status = 'none' }\n\n-- Functions to compute indent in ambiguous cases\nH.indent_funs = {\n  ['min'] = function(top_indent, bottom_indent) return math.min(top_indent, bottom_indent) end,\n  ['max'] = function(top_indent, bottom_indent) return math.max(top_indent, bottom_indent) end,\n  ['top'] = function(top_indent, bottom_indent) return top_indent end,\n  ['bottom'] = function(top_indent, bottom_indent) return bottom_indent end,\n}\n\n-- Functions to compute indent of blank line to satisfy `config.options.border`\nH.blank_indent_funs = {\n  ['none'] = H.indent_funs.min,\n  ['top'] = H.indent_funs.bottom,\n  ['bottom'] = H.indent_funs.top,\n  ['both'] = H.indent_funs.max,\n}\n\n-- Functions to compute border from body\nH.border_from_body = {\n  ['none'] = function(body, opts) return {} end,\n  ['top'] = function(body, opts) return { top = body.top - 1, indent = H.get_line_indent(body.top - 1, opts) } end,\n  ['bottom'] = function(body, opts)\n    return { bottom = body.bottom + 1, indent = H.get_line_indent(body.bottom + 1, opts) }\n  end,\n  ['both'] = function(body, opts)\n    return {\n      top = body.top - 1,\n      bottom = body.bottom + 1,\n      indent = math.max(H.get_line_indent(body.top - 1, opts), H.get_line_indent(body.bottom + 1, opts)),\n    }\n  end,\n}\n\n-- Functions to correct line in case it is a border\nH.border_correctors = {\n  ['none'] = function(line, opts) return line end,\n  ['top'] = function(line, opts)\n    local cur_indent, next_indent = H.get_line_indent(line, opts), H.get_line_indent(line + 1, opts)\n    return (cur_indent < next_indent) and (line + 1) or line\n  end,\n  ['bottom'] = function(line, opts)\n    local prev_indent, cur_indent = H.get_line_indent(line - 1, opts), H.get_line_indent(line, opts)\n    return (cur_indent < prev_indent) and (line - 1) or line\n  end,\n  ['both'] = function(line, opts)\n    local prev_indent, cur_indent, next_indent =\n      H.get_line_indent(line - 1, opts), H.get_line_indent(line, opts), H.get_line_indent(line + 1, opts)\n\n    if prev_indent <= cur_indent and next_indent <= cur_indent then return line end\n\n    -- If prev and next indents are equal and bigger than current, prefer next\n    if prev_indent <= next_indent then return line + 1 end\n\n    return line - 1\n  end,\n}\n\n-- Whether or not Nvim supports the virt_text_repeat_linebreak extmark feature\nH.has_wrapped_virt_text = vim.fn.has('nvim-0.10') == 1\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('draw', config.draw, 'table')\n  H.check_type('draw.delay', config.draw.delay, 'number')\n  H.check_type('draw.animation', config.draw.animation, 'function')\n  H.check_type('draw.predicate', config.draw.predicate, 'function')\n  H.check_type('draw.priority', config.draw.priority, 'number')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.object_scope', config.mappings.object_scope, 'string')\n  H.check_type('mappings.object_scope_with_border', config.mappings.object_scope_with_border, 'string')\n  H.check_type('mappings.goto_top', config.mappings.goto_top, 'string')\n  H.check_type('mappings.goto_bottom', config.mappings.goto_bottom, 'string')\n\n  H.check_type('options', config.options, 'table')\n  H.check_type('options.border', config.options.border, 'string')\n  H.check_type('options.indent_at_cursor', config.options.indent_at_cursor, 'boolean')\n  H.check_type('options.n_lines', config.options.n_lines, 'number')\n  H.check_type('options.try_as_border', config.options.try_as_border, 'boolean')\n\n  H.check_type('symbol', config.symbol, 'string')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniIndentscope.config = config\n  local maps = config.mappings\n\n  --stylua: ignore start\n  H.map('n', maps.goto_top, [[<Cmd>lua MiniIndentscope.operator('top', true)<CR>]], { desc = 'Go to indent scope top' })\n  H.map('n', maps.goto_bottom, [[<Cmd>lua MiniIndentscope.operator('bottom', true)<CR>]], { desc = 'Go to indent scope bottom' })\n\n  H.map('x', maps.goto_top, [[<Cmd>lua MiniIndentscope.operator('top')<CR>]], { desc = 'Go to indent scope top' })\n  H.map('x', maps.goto_bottom, [[<Cmd>lua MiniIndentscope.operator('bottom')<CR>]], { desc = 'Go to indent scope bottom' })\n  H.map('x', maps.object_scope, '<Cmd>lua MiniIndentscope.textobject(false)<CR>', { desc = 'Object scope' })\n  H.map('x', maps.object_scope_with_border, '<Cmd>lua MiniIndentscope.textobject(true)<CR>', { desc = 'Object scope with border' })\n\n  -- Use `<Cmd>...<CR>` to have proper dot-repeat\n  -- See https://github.com/neovim/neovim/issues/23406\n  -- TODO: use local functions if/when that issue is resolved\n  H.map('o', maps.goto_top, [[<Cmd>lua MiniIndentscope.operator('top')<CR>]], { desc = 'Go to indent scope top' })\n  H.map('o', maps.goto_bottom, [[<Cmd>lua MiniIndentscope.operator('bottom')<CR>]], { desc = 'Go to indent scope bottom' })\n  H.map('o', maps.object_scope, '<Cmd>lua MiniIndentscope.textobject(false)<CR>', { desc = 'Object scope' })\n  H.map('o', maps.object_scope_with_border, '<Cmd>lua MiniIndentscope.textobject(true)<CR>', { desc = 'Object scope with border' })\n  --stylua: ignore start\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniIndentscope', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  local lazy_events = { 'CursorMoved', 'CursorMovedI', 'ModeChanged' }\n  au(lazy_events, '*', function() H.auto_draw({ lazy = true }) end, 'Auto draw indentscope lazily')\n  local now_events = { 'TextChanged', 'TextChangedI', 'TextChangedP', 'WinScrolled' }\n  au(now_events, '*', function() H.auto_draw() end, 'Auto draw indentscope')\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  vim.api.nvim_set_hl(0, 'MiniIndentscopeSymbol',    { default = true, link = 'Delimiter' })\n  vim.api.nvim_set_hl(0, 'MiniIndentscopeSymbolOff', { default = true, link = 'MiniIndentscopeSymbol' })\nend\n\nH.is_disabled = function() return vim.g.miniindentscope_disable == true or vim.b.miniindentscope_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniIndentscope.config, vim.b.miniindentscope_config or {}, config or {})\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.auto_draw = function(opts)\n  if H.is_disabled() then\n    H.undraw_scope()\n    return\n  end\n\n  opts = opts or {}\n  local scope = MiniIndentscope.get_scope()\n\n  -- Make early return if nothing has to be done. Doing this before updating\n  -- event id allows to not interrupt ongoing animation.\n  if opts.lazy and H.current.draw_status ~= 'none' and H.scope_is_equal(scope, H.current.scope) then return end\n\n  -- Account for current event\n  local local_event_id = H.current.event_id + 1\n  H.current.event_id = local_event_id\n\n  -- Compute drawing options for current event\n  local draw_opts = H.make_autodraw_opts(scope)\n\n  -- Allow delay\n  if draw_opts.delay > 0 then H.undraw_scope(draw_opts) end\n\n  -- Use `defer_fn()` even if `delay` is 0 to draw indicator only after all\n  -- events are processed (stops flickering)\n  vim.defer_fn(function()\n    if H.current.event_id ~= local_event_id then return end\n\n    H.undraw_scope(draw_opts)\n\n    -- Don't autodraw if not asked to\n    if not H.get_config().draw.predicate(scope) then return end\n\n    H.current.scope = scope\n    H.draw_scope(scope, draw_opts)\n  end, draw_opts.delay)\nend\n\n-- Scope ----------------------------------------------------------------------\n-- Line indent:\n-- - Equals output of `vim.fn.indent()` in case of non-blank line.\n-- - Depends on `MiniIndentscope.config.options.border` in such way so as to\n--   ignore blank lines before line not recognized as border.\nH.get_line_indent = function(line, opts)\n  local prev_nonblank = vim.fn.prevnonblank(line)\n  local res = vim.fn.indent(prev_nonblank)\n\n  -- Compute indent of blank line depending on `border` option\n  local border = opts.border\n  if line ~= prev_nonblank then\n    local next_indent = vim.fn.indent(vim.fn.nextnonblank(line))\n    local blank_rule = H.blank_indent_funs[border]\n    res = blank_rule(res, next_indent)\n  end\n\n  return res\nend\n\nH.cast_ray = function(line, indent, direction, opts)\n  local final_line, increment = 1, -1\n  if direction == 'down' then\n    final_line, increment = vim.fn.line('$'), 1\n  end\n\n  local is_incomplete\n  if math.abs(line - final_line) > opts.n_lines then\n    final_line, is_incomplete = line + increment * opts.n_lines, true\n  end\n\n  local min_indent = math.huge\n  for l = line, final_line, increment do\n    local new_indent = H.get_line_indent(l + increment, opts)\n    if new_indent < indent then return l, min_indent, nil end\n    if new_indent < min_indent then min_indent = new_indent end\n  end\n\n  return final_line, min_indent, is_incomplete\nend\n\nH.scope_get_draw_indent = function(scope) return scope.border.indent or (scope.body.indent - 1) end\n\nH.scope_is_equal = function(scope_1, scope_2)\n  if type(scope_1) ~= 'table' or type(scope_2) ~= 'table' then return false end\n\n  return scope_1.buf_id == scope_2.buf_id\n    and H.scope_get_draw_indent(scope_1) == H.scope_get_draw_indent(scope_2)\n    and scope_1.body.top == scope_2.body.top\n    and scope_1.body.bottom == scope_2.body.bottom\n    and scope_1.body.is_incomplete == scope_2.body.is_incomplete\nend\n\nH.scope_has_intersect = function(scope_1, scope_2)\n  if type(scope_1) ~= 'table' or type(scope_2) ~= 'table' then return false end\n  if (scope_1.buf_id ~= scope_2.buf_id) or (H.scope_get_draw_indent(scope_1) ~= H.scope_get_draw_indent(scope_2)) then\n    return false\n  end\n\n  local body_1, body_2 = scope_1.body, scope_2.body\n  return (body_2.top <= body_1.top and body_1.top <= body_2.bottom)\n    or (body_1.top <= body_2.top and body_2.top <= body_1.bottom)\nend\n\n-- Indicator ------------------------------------------------------------------\n--- Compute indicator of scope to be displayed\n---\n--- Indicator is visual representation of scope in current window view using\n--- extmarks. Currently only needed because Neovim can't correctly process\n--- horizontal window scroll (Neovim issue:\n--- https://github.com/neovim/neovim/issues/14050)\n---\n---@return table|nil Table with indicator info or empty one in case indicator\n---   shouldn't be drawn.\n---@private\nH.indicator_compute = function(scope)\n  scope = scope or H.current.scope\n  local indent = H.scope_get_draw_indent(scope)\n\n  -- Don't draw indicator that should be outside of screen. This condition is\n  -- (perpusfully) \"responsible\" for not drawing indicator spanning whole file.\n  if indent < 0 then return {} end\n\n  -- Text indentation should depend on current window view because it will use\n  -- `virt_text_win_col` attribute of extmark options (the only way to reliably\n  -- put it anywhere on screen; important to show properly on empty lines).\n  local col = indent - vim.fn.winsaveview().leftcol\n  if col < 0 then return {} end\n\n  -- Pick highlight group based on if indent is a multiple of shiftwidth.\n  -- This adds visual indicator of whether indent is \"correct\".\n  local hl_group = (indent % vim.fn.shiftwidth() == 0) and 'MiniIndentscopeSymbol' or 'MiniIndentscopeSymbolOff'\n  local virt_text = { { H.get_config().symbol, hl_group } }\n\n  return {\n    buf_id = vim.api.nvim_get_current_buf(),\n    virt_text = virt_text,\n    virt_text_win_col = col,\n    top = scope.body.top,\n    bottom = scope.body.bottom,\n  }\nend\n\n-- Drawing --------------------------------------------------------------------\nH.draw_scope = function(scope, opts)\n  scope = scope or {}\n  opts = opts or {}\n\n  local indicator = H.indicator_compute(scope)\n\n  -- Don't draw anything if nothing to be displayed\n  if indicator.virt_text == nil or #indicator.virt_text == 0 then\n    H.current.draw_status = 'finished'\n    return\n  end\n\n  -- Make drawing function\n  local draw_fun = H.make_draw_function(indicator, opts)\n\n  -- Perform drawing\n  H.current.draw_status = 'drawing'\n  H.draw_indicator_animation(indicator, draw_fun, opts.animation_fun)\nend\n\nH.draw_indicator_animation = function(indicator, draw_fun, animation_fun)\n  -- Draw from origin (cursor line but within indicator range)\n  local top, bottom = indicator.top, indicator.bottom\n  local origin = math.min(math.max(vim.fn.line('.'), top), bottom)\n\n  local step = 0\n  local n_steps = math.max(origin - top, bottom - origin)\n  local wait_time = 0\n\n  local draw_step\n  draw_step = vim.schedule_wrap(function()\n    -- Check for not drawing outside of interval is done inside `draw_fun`\n    local success = draw_fun(origin - step)\n    if step > 0 then success = success and draw_fun(origin + step) end\n\n    if not success or step == n_steps then\n      H.current.draw_status = step == n_steps and 'finished' or H.current.draw_status\n      H.timer:stop()\n      return\n    end\n\n    step = step + 1\n    wait_time = wait_time + animation_fun(step, n_steps)\n\n    -- Repeat value of `timer` seems to be rounded down to milliseconds. This\n    -- means that values less than 1 will lead to timer stop repeating. Instead\n    -- call next step function directly.\n    if wait_time < 1 then\n      H.timer:set_repeat(0)\n      -- Use `return` to make this proper \"tail call\"\n      return draw_step()\n    else\n      H.timer:set_repeat(wait_time)\n\n      -- Restart `wait_time` only if it is actually used. Do this accounting\n      -- actually set repeat time.\n      wait_time = wait_time - H.timer:get_repeat()\n\n      -- Usage of `again()` is needed to overcome the fact that it is called\n      -- inside callback and to restart initial timer. Mainly this is needed\n      -- only in case of transition from 'non-repeating' timer to 'repeating'\n      -- one in case of complex animation functions. See\n      -- https://docs.libuv.org/en/v1.x/timer.html#api\n      H.timer:again()\n    end\n  end)\n\n  -- Start non-repeating timer without callback execution. This shouldn't be\n  -- `timer:start(0, 0, draw_step)` because it will execute `draw_step` on the\n  -- next redraw (flickers on window scroll).\n  H.timer:start(10000000, 0, draw_step)\n\n  -- Draw step zero (at origin) immediately\n  draw_step()\nend\n\nH.undraw_scope = function(opts)\n  opts = opts or {}\n\n  -- Don't operate outside of current event if able to verify\n  if opts.event_id and opts.event_id ~= H.current.event_id then return end\n\n  pcall(vim.api.nvim_buf_clear_namespace, H.current.scope.buf_id or 0, H.ns_id, 0, -1)\n\n  H.current.draw_status = 'none'\n  H.current.scope = {}\nend\n\nH.make_autodraw_opts = function(scope)\n  local config = H.get_config()\n  local res = {\n    event_id = H.current.event_id,\n    type = 'animation',\n    delay = config.draw.delay,\n    animation_fun = config.draw.animation,\n    priority = config.draw.priority,\n  }\n\n  if H.current.draw_status == 'none' then return res end\n\n  -- Draw immediately scope which intersects (same indent, overlapping ranges)\n  -- currently drawn or finished. This is more natural when typing text.\n  if H.scope_has_intersect(scope, H.current.scope) then\n    res.type = 'immediate'\n    res.delay = 0\n    res.animation_fun = MiniIndentscope.gen_animation.none()\n    return res\n  end\n\n  return res\nend\n\nH.make_draw_function = function(indicator, opts)\n  local extmark_opts = {\n    hl_mode = 'combine',\n    priority = opts.priority,\n    right_gravity = false,\n    virt_text = indicator.virt_text,\n    virt_text_win_col = indicator.virt_text_win_col,\n    virt_text_pos = 'overlay',\n  }\n\n  if H.has_wrapped_virt_text and vim.wo.breakindent and vim.wo.showbreak == '' then\n    extmark_opts.virt_text_repeat_linebreak = true\n  end\n\n  local current_event_id = opts.event_id\n\n  return function(l)\n    -- Don't draw if outdated\n    if H.current.event_id ~= current_event_id and current_event_id ~= nil then return false end\n\n    -- Don't draw if disabled\n    if H.is_disabled() then return false end\n\n    -- Don't put extmark outside of indicator range\n    if not (indicator.top <= l and l <= indicator.bottom) then return true end\n\n    return pcall(vim.api.nvim_buf_set_extmark, indicator.buf_id, H.ns_id, l - 1, 0, extmark_opts)\n  end\nend\n\n-- Animations -----------------------------------------------------------------\n--- Imitate common power easing function\n---\n--- Every step is preceded by waiting time decreasing/increasing in power\n--- series fashion (`d` is \"delta\", ensures total duration time):\n--- - \"in\":  d*n^p; d*(n-1)^p; ... ; d*2^p;     d*1^p\n--- - \"out\": d*1^p; d*2^p;     ... ; d*(n-1)^p; d*n^p\n--- - \"in-out\": \"in\" until 0.5*n, \"out\" afterwards\n---\n--- This way it imitates `power + 1` common easing function because animation\n--- progression behaves as sum of `power` elements.\n---\n---@param power number Power of series.\n---@param opts table Options from `MiniIndentscope.gen_animation` entry.\n---@private\nH.animation_arithmetic_powers = function(power, opts)\n  -- Sum of first `n_steps` natural numbers raised to `power`\n  local arith_power_sum = ({\n    [0] = function(n_steps) return n_steps end,\n    [1] = function(n_steps) return n_steps * (n_steps + 1) / 2 end,\n    [2] = function(n_steps) return n_steps * (n_steps + 1) * (2 * n_steps + 1) / 6 end,\n    [3] = function(n_steps) return n_steps ^ 2 * (n_steps + 1) ^ 2 / 4 end,\n  })[power]\n\n  -- Function which computes common delta so that overall duration will have\n  -- desired value (based on supplied `opts`)\n  local duration_unit, duration_value = opts.unit, opts.duration\n  local make_delta = function(n_steps, is_in_out)\n    local total_time = duration_unit == 'total' and duration_value or (duration_value * n_steps)\n    local total_parts\n    if is_in_out then\n      -- Examples:\n      -- - n_steps=5: 3^d, 2^d, 1^d, 2^d, 3^d\n      -- - n_steps=6: 3^d, 2^d, 1^d, 1^d, 2^d, 3^d\n      total_parts = 2 * arith_power_sum(math.ceil(0.5 * n_steps)) - (n_steps % 2 == 1 and 1 or 0)\n    else\n      total_parts = arith_power_sum(n_steps)\n    end\n    return total_time / total_parts\n  end\n\n  return ({\n    ['in'] = function(s, n) return make_delta(n) * (n - s + 1) ^ power end,\n    ['out'] = function(s, n) return make_delta(n) * s ^ power end,\n    ['in-out'] = function(s, n)\n      local n_half = math.ceil(0.5 * n)\n      local s_halved\n      if n % 2 == 0 then\n        s_halved = s <= n_half and (n_half - s + 1) or (s - n_half)\n      else\n        s_halved = s < n_half and (n_half - s + 1) or (s - n_half + 1)\n      end\n      return make_delta(n, true) * s_halved ^ power\n    end,\n  })[opts.easing]\nend\n\n--- Imitate common exponential easing function\n---\n--- Every step is preceded by waiting time decreasing/increasing in geometric\n--- progression fashion (`d` is 'delta', ensures total duration time):\n--- - 'in':  (d-1)*d^(n-1); (d-1)*d^(n-2); ...; (d-1)*d^1;     (d-1)*d^0\n--- - 'out': (d-1)*d^0;     (d-1)*d^1;     ...; (d-1)*d^(n-2); (d-1)*d^(n-1)\n--- - 'in-out': 'in' until 0.5*n, 'out' afterwards\n---\n---@param opts table Options from `MiniIndentscope.gen_animation` entry.\n---@private\nH.animation_geometrical_powers = function(opts)\n  -- Function which computes common delta so that overall duration will have\n  -- desired value (based on supplied `opts`)\n  local duration_unit, duration_value = opts.unit, opts.duration\n  local make_delta = function(n_steps, is_in_out)\n    local total_time = duration_unit == 'step' and (duration_value * n_steps) or duration_value\n    -- Exact solution to avoid possible (bad) approximation\n    if n_steps == 1 then return total_time + 1 end\n    if is_in_out then\n      local n_half = math.ceil(0.5 * n_steps)\n      -- Example for n_steps=6:\n      -- Steps: (d-1)*d^2, (d-1)*d^1, (d-1)*d^0, (d-1)*d^0, (d-1)*d^1, (d-1)*d^2\n      -- Sum: 2 * (d - 1) * (d^0 + d^1 + d^2) = 2 * (d^3 - 1)\n      -- Solution: 2 * (d^3 - 1) = total_time =>\n      --   d = math.pow(0.5 * total_time + 1, 1 / 3)\n      --\n      -- Example for n_steps=5:\n      -- Steps: (d-1)*d^2, (d-1)*d^1, (d-1)*d^0, (d-1)*d^1, (d-1)*d^2\n      -- Sum: 2 * (d - 1) * (d^0 + d^1 + d^2) - (d - 1) = 2 * (d^3 - 1) - (d - 1)\n      -- Solution: 2 * (d^3 - 1) - (d - 1) = total_time =>\n      --   As there is no general explicit solution, use approximation =>\n      --   (Exact solution without `- (d-1)`):\n      --     d_0 = math.pow(0.5 * total_time + 1, 1 / 3);\n      --   (Correction by solving exactly withtou `- (d-1)` for\n      --   `total_time_corr = total_time + (d_0 - 1)`):\n      --     d_1 = math.pow(0.5 * total_time_corr + 1, 1 / 3)\n      if n_steps % 2 == 1 then total_time = total_time + math.pow(0.5 * total_time + 1, 1 / n_half) - 1 end\n      return math.pow(0.5 * total_time + 1, 1 / n_half)\n    end\n    return math.pow(total_time + 1, 1 / n_steps)\n  end\n\n  return ({\n    ['in'] = function(s, n)\n      local delta = make_delta(n)\n      return (delta - 1) * delta ^ (n - s)\n    end,\n    ['out'] = function(s, n)\n      local delta = make_delta(n)\n      return (delta - 1) * delta ^ (s - 1)\n    end,\n    ['in-out'] = function(s, n)\n      local n_half, delta = math.ceil(0.5 * n), make_delta(n, true)\n      local s_halved\n      if n % 2 == 0 then\n        s_halved = s <= n_half and (n_half - s) or (s - n_half - 1)\n      else\n        s_halved = s < n_half and (n_half - s) or (s - n_half)\n      end\n      return (delta - 1) * delta ^ s_halved\n    end,\n  })[opts.easing]\nend\n\nH.normalize_animation_opts = function(x)\n  x = vim.tbl_deep_extend('force', { easing = 'in-out', duration = 20, unit = 'step' }, x or {})\n\n  if not vim.tbl_contains({ 'in', 'out', 'in-out' }, x.easing) then\n    H.error([[In `gen_animation` option `easing` should be one of 'in', 'out', or 'in-out'.]])\n  end\n\n  if type(x.duration) ~= 'number' or x.duration < 0 then\n    H.error([[In `gen_animation` option `duration` should be a positive number.]])\n  end\n\n  if not vim.tbl_contains({ 'total', 'step' }, x.unit) then\n    H.error([[In `gen_animation` option `unit` should be one of 'step' or 'total'.]])\n  end\n\n  return x\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.indentscope) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.exit_visual_mode = function()\n  local ctrl_v = vim.api.nvim_replace_termcodes('<C-v>', true, true, true)\n  local cur_mode = vim.fn.mode()\n  if cur_mode == 'v' or cur_mode == 'V' or cur_mode == ctrl_v then vim.cmd('normal! ' .. cur_mode) end\nend\n\nreturn MiniIndentscope\n"
  },
  {
    "path": "lua/mini/init.lua",
    "content": "--- *mini.nvim* Collection of minimal, independent and fast Lua modules\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- |mini.nvim| is a collection of minimal, independent, and fast Lua modules\n--- dedicated to improve Neovim (version 0.9 and higher) experience. Each\n--- module can be considered as a separate sub-plugin.\n---\n--- Table of contents:\n---\n---   General principles .......................... |mini.nvim-general-principles|\n---   Module list ........................................ |mini.nvim-module-list|\n---   Disabling recipes ............................ |mini.nvim-disabling-recipes|\n---   Buffer-local config ........................ |mini.nvim-buffer-local-config|\n---   Plugin color schemes ............................. |mini.nvim-color-schemes|\n---   Extend and create a/i textobjects ................................ |mini.ai|\n---   Align text interactively ...................................... |mini.align|\n---   Animate common Neovim actions ............................... |mini.animate|\n---   Base16 colorscheme creation .................................. |mini.base16|\n---   Common configuration presets ................................. |mini.basics|\n---   Go forward/backward with square brackets .................. |mini.bracketed|\n---   Remove buffers ............................................ |mini.bufremove|\n---   Show next key clues ............................................ |mini.clue|\n---   Command line tweaks ......................................... |mini.cmdline|\n---   Tweak and save any color scheme .............................. |mini.colors|\n---   Comment lines ............................................... |mini.comment|\n---   Completion and signature help ............................ |mini.completion|\n---   Autohighlight word under cursor .......................... |mini.cursorword|\n---   Plugin manager ................................................. |mini.deps|\n---   Work with diff hunks ........................................... |mini.diff|\n---   Generate Neovim help files ...................................... |mini.doc|\n---   Extra 'mini.nvim' functionality ............................... |mini.extra|\n---   Navigate and manipulate file system ........................... |mini.files|\n---   Fuzzy matching ................................................ |mini.fuzzy|\n---   Git integration ................................................. |mini.git|\n---   Highlight patterns in text ............................... |mini.hipatterns|\n---   Generate configurable color scheme ............................. |mini.hues|\n---   Icon provider ................................................. |mini.icons|\n---   Visualize and work with indent scope .................... |mini.indentscope|\n---   Jump to next/previous single character ......................... |mini.jump|\n---   Jump within visible lines .................................... |mini.jump2d|\n---   Special key mappings ......................................... |mini.keymap|\n---   Window with buffer text overview ................................ |mini.map|\n---   Miscellaneous functions ........................................ |mini.misc|\n---   Move any selection in any direction ............................ |mini.move|\n---   Show notifications ........................................... |mini.notify|\n---   Text edit operators ....................................... |mini.operators|\n---   Autopairs ..................................................... |mini.pairs|\n---   Pick anything .................................................. |mini.pick|\n---   Session management ......................................... |mini.sessions|\n---   Manage and expand snippets ................................. |mini.snippets|\n---   Split and join arguments .................................. |mini.splitjoin|\n---   Start screen ................................................ |mini.starter|\n---   Statusline ............................................... |mini.statusline|\n---   Surround actions ........................................... |mini.surround|\n---   Tabline ..................................................... |mini.tabline|\n---   Test Neovim plugins ............................................ |mini.test|\n---   Trailspace (highlight and remove) ........................ |mini.trailspace|\n---   Track and reuse file system visits ........................... |mini.visits|\n---@tag mini.nvim-table-of-contents\n\n--- Design ~\n--- Each module is designed to solve a particular problem targeting balance\n--- between feature-richness (handling as many edge-cases as possible) and\n--- simplicity of implementation/support. Granted, not all of them ended up\n--- with the same balance, but it is the goal nevertheless.\n---\n--- Independence ~\n--- Modules are independent of each other and can be run without external\n--- dependencies. Although some of them may need dependencies for full experience.\n---\n--- Structure ~\n--- Each module is a submodule for a placeholder \"mini\" module. For example,\n--- \"surround\" module should be referred to as \"mini.surround\". As later will\n--- be explained, this plugin can also be referred to as \"MiniSurround\".\n---\n--- Setup ~\n--- - Each module you want to use should be enabled separately with\n---   `require(<name of module>).setup({})`. Possibly replace `{}` with your\n---   config table or omit altogether to use defaults. You can supply only\n---   parts of config, the rest will be inferred from defaults.\n---\n--- - Call to module's `setup()` always creates a global Lua object with\n---   coherent camel-case name: `require('mini.surround').setup()` creates\n---   `_G.MiniSurround`. This allows for a simpler usage of plugin available\n---   from `v:lua` like `v:lua.MiniSurround`. Considering this, \"module\" and\n---   \"Lua object\" names can be used interchangeably:\n---   'mini.surround' and 'MiniSurround' will mean the same thing.\n---\n--- - Each supplied `config` table (after extending with default values) is\n---   stored in `config` field of global object. Like `MiniSurround.config`.\n---\n--- - Values of `config`, which affect runtime activity, can be changed on the\n---   fly to have effect. For example, `MiniSurround.config.n_lines` can be\n---   changed during runtime; but changing `MiniSurround.config.mappings` won't\n---   have any effect (as mappings are created once during `setup()`).\n---\n--- - If module works best with some specific non-default option value, it is\n---   set during `setup()`. If the value is not essential to module's functionality,\n---   it is done only if user or another plugin hasn't set it beforehand (no\n---   matter the value).\n---\n--- Buffer local configuration ~\n--- Each module can be additionally configured to use certain runtime config\n--- settings locally to buffer. See |mini.nvim-buffer-local-config| for more\n--- information.\n---\n--- Buffer names ~\n--- All module-related buffers are named according to the following format:\n--- `mini<module-name>://<buffer-number>/<useful-info>` (forward slashes are\n--- used on any platform; `<useful-info>` may be empty). This structure allows\n--- creating identifiable, reasonably unique, and useful buffer names.\n--- For example, |mini.files| buffers are created per displayed directory/file with\n--- names like `minifiles://10/path/to/displayed/directory`.\n---\n--- Disabling ~\n--- Each module's core functionality can be disabled globally or locally to\n--- buffer. See \"Disabling\" section in module's help page for more details.\n--- See |mini.nvim-disabling-recipes| for common recipes.\n---\n--- Silencing ~\n--- Each module can be configured to not show non-error feedback globally or\n--- locally to buffer. See \"Silencing\" section in module's help for more details.\n---\n--- Highlighting ~\n--- Appearance of module's output is controlled by certain set of highlight\n--- groups (see |highlight-groups|). By default they usually link to some\n--- semantically close built-in highlight group. Use |:highlight| command or\n--- |nvim_set_hl()| Lua function to customize highlighting. To see a more\n--- calibrated look, use |mini.hues|, |mini.base16|, or plugin's colorschemes.\n---\n--- Stability ~\n--- Each module upon release is considered to be relatively stable: both in\n--- terms of setup and functionality. Any non-bugfix backward-incompatible\n--- change will be released gradually as much as possible.\n---\n--- Not filetype and language specific ~\n--- Including functionality which needs several filetype/language specific\n--- implementations is an explicit no-goal of this project. This is mostly due\n--- to the potential increase in maintenance to keep implementation up to date.\n--- However, any part which might need filetype/language specific tuning should\n--- be designed to allow it by letting user set proper buffer options and/or\n--- local configuration.\n---@tag mini.nvim-general-principles\n\n--- - |mini.ai| - extend and create `a`/`i` textobjects (like in `di(` or\n---   `va\"`). It enhances some builtin |text-objects| (like |a(|, |a)|, |a'|,\n---   and more), creates new ones (like `a*`, `a<Space>`, `af`, `a?`, and\n---   more), and allows user to create their own (like based on treesitter, and\n---   more). Supports dot-repeat, `v:count`, different search methods,\n---   consecutive application, and customization via Lua patterns or functions.\n---   Has builtins for brackets, quotes, function call, argument, tag, user\n---   prompt, and any punctuation/digit/whitespace character.\n---\n--- - |mini.align| - align text interactively (with or without instant preview).\n---   Allows rich and flexible customization of both alignment rules and user\n---   interaction. Works with charwise, linewise, and blockwise selections in\n---   both Normal mode (on textobject/motion; with dot-repeat) and Visual mode.\n---\n--- - |mini.animate| - animate common Neovim actions. Has \"works out of the box\"\n---   builtin animations for cursor movement, scroll, resize, window open and\n---   close. All of them can be customized and enabled/disabled independently.\n---\n--- - |mini.base16| - fast implementation of base16 theme for manually supplied\n---   palette. Supports 30+ plugin integrations. Has unique palette generator\n---   which needs only background and foreground colors.\n---\n--- - |mini.basics| - common configuration presets. Has configurable presets for\n---   options, mappings, and autocommands. It doesn't change option or mapping\n---   if it was manually created.\n---\n--- - |mini.bracketed| - go forward/backward with square brackets. Among others,\n---   supports variety of non-trivial targets: comments, files on disk, indent\n---   changes, tree-sitter nodes, linear undo states, yank history entries.\n---\n--- - |mini.bufremove| - buffer removing (unshow, delete, wipeout) while saving\n---   window layout.\n---\n--- - |mini.clue| - show next key clues. Implements custom key query process with\n---   customizable opt-in triggers, next key descriptions (clues), hydra-like\n---   submodes, window delay/config. Provides clue sets for some built-in\n---   concepts: `g`/`z` keys, window commands, etc.\n---\n--- - |mini.cmdline| - command line tweaks. Adds autocompletion with customizable\n---   delay, autocorrection for words with fixed candidates, and autopeek command\n---   range in a floating window with customizable context size.\n---\n--- - |mini.colors| - tweak and save any color scheme. Can create colorscheme\n---   object with methods to invert/set/modify/etc.\n---   lightness/saturation/hue/temperature/etc. of foreground/background/all\n---   colors, infer cterm attributes, add transparency, save to a file and more.\n---   Has functionality for interactive experiments and animation of\n---   transition between color schemes.\n---\n--- - |mini.comment| - fast and familiar per-line code commenting.\n---\n--- - |mini.completion| - async (with customizable 'debounce' delay) 'two-stage\n---   chain completion': first builtin LSP, then configurable fallback. Also\n---   has functionality for completion item info and function signature (both\n---   in floating window appearing after customizable delay).\n---\n--- - |mini.cursorword| - automatic highlighting of word under cursor (displayed\n---   after customizable delay). Current word under cursor can be highlighted\n---   differently.\n---\n--- - |mini.deps| - plugin manager for plugins outside of 'mini.nvim'. Uses Git and\n---   built-in packages to install, update, clean, and snapshot plugins.\n---\n--- - |mini.diff| - visualize difference between buffer text and its reference\n---   interactively (with colored signs or line numbers). Uses Git index as\n---   default reference. Provides toggleable overview in text area, built-in\n---   apply/reset/textobject/goto mappings.\n---\n--- - |mini.doc| - generation of help files from EmmyLua-like annotations.\n---   Allows flexible customization of output via hook functions. Used for\n---   documenting this plugin.\n---\n--- - |mini.extra| - extra 'mini.nvim' functionality. Contains 'mini.pick' pickers,\n---   'mini.ai' textobjects, and more.\n---\n--- - |mini.files| - navigate and manipulate file system. A file explorer with\n---   column view capable of manipulating file system by editing text. Can\n---   create/delete/rename/copy/move files/directories inside and across\n---   directories. For full experience needs enabled |mini.icons| module (but works\n---   without it).\n---\n--- - |mini.fuzzy| - functions for fast and simple fuzzy matching. It has\n---   not only functions to perform fuzzy matching of one string to others, but\n---   also a sorter for 'nvim-telescope/telescope.nvim'.\n---\n--- - |mini.git| - Git integration (https://git-scm.com/). Implements tracking of\n---   Git related data (root, branch, etc.), |:Git| command for better integration\n---   with running Neovim instance, and various helpers to explore Git history.\n---\n--- - |mini.hipatterns| - highlight patterns in text with configurable highlighters\n---   (pattern and/or highlight group can be string or callable).\n---   Works asynchronously with configurable debounce delay.\n---\n--- - |mini.hues| - generate configurable color scheme. Takes only background\n---   and foreground colors as required arguments. Can adjust number of hues\n---   for non-base colors, saturation, accent color, plugin integration.\n---\n--- - |mini.icons| - icon provider with fixed set of highlight groups.\n---   Supports various categories, icon and style customizations, caching for\n---   performance. Integrates with Neovim's filetype matching.\n---\n--- - |mini.indentscope| - visualize and operate on indent scope. Supports\n---   customization of debounce delay, animation style, and different\n---   granularity of options for scope computing algorithm.\n---\n--- - |mini.jump| - minimal and fast module for smarter jumping to a single\n---   character.\n---\n--- - |mini.jump2d| - minimal and fast Lua plugin for jumping (moving cursor)\n---   within visible lines via iterative label filtering. Supports custom jump\n---   targets (spots), labels, hooks, allowed windows and lines, and more.\n---\n--- - |mini.keymap| - utilities to make special key mappings: multi-step actions\n---   (with built-in steps for \"smart\" <Tab>, <S-Tab>, <CR>, <BS>),\n---   combos (more general version of \"better escape\" like behavior).\n---\n--- - |mini.map| - window with buffer text overview, scrollbar, and highlights.\n---   Allows configurable symbols for line encode and scrollbar, extensible\n---   highlight integration (with pre-built ones for builtin search, diagnostic,\n---   git line status), window properties, and more.\n---\n--- - |mini.misc| - collection of miscellaneous useful functions. Like `put()`\n---   and `put_text()` which print Lua objects to command line and current\n---   buffer respectively.\n---\n--- - |mini.move| - move any selection in any direction. Supports any Visual\n---   mode (charwise, linewise, blockwise) and Normal mode (current line) for\n---   all four directions (left, right, down, up). Respects `count` and undo.\n---\n--- - |mini.notify| - show one or more highlighted notifications in a single window.\n---   Provides both low-level functions (add, update, remove, clear) and maker\n---   of |vim.notify()| implementation. Sets up automated LSP progress updates.\n---\n--- - |mini.operators| - various text edit operators: replace, exchange,\n---   multiply, sort, evaluate. Creates mappings to operate on textobject,\n---   line, and visual selection. Supports |[count]| and dot-repeat.\n---\n--- - |mini.pairs| - autopairs plugin which has minimal defaults and\n---   functionality to do per-key expression mappings.\n---\n--- - |mini.pick| - general purpose interactive non-blocking picker with\n---   toggleable preview. Has fast default matching with fuzzy/exact/grouped\n---   modes. Provides most used built-in pickers for files, pattern matches,\n---   buffers, etc. For full experience needs enabled |mini.icons| module (but\n---   works without it).\n---\n--- - |mini.sessions| - session management (read, write, delete) which works\n---   using |:mksession|. Implements both global (from configured directory) and\n---   local (from current directory) sessions.\n---\n--- - |mini.snippets| - manage and expand snippets. Supports only syntax from LSP\n---   specification. Provides flexible loaders to manage snippet files, exact and\n---   fuzzy prefix matching, interactive selection, and rich interactive snippet\n---   session experience with dynamic tabstop visualization.\n---\n--- - |mini.splitjoin| - split and join arguments (regions inside brackets\n---   between allowed separators). Has customizable pre and post hooks.\n---   Works inside comments.\n---\n--- - |mini.starter| - minimal, fast, and flexible start screen. Displayed items\n---   are fully customizable both in terms of what they do and how they look\n---   (with reasonable defaults). Item selection can be done using prefix query\n---   with instant visual feedback.\n---\n--- - |mini.statusline| - minimal and fast statusline. Has ability to use custom\n---   content supplied with concise function (using module's provided section\n---   functions) along with builtin default. For full experience needs\n---   enabled |mini.diff|, |mini.git|, and |mini.icons| modules (but works without\n---   any of them).\n---\n--- - |mini.surround| - fast and feature-rich surround plugin. Add, delete,\n---   replace, find, highlight surrounding (like pair of parenthesis, quotes,\n---   etc.). Supports dot-repeat, `v:count`, different search methods,\n---   \"last\"/\"next\" extended mappings, customization via Lua patterns or\n---   functions, and more. Has builtins for brackets, function call, tag, user\n---   prompt, and any alphanumeric/punctuation/whitespace character.\n---\n--- - |mini.test| - framework for writing extensive Neovim plugin tests.\n---   Supports hierarchical tests, hooks, parametrization, filtering (like from\n---   current file or cursor position), screen tests, \"busted-style\" emulation,\n---   customizable reporters, and more. Designed to be used with provided\n---   wrapper for managing child Neovim processes.\n---\n--- - |mini.tabline| - minimal tabline which always shows listed (see 'buflisted')\n---   buffers. Allows showing extra information section in case of multiple vim\n---   tabpages. For full experience needs enabled |mini.icons| module (but works\n---   without it).\n---\n--- - |mini.trailspace| - automatic highlighting of trailing whitespace with\n---   functionality to remove it.\n---\n--- - |mini.visits| - track and reuse file system visits. Tracks data about each\n---   file/directory visit (after delay) and stores it (only) locally. This can be\n---   used to get a list of \"recent\"/\"frequent\"/\"frecent\" visits.\n---   Allows persistently adding labels to visits enabling flexible workflow.\n---@tag mini.nvim-module-list\n\n--- Each module's core functionality can be disabled globally or buffer-locally\n--- by creating appropriate global or buffer-scoped variables equal to |v:true|.\n--- Functionality is disabled if at least one of |g:| or |b:| variables is `v:true`.\n---\n--- Variable names have the same structure: `{g,b}:mini*_disable` where `*` is\n--- module's lowercase name. For example, `g:minianimate_disable` disables\n--- |mini.animate| globally and `b:minianimate_disable` - for current buffer.\n--- Note: in this section disabling 'mini.animate' is used as example;\n--- everything holds for other module variables.\n---\n--- Considering high number of different scenarios and customization intentions,\n--- writing exact rules for disabling module's functionality is left to user.\n---\n--- # Manual disabling ~\n--- >lua\n---   -- Disable globally\n---   vim.g.minianimate_disable = true\n---\n---   -- Disable for current buffer\n---   vim.b.minianimate_disable = true\n---\n---   -- Toggle (disable if enabled, enable if disabled)\n---   vim.g.minianimate_disable = not vim.g.minianimate_disable -- globally\n---   vim.b.minianimate_disable = not vim.b.minianimate_disable -- for buffer\n--- <\n--- # Automated disabling ~\n---\n--- Automated disabling is suggested to be done inside autocommands: >lua\n---\n---   -- Disable for a certain filetype (for example, \"lua\")\n---   local f = function(args) vim.b[args.buf].minianimate_disable = true end\n---   vim.api.nvim_create_autocmd('Filetype', { pattern = 'lua', callback = f })\n---\n---   -- Enable only for certain filetypes (for example, \"lua\" and \"help\")\n---   local f = function(args)\n---     local ft = vim.bo[args.buf].filetype\n---     if ft == 'lua' or ft == 'help' then return end\n---     vim.b[args.buf].minianimate_disable = true\n---   end\n---   vim.api.nvim_create_autocmd('Filetype', { callback = f })\n---\n---   -- Disable in Visual mode\n---   local f_en = function(args) vim.b[args.buf].minianimate_disable = false end\n---   local enable_opts = { pattern = '[vV\\x16]*:*', callback = f_en }\n---   vim.api.nvim_create_autocmd('ModeChanged', enable_opts)\n---\n---   local f_dis = function(args) vim.b[args.buf].minianimate_disable = true end\n---   local disable_opts = { pattern = '*:[vV\\x16]*', callback = f_dis }\n---   vim.api.nvim_create_autocmd('ModeChanged', disable_opts)\n---\n---   -- Disable in Terminal buffer\n---   local f = function(args) vim.b[args.buf].minianimate_disable = true end\n---   vim.api.nvim_create_autocmd('TermOpen', { callback = f })\n--- <\n---@tag mini.nvim-disabling-recipes\n\n--- Each module can be additionally configured locally to buffer by creating\n--- appropriate buffer-scoped variable with values to override. It affects only\n--- runtime options and not those used once during setup (like most `mappings`).\n---\n--- Variable names have the same structure: `b:mini*_config` where `*` is\n--- module's lowercase name. For example, `b:minianimate_config` can store\n--- information about how |mini.animate| will act inside current buffer. Its\n--- value should be a table with same structure as module's `config`. Example: >lua\n---\n---   -- Disable scroll animation in current buffer\n---   vim.b.minianimate_config = { scroll = { enable = false } }\n--- <\n--- Considering high number of different scenarios and customization intentions,\n--- writing exact rules for module's buffer local configuration is left to\n--- user. It is done in similar fashion to |mini.nvim-disabling-recipes|.\n---@tag mini.nvim-buffer-local-config\n\n--- - Color schemes based on |mini.hues|: |MiniHues-color-schemes|.\n--- - Color schemes based on |mini.base16|: |MiniBase16-color-schemes|.\n---@tag mini.nvim-color-schemes\n\nvim.notify([[Do not `require('mini')` directly. Setup every module separately.]])\n\nreturn {}\n"
  },
  {
    "path": "lua/mini/jump.lua",
    "content": "--- *mini.jump* Jump to next/previous single character\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski, Adam Blažek\n\n--- Features:\n--- - Extend f, F, t, T to work on multiple lines.\n---\n--- - Repeat jump by pressing f, F, t, T again. It is reset when cursor moved\n---   as a result of not jumping or timeout after idle time (duration\n---   customizable).\n---\n--- - Highlight (after customizable delay) all possible target characters and\n---   stop it after some (customizable) idle time.\n---\n--- - Normal, Visual, and Operator-pending (with dot-repeat as in clean Neovim)\n---   modes are supported.\n---\n--- This module follows vim's 'ignorecase' and 'smartcase' options. When\n--- 'ignorecase' is set, f, F, t, T will match case-insensitively. When\n--- 'smartcase' is also set, f, F, t, T will only match lowercase\n--- characters case-insensitively.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.jump').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniJump` which you can use for scripting or manually (with\n--- `:lua MiniJump.*`).\n---\n--- See |MiniJump.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minijump_config` which should have same structure as\n--- `MiniJump.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Highlight groups ~\n---\n--- - `MiniJump` - all possible cursor positions.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.minijump_disable` (globally) or\n--- `vim.b.minijump_disable` (for a buffer) to `true`. Considering high number of\n--- different scenarios and customization intentions, writing exact rules for\n--- disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniJump\n\n--- To allow user customization and integration of external tools, certain |User|\n--- autocommand events are triggered under common circumstances:\n---\n--- - `MiniJumpGetTarget` - before asking user for the target. Use |MiniJump.state|\n---   for more information about the upcoming jump.\n--- - `MiniJumpStart` - after jumping has started.\n--- - `MiniJumpJump` - after performing a jump.\n--- - `MiniJumpStop` - after jumping is stopped.\n---@tag MiniJump-events\n\n---@alias __jump_target string|nil The string to jump to.\n---@alias __jump_backward boolean|nil Whether to jump backward.\n---@alias __jump_till boolean|nil Whether to jump just before/after the match instead of\n---   exactly on target. This includes positioning cursor past the end of\n---   previous/current line. Note that with backward jump this might lead to\n---   cursor being on target if can't be put past the line.\n---@alias __jump_n_times number|nil Number of times to perform consecutive jumps.\n\n-- Module definition ==========================================================\nlocal MiniJump = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniJump.config|.\n---\n---@usage >lua\n---   require('mini.jump').setup() -- use default config\n---   -- OR\n---   require('mini.jump').setup({}) -- replace {} with your config table\n--- <\nMiniJump.setup = function(config)\n  -- Export module\n  _G.MiniJump = MiniJump\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniJump.config = {\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    forward = 'f',\n    backward = 'F',\n    forward_till = 't',\n    backward_till = 'T',\n    repeat_jump = ';',\n  },\n\n  -- Delay values (in ms) for different functionalities. Set any of them to\n  -- a very big number (like 10^7) to virtually disable.\n  delay = {\n    -- Delay between jump and highlighting all possible jumps\n    highlight = 250,\n\n    -- Delay between jump and automatic stop if idle (no jump is done)\n    idle_stop = 10000000,\n  },\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module data ================================================================\n--- Data about jumping state\n---\n--- It stores various information used in this module. All elements, except\n--- `jumping`, is about the latest jump. They are used as default values for\n--- similar arguments.\n---\n---@usage This can be used to define mappings which depend on state; either as\n--- a standalone mapping or part of |MiniKeymap.map_multistep()|. For example: >lua\n---\n---   -- Stop jumping after pressing `<Esc>`\n---   local jump_stop = function()\n---     if not MiniJump.state.jumping then return '<Esc>' end\n---     MiniJump.stop_jumping()\n---   end\n---   local opts = { expr = true, desc = 'Stop jumping' }\n---   vim.keymap.set({ 'n', 'x', 'o' }, '<Esc>', jump_stop, opts)\n--- <\n---@class JumpingState\n---\n---@field target __jump_target\n---@field backward __jump_backward\n---@field till __jump_till\n---@field n_times __jump_n_times\n---@field mode string Mode of latest jump (output of |mode()| with non-zero argument).\n---@field jumping boolean Whether module is currently in \"jumping mode\": usage of\n---   |MiniJump.smart_jump()| and all mappings won't require target.\n---@text\n--- Initial values:\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniJump.state = {\n  target = nil,\n  backward = false,\n  till = false,\n  n_times = 1,\n  mode = nil,\n  jumping = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Jump to target\n---\n--- Takes a string and jumps to its first occurrence in desired direction.\n---\n--- All default values are taken from |MiniJump.state| to emulate latest jump.\n---\n---@param target __jump_target\n---@param backward __jump_backward\n---@param till __jump_till\n---@param n_times __jump_n_times\nMiniJump.jump = function(target, backward, till, n_times)\n  if H.is_disabled() then return end\n\n  -- Dot-repeat should not change the state, so save it to later restore\n  local is_expr, is_dot_repeat = MiniJump._is_expr, MiniJump._is_expr and not MiniJump._is_expr_init\n  MiniJump._is_expr, MiniJump._is_expr_init = nil, nil\n  local state_snapshot = is_dot_repeat and vim.deepcopy(MiniJump.state) or nil\n\n  -- Cache inputs for future use\n  H.update_state(target, backward, till, n_times)\n\n  if MiniJump.state.target == nil then return H.message('Can not jump because there is no recent `target`.') end\n\n  -- Construct search and highlight pattern data\n  local pattern, hl_pattern, flags = H.make_search_data()\n\n  -- Delay highlighting after stopping previous one\n  -- Update highlighting immediately if any highlighting is already present\n  local config = H.get_config()\n  H.timers.highlight:stop()\n  local hl = vim.schedule_wrap(function() H.highlight(hl_pattern) end)\n  H.timers.highlight:start(H.is_highlighting() and 0 or config.delay.highlight, 0, hl)\n\n  -- Start idle timer after stopping previous one\n  H.timers.idle_stop:stop()\n  H.timers.idle_stop:start(config.delay.idle_stop, 0, vim.schedule_wrap(function() MiniJump.stop_jumping() end))\n\n  -- Make jump(s)\n  H.cache.n_cursor_moved = 0\n  local was_jumping = MiniJump.state.jumping\n  MiniJump.state.jumping = true\n  if not was_jumping then H.trigger_event('MiniJumpStart') end\n  H.trigger_event('MiniJumpJump')\n\n  local has_jumped = false\n  for _ = 1, MiniJump.state.n_times do\n    local row = vim.fn.search(pattern, flags)\n    has_jumped = has_jumped or row > 0\n  end\n\n  -- Open enough folds to show jump\n  if has_jumped then vim.cmd('normal! zv') end\n\n  -- Track cursor position to account for movement not caught by `CursorMoved`\n  H.cache.latest_cursor = H.get_cursor_data()\n\n  -- Restore the state if needed. It should a jumping state if there was jump\n  -- or if it is possible to jump in other direction (i.e. target is present).\n  MiniJump.state = is_dot_repeat and state_snapshot or MiniJump.state\n  local search_pattern = '\\\\V' .. vim.fn.escape(MiniJump.state.target, '\\\\')\n  MiniJump.state.jumping = has_jumped or vim.fn.search(search_pattern, 'wn') ~= 0\n\n  -- Ensure to undo \"consume a character\" effect in Operator-pending expression\n  -- mapping if there is no target found. Do it here to also act on dot-repeat.\n  if is_expr and not has_jumped then vim.schedule(function() vim.cmd('undo!') end) end\nend\n\n--- Make smart jump\n---\n--- If the last movement was a jump, perform another jump with the same target.\n--- Otherwise, wait for a target input (via |getcharstr()|). Respects |v:count|.\n---\n--- All default values are taken from |MiniJump.state| to emulate latest jump.\n---\n---@param backward __jump_backward\n---@param till __jump_till\nMiniJump.smart_jump = function(backward, till)\n  if H.is_disabled() then return end\n\n  -- Jumping should stop after mode change (use `mode(1)` to track 'omap' case)\n  -- or if cursor has moved after latest jump\n  local has_changed_mode = MiniJump.state.mode ~= vim.fn.mode(1)\n  local has_changed_cursor = not vim.deep_equal(H.cache.latest_cursor, H.get_cursor_data())\n  if has_changed_mode or has_changed_cursor then MiniJump.stop_jumping() end\n\n  H.update_state(nil, backward, till, vim.v.count1)\n\n  -- Ask for target only when needed\n  local target\n  if not MiniJump.state.jumping or MiniJump.state.target == nil then\n    target = H.get_target()\n    -- Stop if user supplied invalid target\n    if target == nil then return end\n  end\n\n  H.update_state(target)\n\n  MiniJump.jump()\nend\n\n--- Stop jumping\n---\n--- Removes highlights (if any) and forces the next smart jump to prompt for\n--- the target. Automatically called on appropriate Neovim |events|.\nMiniJump.stop_jumping = function()\n  H.timers.highlight:stop()\n  H.timers.idle_stop:stop()\n\n  local was_jumping = MiniJump.state.jumping\n  MiniJump.state.jumping = false\n\n  H.cache.n_cursor_moved = 0\n  H.cache.latest_cursor = nil\n  H.cache.msg_shown = false\n\n  H.unhighlight()\n\n  -- Trigger relevant event only if there was jumping\n  if was_jumping then H.trigger_event('MiniJumpStop') end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniJump.config)\n\n-- Cache for various operations\nH.cache = {\n  -- Counter of number of CursorMoved events\n  n_cursor_moved = 0,\n\n  -- Latest cursor position data\n  latest_cursor = nil,\n\n  -- Whether helper message was shown\n  msg_shown = false,\n}\n\n-- Timers for different delay-related functionalities\nH.timers = { highlight = vim.loop.new_timer(), idle_stop = vim.loop.new_timer() }\n\n-- Information about last match highlighting (stored *per window*):\n-- - Key: windows' unique buffer identifiers.\n-- - Value: table with:\n--     - `id` field for match id (from `vim.fn.matchadd()`).\n--     - `pattern` field for highlighted pattern.\nH.window_matches = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('delay', config.delay, 'table')\n  H.check_type('delay.highlight', config.delay.highlight, 'number')\n  H.check_type('delay.idle_stop', config.delay.idle_stop, 'number')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.forward', config.mappings.forward, 'string')\n  H.check_type('mappings.backward', config.mappings.backward, 'string')\n  H.check_type('mappings.forward_till', config.mappings.forward_till, 'string')\n  H.check_type('mappings.backward_till', config.mappings.backward_till, 'string')\n  H.check_type('mappings.repeat_jump', config.mappings.repeat_jump, 'string')\n\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniJump.config = config\n\n  --stylua: ignore start\n  H.map('n', config.mappings.forward, '<Cmd>lua MiniJump.smart_jump(false, false)<CR>', { desc = 'Jump forward' })\n  H.map('n', config.mappings.backward, '<Cmd>lua MiniJump.smart_jump(true, false)<CR>', { desc = 'Jump backward' })\n  H.map('n', config.mappings.forward_till, '<Cmd>lua MiniJump.smart_jump(false, true)<CR>', { desc = 'Jump forward till' })\n  H.map('n', config.mappings.backward_till, '<Cmd>lua MiniJump.smart_jump(true, true)<CR>', { desc = 'Jump backward till' })\n  H.map('n', config.mappings.repeat_jump, '<Cmd>lua MiniJump.jump()<CR>', { desc = 'Repeat jump' })\n\n  H.map('x', config.mappings.forward, '<Cmd>lua MiniJump.smart_jump(false, false)<CR>', { desc = 'Jump forward' })\n  H.map('x', config.mappings.backward, '<Cmd>lua MiniJump.smart_jump(true, false)<CR>', { desc = 'Jump backward' })\n  H.map('x', config.mappings.forward_till, '<Cmd>lua MiniJump.smart_jump(false, true)<CR>', { desc = 'Jump forward till' })\n  H.map('x', config.mappings.backward_till, '<Cmd>lua MiniJump.smart_jump(true, true)<CR>', { desc = 'Jump backward till' })\n  H.map('x', config.mappings.repeat_jump, '<Cmd>lua MiniJump.jump()<CR>', { desc = 'Repeat jump' })\n\n  H.map('o', config.mappings.forward, H.make_expr_jump(false, false), { expr = true, desc = 'Jump forward' })\n  H.map('o', config.mappings.backward, H.make_expr_jump(true, false), { expr = true, desc = 'Jump backward' })\n  H.map('o', config.mappings.forward_till, H.make_expr_jump(false, true), { expr = true, desc = 'Jump forward till' })\n  H.map('o', config.mappings.backward_till, H.make_expr_jump(true, true), { expr = true, desc = 'Jump backward till' })\n  H.map('o', config.mappings.repeat_jump, H.make_expr_jump(), { expr = true, desc = 'Repeat jump' })\n  --stylua: ignore end\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniJump', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('CursorMoved', '*', H.on_cursormoved, 'On CursorMoved')\n  -- Check current buffer not immediately to allow \"temporary buffer switch\"\n  au({ 'BufLeave', 'InsertEnter' }, '*', vim.schedule_wrap(H.stop_if_curbuf), 'Stop jumping')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\nH.create_default_hl = function() vim.api.nvim_set_hl(0, 'MiniJump', { default = true, link = 'SpellRare' }) end\n\nH.is_disabled = function() return vim.g.minijump_disable == true or vim.b.minijump_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniJump.config, vim.b.minijump_config or {}, config or {})\nend\n\n-- Mappings -------------------------------------------------------------------\nH.make_expr_jump = function(backward, till)\n  return function()\n    if H.is_disabled() then return '' end\n\n    local count = vim.v.count1\n    H.update_state(nil, backward, till, count)\n\n    -- Ask for `target` for non-repeating jump as this will be used only in\n    -- operator-pending mode. Dot-repeat is supported via expression-mapping.\n    local isnt_repeat_jump = backward ~= nil and till ~= nil\n    local target = isnt_repeat_jump and H.get_target() or nil\n    if isnt_repeat_jump and target == nil then return '<Esc>' end\n    H.update_state(target)\n\n    -- Set a flag to distinguish first call from dot-repeat\n    MiniJump._is_expr_init = true\n\n    -- Encode state in expression for dot-repeat. Important to use `target=nil`\n    -- for `repeat_jump` case to have it using latest jumping state during\n    -- dot-repeat also (as does `nvim --clean`).\n    local args = string.format('%s,%s,%s,%s', vim.inspect(target), backward, till, count)\n    return 'v<Cmd>lua MiniJump._is_expr=true; MiniJump.jump(' .. args .. ')<CR>'\n  end\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.on_cursormoved = function()\n  -- Check if jumping to avoid unnecessary actions on every CursorMoved\n  if MiniJump.state.jumping then\n    H.cache.n_cursor_moved = H.cache.n_cursor_moved + 1\n    -- Stop jumping only if `CursorMoved` was not a result of smart jump\n    if H.cache.n_cursor_moved > 1 then MiniJump.stop_jumping() end\n  end\nend\n\nH.stop_if_curbuf = function(ev)\n  if ev.buf == vim.api.nvim_get_current_buf() then MiniJump.stop_jumping() end\nend\n\n-- Pattern matching -----------------------------------------------------------\nH.make_search_data = function()\n  local target = vim.fn.escape(MiniJump.state.target, [[\\]])\n  local backward, till = MiniJump.state.backward, MiniJump.state.till\n\n  local flags = backward and 'Wb' or 'W'\n  local pattern, hl_pattern\n\n  if till then\n    -- General logic: moving pattern should match just before/after target,\n    -- while highlight pattern should match target for every \"movable\" place.\n    -- Also allow checking for \"just before/after\" across lines by accepting\n    -- `\\n` as possible match.\n    if backward then\n      -- NOTE: use `\\@<=` instead of `\\zs` because it behaves better in case of\n      -- consecutive matches (like `xxxx` for target `x`)\n      pattern = target .. [[\\@<=\\_.]]\n      hl_pattern = target .. [[\\ze\\_.]]\n    else\n      pattern = [[\\_.\\ze]] .. target\n      hl_pattern = [[\\_.\\@<=]] .. target\n    end\n  else\n    local is_visual = vim.tbl_contains({ 'v', 'V', '\\22' }, vim.fn.mode())\n    local is_exclusive = vim.o.selection == 'exclusive'\n    if not backward and is_visual and is_exclusive then\n      -- Still select target in case of exclusive visual selection\n      pattern = target .. [[\\zs\\_.]]\n      hl_pattern = target .. [[\\ze\\_.]]\n    else\n      pattern = target\n      hl_pattern = target\n    end\n  end\n\n  -- Enable 'very nomagic' mode and possibly case-insensitivity\n  local ignore_case = vim.o.ignorecase and (not vim.o.smartcase or target == target:lower())\n  local prefix = ignore_case and [[\\V\\c]] or [[\\V]]\n  pattern, hl_pattern = prefix .. pattern, prefix .. hl_pattern\n\n  return pattern, hl_pattern, flags\nend\n\n-- Highlighting ---------------------------------------------------------------\nH.highlight = function(pattern)\n  if H.is_highlighting(pattern) or not MiniJump.state.jumping then return end\n\n  -- Stop highlighting possible previous pattern. Needed to adjust highlighting\n  -- when inside jumping but a different kind one. Example: first jump with\n  -- `till = false` and then, without jumping stop, jump to same character with\n  -- `till = true`. If this character is first on line, highlighting should change\n  H.unhighlight()\n\n  -- Never highlight in Insert mode\n  if vim.fn.mode() == 'i' then return end\n\n  local match_id = vim.fn.matchadd('MiniJump', pattern)\n  H.window_matches[vim.api.nvim_get_current_win()] = { id = match_id, pattern = pattern }\nend\n\nH.unhighlight = function()\n  -- Remove highlighting from all windows as jumping is intended to work only\n  -- in current window. This will work also from other (usually popup) window.\n  for win_id, match_info in pairs(H.window_matches) do\n    if vim.api.nvim_win_is_valid(win_id) then\n      -- Use `pcall` because there is an error if match id is not present. It\n      -- can happen if something else called `clearmatches`.\n      pcall(vim.fn.matchdelete, match_info.id, win_id)\n      H.window_matches[win_id] = nil\n    end\n  end\nend\n\n---@param pattern string|nil Highlight pattern to check for. If `nil`, checks for\n---   any highlighting registered in current window.\n---@private\nH.is_highlighting = function(pattern)\n  local win_id = vim.api.nvim_get_current_win()\n  local match_info = H.window_matches[win_id]\n  if match_info == nil then return false end\n  return pattern == nil or match_info.pattern == pattern\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.jump) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg, is_important)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.jump) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local chunks = msg\n  if not is_important then\n    chunks = {}\n    local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n    local tot_width = 0\n    for _, ch in ipairs(msg) do\n      local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n      table.insert(chunks, new_ch)\n      tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n      if tot_width >= max_width then break end\n    end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, is_important, {})\nend\n\nH.unecho = function()\n  if H.cache.msg_shown then vim.cmd([[echo '' | redraw]]) end\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.trigger_event = function(event_name, data) vim.api.nvim_exec_autocmds('User', { pattern = event_name, data = data }) end\n\nH.update_state = function(target, backward, till, n_times)\n  MiniJump.state.mode = vim.fn.mode(1)\n\n  -- Don't use `? and <1> or <2>` because it doesn't work when `<1>` is `false`\n  if target ~= nil then MiniJump.state.target = target end\n  if backward ~= nil then MiniJump.state.backward = backward end\n  if till ~= nil then MiniJump.state.till = till end\n  if n_times ~= nil then MiniJump.state.n_times = n_times end\nend\n\nH.get_cursor_data = function() return { vim.api.nvim_get_current_win(), vim.api.nvim_win_get_cursor(0) } end\n\nH.get_target = function()\n  local needs_reminder = true\n  vim.defer_fn(function()\n    if not needs_reminder then return end\n    H.echo('Reminder to press a target single character ')\n    H.cache.msg_shown = true\n  end, 1000)\n\n  H.trigger_event('MiniJumpGetTarget')\n  local ok, char = pcall(vim.fn.getcharstr)\n  needs_reminder = false\n  H.unecho()\n\n  -- Terminate if couldn't get input (like with <C-c>) or it is `<Esc>`\n  if not ok or char == '\\27' then return end\n  return char\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nreturn MiniJump\n"
  },
  {
    "path": "lua/mini/jump2d.lua",
    "content": "--- *mini.jump2d* Jump within visible lines\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Jump within visible lines via iterative label filtering.\n---\n--- Features:\n--- - Make jump by iterative filtering of possible, equally considered jump\n---   spots until there is only one. Filtering is done by typing a label\n---   character that is visualized at jump spot.\n---\n--- - Customizable (see |MiniJump2d.config|):\n---     - Way of computing possible jump spots with opinionated default.\n---     - Characters used to label jump spots during iterative filtering.\n---     - Visual effects: how many steps ahead to show; dim lines with spots.\n---     - Action hooks to be executed at certain events during jump.\n---     - Allowed windows: current and/or not current.\n---     - Allowed lines: whether to process blank or folded lines, lines\n---       before/at/after cursor line, etc. Example: user can configure to look\n---       for spots only inside current window at or after cursor line.\n---     Example: user can configure to look for word starts only inside current\n---     window at or after cursor line with 'j' and 'k' labels performing some\n---     action after jump.\n---\n--- - Works in Visual and Operator-pending (with dot-repeat) modes.\n---\n--- - Preconfigured ways of computing jump spots (see |MiniJump2d.builtin_opts|):\n---     - Starts of lines.\n---     - Starts of words.\n---     - Single character from user input.\n---     - Variable length query from user input.\n---\n--- - Works with multibyte characters.\n---\n--- General overview of how jump is intended to be performed:\n--- - Lock eyes on desired location (\"spot\") recognizable by future jump.\n---   Should be within visible lines at place where cursor can be placed.\n---\n--- - Initiate jump. Either by custom keybinding or with a call to\n---   |MiniJump2d.start()| (allows customization options). This will highlight\n---   all possible jump spots with their labels (letters from \"a\" to \"z\" by\n---   default). For more details, read |MiniJump2d.start()| and |MiniJump2d.config|.\n---\n--- - Type character that appeared over desired location. If its label was\n---   unique, jump is performed. If it wasn't unique, possible jump spots are\n---   filtered to those having the same label character.\n---\n--- - Repeat previous step until there is only one possible jump spot or type <CR>\n---   to jump to first available jump spot. Typing anything else stops jumping\n---    without moving cursor.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.jump2d').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table\n--- `MiniJump2d` which you can use for scripting or manually (with\n--- `:lua MiniJump2d.*`).\n---\n--- See |MiniJump2d.config| for available config settings.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minijump2d_config` which should have same structure as\n--- `MiniJump2d.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Example usage ~\n---\n--- - Modify default jumping to use only current window at or after cursor line: >lua\n---\n---   require('mini.jump2d').setup({\n---     allowed_lines = { cursor_before = false },\n---     allowed_windows = { not_current = false },\n---   })\n--- <\n--- - Jump to line start using combination of options supplied in\n---   |MiniJump2d.config| and |MiniJump2d.builtin_opts.line_start|: >vim\n---\n---   :lua MiniJump2d.start(MiniJump2d.builtin_opts.line_start)\n--- <\n--- - Jump to a single character typed after executing this command: >vim\n---\n---   :lua MiniJump2d.start(MiniJump2d.builtin_opts.single_character)\n--- <\n--- - See more examples in |MiniJump2d.start()| and |MiniJump2d.builtin_opts|.\n---\n--- # Comparisons ~\n---\n--- - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim):\n---     - Both are fast, customizable, and extensible (user can write their own\n---       ways to define jump spots).\n---     - 'hop.nvim' visualizes all steps at once. While this module can show\n---       configurable number of steps ahead.\n---     - Both have several builtin ways to specify type of jump (word start,\n---       line start, one character or query based on user input). 'hop.nvim'\n---       does that by exporting many targeted Neovim commands, while this\n---       module has preconfigured basic options leaving others to\n---       customization with Lua code (see |MiniJump2d.builtin_opts|).\n---     - 'hop.nvim' computes labels (called \"hints\") differently. Contrary to\n---       this module deliberately not having preference of one jump spot over\n---       another, 'hop.nvim' uses specialized algorithm that produces sequence\n---       of keys in a slightly biased manner: some sequences are intentionally\n---       shorter than the others (leading to fewer average keystrokes). They\n---       are put near cursor (by default) and highlighted differently. Final\n---       order of sequences is based on distance to the cursor.\n---     - 'mini.jump2d' has opinionated default algorithm of computing jump\n---       spots. See |MiniJump2d.default_spotter()|.\n---\n--- # Highlight groups ~\n---\n--- - `MiniJump2dSpot` - highlighting of jump spot's next step. By default it\n---   uses label with highest contrast while not being too visually demanding:\n---   white on black for dark 'background', black on white for light. If it\n---   doesn't suit your liking, try couple of these alternatives (or choose\n---   your own, of course): >lua\n---\n---     -- Reverse underlying colors (mostly *very* visible in any colorscheme)\n---     vim.api.nvim_set_hl(0, 'MiniJump2dSpot', { reverse = true })\n---\n---     -- Bold italic\n---     vim.api.nvim_set_hl(0, 'MiniJump2dSpot', { bold = true, italic = true })\n---\n---     -- Red undercurl\n---     vim.api.nvim_set_hl(0, 'MiniJump2dSpot', { sp = 'Red', undercurl = true })\n--- <\n--- - `MiniJump2dSpotUnique` - highlighting of jump spot's next step if it has\n---   unique label. By default links to `MiniJump2dSpot`.\n---\n--- - `MiniJump2dSpotAhead` - highlighting of jump spot's future steps. By default\n---   similar to `MiniJump2dSpot` but with less contrast and visibility.\n---\n--- - `MiniJump2dDim` - highlighting of lines with at least one jump spot.\n---   Make it non-bright in order for jump spot labels to be more visible.\n---   By default linked to `Comment` highlight group.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minijump2d_disable` (globally) or\n--- `vim.b.minijump2d_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniJump2d\n\n-- Module definition ==========================================================\nlocal MiniJump2d = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniJump2d.config|.\n---\n---@usage >lua\n---   require('mini.jump2d').setup() -- use default config\n---   -- OR\n---   require('mini.jump2d').setup({}) -- replace {} with your config table\n--- <\nMiniJump2d.setup = function(config)\n  -- Export module\n  _G.MiniJump2d = MiniJump2d\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Spotter function ~\n---\n--- Actual computation of possible jump spots is done through spotter function.\n--- It should have the following arguments:\n--- - `line_num` is a line number inside buffer.\n--- - `args` - table with additional arguments:\n---     - {win_id} - identifier of a window where input line number is from.\n---     - {win_id_init} - identifier of a window which was current when\n---       `MiniJump2d.start()` was called.\n---\n--- Its output is a list of byte-indexed positions that should be considered as\n--- possible jump spots for this particular line in this particular window.\n--- Note: for a more aligned visualization this list should be (but not\n--- strictly necessary) sorted increasingly.\n---\n--- Note: spotter function is always called with `win_id` window being\n--- \"temporary current\" (see |nvim_win_call()|). This allows using builtin\n--- Vimscript functions that operate only inside current window.\n---\n--- # View ~\n---\n--- Option `view.n_steps_ahead` controls how many steps ahead to show along\n--- with the currently required label. Those future steps are shown with\n--- different (less visible) highlight group (\"MiniJump2dSpotAhead\"). Usually\n--- it is a good idea to use this with a spotter which doesn't result into many\n--- jump spots (like, for example, |MiniJump2d.builtin_opts.word_start|).\n--- Default is 0 to not show anything ahead as it reduces visual noise.\n---\n--- Option `view.dim` controls whether to dim lines with at least one jump spot.\n--- Dimming is done by applying \"MiniJump2dDim\" highlight group to the whole line.\n---\n--- # Allowed lines ~\n---\n--- Option `allowed_lines` controls which lines will be used for computing\n--- possible jump spots:\n--- - If `blank` or `fold` is `true`, it is possible to jump to first column of blank\n---   line (determined by |prevnonblank()|) or first folded one (determined by\n---   |foldclosed()|) respectively. Otherwise they are skipped. These lines are\n---   not processed by spotter function even if the option is `true`.\n--- - If `cursor_before`, (`cursor_at`, `cursor_after`) is `true`, lines before\n---   (at, after) cursor line of all processed windows are forwarded to spotter\n---   function. Otherwise, they don't. This allows control of jump \"direction\".\n---\n--- # Hooks ~\n---\n--- Following hook functions can be used to further tweak jumping experience:\n--- - `before_start` - called without arguments first thing when jump starts.\n---   One of the possible use cases is to ask for user input and update spotter\n---   function with it.\n--- - `after_jump` - called after jump was actually done. Useful to make\n---   post-adjustments (like move cursor to first non-whitespace character).\nMiniJump2d.config = {\n  -- Function producing jump spots (byte indexed) for a particular line.\n  -- For more information see |MiniJump2d.start()|.\n  -- If `nil` (default) - use |MiniJump2d.default_spotter()|\n  spotter = nil,\n\n  -- Characters used for labels of jump spots (in supplied order)\n  labels = 'abcdefghijklmnopqrstuvwxyz',\n\n  -- Options for visual effects\n  view = {\n    -- Whether to dim lines with at least one jump spot\n    dim = false,\n\n    -- How many steps ahead to show. Set to big number to show all steps.\n    n_steps_ahead = 0,\n  },\n\n  -- Which lines are used for computing spots\n  allowed_lines = {\n    blank = true, -- Blank line (not sent to spotter even if `true`)\n    cursor_before = true, -- Lines before cursor line\n    cursor_at = true, -- Cursor line\n    cursor_after = true, -- Lines after cursor line\n    fold = true, -- Start of fold (not sent to spotter even if `true`)\n  },\n\n  -- Which windows from current tabpage are used for visible lines\n  allowed_windows = {\n    current = true,\n    not_current = true,\n  },\n\n  -- Functions to be executed at certain events\n  hooks = {\n    before_start = nil, -- Before jump start\n    after_jump = nil, -- After jump was actually done\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    start_jumping = '<CR>',\n  },\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Start jumping\n---\n--- Compute possible jump spots, visualize them and wait for iterative filtering.\n---\n--- # First computation of possible jump spots ~\n---\n--- - Process allowed windows (current and/or not current; controlled by\n---   `allowed_windows` option) by visible lines from top to bottom. For each\n---   one see if it is allowed (controlled by `allowed_lines` option). If not\n---   allowed, then do nothing. If allowed and should be processed by\n---   `spotter`, process it.\n--- - Apply spotter function from `spotter` option for each appropriate line\n---   and concatenate outputs. This means that eventual order of jump spots\n---   aligns with lexicographical order within \"window id\" - \"line number\" -\n---   \"position in `spotter` output\" tuples.\n--- - For each possible jump compute its label: a single character from\n---   `labels` option used to filter jump spots. Each possible label character\n---   might be used more than once to label several \"consecutive\" jump spots.\n---   It is done in an optimal way under assumption of no preference of one\n---   spot over another. Basically, it means \"use all labels at each step of\n---   iterative filtering as equally as possible\".\n---\n--- # Visualization ~\n---\n--- Current label for each possible jump spot is shown at that position\n--- overriding everything underneath it.\n---\n--- # Iterative filtering ~\n---\n--- Labels of possible jump spots are computed in order to use them as equally\n--- as possible.\n---\n--- Example:\n--- - With `abc` as `labels` option, initial labels for 10 possible jumps\n---   are \"aaaabbbccc\". As there are 10 spots which should be \"coded\" with 3\n---   symbols, at least 2 symbols need 3 steps to filter them out. With current\n---   implementation those are always the \"first ones\".\n--- - After typing `a`, it filters first four jump spots and recomputes its\n---   labels to be \"aabc\".\n--- - After typing `a` again, it filters first two spots and recomputes its\n---   labels to be \"ab\".\n--- - After typing either `a` or `b` it filters single spot and makes jump.\n---\n--- With default 26 labels for most real-world cases 2 steps is enough for\n--- default spotter function. Rarely 3 steps are needed with several windows.\n---\n---@param opts table|nil Configuration of jumping, overriding global and buffer\n---   local values. Has the same structure as |MiniJump2d.config|\n---   without <mappings> field. Extra allowed fields:\n---   - <hl_group> - highlight group for first step.\n---     Default: `\"MiniJump2dSpot\"`.\n---   - <hl_group_ahead> - highlight group for second and later steps.\n---     Default: `\"MiniJump2dSpotAhead\"`.\n---   - <hl_group_dim> - highlight group for dimming used lines.\n---     Default: `\"MiniJump2dDim\"`.\n---   - <hl_group_unique> - highlight group for unique next step.\n---     Default: `\"MiniJump2dSpotUnique\"`.\n---\n---@usage >lua\n---   -- Start default jumping\n---   MiniJump2d.start()\n---\n---   -- Jump to word start\n---   MiniJump2d.start(MiniJump2d.builtin_opts.word_start)\n---\n---   -- Jump to single character from user input (follow by typing one character)\n---   MiniJump2d.start(MiniJump2d.builtin_opts.single_character)\n---\n---   -- Jump to first character of punctuation group only inside current window\n---   -- which is placed at cursor line; visualize with `Search`\n---   MiniJump2d.start({\n---     spotter = MiniJump2d.gen_spotter.pattern('%p+'),\n---     allowed_lines = { cursor_before = false, cursor_after = false },\n---     allowed_windows = { not_current = false },\n---     hl_group = 'Search'\n---   })\n--- <\n---@seealso |MiniJump2d.config|\nMiniJump2d.start = function(opts)\n  if H.is_disabled() then return end\n\n  opts = opts or {}\n\n  -- Apply `before_start` before `tbl_deep_extend` to allow it modify options\n  -- inside it (notably `spotter`). Example: `builtins.single_character`.\n  local before_start = (opts.hooks or {}).before_start\n    or ((vim.b.minijump2d_config or {}).hooks or {}).before_start\n    or MiniJump2d.config.hooks.before_start\n  if before_start ~= nil then before_start() end\n\n  opts = H.get_config(opts)\n  opts.spotter = opts.spotter or MiniJump2d.default_spotter\n  opts.hl_group = opts.hl_group or 'MiniJump2dSpot'\n  opts.hl_group_ahead = opts.hl_group_ahead or 'MiniJump2dSpotAhead'\n  opts.hl_group_unique = opts.hl_group_unique or 'MiniJump2dSpotUnique'\n  opts.hl_group_dim = opts.hl_group_dim or 'MiniJump2dDim'\n\n  local spots = H.spots_compute(opts)\n  if #spots == 0 then\n    H.message('No spots to show.')\n    return\n  end\n  if #spots == 1 then\n    H.perform_jump(spots[1], opts.hooks.after_jump)\n    return\n  end\n\n  local label_tbl = vim.split(opts.labels, '')\n  spots = H.spots_add_steps(spots, label_tbl, opts.view.n_steps_ahead)\n\n  H.spots_show(spots, opts)\n\n  H.cache.spots = spots\n\n  H.advance_jump(opts)\nend\n\n--- Stop jumping\nMiniJump2d.stop = function()\n  H.spots_unshow()\n  H.cache.spots = nil\n  H.cache.msg_shown = false\n  vim.cmd('redraw')\n\n  if H.cache.is_in_getcharstr then vim.api.nvim_input('<C-c>') end\nend\n\n--- Generate spotter\n---\n--- This is a table with function elements. Call to actually get a spotter.\nMiniJump2d.gen_spotter = {}\n\n--- Generate spotter for Lua pattern\n---\n---@param pattern string|nil Lua pattern. Default: `'[^%s%p]+'` which matches group\n---   of \"non-whitespace non-punctuation characters\" (basically a way of saying\n---   \"group of alphanumeric characters\" that works with multibyte characters).\n---@param side string|nil Which side of pattern match should be considered as\n---   jumping spot. Should be one of 'start' (start of match, default), 'end'\n---   (inclusive end of match), or 'none' (match for spot is done manually\n---   inside pattern with plain `()` matching group).\n---\n---@return function Spotter function.\n---\n---@usage >lua\n---   -- Match any punctuation\n---   MiniJump2d.gen_spotter.pattern('%p')\n---\n---   -- Match first from line start non-whitespace character\n---   MiniJump2d.gen_spotter.pattern('^%s*%S', 'end')\n---\n---   -- Match start of last word\n---   MiniJump2d.gen_spotter.pattern('[^%s%p]+[%s%p]-$', 'start')\n---\n---   -- Match letter followed by another letter (example of manual matching\n---   -- inside pattern)\n---   MiniJump2d.gen_spotter.pattern('%a()%a', 'none')\n--- <\nMiniJump2d.gen_spotter.pattern = function(pattern, side)\n  -- Don't use `%w` to account for multibyte characters\n  pattern = pattern or '[^%s%p]+'\n  side = side or 'start'\n\n  -- Process anchored patterns separately because:\n  -- - `gmatch()` doesn't work if pattern start with `^`.\n  -- - Manual adding of `()` will conflict with anchors.\n  local is_anchored = pattern:sub(1, 1) == '^' or pattern:sub(-1, -1) == '$'\n  if is_anchored then\n    return function(line_num, args)\n      local line = vim.fn.getline(line_num)\n      local s, e, m = line:find(pattern)\n      return { ({ ['start'] = s, ['end'] = e, ['none'] = m })[side] }\n    end\n  end\n\n  -- Handle `side = 'end'` later by appending length of match to match start.\n  -- This, unlike appending `()` to end of pattern, makes output spot to be\n  -- inside matched pattern and on its exact right.\n  -- Having `(%s)` for `side = 'none'` is for compatibility with later `gmatch`\n  local pattern_template = side == 'none' and '(%s)' or '(()%s)'\n  pattern = pattern_template:format(pattern)\n\n  return function(line_num, args)\n    local line = vim.fn.getline(line_num)\n    local res = {}\n    -- NOTE: maybe a more straightforward approach would be a series of\n    -- `line:find(original_pattern, init)` with moving `init`, but it has some\n    -- weird behavior with quantifiers.\n    -- For example: `string.find('  --', '%s*', 4)` returns `4 3`.\n    for whole, spot in string.gmatch(line, pattern) do\n      -- Possibly correct spot to be index of last matched position\n      if side == 'end' then spot = spot + math.max(whole:len() - 1, 0) end\n\n      -- Ensure that index is strictly within line length (which can be not\n      -- true in case of weird pattern, like when using frontier `%f[%W]`)\n      spot = math.min(math.max(spot, 0), line:len())\n\n      -- Unify how spot is chosen in case of multibyte characters\n      -- Use `+-1` to make sure that result is at start of multibyte character\n      local utf_index = H.str_utfindex(line, spot) - 1\n      spot = H.str_byteindex(line, utf_index) + 1\n\n      -- Add spot only if it referces new actually visible column\n      if spot ~= res[#res] then table.insert(res, spot) end\n    end\n    return res\n  end\nend\n\n-- TODO: Remove after releasing 'mini.nvim' 0.17.0\nMiniJump2d.gen_pattern_spotter = function(pattern, side)\n  local msg = '`gen_pattern_spotter` is moved to `gen_spotter.pattern` for consistency with other modules.'\n    .. ' It still works for now, but will stop working after the next release.'\n    .. ' Sorry for the inconvenience.'\n  H.notify(msg, 'WARN')\n  return MiniJump2d.gen_spotter.pattern(pattern, side)\nend\n\n--- Generate spotter for Vimscript pattern\n---\n---@param pattern string|nil Vimscript |pattern|. Default: `\\k\\+` to match group\n---   of \"keyword characters\" (see 'iskeyword').\n---\n---@return function Spotter function.\n---\n---@usage >lua\n---   -- Match start of a keyword\n---   MiniJump2d.gen_spotter.vimpattern('\\\\k\\\\+')\n---\n---   -- Match end of a keyword\n---   MiniJump2d.gen_spotter.vimpattern('\\\\k*\\\\zs\\\\k')\n--- <\nMiniJump2d.gen_spotter.vimpattern = function(pattern)\n  pattern = pattern or '\\\\k\\\\+'\n  if type(pattern) ~= 'string' then H.error('`pattern` should be string') end\n  local r = vim.regex(pattern)\n  local is_anchored = pattern:sub(1, 1) == '^' or pattern:sub(-1, -1) == '$'\n\n  return function(line_num, _)\n    local res, l, start = {}, vim.fn.getline(line_num), 1\n    local n = is_anchored and 1 or (l:len() + 1)\n    for _ = 1, n do\n      local from, to = r:match_str(l)\n      if from == nil then break end\n      table.insert(res, from + start)\n      l, start = l:sub(to + 1), start + to\n    end\n    return res\n  end\nend\n\n--- Generate union of spotters\n---\n---@param ... any Each argument should be a valid spotter.\n---   See |MiniJump2d.config| for more details.\n---\n---@return function Spotter producing union of spots.\n---\n---@usage >lua\n---   -- Match start and end of non-blank character groups:\n---   local nonblank_start = MiniJump2d.gen_spotter.pattern('%S+', 'start')\n---   local nonblank_end = MiniJump2d.gen_spotter.pattern('%S+', 'end')\n---   local spotter = MiniJump2d.gen_spotter.union(nonblank_start, nonblank_end)\n--- <\nMiniJump2d.gen_spotter.union = function(...)\n  local spotters = { ... }\n  if #spotters == 0 then\n    return function() return {} end\n  end\n\n  local is_all_callable = true\n  for _, x in ipairs(spotters) do\n    if not vim.is_callable(x) then is_all_callable = false end\n  end\n\n  if not is_all_callable then H.error('All `gen_spotter.union()` arguments should be callable elements.') end\n\n  return function(line_num, args)\n    local res = spotters[1](line_num, args)\n    for i = 2, #spotters do\n      res = H.merge_unique(res, spotters[i](line_num, args))\n    end\n    return res\n  end\nend\n\n-- TODO: Remove after releasing 'mini.nvim' 0.17.0\nMiniJump2d.gen_union_spotter = function(...)\n  local msg = '`gen_union_spotter` is moved to `gen_spotter.union` for consistency with other modules.'\n    .. ' It still works for now, but will stop working after the next release.'\n    .. ' Sorry for the inconvenience.'\n  H.notify(msg, 'WARN')\n  return MiniJump2d.gen_spotter.union(...)\nend\n\n--- Default spotter function\n---\n--- Spot is possible for jump if it is one of the following:\n--- - Start or end of non-whitespace character group.\n--- - Alphanumeric character followed or preceded by punctuation (useful for\n---   snake case names).\n--- - Start of uppercase character group (useful for camel case names). Usually\n---   only Latin alphabet is recognized due to Lua patterns shortcomings.\n---\n--- These rules are derived in an attempt to balance between two intentions:\n--- - Allow as much useful jumping spots as possible.\n--- - Make labeled jump spots easily distinguishable.\n---\n--- Usually takes from 2 to 3 keystrokes to get to destination.\n---@tag MiniJump2d.default_spotter()\nMiniJump2d.default_spotter = (function()\n  -- NOTE: not using `MiniJump2d.gen_spotter.union()` due to slightly better\n  -- algorithmic complexity merging small arrays first.\n  local nonblank_start = MiniJump2d.gen_spotter.pattern('%S+', 'start')\n  local nonblank_end = MiniJump2d.gen_spotter.pattern('%S+', 'end')\n  -- Use `[^%s%p]` as \"alphanumeric\" to allow working with multibyte characters\n  local alphanum_before_punct = MiniJump2d.gen_spotter.pattern('[^%s%p]%p', 'start')\n  local alphanum_after_punct = MiniJump2d.gen_spotter.pattern('%p[^%s%p]', 'end')\n  -- NOTE: works only with Latin alphabet\n  local upper_start = MiniJump2d.gen_spotter.pattern('%u+', 'start')\n\n  return function(line_num, args)\n    local res_1 = H.merge_unique(nonblank_start(line_num, args), nonblank_end(line_num, args))\n    local res_2 = H.merge_unique(alphanum_before_punct(line_num, args), alphanum_after_punct(line_num, args))\n    local res = H.merge_unique(res_1, res_2)\n    return H.merge_unique(res, upper_start(line_num, args))\n  end\nend)()\n\n--- Table with builtin `opts` values for |MiniJump2d.start()|\n---\n--- Each element of table is itself a table defining one or several options for\n--- `MiniJump2d.start()`. Read help description to see which options it defines\n--- (like in |MiniJump2d.builtin_opts.line_start|).\n---\n---@usage >lua\n---   -- Using `MiniJump2d.builtin_opts.line_start` as example:\n---   -- Command\n---   :lua MiniJump2d.start(MiniJump2d.builtin_opts.line_start)\n---\n---   -- Custom mapping\n---   vim.keymap.set(\n---     'n', '<CR>',\n---     '<Cmd>lua MiniJump2d.start(MiniJump2d.builtin_opts.line_start)<CR>'\n---   )\n---\n---   -- Inside `MiniJump2d.setup()` (make sure to use all defined options)\n---   local jump2d = require('mini.jump2d')\n---   local jump_line_start = jump2d.builtin_opts.line_start\n---   jump2d.setup({\n---     spotter = jump_line_start.spotter,\n---     hooks = { after_jump = jump_line_start.hooks.after_jump }\n---   })\n--- <\nMiniJump2d.builtin_opts = {}\n\n--- Jump with |MiniJump2d.default_spotter()|\n---\n--- Defines `spotter`.\nMiniJump2d.builtin_opts.default = { spotter = MiniJump2d.default_spotter }\n\n--- Jump to line start\n---\n--- Defines `spotter` and `hooks.after_jump`.\nMiniJump2d.builtin_opts.line_start = {\n  spotter = function(line_num, args) return { 1 } end,\n  hooks = {\n    after_jump = function()\n      -- Move to first non-blank character\n      vim.cmd('normal! ^')\n    end,\n  },\n}\n\n--- Jump to word start\n---\n--- Respects 'iskeyword' when computing word start.\n---\n--- Defines `spotter`.\nMiniJump2d.builtin_opts.word_start = { spotter = MiniJump2d.gen_spotter.vimpattern('\\\\k\\\\+') }\n\n-- Produce `opts` which modifies spotter based on user input\nlocal function user_input_opts(input_fun)\n  local res = {\n    spotter = function() return {} end,\n    allowed_lines = { blank = false, fold = false },\n  }\n\n  local before_start = function()\n    local input = input_fun()\n    -- Allow user to cancel input and not show any jumping spots\n    if input == nil then return end\n    res.spotter = MiniJump2d.gen_spotter.pattern(vim.pesc(input))\n  end\n  res.hooks = { before_start = before_start }\n\n  return res\nend\n\n--- Jump to single character taken from user input\n---\n--- Defines `spotter`, `allowed_lines.blank`, `allowed_lines.fold`, and\n--- `hooks.before_start`.\nMiniJump2d.builtin_opts.single_character = user_input_opts(\n  function() return H.getcharstr('Reminder to press a character to search') end\n)\n\n--- Jump to query taken from user input\n---\n--- Defines `spotter`, `allowed_lines.blank`, `allowed_lines.fold`, and\n--- `hooks.before_start`.\nMiniJump2d.builtin_opts.query = user_input_opts(\n  function() return H.user_input('Reminder to enter a query to search') end\n)\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniJump2d.config)\n\n-- Namespaces to be used within module\nH.ns_id = {\n  dim = vim.api.nvim_create_namespace('MiniJump2dDim'),\n  spots = vim.api.nvim_create_namespace('MiniJump2dSpots'),\n  input = vim.api.nvim_create_namespace('MiniJump2dInput'),\n}\n\n-- Table with current relevant data:\nH.cache = {\n  -- Array of shown spots\n  spots = nil,\n\n  -- Indicator of whether Neovim is currently in \"getcharstr\" mode\n  is_in_getcharstr = false,\n\n  -- Whether helper message was shown\n  msg_shown = false,\n}\n\n-- Table with special keys\nH.keys = {\n  esc = vim.api.nvim_replace_termcodes('<Esc>', true, true, true),\n  cr = vim.api.nvim_replace_termcodes('<CR>', true, true, true),\n  block_operator_pending = vim.api.nvim_replace_termcodes('no<C-V>', true, true, true),\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('spotter', config.spotter, 'function', true)\n  H.check_type('labels', config.labels, 'string')\n\n  H.check_type('view', config.view, 'table')\n  H.check_type('view.dim', config.view.dim, 'boolean')\n  H.check_type('view.n_steps_ahead', config.view.n_steps_ahead, 'number')\n\n  H.check_type('allowed_lines', config.allowed_lines, 'table')\n  H.check_type('allowed_lines.blank', config.allowed_lines.blank, 'boolean')\n  H.check_type('allowed_lines.cursor_before', config.allowed_lines.cursor_before, 'boolean')\n  H.check_type('allowed_lines.cursor_at', config.allowed_lines.cursor_at, 'boolean')\n  H.check_type('allowed_lines.cursor_after', config.allowed_lines.cursor_after, 'boolean')\n  H.check_type('allowed_lines.fold', config.allowed_lines.fold, 'boolean')\n\n  H.check_type('allowed_windows', config.allowed_windows, 'table')\n  H.check_type('allowed_windows.current', config.allowed_windows.current, 'boolean')\n  H.check_type('allowed_windows.not_current', config.allowed_windows.not_current, 'boolean')\n\n  H.check_type('hooks', config.hooks, 'table')\n  H.check_type('hooks.before_start', config.hooks.before_start, 'function', true)\n  H.check_type('hooks.after_jump', config.hooks.after_jump, 'function', true)\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.start_jumping', config.mappings.start_jumping, 'string')\n\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniJump2d.config = config\n\n  -- Apply mappings\n  local keymap = config.mappings.start_jumping\n  H.map('n', keymap, MiniJump2d.start, { desc = 'Start 2d jumping' })\n  H.map('x', keymap, MiniJump2d.start, { desc = 'Start 2d jumping' })\n  -- Use `<Cmd>...<CR>` to have proper dot-repeat\n  -- See https://github.com/neovim/neovim/issues/23406\n  -- TODO: use local functions if/when that issue is resolved\n  H.map('o', keymap, '<Cmd>lua MiniJump2d.start()<CR>', { desc = 'Start 2d jumping' })\nend\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniJump2d', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { pattern = pattern, group = gr, callback = callback, desc = desc })\n  end\n\n  -- Corrections for default `<CR>` mapping to not interfere with popular usages\n  if config.mappings.start_jumping == '<CR>' then\n    local revert_cr = function() vim.keymap.set('n', '<CR>', '<CR>', { buffer = true }) end\n    au('FileType', 'qf', revert_cr, 'Revert <CR>')\n    au('CmdwinEnter', '*', revert_cr, 'Revert <CR>')\n  end\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local set_default_hl = function(name, data)\n    data.default = true\n    vim.api.nvim_set_hl(0, name, data)\n  end\n\n  local is_light_bg = vim.o.background == 'light'\n  local bg_color = is_light_bg and 'white' or 'black'\n  local fg_color = is_light_bg and 'black' or 'white'\n\n  set_default_hl('MiniJump2dSpot',       { fg = fg_color, bg = bg_color, bold = true, nocombine = true })\n  set_default_hl('MiniJump2dSpotAhead',  { fg = 'grey',   bg = bg_color, nocombine = true })\n  set_default_hl('MiniJump2dSpotUnique', { link = 'MiniJump2dSpot' })\n  set_default_hl('MiniJump2dDim',        { link = 'Comment' })\nend\n\nH.is_disabled = function() return vim.g.minijump2d_disable == true or vim.b.minijump2d_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniJump2d.config, vim.b.minijump2d_config or {}, config or {})\nend\n\n-- Jump spots -----------------------------------------------------------------\nH.spots_compute = function(opts)\n  local win_id_init, allowed = vim.api.nvim_get_current_win(), opts.allowed_windows\n  local win_id_arr = vim.tbl_filter(function(win_id)\n    if not vim.api.nvim_win_get_config(win_id).focusable then return false end\n    if win_id == win_id_init then return allowed.current end\n    return allowed.not_current\n  end, H.tabpage_list_wins(0))\n\n  local res = {}\n  for _, win_id in ipairs(win_id_arr) do\n    vim.api.nvim_win_call(win_id, function()\n      local cursor_pos = vim.api.nvim_win_get_cursor(win_id)\n      local spotter_args = { win_id = win_id, win_id_init = win_id_init }\n      local buf_id = vim.api.nvim_win_get_buf(win_id)\n\n      -- Use all currently visible lines\n      for i = vim.fn.line('w0'), vim.fn.line('w$') do\n        local columns = H.spot_find_in_line(i, spotter_args, opts, cursor_pos)\n        -- Use all returned columns for particular line\n        for _, col in ipairs(columns) do\n          table.insert(res, { line = i, column = col, buf_id = buf_id, win_id = win_id })\n        end\n      end\n    end)\n  end\n  return res\nend\n\nH.spots_add_steps = function(spots, label_tbl, n_steps_ahead)\n  -- Compute all required steps\n  local steps = {}\n  for _ = 1, #spots do\n    table.insert(steps, {})\n  end\n\n  H.populate_spot_steps(steps, label_tbl, 1, n_steps_ahead + 1)\n\n  for i, spot in ipairs(spots) do\n    spot.steps = steps[i]\n  end\n\n  return spots\nend\n\n---@param spot_steps_arr table Array of step arrays. Single step array consists\n---   from labels user needs to press in order to filter out the spot. Example:\n---   { { 'a', 'a' }, { 'a', 'b' },  { 'b' } }\n---\n---@return nil Modifies `spot_steps_arr` in place.\n---@private\nH.populate_spot_steps = function(spot_steps_arr, label_tbl, cur_step, max_step)\n  local n_spots, n_label_chars = #spot_steps_arr, #label_tbl\n  if n_spots <= 1 or max_step < cur_step then return end\n\n  -- Adding labels for specific step is done by distributing all available\n  -- labels as equally as possible by repeating labels in their order.\n  -- Example: with 3 label characters labels should evolve with progressing\n  -- number of spots like this: 'a', 'ab', 'abc', 'aabc', 'aabbc', 'aabbcc',\n  -- 'aaabbcc', 'aaabbbcc', 'aaabbbccc', etc.\n  local base, extra = math.floor(n_spots / n_label_chars), n_spots % n_label_chars\n\n  -- `cur_label_spot_steps` is an array of spot steps which are expanded with\n  -- the same label. It is used to initiate computing all steps needed.\n  local label_id, cur_label_spot_steps = 1, {}\n  local label_max_count = base + (label_id <= extra and 1 or 0)\n  for _, spot_steps in ipairs(spot_steps_arr) do\n    table.insert(spot_steps, label_tbl[label_id])\n    table.insert(cur_label_spot_steps, spot_steps)\n\n    if #cur_label_spot_steps >= label_max_count then\n      H.populate_spot_steps(cur_label_spot_steps, label_tbl, cur_step + 1, max_step)\n      label_id, cur_label_spot_steps = label_id + 1, {}\n      label_max_count = base + (label_id <= extra and 1 or 0)\n    end\n  end\nend\n\nH.spots_show = function(spots, opts)\n  spots = spots or H.cache.spots or {}\n\n  local set_extmark = vim.api.nvim_buf_set_extmark\n\n  -- Add extmark with proper virtual text to jump spots\n  local dim_buf_lines = {}\n  for _, extmark in ipairs(H.spots_to_extmarks(spots, opts)) do\n    local extmark_opts = {\n      hl_mode = 'combine',\n      -- Use very high priority\n      priority = 1000,\n      virt_text = extmark.virt_text,\n      virt_text_pos = 'overlay',\n    }\n    local buf_id, line = extmark.buf_id, extmark.line\n    pcall(set_extmark, buf_id, H.ns_id.spots, line, extmark.col, extmark_opts)\n\n    -- Register lines to dim\n    local lines = dim_buf_lines[buf_id] or {}\n    lines[line] = true\n    dim_buf_lines[buf_id] = lines\n  end\n\n  -- Possibly dim used lines\n  if opts.view.dim then\n    local extmark_opts = { end_col = 0, hl_eol = true, hl_group = opts.hl_group_dim, priority = 999 }\n    for buf_id, lines in pairs(dim_buf_lines) do\n      for _, l_num in ipairs(vim.tbl_keys(lines)) do\n        extmark_opts.end_line = l_num + 1\n        pcall(set_extmark, buf_id, H.ns_id.dim, l_num, 0, extmark_opts)\n      end\n    end\n  end\n\n  -- Redraw to force showing marks\n  vim.cmd('redraw')\nend\n\nH.spots_unshow = function(spots)\n  spots = spots or H.cache.spots or {}\n\n  -- Remove spot extmarks from all buffers they are present\n  local buf_ids = {}\n  for _, s in ipairs(spots) do\n    buf_ids[s.buf_id] = true\n  end\n\n  for _, buf_id in ipairs(vim.tbl_keys(buf_ids)) do\n    pcall(vim.api.nvim_buf_clear_namespace, buf_id, H.ns_id.spots, 0, -1)\n    pcall(vim.api.nvim_buf_clear_namespace, buf_id, H.ns_id.dim, 0, -1)\n  end\nend\n\n--- Convert consecutive spot labels into single extmark\n---\n--- This considerably increases performance in case of many spots.\n---@private\nH.spots_to_extmarks = function(spots, opts)\n  if #spots == 0 then return {} end\n\n  local hl_group, hl_group_ahead, hl_group_unique = opts.hl_group, opts.hl_group_ahead, opts.hl_group_unique\n\n  -- Compute counts for first step in order to distinguish which highlight\n  -- group to use: `hl_group` or `hl_group_unique`\n  local first_step_counts = {}\n  for _, s in ipairs(spots) do\n    local cur_first_step = s.steps[1]\n    local cur_count = first_step_counts[cur_first_step] or 0\n    first_step_counts[cur_first_step] = cur_count + 1\n  end\n\n  -- Define how steps for single spot are added to virtual text\n  local append_to_virt_text = function(virt_text_arr, steps, n_steps_to_show)\n    -- Use special group if current first step is unique\n    local first_hl_group = first_step_counts[steps[1]] == 1 and hl_group_unique or hl_group\n    table.insert(virt_text_arr, { steps[1], first_hl_group })\n\n    -- Add ahead steps only if they are present\n    local ahead_label = table.concat(steps):sub(2, n_steps_to_show)\n    if ahead_label ~= '' then table.insert(virt_text_arr, { ahead_label, hl_group_ahead }) end\n  end\n\n  -- Convert all spots to array of extmarks\n  local res = {}\n  local buf_id, line, col, virt_text = spots[1].buf_id, spots[1].line - 1, spots[1].column - 1, {}\n\n  for i = 1, #spots - 1 do\n    local cur_spot, next_spot = spots[i], spots[i + 1]\n    local n_steps = #cur_spot.steps\n\n    -- Find which spot steps can be shown\n    local is_in_same_line = cur_spot.buf_id == next_spot.buf_id and cur_spot.line == next_spot.line\n    local max_allowed_steps = is_in_same_line and (next_spot.column - cur_spot.column) or math.huge\n    local n_steps_to_show = math.min(n_steps, max_allowed_steps)\n\n    -- Add text for shown steps\n    append_to_virt_text(virt_text, cur_spot.steps, n_steps_to_show)\n\n    -- Finish creating extmark if next spot is far enough\n    local next_is_close = is_in_same_line and n_steps == max_allowed_steps\n    if not next_is_close then\n      table.insert(res, { buf_id = buf_id, line = line, col = col, virt_text = virt_text })\n      buf_id, line, col, virt_text = next_spot.buf_id, next_spot.line - 1, next_spot.column - 1, {}\n    end\n  end\n\n  local last_steps = spots[#spots].steps\n  append_to_virt_text(virt_text, last_steps, #last_steps)\n  table.insert(res, { buf_id = buf_id, line = line, col = col, virt_text = virt_text })\n\n  return res\nend\n\nH.spot_find_in_line = function(line_num, spotter_args, opts, cursor_pos)\n  local allowed = opts.allowed_lines\n\n  -- Adjust for cursor line\n  local cur_line = cursor_pos[1]\n  if\n    (not allowed.cursor_before and line_num < cur_line)\n    or (not allowed.cursor_at and line_num == cur_line)\n    or (not allowed.cursor_after and line_num > cur_line)\n  then\n    return {}\n  end\n\n  -- Process folds\n  local fold_indicator = vim.fn.foldclosed(line_num)\n  if fold_indicator ~= -1 then return (allowed.fold and fold_indicator == line_num) and { 1 } or {} end\n\n  -- Process blank lines\n  if vim.fn.prevnonblank(line_num) ~= line_num then return allowed.blank and { 1 } or {} end\n\n  -- Finally apply spotter\n  return opts.spotter(line_num, spotter_args)\nend\n\n-- Jump state -----------------------------------------------------------------\nH.advance_jump = function(opts)\n  local label_tbl = vim.split(opts.labels, '')\n\n  local spots = H.cache.spots\n  local n_steps_ahead = opts.view.n_steps_ahead\n\n  if type(spots) ~= 'table' or #spots < 1 then\n    H.spots_unshow(spots)\n    H.cache.spots = nil\n    return\n  end\n\n  local key = H.getcharstr('Reminder to press encoding symbol to advance jumping')\n\n  if vim.tbl_contains(label_tbl, key) then\n    H.spots_unshow(spots)\n    spots = vim.tbl_filter(function(x) return x.steps[1] == key end, spots)\n\n    if #spots > 1 then\n      spots = H.spots_add_steps(spots, label_tbl, n_steps_ahead)\n      H.spots_show(spots, opts)\n      H.cache.spots = spots\n\n      H.advance_jump(opts)\n    end\n  end\n\n  if #spots == 1 or key == H.keys.cr then H.perform_jump(spots[1], opts.hooks.after_jump) end\n\n  MiniJump2d.stop()\nend\n\nH.perform_jump = function(spot, after_hook)\n  -- Add to jumplist\n  vim.cmd('normal! m`')\n\n  vim.api.nvim_set_current_win(spot.win_id)\n  vim.api.nvim_win_set_cursor(spot.win_id, { spot.line, spot.column - 1 })\n\n  -- Possibly unfold to see cursor\n  vim.cmd('normal! zv')\n\n  if after_hook ~= nil then after_hook() end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.jump2d) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.notify = function(msg, level_name, silent)\n  if not silent then vim.notify('(mini.jump2d) ' .. msg, vim.log.levels[level_name]) end\nend\n\nH.echo = function(msg, is_important)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.jump2d) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n  local chunks, tot_width = {}, 0\n  for _, ch in ipairs(msg) do\n    local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n    table.insert(chunks, new_ch)\n    tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n    if tot_width >= max_width then break end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, is_important, {})\nend\n\nH.unecho = function()\n  if H.cache.msg_shown then vim.cmd([[echo '' | redraw]]) end\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.is_operator_pending = function()\n  return vim.tbl_contains({ 'no', 'noV', H.keys.block_operator_pending }, vim.fn.mode(1))\nend\n\nH.getcharstr = function(msg)\n  local needs_reminder = true\n  if msg ~= nil then\n    vim.defer_fn(function()\n      if not needs_reminder then return end\n      H.echo(msg)\n      H.cache.msg_shown = true\n    end, 1000)\n  end\n\n  H.cache.is_in_getcharstr = true\n  local _, char = pcall(vim.fn.getcharstr)\n  H.cache.is_in_getcharstr = false\n  needs_reminder = false\n  H.unecho()\n\n  return char\nend\n\nH.user_input = function(prompt, text)\n  -- Use `on_key` to distinguish cancel with `<Esc>` and immediate `<CR>`\n  local was_cancelled = false\n  vim.on_key(function(key) was_cancelled = was_cancelled or key == '\\27' end, H.ns_id.input)\n\n  -- Ask for input. Use `pcall` to allow `<C-c>` to cancel user input\n  vim.cmd('echohl Question')\n  local ok, res = pcall(vim.fn.input, { prompt = '(mini.jump2d) ' .. prompt .. ': ', default = text or '' })\n  vim.cmd('echohl None | echo \"\" | redraw')\n\n  vim.on_key(nil, H.ns_id.input)\n  return (ok and not was_cancelled) and res or nil\nend\n\n--- This ensures order of windows based on their layout\n---\n--- This is already done by default in `nvim_tabpage_list_wins()`, but is not\n--- documented, so can break any time.\n---\n---@private\nH.tabpage_list_wins = function(tabpage_id)\n  local wins = vim.api.nvim_tabpage_list_wins(tabpage_id)\n  local wins_pos = {}\n  for _, win_id in ipairs(wins) do\n    local pos = vim.api.nvim_win_get_position(win_id)\n    local config = vim.api.nvim_win_get_config(win_id)\n    wins_pos[win_id] = { row = pos[1], col = pos[2], zindex = config.zindex or 0 }\n  end\n\n  -- Sort windows by their position: top to bottom, left to right, low to high\n  table.sort(wins, function(a, b)\n    -- Put higher window further to have them processed later. This means that\n    -- in case of same buffer in floating and underlying regular windows,\n    -- floating will have \"the latest\" extmarks (think like `MiniMisc.zoom()`).\n    if wins_pos[a].zindex < wins_pos[b].zindex then return true end\n    if wins_pos[a].zindex > wins_pos[b].zindex then return false end\n\n    if wins_pos[a].col < wins_pos[b].col then return true end\n    if wins_pos[a].col > wins_pos[b].col then return false end\n\n    return wins_pos[a].row < wins_pos[b].row\n  end)\n\n  return wins\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.merge_unique = function(tbl_1, tbl_2)\n  if type(tbl_1) == 'table' and type(tbl_2) ~= 'table' then return tbl_1 end\n  if type(tbl_1) ~= 'table' and type(tbl_2) == 'table' then return tbl_2 end\n\n  local n_1, n_2 = #tbl_1, #tbl_2\n  local res, i, j = {}, 1, 1\n  local to_add\n  while i <= n_1 and j <= n_2 do\n    if tbl_1[i] < tbl_2[j] then\n      to_add = tbl_1[i]\n      i = i + 1\n    else\n      to_add = tbl_2[j]\n      j = j + 1\n    end\n    if res[#res] ~= to_add then table.insert(res, to_add) end\n  end\n\n  while i <= n_1 do\n    to_add = tbl_1[i]\n    if res[#res] ~= to_add then table.insert(res, to_add) end\n    i = i + 1\n  end\n  while j <= n_2 do\n    to_add = tbl_2[j]\n    if res[#res] ~= to_add then table.insert(res, to_add) end\n    j = j + 1\n  end\n\n  return res\nend\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.str_byteindex = function(s, i) return vim.str_byteindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_byteindex = function(s, i) return vim.str_byteindex(s, i) end end\n\nreturn MiniJump2d\n"
  },
  {
    "path": "lua/mini/keymap.lua",
    "content": "--- *mini.keymap* Special key mappings\n---\n--- MIT License Copyright (c) 2025 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Map keys to perform configurable multi-step actions: if condition for step\n---   one is true - execute step one action, else check step two, and so on until\n---   falling back to executing original keys. This is usually referred to as\n---   \"smart\" keys (like \"smart tab\"). See |MiniKeymap.map_multistep()|.\n---\n---   There are many built-in steps targeted for Insert mode mappings of special\n---   keys like <Tab>, <S-Tab>, <CR>, and <BS>:\n---   - Navigate and accept |popupmenu-completion|. Useful for |mini.completion|.\n---   - Navigate and expand |mini.snippets|.\n---   - Execute <CR> and <BS> respecting |mini.pairs|.\n---   - Jump before/after current tree-sitter node.\n---   - Jump before opening and after closing characters (brackets and quotes).\n---   - Increase/decrease indent when cursor is inside of it.\n---   - Delete all whitespace to the left (\"hungry backspace\").\n---   - Navigate |vim.snippet|.\n---   - Navigate and accept in [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) completion.\n---   - Navigate and accept in [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp) completion.\n---   - Navigate and expand [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip) snippets.\n---   - Execute <CR> and <BS> respecting [windwp/nvim-autopairs](https://github.com/windwp/nvim-autopairs).\n---\n--- - Map keys as \"combo\": each key acts immediately plus execute extra action if\n---   all are typed within configurable delay between each other.\n---   See |MiniKeymap.map_combo()|. Some of the common use cases include:\n---     - Map insertable keys (like \"jk\", \"kj\") in Insert and Command-line mode\n---       to exit into Normal mode.\n---     - Fight against bad habits of pressing the same navigation key by showing\n---       a notification if there are too many of them pressed in a row.\n---\n--- Sources with more details:\n--- - |MiniKeymap-examples|\n---\n--- # Setup ~\n---\n--- This module doesn't need setup, but it can be done to improve usability.\n--- Setup with `require('mini.keymap').setup({})` (replace `{}` with your `config`\n--- table). It will create global Lua table `MiniKeymap` which you can use for\n--- scripting or manually (with `:lua MiniKeymap.*`).\n---\n--- See |MiniKeymap.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minikeymap_config`\n--- will have no effect here.\n---\n--- # Comparisons ~\n---\n--- - [max397574/better-escape.nvim](https://github.com/max397574/better-escape.nvim):\n---     - Mostly similar to |MiniKeymap.map_combo()| with a different approach\n---       to creating mappings.\n---     - Mostly targeted for Insert mode mappings as pressed keys get removed\n---       automatically after typed. This module allows more general cases while\n---       requiring explicit removal of keys (usually via explicit `<BS><BS>`).\n---\n--- - [abecodes/tabout.nvim](https://github.com/abecodes/tabout.nvim):\n---     - Similar general idea as in `'jump_{after,before}_tsnode'` steps\n---       of |MiniKeymap.map_multistep()|.\n---     - Works only with enabled tree-sitter parser. This module provides\n---       fallback via 'jump_after_close' and 'jump_before_open' that work\n---       without tree-sitter parser.\n---     - 'tabout.nvim' has finer control of how the tree-sitter node movement\n---       is done, while this module has \"jump outside of current node\" behavior.\n---\n--- # Disabling ~\n---\n--- To disable acting in mappings, set `vim.g.minikeymap_disable` (globally) or\n--- `vim.b.minikeymap_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user.\n--- See |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniKeymap\n\n--- # Multi-step ~\n---\n--- See |MiniKeymap.map_multistep()| for a general description of how multi-step\n--- mappings work and what built-in steps are available.\n---\n--- Setup that works well with |mini.completion| and |mini.pairs|: >lua\n---\n---   local map_multistep = require('mini.keymap').map_multistep\n---   map_multistep('i', '<Tab>',   { 'pmenu_next' })\n---   map_multistep('i', '<S-Tab>', { 'pmenu_prev' })\n---   map_multistep('i', '<CR>',    { 'pmenu_accept', 'minipairs_cr' })\n---   map_multistep('i', '<BS>',    { 'minipairs_bs' })\n--- <\n--- Use <Tab> / <S-Tab> to also navigate and expand |mini.snippets|: >lua\n---\n---   local map_multistep = require('mini.keymap').map_multistep\n---\n---   local tab_steps = { 'minisnippets_next','minisnippets_expand','pmenu_next' }\n---   map_multistep('i', '<Tab>', tab_steps)\n---\n---   local shifttab_steps = { 'minisnippets_prev', 'pmenu_prev' }\n---   map_multistep('i', '<S-Tab>', shifttab_steps)\n--- <\n--- An extra smart <Tab> and <S-Tab>: >lua\n---\n---   local map_multistep = require('mini.keymap').map_multistep\n---\n---   -- NOTE: this will never insert tab, press <C-v><Tab> for that\n---   local tab_steps = {\n---     'minisnippets_next', 'minisnippets_expand', 'pmenu_next',\n---     'jump_after_tsnode', 'jump_after_close',\n---   }\n---   map_multistep('i', '<Tab>', tab_steps)\n---\n---   local shifttab_steps = {\n---     'minisnippets_prev',  'pmenu_prev',\n---     'jump_before_tsnode', 'jump_before_open',\n---   }\n---   map_multistep('i', '<S-Tab>', shifttab_steps)\n--- <\n--- Navigation in active |vim.snippet| session also requires mapping in |Select-mode|: >lua\n---\n---   local map_multistep = require('mini.keymap').map_multistep\n---   map_multistep({ 'i', 's' }, '<Tab>',   { 'vimsnippet_next', 'pmenu_next' })\n---   map_multistep({ 'i', 's' }, '<S-Tab>', { 'vimsnippet_prev', 'pmenu_prev' })\n--- <\n--- # Combos ~\n---\n--- See |MiniKeymap.map_combo()| for a general description of what is a combo and\n--- more caveats about its usage.\n---\n--- All combos require their left hand side keys to be typed relatively quickly.\n--- To adjust the delay between keys, add `{ delay = 500 }` (use custom value) as\n--- fourth argument.\n---\n--- ## \"Better escape\" to Normal mode ~\n---\n--- Leave into |Normal-mode| without having to reach for <Esc> key: >lua\n---\n---   -- Support most common modes. This can also contain 't', but would\n---   -- only mean to press `<Esc>` inside terminal.\n---   local mode = { 'i', 'c', 'x', 's' }\n---   require('mini.keymap').map_combo(mode, 'jk', '<BS><BS><Esc>')\n---\n---   -- To not have to worry about the order of keys, also map \"kj\"\n---   require('mini.keymap').map_combo(mode, 'kj', '<BS><BS><Esc>')\n---\n---   -- Escape into Normal mode from Terminal mode\n---   require('mini.keymap').map_combo('t', 'jk', '<BS><BS><C-\\\\><C-n>')\n---   require('mini.keymap').map_combo('t', 'kj', '<BS><BS><C-\\\\><C-n>')\n--- <\n--- ## Show bad navigation habits ~\n---\n--- Show notification if there is too much movement by repeating same key: >lua\n---\n---   local notify_many_keys = function(key)\n---     local lhs = string.rep(key, 5)\n---     local action = function() vim.notify('Too many ' .. key) end\n---     require('mini.keymap').map_combo({ 'n', 'x' }, lhs, action)\n---   end\n---   notify_many_keys('h')\n---   notify_many_keys('j')\n---   notify_many_keys('k')\n---   notify_many_keys('l')\n--- <\n--- ## Fix previous spelling mistake ~\n---\n--- Fix previous spelling mistake (see |[s| and |z=|) without manually leaving\n--- Insert mode: >lua\n---\n---   local action = '<BS><BS><Esc>[s1z=gi<Right>'\n---   require('mini.keymap').map_combo('i', 'kk', action)\n--- <\n--- ## Hide search highlighting ~\n---\n--- Use double <Esc><Esc> to execute |:nohlsearch|. Although this can also be done\n--- with `nmap <Esc> <Cmd>nohl<CR>`, the combo approach also exists and can be used\n--- to free <Esc> mapping in Normal mode for something else. >lua\n---\n---   local action = function() vim.cmd('nohlsearch') end\n---   require('mini.keymap').map_combo({ 'n','i','x','c' }, '<Esc><Esc>', action)\n--- <\n--- ## Buffer navigation ~\n---\n--- Replace some movements with easier to type alternatives: >lua\n---\n---   local map_combo = require('mini.keymap').map_combo\n---   map_combo({ 'n', 'x' }, 'll', 'g$')\n---   map_combo({ 'n', 'x' }, 'hh', 'g^')\n---   map_combo({ 'n', 'x' }, 'jj', '}')\n---   map_combo({ 'n', 'x' }, 'kk', '{')\n--- <\n---@tag MiniKeymap-examples\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniKeymap = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniKeymap.config|.\n---\n---@usage >lua\n---   require('mini.keymap').setup({}) -- replace {} with your config table\n---                                    -- needs `keymap` field present\n--- <\nMiniKeymap.setup = function(config)\n  -- Export module\n  _G.MiniKeymap = MiniKeymap\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniKeymap.config = {}\n--minidoc_afterlines_end\n\n--- Map multi-step action\n---\n--- Mapping of a multi-step action is an expression mapping (|:map-expression|).\n--- Executing a multi-step action is essentially:\n--- - Check condition for step one. If `true` - execute step one action and stop.\n--- - Check condition for step two, and so on.\n--- - If there is no more steps, fall back to returning mapped key.\n---\n--- For better user experience there are many built-in steps mostly designed\n--- to create Insert mode \"smart\" mappings of <Tab>, <S-Tab>, <CR>, and <BS>.\n--- Available built-in steps (\"For key\" is a suggestion, any can be used):\n--- >\n---  ┌─────────────────────┬────────────────┬──────────────────────────┬─────────┐\n---  │      Step name      │   Condition    │          Action          │ For key │\n---  ├─────────────────────┴────────────────┴──────────────────────────┴─────────┤\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |ins-completion-menu| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ pmenu_next          │ Pmenu visible  │ Select next (as <C-n>)   │ <Tab>   │\n---  │ pmenu_prev          │ Pmenu visible  │ Select prev (as <C-p>)   │ <S-Tab> │\n---  │ pmenu_accept        │ Item selected  │ Accept (as <C-y>)        │ <CR>    │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.snippets| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ minisnippets_next   │ Session active │ Jump to next tabstop     │ <Tab>   │\n---  │ minisnippets_prev   │ Session active │ Jump to prev tabstop     │ <S-Tab> │\n---  │ minisnippets_expand │ Can expand     │ Expand snippet at cursor │ <Tab>   │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.pairs| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ minipairs_cr        │ Module set up  │ <CR> respecting pairs    │ <CR>    │\n---  │ minipairs_bs        │ Module set up  │ <BS> respecting pairs    │ <BS>    │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Jump around in Insert mode ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ jump_after_tsnode   │ TS parser      │ Jump after node end      │ <Tab>   │\n---  │ jump_before_tsnode  │ TS parser      │ Jump before node start   │ <S-Tab> │\n---  │ jump_after_close    │ Insert mode    │ Jump after  )]}\"'`       │ <Tab>   │\n---  │ jump_before_open    │ Insert mode    │ Jump before ([{\"'`       │ <S-Tab> │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Work with whitespace ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ increase_indent     │ Is on indent   │ Increase indent          │ <Tab>   │\n---  │ decrease_indent     │ Is on indent   │ Decrease indent          │ <S-Tab> │\n---  │ hungry_bs           │ Space to left  │ Delete all space to left │ <BS>    │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |vim.snippet| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ vimsnippet_next     │ Session active │ Jump to next tabstop     │ <Tab>   │\n---  │ vimsnippet_prev     │ Session active │ Jump to prev tabstop     │ <S-Tab> │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'hrsh7th/nvim-cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ cmp_next            │ Menu visible   │ Select next item         │ <Tab>   │\n---  │ cmp_prev            │ Menu visible   │ Select prev item         │ <S-Tab> │\n---  │ cmp_accept          │ Item selected  │ Accept selected item     │ <CR>    │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'Saghen/blink.cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ blink_next          │ Menu visible   │ Select next item         │ <Tab>   │\n---  │ blink_prev          │ Menu visible   │ Select prev item         │ <S-Tab> │\n---  │ blink_accept        │ Item selected  │ Accept selected item     │ <CR>    │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'L3MON4D3/LuaSnip' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ luasnip_next        │ Session active │ Jump to next tabstop     │ <Tab>   │\n---  │ luasnip_prev        │ Session active │ Jump to prev tabstop     │ <S-Tab> │\n---  │ luasnip_expand      │ Can expand     │ Expand snippet at cursor │ <Tab>   │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'windwp/nvim-autopairs' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ nvimautopairs_cr    │ Module present │ <CR> respecting pairs    │ <CR>    │\n---  │ nvimautopairs_bs    │ Module present │ <BS> respecting pairs    │ <BS>    │\n---  └─────────────────────┴────────────────┴──────────────────────────┴─────────┘\n--- <\n--- Notes:\n--- - Executing action has limitations of |:map-expression| (like not allowed text\n---   or buffer changes, etc.). To execute complex lua code, use |vim.schedule()|\n---   inside action, return the code as string in |:map-cmd| format, or return\n---   a function to be later executed. See usage examples.\n---\n--- - Some mapped keys (like <Tab>, <CR>) might require disabling smart presets\n---   in plugins (like 'nvim-cmp', 'blink-cmp', 'nvim-autopairs').\n---\n---@param mode string|table Same as for |vim.keymap.set()|.\n---@param lhs string Same as for |vim.keymap.set()|.\n---@param steps table Array of steps. Each step can be a string with the name\n---   of built-in step or a table with two callable methods (will be called\n---   without arguments):\n---   - <condition> - return `true` if the action should be executed.\n---   - <action> - action to be executed if <condition> returns `true`.\n---     For more flexibility, it can also return a value which can be:\n---       - String - will be returned as expression output. Can be something like\n---         `\"<Tab>\"` (treat as <Tab> key) or `\"<Cmd>lua vim.notify('Hello')<CR>\"`.\n---         Should not escape keycodes (i.e. return \"<Tab>\" and not \"\\t\").\n---         To undo already done escape, use |keytrans()|.\n---       - Function - will be executed as if `\"<Cmd>lua f()<CR>\"`, but does not\n---         need to create a global function for that.\n---       - `false` - do not stop going through steps.\n---@param opts table|nil Same as for |vim.keymap.set()|.\n---\n---@usage See |MiniKeymap-examples| for practical examples.\n---\n--- Some illustrative examples: >lua\n---\n---   _G.log = {}\n---   local steps = {}\n---   steps[1] = {\n---     condition = function() table.insert(_G.log, 'C1'); return _G.cond1 end,\n---     -- Compute and return keys. Will be emulated as pressed.\n---     action = function() table.insert(_G.log, 'A1'); return 'hello' end,\n---   }\n---\n---   steps[2] = {\n---     condition = function() table.insert(_G.log, 'C2'); return _G.cond2 end,\n---     -- Perform action immediately, return `false` to keep asking other steps\n---     action = function() table.insert(_G.log, 'A2'); return false end,\n---   }\n---\n---   steps[3] = {\n---     condition = function() table.insert(_G.log, 'C3'); return _G.cond3 end,\n---     -- Perform action later (to overcom expression mapping limitations)\n---     action = function()\n---       table.insert(_G.log, 'A3_1')\n---       return function() table.insert(_G.log, 'A3_2') end\n---     end,\n---   }\n---\n---   -- Make Insert mode <Tab> mapping\n---   require('mini.keymap').map_multistep('i', '<Tab>', steps)\n---\n---   -- Pressing <Tab> inserts fallback `\\t`; logs C1+C2+C3\n---   _G.cond1, _G.cond2, _G.cond3 = false, false, false\n---\n---   -- Pressing <Tab> inserts `hello`; logs C1+A1\n---   _G.cond1, _G.cond2, _G.cond3 = true, false, false\n---\n---   -- Pressing <Tab> inserts nothing; logs C1+C2+A2+C3+A3_1+A3_2\n---   _G.cond1, _G.cond2, _G.cond3 = false, true, true\n--- <\nMiniKeymap.map_multistep = function(mode, lhs, steps, opts)\n  H.check_type('lhs', lhs, 'string')\n  local lhs_raw, n_steps = vim.api.nvim_replace_termcodes(lhs, true, true, true), #steps\n  local lhs_keycode = vim.fn.keytrans(lhs_raw)\n  steps = H.normalize_steps(steps)\n\n  local rhs = function()\n    if H.is_disabled() then return lhs_keycode end\n    for i = 1, n_steps do\n      if steps[i].condition() then\n        local out = steps[i].action()\n        -- Allow custom string as output of expression mapping\n        if type(out) == 'string' then return out end\n        -- Allow callable output to be properly wrapped in `<Cmd>...<CR>`\n        if vim.is_callable(out) then return H.wrap_in_cmd_lua(out) end\n        -- Allow `false` output to indicate \"keep processing next steps\"\n        if out ~= false then return '' end\n      end\n    end\n    return lhs_keycode\n  end\n\n  local desc = 'Multi ' .. lhs_keycode\n  opts = vim.tbl_extend('force', { desc = desc }, opts or {}, { expr = true, replace_keycodes = true })\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\n--- Generate step for multi-step mappings\n---\n--- This is a table with function elements. Call to actually get a step.\nMiniKeymap.gen_step = {}\n\n--- Search pattern step\n---\n--- Use |search()| to jump to pattern match. Possibly adjust final position to\n--- be just to the right of the match (useful in Insert mode).\n---\n---@param pattern string Same as for |search()|.\n---@param flags string|nil Same as for |search()|.\n---@param opts table|nil Options. Possible fields:\n---   - <side> `(string)` - one of `\"before\"` (default) or `\"after\"`.\n---   - <stopline> `(number|function)` - forwarded to |search()| (as number or\n---     as function's output after calling it before every search).\n---   - <timeout> `(number)` - forwarded to |search()|.\n---   - <skip> `(string|function)` - forwarded to |search()|.\n---\n---@return table Step which searches pattern.\n---\n---@usage Built-in |MiniKeymap.map_multistep()| steps \"jump_after_close\" and\n--- \"jump_before_open\" use this, but only in Insert mode.\n---\n--- Steps that jump before/after all consecutive brackets in several modes: >lua\n---\n---   local keymap = require('mini.keymap')\n---   local tab_step_insert = keymap.gen_step.search_pattern(\n---     -- Need to use 'c' flag and 'after' side for robust \"chaining\"\n---     [=[[)\\]}]\\+]=], 'ceW', { side = 'after' }\n---   )\n---   keymap.map_multistep('i', '<Tab>', { tab_step_insert })\n---   local tab_step = keymap.gen_step.search_pattern([=[[)\\]}]\\+]=], 'eW')\n---   keymap.map_multistep({ 'n', 'x' }, '<Tab>', { tab_step })\n---\n---   local stab_step = keymap.gen_step.search_pattern([=[[(\\[{]\\+]=], 'bW')\n---   keymap.map_multistep({ 'i', 'n', 'x' }, '<S-Tab>', { stab_step })\n--- <\nMiniKeymap.gen_step.search_pattern = function(pattern, flags, opts)\n  if type(pattern) ~= 'string' then H.error('`pattern` should be string, not ' .. vim.inspect(type(pattern))) end\n  flags = flags or ''\n  if type(flags) ~= 'string' then H.error('`flags` should be string, not ' .. vim.inspect(type(flags))) end\n\n  opts = vim.tbl_extend('force', { side = 'before', stopline = nil, timeout = nil, skip = nil }, opts or {})\n  local side = opts.side\n  if not (side == 'before' or side == 'after') then H.error('`opts.side` should be one of \"before\" or \"after\"') end\n\n  local stopline = opts.stopline or function() return nil end\n  if type(stopline) == 'number' then\n    local line = stopline\n    stopline = function() return line end\n  end\n  if not vim.is_callable(stopline) then H.error('`opts.stopline` should be number or callable') end\n\n  -- NOTEs:\n  -- - Using `normal!` doesn't go past the end of line and triggers\n  --   mode-change-related events.\n  -- - Adjusting pattern with `\\zs` prefix doesn't work for consecutive matches\n  --   (like `)))`), as it will match every other one (first, third, etc.).\n  -- - Using `\\@<=` quantifier doesn't work for the last match in consecutive\n  --   matches at end of line. Like `)))` at end of line won't put cursor at\n  --   end of line. The `[)\\]}]\\@<=\\_.` also doesn't seem to work.\n  local adjust_cursor = function()\n    local pos = vim.api.nvim_win_get_cursor(0)\n    vim.api.nvim_win_set_cursor(0, { pos[1], pos[2] + 1 })\n  end\n  if side == 'before' then adjust_cursor = function() end end\n\n  local act = function()\n    H.hide_completion()\n    local had_match = vim.fn.search(pattern, flags, stopline(), opts.timeout, opts.skip)\n    if had_match ~= 0 then adjust_cursor() end\n  end\n\n  return { condition = function() return true end, action = function() return act end }\nend\n\n--- Map combo post action\n---\n--- Create a combo: sequence of keys where each acts immediately plus execute\n--- an extra action if all are typed within configurable delay between each other.\n---\n--- Example for Insert mode \"better escape\" `jk` combo with `<BS><BS><Esc>` action:\n--- - Press `j`. It is visible immediately without any side effects.\n--- - Quickly (no more than default 200 ms after) press `k`. This triggers the\n---   action which is equivalent to typing <BS><BS> (delete already present `jk`)\n---   and <Esc> to exit into Normal mode.\n---\n--- Notes:\n--- - IMPORTANT! Combo is not a regular mapping but a separate key tracking\n---   with |vim.on_key()|. This is important as combos will not be visible and\n---   can not be managed as regular mappings. Instead each combo is associated\n---   with a dedicated |namespace| (named for human readability). However, it is not\n---   really expected to manage them on the fly after they are created.\n---\n--- - String action is executed with |nvim_input()|, i.e. emulated keys will\n---   respect custom mappings.\n---\n--- - Different combos are tracked and act independent of each other. For example,\n---   if there are combos for `jjk` and `jk` keys, fast typing `jjk` will execute both.\n---\n--- - Neovim>=0.11 is recommended due to |vim.on_key()| improvement to allow\n---   watching for keys as they are typed and not as if coming from mappings.\n---   For example, this matters when creating a `jk` combo for Visual mode while\n---   also having `xnoremap j gj` style of remaps. On Neovim<0.11 the fix is to\n---   use `gjgk` as combo's left hand side.\n---\n--- - Each combo adds very small but non-zero overhead on each keystroke.\n---   Usually about 1-3 microseconds (i.e. 0.001-0.003 ms), which should be\n---   fast enough for most setups. For a \"normal, real world\" coding session\n---   with a total of ~20000 keystrokes it results in extra ~40ms of overhead\n---   for a single created combo. Create many combos with caution.\n---\n---@param mode string|table String or array of string mode id (like \"n\", \"i\", etc.).\n---   Array of several modes is more performant than several single mode combos.\n---@param lhs string|table String with tracked key sequence or an array of\n---   tracked keys (one element - one key).\n---@param action string|function Action to perform after key sequence is detected.\n---   If string, treated as keys and emulated with |nvim_input()|.\n---   If function, executed in |vim.schedule()|. Can return string keys which will\n---   be emulated.\n---@param opts table|nil Options. Possible fields:\n---   - <delay> `(number)` - delay in milliseconds within which keys should be\n---     pressed to detect a key sequence. Default: 200.\n---\n---@usage See |MiniKeymap-examples| for practical examples.\n---\n--- Some illustrative examples: >lua\n---\n---   local map_combo = require('mini.keymap').map_combo\n---\n---   -- In Insert mode pressing `x` followed by `x` within 1 second logs 'A'\n---   -- and emulates extra pressing of `yy`\n---   _G.log = {}\n---   local action = function() table.insert(_G.log, 'A'); return 'yy' end\n---   map_combo('i', 'xx', action, { delay = 1000 })\n--- <\nMiniKeymap.map_combo = function(mode, lhs, action, opts)\n  if type(mode) == 'string' then mode = { mode } end\n  if not H.is_array_of(mode, H.is_string) then H.error('`mode` should be string or array of strings') end\n  local mode_tbl = H.combo_make_mode_tbl(mode)\n\n  local seq = H.combo_lhs_to_seq(lhs)\n  seq = vim.tbl_map(function(x) return vim.api.nvim_replace_termcodes(x, true, true, true) end, seq)\n\n  if not (type(action) == 'string' or vim.is_callable(action)) then\n    H.error('`action` should be either string of keys or callable')\n  end\n\n  -- Cache local values for better speed\n  opts = opts or {}\n  local delay = opts.delay or 200\n  if not (type(delay) == 'number' and delay > 0) then H.error('`opts.delay` should be a positive number') end\n\n  local hrtime, get_key = vim.loop.hrtime, H.combo_get_key\n  local i, last_time, n_seq = 0, hrtime(), #seq\n  local delay_ns = 1000000 * delay\n  -- NOTE: It is possible to track mode in 'ModeChanged' event and use it for\n  -- all combos (instead of `get_mode()` for each). Although it scales well\n  -- (O(1) instead of O(n) by number of combos), it can fail when something is\n  -- executed with 'eventignore' blocking 'ModeChanged' event (can happen with\n  -- plugins). Median `get_mode()` execution time is 0.15 microseconds and it\n  -- gets executed on every keystroke. If it proves to be too much, can be\n  -- reverted to 'ModeChanged' approach.\n  local get_mode = vim.fn.mode\n\n  -- Explicitly ignore keys from action. Otherwise they will be processed\n  -- because `nvim_input` mocks \"as if typed\" approach.\n  local input_keys = vim.schedule_wrap(function(keys)\n    H.combo_ignore = true\n    vim.api.nvim_input(keys)\n    -- NOTE: Can't unignore right away because `nvim_input` is executed later\n    H.combo_unignore_later()\n  end)\n\n  if type(action) == 'string' then\n    local keys = action\n    action = function() input_keys(keys) end\n  end\n  local act = vim.schedule_wrap(function()\n    if H.is_disabled() then return end\n    -- Allow action to return keys to manually mimic\n    local keys = action()\n    if type(keys) == 'string' and keys ~= '' then input_keys(keys) end\n  end)\n  local reset = function(key)\n    -- Make latest key start new combo, like for 'jjk' or j-wait-jj for 'jj'\n    i = seq[1] == key and 1 or 0\n    last_time = i == 0 and last_time or hrtime()\n  end\n\n  local watcher = function(key, typed)\n    -- Use only keys \"as if typed\" and in proper mode\n    key = get_key(key, typed)\n    if key == '' or (i == 0 and not mode_tbl[get_mode()]) or H.combo_ignore then return end\n\n    -- Advance tracking and reset if not in sequence\n    i = i + 1\n    if seq[i] ~= key then return reset(key) end\n\n    -- Reset if time between key presses is too big\n    local cur_time = hrtime()\n    if (cur_time - last_time) > delay_ns and i > 1 then return reset(key) end\n    last_time = cur_time\n\n    -- Wait for more info if sequence is not exhausted, act otherwise\n    if i < n_seq then return end\n    i = 0\n    act()\n  end\n\n  local combo_keys = table.concat(vim.tbl_map(vim.fn.keytrans, seq), '')\n  local ns_name = string.format('MiniKeymap-combo-%s-%s-%s', #H.ns_id_combo, table.concat(mode, ''), combo_keys)\n  local ns_id = vim.api.nvim_create_namespace(ns_name)\n  table.insert(H.ns_id_combo, ns_id)\n\n  return vim.on_key(watcher, ns_id)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniKeymap.config)\n\n-- Namespaces for `on_key`\nH.ns_id_combo = {}\n\n-- Current mode used in \"combo\" mappings, for better speed\nH.cur_mode = 'n'\n\n-- Whether to ignore current keys as part of the combo. Needs to be global for\n-- combo's RHS keys not interfering with tracking of other combos.\nH.combo_ignore = false\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n  return config\nend\n\nH.apply_config = function(config) MiniKeymap.config = config end\n\nH.is_disabled = function() return vim.g.minikeymap_disable == true or vim.b.minikeymap_disable == true end\n\n-- Combo ----------------------------------------------------------------------\nH.combo_lhs_to_seq = function(lhs)\n  if H.is_array_of(lhs, H.is_string) then return vim.deepcopy(lhs) end\n  if type(lhs) ~= 'string' then H.error('`lhs` should be string or array of strings') end\n\n  local res, i = {}, 1\n  while i <= lhs:len() do\n    local k, new_i = string.match(lhs, '^(%b<>)()', i)\n    if k == nil or k:find('^.+<') ~= nil then\n      k, new_i = vim.fn.strcharpart(lhs, i - 1, 1), i + 1\n    end\n    table.insert(res, k)\n    i = new_i\n  end\n  return res\nend\n\nH.combo_make_mode_tbl = function(mode)\n  local res = {}\n  for _, m in ipairs(mode) do\n    if m == 'x' then\n      res.v, res.V, res['\\22'] = true, true, true\n    elseif m == 'v' then\n      res.s, res.v, res.V, res['\\22'] = true, true, true, true\n    else\n      res[m] = true\n    end\n  end\n  return res\nend\n\nH.combo_unignore_later = vim.schedule_wrap(function() H.combo_ignore = false end)\n\nH.combo_get_key = function(_, typed) return typed end\nif vim.fn.has('nvim-0.11') == 0 then H.combo_get_key = function(key) return key end end\n\n-- Multi-step -----------------------------------------------------------------\nH.normalize_steps = function(steps)\n  if not H.islist(steps) then H.error('`steps` should be array') end\n  local res = {}\n  for i, step in ipairs(steps) do\n    local s = type(step) == 'string' and H.steps_builtin[step] or step\n    local is_step = type(s) == 'table' and vim.is_callable(s.condition) and vim.is_callable(s.action)\n    if not is_step then H.error('`steps` should contain valid steps, not ' .. vim.inspect(step)) end\n    table.insert(res, s)\n  end\n\n  return res\nend\n\nH.wrap_in_cmd_lua = function(f)\n  local needs_global_cleanup = _G.MiniKeymap == nil\n  _G.MiniKeymap = _G.MiniKeymap or {}\n  _G.MiniKeymap._f = f\n  local extra_cleanup = needs_global_cleanup and '; MiniKeymap = nil' or ''\n  return '<Cmd>lua MiniKeymap._f(); MiniKeymap._f = nil' .. extra_cleanup .. '<CR>'\nend\n\nH.make_cmd_lua_action = function(cmd_string)\n  return function() return '<Cmd>lua ' .. cmd_string .. '<CR>' end\nend\n\nH.has_module = function(name) return (pcall(require, name)) end\n\n--stylua: ignore start\nH.steps_builtin = {}\n\nH.is_visible_pmenu  = function() return vim.fn.pumvisible() == 1 end\nH.is_selected_pmenu = function() return vim.fn.complete_info({ 'selected' }).selected ~= -1 end\n\nH.steps_builtin.pmenu_next   = { condition = H.is_visible_pmenu,  action = function() return '<C-n>' end }\nH.steps_builtin.pmenu_prev   = { condition = H.is_visible_pmenu,  action = function() return '<C-p>' end }\nH.steps_builtin.pmenu_accept = { condition = H.is_selected_pmenu, action = function() return '<C-y>' end }\n\nH.is_minisnippets_session  = function() return _G.MiniSnippets ~= nil and _G.MiniSnippets.session.get() ~= nil end\nH.is_minisnippets_matched  = function() return _G.MiniSnippets ~= nil and #_G.MiniSnippets.expand({ insert = false }) > 0 end\nH.make_minisnippets_action = function(dir) return H.make_cmd_lua_action('MiniSnippets.session.jump(\"' .. dir .. '\")') end\n\nH.steps_builtin.minisnippets_next   = { condition = H.is_minisnippets_session, action = H.make_minisnippets_action('next') }\nH.steps_builtin.minisnippets_prev   = { condition = H.is_minisnippets_session, action = H.make_minisnippets_action('prev') }\nH.steps_builtin.minisnippets_expand = { condition = H.is_minisnippets_matched, action = H.make_cmd_lua_action('MiniSnippets.expand()') }\n\nH.has_minipairs = function() return _G.MiniPairs ~= nil end\n\nH.steps_builtin.minipairs_cr = { condition = H.has_minipairs, action = function() return vim.fn.keytrans(_G.MiniPairs.cr()) end }\nH.steps_builtin.minipairs_bs = { condition = H.has_minipairs, action = function() return vim.fn.keytrans(_G.MiniPairs.bs()) end }\n\nH.can_jump_tsnode = function()\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, 0, nil, { error = false })\n  return has_parser and parser ~= nil\nend\n\nH.make_jump_tsnode = function(side)\n  local act = function()\n    local node, pos, new_pos = H.get_tsnode(), vim.api.nvim_win_get_cursor(0), nil\n    while node ~= nil do\n      -- Output of `get_node_range` is 0-indexed with \"from\" data inclusive and\n      -- \"to\" data exclusive. This is exactly what is needed here:\n      -- - For \"before\" direction exact left end is needed. This will be used\n      --   in Insert mode and cursor will be between target and its left cell.\n      -- - For \"after\" direction the one cell to right (after normalization) is\n      --   needed because cursor in Insert mode will be just after the node.\n      local from_row, from_col, to_row, to_col = vim.treesitter.get_node_range(node)\n      local row = side == 'before' and from_row or to_row\n      local col = side == 'before' and from_col or to_col\n      new_pos = H.normalize_pos(row, col)\n      -- Iterate up the tree until different position is found. This is useful\n      -- for \"before\" direction and non-Insert mode.\n      if not (new_pos[1] == pos[1] and new_pos[2] == pos[2]) then\n        H.hide_completion()\n        pcall(vim.api.nvim_win_set_cursor, 0, new_pos)\n        new_pos = vim.api.nvim_win_get_cursor(0)\n      end\n      if not (new_pos[1] == pos[1] and new_pos[2] == pos[2]) then break end\n      node = node:parent()\n    end\n  end\n\n  -- Return callable which is wrapped to be executed after expression mapping\n  return function() return act end\nend\n\nH.steps_builtin.jump_after_tsnode  = { condition = H.can_jump_tsnode, action = H.make_jump_tsnode('after') }\nH.steps_builtin.jump_before_tsnode = { condition = H.can_jump_tsnode, action = H.make_jump_tsnode('before') }\n\nH.steps_builtin.jump_after_close = {\n  condition = function() return vim.fn.mode() == 'i' end,\n  -- NOTE: In Insert mode 'c' flag (accept at cursor) with 'after' adjust are\n  -- needed for working \"chaining\". In other modes it is no flag and no adjust,\n  -- which is why these steps only work in Insert mode.\n  action = MiniKeymap.gen_step.search_pattern([=[[)\\]}\"'`]]=], 'cW', { side = 'after' }).action,\n}\nH.steps_builtin.jump_before_open = {\n  condition = function() return vim.fn.mode() == 'i' end,\n  action = MiniKeymap.gen_step.search_pattern([=[[(\\[{\"'`]]=], 'bW', { side = 'before' }).action,\n}\n\nH.is_in_indent = function()\n  local line, col = vim.api.nvim_get_current_line(), vim.fn.col('.')\n  local offset = vim.fn.mode() == 'i' and 1 or 0\n  return line:sub(1, col - offset):find('^%s*$') ~= nil\nend\n\nH.increase_indent_keys = { i = '<C-t>', v = '>', V = '>', ['\\22'] = '>' }\nH.decrease_indent_keys = { i = '<C-d>', v = '<', V = '<', ['\\22'] = '<' }\n\nH.steps_builtin.increase_indent = { condition = H.is_in_indent, action = function() return H.increase_indent_keys[vim.fn.mode()] or '>>' end }\nH.steps_builtin.decrease_indent = { condition = H.is_in_indent, action = function() return H.decrease_indent_keys[vim.fn.mode()] or '<<' end }\n\nH.hungry_bs_condition = function()\n  local line, col = vim.api.nvim_get_current_line(), vim.fn.col('.')\n  local offset = vim.fn.mode() == 'i' and 1 or 0\n  return line:sub(1, col - offset):find('%s+$') ~= nil\nend\n\nH.hungry_bs_action = function()\n  return function()\n    local line, lnum, col = vim.api.nvim_get_current_line(), vim.fn.line('.'), vim.fn.col('.')\n    local offset = vim.fn.mode() == 'i' and 1 or 0\n    local from_col = line:sub(1, col - offset):match('()%s+$')\n    vim.api.nvim_buf_set_text(0, lnum - 1, from_col - 1, lnum - 1, col - offset, {})\n    vim.api.nvim_win_set_cursor(0, { lnum, from_col - 1 })\n  end\nend\n\nH.steps_builtin.hungry_bs = { condition = H.hungry_bs_condition, action = H.hungry_bs_action }\n\nH.make_vimsnippet_condition = function(dir) return function() return vim.snippet.active({ direction = dir }) end end\nH.make_vimsnippet_action    = function(dir) return H.make_cmd_lua_action('vim.snippet.jump(' .. dir .. ')') end\n\nH.steps_builtin.vimsnippet_next = { condition = H.make_vimsnippet_condition(1),  action = H.make_vimsnippet_action(1) }\nH.steps_builtin.vimsnippet_prev = { condition = H.make_vimsnippet_condition(-1), action = H.make_vimsnippet_action(-1) }\n\nH.is_visible_cmp  = function() return H.has_module('cmp') and require('cmp').visible() end\nH.is_selected_cmp = function() return H.has_module('cmp') and require('cmp').get_selected_entry() ~= nil end\nH.make_cmp_action = function(action) return H.make_cmd_lua_action('require(\"cmp\").' .. action .. '()') end\n\nH.steps_builtin.cmp_next   = { condition = H.is_visible_cmp,  action = H.make_cmp_action('select_next_item') }\nH.steps_builtin.cmp_prev   = { condition = H.is_visible_cmp,  action = H.make_cmp_action('select_prev_item') }\nH.steps_builtin.cmp_accept = { condition = H.is_selected_cmp, action = H.make_cmp_action('confirm') }\n\nH.is_visible_blink  = function() return H.has_module('blink.cmp') and require('blink.cmp').is_menu_visible() end\nH.is_selected_blink = function() return H.is_visible_blink() and require('blink.cmp').get_selected_item() ~= nil end\nH.make_blink_action = function(action) return H.make_cmd_lua_action('require(\"blink.cmp\").' .. action .. '()') end\n\nH.steps_builtin.blink_next   = { condition = H.is_visible_blink,  action = H.make_blink_action('select_next') }\nH.steps_builtin.blink_prev   = { condition = H.is_visible_blink,  action = H.make_blink_action('select_prev') }\nH.steps_builtin.blink_accept = { condition = H.is_selected_blink, action = H.make_blink_action('accept') }\n\nH.make_luasnip_condition = function(dir) return function() return H.has_module('luasnip') and require('luasnip').jumpable(dir) end end\nH.is_luasnip_expandable  = function() return H.has_module('luasnip') and require('luasnip').expandable() end\nH.make_luasnip_action    = function(dir) return H.make_cmd_lua_action('require(\"luasnip\").jump(' .. dir .. ')') end\n\nH.steps_builtin.luasnip_next   = { condition = H.make_luasnip_condition(1),  action = H.make_luasnip_action(1) }\nH.steps_builtin.luasnip_prev   = { condition = H.make_luasnip_condition(-1), action = H.make_luasnip_action(-1) }\nH.steps_builtin.luasnip_expand = { condition = H.is_luasnip_expandable,      action = H.make_cmd_lua_action('require(\"luasnip\").expand()') }\n\nH.has_nvimautopairs         = function() return H.has_module('nvim-autopairs') end\nH.make_nvimautopairs_action = function(method) return function() return vim.fn.keytrans(require('nvim-autopairs')[method]()) end end\n\nH.steps_builtin.nvimautopairs_cr = { condition = H.has_nvimautopairs, action = H.make_nvimautopairs_action('autopairs_cr') }\nH.steps_builtin.nvimautopairs_bs = { condition = H.has_nvimautopairs, action = H.make_nvimautopairs_action('autopairs_bs') }\n--stylua: ignore end\n\n-- Validators -----------------------------------------------------------------\nH.is_string = function(x) return type(x) == 'string' end\n\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for i = 1, #x do\n    if not predicate(x[i]) then return false end\n  end\n  return true\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.keymap) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.notify = function(msg, level_name, silent)\n  if not silent then vim.notify('(mini.keymap) ' .. msg, vim.log.levels[level_name]) end\nend\n\nH.normalize_pos = function(row, col)\n  -- Input is {0,0} indexed, output is {1,0} indexed\n  if row < 0 or (row == 0 and col < 0) then return { 1, 0 } end\n  local last_row = vim.api.nvim_buf_line_count(0) - 1\n  local n_col_last_row = H.get_row_cols(last_row)\n  -- Assume this is used in Insert node, so placing just after EOL can be done\n  if row > last_row or (row == last_row and col > n_col_last_row) then return { last_row + 1, n_col_last_row } end\n\n  if col < 0 then return { row, H.get_row_cols(row - 1) } end\n  if col > H.get_row_cols(row) then return { row + 2, 0 } end\n  return { row + 1, col }\nend\n\nH.get_row_cols = function(row) return vim.fn.getline(row + 1):len() end\n\nH.get_tsnode = function() return vim.treesitter.get_node() end\n\nH.hide_completion = function()\n  -- NOTE: `complete()` instead of emulating <C-y> works immediately (without\n  -- the need to `vim.schedule()`). See 'mini.snippets' for more details.\n  -- NOTE: Checking 'pumvisible() == 1' should not lead to edge cases from\n  -- 'mini.snippets' (as there is no extmarks involved).\n  if vim.fn.mode() == 'i' and vim.fn.pumvisible() == 1 then vim.cmd('silent noautocmd call complete(col(\".\"), [])') end\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniKeymap\n"
  },
  {
    "path": "lua/mini/map.lua",
    "content": "--- *mini.map* Window with buffer text overview\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Features:\n--- - Show and manage special floating window displaying automatically updated\n---   overview of current buffer text. Window takes up whole height of Neovim\n---   instance and is fixed to a left/right side. Map content is computed by\n---   taking all current lines, converting it to binary whitespace/non-whitespace\n---   mask, rescaling to appropriate dimensions, and converting back to strings\n---   consisting from special encoding symbols. All this is done **very fast** and\n---   **asynchronously**. See |MiniMap.open()|, |MiniMap.refresh()|, |MiniMap.close()|,\n---   |MiniMap.toggle()|, |MiniMap.toggle_side()|.\n---   For a general overview and tips, see |mini.map-usage|.\n---\n--- - Show scrollbar next to map content. It represents current line and view\n---   (top and bottom visible lines). Can be the only thing shown, making map\n---   window a \"pure scrollbar\". See \"Pure scrollbar config\" section in\n---   |MiniMap.config|.\n---\n--- - Highlight map lines representing certain data in current buffer. This is\n---   done via extensible set of callables, called integrations (see\n---   \"Integrations\" section in |MiniMap.config|). There are pre-built generators\n---   for common integrations:\n---     - Builtin search (as result of |/| and similar).\n---     - Builtin diagnostic (taken from |vim.diagnostic.get()|).\n---     - General diff hunks provided by |mini.diff|.\n---     - Hunks computed provided by 'lewis6991/gitsigns.nvim'.\n---   For more details see |MiniMap.gen_integration|.\n---\n--- - Focus on map window to quickly browse current (source) buffer. Moving inside\n---   map window updates cursor position in source window enabling fast and\n---   targeted buffer exploration. To focus back, hit `<CR>` to accept current\n---   explored position or `<Esc>` to go back to original position. See\n---   |MiniMap.toggle_focus()|.\n---\n--- - Customizable via |MiniMap.config| and/or `opts` argument of |MiniMap.open()|\n---   or |MiniMap.refresh()|:\n---     - Encoding symbols used to display binary information of different\n---       resolution (default is 3x2). There are pre-built generators for\n---       different basic character families and resolutions. See\n---       |MiniMap.gen_encode_symbols|.\n---     - Scrollbar symbols, separate for line and view. Can have any width\n---       (even zero, which virtually disables scrollbar).\n---     - Integrations producing map line highlights.\n---     - Window options: side (left/right), width, 'winblend', and more.\n---\n--- What it doesn't do:\n--- - Automatically refresh when typing in Insert mode. Although it can be done in\n---   non-blocking way, it still might introduce considerable computation overhead\n---   (especially in very large files).\n--- - Has more flexible window configuration. In case a full height floating\n---   window obstructs vision of underlying buffers, use |MiniMap.toggle()| or\n---   |MiniMap.toggle_side()|. Works best with global statusline.\n--- - Provide autoopen functionality. Due to vast differences in user preference\n---   of when map window should be shown, set up of automatic opening is left to\n---   user. A common approach would be to call `MiniMap.open()` on |VimEnter| event.\n---   If you use |mini.starter|, you can modify `<CR>` buffer mapping: >lua\n---\n---     local set_map_keymap = function()\n---       local rhs = function()\n---         MiniStarter.eval_current_item()\n---         MiniMap.open()\n---       end\n---       vim.keymap.set('n', '<CR>', rhs, { buffer = true })\n---     end\n---     local opts = { pattern = 'MiniStarterOpened', callback = set_map_keymap }\n---     vim.api.nvim_create_autocmd('User', opts)\n--- <\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.map').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniMap`\n--- which you can use for scripting or manually (with `:lua MiniMap.*`).\n---\n--- See |MiniMap.config| for available config settings.\n---\n--- You can override runtime config settings (like `config.modifiers`) locally\n--- to buffer inside `vim.b.minimap_config` which should have same structure\n--- as `MiniMap.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies (provide extra functionality for integrations):\n--- - Enabled |mini.diff| module for general diff highlighting via\n---   |MiniMap.gen_integration.diff()|. If missing, no highlighting is added.\n--- - Plugin [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n---   for Git status highlighting via |MiniMap.gen_integration.gitsigns()|.\n---   If missing, no highlighting is added.\n---\n--- # Comparisons ~\n---\n--- - [wfxr/minimap.vim](https://github.com/wfxr/minimap.vim):\n---     - 'mini.map' doesn't have dependencies while being as fast as written\n---       in Rust dependency of 'minimap.vim'.\n---     - 'mini.map' uses floating window, while 'minimap.vim' uses regular one.\n---     - 'mini.map' provides slightly different visual interface with\n---       scrollbar and integration counts.\n---     - 'mini.map' allows encode symbols customization, 'minimap.vim' does not.\n---     - 'mini.map' allows extending highlight integrations, while only\n---       builtin search and git status are supported in 'minimap.vim'.\n---     - 'mini.map' updates in asynchronous (non-blocking) fashion, 'minimap.vim'\n---       does not.\n---     - 'mini.map' can be used as a pure scrollbar, 'minimap.vim' can not.\n--- - [dstein64/nvim-scrollview](https://github.com/dstein64/nvim-scrollview):\n---     - 'mini.map' has two-part scrollbar showing current line and view (with\n---       variable height), while 'nvim-scrollview' shows only current view\n---       (with fixed height).\n---     - 'nvim-scrollview' respects folds, i.e. shows view of visible lines,\n---       while 'mini.map' by design always shows view based on actual lines.\n---     - 'nvim-scrollview' creates scrollbar which can be dragged with mouse,\n---       while 'mini.nvim' does not, by design (use |MiniMap.toggle_focus()|).\n---     - 'mini.map' can show buffer outline, while 'nvim-scrollview' can not.\n---     - 'mini.map' can show highlight integrations, while 'nvim-scrollview'\n---       can not.\n--- - [petertriho/nvim-scrollbar](https://github.com/petertriho/nvim-scrollbar):\n---     - 'mini.map' has two-part scrollbar showing current line and view (with\n---       variable height), while 'nvim-scrollbar' shows only current view.\n---     - 'mini.map' can show buffer outline, while 'nvim-scrollbar' can not.\n---     - 'mini.map' has fully extendable highlight integrations, while\n---       'nvim-scrollbar' only supports diagnostic and search (with dependency).\n--- - [lewis6991/satellite.nvim](https://github.com/lewis6991/satellite.nvim):\n---     - Almost the same differences as with 'dstein64/nvim-scrollview', except\n---       'satellite.nvim' can display some set of integration highlights.\n---\n--- # Highlight groups ~\n---\n--- - `MiniMapNormal` - basic highlight of whole window.\n--- - `MiniMapSymbolCount` - counts of per-line integration items.\n--- - `MiniMapSymbolLine` - scrollbar part representing current line.\n--- - `MiniMapSymbolView` - scrollbar part representing current view.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minimap_disable` (globally) or `vim.b.minimap_disable`\n--- (for a buffer) to `true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniMap\n\n--- # Mappings ~\n---\n--- This module doesn't make mappings, only provides functions for users to map\n--- manually. Here is how one |<Leader>| set of mappings can be constructed: >lua\n---\n---   vim.keymap.set('n', '<Leader>mc', MiniMap.close)\n---   vim.keymap.set('n', '<Leader>mf', MiniMap.toggle_focus)\n---   vim.keymap.set('n', '<Leader>mo', MiniMap.open)\n---   vim.keymap.set('n', '<Leader>mr', MiniMap.refresh)\n---   vim.keymap.set('n', '<Leader>ms', MiniMap.toggle_side)\n---   vim.keymap.set('n', '<Leader>mt', MiniMap.toggle)\n--- <\n--- # How automatic refresh works ~\n---\n--- Automatic refresh is done by calling |MiniMap.refresh()| when appropriate\n--- |events| occur. It is done with specially chosen `parts` argument value (to\n--- avoid unnecessary computations). For example, when only cursor has moved\n--- (|CursorMoved|), only scrollbar is updated; so no recomputation of integrations\n--- or line encoding is done.\n---\n--- To avoid visual clutter, automatic refresh is done only in normal buffers\n--- and help pages (i.e. with |'buftype'| being empty or \"help\")\n---\n--- When you think content is not up to date, try one of these:\n--- - Call |MiniMap.refresh()| manually. Make mapping to make it easier.\n--- - Save current buffer, for example with |:write|.\n--- - Exit and enter Normal mode (if your Neovim version supports |ModeChanged|).\n---@tag mini.map-usage\n\n---@alias __map_opts table|nil Options used to define map configuration. Same structure\n---   as |MiniMap.config|. Will have effect until at least one tabpage has opened\n---   map window. Default values are taken in the following order:\n---   - From `opts` field of |MiniMap.current|.\n---   - From `vim.b.minimap_config`.\n---   - From |MiniMap.config|.\n\n---@diagnostic disable:undefined-field\n\n-- Module definition ==========================================================\nlocal MiniMap = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniMap.config|.\n---\n---@usage >lua\n---   require('mini.map').setup() -- use default config\n---   -- OR\n---   require('mini.map').setup({}) -- replace {} with your config table\n--- <\nMiniMap.setup = function(config)\n  -- Export module\n  _G.MiniMap = MiniMap\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Symbols ~\n---\n--- Options in `config.symbols` define characters used to display various\n--- information in map window.\n---\n--- ## Encode symbols ~\n---\n--- The `config.symbols.encode` option defines which characters are used to\n--- encode source buffer lines. For details of encode algorithm, see\n--- |MiniMap.encode_strings()|.\n---\n--- This option should be a table with the following structure:\n--- - <resolution> field - table containing <row> and <col> elements with row\n---   and column resolution of each symbol. This defines encoding structure and\n---   number of needed encode symbols.\n--- - Numerical fields 1, 2, ..., 2^(row_resolution * col_resolution). Each symbol\n---   represents a `(row_resolution, col_resolution)` boolean mask (`true` for\n---   non-whitespace, `false` for whitespace), created as (reversed) binary digit:\n---   `true` as 1; `false` as 0. Traversing left-right, top-bottom (top-left is\n---   lowest bit, bottom-right - highest). So first symbol encodes a complete\n---   whitespace, last - complete non-whitespace.\n---\n--- If `nil` (default), output of |MiniMap.gen_encode_symbols.block()| with `'3x2'`\n--- identifier is used.\n---\n--- Example: { '1', '2', '3', '4', resolution = { row = 1, col = 2 } }. This\n--- will encode two characters in each input row. So a string `'  a  aaa'` will\n--- be encoded as `'1234'`.\n---\n--- There are pre-built generators of encode symbols:\n--- - |MiniMap.gen_encode_symbols.block()|\n--- - |MiniMap.gen_encode_symbols.dot()|\n--- - |MiniMap.gen_encode_symbols.shade()|\n---\n--- ## Scrollbar symbols ~\n---\n--- Options `config.symbols.scroll_line` and `config.symbols.scroll_view` define\n--- strings used to represent current line and current view inside map window.\n--- Can have any length, map window content will adjust.\n---\n--- If supplied window width is small enough so that only (part of) of\n--- scrollbar can be shown, it is called a \"pure scrollbar\". The behavior differs\n--- slightly from normal map window. See \"Pure scrollbar config\" later section.\n---\n--- Some suggestions for scrollbar symbols:\n--- - View-line pairs: '▒' and '█'.\n--- - Line - '🮚', '▶'.\n--- - View - '╎', '┋', '┋'.\n---\n--- # Integrations ~\n---\n--- Option `config.integrations` is an array of integrations. Each one is used\n--- to define map line highlights representing some important lines in source\n--- buffer. If `nil` (default), no integrations are used.\n---\n--- Each integration should be a callable returning an array with data about\n--- **source buffer** lines it wants to highlight. Each array element should be\n--- a table with <line> (source buffer line number) and <hl_group> (string with\n--- highlight group name) keys. Note: line number outside of source buffer\n--- count will be converted to a nearest appropriate one.\n---\n--- Example output of single integration: >lua\n---\n---   {\n---     { line = 1, hl_group = 'Search' },\n---     { line = 2, hl_group = 'Operator' },\n---     { line = 9, hl_group = 'Search'}\n---   }\n--- <\n--- Conversion to map highlights is done on a \"first seen\" basis: actual\n--- highlight group applied to a map line is taken from the first integration\n--- output convertible to that map line. Other outputs with same map line\n--- (after conversion) contribute to integration count shown between scrollbar\n--- and encoded lines (if `config.window.show_integration_count` is `true`).\n---\n--- Previous example output with default `'3x2'` resolution will add |hl-Search|\n--- highlight on map lines 1 and 3, and show integration count 2 on first line.\n---\n--- Every element of integrations array is called one by one from start to end\n--- with their outputs appended to end of single array. This means that more\n--- important integrations should be placed in the beginning of an array, as\n--- this will make them have higher priority in case other integrations will\n--- highlight same map line.\n---\n--- Example of using `config.integrations`: >lua\n---\n---   local map = require('mini.map')\n---   map.setup({\n---     integrations = {\n---       map.gen_integration.builtin_search(),\n---       map.gen_integration.diff(),\n---       map.gen_integration.diagnostic(),\n---     },\n---   })\n--- <\n--- # Window config ~\n---\n--- Option `config.window` defines some properties of map window.\n---\n--- `window.focusable` - whether to allow focusing on map window with other\n--- methods beside |MiniMap.toggle_focus()| (like |:wincmd|, |CTRL-W|, or mouse).\n--- Default: `false`.\n---\n--- `window.side` - which side to stick map window: `'left'` or `'right'` (default).\n---\n--- `window.show_integration_count` - whether to show integration count between\n--- scrollbar and encoded lines. Integration count is a number of integration\n--- outputs which were converted to same map line. When `true`, adds single\n--- cell column with numbers from 2 to 9 and character '+' indicating count\n--- greater than 9. Count 1 is not shown, because it is redundant to highlighted\n--- map line. Default: `true`.\n---\n--- `window.width` - width of floating window, including scrollbar and\n--- integration count column. Default: 10.\n---\n--- `window.winblend` - value of 'winblend' of floating window. Value 0 makes it\n--- completely non-transparent, 100 - completely transparent (content is still\n--- visible, but with slightly different highlights).\n---\n--- `window.zindex` - z-index of floating window. Default: 10.\n---\n--- # Pure scrollbar config ~\n---\n--- \"Pure scrollbar\" is a configuration when window width is not enough to show\n--- encoded content. It has following differences from default \"map\" approach:\n--- - It doesn't perform line encoding with |MiniMap.encode_strings()|\n---   but instead uses encoding with fixed number of lines (equal to window\n---   height).\n--- - Integration highlights are not computed.\n---\n--- Config: >lua\n---\n---   require('mini.map').setup({\n---     -- Customize `symbols` to your liking\n---\n---     window = {\n---       -- Set this to the maximum width of your scroll symbols\n---       width = 1,\n---\n---       -- Set this to your liking. Try values 0, 25, 50, 75, 100\n---       winblend = 100,\n---\n---       -- Don't need extra column\n---       show_integration_count = false,\n---     }\n---   })\n--- <\nMiniMap.config = {\n  -- Highlight integrations (none by default)\n  integrations = nil,\n\n  -- Symbols used to display data\n  symbols = {\n    -- Encode symbols. See `:h MiniMap.config` for specification and\n    -- `:h MiniMap.gen_encode_symbols` for pre-built ones.\n    -- Default: solid blocks with 3x2 resolution.\n    encode = nil,\n\n    -- Scrollbar parts for view and line. Use empty string to disable any.\n    scroll_line = '█',\n    scroll_view = '┃',\n  },\n\n  -- Window options\n  window = {\n    -- Whether window is focusable in normal way (with `wincmd` or mouse)\n    focusable = false,\n\n    -- Side to stick ('left' or 'right')\n    side = 'right',\n\n    -- Whether to show count of multiple integration highlights\n    show_integration_count = true,\n\n    -- Total width\n    width = 10,\n\n    -- Value of 'winblend' option\n    winblend = 25,\n\n    -- Z-index\n    zindex = 10,\n  },\n}\n--minidoc_afterlines_end\n\n--- Table with information about current state of map\n---\n--- At least these keys are supported:\n--- - <buf_data> - table with buffer identifiers. Field <map> contains\n---   identifier of a buffer used to display map. Field <source> - buffer\n---   identifier which content map is displaying (i.e. source buffer).\n--- - <win_data> - table of window identifiers used to display map in certain\n---   tabpage. Keys: tabpage identifier. Values: window identifier.\n--- - <opts> - current options used to control map display. Same structure\n---   as |MiniMap.config|. Takes precedence over global and buffer-local configs.\n---   Is reset when last map window is closed with |MiniMap.close()|.\nMiniMap.current = {\n  buf_data = {},\n  win_data = {},\n  opts = {},\n}\n\n-- Module functionality =======================================================\n--- Encode strings\n---\n--- This takes arbitrary array of strings and computes its non-whitespace\n--- outline. Output is an array of strings with configurable array length, string\n--- width, and symbols representing encoding.\n---\n--- Each encode symbol is assumed to have resolution within which it can convey\n--- binary information. For example, resolution `3x2` (row resolution 3,\n--- column - 2) means that each symbol can encode 3 rows and 2 columns of\n--- binary data. Here it is used to encode non-whitespace mask. See more in\n--- \"Encode symbols\" section of |MiniMap.config|.\n---\n--- Encoding has the following steps:\n--- - Convert strings to boolean mask: 2d boolean array with each row\n---   representing a string. Element in every row subarray is `true` if\n---   respective (possibly multibyte) character in a string is not a whitespace,\n---   `false` otherwise. Note: tabs are expanded into 'tabstop' spaces.\n--- - Rescale to appropriate dimensions:\n---     - Each output dimension is just enough to encode all input strings, but\n---       not more than supplied dimensions (`opts.n_rows * resolution.row` and\n---       `opts.n_cols * resolution.col` respectively).\n---     - If input dimensions are too big to fit inside output, perform grid\n---       downscaling with loss of information. Input boolean mask is divided\n---       into 2d-bins with as equal as possible dimensions. Each bin then\n---       converted into single boolean value: `true` if bin contains at least\n---       one `true` element, `false` otherwise. This leads to a whitespace\n---       output meaning that **all** entries in a bin are whitespace, while\n---       non-whitespace output means that **some** entry is non-whitespace.\n--- - Convert boolean mask to symbol strings:\n---     - Input rescaled boolean mask is divided into bins with dimensions of\n---       symbol resolution (assuming `false` outer padding).\n---     - Each bin with resolution dimensions is transformed into encode symbol.\n---       Single convertible `(resolution.row, resolution.col)` boolean\n---       mask is treated as (reversed) binary digit: `true` as 1; `false` as 0.\n---       Traversing left-right, top-bottom (top-left is lowest bit,\n---       bottom-right - highest).\n---\n--- Example:\n---\n--- Assume the output should have 3 rows of symbols each with width 2. Encode\n--- symbols are ' ', '▌', '▐', '█' with `1x2` resolution.\n---\n--- Assume input strings: >\n---   aaaaa\n---    b b\n---\n---    d d\n---   e e\n--- <\n--- Steps:\n--- - Convert to boolean mask (each row is a boolean array, \"t\"/\"f\" ~ `true`/`false`,\n---   empty spots are equivalent to being `false`): >\n---   ttttt\n---   ftft\n---\n---   ftft\n---   tft\n--- <\n--- - Rescale. Output dimensions are `n_rows * resolution.row = 3 * 1 = 3` rows and\n---   `n_cols * resolution.col = 2 * 2 = 4`. It creates as equal as possible grid\n---   with 3 rows and 4 columns and converts bins to single booleans. Result: >\n---   tttt\n---   tftf\n---   ttff\n--- <\n--- - Convert to symbols. It makes `1x2` bins, treats their input as (reversed)\n---   binary digits (`ff=00=0`, `tf=10=1`, `ft=01=2`, `tt=11=3`) and takes\n---   corresponding symbols from supplied options (value plus 1). Result: >\n---   ██\n---   ▌▌\n---   █\n--- <\n---@param strings table Array of arbitrary strings.\n---@param opts table|nil Options. Possible fields:\n---   - <n_rows> - number of rows in output encoding. If too big, will be\n---     truncated to be maximum needed to encode all input strings (taking into\n---     account symbols row resolution). Default: `math.huge`.\n---   - <n_cols> - width of every encoding string. If too big, will be truncated\n---     to be maximum needed to encode all input strings (taking into account\n---     symbols column resolution). Default: `math.huge`.\n---   - <symbols> - array of symbols with extra `resolution` field. See \"Encode\n---     symbols\" section of |MiniMap.config| for more details. Default: output\n---     of |MiniMap.gen_encode_symbols.block()| with `'3x2'` identifier.\n---\n---@return table Array of encoded strings.\nMiniMap.encode_strings = function(strings, opts)\n  -- Validate input\n  if not H.is_array_of(strings, H.is_string) then\n    H.error('`strings` argument of `encode_strings()` should be array of strings.')\n  end\n\n  opts = vim.tbl_deep_extend(\n    'force',\n    { n_rows = math.huge, n_cols = math.huge, symbols = H.get_config().symbols.encode or H.default_symbols },\n    opts or {}\n  )\n\n  -- Compute encoding\n  local mask = H.mask_from_strings(strings, opts)\n  mask = H.mask_rescale(mask, opts)\n  return H.mask_to_symbols(mask, opts)\nend\n\n--- Open map window\n---\n--- This creates and shows map window in current tabpage. It basically has\n--- two steps:\n--- - If not already done, create map buffer (used to set lines and other\n---   visual indicators) and map window.\n--- - Call |MiniMap.refresh()|.\n---\n---@param opts __map_opts\nMiniMap.open = function(opts)\n  -- Early returns\n  if H.is_disabled() then return end\n\n  -- Normalize input\n  opts = H.normalize_opts(opts)\n\n  -- Allow execution in case of already opened window\n  if H.is_window_open() then\n    MiniMap.refresh(opts)\n    return\n  end\n\n  -- Open buffer and window\n  local buf_id = MiniMap.current.buf_data.map\n  if buf_id == nil or not vim.api.nvim_buf_is_valid(buf_id) then\n    buf_id = H.create_map_buffer()\n    MiniMap.current.buf_data.map = buf_id\n  end\n\n  local win_id = vim.api.nvim_open_win(buf_id, false, H.normalize_window_options(opts.window))\n  H.set_current_map_win(win_id)\n\n  -- Set buffer and window options. Other important options are handled by\n  -- `style = 'minimal'` in `nvim_open_win()`.\n  vim.api.nvim_win_call(win_id, function()\n    --stylua: ignore\n    local options = {\n      'buftype=nofile', 'foldcolumn=0', 'foldlevel=999', 'matchpairs=', 'nobuflisted',\n      'nomodeline',     'noreadonly',   'noswapfile',    'synmaxcol&',  'nowrap',\n    }\n    -- Vim's `setlocal` is currently more robust compared to `opt_local`\n    -- Use `noautocmd` to make it more invisible for others\n    vim.cmd(('silent! noautocmd setlocal %s'):format(table.concat(options, ' ')))\n\n    -- Override Normal highlighting locally for map window\n    vim.cmd('silent! setlocal winhighlight=NormalFloat:MiniMapNormal')\n  end)\n\n  -- Refresh content\n  MiniMap.refresh(opts)\nend\n\n--- Refresh map window\n---\n--- This function serves two purposes:\n--- - Update current map configuration via `opts`.\n--- - Update parts of displayed content via `parts`.\n---\n---@param opts __map_opts\n---@param parts table|nil Which parts to update. Recognised keys with boolean\n---   values (all `true` by default):\n---   - <integrations> - whether to update integration highlights.\n---   - <lines> - whether to update map lines.\n---   - <scrollbar> - whether to update scrollbar.\nMiniMap.refresh = function(opts, parts)\n  -- Early return\n  if H.is_disabled() or not H.is_window_open() then return end\n\n  -- Normalize input\n  opts = H.normalize_opts(opts)\n  parts = vim.tbl_deep_extend('force', { integrations = true, lines = true, scrollbar = true }, parts or {})\n\n  -- Update current data\n  H.cache.scrollbar_data.offset = math.max(H.str_width(opts.symbols.scroll_line), H.str_width(opts.symbols.scroll_view))\n    + (opts.window.show_integration_count and 1 or 0)\n  MiniMap.current.opts = opts\n\n  -- Update window options\n  H.update_window_opts()\n\n  -- Possibly update parts in asynchronous fashion\n  if parts.lines then vim.schedule(H.update_map_lines) end\n  if parts.scrollbar then vim.schedule(H.update_map_scrollbar) end\n  if parts.integrations then vim.schedule(H.update_map_integrations) end\nend\n\n--- Close map window\n---\n--- Also resets `opts` field of |MiniMap.current| after closing last map window\n--- (among possibly several tabpages).\nMiniMap.close = function()\n  pcall(vim.api.nvim_win_close, H.get_current_map_win(), true)\n  H.set_current_map_win(nil)\n\n  -- Reset current options if closed last window so as to use config during\n  -- next opening\n  if vim.tbl_count(MiniMap.current.win_data) == 0 then MiniMap.current.opts = {} end\nend\n\n--- Toggle map window\n---\n--- Open if not shown in current tabpage, close otherwise.\n---\n---@param opts table|nil Input for |MiniMap.open()|.\nMiniMap.toggle = function(opts)\n  if H.is_window_open() then\n    MiniMap.close()\n  else\n    MiniMap.open(opts)\n  end\nend\n\n--- Toggle focus to/from map window\n---\n--- When not inside map window, put cursor inside map window; otherwise put\n--- cursor in previous window with source buffer.\n---\n--- When cursor is moving inside map window (but not just after focusing), view of\n--- source window is updated to show first line convertible to current map line.\n--- This allows quick targeted source buffer exploration.\n---\n--- There are at least these extra methods to focus back from map window:\n--- - Press `<CR>` to accept current explored position in source buffer.\n---   Equivalent to calling this function with `false` argument.\n--- - Press `<Esc>` to go back to original position prior focusing on map window.\n---   Equivalent to calling this function with `true` argument.\n---\n---@param use_previous_cursor boolean|nil Whether to focus on source window at\n---   original cursor position (the one prior focusing on map window).\nMiniMap.toggle_focus = function(use_previous_cursor)\n  if not H.is_window_open() then return end\n  local cur_win, map_win = vim.api.nvim_get_current_win(), H.get_current_map_win()\n\n  if cur_win == map_win then\n    -- Focus on previous window\n    vim.api.nvim_set_current_win(H.cache.previous_win.id)\n\n    -- Use either previous cursor or first non-whitespace character (if this\n    -- was the result of cursor movement inside map window)\n    if use_previous_cursor and H.cache.previous_win.cursor ~= nil then\n      vim.api.nvim_win_set_cursor(0, H.cache.previous_win.cursor)\n    elseif H.cache.n_map_cursor_moves > 1 then\n      vim.cmd('normal! ^')\n    end\n  else\n    -- Focus on map window. Cursor is set on `BufEnter` to account for other\n    -- ways of focusing on buffer (for example, with `<C-w><C-w>`)\n    vim.api.nvim_set_current_win(map_win)\n  end\nend\n\n--- Toggle side of map window\n---\n--- A small convenience wrapper for calling |MiniMap.refresh()| to change the\n--- side of map window.\nMiniMap.toggle_side = function()\n  if not H.is_window_open() then return end\n  local cur_side = MiniMap.current.opts.window.side\n  MiniMap.refresh(\n    { window = { side = cur_side == 'left' and 'right' or 'left' } },\n    { integrations = false, lines = false, scrollbar = false }\n  )\nend\n\n--- Generate encode symbols\n---\n--- This is a table with function elements. Call to actually get encode symbols.\n---\n--- Each element takes a string resolution identifier of a form `'rxc'` (like `'3x2'`)\n--- where `r` is a row resolution of each symbol (how many rows of binary data it\n--- can encode) and `c` is a column resolution (how many columns it can encode).\nMiniMap.gen_encode_symbols = {}\n\n--- Generate block encode symbols\n---\n--- Outputs use solid block to encode binary data. Example: '🬗', '▟', '█'.\n---\n---@param id string Resolution identifier.\n---   Available values: `'1x2'`, `'2x1'`, `'2x2'`, `'3x2'` (default in 'mini.map').\nMiniMap.gen_encode_symbols.block = function(id) return H.block_symbols[id] end\n\n--- Generate dot encode symbols\n---\n--- Outputs use dots to encode binary data. Example: '⡪', '⣼', '⣿'.\n---\n---@param id string Resolution identifier. Available values: `'4x2'`, `'3x2'`.\nMiniMap.gen_encode_symbols.dot = function(id) return H.dot_symbols[id] end\n\n--- Generate shade encode symbols\n---\n--- Outputs use whole cell shades to encode binary data. They use same set of\n--- characters ('░', '▒', '▒', '▓), but with different resolution.\n---\n---@param id string Resolution identifier. Available values: `'1x2'`, `'2x1'`.\nMiniMap.gen_encode_symbols.shade = function(id) return H.shade_symbols[id] end\n\n--- Generate integrations\n---\n--- This is a table with function elements. Call to actually get encode symbols.\n---\n--- Each element takes a table defining highlight groups used for to highlight\n--- map lines.\nMiniMap.gen_integration = {}\n\n--- Builtin search\n---\n--- Highlight lines with matches of current builtin search (like with |/|, |?|, etc.).\n--- Integration count reflects number of actual matches.\n---\n--- It prompts integration highlighting update on every change of |'hlsearch'|\n--- (see |OptionSet|) or |v:hlsearch|. Note that it is not happening for some keys:\n--- - After starting search with |n|, |N|, |star|, or |#|.\n---   To enable highlight update on this keys, make custom mappings. Like this: >lua\n---\n---   for _, key in ipairs({ 'n', 'N', '*', '#' }) do\n---     local rhs = key ..\n---       '<Cmd>lua MiniMap.refresh({}, {lines = false, scrollbar = false})<CR>'\n---     vim.keymap.set('n', key, rhs)\n---   end\n--- <\n---@param hl_groups table|nil Table defining highlight groups. Can have the\n---   following fields:\n---   - <search> - highlight group for search matches. Default: |hl-Search|.\nMiniMap.gen_integration.builtin_search = function(hl_groups)\n  if hl_groups == nil then hl_groups = { search = 'Search' } end\n\n  -- Update when necessary. Not ideal, because it won't react on `n/N/*`, etc.\n  -- See https://github.com/neovim/neovim/issues/18879\n  local gr = vim.api.nvim_create_augroup('MiniMapBuiltinSearch', {})\n  local opts = { group = gr, pattern = 'hlsearch', callback = H.on_integration_update, desc = \"On 'hlsearch' update\" }\n  vim.api.nvim_create_autocmd('OptionSet', opts)\n\n  -- - NOTE: beware of possible https://github.com/neovim/neovim/issues/21469\n  vim.cmd([[\n    silent! call dictwatcherdel(v:, 'hlsearch', 'MiniMapOnHLSearchChanged')\n    function! MiniMapOnHLSearchChanged(d,k,z)\n      lua MiniMap.refresh(nil, { lines = false, scrollbar = false })\n    endfunction\n    call dictwatcheradd(v:, 'hlsearch', 'MiniMapOnHLSearchChanged')\n  ]])\n\n  local search_hl = hl_groups.search\n\n  return function()\n    -- Do nothing of search is not active\n    if vim.v.hlsearch == 0 or not vim.o.hlsearch then return {} end\n\n    -- Do nothing if not inside source buffer (can happen in map buffer, for example)\n    if not H.is_source_buffer() then return {} end\n\n    -- Save window view to later restore, as the only way to get positions of\n    -- search matches seems to be consecutive application of `search()` and\n    -- retrieving cursor position.\n    local win_view = vim.fn.winsaveview()\n\n    vim.api.nvim_win_set_cursor(0, { 1, 0 })\n    local search_count = vim.fn.searchcount({ recompute = true, maxcount = 0 })\n    local search_pattern = vim.fn.getreg('/')\n    local line_hl = {}\n    for _ = 1, (search_count.total or 0) do\n      vim.fn.search(search_pattern)\n      table.insert(line_hl, { line = vim.fn.line('.'), hl_group = search_hl })\n    end\n\n    vim.fn.winrestview(win_view)\n\n    return line_hl\n  end\nend\n\n--- Builtin diagnostic\n---\n--- Highlight lines with matches of current diagnostic items. Items are computed\n--- with |vim.diagnostic.get()| for current (source) buffer.\n---\n--- It prompts integration highlighting update on every |DiagnosticChanged| event.\n--- Diagnostic items with higher severity (see |vim.diagnostic.severity|) have\n--- higher highlight priority (errors will be shown over all others, etc.).\n---\n---@param hl_groups table|nil Table defining highlight groups. Supplied fields\n---   also define which diagnostic severity to highlight.\n---   Can have the following fields:\n---   - <error> - highlight group for error items.\n---     Default: |hl-DiagnosticFloatingError|.\n---   - <warn> - highlight group for warning items. Default: `nil` (not shown).\n---   - <info> - highlight group for info items. Default: `nil` (not shown).\n---   - <hint> - highlight group for hint items. Default: `nil` (not shown).\n---\n---@usage >lua\n---   -- Show all diagnostic levels\n---   local map = require('mini.map')\n---   local diagnostic_integration = map.gen_integration.diagnostic({\n---     error = 'DiagnosticFloatingError',\n---     warn  = 'DiagnosticFloatingWarn',\n---     info  = 'DiagnosticFloatingInfo',\n---     hint  = 'DiagnosticFloatingHint',\n---   })\n---   map.setup({ integrations = { diagnostic_integration } })\n--- <\nMiniMap.gen_integration.diagnostic = function(hl_groups)\n  if hl_groups == nil then hl_groups = { error = 'DiagnosticFloatingError' } end\n\n  -- Precompute ordered array of supported levels. Using keys of\n  -- `severity_highlights` is not enough because higher severity should be\n  -- processed later in order to appear on top.\n  local severity_level_names = vim.tbl_filter(\n    function(x) return vim.tbl_contains(vim.tbl_keys(hl_groups), x) end,\n    { 'error', 'warn', 'info', 'hint' }\n  )\n  local severity_data = vim.tbl_map(\n    function(x) return { severity = vim.diagnostic.severity[x:upper()], hl_group = hl_groups[x] } end,\n    severity_level_names\n  )\n\n  -- Refresh map when needed\n  local augroup = vim.api.nvim_create_augroup('MiniMapDiagnostics', {})\n  vim.api.nvim_create_autocmd(\n    'DiagnosticChanged',\n    { group = augroup, callback = H.on_integration_update, desc = 'On DiagnosticChanged' }\n  )\n\n  return function()\n    local line_hl = {}\n    local diagnostic_arr = vim.diagnostic.get(MiniMap.current.buf_data.source)\n    for _, data in ipairs(severity_data) do\n      local severity_diagnostic_arr = vim.tbl_filter(function(x) return x.severity == data.severity end, diagnostic_arr)\n      for _, diag in ipairs(severity_diagnostic_arr) do\n        -- Add all diagnostic lines to highlight\n        for i = diag.lnum, diag.end_lnum do\n          table.insert(line_hl, { line = i + 1, hl_group = data.hl_group })\n        end\n      end\n    end\n\n    return line_hl\n  end\nend\n\n--- General diff hunks from |mini.diff|\n---\n--- Highlight lines which are part of current diff.\n--- Requires 'mini.diff' as dependency.\n---\n---@param hl_groups table|nil Table defining highlight groups. If `nil` (not\n---   supplied), this status is not highlighted. Can have the following fields:\n---   - <add> - group name for \"add\" hunks. Default: \"MiniDiffSignAdd\".\n---   - <change> - group name for \"change\" hunks. Default: \"MiniDiffSignChange\".\n---   - <delete> - group name for \"delete\" hunks. Default: \"MiniDiffSignDelete\".\nMiniMap.gen_integration.diff = function(hl_groups)\n  if hl_groups == nil then\n    hl_groups = { add = 'MiniDiffSignAdd', change = 'MiniDiffSignChange', delete = 'MiniDiffSignDelete' }\n  end\n\n  local augroup = vim.api.nvim_create_augroup('MiniMapDiff', {})\n  vim.api.nvim_create_autocmd(\n    'User',\n    { group = augroup, pattern = 'MiniDiffUpdated', callback = H.on_integration_update, desc = 'On MiniDiffUpdated' }\n  )\n\n  return function()\n    local has_diff, diff = pcall(require, 'mini.diff')\n    if not has_diff or diff == nil then return {} end\n\n    local has_buf_data, buf_data = pcall(diff.get_buf_data, MiniMap.current.buf_data.source)\n    if not has_buf_data or buf_data == nil then return {} end\n\n    return H.hunks_to_line_hl(buf_data.hunks, hl_groups)\n  end\nend\n\n--- Hunks from 'lewis6991/gitsigns.nvim'\n---\n--- Highlight lines which have non-trivial Git status.\n--- Requires [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim).\n---\n---@param hl_groups table|nil Table defining highlight groups. If `nil` (not\n---   supplied), this status is not highlighted. Can have the following fields:\n---   - <add> - group name for added lines. Default: \"GitSignsAdd\".\n---   - <change> - group name for changed lines. Default: \"GitSignsChange\".\n---   - <delete> - group name for deleted lines. Default: \"GitSignsDelete\".\nMiniMap.gen_integration.gitsigns = function(hl_groups)\n  if hl_groups == nil then hl_groups = { add = 'GitSignsAdd', change = 'GitSignsChange', delete = 'GitSignsDelete' } end\n\n  local augroup = vim.api.nvim_create_augroup('MiniMapGitsigns', {})\n  vim.api.nvim_create_autocmd(\n    'User',\n    { group = augroup, pattern = 'GitSignsUpdate', callback = H.on_integration_update, desc = 'On GitSignsUpdate' }\n  )\n\n  return function()\n    local has_gitsigns, gitsigns = pcall(require, 'gitsigns')\n    if not has_gitsigns or gitsigns == nil then return {} end\n\n    local has_hunks, hunks = pcall(gitsigns.get_hunks, MiniMap.current.buf_data.source)\n    if not has_hunks or hunks == nil then return {} end\n\n    local diff_hunks = {}\n    for _, h in ipairs(hunks) do\n      --stylua: ignore\n      table.insert( diff_hunks, {\n        type = h.type,\n        buf_start = h.added.start,   buf_count = h.added.count,\n        ref_start = h.removed.start, ref_count = h.removed.count,\n      })\n    end\n\n    return H.hunks_to_line_hl(diff_hunks, hl_groups)\n  end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniMap.config)\n\n-- Cache for various operations\nH.cache = {\n  -- Data about previous window. Used for focus related computations.\n  previous_win = {},\n\n  -- Table with information used for latest buffer lines encoding. Used for\n  -- quick conversion between source and map coordinates.\n  encode_data = {},\n\n  -- Table with information about scrollbar. Used for quick scrollbar related\n  -- computations.\n  scrollbar_data = { view = {}, line = nil },\n\n  -- Number of cursor movements inside map buffer since focusing. Needed to not\n  -- update source buffer view just after focusing.\n  n_map_cursor_moves = 0,\n}\n\nH.ns_id = {\n  integrations = vim.api.nvim_create_namespace('MiniMapIntegrations'),\n  scroll_view = vim.api.nvim_create_namespace('MiniMapScrollView'),\n  scroll_line = vim.api.nvim_create_namespace('MiniMapScrollLine'),\n}\n\n--stylua: ignore start\nH.block_symbols = {}\n\nH.block_symbols['1x2'] = { ' ', '▌', '▐', '█', resolution = { row = 1, col = 2 } }\n\nH.block_symbols['2x1'] = { ' ', '▀', '▄', '█', resolution = { row = 2, col = 1 } }\n\nH.block_symbols['2x2'] = {\n  ' ', '▘', '▝', '▀', '▖', '▌', '▞', '▛', '▗', '▚', '▐', '▜', '▄', '▙', '▟', '█',\n  resolution = { row = 2, col = 2 },\n}\n\nH.block_symbols['3x2'] = {\n  ' ', '🬀', '🬁', '🬂', '🬃', '🬄', '🬅', '🬆', '🬇', '🬈', '🬉', '🬊', '🬋', '🬌', '🬍', '🬎',\n  '🬏', '🬐', '🬑', '🬒', '🬓', '▌', '🬔', '🬕', '🬖', '🬗', '🬘', '🬙', '🬚', '🬛', '🬜', '🬝',\n  '🬞', '🬟', '🬠', '🬡', '🬢', '🬣', '🬤', '🬥', '🬦', '🬧', '▐', '🬨', '🬩', '🬪', '🬫', '🬬',\n  '🬭', '🬮', '🬯', '🬰', '🬱', '🬲', '🬳', '🬴', '🬵', '🬶', '🬷', '🬸', '🬹', '🬺', '🬻', '█',\n  resolution = { row = 3, col = 2 },\n}\n\nH.dot_symbols = {}\n\nH.dot_symbols['4x2'] = {\n  '⠀', '⠁', '⠈', '⠉', '⠂', '⠃', '⠊', '⠋', '⠐', '⠑', '⠘', '⠙', '⠒', '⠓', '⠚', '⠛',\n  '⠄', '⠅', '⠌', '⠍', '⠆', '⠇', '⠎', '⠏', '⠔', '⠕', '⠜', '⠝', '⠖', '⠗', '⠞', '⠟',\n  '⠠', '⠡', '⠨', '⠩', '⠢', '⠣', '⠪', '⠫', '⠰', '⠱', '⠸', '⠹', '⠲', '⠳', '⠺', '⠻',\n  '⠤', '⠥', '⠬', '⠭', '⠦', '⠧', '⠮', '⠯', '⠴', '⠵', '⠼', '⠽', '⠶', '⠷', '⠾', '⠿',\n  '⡀', '⡁', '⡈', '⡉', '⡂', '⡃', '⡊', '⡋', '⡐', '⡑', '⡘', '⡙', '⡒', '⡓', '⡚', '⡛',\n  '⡄', '⡅', '⡌', '⡍', '⡆', '⡇', '⡎', '⡏', '⡔', '⡕', '⡜', '⡝', '⡖', '⡗', '⡞', '⡟',\n  '⡠', '⡡', '⡨', '⡩', '⡢', '⡣', '⡪', '⡫', '⡰', '⡱', '⡸', '⡹', '⡲', '⡳', '⡺', '⡻',\n  '⡤', '⡥', '⡬', '⡭', '⡦', '⡧', '⡮', '⡯', '⡴', '⡵', '⡼', '⡽', '⡶', '⡷', '⡾', '⡿',\n  '⢀', '⢁', '⢈', '⢉', '⢂', '⢃', '⢊', '⢋', '⢐', '⢑', '⢘', '⢙', '⢒', '⢓', '⢚', '⢛',\n  '⢄', '⢅', '⢌', '⢍', '⢆', '⢇', '⢎', '⢏', '⢔', '⢕', '⢜', '⢝', '⢖', '⢗', '⢞', '⢟',\n  '⢠', '⢡', '⢨', '⢩', '⢢', '⢣', '⢪', '⢫', '⢰', '⢱', '⢸', '⢹', '⢲', '⢳', '⢺', '⢻',\n  '⢤', '⢥', '⢬', '⢭', '⢦', '⢧', '⢮', '⢯', '⢴', '⢵', '⢼', '⢽', '⢶', '⢷', '⢾', '⢿',\n  '⣀', '⣁', '⣈', '⣉', '⣂', '⣃', '⣊', '⣋', '⣐', '⣑', '⣘', '⣙', '⣒', '⣓', '⣚', '⣛',\n  '⣄', '⣅', '⣌', '⣍', '⣆', '⣇', '⣎', '⣏', '⣔', '⣕', '⣜', '⣝', '⣖', '⣗', '⣞', '⣟',\n  '⣠', '⣡', '⣨', '⣩', '⣢', '⣣', '⣪', '⣫', '⣰', '⣱', '⣸', '⣹', '⣲', '⣳', '⣺', '⣻',\n  '⣤', '⣥', '⣬', '⣭', '⣦', '⣧', '⣮', '⣯', '⣴', '⣵', '⣼', '⣽', '⣶', '⣷', '⣾', '⣿',\n  resolution = { row = 4, col = 2 },\n}\n\nH.dot_symbols['3x2'] = { resolution = { row = 3, col = 2 } }\nfor i = 1,64 do H.dot_symbols['3x2'][i] = H.dot_symbols['4x2'][i] end\n\nH.shade_symbols = {}\n\nH.shade_symbols['2x1'] = { '░', '▒', '▒', '▓', resolution = { row = 2, col = 1 } }\n\nH.shade_symbols['1x2'] = { '░', '▒', '▒', '▓', resolution = { row = 1, col = 2 } }\n\nH.default_symbols = H.block_symbols['3x2']\n--stylua: ignore end\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  local ok_integrations, msg_integrations = H.is_valid_config_integrations(config.integrations, 'integrations')\n  if not ok_integrations then H.error(msg_integrations) end\n\n  local ok_symbols, msg_symbols = H.is_valid_config_symbols(config.symbols, 'symbols')\n  if not ok_symbols then H.error(msg_symbols) end\n\n  local ok_window, msg_window = H.is_valid_config_window(config.window, 'window')\n  if not ok_window then H.error(msg_window) end\n\n  return config\nend\n\nH.apply_config = function(config) MiniMap.config = config end\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniMap', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au({ 'BufEnter', 'BufWritePost', 'TextChanged', 'VimResized' }, '*', H.on_content_change, 'On content change')\n  au({ 'CursorMoved', 'WinScrolled' }, '*', H.on_view_change, 'On view change')\n  au('WinLeave', '*', H.on_winleave, 'On WinLeave')\n  au('WinClosed', '*', H.on_winclosed, 'On WinClosed')\n  au('ModeChanged', '*:n', H.on_content_change, 'On return to Normal mode')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local set_default_hl = function(name, data)\n    data.default = true\n    vim.api.nvim_set_hl(0, name, data)\n  end\n\n  set_default_hl('MiniMapNormal',      { link = 'NormalFloat' })\n  set_default_hl('MiniMapSymbolCount', { link = 'Special' })\n  set_default_hl('MiniMapSymbolLine',  { link = 'Title' })\n  set_default_hl('MiniMapSymbolView',  { link = 'Delimiter' })\nend\n\nH.is_disabled = function() return vim.g.minimap_disable == true or vim.b.minimap_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniMap.config, vim.b.minimap_config or {}, config or {})\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.on_content_change = vim.schedule_wrap(function()\n  -- Using `vim.schedule_wrap()` helps computing more precise buffer data.\n  -- Example: if omitted, terminal buffer is recognized as normal and thus map\n  -- is updated.\n  if not H.is_proper_buftype() then return end\n  MiniMap.refresh()\nend)\n\nH.on_view_change = vim.schedule_wrap(function()\n  if not (H.is_proper_buftype() and H.is_source_buffer()) then return end\n  MiniMap.refresh({}, { integrations = false, lines = false })\nend)\n\nH.on_integration_update = vim.schedule_wrap(function()\n  if not (H.is_proper_buftype() and H.is_source_buffer()) then return end\n  MiniMap.refresh({}, { lines = false, scrollbar = false })\nend)\n\nH.on_winleave = function()\n  if not (H.is_proper_buftype() and H.is_source_buffer()) then return end\n\n  H.cache.previous_win.id = vim.api.nvim_get_current_win()\n  H.cache.previous_win.cursor = vim.api.nvim_win_get_cursor(0)\nend\n\nH.on_winclosed = function(data)\n  -- Ensure that `H.cache.previous_win` always points to a valid normal window\n  local ok, closed_win_id = pcall(tonumber, data.match)\n  if not ok or closed_win_id ~= H.cache.previous_win.id then return end\n\n  for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do\n    if win_id ~= closed_win_id and vim.api.nvim_win_get_config(win_id).relative == '' then\n      H.cache.previous_win = { id = win_id }\n      return\n    end\n  end\nend\n\nH.track_map_cursor = function()\n  -- Operate only inside map window but not just after focusing\n  H.cache.n_map_cursor_moves = H.cache.n_map_cursor_moves + 1\n  local cur_win, map_win = vim.api.nvim_get_current_win(), H.get_current_map_win()\n  if cur_win ~= map_win or H.cache.n_map_cursor_moves <= 1 then return end\n\n  -- Don't allow putting cursor inside offset (where scrollbar is)\n  local cur_pos = vim.api.nvim_win_get_cursor(map_win)\n  if cur_pos[2] < H.cache.scrollbar_data.offset then\n    vim.api.nvim_win_set_cursor(map_win, { cur_pos[1], H.cache.scrollbar_data.offset })\n  end\n\n  -- Synchronize cursors in map and previous window\n  local prev_win_id = H.cache.previous_win.id\n  if prev_win_id == nil then return end\n\n  vim.api.nvim_win_set_cursor(prev_win_id, { H.mapline_to_sourceline(cur_pos[1]), 0 })\n\n  -- Open just enough folds and center cursor\n  vim.api.nvim_win_call(prev_win_id, function() vim.cmd('normal! zvzz') end)\nend\n\nH.on_map_enter = function()\n  -- Check if anything is present (window can be not opened because there is\n  -- one buffer, but many possible windows; so this can be executed on second\n  -- `MiniMap.open()` without opened window)\n  if not H.is_window_open() or H.cache.previous_win.cursor == nil then return end\n\n  -- Put cursor in map window at line indicator to the right of scrollbar\n  local map_line = H.sourceline_to_mapline(H.cache.previous_win.cursor[1])\n  local win_id = H.get_current_map_win()\n\n  vim.api.nvim_win_set_cursor(win_id, { map_line, H.cache.scrollbar_data.offset })\n\n  -- Reset number of cursor moves to later check if should track cursor move\n  H.cache.n_map_cursor_moves = 0\nend\n\n-- Work with mask -------------------------------------------------------------\n---@param strings table Array of strings\n---@return table Non-whitespace mask, boolean 2d array. Each row corresponds to\n---   string, each column - to whether character with that number is a\n---   non-whitespace. Respects multibyte characters.\n---@private\nH.mask_from_strings = function(strings, _)\n  local tab_space = string.rep(' ', vim.o.tabstop)\n\n  local res = {}\n  for i, s in ipairs(strings) do\n    -- Expand tabs into spaces\n    local s_ext = s:gsub('\\t', tab_space)\n    local n_cols = H.str_width(s_ext)\n    local mask_row = H.tbl_repeat(true, n_cols)\n\n    -- Detect whitespace\n    s_ext:gsub('()%s', function(j) mask_row[H.str_utfindex(s_ext, j)] = false end)\n    res[i] = mask_row\n  end\n\n  return res\nend\n\n---@param mask table Boolean 2d array.\n---@return table Boolean 2d array rescaled to be shown by symbols:\n---   `opts.n_rows` lines and `opts.n_cols` within a row.\n---@private\nH.mask_rescale = function(mask, opts)\n  -- Infer output number of rows and columns. Should be multiples of\n  -- `symbols.resolution.row` and `symbols.resolution.col` respectively.\n  local source_rows = #mask\n  local source_cols = 0\n  for _, m_row in ipairs(mask) do\n    source_cols = math.max(source_cols, #m_row)\n  end\n\n  -- Compute effective number of rows and columns in output such that it can\n  -- contain all encoded symbols (taking into account their resolution).\n  -- Don't make it a multiple of resolution at this stage because it can later\n  -- lead to inaccurate representation in some cases. Like with small source\n  -- number of rows it will lead to conversion coefficients greater than 1\n  -- (because `math.ceil()` should be used to round for resolution) and some\n  -- rows in the middle of output will be skipped.\n  local resolution = opts.symbols.resolution\n  local n_rows = math.min(source_rows, opts.n_rows * resolution.row)\n  local n_cols = math.min(source_cols, opts.n_cols * resolution.col)\n\n  -- Rescale. It uses unequal but optimal bins to map source lines/columns to\n  -- boolean encoding (has target dimensions but multiplied by resolution).\n  -- Value within 2d-bin is `true` if at least one value within it is `true`.\n  local res = {}\n  for i = 1, n_rows do\n    res[i] = H.tbl_repeat(false, n_cols)\n  end\n\n  local rows_coeff, cols_coeff = n_rows / source_rows, n_cols / source_cols\n\n  for i, m_row in ipairs(mask) do\n    for j, m in ipairs(m_row) do\n      local res_i = math.floor((i - 1) * rows_coeff) + 1\n      local res_j = math.floor((j - 1) * cols_coeff) + 1\n      res[res_i][res_j] = m or res[res_i][res_j]\n    end\n  end\n\n  return res\nend\n\n--- Convert extended map mask to strings. Each bin with resolution dimensions\n--- is transformed into encode symbol. Single convertible `(resolution.row,\n--- resolution.col)` boolean mask is treated as binary digit: `true` as 1;\n--- `false` as 0; traversing left-right, top-bottom (top-left is lowest bit,\n--- bottom-right - highest).\n---\n---@param mask table Boolean 2d array to be shown as symbols.\n---@return table Array of strings representing input `mask`.\n---@private\nH.mask_to_symbols = function(mask, opts)\n  local symbols = opts.symbols\n  local row_resol, col_resol = symbols.resolution.row, symbols.resolution.col\n\n  local powers_of_two = {}\n  for i = 0, (row_resol * col_resol - 1) do\n    powers_of_two[i] = 2 ^ i\n  end\n\n  -- Assumes rectangular table\n  local symbols_n_rows, symbols_n_cols = math.ceil(#mask / row_resol), math.ceil(#mask[1] / col_resol)\n\n  -- Compute symbols array indexes (start from zero)\n  local symbol_ind = {}\n  for i = 1, symbols_n_rows do\n    symbol_ind[i] = H.tbl_repeat(0, symbols_n_cols)\n  end\n\n  for i = 0, #mask - 1 do\n    local row = mask[i + 1]\n    local row_div, row_mod = math.floor(i / row_resol), i % row_resol\n    for j = 0, #row - 1 do\n      local col_div, col_mod = math.floor(j / col_resol), j % col_resol\n\n      local two_power = row_mod * col_resol + col_mod\n      local to_add = row[j + 1] and powers_of_two[two_power] or 0\n\n      local sym_i, sym_j = row_div + 1, col_div + 1\n      symbol_ind[sym_i][sym_j] = symbol_ind[sym_i][sym_j] + to_add\n    end\n  end\n\n  -- Construct symbols strings\n  local res = {}\n  for i, row in ipairs(symbol_ind) do\n    local syms = vim.tbl_map(function(id) return symbols[id + 1] end, row)\n    res[i] = table.concat(syms)\n  end\n\n  return res\nend\n\n-- Work with config -----------------------------------------------------------\nH.normalize_opts = function(x)\n  x = vim.tbl_deep_extend('force', H.get_config(), MiniMap.current.opts or {}, x or {})\n  H.validate_if(H.is_valid_opts, x, 'opts')\n  return x\nend\n\nH.is_valid_opts = function(x, x_name)\n  x_name = x_name or 'opts'\n\n  local ok_integrations, msg_integrations = H.is_valid_config_integrations(x.integrations, x_name .. '.integrations')\n  if not ok_integrations then return ok_integrations, msg_integrations end\n\n  local ok_symbols, msg_symbols = H.is_valid_config_symbols(x.symbols, x_name .. '.symbols')\n  if not ok_symbols then return ok_symbols, msg_symbols end\n\n  local ok_window, msg_window = H.is_valid_config_window(x.window, x_name .. '.window')\n  if not ok_window then return ok_window, msg_window end\n\n  return true\nend\n\nH.is_valid_config_integrations = function(x, x_name)\n  x_name = x_name or 'config.integrations'\n\n  if x ~= nil then\n    if not H.is_array_of(x, vim.is_callable) then return false, H.msg_config(x_name, 'array of callables') end\n  end\n\n  return true\nend\n\nH.is_valid_config_symbols = function(x, x_name)\n  x_name = x_name or 'config.symbols'\n\n  if type(x) ~= 'table' then return false, H.msg_config(x_name, 'table') end\n\n  -- Encode symbols is `nil` by default\n  if x.encode ~= nil then\n    local ok_encode, msg_encode = H.is_encode_symbols(x.encode, x_name .. '.encode')\n    if not ok_encode then return ok_encode, msg_encode end\n  end\n\n  -- Current line\n  if not H.is_string(x.scroll_line) then return false, H.msg_config(x_name .. '.scroll_line', 'string') end\n\n  -- Current view\n  if not H.is_string(x.scroll_view) then return false, H.msg_config(x_name .. '.scroll_view', 'string') end\n\n  return true\nend\n\nH.is_valid_config_window = function(x, x_name)\n  x_name = x_name or 'config.window'\n\n  if type(x) ~= 'table' then return false, H.msg_config(x_name, 'table') end\n\n  -- Focusable\n  if type(x.focusable) ~= 'boolean' then return false, H.msg_config(x_name .. '.focusable', 'boolean') end\n\n  -- Side\n  if not (x.side == 'left' or x.side == 'right') then\n    return false, H.msg_config(x_name .. '.side', [[one of 'left', 'right']])\n  end\n\n  -- Width\n  if not (type(x.width) == 'number' and x.width > 0) then\n    return false, H.msg_config(x_name .. '.width', 'positive number')\n  end\n\n  -- Show \"more\" integration symbols\n  if type(x.show_integration_count) ~= 'boolean' then\n    return false, H.msg_config(x_name .. '.show_integration_count', 'boolean')\n  end\n\n  -- Window local 'winblend'\n  if not (type(x.winblend) == 'number' and 0 <= x.winblend and x.winblend <= 100) then\n    return false, H.msg_config(x_name .. '.winblend', 'number between 0 and 100')\n  end\n\n  -- Z-index\n  if not (type(x.zindex) == 'number' and x.zindex > 0) then\n    return false, H.msg_config(x_name .. '.zindex', 'positive number')\n  end\n\n  return true\nend\n\nH.msg_config = function(x_name, msg) return string.format('`%s` should be %s.', x_name, msg) end\n\n-- Work with map window -------------------------------------------------------\nH.normalize_window_options = function(win_opts, full)\n  if full == nil then full = true end\n\n  local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)\n  local has_statusline = vim.o.laststatus > 0\n  local anchor, col = 'NE', vim.o.columns\n  if win_opts.side == 'left' then\n    anchor, col = 'NW', 0\n  end\n\n  local res = {\n    relative = 'editor',\n    anchor = anchor,\n    row = has_tabline and 1 or 0,\n    col = col,\n    width = win_opts.width,\n    -- Can be updated at `VimResized` event\n    height = vim.o.lines - vim.o.cmdheight - (has_tabline and 1 or 0) - (has_statusline and 1 or 0),\n    focusable = win_opts.focusable,\n    border = 'none',\n    zindex = win_opts.zindex,\n  }\n  if not full then return res end\n\n  res.style = 'minimal'\n  return res\nend\n\nH.get_current_map_win = function() return MiniMap.current.win_data[vim.api.nvim_get_current_tabpage()] end\n\nH.set_current_map_win = function(win_id) MiniMap.current.win_data[vim.api.nvim_get_current_tabpage()] = win_id end\n\nH.is_window_open = function()\n  local cur_win_id = H.get_current_map_win()\n  return cur_win_id ~= nil and vim.api.nvim_win_is_valid(cur_win_id)\nend\n\n-- Work with map updates ------------------------------------------------------\nH.create_map_buffer = function()\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  H.set_buf_name(buf_id, 'content')\n\n  -- Set buffer local options (which don't involve `noautocmd`)\n  vim.bo[buf_id].filetype = 'minimap'\n\n  -- Make buffer local mappings\n  vim.keymap.set('n', '<CR>', '<Cmd>lua MiniMap.toggle_focus(false)<CR>', { buffer = buf_id })\n  vim.keymap.set('n', '<Esc>', '<Cmd>lua MiniMap.toggle_focus(true)<CR>', { buffer = buf_id })\n\n  -- Make buffer local autocommands\n  vim.api.nvim_create_autocmd('BufEnter', { buffer = buf_id, callback = H.on_map_enter, desc = 'On map enter' })\n  vim.api.nvim_create_autocmd(\n    'CursorMoved',\n    { buffer = buf_id, callback = H.track_map_cursor, desc = 'Track map cursor' }\n  )\n\n  -- Make buffer play nicely with other 'mini.nvim' modules\n  vim.api.nvim_buf_set_var(buf_id, 'minicursorword_disable', true)\n\n  return buf_id\nend\n\nH.update_window_opts = function()\n  local opts = MiniMap.current.opts\n  local win_id = H.get_current_map_win()\n\n  -- Window config\n  vim.api.nvim_win_set_config(win_id, H.normalize_window_options(opts.window, false))\n\n  -- 'winblend'\n  vim.wo[win_id].winblend = opts.window.winblend\nend\n\nH.update_map_lines = function()\n  if not H.is_window_open() then return end\n\n  local buf_id, opts = MiniMap.current.buf_data.map, MiniMap.current.opts\n  local win_id = H.get_current_map_win()\n\n  -- Compute output number of rows and columns to fit currently shown window\n  local offset = H.cache.scrollbar_data.offset\n  local n_cols = vim.api.nvim_win_get_width(win_id) - offset\n  local n_rows = vim.api.nvim_win_get_height(win_id)\n\n  -- Encode lines from current buffer\n  local source_buf_id = vim.api.nvim_get_current_buf()\n  MiniMap.current.buf_data.source = source_buf_id\n  local buf_lines = vim.api.nvim_buf_get_lines(source_buf_id, 0, -1, true)\n  -- Ensure that current buffer has lines (can be not the case when this is\n  -- executed asynchronously during Neovim closing)\n  if #buf_lines == 0 then return end\n\n  local encode_symbols = opts.symbols.encode or H.default_symbols\n  local source_rows, scrollbar_prefix = #buf_lines, string.rep(' ', offset)\n  local encoded_lines, rescaled_rows, resolution_row\n  if n_cols <= 0 then\n    -- Case of \"only scroll indicator\". Needed to make scrollbar correctly\n    -- travel from buffer top to bottom.\n    encoded_lines = H.tbl_repeat(scrollbar_prefix, n_rows)\n\n    -- Note that full encoding was done with single whitespace per line\n    rescaled_rows, resolution_row = n_rows, 1\n  else\n    -- Case of \"full map\"\n    local encode_opts = { n_cols = n_cols, n_rows = n_rows, symbols = encode_symbols }\n    encoded_lines = MiniMap.encode_strings(buf_lines, encode_opts)\n\n    -- Add whitespace for scrollbar\n    encoded_lines = vim.tbl_map(function(x) return string.format('%s%s', scrollbar_prefix, x) end, encoded_lines)\n\n    -- Note that actual encoding was done\n    resolution_row = encode_symbols.resolution.row\n    rescaled_rows = math.min(source_rows, n_rows * resolution_row)\n  end\n\n  -- Set map lines. Compute encode data in a way used in mask rescaling\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, true, encoded_lines)\n\n  -- Cache encode data to speed up most frequent scrollbar computation\n  H.cache.encode_data = {\n    source_rows = source_rows,\n    rescaled_rows = rescaled_rows,\n    resolution_row = resolution_row,\n    map_rows = #encoded_lines,\n  }\n\n  -- Force scrollbar update\n  H.cache.scrollbar_data.view, H.cache.scrollbar_data.line = {}, nil\nend\n\nH.update_map_scrollbar = function()\n  if not H.is_window_open() then return end\n\n  local buf_id = MiniMap.current.buf_data.map\n  local cur_view, cur_line = H.cache.scrollbar_data.view or {}, H.cache.scrollbar_data.line\n  local symbols = MiniMap.current.opts.symbols\n\n  -- View\n  local view = { from_line = vim.fn.line('w0'), to_line = vim.fn.line('w$') }\n  if not (view.from_line == cur_view.from_line and view.to_line == cur_view.to_line) then\n    local ns_id = H.ns_id.scroll_view\n    local extmark_opts =\n      { virt_text = { { symbols.scroll_view, 'MiniMapSymbolView' } }, virt_text_pos = 'overlay', priority = 10 }\n\n    -- Remove previous view\n    vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n\n    -- Add current view\n    local map_from_line = H.sourceline_to_mapline(view.from_line)\n    local map_to_line = H.sourceline_to_mapline(view.to_line)\n\n    for i = map_from_line, map_to_line do\n      H.set_extmark_safely(buf_id, ns_id, i - 1, 0, extmark_opts)\n    end\n\n    H.cache.scrollbar_data.view = view\n  end\n\n  -- Current line\n  local scroll_line = vim.fn.line('.')\n  if scroll_line ~= cur_line then\n    local ns_id = H.ns_id.scroll_line\n    -- Set higher priority than view signs to be visible over them\n    local extmark_opts =\n      { virt_text = { { symbols.scroll_line, 'MiniMapSymbolLine' } }, virt_text_pos = 'overlay', priority = 11 }\n\n    -- Remove previous line\n    vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n\n    -- Add new line\n    local map_line = H.sourceline_to_mapline(scroll_line)\n\n    H.set_extmark_safely(buf_id, ns_id, map_line - 1, 0, extmark_opts)\n    H.cache.scrollbar_data.line = scroll_line\n  end\nend\n\nH.update_map_integrations = function()\n  if not H.is_window_open() then return end\n\n  local buf_id = MiniMap.current.buf_data.map\n  local integrations = MiniMap.current.opts.integrations or {}\n\n  -- Remove previous highlights and signs\n  local ns_id = H.ns_id.integrations\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n\n  -- Do nothing more in case of pure scrollbar\n  -- This is after removing \"more\" signs to allow switching to pure scrollbar\n  -- after such were already visible\n  if H.is_pure_scrollbar() then return end\n\n  -- Add line highlights. Use latest one for every map line.\n  local line_counts = {}\n  for _, integration in ipairs(integrations) do\n    local line_hl = integration()\n    for _, lh in ipairs(line_hl) do\n      local map_line = H.sourceline_to_mapline(lh.line)\n      local cur_count = line_counts[map_line] or 0\n      line_counts[map_line] = cur_count + 1\n\n      -- Actually highlight only first map line occurrence\n      if cur_count == 0 then H.add_line_hl(buf_id, ns_id, lh.hl_group, map_line - 1) end\n    end\n  end\n\n  -- Possibly add integration counts\n  if not MiniMap.current.opts.window.show_integration_count then return end\n\n  local col = H.cache.scrollbar_data.offset - 1\n  for l, count in pairs(line_counts) do\n    if count > 1 then\n      local text = count > 9 and '+' or tostring(count)\n      local extmark_opts = {\n        virt_text = { { text, 'MiniMapSymbolCount' } },\n        virt_text_pos = 'overlay',\n        hl_mode = 'blend',\n      }\n      H.set_extmark_safely(buf_id, ns_id, l - 1, col, extmark_opts)\n    end\n  end\nend\n\nH.sourceline_to_mapline = function(source_line)\n  local data = H.cache.encode_data\n  local coef = data.rescaled_rows / data.source_rows\n  local rescaled_row = math.floor(coef * (source_line - 1)) + 1\n  local res = math.floor((rescaled_row - 1) / data.resolution_row) + 1\n  return math.min(math.max(res, 1), data.map_rows)\nend\n\nH.mapline_to_sourceline = function(map_line)\n  local data = H.cache.encode_data\n  local coef = data.rescaled_rows / data.source_rows\n  local rescaled_row = (map_line - 1) * data.resolution_row + 1\n  local res = math.ceil((rescaled_row - 1) / coef) + 1\n  return math.min(math.max(res, 1), data.source_rows)\nend\n\n-- Hunks ----------------------------------------------------------------------\nH.hunks_to_line_hl = function(hunks, hl_groups)\n  local res = {}\n  for _, h in ipairs(hunks) do\n    local from_line = h.buf_start\n    local n_added, n_removed = h.buf_count, h.ref_count\n    local n_lines = math.max(n_added, 1)\n    -- Highlight similar to hunk summary logic:\n    -- - Delete - single first line if nothing was added.\n    -- - Change - added lines that are within first removed lines.\n    -- - Added - added lines after first removed lines.\n    for i = 1, n_lines do\n      local hl_type = (n_added < i and 'delete') or (i <= n_removed and 'change' or 'add')\n      local hl_group = hl_groups[hl_type]\n      if hl_group ~= nil then table.insert(res, { line = from_line + i - 1, hl_group = hl_group }) end\n    end\n  end\n\n  return res\nend\n\n-- Predicates -----------------------------------------------------------------\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not predicate(v) then return false end\n  end\n  return true\nend\n\nH.is_string = function(x) return type(x) == 'string' end\n\nH.is_encode_symbols = function(x, x_name)\n  x_name = x_name or 'symbols'\n\n  if type(x) ~= 'table' then return false, H.msg_config(x_name, 'table') end\n  if type(x.resolution) ~= 'table' then return false, H.msg_config(x_name .. '.resolution', 'table') end\n  if type(x.resolution.col) ~= 'number' then return false, H.msg_config(x_name .. '.resolution.col', 'number') end\n  if type(x.resolution.row) ~= 'number' then return false, H.msg_config(x_name .. '.resolution.row', 'number') end\n\n  local two_power = x.resolution.col * x.resolution.row\n  for i = 1, 2 ^ two_power do\n    if not H.is_string(x[i]) then return false, H.msg_config(string.format('%s[%d]', x_name, i), 'string') end\n  end\n\n  return true\nend\n\nH.is_proper_buftype = function()\n  local buf_type = vim.bo.buftype\n  return buf_type == '' or buf_type == 'help'\nend\n\nH.is_source_buffer = function() return vim.api.nvim_get_current_buf() == MiniMap.current.buf_data.source end\n\nH.is_pure_scrollbar = function()\n  local win_id = H.get_current_map_win()\n  local offset = H.cache.scrollbar_data.offset\n  return vim.api.nvim_win_get_width(win_id) <= offset\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.map) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minimap://' .. buf_id .. '/' .. name) end\n\nH.validate_if = function(predicate, x, x_name)\n  local is_valid, msg = predicate(x, x_name)\n  if not is_valid then H.error(msg) end\nend\n\nH.add_line_hl = function(buf_id, ns_id, hl_group, line)\n  H.set_extmark_safely(buf_id, ns_id, line, H.cache.scrollbar_data.offset, {\n    hl_group = hl_group,\n    end_row = line + 1,\n    end_col = 0,\n    strict = false,\n  })\nend\n\nH.set_extmark_safely = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.str_width = function(x) return H.str_utfindex(x) end\n\nH.tbl_repeat = function(x, n)\n  local res = {}\n  for _ = 1, n do\n    table.insert(res, x)\n  end\n  return res\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniMap\n"
  },
  {
    "path": "lua/mini/misc.lua",
    "content": "--- *mini.misc* Miscellaneous functions\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features the following functions:\n--- - |MiniMisc.bench_time()| to benchmark function execution time.\n---   Useful in combination with `stat_summary()`.\n---\n--- - |MiniMisc.log_add()|, |MiniMisc.log_show()| and other helper functions to work\n---   with a special in-memory log array. Useful when debugging Lua code.\n---\n--- - |MiniMisc.put()| and |MiniMisc.put_text()| to pretty print its arguments\n---   into command line and current buffer respectively.\n---\n--- - |MiniMisc.resize_window()| to resize current window to its editable width.\n---\n--- - |MiniMisc.safely()| to execute a function on a condition and warn on error.\n---   Useful to organize |init.lua| in fail-safe sections with simple lazy loading.\n---\n--- - |MiniMisc.setup_auto_root()| to set up automated change of current directory.\n---\n--- - |MiniMisc.setup_termbg_sync()| to set up terminal background synchronization\n---   (removes possible \"frame\" around current Neovim instance).\n---\n--- - |MiniMisc.setup_restore_cursor()| to set up automated restoration of\n---   cursor position on file reopen.\n---\n--- - |MiniMisc.stat_summary()| to compute summary statistics of numerical array.\n---   Useful in combination with `bench_time()`.\n---\n--- - |MiniMisc.tbl_head()| and |MiniMisc.tbl_tail()| to return \"first\" and \"last\"\n---   elements of table.\n---\n--- - |MiniMisc.zoom()| to zoom in and out of a buffer, making it full screen\n---   in a floating window.\n---\n--- - And more.\n---\n--- # Setup ~\n---\n--- This module doesn't need setup, but it can be done to improve usability.\n--- Setup with `require('mini.misc').setup({})` (replace `{}` with your\n--- `config` table). It will create global Lua table `MiniMisc` which you can\n--- use for scripting or manually (with `:lua MiniMisc.*`).\n---\n--- See |MiniMisc.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minimisc_config`\n--- will have no effect here.\n---@tag MiniMisc\n\n-- Module definition ==========================================================\nlocal MiniMisc = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniMisc.config|.\n---\n---@usage >lua\n---   require('mini.misc').setup() -- use default config\n---   -- OR\n---   require('mini.misc').setup({}) -- replace {} with your config table\n--- <\nMiniMisc.setup = function(config)\n  -- Export module\n  _G.MiniMisc = MiniMisc\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniMisc.config = {\n  -- Array of fields to make global (to be used as independent variables)\n  make_global = { 'put', 'put_text' },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Execute `f` several times and time how long it took\n---\n---@param f function Function which execution to benchmark.\n---@param n number|nil Number of times to execute `f(...)`. Default: 1.\n---@param ... any Arguments when calling `f`.\n---\n---@return ... Table with durations (in seconds; up to nanoseconds) and\n---   output of (last) function execution.\nMiniMisc.bench_time = function(f, n, ...)\n  n = n or 1\n  local durations, output = {}, nil\n  for _ = 1, n do\n    local start_time = vim.loop.hrtime()\n    output = f(...)\n    local end_time = vim.loop.hrtime()\n    table.insert(durations, 0.000000001 * (end_time - start_time))\n  end\n\n  return durations, output\nend\n\n--- Compute width of gutter (info column on the left of the window)\n---\n---@param win_id number|nil Window identifier (see |win_getid()|) for which gutter\n---   width is computed. Default: 0 for current.\nMiniMisc.get_gutter_width = function(win_id)\n  win_id = (win_id == nil or win_id == 0) and vim.api.nvim_get_current_win() or win_id\n  return vim.fn.getwininfo(win_id)[1].textoff\nend\n\n--- Add an entry to the in-memory log array\n---\n--- Useful when trying to debug a Lua code (like Neovim config or plugin).\n--- Use this instead of ad-hoc `print()` statements.\n---\n--- Each entry is a table with the following fields:\n--- - <desc> `(any)` - entry description. Usually a string describing a place\n---   in the code.\n--- - <state> `(any)` - data about current state. Usually a table.\n--- - <timestamp> `(number)` - a timestamp of when the entry was added. A number of\n---   milliseconds since the in-memory log was initiated (after |MiniMisc.setup()|\n---   or |MiniMisc.log_clear()|). Useful during profiling.\n---\n---@param desc any Entry description.\n---@param state any Data about current state.\n---@param opts table|nil Options. Possible fields:\n---   - <deepcopy> - (boolean) Whether to apply |vim.deepcopy| to the {state}.\n---     Usually helpful to record the exact state during code execution and avoid\n---     side effects of tables being changed in-place. Default `true`.\n---\n---@usage >lua\n---   local t = { a = 1 }\n---   MiniMisc.log_add('before', { t = t }) -- Will show `t = { a = 1 }` state\n---   t.a = t.a + 1\n---   MiniMisc.log_add('after', { t = t })  -- Will show `t = { a = 2 }` state\n---\n---   -- Use `:lua MiniMisc.log_show()` or `:=MiniMisc.log_get()` to see the log\n--- <\n---@seealso - |MiniMisc.log_get()| to get log array\n--- - |MiniMisc.log_show()| to show log array in the dedicated buffer\n--- - |MiniMisc.log_clear()| to clear the log array\nMiniMisc.log_add = function(desc, state, opts)\n  opts = vim.tbl_extend('force', { deepcopy = true }, opts or {})\n  local entry = {\n    desc = desc,\n    state = opts.deepcopy and vim.deepcopy(state) or state,\n    timestamp = 0.000001 * (vim.loop.hrtime() - H.log_cache.start_htime),\n  }\n  table.insert(H.log_cache.log, entry)\nend\n\n--- Get log array\n---\n---@return table[] Log array. Returned as is, without |vim.deepcopy()|.\n---\n---@seealso - |MiniMisc.log_add()| to add to the log array\nMiniMisc.log_get = function() return H.log_cache.log end\n\n--- Show log array in a scratch buffer\n---\n---@seealso - |MiniMisc.log_add()| to add to the log array\nMiniMisc.log_show = function()\n  local buf_id = H.log_cache.buf_id\n  if buf_id == nil or not vim.api.nvim_buf_is_valid(buf_id) then\n    buf_id = vim.api.nvim_create_buf(true, true)\n    vim.api.nvim_buf_set_name(buf_id, 'minimisc://' .. buf_id .. '/log')\n    H.log_cache.buf_id = buf_id\n  end\n  local lines = vim.split(vim.inspect(H.log_cache.log), '\\n')\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n\n  local buf_wins = vim.fn.win_findbuf(buf_id)\n  if buf_wins[1] == nil then return vim.api.nvim_win_set_buf(0, buf_id) end\n  vim.api.nvim_set_current_win(buf_wins[1])\nend\n\n--- Clear log array\n---\n--- This also sets a new starting point for entry timestamps.\n---\n---@seealso - |MiniMisc.log_add()| to add to the log array\nMiniMisc.log_clear = function()\n  H.log_cache.log = {}\n  H.log_cache.start_htime = vim.loop.hrtime()\n  H.notify('Cleared log')\nend\n\nH.log_cache = { log = {}, start_htime = vim.loop.hrtime(), buf_id = nil }\n\n--- Print Lua objects in command line\n---\n---@param ... any Any number of objects to be printed each on separate line.\nMiniMisc.put = function(...)\n  local objects = {}\n  -- Not using `{...}` because it removes `nil` input\n  for i = 1, select('#', ...) do\n    local v = select(i, ...)\n    table.insert(objects, vim.inspect(v))\n  end\n\n  print(table.concat(objects, '\\n'))\n\n  return ...\nend\n\n--- Print Lua objects in current buffer\n---\n---@param ... any Any number of objects to be printed each on separate line.\nMiniMisc.put_text = function(...)\n  local objects = {}\n  -- Not using `{...}` because it removes `nil` input\n  for i = 1, select('#', ...) do\n    local v = select(i, ...)\n    table.insert(objects, vim.inspect(v))\n  end\n\n  local lines = vim.split(table.concat(objects, '\\n'), '\\n')\n  local lnum = vim.api.nvim_win_get_cursor(0)[1]\n  vim.fn.append(lnum, lines)\n\n  return ...\nend\n\n--- Resize window to have exact number of editable columns\n---\n---@param win_id number|nil Window identifier (see |win_getid()|) to be resized.\n---   Default: 0 for current.\n---@param text_width number|nil Number of editable columns resized window will\n---   display. Default: first element of 'colorcolumn' or otherwise 'textwidth'\n---   (using screen width as its default but not more than 79).\nMiniMisc.resize_window = function(win_id, text_width)\n  win_id = win_id or 0\n  text_width = text_width or H.default_text_width(win_id)\n\n  vim.api.nvim_win_set_width(win_id, text_width + MiniMisc.get_gutter_width(win_id))\nend\n\nH.default_text_width = function(win_id)\n  local buf = vim.api.nvim_win_get_buf(win_id)\n  local textwidth = vim.bo[buf].textwidth\n  textwidth = (textwidth == 0) and math.min(vim.o.columns, 79) or textwidth\n\n  local colorcolumn = vim.wo[win_id].colorcolumn\n  if colorcolumn ~= '' then\n    local cc = vim.split(colorcolumn, ',')[1]\n    local is_cc_relative = vim.tbl_contains({ '-', '+' }, cc:sub(1, 1))\n\n    if is_cc_relative then\n      return textwidth + tonumber(cc)\n    else\n      return tonumber(cc)\n    end\n  else\n    return textwidth\n  end\nend\n\n--- Execute a function on a condition and warn on error\n---\n--- Input function is executed exactly once. Its possible error is captured and is\n--- shown as a |vim.notify()| warning.\n---\n--- Useful to organize |init.lua| in fail-safe sections with simple lazy loading.\n---\n---@param when string When to execute a function. One of:\n---   - `'now'` - immediately.\n---   - `'later'` - queue to be executed soon without blocking the execution of next\n---     code in file. Queued functions are executed in order they are added.\n---   - `'delay:<number>'` - after a specified delay with |vim.defer_fn()|.\n---   - `'event:<events>'` - on whichever specified event is triggered first.\n---   - `'event:<events>~<patterns>` - same as above, but events must match\n---     specified |autocmd-pattern|.\n---   - `'filetype:<filetypes>'` - same as `'event:FileType~<filetypes>'`, but follow\n---     successful function execution with |filetype-detect| for all normal buffers\n---     (if new |ftdetect| scripts were added) and sourcing |ftplugin| (for buffers\n---     matching `<filetypes>`). Intended to be used for loading \"language plugins\".\n---@param f function Function to execute (without arguments).\n---\n---@usage >lua\n---   MiniMisc.safely('later', function()\n---     vim.notify('This will be executed after the next \"now\" call')\n---   end)\n---   MiniMisc.safely('now', function() error('This will be a warning') end)\n---\n---   MiniMisc.safely('event:InsertEnter', function()\n---     require('mini.completion').setup()\n---   end)\n---   MiniMisc.safely('event:CmdlineEnter~/', function()\n---     vim.notify('Start searching for the first time')\n---   end)\n---\n---   MiniMisc.safely('filetype:tex,plaintex', function()\n---     -- Load plugin to improve writing LaTeX\n---   end)\n--- <\nMiniMisc.safely = function(when, f)\n  H.check_type('when', when, 'string', false)\n  H.check_type('f', f, 'callable', false)\n\n  if when == 'now' then\n    H.execute_now(f)\n    return\n  end\n\n  -- Compute traceback before delaying execution to provide more info\n  local trace = debug.traceback('', 2)\n\n  if when == 'later' then\n    if #H.safely_cache.later == 0 then vim.schedule(H.execute_later) end\n    table.insert(H.safely_cache.later, { f = f, trace = trace })\n    return\n  end\n\n  local delay = tonumber(when:match('^delay:(%d+)$'))\n  if delay ~= nil then\n    vim.defer_fn(function() H.execute_now(f, trace) end, delay)\n    return\n  end\n\n  local events = when:match('^event:(.+)$')\n  if events then\n    local ev, patt = events:match('^(.+)~(.+)$')\n    local event = vim.split(ev or events, ',', { trimempty = true })\n    local pattern = vim.split(patt or '', ',', { trimempty = true })\n    H.make_defer_autocmd(event, pattern, f, trace)\n    return\n  end\n\n  local filetypes = when:match('^filetype:(.+)$')\n  if filetypes then\n    local ft_arr = vim.split(filetypes, ',')\n    -- NOTE: Needs `vim.schedule_wrap()` for a correct redetect. This also\n    -- prompts using `H.execute_now` and not rely on `H.make_defer_autocmd`.\n    local f_and_redetect = vim.schedule_wrap(function()\n      -- Look out for new 'ftdetect' scripts by comparing before and after\n      local ftdetect_scripts_before = vim.api.nvim_get_runtime_file('ftdetect/*.{vim,lua}', true)\n\n      local ok = H.execute_now(f, trace)\n\n      -- Skip redetect if there was error or detection is disabled\n      if not (ok and vim.g.did_load_filetypes == 1) then return end\n\n      local ftdetect_scripts_after = vim.api.nvim_get_runtime_file('ftdetect/*.{vim,lua}', true)\n      local needs_redetect = not vim.deep_equal(ftdetect_scripts_before, ftdetect_scripts_after)\n      for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n        H.redetect_filetypes(buf_id, ft_arr, needs_redetect)\n      end\n    end)\n    return H.make_defer_autocmd('FileType', ft_arr, f_and_redetect)\n  end\n\n  H.error('Could not parse `when` in `safely`')\nend\n\nH.execute_now = function(f, init_trace)\n  local ok, err = xpcall(f, function(e) return debug.traceback(e .. '\\n', 2) end)\n  if ok then return true end\n  init_trace = init_trace == nil and '' or ('\\n\\nTraceback of `MiniMisc.safely()` call:\\n' .. init_trace)\n  H.notify('Error during safe execution: ' .. err .. init_trace, 'WARN')\n  return false\nend\n\nH.safely_cache = { later = {} }\n\nH.execute_later = function()\n  local timer = assert(vim.loop.new_timer())\n  local f\n  f = vim.schedule_wrap(function()\n    local cb = H.safely_cache.later[1]\n    if cb == nil then\n      if not timer:is_closing() then timer:close() end\n      return\n    end\n\n    table.remove(H.safely_cache.later, 1)\n    H.execute_now(cb.f, cb.trace)\n    timer:start(1, 0, f)\n  end)\n  -- Space out \"later\" executions to be sure that they don't block anything\n  timer:start(1, 0, f)\nend\n\nH.make_defer_autocmd = function(event, pattern, f, trace)\n  local au_id\n  local function cb()\n    -- Execute exactly once, not once per event or pattern match\n    -- Delete before executing `f` to account for nested events\n    vim.api.nvim_del_autocmd(au_id)\n    H.execute_now(f, trace)\n  end\n\n  local group = vim.api.nvim_create_augroup('MiniMiscSafely', { clear = false })\n  local opts = { group = group, pattern = pattern, callback = cb, nested = true }\n  au_id = vim.api.nvim_create_autocmd(event, opts)\nend\n\nH.redetect_filetypes = function(buf_id, ft_arr, needs_redetect)\n  if not vim.api.nvim_buf_is_loaded(buf_id) then return end\n\n  vim.api.nvim_buf_call(buf_id, function()\n    -- Try detecting new filetypes\n    if needs_redetect and vim.bo.buftype == '' then vim.cmd('filetype detect') end\n\n    -- Force execution of 'ftplugin' scripts for matched filetypes\n    if vim.tbl_contains(ft_arr, vim.bo.filetype) then vim.bo.filetype = vim.bo.filetype end\n  end)\nend\n\n--- Set up automated change of current directory\n---\n--- What it does:\n--- - Creates autocommand which on every |BufEnter| event with |MiniMisc.find_root()|\n---   finds root directory for current buffer file and sets |current-directory|\n---   to it (using |chdir()|).\n--- - Resets |'autochdir'| to `false`.\n---\n---@param names table|function|nil Forwarded to |MiniMisc.find_root()|.\n---@param fallback function|nil Forwarded to |MiniMisc.find_root()|.\n---\n---@usage >lua\n---   require('mini.misc').setup()\n---   MiniMisc.setup_auto_root()\n--- <\nMiniMisc.setup_auto_root = function(names, fallback)\n  names = names or { '.git', 'Makefile' }\n  if not (H.is_array_of(names, H.is_string) or vim.is_callable(names)) then\n    H.error('Argument `names` of `setup_auto_root()` should be array of string file names or a callable.')\n  end\n\n  fallback = fallback or function() return nil end\n  if not vim.is_callable(fallback) then H.error('Argument `fallback` of `setup_auto_root()` should be callable.') end\n\n  -- Disable conflicting option\n  vim.o.autochdir = false\n\n  -- Create autocommand\n  local set_root = vim.schedule_wrap(function(data)\n    if data.buf ~= vim.api.nvim_get_current_buf() then return end\n    local root = MiniMisc.find_root(data.buf, names, fallback)\n    if root == nil then return end\n    vim.fn.chdir(root)\n  end)\n  local augroup = vim.api.nvim_create_augroup('MiniMiscAutoRoot', {})\n  local opts = { group = augroup, nested = true, callback = set_root, desc = 'Find root and change current directory' }\n  vim.api.nvim_create_autocmd('BufEnter', opts)\nend\n\n--- Find root directory\n---\n--- Based on a buffer name (full path to file opened in a buffer) find a root\n--- directory. If buffer is not associated with file, returns `nil`.\n---\n--- Root directory is a directory containing at least one of pre-defined files.\n--- It is searched using |vim.fs.find()| with `upward = true` starting from\n--- directory of current buffer file until first occurrence of root file(s).\n---\n--- Notes:\n--- - Uses directory path caching to speed up computations. This means that no\n---   changes in root directory will be detected after directory path was already\n---   used in this function. Reload Neovim to account for that.\n---\n---@param buf_id number|nil Buffer identifier (see |bufnr()|) to use.\n---   Default: 0 for current.\n---@param names table|function|nil Array of file names or a callable used to\n---   identify a root directory. Forwarded to |vim.fs.find()|.\n---   Default: `{ '.git', 'Makefile' }`.\n---@param fallback function|nil Callable fallback to use if no root is found\n---   with |vim.fs.find()|. Will be called with a buffer path and should return\n---   a valid directory path.\nMiniMisc.find_root = function(buf_id, names, fallback)\n  buf_id = buf_id or 0\n  names = names or { '.git', 'Makefile' }\n  fallback = fallback or function() return nil end\n\n  if not H.is_valid_buf(buf_id) then H.error('Argument `buf_id` of `find_root()` should be valid buffer id.') end\n  if not (H.is_array_of(names, H.is_string) or vim.is_callable(names)) then\n    H.error('Argument `names` of `find_root()` should be array of string file names or a callable.')\n  end\n  if not vim.is_callable(fallback) then H.error('Argument `fallback` of `find_root()` should be callable.') end\n\n  -- Compute directory to start search from. NOTEs on why not using file path:\n  -- - This has better performance because `vim.fs.find()` is called less.\n  -- - *Needs* to be a directory for callable `names` to work.\n  -- - Later search is done including initial `path` if directory, so this\n  --   should work for detecting buffer directory as root.\n  local path = vim.api.nvim_buf_get_name(buf_id)\n  if path == '' then return end\n  local dir_path = vim.fs.dirname(path)\n\n  -- Try using cache\n  local res = H.root_cache[dir_path]\n  if res ~= nil then return res end\n\n  -- Find root\n  local root_file = vim.fs.find(names, { path = dir_path, upward = true })[1]\n  if root_file ~= nil then\n    res = vim.fs.dirname(root_file)\n  else\n    res = fallback(path)\n  end\n\n  -- Use absolute path to an existing directory\n  if type(res) ~= 'string' then return end\n  res = vim.fs.normalize(vim.fn.fnamemodify(res, ':p'))\n  if vim.fn.isdirectory(res) == 0 then return end\n\n  -- Cache result per directory path\n  H.root_cache[dir_path] = res\n\n  return res\nend\n\nH.root_cache = {}\n\n--- Set up terminal background synchronization\n---\n--- What it does:\n--- - Checks if terminal emulator supports OSC 11 control sequence through\n---   appropriate `stdout`. Stops if not.\n--- - Creates autocommands for |ColorScheme| and |VimResume| events, which\n---   change terminal background to have same color as |guibg| of |hl-Normal|.\n--- - Creates autocommands for |VimLeavePre| and |VimSuspend| events which set\n---   terminal background back to its original color.\n--- - Synchronizes background immediately to allow not depend on loading order.\n---\n--- Primary use case is to remove possible \"frame\" around current Neovim instance\n--- which appears if Neovim's |hl-Normal| background color differs from what is\n--- used by terminal emulator itself.\n---\n--- Works only on Neovim>=0.10.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <explicit_reset> `(boolean)` - whether to reset terminal background by\n---     explicitly setting it to the color it had when this function was called.\n---     Set to `true` if terminal emulator doesn't support OSC 111 control sequence.\n---     Default: `false`.\nMiniMisc.setup_termbg_sync = function(opts)\n  -- Handling `'\\027]11;?\\007'` response was added in Neovim 0.10\n  if vim.fn.has('nvim-0.10') == 0 then return H.notify('`setup_termbg_sync()` requires Neovim>=0.10', 'WARN') end\n\n  -- Proceed only if there is a valid stdout to use\n  local has_stdout_tty = false\n  for _, ui in ipairs(vim.api.nvim_list_uis()) do\n    has_stdout_tty = has_stdout_tty or ui.stdout_tty\n  end\n  if not has_stdout_tty then return end\n\n  opts = vim.tbl_extend('force', { explicit_reset = false }, opts or {})\n\n  -- Choose a method for how terminal emulator background is reset\n  local reset = function() io.stdout:write('\\027]111\\027\\\\') end\n  if opts.explicit_reset then reset = function() io.stdout:write('\\027]11;' .. H.termbg_init .. '\\007') end end\n\n  local augroup = vim.api.nvim_create_augroup('MiniMiscTermbgSync', { clear = true })\n  local track_au_id, bad_responses, had_proper_response = nil, {}, false\n  local f = function(args)\n    -- Process proper response only once\n    if had_proper_response then return end\n\n    -- Neovim=0.10 uses string sequence as response, while Neovim>=0.11 sets it\n    -- in `sequence` table field\n    local seq = type(args.data) == 'table' and args.data.sequence or args.data\n    local ok, termbg = pcall(H.parse_osc11, seq)\n    if not (ok and type(termbg) == 'string') then return table.insert(bad_responses, seq) end\n    had_proper_response = true\n    pcall(vim.api.nvim_del_autocmd, track_au_id)\n\n    -- Set up reset to the color returned from the very first call\n    H.termbg_init = H.termbg_init or termbg\n    vim.api.nvim_create_autocmd({ 'VimLeavePre', 'VimSuspend' }, { group = augroup, callback = reset })\n\n    -- Set up sync\n    local sync = function()\n      local normal = vim.api.nvim_get_hl_by_name('Normal', true)\n      if normal.background == nil then return reset() end\n      -- NOTE: use `io.stdout` instead of `io.write` to ensure correct target\n      -- Otherwise after `io.output(file); file:close()` there is an error\n      io.stdout:write(string.format('\\027]11;#%06x\\007', normal.background))\n    end\n    vim.api.nvim_create_autocmd({ 'VimResume', 'ColorScheme' }, { group = augroup, callback = sync })\n\n    -- Sync immediately\n    sync()\n  end\n\n  -- Ask about current background color and process the proper response.\n  -- NOTE: do not use `once = true` as Neovim itself triggers `TermResponse`\n  -- events during startup, so this should wait until the proper one.\n  track_au_id = vim.api.nvim_create_autocmd('TermResponse', { group = augroup, callback = f, nested = true })\n  io.stdout:write('\\027]11;?\\007')\n  vim.defer_fn(function()\n    if had_proper_response then return end\n    pcall(vim.api.nvim_del_augroup_by_id, augroup)\n    local bad_suffix = #bad_responses == 0 and '' or (', only these: ' .. vim.inspect(bad_responses))\n    local msg = '`setup_termbg_sync()` did not get proper response from terminal emulator' .. bad_suffix\n    H.notify(msg, 'WARN')\n  end, 1000)\nend\n\n-- Source: 'runtime/lua/vim/_defaults.lua' in Neovim source\nH.parse_osc11 = function(x)\n  local r, g, b = x:match('^\\027%]11;rgb:(%x+)/(%x+)/(%x+)$')\n  if not (r and g and b) then\n    local a\n    r, g, b, a = x:match('^\\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')\n    if not (a and a:len() <= 4) then return end\n  end\n  if not (r and g and b) then return end\n  if not (r:len() <= 4 and g:len() <= 4 and b:len() <= 4) then return end\n  local parse_osc_hex = function(c) return c:len() == 1 and (c .. c) or c:sub(1, 2) end\n  return '#' .. parse_osc_hex(r) .. parse_osc_hex(g) .. parse_osc_hex(b)\nend\n\n--- Restore cursor position on file open\n---\n--- When reopening a file this will make sure the cursor is placed back to the\n--- position where you left before. This implements |restore-cursor| in a nicer way.\n--- File should have a recognized file type (see 'filetype') and be opened in\n--- a normal buffer (see 'buftype').\n---\n--- Note: it relies on file mark data stored in 'shadafile' (see |shada-f|).\n--- Be sure to enable it.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <center> - (boolean) Center the window after we restored the cursor.\n---     Default: `true`.\n---   - <ignore_filetype> - Array with file types to be ignored (see 'filetype').\n---     Default: `{ \"gitcommit\", \"gitrebase\" }`.\n---\n---@usage >lua\n---   require('mini.misc').setup_restore_cursor()\n--- <\nMiniMisc.setup_restore_cursor = function(opts)\n  opts = opts or {}\n\n  opts.ignore_filetype = opts.ignore_filetype or { 'gitcommit', 'gitrebase' }\n  if not H.is_array_of(opts.ignore_filetype, H.is_string) then\n    H.error('In `setup_restore_cursor()` `opts.ignore_filetype` should be an array of strings.')\n  end\n\n  if opts.center == nil then opts.center = true end\n  if type(opts.center) ~= 'boolean' then H.error('In `setup_restore_cursor()` `opts.center` should be a boolean.') end\n\n  -- Create autocommand which runs once on `FileType` for every new buffer\n  local augroup = vim.api.nvim_create_augroup('MiniMiscRestoreCursor', {})\n  vim.api.nvim_create_autocmd('BufReadPre', {\n    group = augroup,\n    callback = function(data)\n      vim.api.nvim_create_autocmd('FileType', {\n        buffer = data.buf,\n        once = true,\n        callback = function() H.restore_cursor(opts) end,\n      })\n    end,\n  })\nend\n\nH.restore_cursor = function(opts)\n  -- Stop if not a normal buffer\n  if vim.bo.buftype ~= '' then return end\n\n  -- Stop if filetype is ignored\n  if vim.tbl_contains(opts.ignore_filetype, vim.bo.filetype) then return end\n\n  -- Stop if line is already specified (like during start with `nvim file +num`)\n  local cursor_line = vim.api.nvim_win_get_cursor(0)[1]\n  if cursor_line > 1 then return end\n\n  -- Stop if can't restore proper line for some reason\n  local mark_line = vim.api.nvim_buf_get_mark(0, [[\"]])[1]\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  if not (1 <= mark_line and mark_line <= n_lines) then return end\n\n  -- Restore cursor and open just enough folds\n  vim.cmd([[normal! g`\"zv]])\n\n  -- Center window\n  if opts.center then vim.cmd('normal! zz') end\nend\n\n--- Compute summary statistics of numerical array\n---\n--- This might be useful to compute summary of time benchmarking with\n--- |MiniMisc.bench_time()|.\n---\n---@param t table Array (table suitable for `ipairs`) of numbers.\n---\n---@return table Table with summary values under following keys (may be\n---   extended in the future): <maximum>, <mean>, <median>, <minimum>, <n>\n---   (number of elements), <sd> (sample standard deviation).\nMiniMisc.stat_summary = function(t)\n  if not H.is_array_of(t, H.is_number) then\n    H.error('Input of `MiniMisc.stat_summary()` should be an array of numbers.')\n  end\n\n  -- Welford algorithm of computing variance\n  -- Source: https://www.johndcook.com/blog/skewness_kurtosis/\n  local n = #t\n  local delta, m1, m2 = 0, 0, 0\n  local minimum, maximum = math.huge, -math.huge\n  for i, x in ipairs(t) do\n    delta = x - m1\n    m1 = m1 + delta / i\n    m2 = m2 + delta * (x - m1)\n\n    -- Extremums\n    minimum = x < minimum and x or minimum\n    maximum = x > maximum and x or maximum\n  end\n\n  return {\n    maximum = maximum,\n    mean = m1,\n    median = H.compute_median(t),\n    minimum = minimum,\n    n = n,\n    sd = math.sqrt(n > 1 and m2 / (n - 1) or 0),\n  }\nend\n\nH.compute_median = function(t)\n  local n = #t\n  if n == 0 then return 0 end\n\n  local t_sorted = vim.deepcopy(t)\n  table.sort(t_sorted)\n  return 0.5 * (t_sorted[math.ceil(0.5 * n)] + t_sorted[math.ceil(0.5 * (n + 1))])\nend\n\n--- Return \"first\" elements of table as decided by `pairs`\n---\n--- Note: order of elements might vary.\n---\n---@param t table Input table.\n---@param n number|nil Maximum number of first elements. Default: 5.\n---\n---@return table Table with at most `n` first elements of `t` (with same keys).\nMiniMisc.tbl_head = function(t, n)\n  n = n or 5\n  local res, n_res = {}, 0\n  for k, val in pairs(t) do\n    if n_res >= n then return res end\n    res[k] = val\n    n_res = n_res + 1\n  end\n  return res\nend\n\n--- Return \"last\" elements of table as decided by `pairs`\n---\n--- This function makes two passes through elements of `t`:\n--- - First to count number of elements.\n--- - Second to construct result.\n---\n--- Note: order of elements might vary.\n---\n---@param t table Input table.\n---@param n number|nil Maximum number of last elements. Default: 5.\n---\n---@return table Table with at most `n` last elements of `t` (with same keys).\nMiniMisc.tbl_tail = function(t, n)\n  n = n or 5\n\n  -- Count number of elements on first pass\n  local n_all = 0\n  for _, _ in pairs(t) do\n    n_all = n_all + 1\n  end\n\n  -- Construct result on second pass\n  local res = {}\n  local i, start_i = 0, n_all - n + 1\n  for k, val in pairs(t) do\n    i = i + 1\n    if i >= start_i then res[k] = val end\n  end\n  return res\nend\n\n--- Add possibility of nested comment leader\n---\n--- This works by parsing 'commentstring' buffer option, extracting\n--- non-whitespace comment leader (symbols on the left of commented line), and\n--- locally modifying 'comments' option (by prepending `n:<leader>`). Does\n--- nothing if 'commentstring' is empty or has comment symbols both in front\n--- and back (like \"/*%s*/\").\n---\n--- Nested comment leader added with this function is useful for formatting\n--- nested comments. For example, have in Lua \"first-level\" comments with '--'\n--- and \"second-level\" comments with '----'. With nested comment leader second\n--- type can be formatted with `gq` in the same way as first one.\n---\n--- Recommended usage is with |autocmd|: >lua\n---\n---   local use_nested_comments = function() MiniMisc.use_nested_comments() end\n---   vim.api.nvim_create_autocmd('BufEnter', { callback = use_nested_comments })\n--- <\n--- Note: for most filetypes 'commentstring' option is added only when buffer\n--- with this filetype is entered, so using non-current `buf_id` can not lead\n--- to desired effect.\n---\n---@param buf_id number|nil Buffer identifier (see |bufnr()|) in which function\n---   will operate. Default: 0 for current.\nMiniMisc.use_nested_comments = function(buf_id)\n  buf_id = buf_id or 0\n\n  local commentstring = vim.bo[buf_id].commentstring\n  if commentstring == '' then return end\n\n  -- Extract raw comment leader from 'commentstring' option\n  local comment_parts = vim.tbl_filter(function(x) return x ~= '' end, vim.split(commentstring, '%s', true))\n\n  -- Don't do anything if 'commentstring' is like '/*%s*/' (as in 'json')\n  if #comment_parts > 1 then return end\n\n  -- Get comment leader by removing whitespace\n  local leader = vim.trim(comment_parts[1])\n\n  local comments = vim.bo[buf_id].comments\n  vim.bo[buf_id].comments = string.format('n:%s,%s', leader, comments)\nend\n\n--- Zoom in and out of a buffer, making it full screen in a floating window\n---\n--- This function is useful when working with multiple windows but temporarily\n--- needing to zoom into one to see more of the code from that buffer. Call it\n--- again (without arguments) to zoom out.\n---\n---@param buf_id number|nil Buffer identifier (see |bufnr()|) to be zoomed.\n---   Default: 0 for current.\n---@param config table|nil Optional config for window (as for |nvim_open_win()|).\n---\n---@return boolean Whether current buffer is zoomed in.\nMiniMisc.zoom = function(buf_id, config)\n  -- Hide\n  if H.zoom_winid and vim.api.nvim_win_is_valid(H.zoom_winid) then\n    pcall(vim.api.nvim_del_augroup_by_name, 'MiniMiscZoom')\n    vim.api.nvim_win_close(H.zoom_winid, true)\n    H.zoom_winid = nil\n    return false\n  end\n\n  -- Show\n  local compute_config = function()\n    -- Use precise dimensions for no Command line interactions (better scroll)\n    local max_width, max_height = vim.o.columns, vim.o.lines - vim.o.cmdheight\n    local default_border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'none' or nil\n    --stylua: ignore\n    local default_config = {\n      relative = 'editor', row = 0, col = 0,\n      width = max_width, height = max_height,\n      title = ' Zoom ', border = default_border,\n    }\n    local res = vim.tbl_deep_extend('force', default_config, config or {})\n\n    -- Adjust dimensions to fit actually present border parts\n    local bor = res.border == 'none' and { '' } or res.border\n    local n = type(bor) == 'table' and #bor or 0\n    local height_offset = n == 0 and 2 or ((bor[1 % n + 1] == '' and 0 or 1) + (bor[5 % n + 1] == '' and 0 or 1))\n    local width_offset = n == 0 and 2 or ((bor[3 % n + 1] == '' and 0 or 1) + (bor[7 % n + 1] == '' and 0 or 1))\n    res.height = math.min(res.height, max_height - height_offset)\n    res.width = math.min(res.width, max_width - width_offset)\n\n    -- Ensure proper title\n    if type(res.title) == 'string' then res.title = H.fit_to_width(res.title, res.width) end\n\n    return res\n  end\n  H.zoom_winid = vim.api.nvim_open_win(buf_id or 0, true, compute_config())\n  vim.wo[H.zoom_winid].winblend = 0\n  vim.cmd('normal! zz')\n\n  -- - Make sure zoom window is adjusting to changes in its hyperparameters\n  local gr = vim.api.nvim_create_augroup('MiniMiscZoom', { clear = true })\n  local adjust_config = function()\n    if not (type(H.zoom_winid) == 'number' and vim.api.nvim_win_is_valid(H.zoom_winid)) then\n      pcall(vim.api.nvim_del_augroup_by_name, 'MiniMiscZoom')\n      return\n    end\n    vim.api.nvim_win_set_config(H.zoom_winid, compute_config())\n  end\n  vim.api.nvim_create_autocmd('VimResized', { group = gr, callback = adjust_config })\n  vim.api.nvim_create_autocmd('OptionSet', { group = gr, pattern = 'cmdheight', callback = adjust_config })\n  return true\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniMisc.config)\n\n-- Window identifier of current zoom (for `zoom()`)\nH.zoom_winid = nil\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  -- NOTE: Don't use `tbl_deep_extend` to prefer full input `make_global` array\n  -- Needs adjusting if there is a new setting with nested tables\n  config = vim.tbl_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('make_global', config.make_global, 'table')\n  for _, v in pairs(config.make_global) do\n    if MiniMisc[v] == nil then H.error(\"`make_global` should be a table with exported 'mini.misc' methods\") end\n  end\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniMisc.config = config\n\n  for _, v in pairs(config.make_global) do\n    _G[v] = MiniMisc[v]\n  end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.misc) ' .. msg) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.notify = function(msg, level) vim.notify('(mini.misc) ' .. msg, vim.log.levels[level]) end\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not predicate(v) then return false end\n  end\n  return true\nend\n\nH.is_number = function(x) return type(x) == 'number' end\n\nH.is_string = function(x) return type(x) == 'string' end\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniMisc\n"
  },
  {
    "path": "lua/mini/move.lua",
    "content": "--- *mini.move* Move any selection in any direction\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Works in two modes:\n---     - Visual mode. Select text (charwise with |v|, linewise with |V|, and\n---       blockwise with |CTRL-V|) and press customizable mapping to move in\n---       all four directions (left, right, down, up). It keeps Visual mode.\n---     - Normal mode. Press customizable mapping to move current line in all\n---       four directions (left, right, down, up).\n---     - Special handling of linewise movement:\n---         - Vertical movement gets reindented with |=|.\n---         - Horizontal movement is improved indent/dedent with |>| / |<|.\n---         - Cursor moves along with selection.\n---\n--- - Provides both mappings and Lua functions for motions. See\n---   |MiniMove.move_selection()| and |MiniMove.move_line()|.\n---\n--- - Respects |v:count|. Movement mappings can be preceded by a number which\n---   multiplies command effect.\n---\n--- - All consecutive moves (regardless of direction) can be undone by a single |u|.\n---\n--- - Respects preferred column for vertical movement. It will vertically move\n---   selection as how cursor is moving (not strictly vertically if target\n---   column is not present in target line).\n---\n--- Notes:\n--- - Doesn't allow moving selection outside of current lines (by design).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.move').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniMove`\n--- which you can use for scripting or manually (with `:lua MiniMove.*`).\n---\n--- See |MiniMove.config| for available config settings.\n---\n--- You can override runtime config settings (but not `config.mappings`) locally\n--- to buffer inside `vim.b.minimove_config` which should have same structure\n--- as `MiniMove.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [matze/vim-move](https://github.com/matze/vim-move):\n---     - Doesn't support vertical movement of charwise and blockwise selections.\n---       While 'mini.move' does.\n---     - Doesn't support horizontal movement of current line in favor of\n---       horizontal movement of current character. While 'mini.move' supports\n---       horizontal movement of current line and doesn't support such movement\n---       of current character.\n---     - Has extra functionality for certain moves (like move by half page).\n---       While 'mini.move' does not (by design).\n--- - [booperlv/nvim-gomove](https://github.com/booperlv/nvim-gomove):\n---     - Doesn't support movement in charwise visual selection.\n---       While 'mini.move' does.\n---     - Has extra functionality beyond moving text, like duplication.\n---       While 'mini.move' concentrates only on moving functionality.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minimove_disable` (globally) or `vim.b.minimove_disable`\n--- (for a buffer) to `true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniMove\n\n---@alias __move_direction string One of \"left\", \"down\", \"up\", \"right\".\n---@alias __move_opts table|nil Options. Same structure as `options` in |MiniMove.config|\n---   (with its values as defaults) plus these allowed extra fields:\n---   - <n_times> (number) - number of times to try to make a move.\n---     Default: |v:count1|.\n\n---@diagnostic disable:undefined-field\n\n-- Module definition ==========================================================\nlocal MiniMove = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniMove.config|.\n---\n---@usage >lua\n---   require('mini.move').setup() -- use default config\n---   -- OR\n---   require('mini.move').setup({}) -- replace {} with your config table\n--- <\nMiniMove.setup = function(config)\n  -- Export module\n  _G.MiniMove = MiniMove\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Mappings ~\n---\n--- Other possible choices of mappings: >lua\n---\n---   -- `HJKL` for moving visual selection (overrides H, L, J in Visual mode)\n---   require('mini.move').setup({\n---     mappings = {\n---       left  = 'H',\n---       right = 'L',\n---       down  = 'J',\n---       up    = 'K',\n---     }\n---   })\n---\n---   -- Shift + arrows\n---   require('mini.move').setup({\n---     mappings = {\n---       left  = '<S-left>',\n---       right = '<S-right>',\n---       down  = '<S-down>',\n---       up    = '<S-up>',\n---\n---       line_left  = '<S-left>',\n---       line_right = '<S-right>',\n---       line_down  = '<S-down>',\n---       line_up    = '<S-up>',\n---     }\n---   })\n--- <\nMiniMove.config = {\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Move visual selection in Visual mode. Defaults are Alt (Meta) + hjkl.\n    left = '<M-h>',\n    right = '<M-l>',\n    down = '<M-j>',\n    up = '<M-k>',\n\n    -- Move current line in Normal mode\n    line_left = '<M-h>',\n    line_right = '<M-l>',\n    line_down = '<M-j>',\n    line_up = '<M-k>',\n  },\n\n  -- Options which control moving behavior\n  options = {\n    -- Automatically reindent selection during linewise vertical move\n    reindent_linewise = true,\n  },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Move visually selected region in any direction within present lines\n---\n--- Main function powering visual selection move in Visual mode.\n---\n--- Notes:\n--- - Vertical movement in linewise mode is followed up by reindent with |v_=|.\n--- - Horizontal movement in linewise mode is same as |v_<| and |v_>|.\n---\n---@param direction __move_direction\n---@param opts __move_opts\nMiniMove.move_selection = function(direction, opts)\n  if H.is_disabled() or not vim.o.modifiable then return end\n\n  opts = vim.tbl_deep_extend('force', H.get_config().options, opts or {})\n\n  -- This could have been a one-line expression mappings, but there are issues:\n  -- - Initial yanking modifies some register. Not critical, but also not good.\n  -- - Doesn't work at movement edges (first line for `K`, etc.). See\n  --   https://github.com/vim/vim/issues/11786\n  -- - Results into each movement being a separate undo block, which is\n  --   inconvenient with several back-to-back movements.\n  local cur_mode = vim.fn.mode()\n\n  -- Act only inside visual mode\n  if not (cur_mode == 'v' or cur_mode == 'V' or cur_mode == '\\22') then return end\n\n  -- Define common predicates\n  local dir_type = (direction == 'up' or direction == 'down') and 'vert' or 'hori'\n  local is_linewise = cur_mode == 'V'\n\n  -- Make early return in small buffer\n  if vim.api.nvim_buf_line_count(0) == 1 then\n    if is_linewise and dir_type == 'vert' then return end\n    if not is_linewise and vim.fn.getline(1):len() == 0 then return end\n  end\n\n  -- Cache useful data because it will be reset when executing commands\n  local n_times = opts.n_times or vim.v.count1\n  local ref_curpos, ref_last_col = vim.fn.getcurpos(), vim.fn.col('$')\n  local is_cursor_on_selection_start = vim.fn.line('.') < vim.fn.line('v')\n\n  -- Determine if previous action was this type of move\n  local is_moving = vim.deep_equal(H.state, H.get_move_state())\n  if not is_moving then H.curswant = nil end\n\n  -- Allow undo of consecutive moves at once (direction doesn't matter)\n  local cmd = H.make_cmd_normal(is_moving)\n\n  -- Treat horizontal linewise movement specially\n  if is_linewise and dir_type == 'hori' then\n    -- Use indentation as horizontal movement for linewise selection\n    cmd(n_times .. H.indent_keys[direction] .. 'gv')\n\n    -- Make cursor move along selection\n    H.correct_cursor_col(ref_curpos, ref_last_col)\n\n    -- Track new state to allow joining in single undo block\n    H.state = H.get_move_state()\n\n    return\n  end\n\n  -- Temporarily ensure possibility to put cursor just after line end.\n  -- This allows a more intuitive cursor positioning from and to end of line.\n  -- NOTE: somehow, this should be done before initial cut to take effect.\n  local cache_virtualedit = vim.o.virtualedit\n  if not cache_virtualedit:find('all') then vim.o.virtualedit = 'onemore' end\n\n  -- Cut selection while saving caching register\n  local cache_z_reg = vim.fn.getreginfo('z')\n  -- - Don't use `\"zx` directly to not affect registers 1-9\n  cmd('\"zygv\"_x')\n\n  -- Detect edge selection: last line(s) for vertical and last character(s)\n  -- for horizontal. At this point (after cutting selection) cursor is on the\n  -- edge which can happen in two cases:\n  --   - Move second to last selection towards edge (like in 'abc' move 'b'\n  --     to right or second to last line down).\n  --   - Move edge selection away from edge (like in 'abc' move 'c' to left\n  --     or last line up).\n  -- Use condition that removed selection was further than current cursor\n  -- to distinguish between two cases.\n  local is_edge_selection_hori = dir_type == 'hori' and vim.fn.col('.') < vim.fn.col(\"'<\")\n  local is_edge_selection_vert = dir_type == 'vert' and vim.fn.line('.') < vim.fn.line(\"'<\")\n  local is_edge_selection = is_edge_selection_hori or is_edge_selection_vert\n\n  -- Use `p` as paste key instead of `P` in cases which might require moving\n  -- selection to place which is unreachable with `P`: right to be line end\n  -- and down to be last line. NOTE: temporary `virtualedit=onemore` solves\n  -- this only for horizontal movement, but not for vertical.\n  local can_go_overline = not is_linewise and direction == 'right'\n  local can_go_overbuf = is_linewise and direction == 'down'\n  local paste_key = (can_go_overline or can_go_overbuf) and 'p' or 'P'\n\n  -- Restore `curswant` to try move cursor to initial column (just like\n  -- default `hjkl` moves)\n  if dir_type == 'vert' then H.set_curswant(H.curswant) end\n\n  -- Possibly reduce number of moves by one to not overshoot move\n  local n = n_times - ((paste_key == 'p' or is_edge_selection) and 1 or 0)\n\n  -- Don't allow movement past last line of block selection (any part)\n  if cur_mode == '\\22' and direction == 'down' and vim.fn.line('$') == vim.fn.line(\"'>\") then n = 0 end\n\n  -- Move cursor\n  if n > 0 then cmd(n .. H.move_keys[direction]) end\n\n  -- Save curswant. Correct for one less move when using `p` as paste.\n  H.curswant = H.get_curswant() + ((direction == 'right' and paste_key == 'p') and 1 or 0)\n\n  -- Open just enough folds (but not in linewise mode, as it allows moving\n  -- past folds)\n  if not is_linewise then cmd('zv') end\n\n  -- Paste\n  cmd('\"z' .. paste_key)\n\n  -- Select newly moved region. Another way is to use something like `gvhoho`\n  -- but it doesn't work well with selections spanning several lines.\n  cmd('`[1v')\n\n  -- Do extra in case of linewise selection\n  if is_linewise then\n    -- Reindent linewise selection if `=` can do that.\n    -- NOTE: this sometimes doesn't work well with folds (and probably\n    -- `foldmethod=indent`) and linewise mode because it recomputes folds after\n    -- that and the whole \"move past fold\" doesn't work.\n    if opts.reindent_linewise and dir_type == 'vert' and vim.o.equalprg == '' then cmd('=gv') end\n\n    -- Move cursor along the selection. NOTE: do this *after* reindent to\n    -- account for its effect.\n    -- - Ensure that cursor is on the right side of selection\n    if is_cursor_on_selection_start then cmd('o') end\n    H.correct_cursor_col(ref_curpos, ref_last_col)\n  end\n\n  -- Restore intermediate values\n  vim.fn.setreg('z', cache_z_reg)\n  vim.o.virtualedit = cache_virtualedit\n\n  -- Track new state to allow joining in single undo block\n  H.state = H.get_move_state()\nend\n\n--- Move current line in any direction\n---\n--- Main function powering current line move in Normal mode.\n---\n--- Notes:\n--- - Vertical movement is followed up by reindent with |v_=|.\n--- - Horizontal movement is almost the same as |<<| and |>>| with a different\n---   handling of |v:count| (multiplies shift effect instead of modifying that\n---   number of lines).\n---\n---@param direction __move_direction\n---@param opts __move_opts\nMiniMove.move_line = function(direction, opts)\n  if H.is_disabled() or not vim.o.modifiable then return end\n  if vim.api.nvim_buf_line_count(0) == 1 and (direction == 'down' or direction == 'up') then return end\n\n  opts = vim.tbl_deep_extend('force', H.get_config().options, opts or {})\n\n  -- Determine if previous action was this type of move\n  local is_moving = vim.deep_equal(H.state, H.get_move_state())\n\n  -- Allow undo of consecutive moves at once (direction doesn't matter)\n  local cmd = H.make_cmd_normal(is_moving)\n\n  -- Cache useful data because it will be reset when executing commands\n  local n_times = opts.n_times or vim.v.count1\n  local is_last_line_up = direction == 'up' and vim.fn.line('.') == vim.fn.line('$')\n  local ref_curpos, ref_last_col = vim.fn.getcurpos(), vim.fn.col('$')\n\n  if direction == 'left' or direction == 'right' then\n    -- Use indentation as horizontal movement. Explicitly call `count1` because\n    -- `<`/`>` use `v:count` to define number of lines.\n    -- Go to first non-blank at the end.\n    local key = H.indent_keys[direction]\n    cmd(string.rep(key .. key, n_times))\n\n    -- Make cursor move along selection\n    H.correct_cursor_col(ref_curpos, ref_last_col)\n\n    -- Track new state to allow joining in single undo block\n    H.state = H.get_move_state()\n\n    return\n  end\n\n  -- Cut current line while saving caching register\n  local cache_z_reg = vim.fn.getreginfo('z')\n  -- - Don't use `\"zdd` directly to not affect registers 1-9\n  cmd('\"zyy\"_dd')\n\n  -- Move cursor\n  local paste_key = direction == 'up' and 'P' or 'p'\n  local n = n_times - ((paste_key == 'p' or is_last_line_up) and 1 or 0)\n  if n > 0 then cmd(n .. H.move_keys[direction]) end\n\n  -- Paste\n  cmd('\"z' .. paste_key)\n\n  -- Reindent and put cursor on first non-blank\n  if opts.reindent_linewise and vim.o.equalprg == '' then cmd('==') end\n\n  -- Move cursor along the selection. NOTE: do this *after* reindent to\n  -- account for its effect.\n  H.correct_cursor_col(ref_curpos, ref_last_col)\n\n  -- Restore intermediate values\n  vim.fn.setreg('z', cache_z_reg)\n\n  -- Track new state to allow joining in single undo block\n  H.state = H.get_move_state()\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniMove.config)\n\nH.move_keys = { left = 'h', down = 'j', up = 'k', right = 'l' }\nH.indent_keys = { left = '<', right = '>' }\n\n-- Moving state used to decide when to start new undo block ...\nH.state = {\n  -- ... on buffer change\n  buf_id = nil,\n  -- ... on text change\n  changedtick = nil,\n  -- ... on cursor move\n  cursor = nil,\n  -- ... on mode change\n  mode = nil,\n}\n\nH.curswant = nil\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.left', config.mappings.left, 'string')\n  H.check_type('mappings.down', config.mappings.down, 'string')\n  H.check_type('mappings.up', config.mappings.up, 'string')\n  H.check_type('mappings.right', config.mappings.right, 'string')\n  H.check_type('mappings.line_left', config.mappings.line_left, 'string')\n  H.check_type('mappings.line_right', config.mappings.line_right, 'string')\n  H.check_type('mappings.line_down', config.mappings.line_down, 'string')\n  H.check_type('mappings.line_up', config.mappings.line_up, 'string')\n\n  H.check_type('options', config.options, 'table')\n  H.check_type('options.reindent_linewise', config.options.reindent_linewise, 'boolean')\n\n  return config\nend\n\n--stylua: ignore\nH.apply_config = function(config)\n  MiniMove.config = config\n\n  -- Make mappings\n  local maps = config.mappings\n\n  H.map('x', maps.left,  [[<Cmd>lua MiniMove.move_selection('left')<CR>]],  { desc = 'Move left' })\n  H.map('x', maps.right, [[<Cmd>lua MiniMove.move_selection('right')<CR>]], { desc = 'Move right' })\n  H.map('x', maps.down,  [[<Cmd>lua MiniMove.move_selection('down')<CR>]],  { desc = 'Move down' })\n  H.map('x', maps.up,    [[<Cmd>lua MiniMove.move_selection('up')<CR>]],    { desc = 'Move up' })\n\n  H.map('n', maps.line_left,  [[<Cmd>lua MiniMove.move_line('left')<CR>]],  { desc = 'Move line left' })\n  H.map('n', maps.line_right, [[<Cmd>lua MiniMove.move_line('right')<CR>]], { desc = 'Move line right' })\n  H.map('n', maps.line_down,  [[<Cmd>lua MiniMove.move_line('down')<CR>]],  { desc = 'Move line down' })\n  H.map('n', maps.line_up,    [[<Cmd>lua MiniMove.move_line('up')<CR>]],    { desc = 'Move line up' })\nend\n\nH.is_disabled = function() return vim.g.minimove_disable == true or vim.b.minimove_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniMove.config, vim.b.minimove_config or {}, config or {})\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.move) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.make_cmd_normal = function(include_undojoin)\n  local normal_command = (include_undojoin and 'undojoin | ' or '') .. 'silent keepjumps normal! '\n\n  return function(x)\n    -- Caching and restoring data on every command is not necessary but leads\n    -- to a nicer implementation\n\n    -- Disable 'mini.bracketed' to avoid unwanted entries to its yank history\n    local cache_minibracketed_disable = vim.b.minibracketed_disable\n    local cache_unnamed_register = { points_to = vim.fn.getreginfo('\"').points_to }\n\n    -- Don't track possible put commands into yank history\n    vim.b.minibracketed_disable = true\n\n    vim.cmd(normal_command .. x)\n\n    vim.b.minibracketed_disable = cache_minibracketed_disable\n    vim.fn.setreg('\"', cache_unnamed_register)\n  end\nend\n\nH.get_move_state = function()\n  return {\n    buf_id = vim.api.nvim_get_current_buf(),\n    changedtick = vim.b.changedtick,\n    cursor = vim.api.nvim_win_get_cursor(0),\n    mode = vim.fn.mode(),\n  }\nend\n\nH.correct_cursor_col = function(ref_curpos, ref_last_col)\n  -- Use `ref_curpos = getcurpos()` instead of `vim.api.nvim_win_get_cursor(0)`\n  -- allows to also account for `virtualedit=all`\n\n  local col_diff = vim.fn.col('$') - ref_last_col\n  local new_col = math.max(ref_curpos[3] + col_diff, 1)\n  vim.fn.cursor({ vim.fn.line('.'), new_col, ref_curpos[4], ref_curpos[5] + col_diff })\nend\n\nH.get_curswant = function() return vim.fn.winsaveview().curswant end\nH.set_curswant = function(x)\n  if x == nil then return end\n  vim.fn.winrestview({ curswant = x })\nend\n\nreturn MiniMove\n"
  },
  {
    "path": "lua/mini/notify.lua",
    "content": "--- *mini.notify* Show notifications\n---\n--- MIT License Copyright (c) 2024 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Show one or more highlighted notifications in a single floating window.\n---\n--- - Manage notifications (add, update, remove, clear).\n---\n--- - Custom |vim.notify()| implementation. To adjust, use |MiniNotify.make_notify()|\n---   or save-restore `vim.notify` manually after calling |MiniNotify.setup()|.\n---\n--- - Automated show of LSP progress report.\n---\n--- - Track history which can be accessed with |MiniNotify.get_all()|\n---   and shown with |MiniNotify.show_history()|.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.notify').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniNotify`\n--- which you can use for scripting or manually (with `:lua MiniNotify.*`).\n---\n--- See |MiniNotify.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.mininotify_config` which should have same structure as\n--- `MiniNotify.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [j-hui/fidget.nvim](https://github.com/j-hui/fidget.nvim):\n---     - Basic goals of providing interface for notifications are similar.\n---     - Has more configuration options and visual effects, while this module\n---       does not (by design).\n---\n--- - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify):\n---     - Similar to 'j-hui/fidget.nvim'.\n---\n--- # Highlight groups ~\n---\n--- - `MiniNotifyBorder` - window border.\n--- - `MiniNotifyLspProgress` - notifications from built-in LSP progress report.\n--- - `MiniNotifyNormal` - basic foreground/background highlighting.\n--- - `MiniNotifyTitle` - window title.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- NOTE: |vim.notify()| override after |MiniNotify.make_notify()| uses own\n--- highlight groups per notification level.\n---\n--- # Disabling ~\n---\n--- To disable showing notifications, set `vim.g.mininotify_disable` (globally) or\n--- `vim.b.mininotify_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniNotify\n\n--- # Notification specification ~\n---\n--- Notification is a table with the following keys:\n---\n--- - <msg> `(string)` - single string with notification message.\n---   Use `\\n` to delimit several lines.\n--- - <level> `(string)` - notification level as key of |vim.log.levels|.\n---   Like \"ERROR\", \"WARN\", \"INFO\", etc.\n--- - <hl_group> `(string)` - highlight group with which notification is shown.\n--- - <data> `(table)` - extra data to store in notification (like `source`, etc.).\n--- - <ts_add> `(number)` - timestamp of when notification is added.\n--- - <ts_update> `(number)` - timestamp of the latest notification update.\n--- - <ts_remove> `(number|nil)` - timestamp of when notification is removed.\n---   It is `nil` if notification was never removed and thus considered \"active\".\n---\n--- Notes:\n--- - Timestamps are compatible with |strftime()| and have fractional part.\n---@tag MiniNotify-specification\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n-- Module definition ==========================================================\nlocal MiniNotify = {}\nlocal H = {}\n\n--- Module setup\n---\n--- This will also:\n--- - Set |vim.notify()| custom implementation (see |MiniNotify.make_notify()|).\n--- - Clean the history. Use `MiniNotify.setup(MiniNotify.config)` to force\n---   clean history while preserving the config.\n---\n---@param config table|nil Module config table. See |MiniNotify.config|.\n---\n---@usage >lua\n---   require('mini.notify').setup() -- use default config\n---   -- OR\n---   require('mini.notify').setup({}) -- replace {} with your config table\n--- <\nMiniNotify.setup = function(config)\n  -- Export module\n  _G.MiniNotify = MiniNotify\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\n\n  -- Set custom implementation\n  vim.notify = MiniNotify.make_notify()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Content ~\n---\n--- `config.content` defines how notifications are shown.\n---\n--- `content.format` is a function which takes single notification object\n--- (see |MiniNotify-specification|) and returns a string to be used directly\n--- when showing notification.\n--- Default: `nil` for |MiniNotify.default_format()|.\n---\n--- `content.sort` is a function which takes array of notification objects\n--- (see |MiniNotify-specification|) and returns an array of such objects.\n--- It can be used to define custom order and/or filter for notifications which\n--- are shown simultaneously.\n--- Note: Input contains notifications before applying `content.format`.\n--- Default: `nil` for |MiniNotify.default_sort()|.\n---\n--- Example: >lua\n---\n---   require('mini.notify').setup({\n---     content = {\n---       -- Use notification message as is for LSP progress\n---       format = function(notif)\n---         if notif.data.source == 'lsp_progress' then return notif.msg end\n---         return MiniNotify.default_format(notif)\n---       end,\n---\n---       -- Show more recent notifications first\n---       sort = function(notif_arr)\n---         table.sort(\n---           notif_arr,\n---           function(a, b) return a.ts_update > b.ts_update end\n---         )\n---         return notif_arr\n---       end,\n---     },\n---   })\n--- <\n--- # LSP progress ~\n---\n--- `config.lsp_progress` defines automated notifications for LSP progress.\n--- It is implemented as a single updating notification per progress with all\n--- information about it.\n--- Setting up is done inside |MiniNotify.setup()| via |vim.schedule()|'ed setting\n--- of |lsp-handler| for \"$/progress\" method.\n---\n--- `lsp_progress.enable` is a boolean indicating whether LSP progress should\n--- be shown in notifications. Can be disabled in current session.\n--- Default: `true`. Note: Should be `true` during |MiniNotify.setup()| call to be able\n--- to enable it in current session.\n---\n--- `lsp_progress.level` is a level to be used in |MiniNotify.add()|.\n--- Default: `'INFO'`.\n---\n--- `lsp_progress.duration_last` is a number of milliseconds for the last progress\n--- report to be shown on screen before removing it.\n--- Default: 1000.\n---\n--- Notes:\n--- - This respects previously set handler by saving and calling it.\n--- - Overriding \"$/progress\" method of `vim.lsp.handlers` disables notifications.\n--- - All LSP progress notifications set the following fields in `data`:\n---     - <source> is `\"lsp_progress\"`.\n---     - <client_name> is set to client's name (provided by client or inferred).\n---     - <context> is the latest LSP request context (`ctx` arg of |lsp-handler|).\n---     - <response> is the latest LSP response (`result` arg of |lsp-handler|).\n---\n--- # Window ~\n---\n--- `config.window` defines behavior of notification window.\n---\n--- `window.config` is a table defining floating window characteristics\n--- or a callable returning such table (will be called with identifier of\n--- window's buffer already showing notifications). It should have the same\n--- structure as in |nvim_open_win()|. It has the following default values\n--- which show notifications in the upper right corner with upper limit on width:\n--- - `width` is chosen to fit buffer content but at most `window.max_width_share`\n---   share of 'columns'.\n---   To have higher maximum width, use function in `config.window` which computes\n---   dimensions inside of it (based on buffer content).\n--- - `height` is chosen to fit buffer content with enabled 'wrap' (assuming\n---   default value of `width`).\n--- - `anchor`, `col`, and `row` are \"NE\", 'columns', and 0 or 1 (depending on tabline).\n--- - `border` is \"single\".\n--- - `zindex` is 999 to be as much on top as reasonably possible.\n---\n--- `window.max_width_share` defines maximum window width as a share of 'columns'.\n--- Should be a number between 0 (not included) and 1.\n--- Default: 0.382.\n---\n--- Example for showing notifications in bottom right corner: >lua\n---\n---   local win_config = function()\n---     local has_statusline = vim.o.laststatus > 0\n---     local pad = vim.o.cmdheight + (has_statusline and 1 or 0)\n---     return { anchor = 'SE', col = vim.o.columns, row = vim.o.lines - pad }\n---   end\n---   require('mini.notify').setup({ window = { config = win_config } })\n--- <\n--- `window.winblend` defines 'winblend' value for notification window.\n--- Default: 25.\nMiniNotify.config = {\n  -- Content management\n  content = {\n    -- Function which formats the notification message\n    -- By default prepends message with notification time\n    format = nil,\n\n    -- Function which orders notification array from most to least important\n    -- By default orders first by level and then by update timestamp\n    sort = nil,\n  },\n\n  -- Notifications about LSP progress\n  lsp_progress = {\n    -- Whether to enable showing\n    enable = true,\n\n    -- Notification level\n    level = 'INFO',\n\n    -- Duration (in ms) of how long last message should be shown\n    duration_last = 1000,\n  },\n\n  -- Window options\n  window = {\n    -- Floating window config\n    config = {},\n\n    -- Maximum window width as share (between 0 and 1) of available columns\n    max_width_share = 0.382,\n\n    -- Value of 'winblend' option\n    winblend = 25,\n  },\n}\n--minidoc_afterlines_end\n\n--- Make vim.notify wrapper\n---\n--- Calling this function creates an implementation of |vim.notify()| powered by\n--- this module. General idea is to show notification as soon as safely possible\n--- (see |vim.schedule_wrap()|) and remove it after a configurable amount of time.\n---\n--- All notifications set `source = \"vim.notify\"` in their `data` field.\n---\n--- This is used with default options inside |MiniNotify.setup()|. To adjust,\n--- call manually after `setup()`. For example, to show errors longer: >lua\n---\n---   require('mini.notify').setup()\n---   vim.notify = MiniNotify.make_notify({ ERROR = { duration = 10000 } })\n--- <\n--- To preserve original `vim.notify`: >lua\n---\n---   local notify_orig = vim.notify\n---   require('mini.notify').setup()\n---   vim.notify = notify_orig\n--- <\n---@param opts table|nil Options to configure behavior of notification `level`\n---   (as in |MiniNotify.add()|). Fields are the same as names of `vim.log.levels`\n---   with values being tables with possible fields:\n---   - <duration> `(number)` - duration (in ms) of how much a notification\n---     should be shown. If 0 or negative, notification is not shown at all.\n---   - <hl_group> `(string)` - highlight group of notification.\n---   Only data different to default can be supplied.\n---\n---   Default: >lua\n---\n---   {\n---     ERROR = { duration = 5000, hl_group = 'DiagnosticError'  },\n---     WARN  = { duration = 5000, hl_group = 'DiagnosticWarn'   },\n---     INFO  = { duration = 5000, hl_group = 'DiagnosticInfo'   },\n---     DEBUG = { duration = 0,    hl_group = 'DiagnosticHint'   },\n---     TRACE = { duration = 0,    hl_group = 'DiagnosticOk'     },\n---     OFF   = { duration = 0,    hl_group = 'MiniNotifyNormal' },\n---   }\n--- <\nMiniNotify.make_notify = function(opts)\n  local level_names = {}\n  for k, v in pairs(vim.log.levels) do\n    level_names[v] = k\n  end\n\n  --stylua: ignore\n  local default_opts = {\n    ERROR = { duration = 5000, hl_group = 'DiagnosticError'  },\n    WARN  = { duration = 5000, hl_group = 'DiagnosticWarn'   },\n    INFO  = { duration = 5000, hl_group = 'DiagnosticInfo'   },\n    DEBUG = { duration = 0,    hl_group = 'DiagnosticHint'   },\n    TRACE = { duration = 0,    hl_group = 'DiagnosticOk'     },\n    OFF   = { duration = 0,    hl_group = 'MiniNotifyNormal' },\n  }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  for key, val in pairs(opts) do\n    if default_opts[key] == nil then H.error('Keys should be log level names.') end\n    if type(val) ~= 'table' then H.error('Level data should be table.') end\n    if type(val.duration) ~= 'number' then H.error('`duration` in level data should be number.') end\n    if type(val.hl_group) ~= 'string' then H.error('`hl_group` in level data should be string.') end\n  end\n\n  return vim.schedule_wrap(function(msg, level)\n    level = level or vim.log.levels.INFO\n    local level_name = level_names[level]\n    if level_name == nil then H.error('Only valid values of `vim.log.levels` are supported.') end\n\n    local level_data = opts[level_name]\n    if level_data.duration <= 0 then return end\n\n    local id = MiniNotify.add(msg, level_name, level_data.hl_group, { source = 'vim.notify' })\n    vim.defer_fn(function() MiniNotify.remove(id) end, level_data.duration)\n  end)\nend\n\n--- Add notification\n---\n--- Add notification to history. It is considered \"active\" and is shown.\n--- To hide, call |MiniNotify.remove()| with identifier this function returns.\n---\n--- Example: >lua\n---\n---   local id = MiniNotify.add('Hello', 'WARN', 'Comment')\n---   vim.defer_fn(function() MiniNotify.remove(id) end, 1000)\n--- <\n---@param msg string Notification message.\n---@param level string|nil Notification level as key of |vim.log.levels|.\n---   Default: `'INFO'`.\n---@param hl_group string|nil Notification highlight group.\n---   Default: `'MiniNotifyNormal'`.\n---@param data table|nil Extra data to store in the notification.\n---   Default: `{}`.\n---\n---@return number Notification identifier.\nMiniNotify.add = function(msg, level, hl_group, data)\n  H.validate_msg(msg)\n  level = level or 'INFO'\n  H.validate_level(level)\n  hl_group = hl_group or 'MiniNotifyNormal'\n  H.validate_hl_group(hl_group)\n  data = data or {}\n  H.check_type('data', data, 'table')\n\n  local cur_ts = H.get_timestamp()\n  local new_notif = { msg = msg, level = level, hl_group = hl_group, ts_add = cur_ts, ts_update = cur_ts, data = data }\n\n  local new_id = #H.history + 1\n  -- NOTE: Crucial to use the same table here and later only update values\n  -- inside of it in place. This makes sure that history entries are in sync.\n  H.history[new_id], H.active[new_id] = new_notif, new_notif\n\n  -- Refresh active notifications\n  MiniNotify.refresh()\n\n  return new_id\nend\n\n--- Update active notification\n---\n--- Modify contents of active notification.\n---\n---@param id number Identifier of currently active notification as returned\n---   by |MiniNotify.add()|.\n---@param new table Table with contents to update. Keys should be as non-timestamp\n---   fields of |MiniNotify-specification| and values - new content values.\n---   If present, field `data` is updated as is. Use |MiniNotify.get()| together\n---   with |vim.tbl_deep_extend()| to change only part of it.\nMiniNotify.update = function(id, new)\n  local notif = H.active[id]\n  if notif == nil then H.error('`id` is not an identifier of active notification.') end\n  H.check_type('new', new, 'table')\n\n  if new.msg ~= nil then H.validate_msg(new.msg) end\n  if new.level ~= nil then H.validate_level(new.level) end\n  if new.hl_group ~= nil then H.validate_hl_group(new.hl_group) end\n  H.check_type('data', new.data, 'table', true)\n\n  notif.msg = new.msg or notif.msg\n  notif.level = new.level or notif.level\n  notif.hl_group = new.hl_group or notif.hl_group\n  notif.data = new.data or notif.data\n  notif.ts_update = H.get_timestamp()\n\n  MiniNotify.refresh()\nend\n\n--- Remove notification\n---\n--- If notification is active, make it not active (by setting `ts_remove` field).\n--- If not active, do nothing.\n---\n---@param id number|nil Identifier of previously added notification.\n---   If it is not, nothing is done (silently).\nMiniNotify.remove = function(id)\n  local notif = H.active[id]\n  if notif == nil then return end\n  notif.ts_remove = H.get_timestamp()\n  H.active[id] = nil\n\n  MiniNotify.refresh()\nend\n\n--- Remove all active notifications\n---\n--- Hide all active notifications and stop showing window (if shown).\nMiniNotify.clear = function()\n  local cur_ts = H.get_timestamp()\n  for id, _ in pairs(H.active) do\n    H.active[id].ts_remove = cur_ts\n  end\n  H.active = {}\n\n  MiniNotify.refresh()\nend\n\n--- Refresh notification window\n---\n--- Make notification window show relevant information:\n--- - Create an array of active notifications (see |MiniNotify-specification|).\n--- - Apply `config.content.sort` to an array. If output has zero notifications,\n---   make notification window to not show.\n--- - Apply `config.content.format` to each element of notification array and\n---   update its message.\n--- - Construct content from notifications and show them in a window.\n---\n--- Note: effects are delayed if inside fast event (|vim.in_fast_event()|).\nMiniNotify.refresh = function()\n  if vim.in_fast_event() then return vim.schedule(MiniNotify.refresh) end\n  if H.is_textlock() and vim.fn.has('nvim-0.10') == 1 then\n    pcall(vim.api.nvim_del_autocmd, H.cache.safestate_au_id)\n    local au_opts = { once = true, nested = true, callback = vim.schedule_wrap(MiniNotify.refresh) }\n    H.cache.safestate_au_id = vim.api.nvim_create_autocmd('SafeState', au_opts)\n    return\n  end\n  if H.is_disabled() or type(vim.v.exiting) == 'number' then return H.window_close() end\n\n  -- Prepare array of active notifications\n  local notif_arr = vim.deepcopy(vim.tbl_values(H.active))\n  local config_content = H.get_config().content\n\n  local sort = vim.is_callable(config_content.sort) and config_content.sort or MiniNotify.default_sort\n  notif_arr = sort(notif_arr)\n  if not H.is_notification_array(notif_arr) then H.error('Output of `content.sort` should be notification array.') end\n  if #notif_arr == 0 then return H.window_close() end\n\n  local format = vim.is_callable(config_content.format) and config_content.format or MiniNotify.default_format\n  notif_arr = H.notif_apply_format(notif_arr, format)\n\n  -- Refresh buffer\n  local buf_id = H.cache.buf_id\n  if not H.is_valid_buf(buf_id) then buf_id = H.buffer_create() end\n  H.buffer_refresh(buf_id, notif_arr)\n\n  -- Refresh window\n  local win_id = H.cache.win_id\n  if not (H.is_valid_win(win_id) and H.is_win_in_tabpage(win_id)) then\n    H.window_close()\n    win_id = H.window_open(buf_id)\n  else\n    local new_config = H.window_compute_config(buf_id)\n    vim.api.nvim_win_set_config(win_id, new_config)\n  end\n\n  -- Redraw\n  vim.cmd('redraw')\n\n  -- Update cache\n  H.cache.buf_id, H.cache.win_id = buf_id, win_id\nend\n\n--- Get previously added notification by id\n---\n---@param id number Identifier of notification.\n---\n---@return table Notification object (see |MiniNotify-specification|).\nMiniNotify.get = function(id) return vim.deepcopy(H.history[id]) end\n\n--- Get all previously added notifications\n---\n--- Get map of used notifications with keys being notification identifiers.\n---\n--- Can be used to get only active notification objects. Example: >lua\n---\n---   -- Get active notifications\n---   vim.tbl_filter(\n---     function(notif) return notif.ts_remove == nil end,\n---     MiniNotify.get_all()\n---   )\n--- <\n---@return table Map with notification object values (see |MiniNotify-specification|).\n---   Note: messages are taken from last valid update.\nMiniNotify.get_all = function() return vim.deepcopy(H.history) end\n\n--- Show history\n---\n--- Open or reuse a scratch buffer with all previously shown notifications.\n---\n--- Notes:\n--- - Content is ordered from oldest to newest based on latest update time.\n--- - Message is formatted with `config.content.format`.\nMiniNotify.show_history = function()\n  -- Prepare content\n  local config_content = H.get_config().content\n  local notif_arr = MiniNotify.get_all()\n  table.sort(notif_arr, function(a, b) return a.ts_update < b.ts_update end)\n  local format = vim.is_callable(config_content.format) and config_content.format or MiniNotify.default_format\n  notif_arr = H.notif_apply_format(notif_arr, format)\n\n  -- Show content in a reusable buffer\n  local buf_id\n  for _, id in ipairs(vim.api.nvim_list_bufs()) do\n    if vim.bo[id].filetype == 'mininotify-history' then buf_id = id end\n  end\n  if buf_id == nil then\n    buf_id = vim.api.nvim_create_buf(true, true)\n    H.set_buf_name(buf_id, 'history')\n    vim.bo[buf_id].filetype = 'mininotify-history'\n  end\n  H.buffer_refresh(buf_id, notif_arr)\n  vim.api.nvim_win_set_buf(0, buf_id)\nend\n\n--- Default content format\n---\n--- Used by default as `config.content.format`. Prepends notification message\n--- with the human readable update time and a separator.\n---\n---@param notif table Notification object (see |MiniNotify-specification|).\n---\n---@return string Formatted notification message.\nMiniNotify.default_format = function(notif)\n  local time = vim.fn.strftime('%H:%M:%S', math.floor(notif.ts_update))\n  return string.format('%s │ %s', time, notif.msg)\nend\n\n--- Default content sort\n---\n--- Used by default as `config.content.sort`. First sorts by notification's `level`\n--- (\"ERROR\" > \"WARN\" > \"INFO\" > \"DEBUG\" > \"TRACE\" > \"OFF\"; the bigger the more\n--- important); if draw - by latest update time (the later the more important).\n---\n---@param notif_arr table Array of notifications (see |MiniNotify-specification|).\n---\n---@return table Sorted array of notifications.\nMiniNotify.default_sort = function(notif_arr)\n  local res = vim.deepcopy(notif_arr)\n  table.sort(res, H.notif_compare)\n  return res\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniNotify.config\n\n-- Map of currently active notifications with their id as key\nH.active = {}\n\n-- History of all notifications in order they are created\nH.history = {}\n\n-- Map of LSP progress process id to notification content\nH.lsp_progress = {}\n\n-- Priorities of levels\nH.level_priority = { ERROR = 6, WARN = 5, INFO = 4, DEBUG = 3, TRACE = 2, OFF = 1 }\n\n-- Namespaces\nH.ns_id = {\n  highlight = vim.api.nvim_create_namespace('MiniNotifyHighlight'),\n}\n\n-- Various cache\nH.cache = {\n  -- Notification buffer and window\n  buf_id = nil,\n  win_id = nil,\n  -- Scratch buffer to test if the editor is in textlock state\n  textlock_buf_id = nil,\n  -- Autocommand identifier when delaying until `SafeState`\n  safestate_au_id = nil,\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('content', config.content, 'table')\n  H.check_type('content.format', config.content.format, 'function', true)\n  H.check_type('content.sort', config.content.sort, 'function', true)\n\n  H.check_type('lsp_progress', config.lsp_progress, 'table')\n  H.check_type('lsp_progress.enable', config.lsp_progress.enable, 'boolean')\n  H.check_type('lsp_progress.duration_last', config.lsp_progress.duration_last, 'number')\n\n  H.check_type('window', config.window, 'table')\n  if not (type(config.window.config) == 'table' or vim.is_callable(config.window.config)) then\n    H.error('`window.config` should table or callable, not ' .. type(config.window.config))\n  end\n  H.check_type('window.max_width_share', config.window.max_width_share, 'number')\n  H.check_type('window.winblend', config.window.winblend, 'number')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniNotify.config = config\n\n  if config.lsp_progress.enable then\n    -- Use `vim.schedule` to reduce startup time (sourcing `vim.lsp` is costly)\n    vim.schedule(function()\n      -- Cache original handler only once (to avoid infinite loop)\n      if vim.lsp.handlers['$/progress before mini.notify'] == nil then\n        vim.lsp.handlers['$/progress before mini.notify'] = vim.lsp.handlers['$/progress']\n      end\n\n      vim.lsp.handlers['$/progress'] = H.lsp_progress_handler\n    end)\n  end\n\n  -- Clean history\n  if #H.history > 0 then MiniNotify.clear() end\n  H.history = {}\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniNotify', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au({ 'TabEnter', 'VimResized' }, '*', function() MiniNotify.refresh() end, 'Refresh notifications')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  hi('MiniNotifyBorder', { link = 'FloatBorder' })\n  hi('MiniNotifyLspProgress', { link = 'MiniNotifyNormal' })\n  hi('MiniNotifyNormal', { link = 'NormalFloat' })\n  hi('MiniNotifyTitle',  { link = 'FloatTitle'  })\nend\n\nH.is_disabled = function() return vim.g.mininotify_disable == true or vim.b.mininotify_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniNotify.config, vim.b.mininotify_config or {}, config or {})\nend\n\n-- LSP progress ---------------------------------------------------------------\nH.lsp_progress_handler = function(err, result, ctx, config)\n  -- Make basic response processing. First call original LSP handler.\n  -- On Neovim>=0.10 this is crucial to not override `LspProgress` event.\n  if vim.is_callable(vim.lsp.handlers['$/progress before mini.notify']) then\n    vim.lsp.handlers['$/progress before mini.notify'](err, result, ctx, config)\n  end\n\n  local lsp_progress_config = H.get_config().lsp_progress\n  if not lsp_progress_config.enable then return end\n\n  if err ~= nil then return vim.notify(vim.inspect(err), vim.log.levels.ERROR) end\n  if not (type(result) == 'table' and type(result.value) == 'table') then return end\n  local value = result.value\n\n  local client = vim.lsp.get_client_by_id(ctx.client_id)\n  if client == nil then return end\n\n  -- Construct LSP progress id\n  local buf_id = ctx.bufnr or 'nil'\n  local lsp_progress_id = buf_id .. client.name .. (result.token or '')\n  local progress_info = H.lsp_progress[lsp_progress_id] or {}\n  local data = { source = 'lsp_progress', client_name = client.name, response = result, context = ctx }\n\n  -- Store percentage to be used if no new one was sent\n  progress_info.percentage = (value.kind == 'end' and 100 or value.percentage) or progress_info.percentage or 0\n\n  -- Cache title because it is only supplied on 'begin'\n  if value.kind == 'begin' then progress_info.title = value.title end\n\n  -- Make message\n  local title, message = progress_info.title or '', value.message or ''\n  --stylua: ignore\n  local msg = string.format(\n    '%s: %s%s%s%s(%s%%)',\n    client.name, title, title == '' and '' or ' ', message, message == '' and '' or ' ', progress_info.percentage\n  )\n\n  -- Check for valid history entry as `setup()` might have removed the id\n  if H.history[progress_info.notif_id] == nil then\n    progress_info.notif_id = MiniNotify.add(msg, lsp_progress_config.level, 'MiniNotifyLspProgress', data)\n  else\n    MiniNotify.update(progress_info.notif_id, { msg = msg, data = data })\n  end\n\n  -- Cache progress info\n  H.lsp_progress[lsp_progress_id] = progress_info\n\n  -- Hide notification after last update to reduce flicker\n  if value.kind == 'end' then\n    H.lsp_progress[lsp_progress_id] = nil\n    local delay = math.max(lsp_progress_config.duration_last, 0)\n    vim.defer_fn(function() MiniNotify.remove(progress_info.notif_id) end, delay)\n  end\nend\n\n-- Buffer ---------------------------------------------------------------------\nH.buffer_create = function()\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  H.set_buf_name(buf_id, 'content')\n  vim.bo[buf_id].filetype = 'mininotify'\n  return buf_id\nend\n\nH.buffer_refresh = function(buf_id, notif_arr)\n  local ns_id = H.ns_id.highlight\n\n  -- Ensure clear buffer\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, true, {})\n\n  -- Compute lines and highlight regions\n  local lines, highlights = {}, {}\n  for _, notif in ipairs(notif_arr) do\n    local notif_lines = vim.split(notif.msg, '\\n')\n    for _, l in ipairs(notif_lines) do\n      table.insert(lines, l)\n    end\n    table.insert(highlights, { group = notif.hl_group, from_line = #lines - #notif_lines + 1, to_line = #lines })\n  end\n\n  -- Set lines and highlighting\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, true, lines)\n  local extmark_opts = { end_col = 0, hl_eol = true, hl_mode = 'combine' }\n  for _, hi_data in ipairs(highlights) do\n    extmark_opts.end_row, extmark_opts.hl_group = hi_data.to_line, hi_data.group\n    vim.api.nvim_buf_set_extmark(buf_id, ns_id, hi_data.from_line - 1, 0, extmark_opts)\n  end\nend\n\nH.buffer_default_dimensions = function(buf_id, max_width_share)\n  local line_widths = vim.tbl_map(vim.fn.strdisplaywidth, vim.api.nvim_buf_get_lines(buf_id, 0, -1, true))\n\n  -- Compute width so as to fit all lines\n  local width = 1\n  for _, l_w in ipairs(line_widths) do\n    width = math.max(width, l_w)\n  end\n  -- - Limit from above for better visuals\n  max_width_share = math.min(math.max(max_width_share, 0), 1)\n  local max_width = math.max(math.floor(max_width_share * vim.o.columns), 1)\n  width = math.min(width, max_width)\n\n  -- Compute height based on the width so as to fit all lines with 'wrap' on\n  local height = 0\n  for _, l_w in ipairs(line_widths) do\n    height = height + math.floor(math.max(l_w - 1, 0) / width) + 1\n  end\n\n  return width, height\nend\n\n-- Window ---------------------------------------------------------------------\nH.window_open = function(buf_id)\n  local config = H.window_compute_config(buf_id, true)\n  local win_id = vim.api.nvim_open_win(buf_id, false, config)\n\n  vim.wo[win_id].foldenable = false\n  vim.wo[win_id].foldmethod = 'manual'\n  vim.wo[win_id].winblend = H.get_config().window.winblend\n  vim.wo[win_id].winhighlight = 'NormalFloat:MiniNotifyNormal,FloatBorder:MiniNotifyBorder,FloatTitle:MiniNotifyTitle'\n  vim.wo[win_id].wrap = true\n\n  return win_id\nend\n\nH.window_compute_config = function(buf_id, is_for_open)\n  local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)\n  local has_statusline = vim.o.laststatus > 0\n  local max_height = vim.o.lines - vim.o.cmdheight - (has_tabline and 1 or 0) - (has_statusline and 1 or 0)\n  local max_width = vim.o.columns\n\n  local config_win = H.get_config().window\n  local default_config = { relative = 'editor', style = 'minimal', noautocmd = is_for_open, zindex = 999 }\n  default_config.anchor, default_config.col, default_config.row = 'NE', vim.o.columns, has_tabline and 1 or 0\n  default_config.width, default_config.height = H.buffer_default_dimensions(buf_id, config_win.max_width_share)\n  default_config.border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil\n  default_config.title = ' Notifications '\n  -- Don't allow focus to not disrupt window navigation\n  default_config.focusable = false\n\n  local win_config = config_win.config\n  if vim.is_callable(win_config) then win_config = win_config(buf_id) end\n  local config = vim.tbl_deep_extend('force', default_config, win_config or {})\n\n  -- Tweak config values to ensure they are proper, accounting for border\n  local offset = config.border == 'none' and 0 or 2\n  config.height = math.min(config.height, max_height - offset)\n  config.width = math.min(config.width, max_width - offset)\n  if type(config.title) == 'string' then config.title = H.fit_to_width(config.title, config.width) end\n\n  return config\nend\n\nH.window_close = function()\n  if H.is_valid_win(H.cache.win_id) then vim.api.nvim_win_close(H.cache.win_id, true) end\n  H.cache.win_id = nil\nend\n\n-- Notifications --------------------------------------------------------------\nH.validate_msg = function(x)\n  if type(x) ~= 'string' then H.error('`msg` should be string.') end\nend\n\nH.validate_level = function(x)\n  if vim.log.levels[x] == nil then H.error('`level` should be key of `vim.log.levels`.') end\nend\n\nH.validate_hl_group = function(x)\n  if type(x) ~= 'string' then H.error('`hl_group` should be string.') end\nend\n\nH.is_notification = function(x)\n  return type(x) == 'table'\n    and type(x.msg) == 'string'\n    and vim.log.levels[x.level] ~= nil\n    and type(x.hl_group) == 'string'\n    and type(x.ts_add) == 'number'\n    and type(x.ts_update) == 'number'\n    and (x.ts_remove == nil or type(x.ts_remove) == 'number')\nend\n\nH.is_notification_array = function(x)\n  if not H.islist(x) then return false end\n  for _, y in ipairs(x) do\n    if not H.is_notification(y) then return false end\n  end\n  return true\nend\n\nH.notif_apply_format = function(notif_arr, format)\n  for _, notif in ipairs(notif_arr) do\n    local res = format(notif)\n    if type(res) ~= 'string' then H.error('Output of `content.format` should be string.') end\n    notif.msg = res\n  end\n  return notif_arr\nend\n\nH.notif_compare = function(a, b)\n  local a_priority, b_priority = H.level_priority[a.level], H.level_priority[b.level]\n  return a_priority > b_priority or (a_priority == b_priority and a.ts_update > b.ts_update)\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.notify) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'mininotify://' .. buf_id .. '/' .. name) end\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.is_win_in_tabpage = function(win_id) return vim.api.nvim_win_get_tabpage(win_id) == vim.api.nvim_get_current_tabpage() end\n\nH.is_textlock = function()\n  if not H.is_valid_buf(H.cache.textlock_buf_id) then\n    H.cache.textlock_buf_id = vim.api.nvim_create_buf(false, true)\n    H.set_buf_name(H.cache.textlock_buf_id, 'textlock-check-scratch')\n  end\n  local ok = pcall(vim.api.nvim_buf_set_lines, H.cache.textlock_buf_id, 0, -1, false, {})\n  return not ok\nend\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.get_timestamp = function()\n  -- This is more acceptable for `vim.fn.strftime()` than `vim.loop.hrtime()`\n  local seconds, microseconds = vim.loop.gettimeofday()\n  return seconds + 0.000001 * microseconds\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniNotify\n"
  },
  {
    "path": "lua/mini/operators.lua",
    "content": "--- *mini.operators* Text edit operators\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Operators:\n---     - Evaluate text and replace with output.\n---     - Exchange text regions.\n---     - Multiply (duplicate) text.\n---     - Replace text with register.\n---     - Sort text.\n---\n--- - Automated configurable mappings to operate on textobject, line, selection.\n---   Can be disabled in favor of more control with |MiniOperators.make_mappings()|.\n---\n--- - All operators support |[count]| and dot-repeat.\n---\n--- See |MiniOperators-overview| and |MiniOperators.config| for more details.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.operators').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniOperators`\n--- which you can use for scripting or manually (with `:lua MiniOperators.*`).\n---\n--- See |MiniOperators.config| for available config settings.\n---\n--- You can override runtime config settings (but not `config.mappings`) locally\n--- to buffer inside `vim.b.minioperators_config` which should have same structure\n--- as `MiniOperators.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [gbprod/substitute.nvim](https://github.com/gbprod/substitute.nvim):\n---     - Has \"replace\" and \"exchange\" variants, but not others from this module.\n---     - Has \"replace/substitute\" over range functionality, while this module\n---       does not by design (it is similar to |:s| functionality while not\n---       offering significantly lower mental complexity).\n---     - \"Replace\" highlights pasted text, while in this module it doesn't.\n---     - \"Exchange\" doesn't work across buffers, while in this module it does.\n---\n--- - [svermeulen/vim-subversive](https://github.com/svermeulen/vim-subversive):\n---     - Main inspiration for \"replace\" functionality, so they are mostly similar\n---       for this operator.\n---     - Has \"replace/substitute\" over range functionality, while this module\n---       does not by design.\n---\n--- - [tommcdo/vim-exchange](https://github.com/tommcdo/vim-exchange):\n---     - Main inspiration for \"exchange\" functionality, so they are mostly\n---       similar for this operator.\n---     - Doesn't work across buffers, while this module does.\n---\n--- - [christoomey/vim-sort-motion](https://github.com/christoomey/vim-sort-motion):\n---     - Uses |:sort| for linewise sorting, while this module uses consistent\n---       sorting algorithm (by default, see |MiniOperators.default_sort_func()|).\n---     - Sorting algorithm can't be customized, while this module allows this\n---       (see `sort.func` in |MiniOperators.config|).\n---     - For charwise region uses only commas as separators, while this module\n---       can also separate by semicolon or whitespace (by default,\n---       see |MiniOperators.default_sort_func()|).\n---\n--- # Highlight groups ~\n---\n--- - `MiniOperatorsExchangeFrom` - first region to exchange.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable main functionality, set `vim.g.minioperators_disable` (globally) or\n--- `vim.b.minioperators_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniOperators\n\n--- Operator defines an action that will be performed on a textobject, motion,\n--- or visual selection (similar to |d|, |c|, etc.). When makes sense, it can also\n--- respect supplied register (like \"replace\" operator).\n---\n--- This module implements each operator in a separate dedicated function\n--- (like |MiniOperators.replace()| for \"replace\" operator). Each such function\n--- takes `mode` as argument and acts depending on it:\n---\n--- - If `mode` is `nil` (or not explicitly supplied), it sets |'operatorfunc'|\n---   to this dedicated function and returns `g@` assuming being called from\n---   expression mapping. See |:map-operator| and |:map-expression| for more details.\n---\n--- - If `mode` is \"char\", \"line\", or \"block\", it acts as `operatorfunc` and performs\n---   action for region between |`[| and |`]| marks.\n---\n--- - If `mode` is \"visual\", it performs action for region between |`<| and |`>| marks.\n---\n--- For more details about specific operator, see help for its function:\n---\n--- - Evaluate: |MiniOperators.evaluate()|\n--- - Exchange: |MiniOperators.exchange()|\n--- - Multiply: |MiniOperators.multiply()|\n--- - Replace:  |MiniOperators.replace()|\n--- - Sort:     |MiniOperators.sort()|\n---\n--- # Mappings ~\n--- *MiniOperators-mappings*\n---\n--- All operators are automatically mapped during |MiniOperators.setup()| execution.\n--- Mappings keys are deduced from `prefix` field of corresponding `config` entry.\n--- All built-in conflicting mappings are removed (like |gra|, |grn| in Neovim>=0.11).\n--- Both |gx| and |v_gx| are remapped to `gX` (if that is not already taken).\n---\n--- For each operator the following mappings are created:\n---\n--- - In Normal mode to operate on textobject. Uses `prefix` directly.\n--- - In Normal mode to operate on line. Appends to `prefix` the last character.\n---   This aligns with |operator-doubled| and established patterns for operators\n---   with more than two characters, like |guu|, |gUU|, etc.\n--- - In Visual mode to operate on visual selection. Uses `prefix` directly.\n---\n--- Example of default mappings for \"replace\":\n--- - `gr` in Normal mode for operating on textobject.\n---   Example of usage: `griw` replaces \"inner word\" with default register.\n--- - `grr` in Normal mode for operating on line.\n---   Example of usage: `grr` replaces current line.\n--- - `gr` in Visual mode for operating on visual selection.\n---   Example of usage: `viw` selects \"inner word\" and `gr` replaces it.\n---\n--- There are two suggested ways to customize mappings:\n---\n--- - Change `prefix` in |MiniOperators.setup()| call. For example, doing >lua\n---\n---     require('mini.operators').setup({ replace = { prefix = 'cr' } })\n--- <\n---   will make mappings for `cr` / `crr` / `cr` instead of `gr` / `grr` / `gr`.\n---\n--- - Disable automated mapping creation by supplying empty string as prefix and\n---   use |MiniOperators.make_mappings()| directly. For example: >lua\n---\n---     -- Disable automated creation of \"replace\"\n---     local operators = require('mini.operators')\n---     operators.setup({ replace = { prefix = '' } })\n---\n---     -- Make custom mappings\n---     operators.make_mappings(\n---       'replace',\n---       { textobject = 'cr', line = 'crr', selection = 'cr' }\n---     )\n--- <\n---@tag MiniOperators-overview\n\n---@alias __operators_mode string|nil One of `nil`, `'char'`, `'line'`, `'block'`, `'visual'`.\n---@alias __operators_content table Table with the following fields:\n---   - <lines> `(table)` - array with content lines.\n---   - <submode> `(string)` - region submode. One of `'v'`, `'V'`, `'<C-v>'` (escaped).\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n\n-- Module definition ==========================================================\nlocal MiniOperators = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniOperators.config|.\n---\n---@usage >lua\n---   require('mini.operators').setup() -- use default config\n---   -- OR\n---   require('mini.operators').setup({}) -- replace {} with your config table\n--- <\nMiniOperators.setup = function(config)\n  -- Export module\n  _G.MiniOperators = MiniOperators\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Evaluate ~\n---\n--- `evaluate.prefix` is a string used to automatically infer operator mappings keys\n--- during |MiniOperators.setup()|. See |MiniOperators-mappings|.\n---\n--- `evaluate.func` is a function used to actually evaluate text region.\n--- If `nil` (default), |MiniOperators.default_evaluate_func()| is used.\n---\n--- This function will take content table representing selected text as input\n--- and should return array of lines as output (each item per line).\n--- Content table has fields `lines`, array of region lines, and `submode`,\n--- one of `v`, `V`, `\\22` (escaped `<C-v>`) for charwise, linewise, and blockwise.\n---\n--- To customize evaluation per language, set `evaluate.func` in buffer-local\n--- config (`vim.b.minioperators_config`; see |mini.nvim-buffer-local-config|).\n---\n--- # Exchange ~\n---\n--- `exchange.prefix` is a string used to automatically infer operator mappings keys\n--- during |MiniOperators.setup()|. See |MiniOperators-mappings|.\n---\n--- Note: default value \"gx\" overrides |gx| / |v_gx|. Instead they are remapped\n--- to `gX` (if that is not already taken). To keep using `gx` with built-in\n--- feature (open URL at cursor) choose different `config.prefix`.\n---\n--- `exchange.reindent_linewise` is a boolean indicating whether newly put linewise\n--- text should preserve indent of replaced text. In other words, if `false`,\n--- regions are exchanged preserving their indents; if `true` - without them.\n---\n--- # Multiply ~\n---\n--- `multiply.prefix` is a string used to automatically infer operator mappings keys\n--- during |MiniOperators.setup()|. See |MiniOperators-mappings|.\n---\n--- `multiply.func` is a function used to optionally update multiplied text.\n--- If `nil` (default), text used as is.\n---\n--- Takes content table as input (see \"Evaluate\" section) and should return\n--- array of lines as output.\n---\n--- # Replace ~\n---\n--- `replace.prefix` is a string used to automatically infer operator mappings keys\n--- during |MiniOperators.setup()|. See |MiniOperators-mappings|.\n---\n--- `replace.reindent_linewise` is a boolean indicating whether newly put linewise\n--- text should preserve indent of replaced text.\n---\n--- # Sort ~\n---\n--- `sort.prefix` is a string used to automatically infer operator mappings keys\n--- during |MiniOperators.setup()|. See |MiniOperators-mappings|.\n---\n--- `sort.func` is a function used to actually sort text region.\n--- If `nil` (default), |MiniOperators.default_sort_func()| is used.\n---\n--- Takes content table as input (see \"Evaluate\" section) and should return\n--- array of lines as output.\n---\n--- Example of `sort.func` which asks user for custom delimiter for charwise region: >lua\n---\n---   local sort_func = function(content)\n---     local opts = {}\n---     if content.submode == 'v' then\n---       -- Ask for delimiter to be treated as is (not as Lua pattern)\n---       local delimiter = vim.fn.input('Sort delimiter: ')\n---       -- Treat surrounding whitespace as part of split\n---       opts.split_patterns = { '%s*' .. vim.pesc(delimiter) .. '%s*' }\n---     end\n---     return MiniOperators.default_sort_func(content, opts)\n---   end\n---\n---   require('mini.operators').setup({ sort = { func = sort_func } })\n--- <\nMiniOperators.config = {\n  -- Each entry configures one operator.\n  -- `prefix` defines keys mapped during `setup()`: in Normal mode\n  -- to operate on textobject and line, in Visual - on selection.\n\n  -- Evaluate text and replace with output\n  evaluate = {\n    prefix = 'g=',\n\n    -- Function which does the evaluation\n    func = nil,\n  },\n\n  -- Exchange text regions\n  exchange = {\n    -- NOTE: Default `gx` is remapped to `gX`\n    prefix = 'gx',\n\n    -- Whether to reindent new text to match previous indent\n    reindent_linewise = true,\n  },\n\n  -- Multiply (duplicate) text\n  multiply = {\n    prefix = 'gm',\n\n    -- Function which can modify text before multiplying\n    func = nil,\n  },\n\n  -- Replace text with register\n  replace = {\n    -- NOTE: Default `gr*` LSP mappings are removed\n    prefix = 'gr',\n\n    -- Whether to reindent new text to match previous indent\n    reindent_linewise = true,\n  },\n\n  -- Sort text\n  sort = {\n    prefix = 'gs',\n\n    -- Function which does the sort\n    func = nil,\n  }\n}\n--minidoc_afterlines_end\n\n--- Evaluate text and replace with output\n---\n--- It replaces the region with the output of `config.evaluate.func`.\n--- By default it is |MiniOperators.default_evaluate_func()| which evaluates\n--- text as Lua code depending on the region submode.\n---\n---@param mode __operators_mode\nMiniOperators.evaluate = function(mode)\n  if H.is_disabled() or not vim.bo.modifiable then return '' end\n\n  -- If used without arguments inside expression mapping, set it as\n  -- 'operatorfunc' and call it again as a result of expression mapping.\n  if mode == nil then\n    vim.o.operatorfunc = 'v:lua.MiniOperators.evaluate'\n    return 'g@'\n  end\n\n  local evaluate_func = H.get_config().evaluate.func or MiniOperators.default_evaluate_func\n  local data = H.get_region_data(mode)\n  if data == nil then return end\n  data.reindent_linewise = true\n  H.apply_content_func(evaluate_func, data)\nend\n\n--- Exchange text regions\n---\n--- Has two-step logic:\n--- - First call remembers the region as the one to be exchanged and highlights it\n---   with `MiniOperatorsExchangeFrom` highlight group.\n--- - Second call performs the exchange. Basically, a two substeps action:\n---   \"yank both regions\" and replace each one with another.\n---\n--- Notes:\n--- - Use `<C-c>` to stop exchanging after the first step.\n---\n--- - Exchanged regions can have different (char,line,block)-wise submodes.\n---\n--- - Works with most cases of intersecting regions, but not officially supported.\n---\n---@param mode __operators_mode\nMiniOperators.exchange = function(mode)\n  if H.is_disabled() or not vim.bo.modifiable then return '' end\n\n  -- If used without arguments inside expression mapping, set it as\n  -- 'operatorfunc' and call it again as a result of expression mapping.\n  if mode == nil then\n    vim.o.operatorfunc = 'v:lua.MiniOperators.exchange'\n    return 'g@'\n  end\n\n  -- Depending on present cache data, perform exchange step\n  if not H.exchange_has_step_one() then\n    -- Store data about first region\n    H.cache.exchange.step_one = H.exchange_set_region_extmark(mode, true)\n    if H.cache.exchange.step_one == nil then return end\n\n    -- Temporarily remap `<C-c>` to stop the exchange\n    H.exchange_set_stop_mapping()\n  else\n    -- Store data about second region\n    H.cache.exchange.step_two = H.exchange_set_region_extmark(mode, false)\n    if H.cache.exchange.step_two == nil then return end\n\n    -- Do exchange\n    H.exchange_do()\n\n    -- Stop exchange\n    H.exchange_stop()\n  end\nend\n\n--- Multiply (duplicate) text\n---\n--- Copies a region (without affecting registers) and puts it directly after.\n---\n--- Notes:\n--- - Supports two types of |[count]|: `[count1]gm[count2][textobject]` with default\n---   `config.multiply.prefix` makes `[count1]` copies of region defined by\n---   `[count2][textobject]`. Example: `2gm3aw` - 2 copies of `3aw`.\n---\n--- - |[count]| for \"line\" mapping (`gmm` by default) is treated as `[count1]` from\n---   previous note.\n---\n--- - Advantages of using this instead of \"yank\" + \"paste\":\n---    - Doesn't modify any register, while separate steps need some register to\n---      hold multiplied text.\n---    - In most cases separate steps would be \"yank\" + \"move cursor\" + \"paste\",\n---      while \"multiply\" makes it at once.\n---\n---@param mode __operators_mode\nMiniOperators.multiply = function(mode)\n  if H.is_disabled() or not vim.bo.modifiable then return '' end\n\n  -- If used without arguments inside expression mapping, set it as\n  -- 'operatorfunc' and call it again as a result of expression mapping.\n  if mode == nil then\n    vim.o.operatorfunc = 'v:lua.MiniOperators.multiply'\n    H.cache.multiply = { count = vim.v.count1 }\n\n    -- Reset count to allow two counts: first for paste, second for textobject\n    return vim.api.nvim_replace_termcodes('<Cmd>redraw<CR>g@', true, true, true)\n  end\n\n  local count = mode == 'visual' and vim.v.count1 or H.cache.multiply.count\n  local data = H.get_region_data(mode)\n  if data == nil then return end\n  local mark_from, mark_to, submode = data.mark_from, data.mark_to, data.submode\n\n  H.with_temp_context({ registers = { 'x', '\"' } }, function()\n    -- Yank to temporary \"x\" register\n    local yank_data = { mark_from = mark_from, mark_to = mark_to, submode = submode, mode = mode, register = 'x' }\n    H.do_between_marks('y', yank_data)\n\n    -- Modify lines in \"x\" register\n    local func = H.get_config().multiply.func or function(content) return content.lines end\n    local x_reginfo = vim.fn.getreginfo('x')\n    x_reginfo.regcontents = func({ lines = x_reginfo.regcontents, submode = submode })\n    vim.fn.setreg('x', x_reginfo)\n\n    -- Adjust cursor for a proper paste\n    local ref_coords = H.multiply_get_ref_coords(mark_from, mark_to, submode)\n    vim.api.nvim_win_set_cursor(0, ref_coords)\n\n    -- Paste after textobject from temporary register\n    H.cmd_normal(count .. '\"xp')\n\n    -- Adjust cursor to be at start of pasted text. Not in linewise mode as it\n    -- already is at first non-blank, while this moves to first column.\n    if submode ~= 'V' then vim.cmd('normal! `[') end\n  end)\nend\n\n--- Replace text with register\n---\n--- Notes:\n--- - Supports two types of |[count]|: `[count1]gr[count2][textobject]` with default\n---   `config.replace.prefix` puts `[count1]` contents of register over region defined\n---   by `[count2][textobject]`. Example: `2gr3aw` - 2 register contents over `3aw`.\n---\n--- - |[count]| for \"line\" mapping (`grr` by default) is treated as `[count1]` from\n---   previous note.\n---\n--- - Advantages of using this instead of \"visually select\" + \"paste with |v_P|\":\n---    - As operator it is dot-repeatable which has cumulative gain in case of\n---      multiple replacing is needed.\n---    - Can automatically reindent.\n---\n---@param mode __operators_mode\nMiniOperators.replace = function(mode)\n  if H.is_disabled() or not vim.bo.modifiable then return '' end\n\n  -- If used without arguments inside expression mapping, set it as\n  -- 'operatorfunc' and call it again as a result of expression mapping.\n  if mode == nil then\n    vim.o.operatorfunc = 'v:lua.MiniOperators.replace'\n    H.cache.replace = { count = vim.v.count1, register = vim.v.register }\n\n    -- Reset count to allow two counts: first for paste, second for textobject\n    return vim.api.nvim_replace_termcodes('<Cmd>redraw<CR>g@', true, true, true)\n  end\n\n  -- Do replace\n  -- - Compute `count` and `register` prior getting region data because it\n  --   invalidates them for active Visual mode\n  local count = mode == 'visual' and vim.v.count1 or H.cache.replace.count\n  local register = mode == 'visual' and vim.v.register or H.cache.replace.register\n  local data = H.get_region_data(mode)\n  if data == nil then return '' end\n  data.count = count\n  data.register = register\n  data.reindent_linewise = H.get_config().replace.reindent_linewise\n\n  H.replace_do(data)\n\n  return ''\nend\n\n--- Sort text\n---\n--- It replaces the region with the output of `config.sort.func`.\n--- By default it is |MiniOperators.default_sort_func()| which sorts the text\n--- depending on submode.\n---\n--- Notes:\n--- - \"line\" mapping is charwise (as there is not much sense in sorting\n---   linewise a single line). This also results into no |[count]| support.\n---\n---@param mode __operators_mode\nMiniOperators.sort = function(mode)\n  if H.is_disabled() or not vim.bo.modifiable then return '' end\n\n  -- If used without arguments inside expression mapping, set it as\n  -- 'operatorfunc' and call it again as a result of expression mapping.\n  if mode == nil then\n    vim.o.operatorfunc = 'v:lua.MiniOperators.sort'\n    return 'g@'\n  end\n\n  local sort_func = H.get_config().sort.func or MiniOperators.default_sort_func\n  H.apply_content_func(sort_func, H.get_region_data(mode))\nend\n\n--- Make operator mappings\n---\n---@param operator_name string Name of existing operator from this module.\n---@param lhs_tbl table Table with mappings keys. Should have these fields:\n---   - <textobject> `(string)` - Normal mode mapping to operate on textobject.\n---   - <line> `(string)` - Normal mode mapping to operate on line.\n---     Usually an alias for textobject mapping followed by |_|.\n---     For \"sort\" it operates charwise on whole line without left and right\n---     whitespace (as there is not much sense in sorting linewise a single line).\n---   - <selection> `(string)` - Visual mode mapping to operate on selection.\n---\n---   Supply empty string to not create particular mapping. Note: creating `line`\n---   mapping needs `textobject` mapping to be set.\n---\n---@usage >lua\n---   require('mini.operators').make_mappings(\n---     'replace',\n---     { textobject = 'cr', line = 'crr', selection = 'cr' }\n---   )\n--- <\nMiniOperators.make_mappings = function(operator_name, lhs_tbl)\n  -- Validate arguments\n  if not (type(operator_name) == 'string' and MiniOperators[operator_name] ~= nil) then\n    H.error('`operator_name` should be a valid operator name.')\n  end\n  local is_keys_tbl = type(lhs_tbl) == 'table'\n    and type(lhs_tbl.textobject) == 'string'\n    and type(lhs_tbl.line) == 'string'\n    and type(lhs_tbl.selection) == 'string'\n  if not is_keys_tbl then H.error('`lhs_tbl` should be a valid table of keys.') end\n\n  if lhs_tbl.line ~= '' and lhs_tbl.textobject == '' then\n    H.error('Creating mapping for `line` needs mapping for `textobject`.')\n  end\n\n  -- Make mappings\n  local operator_desc = operator_name:sub(1, 1):upper() .. operator_name:sub(2)\n\n  local expr_opts = { expr = true, replace_keycodes = false, desc = operator_desc }\n  H.map('n', lhs_tbl.textobject, string.format('v:lua.MiniOperators.%s()', operator_name), expr_opts)\n\n  local rhs = lhs_tbl.textobject .. '_'\n  -- - Make `sort()` line mapping to be charwise\n  if operator_name == 'sort' then rhs = '^' .. lhs_tbl.textobject .. 'g_' end\n  H.map('n', lhs_tbl.line, rhs, { remap = true, desc = operator_desc .. ' line' })\n\n  local visual_rhs = string.format([[<Cmd>lua MiniOperators.%s('visual')<CR>]], operator_name)\n  H.map('x', lhs_tbl.selection, visual_rhs, { desc = operator_desc .. ' selection' })\nend\n\n--- Default evaluate function\n---\n--- Evaluate text as Lua code and return object from last line (like if last\n--- line is prepended with `return` if it is not already).\n---\n--- Behavior depends on region submode:\n---\n--- - For charwise and linewise regions, text evaluated as is.\n---\n--- - For blockwise region, lines are evaluated per line using only first lines\n---   of outputs. This allows separate execution of lines in order to provide\n---   something different compared to linewise region.\n---\n---@param content __operators_content\nMiniOperators.default_evaluate_func = function(content)\n  if not H.is_content(content) then H.error('`content` should be a content table.') end\n\n  local lines, submode = content.lines, content.submode\n\n  -- In non-blockwise mode return the result of the last line\n  if submode ~= H.submode_keys.block then return H.eval_lua_lines(lines) end\n\n  -- In blockwise selection evaluate and return each line separately\n  return vim.tbl_map(function(l) return H.eval_lua_lines({ l })[1] end, lines)\nend\n\n--- Default sort function\n---\n--- Sort text based on region submode:\n---\n--- - For charwise region, split by separator pattern, sort parts, merge back\n---   with separators. Actual pattern is inferred based on the array of patterns\n---   from `opts.split_patterns`: whichever element is present in the text is\n---   used, preferring the earlier one if several are present.\n---   Example: sorting \"c, b; a\" line with default `opts.split_patterns` results\n---   into \"b; a, c\" as it is split only by comma.\n---\n--- - For linewise and blockwise regions sort lines as is.\n---\n--- Notes:\n--- - Sort is done with |table.sort()| on an array of lines, which doesn't treat\n---   whitespace or digits specially. Use |:sort| for more complicated tasks.\n---\n--- - Pattern is allowed to be an empty string in which case split results into\n---   all characters as parts.\n---\n--- - Pad pattern in `split_patterns` with `%s*` to include whitespace into separator.\n---   Example: line \"b _ a\" with \"_\" pattern will be sorted as \" a_b \" (because\n---   it is split as \"b \", \"_\", \" a\" ) while with \"%s*_%s*\" pattern it results\n---   into \"a _ b\" (split as \"b\", \" _ \", \"a\").\n---\n---@param content __operators_content\n---@param opts table|nil Options. Possible fields:\n---   - <compare_fun> `(function)` - compare function compatible with |table.sort()|.\n---     Default: direct compare with `<`.\n---   - <split_patterns> `(table)` - array of split Lua patterns to be used for\n---     charwise submode. Order is important.\n---     Default: `{ '%s*,%s*', '%s*;%s*', '%s+', '' }`.\nMiniOperators.default_sort_func = function(content, opts)\n  if not H.is_content(content) then H.error('`content` should be a content table.') end\n\n  opts = vim.tbl_deep_extend('force', { compare_fun = nil, split_patterns = nil }, opts or {})\n\n  local compare_fun = opts.compare_fun or function(a, b) return a < b end\n  if not vim.is_callable(compare_fun) then H.error('`opts.compare_fun` should be callable.') end\n\n  local split_patterns = opts.split_patterns or { '%s*,%s*', '%s*;%s*', '%s+', '' }\n  if not H.islist(split_patterns) then H.error('`opts.split_patterns` should be array.') end\n\n  -- Prepare lines to sort\n  local lines, submode = content.lines, content.submode\n\n  if submode ~= 'v' then\n    table.sort(lines, compare_fun)\n    return lines\n  end\n\n  local parts, seps = H.sort_charwise_split(lines, split_patterns)\n  table.sort(parts, compare_fun)\n  return H.sort_charwise_unsplit(parts, seps)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniOperators.config)\n\n-- Namespaces\nH.ns_id = {\n  exchange = vim.api.nvim_create_namespace('MiniOperatorsExchange'),\n}\n\n-- Cache for all operators\nH.cache = {\n  exchange = {},\n  multiply = {},\n  replace = {},\n}\n\n-- Submode keys for\nH.submode_keys = {\n  char = 'v',\n  line = 'V',\n  block = vim.api.nvim_replace_termcodes('<C-v>', true, true, true),\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('evaluate', config.evaluate, 'table')\n  H.check_type('evaluate.prefix', config.evaluate.prefix, 'string')\n  H.check_type('evaluate.func', config.evaluate.func, 'function', true)\n\n  H.check_type('exchange', config.exchange, 'table')\n  H.check_type('exchange.prefix', config.exchange.prefix, 'string')\n  H.check_type('exchange.reindent_linewise', config.exchange.reindent_linewise, 'boolean')\n\n  H.check_type('multiply', config.multiply, 'table')\n  H.check_type('multiply.prefix', config.multiply.prefix, 'string')\n  H.check_type('multiply.func', config.multiply.func, 'function', true)\n\n  H.check_type('replace', config.replace, 'table')\n  H.check_type('replace.prefix', config.replace.prefix, 'string')\n  H.check_type('replace.reindent_linewise', config.replace.reindent_linewise, 'boolean')\n\n  H.check_type('sort', config.sort, 'table')\n  H.check_type('sort.prefix', config.sort.prefix, 'string')\n  H.check_type('sort.func', config.sort.func, 'function', true)\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniOperators.config = config\n\n  local remove_lsp_mapping = function(mode, lhs)\n    local map_desc = vim.fn.maparg(lhs, mode, false, true).desc\n    if map_desc == nil or string.find(map_desc, 'vim%.lsp') == nil then return end\n    vim.keymap.del(mode, lhs)\n  end\n\n  local remap_builtin_gx = function(mode)\n    if vim.fn.maparg('gX', mode) ~= '' then return end\n    local keymap = vim.fn.maparg('gx', mode, false, true)\n    local rhs = keymap.callback or keymap.rhs\n    if rhs == nil or (keymap.desc or ''):find('URI under cursor') == nil then return end\n    vim.keymap.set(mode, 'gX', rhs, { desc = keymap.desc })\n  end\n\n  -- Make mappings\n  local map_all = function(operator_name)\n    -- Map only valid LHS\n    local prefix = config[operator_name].prefix\n    if type(prefix) ~= 'string' or prefix == '' then return end\n\n    -- Remove conflicting built-in mappings\n    if prefix == 'gr' and vim.fn.has('nvim-0.11') == 1 then\n      remove_lsp_mapping('n', 'gra')\n      remove_lsp_mapping('x', 'gra')\n      remove_lsp_mapping('n', 'gri')\n      remove_lsp_mapping('n', 'grn')\n      remove_lsp_mapping('n', 'grr')\n      remove_lsp_mapping('n', 'grt')\n      remove_lsp_mapping('n', 'grx')\n    end\n\n    if prefix == 'gx' and vim.fn.has('nvim-0.10') == 1 then\n      remap_builtin_gx('n')\n      remap_builtin_gx('x')\n    end\n\n    local lhs_tbl = {\n      textobject = prefix,\n      line = prefix .. vim.fn.strcharpart(prefix, vim.fn.strchars(prefix) - 1, 1),\n      selection = prefix,\n    }\n    MiniOperators.make_mappings(operator_name, lhs_tbl)\n  end\n\n  map_all('evaluate')\n  map_all('exchange')\n  map_all('multiply')\n  map_all('replace')\n  map_all('sort')\nend\n\nH.is_disabled = function() return vim.g.minioperators_disable == true or vim.b.minioperators_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniOperators.config, vim.b.minioperators_config or {}, config or {})\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniOperators', {})\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\nend\n\nH.create_default_hl = function()\n  vim.api.nvim_set_hl(0, 'MiniOperatorsExchangeFrom', { default = true, link = 'IncSearch' })\nend\n\n-- Evaluate -------------------------------------------------------------------\nH.eval_lua_lines = function(lines)\n  -- Copy to not modify input\n  local lines_copy, n = vim.deepcopy(lines), #lines\n  lines_copy[n] = (lines_copy[n]:find('^%s*return%s+') == nil and 'return ' or '') .. lines_copy[n]\n\n  local str_to_eval = table.concat(lines_copy, '\\n')\n\n  -- Allow returning tuple with any value(s) being `nil`\n  return H.inspect_objects(assert(loadstring(str_to_eval))())\nend\n\nH.inspect_objects = function(...)\n  local objects = {}\n  -- Not using `{...}` because it removes `nil` input\n  for i = 1, select('#', ...) do\n    local v = select(i, ...)\n    table.insert(objects, vim.inspect(v))\n  end\n\n  return vim.split(table.concat(objects, '\\n'), '\\n')\nend\n\n-- Exchange -------------------------------------------------------------------\nH.exchange_do = function()\n  local step_one, step_two = H.cache.exchange.step_one, H.cache.exchange.step_two\n\n  -- Do nothing if regions are the same\n  if H.exchange_is_same_steps(step_one, step_two) then return end\n\n  -- Save temporary registers\n  local reg_one, reg_two = vim.fn.getreginfo('a'), vim.fn.getreginfo('b')\n\n  -- Create step temporary contexts (data that should not change)\n  local context_one = { buf_id = step_one.buf_id, marks = { 'x', 'y' }, registers = { '\"' } }\n  local context_two = { buf_id = step_two.buf_id, marks = { 'x', 'y' }, registers = { '\"' } }\n\n  -- Put regions into registers. NOTE: do it before actual exchange to allow\n  -- intersecting regions.\n  local populating_register = function(step, register)\n    return function()\n      H.exchange_set_step_marks(step, { 'x', 'y' })\n      local yank_data =\n        { mark_from = 'x', mark_to = 'y', submode = step.submode, mode = step.mode, register = register }\n      H.do_between_marks('y', yank_data)\n    end\n  end\n\n  H.with_temp_context(context_one, populating_register(step_one, 'a'))\n  H.with_temp_context(context_two, populating_register(step_two, 'b'))\n\n  -- Sequentially replace\n  local replacing = function(step, register)\n    return function()\n      H.exchange_set_step_marks(step, { 'x', 'y' })\n\n      local replace_data = {\n        count = 1,\n        mark_from = 'x',\n        mark_to = 'y',\n        mode = step.mode,\n        register = register,\n        reindent_linewise = H.get_config().exchange.reindent_linewise,\n        submode = step.submode,\n      }\n      H.replace_do(replace_data)\n    end\n  end\n\n  H.with_temp_context(context_one, replacing(step_one, 'b'))\n  H.with_temp_context(context_two, replacing(step_two, 'a'))\n\n  -- Restore temporary registers\n  vim.fn.setreg('a', reg_one)\n  vim.fn.setreg('b', reg_two)\nend\n\nH.exchange_has_step_one = function()\n  local step_one = H.cache.exchange.step_one\n  if type(step_one) ~= 'table' then return false end\n\n  if not vim.api.nvim_buf_is_valid(step_one.buf_id) then\n    H.exchange_stop()\n    return false\n  end\n  return true\nend\n\nH.exchange_set_region_extmark = function(mode, add_highlight)\n  local ns_id = H.ns_id.exchange\n\n  -- Compute regular marks for target region\n  local region_data = H.get_region_data(mode)\n  if region_data == nil then return end\n  local submode = region_data.submode\n  local markcoords_from, markcoords_to = H.get_mark(region_data.mark_from), H.get_mark(region_data.mark_to)\n\n  -- Compute extmark's range for target region\n  local extmark_from = { markcoords_from[1] - 1, markcoords_from[2] }\n  local extmark_to = { markcoords_to[1] - 1, H.get_next_char_bytecol(markcoords_to) }\n\n  -- Adjust for visual selection in case of 'selection=exclusive'\n  if region_data.mark_to == '>' and vim.o.selection == 'exclusive' then extmark_to[2] = extmark_to[2] - 1 end\n\n  -- - Tweak columns for linewise marks\n  if submode == 'V' then\n    extmark_from[2] = 0\n    extmark_to[2] = vim.fn.col({ extmark_to[1] + 1, '$' }) - 1\n  end\n\n  -- Set extmark to represent region. Add highlighting inside of it only if\n  -- needed and not in blockwise submode (can't highlight that way).\n  local buf_id = vim.api.nvim_get_current_buf()\n\n  local extmark_hl_group\n  if add_highlight and submode ~= H.submode_keys.block then extmark_hl_group = 'MiniOperatorsExchangeFrom' end\n\n  local extmark_opts = {\n    end_row = extmark_to[1],\n    end_col = extmark_to[2],\n    hl_group = extmark_hl_group,\n    -- Using this gravity is better for handling empty lines in linewise mode\n    end_right_gravity = mode == 'line',\n  }\n  local region_extmark_id = vim.api.nvim_buf_set_extmark(buf_id, ns_id, extmark_from[1], extmark_from[2], extmark_opts)\n\n  -- - Possibly add highlighting for blockwise mode\n  if add_highlight and extmark_hl_group == nil then\n    -- Highlighting blockwise region needs full register type with width\n    local opts = { regtype = H.exchange_get_blockwise_regtype(markcoords_from, markcoords_to) }\n    H.highlight_range(buf_id, ns_id, 'MiniOperatorsExchangeFrom', extmark_from, extmark_to, opts)\n  end\n\n  -- Return data to cache\n  return { buf_id = buf_id, mode = mode, submode = submode, extmark_id = region_extmark_id }\nend\n\nH.exchange_get_region_extmark = function(step)\n  return vim.api.nvim_buf_get_extmark_by_id(step.buf_id, H.ns_id.exchange, step.extmark_id, { details = true })\nend\n\nH.exchange_set_step_marks = function(step, mark_names)\n  local extmark_details = H.exchange_get_region_extmark(step)\n\n  H.set_mark(mark_names[1], { extmark_details[1] + 1, extmark_details[2] })\n\n  -- Unadjust for visual selection in case of 'selection=exclusive'\n  local should_unadjust = step.mode == 'visual' and vim.o.selection == 'exclusive'\n  local col_offset = should_unadjust and 1 or 0\n\n  H.set_mark(mark_names[2], { extmark_details[3].end_row + 1, extmark_details[3].end_col - 1 + col_offset })\nend\n\nH.exchange_get_blockwise_regtype = function(markcoords_from, markcoords_to)\n  local f = function()\n    -- Yank into \"z\" register and return its blockwise type\n    H.set_mark('x', markcoords_from)\n    H.set_mark('y', markcoords_to)\n    local yank_data = { mark_from = 'x', mark_to = 'y', submode = H.submode_keys.block, mode = 'block', register = 't' }\n    H.do_between_marks('y', yank_data)\n\n    return vim.fn.getregtype('t')\n  end\n\n  return H.with_temp_context({ buf_id = 0, marks = { 'x', 'y' }, registers = { 't' } }, f)\nend\n\nH.exchange_stop = function()\n  H.exchange_del_stop_mapping()\n\n  local cur, ns_id = H.cache.exchange, H.ns_id.exchange\n  if cur.step_one ~= nil then pcall(vim.api.nvim_buf_clear_namespace, cur.step_one.buf_id, ns_id, 0, -1) end\n  if cur.step_two ~= nil then pcall(vim.api.nvim_buf_clear_namespace, cur.step_two.buf_id, ns_id, 0, -1) end\n  H.cache.exchange = {}\nend\n\nH.exchange_set_stop_mapping = function()\n  local lhs = '<C-c>'\n  H.cache.exchange.stop_restore_map_data = vim.fn.maparg(lhs, 'n', false, true)\n  vim.keymap.set('n', lhs, H.exchange_stop, { desc = 'Stop exchange' })\nend\n\nH.exchange_del_stop_mapping = function()\n  local map_data = H.cache.exchange.stop_restore_map_data\n  if map_data == nil then return end\n\n  -- Try restore previous mapping if it was set\n  if vim.tbl_count(map_data) > 0 then\n    vim.fn.mapset('n', false, map_data)\n  else\n    vim.keymap.del('n', map_data.lhs or '<C-c>')\n  end\nend\n\nH.exchange_is_same_steps = function(step_one, step_two)\n  if step_one.buf_id ~= step_two.buf_id or step_one.submode ~= step_two.submode then return false end\n  -- Region's start and end should be the same\n  local one, two = H.exchange_get_region_extmark(step_one), H.exchange_get_region_extmark(step_two)\n  return one[1] == two[1] and one[2] == two[2] and one[3].end_row == two[3].end_row and one[3].end_col == two[3].end_col\nend\n\n-- Multiply -------------------------------------------------------------------\nH.multiply_get_ref_coords = function(mark_from, mark_to, submode)\n  local markcoords_from, markcoords_to = H.get_mark(mark_from), H.get_mark(mark_to)\n  if mark_to == '>' and vim.o.selection == 'exclusive' then markcoords_to[2] = markcoords_to[2] - 1 end\n\n  if submode ~= H.submode_keys.block then return markcoords_to end\n\n  -- In blockwise selection go to top right corner (allowing for presence of\n  -- multibyte characters)\n  local row = math.min(markcoords_from[1], markcoords_to[1])\n\n  -- - \"from\"/\"to\" may not only be \"top-left\"/\"bottom-right\" but also\n  --   \"top-right\" and \"bottom-left\"\n  local virtcol_from = vim.fn.virtcol({ markcoords_from[1], markcoords_from[2] + 1 })\n  local virtcol_to = vim.fn.virtcol({ markcoords_to[1], markcoords_to[2] + 1 })\n  local virtcol = math.max(virtcol_from, virtcol_to)\n\n  local col = vim.fn.virtcol2col(0, row, virtcol)\n\n  return { row, col - 1 }\nend\n\n-- Replace --------------------------------------------------------------------\n--- Delete region between two marks and paste from register\n---\n---@param data table Fields:\n---   - <count> (optional) - Number of times to paste.\n---   - <mark_from> - Name of \"from\" mark.\n---   - <mark_to> - Name of \"to\" mark.\n---   - <mode> - Operator mode. One of 'visual', 'char', 'line', 'block'.\n---   - <register> - Name of register from which to paste.\n---   - <submode> - Region submode. One of 'v', 'V', '\\22'.\n---@private\nH.replace_do = function(data)\n  -- NOTE: Ideally, implementation would leverage \"Visually select - press `P`\"\n  -- approach, but it has issues with dot-repeat. The `cancel_redo()` approach\n  -- doesn't work probably because `P` implementation uses more than one\n  -- dot-repeat overwrite.\n  local register, submode = data.register, data.submode\n  local mark_from, mark_to = data.mark_from, data.mark_to\n\n  -- Do nothing with invalid register (don't allow A-Z because they are used to\n  -- append to lowercase register and have no use here)\n  local reg_is_invalid = string.find(register, '^[0-9a-z\"%-:.%%#=*+_/]$') == nil\n  if reg_is_invalid then H.error('Register ' .. vim.inspect(register) .. ' is invalid.') end\n\n  -- Get reginfo and infer missing data (can be empty for special registers)\n  local reg_info = vim.fn.getreginfo(register)\n  if reg_info.regcontents == nil then H.error('Register ' .. vim.inspect(register) .. ' is empty.') end\n  reg_info.regtype = reg_info.regtype or 'v'\n\n  -- Determine if region is at edge which is needed for the correct paste key\n  local from_line, from_col = unpack(H.get_mark(mark_from))\n  local to_line, to_col = unpack(H.get_mark(mark_to))\n  local edge_to_col = vim.fn.col({ to_line, '$' }) - 1 - (vim.o.selection == 'exclusive' and 0 or 1)\n\n  local is_edge_line = submode == 'V' and to_line == vim.fn.line('$')\n  local is_edge_col = submode ~= 'V' and to_col == edge_to_col and vim.o.virtualedit ~= 'all'\n  local is_edge = is_edge_line or is_edge_col\n\n  local covers_linewise_all_buffer = is_edge_line and from_line == 1\n\n  -- Compute current indent if needed\n  local init_indent\n  local should_reindent = data.reindent_linewise and data.submode == 'V' and vim.o.equalprg == ''\n  if should_reindent then init_indent = H.get_region_indent(mark_from, mark_to) end\n\n  -- Delete region to black whole register\n  -- - Delete single character in blockwise submode with inclusive motion.\n  --   See https://github.com/neovim/neovim/issues/24613\n  local is_blockwise_single_cell = submode == H.submode_keys.block and from_line == to_line and from_col == to_col\n  local forced_motion = is_blockwise_single_cell and 'v' or submode\n\n  local delete_data =\n    { mark_from = mark_from, mark_to = mark_to, submode = forced_motion, mode = data.mode, register = '_' }\n  H.do_between_marks('d', delete_data)\n\n  -- Set temporary register data to have proper submode and indent\n  -- NOTE: use dedicated temporary register to workaround not being able to\n  -- write register data into readonly registers ('%', '#', '.').\n  local tmp_register, tmp_reg_info = register == '=' and '=' or 'x', vim.deepcopy(reg_info)\n  if tmp_reg_info.regtype:sub(1, 1) ~= submode then tmp_reg_info.regtype = submode end\n  if should_reindent then tmp_reg_info.regcontents = H.update_indent(tmp_reg_info.regcontents, init_indent) end\n\n  local cache_reg_info = vim.fn.getreginfo(tmp_register)\n  vim.fn.setreg(tmp_register, tmp_reg_info)\n\n  -- Paste\n  local expr_reg_keys = tmp_register == '=' and (reg_info.regcontents[1] .. '\\r') or ''\n  local paste_keys = (data.count or 1) .. '\"' .. tmp_register .. expr_reg_keys .. (is_edge and 'p' or 'P')\n  H.cmd_normal(paste_keys)\n\n  -- Restore temporary register data\n  vim.fn.setreg(tmp_register, cache_reg_info)\n\n  -- Adjust cursor to be at start mark\n  vim.api.nvim_win_set_cursor(0, { from_line, from_col })\n\n  -- Adjust for extra empty line after pasting inside empty buffer\n  if covers_linewise_all_buffer then vim.api.nvim_buf_set_lines(0, 0, 1, true, {}) end\nend\n\n-- Sort -----------------------------------------------------------------------\nH.sort_charwise_split = function(lines, split_patterns)\n  local lines_str = table.concat(lines, '\\n')\n\n  local pat\n  for _, pattern in ipairs(split_patterns) do\n    if lines_str:find(pattern) ~= nil then\n      pat = pattern\n      break\n    end\n  end\n\n  if pat == nil then return lines, {} end\n\n  -- Allow pattern to be an empty string to get every character\n  if pat == '' then\n    local parts = vim.split(lines_str, '')\n    local seps = vim.fn['repeat']({ '' }, #parts - 1)\n    return parts, seps\n  end\n\n  -- Split into parts and separators\n  local parts, seps = {}, {}\n  local init, n = 1, lines_str:len()\n  while init < n do\n    local sep_from, sep_to = string.find(lines_str, pat, init)\n    if sep_from == nil then break end\n    table.insert(parts, lines_str:sub(init, sep_from - 1))\n    table.insert(seps, lines_str:sub(sep_from, sep_to))\n    init = sep_to + 1\n  end\n  table.insert(parts, lines_str:sub(init, n))\n\n  return parts, seps\nend\n\nH.sort_charwise_unsplit = function(parts, seps)\n  local all = {}\n  for i = 1, #parts do\n    table.insert(all, parts[i])\n    table.insert(all, seps[i] or '')\n  end\n\n  return vim.split(table.concat(all, ''), '\\n')\nend\n\n-- General --------------------------------------------------------------------\nH.apply_content_func = function(content_func, data)\n  if data == nil then return end\n  local mark_from, mark_to, submode = data.mark_from, data.mark_to, data.submode\n  local reindent_linewise = data.reindent_linewise\n\n  H.with_temp_context({ marks = { '>' }, registers = { 'x', '\"' } }, function()\n    -- Yank effective region content into \"x\" register.\n    data.register = 'x'\n    H.do_between_marks('y', data)\n\n    -- Apply content function to register content\n    local reg_info = vim.fn.getreginfo('x')\n    local content_init = { lines = reg_info.regcontents, submode = submode }\n    reg_info.regcontents = content_func(content_init)\n    vim.fn.setreg('x', reg_info)\n\n    -- Replace region with new register content\n    local replace_data = {\n      count = 1,\n      mark_from = mark_from,\n      mark_to = mark_to,\n      mode = data.mode,\n      register = 'x',\n      reindent_linewise = reindent_linewise,\n      submode = submode,\n    }\n    H.replace_do(replace_data)\n  end)\nend\n\nH.do_between_marks = function(operator, data)\n  -- Force 'inclusive' selection as `<C-v>` submode does not force it (while\n  -- `v` does). This means that in case of 'selection=exclusive' marks should\n  -- be adjusted prior to this.\n  local cache_selection = vim.o.selection\n  if data.mode == 'block' and vim.o.selection == 'exclusive' then vim.o.selection = 'inclusive' end\n\n  -- Allow positioning cursor past line end to work for regions with newline\n  local cache_virtualedit = vim.o.virtualedit\n  vim.o.virtualedit = 'onemore'\n\n  -- Don't trigger `TextYankPost` event as these yanks are not user-facing\n  local is_yank = operator == 'y'\n  local cache_eventignore = vim.o.eventignore\n  if is_yank then vim.o.eventignore = 'TextYankPost' end\n\n  -- Make sure that marks `[` and `]` don't change after `y`\n  local context_marks = { '<', '>' }\n  if is_yank then context_marks = vim.list_extend(context_marks, { '[', ']' }) end\n  H.with_temp_context({ marks = context_marks }, function()\n    local mark_from, mark_to, submode, register = data.mark_from, data.mark_to, data.submode, data.register\n    local keys\n    if data.mode == 'visual' and vim.o.selection == 'exclusive' then\n      keys = ('`' .. mark_from) .. submode .. ('`' .. mark_to) .. ('\"' .. register .. operator)\n    else\n      keys = ('`' .. mark_from) .. ('\"' .. register .. operator .. submode) .. ('`' .. mark_to)\n    end\n\n    -- Make sure that outer action is dot-repeatable by cancelling effect of\n    -- `d` or dot-repeatable `y`\n    local cancel_redo = operator == 'd' or (operator == 'y' and vim.o.cpoptions:find('y') ~= nil)\n    H.cmd_normal(keys, { cancel_redo = cancel_redo })\n  end)\n\n  vim.o.selection = cache_selection\n  vim.o.virtualedit = cache_virtualedit\n  if is_yank then vim.o.eventignore = cache_eventignore end\nend\n\nH.is_content = function(x) return type(x) == 'table' and H.islist(x.lines) and type(x.submode) == 'string' end\n\n-- Marks ----------------------------------------------------------------------\nH.get_region_data = function(mode)\n  local submode = H.get_submode(mode)\n  local selection_is_visual = mode == 'visual'\n\n  -- Make sure that visual selection marks are relevant\n  if selection_is_visual and H.is_visual_mode() then vim.cmd('normal! \\27') end\n\n  local mark_from = selection_is_visual and '<' or '['\n  local mark_to = selection_is_visual and '>' or ']'\n\n  -- Detect empty region. NOTE: This doesn't work when cursor is on first line\n  -- and first column, but there doesn't seem to be a better way to do that.\n  local pos_from, pos_to = H.get_mark(mark_from), H.get_mark(mark_to)\n  if pos_to[1] < pos_from[1] or (pos_to[1] == pos_from[1] and pos_to[2] < pos_from[2]) then return end\n\n  return { mode = mode, submode = submode, mark_from = mark_from, mark_to = mark_to }\nend\n\nH.get_region_indent = function(mark_from, mark_to)\n  local l_from, l_to = H.get_mark(mark_from)[1], H.get_mark(mark_to)[1]\n  local lines = vim.api.nvim_buf_get_lines(0, l_from - 1, l_to, true)\n  return H.compute_indent(lines)\nend\n\nH.get_mark = function(mark_name) return vim.api.nvim_buf_get_mark(0, mark_name) end\n\nH.set_mark = function(mark_name, mark_data) vim.api.nvim_buf_set_mark(0, mark_name, mark_data[1], mark_data[2], {}) end\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.str_byteindex = function(s, i) return vim.str_byteindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_byteindex = function(s, i) return vim.str_byteindex(s, i) end end\n\nH.get_next_char_bytecol = function(markcoords)\n  local line = vim.fn.getline(markcoords[1])\n  local utf_index = H.str_utfindex(line, math.min(line:len(), markcoords[2] + 1))\n  return H.str_byteindex(line, utf_index)\nend\n\n-- Indent ---------------------------------------------------------------------\nH.compute_indent = function(lines)\n  local res_indent, res_indent_width = nil, math.huge\n  local blank_indent, blank_indent_width = nil, math.huge\n  for _, l in ipairs(lines) do\n    local cur_indent = l:match('^%s*')\n    local cur_indent_width = cur_indent:len()\n    local is_blank = cur_indent_width == l:len()\n    if not is_blank and cur_indent_width < res_indent_width then\n      res_indent, res_indent_width = cur_indent, cur_indent_width\n    elseif is_blank and cur_indent_width < blank_indent_width then\n      blank_indent, blank_indent_width = cur_indent, cur_indent_width\n    end\n  end\n\n  return res_indent or blank_indent or ''\nend\n\nH.update_indent = function(lines, new_indent)\n  -- Replace current indent with new indent without affecting blank lines\n  local n_cur_indent = H.compute_indent(lines):len()\n  return vim.tbl_map(function(l)\n    if l:find('^%s*$') ~= nil then return l end\n    return new_indent .. l:sub(n_cur_indent + 1)\n  end, lines)\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.operators) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.get_submode = function(mode)\n  if mode == 'visual' then return H.is_visual_mode() and vim.fn.mode() or vim.fn.visualmode() end\n  return H.submode_keys[mode]\nend\n\nH.is_visual_mode = function()\n  local cur_mode = vim.fn.mode()\n  return cur_mode == 'v' or cur_mode == 'V' or cur_mode == H.submode_keys.block\nend\n\nH.with_temp_context = function(context, f)\n  local res\n  vim.api.nvim_buf_call(context.buf_id or 0, function()\n    -- Cache temporary data\n    local marks_data = {}\n    for _, mark_name in ipairs(context.marks or {}) do\n      marks_data[mark_name] = H.get_mark(mark_name)\n    end\n\n    local reg_data = {}\n    for _, reg_name in ipairs(context.registers or {}) do\n      reg_data[reg_name] = vim.fn.getreginfo(reg_name)\n    end\n\n    -- Perform action\n    res = f()\n\n    -- Restore data\n    for mark_name, data in pairs(marks_data) do\n      pcall(H.set_mark, mark_name, data)\n    end\n    for reg_name, data in pairs(reg_data) do\n      pcall(vim.fn.setreg, reg_name, data)\n    end\n  end)\n\n  return res\nend\n\n-- A hack to restore previous dot-repeat action\nH.cancel_redo = function() end\n(function()\n  local has_ffi, ffi = pcall(require, 'ffi')\n  if not has_ffi then return end\n  local has_cancel_redo = pcall(ffi.cdef, 'void CancelRedo(void)')\n  if not has_cancel_redo then return end\n  H.cancel_redo = function() pcall(ffi.C.CancelRedo) end\nend)()\n\nH.cmd_normal = function(command, opts)\n  opts = opts or {}\n  local cancel_redo = opts.cancel_redo\n  if cancel_redo == nil then cancel_redo = true end\n\n  vim.cmd('silent keepjumps normal! ' .. command)\n\n  if cancel_redo then H.cancel_redo() end\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\n-- TODO: Remove after compatibility with Neovim=0.10 is dropped\nH.highlight_range = function(...) vim.hl.range(...) end\nif vim.fn.has('nvim-0.11') == 0 then H.highlight_range = function(...) vim.highlight.range(...) end end\n\nreturn MiniOperators\n"
  },
  {
    "path": "lua/mini/pairs.lua",
    "content": "--- *mini.pairs* Autopairs\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Functionality to work with two \"paired\" characters conditional on cursor's\n---   neighborhood (character to its left and character to its right).\n---\n--- - Usage should be through making appropriate mappings using |MiniPairs.map()|\n---   or in |MiniPairs.setup()| (for global mapping), |MiniPairs.map_buf()| (for\n---   buffer mapping).\n---\n--- - Pairs get automatically registered for special <BS> (all configured modes)\n---   and <CR> (only Insert mode) mappings. Pressing the key inside pair will\n---   delete whole pair and insert extra blank line inside pair respectively.\n---   Note: these mappings are autocreated if they do not override existing ones.\n---\n--- What it doesn't do:\n--- - Provide smart behavior, like based on bracket balance. The default behavior\n---   is to almost always perform an action (insert pair, jump over). Manually\n---   press |i_CTRL-V| before a character to explicitly insert it (and only it).\n---\n--- - It doesn't support multiple characters as \"open\" and \"close\" symbols. Use\n---   snippets for that.\n---\n--- - It doesn't support dependency on filetype. Use |i_CTRL-V| to insert\n---   single symbol or `autocmd` command or 'after/ftplugin' approach to:\n---     - `:lua MiniPairs.map_buf(0, 'i', <*>, <pair_info>)` - make new mapping\n---       for '<*>' in current buffer.\n---     - `:lua MiniPairs.unmap_buf(0, 'i', <*>, <pair>)` - unmap key `<*>` while\n---       unregistering `<pair>` pair in current buffer. Note: this reverts\n---       mapping done by |MiniPairs.map_buf()|. If mapping was done with\n---       |MiniPairs.map()|, unmap for buffer in usual Neovim manner:\n---       `inoremap <buffer> <*> <*>` (this maps `<*>` key to do the same it\n---       does by default).\n---     - Disable module for buffer (see 'Disabling' section).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.pairs').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniPairs` which you can use for scripting or manually (with\n--- `:lua MiniPairs.*`).\n---\n--- See |MiniPairs.config| for `config` structure and default values.\n---\n--- This module doesn't have runtime options, so using `vim.b.minipairs_config`\n--- will have no effect here.\n---\n--- # Example mappings ~\n--- >lua\n---   -- Register quotes inside `config` of `MiniPairs.setup()`\n---   mappings = {\n---     ['\"'] = { register = { cr = true } },\n---     [\"'\"] = { register = { cr = true } },\n---   }\n---\n---   -- Insert `<>` pair if `<` is typed at line start, don't register for <CR>\n---   local lt_opts = {\n---     action = 'open',\n---     pair = '<>',\n---     neigh_pattern = '\\r.',\n---     register = { cr = false },\n---   }\n---   MiniPairs.map('i', '<', lt_opts)\n---\n---   local gt_opts = { action = 'close', pair = '<>', register = { cr = false } }\n---   MiniPairs.map('i', '>', gt_opts)\n---\n---   -- Create symmetrical `$$` pair only in Tex files\n---   local map_tex = function()\n---     MiniPairs.map_buf(0, 'i', '$', { action = 'closeopen', pair = '$$' })\n---   end\n---   vim.api.nvim_create_autocmd(\n---     'FileType',\n---     { pattern = 'tex', callback = map_tex }\n---   )\n--- <\n--- # Notes ~\n---\n--- - Make sure to make proper mapping of <CR> in order to support completion\n---   plugin of your choice:\n---     - For |mini.completion| see 'Helpful key mappings' section.\n---     - For current implementation of \"hrsh7th/nvim-cmp\" there is no need to\n---       make custom mapping. You can use default setup, which will confirm\n---       completion selection if popup is visible and expand pair otherwise.\n--- - Having mapping in terminal mode can conflict with:\n---     - Autopairing capabilities of interpretators (`ipython`, `radian`).\n---     - Vim mode of terminal itself.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minipairs_disable` (globally) or `vim.b.minipairs_disable`\n--- (for a buffer) to `true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniPairs\n\n---@alias __pairs_neigh_pattern string|nil Pattern for two neighborhood characters.\n---   Character \"\\r\" indicates line start, \"\\n\" - line end.\n---@alias __pairs_pair string String with two characters representing pair.\n---@alias __pairs_unregistered_pair string Pair which should be unregistered from both <BS> and <CR>.\n---   Should be explicitly supplied to avoid confusion.\n---   Supply `''` to not unregister pair.\n\n-- Module definition ==========================================================\nlocal MiniPairs = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniPairs.config|.\n---\n---@usage >lua\n---   require('mini.pairs').setup() -- use default config\n---   -- OR\n---   require('mini.pairs').setup({}) -- replace {} with your config table\n--- <\nMiniPairs.setup = function(config)\n  -- Export module\n  _G.MiniPairs = MiniPairs\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniPairs.config = {\n  -- In which modes mappings from this `config` should be created\n  modes = { insert = true, command = false, terminal = false },\n\n  -- Global mappings. Each right hand side should be a pair information, a\n  -- table with at least these fields (see more in |MiniPairs.map()|):\n  -- - <action> - one of \"open\", \"close\", \"closeopen\".\n  -- - <pair> - two character string for pair to be used.\n  -- By default pair is not inserted after `\\`, quotes are not recognized by\n  -- <CR>, `'` does not insert the pair after a letter.\n  -- Only parts of tables can be tweaked (others will use these defaults).\n  -- Supply `false` instead of table to not map particular key.\n  mappings = {\n    ['('] = { action = 'open', pair = '()', neigh_pattern = '^[^\\\\]' },\n    ['['] = { action = 'open', pair = '[]', neigh_pattern = '^[^\\\\]' },\n    ['{'] = { action = 'open', pair = '{}', neigh_pattern = '^[^\\\\]' },\n\n    [')'] = { action = 'close', pair = '()', neigh_pattern = '^[^\\\\]' },\n    [']'] = { action = 'close', pair = '[]', neigh_pattern = '^[^\\\\]' },\n    ['}'] = { action = 'close', pair = '{}', neigh_pattern = '^[^\\\\]' },\n\n    ['\"'] = { action = 'closeopen', pair = '\"\"', neigh_pattern = '^[^\\\\]',   register = { cr = false } },\n    [\"'\"] = { action = 'closeopen', pair = \"''\", neigh_pattern = '^[^%a\\\\]', register = { cr = false } },\n    ['`'] = { action = 'closeopen', pair = '``', neigh_pattern = '^[^\\\\]',   register = { cr = false } },\n  },\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Make global mapping\n---\n--- This is a wrapper for |nvim_set_keymap()| but instead of right hand side of\n--- mapping (as string) it expects table with pair information.\n---\n--- Using this function instead of |nvim_set_keymap()| allows automatic\n--- registration of pairs which will be recognized by <BS> and <CR>.\n--- It also infers mapping description from `pair_info`.\n---\n---@param mode string `mode` for |nvim_set_keymap()|.\n---@param lhs string `lhs` for |nvim_set_keymap()|.\n---@param pair_info table Table with pair information. Fields:\n---   - <action> - one of \"open\" for |MiniPairs.open()|,\n---     \"close\" for |MiniPairs.close()|, or \"closeopen\" for |MiniPairs.closeopen()|.\n---   - <pair> - two character string to be passed to an action function.\n---     Can contain multibyte characters.\n---   - <neigh_pattern> - optional neighborhood pattern to be passed to an action\n---     function. Will be matched against two character neighborhood (might\n---     contain multibyte characters).\n---     Default: `'..'` (no restriction from neighborhood).\n---   - <register> - optional table with information about whether this pair will\n---     be recognized by <BS> (in |MiniPairs.bs()|) and/or <CR> (in |MiniPairs.cr()|).\n---     Should have boolean fields <bs> and <cr> (both `true` by default).\n---@param opts table|nil Optional table `opts` for |nvim_set_keymap()|. Elements\n---   `expr` and `noremap` won't be recognized (`true` by default).\nMiniPairs.map = function(mode, lhs, pair_info, opts)\n  pair_info = H.validate_pair_info(pair_info)\n  opts = vim.tbl_deep_extend('force', opts or {}, { expr = true, noremap = true })\n  opts.desc = H.infer_mapping_description(pair_info)\n\n  vim.api.nvim_set_keymap(mode, lhs, H.pair_info_to_map_rhs(pair_info), opts)\n  H.register_pair(pair_info, mode, 'all')\n\n  -- Ensure that <BS> and <CR> are mapped for input mode\n  H.ensure_cr_bs(mode)\nend\n\n--- Make buffer mapping\n---\n--- This is a wrapper for |nvim_buf_set_keymap()| but instead of string right\n--- hand side of mapping it expects table with pair information similar to one\n--- in |MiniPairs.map()|.\n---\n--- Using this function instead of |nvim_buf_set_keymap()| allows automatic\n--- registration of pairs which will be recognized by <BS> and <CR>.\n--- It also infers mapping description from `pair_info`.\n---\n---@param buffer number `buffer` for |nvim_buf_set_keymap()|.\n---@param mode string `mode` for |nvim_buf_set_keymap()|.\n---@param lhs string `lhs` for |nvim_buf_set_keymap()|.\n---@param pair_info table Table with pair information.\n---@param opts table|nil Optional table `opts` for |nvim_buf_set_keymap()|.\n---   Elements `expr` and `noremap` won't be recognized (`true` by default).\nMiniPairs.map_buf = function(buffer, mode, lhs, pair_info, opts)\n  pair_info = H.validate_pair_info(pair_info)\n  opts = vim.tbl_deep_extend('force', opts or {}, { expr = true, noremap = true })\n  opts.desc = H.infer_mapping_description(pair_info)\n\n  vim.api.nvim_buf_set_keymap(buffer, mode, lhs, H.pair_info_to_map_rhs(pair_info), opts)\n  H.register_pair(pair_info, mode, buffer == 0 and vim.api.nvim_get_current_buf() or buffer)\n\n  -- Ensure that <BS> and <CR> are mapped for input mode\n  H.ensure_cr_bs(mode)\nend\n\n--- Remove global mapping\n---\n--- A wrapper for |nvim_del_keymap()| which registers supplied `pair`.\n---\n---@param mode string `mode` for |nvim_del_keymap()|.\n---@param lhs string `lhs` for |nvim_del_keymap()|.\n---@param pair __pairs_unregistered_pair\nMiniPairs.unmap = function(mode, lhs, pair)\n  -- `pair` should be supplied explicitly\n  H.check_type('pair', pair, 'string')\n\n  -- Use `pcall` to allow 'deleting' already deleted mapping\n  pcall(vim.api.nvim_del_keymap, mode, lhs)\n  if pair == '' then return end\n  H.unregister_pair(pair, mode, 'all')\nend\n\n--- Remove buffer mapping\n---\n--- Wrapper for |nvim_buf_del_keymap()| which also unregisters supplied `pair`.\n---\n--- Note: this only reverts mapping done by |MiniPairs.map_buf()|. If mapping was\n--- done with |MiniPairs.map()|, revert to default behavior for buffer: >lua\n---\n---   -- Map `X` key to do the same it does by default\n---   vim.keymap.set('i', 'X', 'X', { buffer = true })\n--- <\n---@param buffer number `buffer` for |nvim_buf_del_keymap()|.\n---@param mode string `mode` for |nvim_buf_del_keymap()|.\n---@param lhs string `lhs` for |nvim_buf_del_keymap()|.\n---@param pair __pairs_unregistered_pair\nMiniPairs.unmap_buf = function(buffer, mode, lhs, pair)\n  -- `pair` should be supplied explicitly\n  H.check_type('pair', pair, 'string')\n\n  -- Use `pcall` to allow 'deleting' already deleted mapping\n  pcall(vim.api.nvim_buf_del_keymap, buffer, mode, lhs)\n  if pair == '' then return end\n  H.unregister_pair(pair, mode, buffer == 0 and vim.api.nvim_get_current_buf() or buffer)\nend\n\n--- Process \"open\" symbols\n---\n--- Used as |:map-<expr>| mapping for \"open\" symbols in asymmetric pair ('(', '[',\n--- etc.). If neighborhood doesn't match supplied pattern, function results\n--- into \"open\" symbol. Otherwise, it pastes whole pair and moves inside pair\n--- with |<Left>|.\n---\n--- Used inside |MiniPairs.map()| and |MiniPairs.map_buf()| for an actual mapping.\n---\n---@param pair __pairs_pair\n---@param neigh_pattern __pairs_neigh_pattern\n---\n---@return string Keys performing \"open\" action.\nMiniPairs.open = function(pair, neigh_pattern)\n  if H.is_disabled() or not H.neigh_match(neigh_pattern) then return H.get_open_char(pair) end\n\n  -- Temporarily redraw lazily for no cursor flicker due to `<Left>`.\n  -- This can happen in a big file with tree-sitter highlighting enabled.\n  H.with_temp_option('lazyredraw', true)\n\n  -- NOTE: Do not ensure no wildmenu because by the time arrow is executed\n  -- wildmenu should already (usually) be hidden due to inserting `pair`\n  return pair .. H.get_arrow_key('left')\nend\n\n--- Process \"close\" symbols\n---\n--- Used as |:map-<expr>| mapping for \"close\" symbols in asymmetric pair (')',\n--- ']', etc.). If neighborhood doesn't match supplied pattern, function\n--- results into \"close\" symbol. Otherwise it jumps over symbol to the right of\n--- cursor (with |<Right>|) if it is equal to \"close\" one and inserts it\n--- otherwise.\n---\n--- Used inside |MiniPairs.map()| and |MiniPairs.map_buf()| for an actual mapping.\n---\n---@param pair __pairs_pair\n---@param neigh_pattern __pairs_neigh_pattern\n---\n---@return string Keys performing \"close\" action.\nMiniPairs.close = function(pair, neigh_pattern)\n  local close = H.get_close_char(pair)\n  local move_right = not H.is_disabled() and H.neigh_match(neigh_pattern) and H.get_neigh('right') == close\n  return move_right and H.get_arrow_key('right', true) or close\nend\n\n--- Process \"closeopen\" symbols\n---\n--- Used as |:map-<expr>| mapping for 'symmetrical' symbols (like \" and ')\n--- It tries to perform 'closeopen action': move over right character\n--- (with |<Right>|) if it is equal to second character from pair or\n--- conditionally paste pair otherwise (with |MiniPairs.open()|).\n---\n--- Used inside |MiniPairs.map()| and |MiniPairs.map_buf()| for an actual mapping.\n---\n---@param pair __pairs_pair\n---@param neigh_pattern __pairs_neigh_pattern\n---\n---@return string Keys performing \"closeopen\" action.\nMiniPairs.closeopen = function(pair, neigh_pattern)\n  local move_right = not H.is_disabled() and H.get_neigh('right') == H.get_close_char(pair)\n  return move_right and H.get_arrow_key('right', true) or MiniPairs.open(pair, neigh_pattern)\nend\n\n--- Process |<BS>|\n---\n--- Used as |:map-<expr>| mapping for <BS> in Insert mode. It removes whole pair\n--- (via executing <Del> after input key) if neighborhood is equal to a whole\n--- pair recognized for current buffer. Pair is recognized for current buffer\n--- if it is registered for global or current buffer mapping. Pair is\n--- registered as a result of calling |MiniPairs.map()| or |MiniPairs.map_buf()|.\n---\n--- Mapped by default inside |MiniPairs.setup()|.\n---\n--- This can be used to modify other Insert mode keys to respect neighborhood\n--- pair. Examples: >lua\n---\n---   local map_bs = function(lhs, rhs)\n---     vim.keymap.set('i', lhs, rhs, { expr = true, replace_keycodes = false })\n---   end\n---\n---   map_bs('<C-h>', 'v:lua.MiniPairs.bs()')\n---   map_bs('<C-w>', 'v:lua.MiniPairs.bs(\"\\23\")')\n---   map_bs('<C-u>', 'v:lua.MiniPairs.bs(\"\\21\")')\n--- <\n---@param key string|nil Key to use. Default: `'<BS>'`.\n---\n---@return string Keys performing \"backspace\" action.\nMiniPairs.bs = function(key)\n  local res, neigh = key or H.keys.bs, H.get_neigh('whole')\n  local do_extra = not H.is_disabled() and H.is_pair_registered(neigh, vim.fn.mode(), 'bs')\n  return do_extra and (res .. H.keys.del) or res\nend\n\n--- Process |i_<CR>|\n---\n--- Used as |:map-<expr>| mapping for <CR> in insert mode. It puts \"close\"\n--- symbol on next line (via `<CR><C-o>O`) if neighborhood is equal to a whole\n--- pair recognized for current buffer. Pair is recognized for current buffer\n--- if it is registered for global or current buffer mapping. Pair is\n--- registered as a result of calling |MiniPairs.map()| or |MiniPairs.map_buf()|.\n---\n--- Note: some relevant mode changing events are temporarily ignored\n--- (with |'eventignore'|) to counter effect of using |i_CTRL-O|.\n---\n--- Mapped by default inside |MiniPairs.setup()|.\n---\n---@param key string|nil Key to use. Default: `'<CR>'`.\n---\n---@return string Keys performing \"new line\" action.\nMiniPairs.cr = function(key)\n  local res = key or H.keys.cr\n\n  local neigh = H.get_neigh('whole')\n  if H.is_disabled() or not H.is_pair_registered(neigh, vim.fn.mode(), 'cr') then return res end\n\n  -- Temporarily ignore mode change to not trigger some common expensive\n  -- autocommands (like diagnostic check, etc.)\n  H.with_temp_option('eventignore', 'InsertLeave,InsertLeavePre,InsertEnter,TextChanged,ModeChanged')\n\n  -- Temporarily redraw lazily for no cursor flicker due to `<C-o>O`.\n  -- This can happen in a big file with tree-sitter highlighting enabled.\n  H.with_temp_option('lazyredraw', true)\n\n  return res .. H.keys.above\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniPairs.config)\n\n-- Default value of `pair_info` for mapping functions\nH.default_pair_info = { neigh_pattern = '..', register = { bs = true, cr = true } }\n\n-- Pair sets registered *per mode-buffer-key*. Buffer `'all'` contains pairs\n-- registered for all buffers.\nH.registered_pairs = {\n  i = { all = { bs = {}, cr = {} } },\n  c = { all = { bs = {}, cr = {} } },\n  t = { all = { bs = {}, cr = {} } },\n}\n\n-- Precomputed keys to increase speed\n-- stylua: ignore start\nlocal function escape(s) return vim.api.nvim_replace_termcodes(s, true, true, true) end\nH.keys = {\n  above      = escape('<C-o>O'),\n  bs         = escape('<BS>'),\n  cr         = escape('<CR>'),\n  del        = escape('<Del>'),\n  ctrl_y     = escape('<C-y>'),\n  -- Using left/right keys in insert mode breaks undo sequence and, more\n  -- importantly, dot-repeat. To avoid this, use 'i_CTRL-G_U' mapping.\n  -- Use `H.get_arrow_key()` for keys instead of direct from this table.\n  left       = escape('<Left>'),\n  right      = escape('<Right>'),\n  left_undo  = escape('<C-g>U<Left>'),\n  right_undo = escape('<C-g>U<Right>'),\n}\n-- stylua: ignore end\n\n-- Cache for temporary set options\nH.options_cache = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('modes', config.modes, 'table')\n  H.check_type('modes.insert', config.modes.insert, 'boolean')\n  H.check_type('modes.command', config.modes.command, 'boolean')\n  H.check_type('modes.terminal', config.modes.terminal, 'boolean')\n\n  H.check_type('mappings', config.mappings, 'table')\n\n  local validate_mapping = function(pair_info, prefix)\n    -- Allow `false` to not create mapping\n    if pair_info == false then return end\n    H.validate_pair_info(pair_info, prefix)\n  end\n\n  validate_mapping(config.mappings['('], \"mappings['(']\")\n  validate_mapping(config.mappings['['], \"mappings['[']\")\n  validate_mapping(config.mappings['{'], \"mappings['{']\")\n  validate_mapping(config.mappings[')'], \"mappings[')']\")\n  validate_mapping(config.mappings[']'], \"mappings[']']\")\n  validate_mapping(config.mappings['}'], \"mappings['}']\")\n  validate_mapping(config.mappings['\"'], \"mappings['\\\"']\")\n  validate_mapping(config.mappings[\"'\"], 'mappings[\"\\'\"]')\n  validate_mapping(config.mappings['`'], \"mappings['`']\")\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniPairs.config = config\n\n  -- Setup mappings in supplied modes\n  local mode_ids = { insert = 'i', command = 'c', terminal = 't' }\n  -- Compute in which modes mapping should be set up\n  local mode_array = {}\n  for name, to_set in pairs(config.modes) do\n    if to_set then table.insert(mode_array, mode_ids[name]) end\n  end\n\n  local map_conditionally = function(mode, key, pair_info)\n    -- Allow `false` to not create mapping\n    if pair_info == false then return end\n\n    -- This also should take care of mapping <BS> and <CR>\n    MiniPairs.map(mode, key, pair_info)\n  end\n\n  for _, mode in pairs(mode_array) do\n    for key, pair_info in pairs(config.mappings) do\n      map_conditionally(mode, key, pair_info)\n    end\n  end\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniPairs', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('FileType', { 'TelescopePrompt', 'fzf' }, function() vim.b.minipairs_disable = true end, 'Disable locally')\nend\n\nH.is_disabled = function() return vim.g.minipairs_disable == true or vim.b.minipairs_disable == true end\n\n-- Pair registration ----------------------------------------------------------\nH.register_pair = function(pair_info, mode, buffer)\n  -- Process new mode\n  H.registered_pairs[mode] = H.registered_pairs[mode] or { all = { bs = {}, cr = {} } }\n  local mode_pairs = H.registered_pairs[mode]\n\n  -- Process new buffer\n  local buf_pairs = mode_pairs[buffer] or { bs = {}, cr = {} }\n  mode_pairs[buffer] = buf_pairs\n\n  -- Register pair in a buffer or 'all'. NOTE: ensure to add entry only if\n  -- `register[key]` is `true` for a faster check in `is_pair_registered`.\n  local register, pair = pair_info.register, pair_info.pair\n  buf_pairs.bs[pair] = register.bs == true and true or nil\n  buf_pairs.cr[pair] = register.cr == true and true or nil\nend\n\nH.unregister_pair = function(pair, mode, buffer)\n  local mode_pairs = H.registered_pairs[mode]\n  if not (mode_pairs and mode_pairs[buffer]) then return end\n\n  local buf_pairs = mode_pairs[buffer]\n  buf_pairs.bs[pair], buf_pairs.cr[pair] = nil, nil\nend\n\nH.is_pair_registered = function(pair, mode, key)\n  local mode_pairs = H.registered_pairs[mode]\n  if not mode_pairs then return false end\n\n  if mode_pairs['all'][key][pair] then return true end\n\n  local buf_pairs = mode_pairs[vim.api.nvim_get_current_buf()]\n  if not buf_pairs then return false end\n\n  return buf_pairs[key][pair] == true\nend\n\nH.ensure_cr_bs = function(mode)\n  local has_any_cr_pair, has_any_bs_pair = false, false\n  for _, pair_tbl in pairs(H.registered_pairs[mode]) do\n    has_any_cr_pair = has_any_cr_pair or not vim.tbl_isempty(pair_tbl.cr)\n    has_any_bs_pair = has_any_bs_pair or not vim.tbl_isempty(pair_tbl.bs)\n  end\n\n  -- NOTE: this doesn't distinguish between global and buffer mappings. Both\n  -- <BS> and <CR> should work as normal even if no pairs are registered\n  -- NOTE: do not autocreate mappings if there is already one present. This\n  -- allows creating more complicated `<CR>`/`<BS>` mappings and not worry\n  -- about the initialization/setup order.\n  if has_any_bs_pair and vim.fn.maparg('<BS>', mode) == '' then\n    -- Use not `silent` in Command mode to make it redraw\n    local opts = { silent = mode ~= 'c', expr = true, replace_keycodes = false, desc = 'MiniPairs <BS>' }\n    H.map(mode, '<BS>', 'v:lua.MiniPairs.bs()', opts)\n  end\n  if mode == 'i' and has_any_cr_pair and vim.fn.maparg('<CR>', mode) == '' then\n    local opts = { expr = true, replace_keycodes = false, desc = 'MiniPairs <CR>' }\n    H.map(mode, '<CR>', 'v:lua.MiniPairs.cr()', opts)\n  end\nend\n\n-- Work with pair_info --------------------------------------------------------\nH.validate_pair_info = function(x, prefix)\n  prefix = prefix or 'pair_info'\n  H.check_type(prefix, x, 'table')\n  x = vim.tbl_deep_extend('force', H.default_pair_info, x)\n\n  H.check_type(prefix .. '.action', x.action, 'string')\n  H.check_type(prefix .. '.pair', x.pair, 'string')\n  H.check_type(prefix .. '.neigh_pattern', x.neigh_pattern, 'string')\n  H.check_type(prefix .. '.register', x.register, 'table')\n\n  H.check_type(prefix .. '.register.bs', x.register.bs, 'boolean')\n  H.check_type(prefix .. '.register.cr', x.register.cr, 'boolean')\n\n  return x\nend\n\nH.pair_info_to_map_rhs = function(x)\n  return string.format('v:lua.MiniPairs.%s(%s, %s)', x.action, vim.inspect(x.pair), vim.inspect(x.neigh_pattern))\nend\n\nH.infer_mapping_description = function(x)\n  local action_name = x.action:sub(1, 1):upper() .. x.action:sub(2)\n  return string.format('%s action for %s pair', action_name, vim.inspect(x.pair))\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.pairs) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.get_neigh = function(neigh_type)\n  local is_command_mode = vim.fn.mode() == 'c'\n  -- Get line and add '\\r' and '\\n' to always return 2 characters\n  local line = is_command_mode and vim.fn.getcmdline() or vim.api.nvim_get_current_line()\n  line = '\\r' .. line .. '\\n'\n  -- Get start character index accounting for added '\\r' at the start\n  local start = is_command_mode and vim.fn.charidx(line, vim.fn.getcmdpos()) or vim.fn.charcol('.')\n  start = start - 1\n\n  return vim.fn.strcharpart(line, start + (neigh_type == 'right' and 1 or 0), neigh_type == 'whole' and 2 or 1)\nend\n\nH.neigh_match = function(pattern) return H.get_neigh('whole'):find(pattern or '') ~= nil end\n\nH.get_open_char = function(x) return vim.fn.strcharpart(x, 0, 1) end\nH.get_close_char = function(x) return vim.fn.strcharpart(x, 1, 1) end\n\nH.get_arrow_key = function(key, ensure_no_wildmenu)\n  if vim.fn.mode() == 'i' then\n    -- Take into account that `virtualedit=all` can go into inline virtual text\n    H.with_temp_option('virtualedit', 'none')\n    return key == 'right' and H.keys.right_undo or H.keys.left_undo\n  end\n  local prefix = ''\n  -- In Command-line mode <Left> / <Right> act like <C-p> / <C-n> if wildmenu\n  -- is shown. Make sure that arrow key moves cursor.\n  if vim.fn.mode() == 'c' and ensure_no_wildmenu then prefix = vim.fn.wildmenumode() == 1 and H.keys.ctrl_y or '' end\n  return prefix .. (key == 'right' and H.keys.right or H.keys.left)\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.with_temp_option = function(name, value)\n  -- Cache option only once to not override it later with temporary set value\n  -- Like in case of `nvim_feedkeys('(\\r(\\r')`\n  if H.options_cache[name] == nil then H.options_cache[name] = vim.o[name] end\n  vim.o[name] = value\n  H.restore_option_later(name)\nend\n\nH.restore_option_later = vim.schedule_wrap(function(name)\n  if H.options_cache[name] == nil then return end\n  vim.o[name] = H.options_cache[name]\n  H.options_cache[name] = nil\nend)\n\nreturn MiniPairs\n"
  },
  {
    "path": "lua/mini/pick.lua",
    "content": "--- *mini.pick* Pick anything\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Single window general purpose interface for picking element from any array.\n---\n--- - On demand toggleable preview and info views.\n---\n--- - Interactive query matching (filter+sort) with fast non-blocking default\n---   which does fuzzy matching and allows other modes (|MiniPick.default_match()|).\n---\n--- - Built-in pickers (see |MiniPick.builtin|):\n---     - Files.\n---     - Pattern match (for fixed pattern or with live feedback; both allow\n---       file filtering via glob patterns).\n---     - Buffers.\n---     - Help tags.\n---     - CLI output.\n---     - Resume latest picker.\n---\n--- - |:Pick| command to work with extensible |MiniPick.registry|.\n---\n--- - |vim.ui.select()| implementation. To adjust, use |MiniPick.ui_select()|\n---   or save-restore `vim.ui.select` manually after calling |MiniPick.setup()|.\n---\n--- - Rich and customizable built-in |MiniPick-actions| when picker is active:\n---     - Manually change currently focused item.\n---     - Scroll vertically and horizontally.\n---     - Toggle preview or info view.\n---     - Mark/unmark items to choose later.\n---     - Refine current matches (make them part of a new picker).\n---     - And many more.\n---\n--- - Minimal yet flexible |MiniPick-source| specification with:\n---     - Items (array, callable, or manually set later).\n---     - Source name.\n---     - Working directory.\n---     - Matching algorithm.\n---     - Way matches are shown in main window.\n---     - Item preview.\n---     - \"On choice\" action for current and marked items.\n---\n--- - Custom actions/keys can be configured globally, per buffer, or per picker.\n---\n--- - Out of the box support for 'ignorecase' and 'smartcase'.\n---\n--- - Match caching to increase responsiveness on repeated prompts.\n---\n--- Notes:\n--- - Works on all supported versions but Neovim>=0.10 will give more visual\n---   feedback in floating window footer.\n---\n--- - For more pickers see |MiniExtra.pickers|.\n---\n--- Sources with more details:\n--- - |MiniPick-overview|\n--- - |MiniPick-source|\n--- - |MiniPick-actions|\n--- - |MiniPick-examples|\n--- - |MiniPick.builtin|\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies (provide extra functionality, will work without them):\n---\n--- - Enabled |mini.icons| module to show icons near the items for actual paths.\n---   Falls back to 'nvim-tree/nvim-web-devicons' plugin or no icons will be used.\n---\n--- - *MiniPick-cli-tools* CLI tool(s) to power |MiniPick.builtin.files()|,\n---   |MiniPick.builtin.grep()|, and |MiniPick.builtin.grep_live()| built-in pickers:\n---     - `rg` (github.com/BurntSushi/ripgrep; enough for all three; recommended).\n---     - `fd` (github.com/sharkdp/fd; for `files` only).\n---     - `git` (github.com/git/git; enough for all three).\n---\n---   Note: CLI tools are called only with basic arguments needed to get items.\n---   To customize the output, use their respective configuration approaches.\n---   Here are some examples of where to start:\n---     - github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#configuration-file\n---     - github.com/sharkdp/fd#excluding-specific-files-or-directories\n---     - git-scm.com/docs/gitignore\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.pick').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniPick`\n--- which you can use for scripting or manually (with `:lua MiniPick.*`).\n---\n--- See |MiniPick.config| for available config settings.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minipick_config` which should have same structure as `MiniPick.config`.\n--- See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim):\n---     - The main inspiration for this module, so there is significant overlap.\n---     - Has three (or two) window UI (prompt, matches, preview), while this\n---       module combines everything in one window. It allows more straightforward\n---       customization for unusual scenarios.\n---     - Default match algorithm is somewhat slow, while this module should\n---       match relatively lag-free for at least 100K+ items.\n---     - Has many built-in pickers, while this module has handful at its core\n---       relying on other 'mini.nvim' modules to provide more (see |mini.extra|).\n---\n--- - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua):\n---     - Mostly same comparison as with 'nvim-telescope/telescope.nvim'.\n---     - Requires [junegunn/fzf](https://github.com/junegunn/fzf) installed to\n---       power fuzzy matching, while this module provides built-in Lua matching.\n---\n--- # Highlight groups ~\n---\n--- - `MiniPickBorder` - window border.\n--- - `MiniPickBorderBusy` - window border while picker is busy processing.\n--- - `MiniPickBorderText` - non-prompt on border.\n--- - `MiniPickCursor` - cursor during active picker (hidden by default).\n--- - `MiniPickIconDirectory` - default icon for directory.\n--- - `MiniPickIconFile` - default icon for file.\n--- - `MiniPickHeader` - headers in info buffer and previews.\n--- - `MiniPickMatchCurrent` - current matched item.\n--- - `MiniPickMatchMarked` - marked matched items.\n--- - `MiniPickMatchRanges` - ranges matching query elements.\n--- - `MiniPickNormal` - basic foreground/background highlighting.\n--- - `MiniPickPreviewLine` - target line in preview.\n--- - `MiniPickPreviewRegion` - target region in preview.\n--- - `MiniPickPrompt` - prompt.\n--- - `MiniPickPromptCaret` - caret in prompt.\n--- - `MiniPickPromptPrefix` - prefix of the prompt.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---@tag MiniPick\n\n--- To allow user customization and integration of external tools, certain |User|\n--- autocommand events are triggered under common circumstances:\n---\n--- - `MiniPickMatch` - just after updating query matches or setting items.\n--- - `MiniPickStart` - just after picker has started.\n--- - `MiniPickStop` - just before picker is stopped.\n---@tag MiniPick-events\n\n--- General idea is to take array of objects, display them with interactive\n--- filter/sort/navigate/preview, and allow to choose one or more items.\n---\n--- # How to start a picker ~\n---\n--- - Use |MiniPick.start()| with `opts.source` defining |MiniPick-source|.\n---   Example: `MiniPick.start({ source = { items = vim.fn.readdir('.') } })`\n---\n--- - Use any of |MiniPick.builtin| pickers directly.\n---   Example: `MiniPick.builtin.files({ tool = 'git' })`\n---\n--- - Use |:Pick| command which uses customizable pickers from |MiniPick.registry|.\n---   Example: `:Pick files tool='git'`\n---\n--- # User interface ~\n---\n--- UI consists from a single window capable of displaying three different views:\n--- - \"Main\" - where current query matches are shown.\n--- - \"Preview\" - preview of current item (toggle with `<Tab>`).\n--- - \"Info\" - general info about picker and its state (toggle with `<S-Tab>`).\n---\n--- Current prompt is displayed at the top left of the window border with vertical\n--- line indicating caret (current input position).\n---\n--- Bottom part of window border displays (in Neovim>=0.10) extra visual feedback:\n--- - Left part is a picker name.\n--- - Right part contains information in the format >\n---\n---   <current index in matches> | <match count> | <marked count> / <total count>\n--- <\n--- When picker is busy (like if there are no items yet set or matching is active)\n--- window border changes color to be `MiniPickBorderBusy` after `config.delay.busy`\n--- milliseconds of idle time.\n---\n--- # Life cycle ~\n---\n--- - Type characters to filter and sort matches. It uses |MiniPick.default_match()|\n---   with `query` being an array of pressed characters.\n---   Overview of how it matches:\n---     - If query starts with `'`, the match is exact.\n---     - If query starts with `^`, the match is exact at start.\n---     - If query ends with `$`, the match is exact at end.\n---     - If query starts with `*`, the match is forced to be fuzzy.\n---     - Otherwise match is fuzzy.\n---     - Sorting is done to first minimize match width and then match start.\n---       Nothing more: no favoring certain places in string, etc.\n---\n--- - Type special keys to perform |MiniPick-actions|. Here are some basic ones:\n---     - `<C-n>` / `<Down>` moves down; `<C-p>` / `<Up>` moves up.\n---     - `<Left>` / `<Right>` moves prompt caret left / right.\n---     - `<S-Tab>` toggles information window with all available mappings.\n---     - `<Tab>` toggles preview.\n---     - `<C-x>` / `<C-a>` toggles current / all item(s) as (un)marked.\n---     - `<C-Space>` / `<M-Space>` makes all matches or marked items as new picker.\n---     - `<CR>` / `<M-CR>` chooses current/marked item(s).\n---     - `<Esc>` / `<C-c>` stops picker.\n---\n--- # Implementation details ~\n---\n--- - Processing key typing is done via a dedicated key query process for more\n---   control over their side effects. As a result, regular mappings don't work\n---   here and picker's window needs to be current as long as it is shown.\n---   Changing window focus leads to automatic picker stop (after small delay).\n---   Not picker related screen changes require explicit |:redraw|.\n--- - Any picker is non-blocking but waits to return the chosen item. Example:\n---   `file = MiniPick.builtin.files()` allows other actions to be executed when\n---   picker is shown while still assigning `file` with value of the chosen item.\n---@tag MiniPick-overview\n\n--- Source is defined as a `source` field inside one of (in increasing priority):\n--- - |MiniPick.config| - has global effect.\n--- - `vim.b.minipick_config` - has buffer-local effect.\n--- - `opts.source` in picker call - has effect for that particular call.\n---\n--- Example of source to choose from |arglist|: >lua\n---\n---   { items = vim.fn.argv, name = 'Arglist' }\n--- <\n--- Note: this is mostly useful for writing pickers. Can safely skip if you\n--- want to just use provided pickers.\n---\n--- # Items ~\n--- *MiniPick-source.items*\n---\n--- `source.items` defines items to choose from. It should be one of the following:\n--- - Array of objects which can have different types. Any type is allowed.\n--- - `nil`. Picker waits for explicit |MiniPick.set_picker_items()| call.\n--- - Callable returning any of the previous types. Will be called once on start\n---   with source's `cwd` set as |current-directory|.\n---\n--- *MiniPick-source.items-stritems*\n--- Matching is done for items array based on the string representation of its\n--- elements (here called \"stritems\"). For single item it is computed as follows:\n--- - Callable is called once with output used in next steps.\n--- - String item is used as is.\n--- - String <text> field of table item is used (if present).\n--- - Use output of |vim.inspect()|.\n---\n--- Example: >lua\n---\n---   items = { 'aaa.txt', { text = 'bbb' }, function() return 'ccc' end }\n---   -- corresponding stritems are { 'aaa.txt', 'bbb', 'ccc' }\n--- <\n--- Default value is `nil`, assuming it always be supplied by the caller.\n---\n--- *MiniPick-source.items-common*\n--- There are some recommendations for common item types in order for them to work\n--- out of the box with |MiniPick.default_show()|, |MiniPick.default_preview()|,\n--- |MiniPick.default_choose()|, |MiniPick.default_choose_marked()|:\n---\n--- - Path (file or directory). Use string or `path` field of a table. Path can\n---   be either absolute, relative to the `source.cwd`, or have a general URI format\n---   (only if supplied as table field).\n---   Examples: `'aaa.txt'`, `{ path = 'aaa.txt' }`\n---\n--- - Buffer. Use buffer id as number, string, or `bufnr` / `buf_id` / `buf`\n---   field of a table (any name is allowed).\n---   Examples: `1`, `'1'`, `{ bufnr = 1 }`, `{ buf_id = 1 }`, `{ buf = 1 }`\n---\n--- - Line in file or buffer. Use table representation with `lnum` field with line\n---   number (starting from 1) or string in \"<path>\\0<line>\" format (`\\0` is\n---   an actual null character; don't escape the slash; may need to be `\\000`).\n---   Examples: >lua\n---\n---     { path = 'aaa.txt', lnum = 2 }, 'aaa.txt\\0002', { bufnr = 1, lnum = 3 }\n--- <\n--- - Position in file or buffer. Use table representation with `lnum` and `col`\n---   fields with line and column numbers (starting from 1) or string in\n---   \"<path>\\0<line>\\0<col>\" format (`\\0` is an actual null character, don't\n---   escape the slash; may need to be `\\000`).\n---   Examples: >lua\n---\n---     { path = 'aaa.txt', lnum = 2, col = 3 }, 'aaa.txt\\0' .. '2\\0003',\n---     { bufnr = 1, lnum = 3, col = 4 }\n--- <\n--- - Region in file or buffer. Use table representation with `lnum`, `col`,\n---   `end_lnum`, `end_col` fields for start and end line/column. All numbers\n---   start from 1, end line is inclusive, end column is exclusive.\n---   This naming is similar to |getqflist()| and |diagnostic-structure|.\n---   Examples: >lua\n---\n---     { path = 'aaa.txt', lnum = 2, col = 3, end_lnum = 4, end_col = 5 },\n---     { bufnr = 1, lnum = 3, col = 4, end_lnum = 5, end_col = 6 }\n--- <\n--- Note: all table items will benefit from having `text` field for better matching.\n---\n--- # Name ~\n--- *MiniPick-source.name*\n---\n--- `source.name` defines the name of the picker to be used for visual feedback.\n---\n--- Default value is \"<No name>\".\n---\n--- # Current working directory ~\n--- *MiniPick-source.cwd*\n---\n--- `source.cwd` is a string defining the current working directory in which\n--- picker operates. It should point to a valid actually present directory path.\n--- This is a part of source to allow persistent way to use relative paths,\n--- i.e. not depend on current directory being constant after picker start.\n--- It also makes the |MiniPick.builtin.resume()| picker more robust.\n---\n--- It will be set as local |current-directory| (|:lcd|) of picker's main window\n--- to allow simpler code for \"in window\" functions (choose/preview/custom/etc.).\n---\n--- Default value is |current-directory|.\n---\n--- # Match ~\n--- *MiniPick-source.match*\n---\n--- `source.match` is a callable defining how stritems\n--- (see |MiniPick-source.items-stritems|) are matched (filtered and sorted) based\n--- on the query.\n---\n--- It will be called with the following arguments:\n--- - `stritems` - all available stritems for current picker.\n--- - `inds` - array of `stritems` indexes usually pointing at current matches.\n---   It does point to current matches in the case of interactively appending\n---   character at the end of the query. It assumes that matches for such bigger\n---   query is a subset of previous matches (implementation can ignore it).\n---   This can be utilized to increase performance by checking fewer stritems.\n--- - `query` - array of strings. Usually (like is common case of user interactively\n---   typing query) each string represents one character. However, any strings are\n---   allowed, as query can be set with |MiniPick.set_picker_query()|.\n---\n--- It should either return array of match indexes for stritems elements matching\n--- the query (synchronous) or explicitly use |MiniPick.set_picker_match_inds()|\n--- to set them (may be asynchronous).\n---\n--- Notes:\n--- - The result can be any array of `stritems` indexes, i.e. not necessarily\n---   a subset of input `inds`.\n---\n--- - Both `stritems` and `query` depend on values of 'ignorecase' and 'smartcase'.\n---   If query shows \"ignore case\" properties (only 'ignorecase' is set or both\n---   'ignorecase' / 'smartcase' are set and query has only lowercase characters),\n---   then `stritems` and `query` will have only lowercase characters.\n---   This allows automatic support for case insensitive matching while being\n---   faster and having simpler match function implementation.\n---\n--- - Writing custom `source.match` usually means also changing |MiniPick-source.show|\n---   because it is used to highlight stritems parts actually matching the query.\n---\n--- Example of simple \"exact\" `match()` preserving initial order: >lua\n---\n---   local match_exact = function(stritems, inds, query)\n---     local prompt_pattern = vim.pesc(table.concat(query))\n---     local f = function(i) return stritems[i]:find(prompt_pattern) ~= nil end\n---     return vim.tbl_filter(f, inds)\n---   end\n---   -- For non-blocking version see `:h MiniPick.poke_is_picker_active()`\n--- <\n--- Default value is |MiniPick.default_match()|.\n---\n--- # Show ~\n--- *MiniPick-source.show*\n---\n--- `source.show` is a callable defining how matched items are shown in the window.\n---\n--- It will be called with the following arguments:\n--- - `buf_id` - identifier of the target buffer.\n--- - `items_to_show` - array of actual items to be shown in `buf_id`. This is\n---   a subset of currently matched items computed to fit in current window view.\n--- - `query` - array of strings. Same as in `source.match`.\n---\n--- It should update buffer `buf_id` to visually represent `items_to_show`\n--- __one item per line starting from line one__ (it shouldn't depend on\n--- `options.content_from_bottom`). This also includes possible visualization\n--- of which parts of stritem actually matched query.\n---\n--- Example (assuming string items; without highlighting): >lua\n---\n---   local show_prepend = function(buf_id, items_arr, query)\n---     local lines = vim.tbl_map(function(x) return 'Item: ' .. x end, items_arr)\n---     vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n---   end\n--- <\n--- Default value is |MiniPick.default_show()|.\n---\n--- # Preview ~\n--- *MiniPick-source.preview*\n---\n--- `source.preview` is a callable defining how item preview is done.\n---\n--- It will be called with the following arguments:\n--- - `buf_id` - identifier of the target buffer. Note: for every separate instance\n---   of item previewing new scratch buffer is be created.\n--- - `item` - item to preview.\n---\n--- It should update buffer `buf_id` to visually represent `item`. It can also\n--- directly set another buffer in picker's main window, but usually it is more\n--- robust to update given `buf_id` directly.\n---\n--- Example: >lua\n---\n---   local preview_inspect = function(buf_id, item)\n---     local lines = vim.split(vim.inspect(item), '\\n')\n---     vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n---   end\n--- <\n--- Default value is |MiniPick.default_preview()|.\n---\n--- # Choose an item ~\n--- *MiniPick-source.choose*\n---\n--- `source.choose` is a callable defining what to do when an item is chosen.\n---\n--- It will be called with the following arguments:\n--- - `item` - chosen item. Always non-`nil`.\n---\n--- It should perform any intended \"choose\" action for an item and return\n--- a value indicating whether picker should continue (i.e. not stop):\n--- `nil` and `false` will stop picker, other values will continue.\n---\n--- Notes:\n--- - It is called when picker window is still current. Use `windows.target` value\n---   from |MiniPick.get_picker_state()| output to do something with target window.\n---\n--- Example: >lua\n---\n---   local choose_file_continue = function(item)\n---     if vim.fn.filereadable(item) == 0 then return end\n---     vim.api.nvim_win_call(\n---       MiniPick.get_picker_state().windows.target,\n---       function() vim.cmd('edit ' .. item) end\n---     )\n---     return true\n---   end\n--- <\n--- Default value is |MiniPick.default_choose()|.\n---\n--- # Choose marked items ~\n--- *MiniPick-source.choose_marked*\n---\n--- `source.choose_marked` is a callable defining what to do when marked items\n--- (see |MiniPick-actions-mark|) are chosen. Serves as a companion to\n--- `source.choose` which can choose several items.\n---\n--- It will be called with the following arguments:\n--- - `items_marked` - array of marked items. Can be empty.\n---\n--- It should perform any intended \"choose\" action for several items and return\n--- a value indicating whether picker should continue (i.e. not stop):\n--- `nil` and `false` will stop picker, other values will continue.\n---\n--- Notes:\n--- - It is called when picker window is still current. Use `windows.target` value\n---   from |MiniPick.get_picker_state()| output to do something with target window.\n---\n--- Example: >lua\n---\n---   local choose_marked_print = function(items) print(vim.inspect(items)) end\n--- <\n--- Default value is |MiniPick.default_choose_marked()|.\n---@tag MiniPick-source\n\n--- When picker is active, `mappings` table defines a set of special keys which when\n--- pressed will execute certain actions. Those can be of two types:\n--- - Built-in: actions present in default `config.mappings`. Can be only overridden\n---   with a different key.\n--- - Custom: user defined actions. Should be a table with `char` and `func` fields.\n---\n---\n--- # Built-in ~\n---\n--- ## Caret ~\n--- *MiniPick-actions-caret*\n---\n--- User can add character not only at query end, but more generally at caret.\n---\n--- - `mappings.caret_left` - move caret to left.\n--- - `mappings.caret_right` - move caret to right.\n---\n--- ## Choose ~\n--- *MiniPick-actions-choose*\n---\n--- Choose is a fundamental action that actually implements the intent of\n--- calling a picker, i.e. pick an item.\n---\n--- - `mappings.choose` - choose as is, i.e. apply `source.choose` for current item.\n--- - `mappings.choose_in_split` - make horizontal split at target window, update\n---   target window to the new split, and choose.\n--- - `mappings.choose_in_tabpage` - same as `choose_in_split`, but create tabpage.\n--- - `mappings.choose_in_vsplit` - same as `choose_in_split`, but split vertically.\n--- - `mappings.choose_marked` - choose marked items as is, i.e.\n---   apply `source.choose_marked` at current marked items.\n---\n--- ## Delete ~\n--- *MiniPick-actions-delete*\n---\n--- Delete actions are for deleting elements from query.\n---\n--- - `mappings.delete_char` - delete one character to the left.\n--- - `mappings.delete_char_right` - delete one character to the right.\n--- - `mappings.delete_left` - delete everything to the left (like |i_CTRL-U|).\n--- - `mappings.delete_word` - delete word to the left (like |i_CTRL-W|).\n---\n--- ## Mark ~\n--- *MiniPick-actions-mark*\n---\n--- Marking is an action of adding certain items to a separate list which then can\n--- be chosen with `mappings.choose_marked` (for example, sent to quickfix list).\n--- This is a companion to a regular choosing which can pick only one item.\n---\n--- - `mappings.mark` - toggle marked/unmarked state of current item.\n--- - `mappings.mark_all` - toggle marked/unmarked state (mark all if not all\n---   marked; unmark all otherwise) of all currently matched items.\n---\n--- Notes:\n--- - Marks persist across queries and matches. For example, user can make a query\n---   with marking all matches several times and marked items from all queries\n---   will be preserved.\n---\n--- ## Move ~\n--- *MiniPick-actions-move*\n---\n--- Move is a fundamental action of changing which item is current.\n---\n--- - `mappings.move_down` - change focus to the item below.\n--- - `mappings.move_start` change focus to the first currently matched item\n--- - `mappings.move_up` - change focus to the item above.\n---\n--- Notes:\n--- - Up and down wrap around edges: `move_down` on last item moves to first,\n---   `move_up` on first moves to last.\n--- - Moving when preview or info view is shown updates the view with new item.\n--- - These also work with non-overridable alternatives:\n---     - `<Down>` moves down.\n---     - `<Home>` moves to first matched.\n---     - `<Up>` moves up.\n---\n--- ## Paste ~\n--- *MiniPick-actions-paste*\n---\n--- Paste is an action to paste content of |registers| at caret.\n---\n--- - `mappings.paste` - paste from register defined by the next key press.\n---\n--- Notes:\n--- - Does not support expression register `=`.\n--- - Supports special cases of register: <C-f> (as |c_CTRL-R_CTRL-F|),\n---   <C-w> (as |c_CTRL-R_CTRL-W|), <C-a> (as |c_CTRL-R_CTRL-A|),\n---   <C-l> (as |c_CTRL-R_CTRL-L|).\n---\n--- ## Refine ~\n--- *MiniPick-actions-refine*\n---\n--- Refine is an action that primarily executes the following:\n--- - Takes certain items and makes them be all items (in order they are present).\n--- - Resets query.\n--- - Updates `source.match` to be the one from config.\n---\n--- - `mappings.refine` - refine currently matched items.\n--- - `mappings.refine_marked` - refine currently marked items.\n---\n--- This action is useful in at least two cases:\n--- - Perform consecutive \"narrowing\" queries. Example: to get items that contain\n---   both \"hello\" and \"world\" exact matches (in no particular order) with default\n---   matching, type \"'hello\" (notice \"'\" at the start) followed by `<C-Space>` and\n---   another \"'world\".\n--- - Reset `match` to default. Particularly useful in |MiniPick.builtin.grep_live()|\n---   and |MiniExtra.pickers.lsp()| with \"workspace_symbol_live\" scope.\n---\n--- ## Scroll ~\n--- *MiniPick-actions-scroll*\n---\n--- Scroll is an action to either move current item focus further than to the\n--- neighbor item or adjust window view to see more information.\n---\n--- - `mappings.scroll_down` - when matches are shown, go down by the amount of\n---   visible matches. In preview and info view - scroll down as with |CTRL-F|.\n--- - `mappings.scroll_left` - scroll left as with |zH|.\n--- - `mappings.scroll_right` - scroll right as with |zL|.\n--- - `mappings.scroll_up` - when matches are shown, go up by the amount of\n---   visible matches. In preview and info view - scroll up as with |CTRL-B|.\n---\n--- ## Stop ~\n--- *MiniPick-actions-stop*\n---\n--- `mappings.stop` stops the picker. <C-c> also always stops the picker.\n---\n---\n--- ## Toggle ~\n--- *MiniPick-actions-toggle*\n---\n--- Toggle action is a way to change view: show if target is not shown, reset to\n--- main view otherwise.\n---\n--- - `mappings.toggle_info` - toggle info view.\n--- - `mappings.toggle_preview` - toggle preview.\n---\n--- Note:\n--- - Updating query in any way resets window view to show matches.\n--- - Moving current item focus keeps preview or info view with updated item.\n---\n--- # Custom ~\n--- *MiniPick-actions-custom*\n---\n--- Along with built-in actions, users can define custom actions. This can be\n--- done by supplying custom elements to `mappings` table. The field defines action\n--- name (used to infer an action description in info view). The value is a table\n--- with the following fields:\n--- - <char> `(string)` - single character acting as action trigger.\n--- - <func> `(function)` - callable to be executed without arguments after\n---   user presses <char>. Its return value is treated as \"should stop picker\n---   after execution\", i.e. returning nothing, `nil`, or `false` continues\n---   picker while everything else (prefer `true`) stops it.\n---\n--- Example of `execute` custom mapping: >lua\n---\n---   execute = {\n---     char = '<C-e>',\n---     func = function() vim.cmd(vim.fn.input('Execute: ')) end,\n---   }\n--- <\n---@tag MiniPick-actions\n\n--- # Disable icons ~\n---\n--- Disable icons in |MiniPick.builtin| pickers related to paths: >lua\n---\n---   local pick = require('mini.pick')\n---   pick.setup({ source = { show = pick.default_show } })\n--- <\n--- # Switch toggle and move keys ~\n--- >lua\n---   require('mini.pick').setup({\n---     mappings = {\n---       toggle_info    = '<C-k>',\n---       toggle_preview = '<C-p>',\n---       move_down      = '<Tab>',\n---       move_up        = '<S-Tab>',\n---     }\n---   })\n--- <\n--- # Different window styles ~\n--- >lua\n---   -- Different border\n---   { window = { config = { border = 'double' } } }\n---\n---   -- \"Cursor tooltip\"\n---   {\n---     window = {\n---       config = {\n---         relative = 'cursor', anchor = 'NW',\n---         row = 0, col = 0, width = 40, height = 20,\n---       },\n---     },\n---   }\n---\n---   -- Centered on screen\n---   local win_config = function()\n---     local height = math.floor(0.618 * vim.o.lines)\n---     local width = math.floor(0.618 * vim.o.columns)\n---     return {\n---       anchor = 'NW', height = height, width = width,\n---       row = math.floor(0.5 * (vim.o.lines - height)),\n---       col = math.floor(0.5 * (vim.o.columns - width)),\n---     }\n---   end\n---   { window = { config = win_config } }\n--- <\n---@tag MiniPick-examples\n\n---@alias __pick_builtin_opts table|nil Options forwarded to |MiniPick.start()|.\n---@alias __pick_builtin_local_opts table|nil Options defining behavior of this particular picker.\n---@alias __pick_builtin_grep_globs <globs> `(table)` - array of string glob patterns to restrict search to\n---     matching files. Supported only by \"rg\" and \"git\" tools, respects their\n---     specific glob syntax and effects. Default: `{}` (no restriction).\n---     Example: `{ '*.lua', 'lua/**' }` for Lua files and files in \"lua\" directory.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n\n-- Module definition ==========================================================\nlocal MiniPick = {}\nlocal H = {}\n\n--- Module setup\n---\n--- # :Pick ~\n--- *:Pick*\n---\n--- Calling this function creates a `:Pick` user command. It takes picker name\n--- from |MiniPick.registry| as mandatory first argument and executes it with\n--- following (expanded, |expandcmd()|) |<f-args>| combined in a single table.\n--- To add custom pickers, update |MiniPick.registry|.\n---\n--- Example: >vim\n---\n---   :Pick files tool='git'\n---   :Pick grep pattern='<cword>'\n--- <\n---\n--- It also sets custom |vim.ui.select()| implementation to use the module.\n--- See |MiniPick.ui_select()|.\n---\n---@param config table|nil Module config table. See |MiniPick.config|.\n---\n---@usage >lua\n---   require('mini.pick').setup() -- use default config\n---   -- OR\n---   require('mini.pick').setup({}) -- replace {} with your config table\n--- <\nMiniPick.setup = function(config)\n  -- Export module\n  _G.MiniPick = MiniPick\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\n\n  -- Create user commands\n  H.create_user_commands()\n\n  -- Disable terminal emulator's pasting with active picker\n  local paste_orig = vim.paste\n  vim.paste = function(...)\n    if not MiniPick.is_picker_active() then return paste_orig(...) end\n    H.notify('Use `mappings.paste` (`<C-r>` by default) with \"*\" or \"+\" register.', 'HINT')\n  end\n\n  -- Set custom implementation\n  vim.ui.select = MiniPick.ui_select\nend\n\n--stylua: ignore\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Delays ~\n---\n--- `config.delay` defines plugin delays (in ms). All should be strictly positive.\n---\n--- `delay.async` is a delay between forcing asynchronous behavior. This usually\n--- means forcing |:redraw| in preview (several but limited number of times to\n--- ensure visible async highlighting) and using |MiniPick.poke_is_picker_active()|\n--- (for example, to stop current matching if query has updated).\n--- Smaller values give smoother user experience at the cost of more computations.\n---\n--- `delay.busy` is a delay between when some computation starts and showing\n--- visual feedback about it by making window border to have `MiniPickBorderBusy`\n--- highlight group.\n--- Smaller values will give feedback faster at the cost of feeling like flicker.\n---\n--- # Mappings ~\n---\n--- `config.mappings` defines keys for special actions to be triggered after certain\n--- keys. See |MiniPick-actions| for more information.\n---\n--- # Options ~\n---\n--- `config.options` contains some general purpose options.\n---\n--- `options.content_from_bottom` is a boolean indicating whether content should be\n--- shown from bottom to top. That means that best matches will be shown at\n--- the bottom. Note: for better experience use Neovim>=0.10, which has floating\n--- window footer capability. Default: `false`.\n---\n--- `options.use_cache` is a boolean indicating whether match results should be\n--- cached per prompt (i.e. concatenated query). This results into faster response\n--- on repeated prompts (like when deleting query entries) at the cost of using\n--- more memory. Default: `false`.\n---\n--- # Source ~\n---\n--- `config.source` defines fallbacks for source specification. For example, this\n--- can be used to change default `match` to use different implementation or `show`\n--- to not show icons for some |MiniPick.builtin| pickers (see |MiniPick-examples|).\n--- See |MiniPick-source| for more information.\n---\n--- # Window ~\n---\n--- `config.window` contains window specific configurations.\n---\n--- `window.config` defines a (parts of) default floating window config for the main\n--- picker window. This can be either a table overriding some parts or a callable\n--- returning such table. See |MiniPick-examples| for some examples.\n---\n--- `window.prompt_caret` defines how caret is displayed in window's prompt.\n--- Default: '▏'.\n---\n--- `window.prompt_prefix` defines what prefix is used in window's prompt.\n--- Default: '> '.\nMiniPick.config = {\n  -- Delays (in ms; should be at least 1)\n  delay = {\n    -- Delay between forcing asynchronous behavior\n    async = 10,\n\n    -- Delay between computation start and visual feedback about it\n    busy = 50,\n  },\n\n  -- Keys for performing actions. See `:h MiniPick-actions`.\n  mappings = {\n    caret_left  = '<Left>',\n    caret_right = '<Right>',\n\n    choose            = '<CR>',\n    choose_in_split   = '<C-s>',\n    choose_in_tabpage = '<C-t>',\n    choose_in_vsplit  = '<C-v>',\n    choose_marked     = '<M-CR>',\n\n    delete_char       = '<BS>',\n    delete_char_right = '<Del>',\n    delete_left       = '<C-u>',\n    delete_word       = '<C-w>',\n\n    mark     = '<C-x>',\n    mark_all = '<C-a>',\n\n    move_down  = '<C-n>',\n    move_start = '<C-g>',\n    move_up    = '<C-p>',\n\n    paste = '<C-r>',\n\n    refine        = '<C-Space>',\n    refine_marked = '<M-Space>',\n\n    scroll_down  = '<C-f>',\n    scroll_left  = '<C-h>',\n    scroll_right = '<C-l>',\n    scroll_up    = '<C-b>',\n\n    stop = '<Esc>',\n\n    toggle_info    = '<S-Tab>',\n    toggle_preview = '<Tab>',\n  },\n\n  -- General options\n  options = {\n    -- Whether to show content from bottom to top\n    content_from_bottom = false,\n\n    -- Whether to cache matches (more speed and memory on repeated prompts)\n    use_cache = false,\n  },\n\n  -- Source definition. See `:h MiniPick-source`.\n  source = {\n    items = nil,\n    name  = nil,\n    cwd   = nil,\n\n    match   = nil,\n    show    = nil,\n    preview = nil,\n\n    choose        = nil,\n    choose_marked = nil,\n  },\n\n  -- Window related options\n  window = {\n    -- Float window config (table or callable returning it)\n    config = nil,\n\n    -- String to use as caret in prompt\n    prompt_caret = '▏',\n\n    -- String to use as prefix in prompt\n    prompt_prefix = '> ',\n  },\n}\n--minidoc_afterlines_end\n\n--- Start picker\n---\n--- Notes:\n--- - If there is currently an active picker, it is properly stopped and new one\n---   is started \"soon\" in the main event-loop (see |vim.schedule()|).\n--- - Current window at the moment of this function call is treated as \"target\".\n---   It will be set back as current after |MiniPick.stop()|.\n---   See |MiniPick.get_picker_state()| and |MiniPick.set_picker_target_window()|.\n---\n---@param opts table|nil Options. Should have same structure as |MiniPick.config|.\n---   Default values are inferred from there.\n---   Usually should have proper |MiniPick-source.items| defined.\n---\n---@return any Item which was current when picker is stopped; `nil` if aborted.\nMiniPick.start = function(opts)\n  if MiniPick.is_picker_active() then\n    -- Try proper 'key query process' stop\n    MiniPick.stop()\n    -- NOTE: Needs `defer_fn()` for `stop()` to properly finish code flow and\n    -- not be executed before it\n    return vim.defer_fn(function()\n      -- NOTE: if `MiniPick.stop()` still didn't stop, force abort\n      if MiniPick.is_picker_active() then H.picker_stop(H.pickers.active, true) end\n      MiniPick.start(opts)\n    end, 0.5)\n  end\n\n  H.cache = {}\n  opts = H.validate_picker_opts(opts)\n  local picker = H.picker_new(opts)\n  H.pickers.active = picker\n\n  H.picker_set_busy(picker, true)\n  local items = H.expand_callable(opts.source.items)\n  -- - Set items on next event loop to not block when computing stritems\n  if H.islist(items) then vim.schedule(function() MiniPick.set_picker_items(items) end) end\n\n  H.picker_track_lost_focus(picker)\n  return H.picker_advance(picker)\nend\n\n--- Stop active picker\nMiniPick.stop = function()\n  if not MiniPick.is_picker_active() then return end\n  H.cache.is_force_stop_advance = true\n  if H.cache.is_in_getcharstr then vim.api.nvim_feedkeys('\\3', 't', true) end\nend\n\n--- Refresh active picker\nMiniPick.refresh = function()\n  if not MiniPick.is_picker_active() then return end\n  H.picker_update(H.pickers.active, false, true)\n  -- Needed for something like `VimResized` (as `getcharstr` blocks redraw)\n  H.ensure_redraw(H.pickers.active)\nend\n\n--- Default match\n---\n--- Filter target stritems to contain query and sort from best to worst matches.\n---\n--- Implements default value for |MiniPick-source.match|.\n---\n--- By default (if no special modes apply) it does the following fuzzy matching:\n---\n--- - Stritem contains query if it contains all its elements verbatim in the same\n---   order (possibly with gaps, i.e. not strictly one after another).\n---   Note: empty query and empty string element is contained in any string.\n---\n--- - Sorting is done with the following ordering (same as in |mini.fuzzy|):\n---     - The smaller the match width (end column minus start column) the better.\n---     - Among same match width, the smaller start column the better.\n---     - Among same match width and start column, preserve original order.\n---\n--- Notes:\n--- - Most common interactive usage results into `query` containing one typed\n---   character per element.\n---\n--- # Special modes ~\n---\n--- - Forced modes:\n---     - Query starts with \"*\": match the rest fuzzy (without other modes).\n---     - Query starts with \"'\": match the rest exactly (without gaps).\n---\n--- - Place modes:\n---     - Query starts with '^': match the rest exactly at start.\n---     - Query ends with '$': match the rest exactly at end.\n---     - Both modes can be used simultaneously.\n---\n--- - Grouped: query contains at least one whitespace element. Output is computed\n---   as if query is split at whitespace indexes with concatenation between them.\n---\n--- Precedence of modes:\n---   \"forced exact\" = \"forced fuzzy\" > \"place start/end\" > \"grouped\" > \"default\"\n---\n--- # Examples ~\n---\n--- Assuming `stritems` are `{ '_abc', 'a_bc', 'ab_c', 'abc_' }`, here are some\n--- example matches based on prompt (concatenated query): >\n---\n---   | Prompt | Matches                |\n---   |--------|------------------------|\n---   | abc    | All                    |\n---   | *abc   | All                    |\n---   |        |                        |\n---   | 'abc   | abc_, _abc             |\n---   | *'abc  | None (no \"'\" in items) |\n---   |        |                        |\n---   | ^abc   | abc_                   |\n---   | *^abc  | None (no \"^\" in items) |\n---   |        |                        |\n---   | abc$   | _abc                   |\n---   | *abc$  | None (no \"$\" in items) |\n---   |        |                        |\n---   | ab c   | abc_, _abc, ab_c       |\n---   | *ab c  | None (no \" \" in items) |\n--- <\n--- Having query `{ 'ab', 'c' }` is the same as \"ab c\" prompt.\n---\n--- You can have a feel of how this works with this command: >lua\n---\n---   MiniPick.start({ source = { items = { '_abc', 'a_bc', 'ab_c', 'abc_' } } })\n--- <\n---@param stritems table Array of all stritems.\n---@param inds table Array of `stritems` indexes to match. All of them should point\n---   at string elements of `stritems`. No check is done for performance reasons.\n---@param query table Array of strings.\n---@param opts table|nil Options. Possible fields:\n---   - <sync> `(boolean)` - Whether to match synchronously. Default: `false`.\n---   - <preserve_order> `(boolean)` - Whether to skip sort step. Default: `false`.\n---\n---@return table|nil Depending on whether computation is synchronous (either `opts.sync`\n---   is `true` or there is an active picker):\n---   - If yes, array of `stritems` indexes matching the `query` (from best to worst).\n---   - If no, `nil` is returned with |MiniPick.set_picker_match_inds()| used later.\nMiniPick.default_match = function(stritems, inds, query, opts)\n  opts = opts or {}\n  local is_sync = opts.sync or not MiniPick.is_picker_active()\n  local set_match_inds = is_sync and function(x) return x end or MiniPick.set_picker_match_inds\n  local f = function()\n    if #query == 0 then return set_match_inds(H.seq_along(stritems)) end\n    local match_data, match_type = H.match_filter(inds, stritems, query)\n    if match_data == nil then return end\n    if match_type == 'useall' then return set_match_inds(H.seq_along(stritems)) end\n    if opts.preserve_order then return set_match_inds(H.match_no_sort(match_data)) end\n    local match_inds = H.match_sort(match_data)\n    if match_inds == nil then return end\n    return set_match_inds(match_inds)\n  end\n\n  if is_sync then return f() end\n  coroutine.resume(coroutine.create(f))\nend\n\n--- Default show\n---\n--- Show items in a buffer and highlight parts that actually match query (assuming\n--- match is done with |MiniPick.default_match()|). Lines are computed based on\n--- the |MiniPick-source.items-stritems|.\n---\n--- Implements default value for |MiniPick-source.show|.\n---\n--- Uses the following highlight groups (see |mini.pick| for their description):\n---\n--- - `MiniPickIconDirectory`\n--- - `MiniPickIconFile`\n--- - `MiniPickMatchCurrent`\n--- - `MiniPickMatchMarked`\n--- - `MiniPickMatchRanges`\n---\n---@param buf_id number Identifier of target buffer.\n---@param items table Array of items to show.\n---@param query table Array of strings representing query.\n---@param opts table|nil Options. Possible fields:\n---   - <show_icons> `(boolean)` - whether to show icons for entries recognized as\n---     valid actually present paths on disk (see |MiniPick-source.items-common|),\n---     empty space otherwise. Tries to use `text` field as fallback for path.\n---     Default: `false`. Note: |MiniPick.builtin| pickers showing file/directory\n---     paths use `true` by default.\n---   - <icons> `(table)` - table with fallback icons used if icon provider\n---     does not itself supply default icons for category. Can have fields:\n---       - <directory> `(string)` - icon for directory. Default: \" \".\n---       - <file> `(string)` - icon for file. Default: \" \".\n---       - <none> `(string)` - icon for non-valid path. Default: \"  \".\nMiniPick.default_show = function(buf_id, items, query, opts)\n  local default_icons = { directory = ' ', file = ' ', none = '  ' }\n  opts = vim.tbl_deep_extend('force', { show_icons = false, icons = default_icons }, opts or {})\n\n  -- Compute and set lines. Compute prefix based on the whole items to allow\n  -- separate `text` and `path` table fields (preferring second one).\n  local get_prefix_data = opts.show_icons and function(item) return H.get_icon(item, opts.icons) end\n    or function() return { text = '' } end\n  local prefix_data = vim.tbl_map(get_prefix_data, items)\n\n  local lines = vim.tbl_map(H.item_to_string, items)\n  local tab_spaces = string.rep(' ', vim.o.tabstop)\n  lines = vim.tbl_map(function(l) return l:gsub('%z', '│'):gsub('[\\r\\n]', ' '):gsub('\\t', tab_spaces) end, lines)\n\n  local lines_to_show = {}\n  for i, l in ipairs(lines) do\n    lines_to_show[i] = prefix_data[i].text .. l\n  end\n\n  H.set_buflines(buf_id, lines_to_show)\n\n  -- Extract match ranges\n  local ns_id = H.ns_id.ranges\n  H.clear_namespace(buf_id, ns_id)\n\n  if H.query_is_ignorecase(query) then\n    lines, query = vim.tbl_map(H.tolower, lines), vim.tbl_map(H.tolower, query)\n  end\n  local match_data, match_type, query_adjusted = H.match_filter(H.seq_along(lines), lines, query)\n  if match_data == nil then return end\n\n  local match_ranges_fun = match_type == 'fuzzy' and H.match_ranges_fuzzy or H.match_ranges_exact\n  local match_ranges = match_ranges_fun(match_data, query_adjusted, lines)\n\n  -- Place range highlights accounting for possible shift due to prefixes\n  local extmark_opts = { hl_group = 'MiniPickMatchRanges', hl_mode = 'combine', priority = 200 }\n  for i = 1, #match_data do\n    local row, ranges = match_data[i][3], match_ranges[i]\n    local start_offset = prefix_data[row].text:len()\n    for _, range in ipairs(ranges) do\n      extmark_opts.end_row, extmark_opts.end_col = row - 1, start_offset + range[2]\n      H.set_extmark(buf_id, ns_id, row - 1, start_offset + range[1] - 1, extmark_opts)\n    end\n  end\n\n  -- Highlight prefixes\n  if not opts.show_icons then return end\n  local icon_extmark_opts = { hl_mode = 'combine', priority = 200 }\n  for i = 1, #prefix_data do\n    icon_extmark_opts.hl_group = prefix_data[i].hl\n    icon_extmark_opts.end_row, icon_extmark_opts.end_col = i - 1, prefix_data[i].text:len()\n    H.set_extmark(buf_id, ns_id, i - 1, 0, icon_extmark_opts)\n  end\nend\n\n--- Default preview\n---\n--- Preview item. Logic follows the rules in |MiniPick-source.items-common|:\n--- - File and buffer are shown at the start.\n--- - Directory has its content listed.\n--- - Line/position/region in file or buffer is shown at start.\n--- - Others are shown directly with |vim.inspect()|.\n---\n--- Implements default value for |MiniPick-source.preview|.\n---\n--- Uses the following highlight groups (see |mini.pick| for their description):\n---\n--- - `MiniPickPreviewLine`\n--- - `MiniPickPreviewRegion`\n---\n---@param buf_id number Identifier of target buffer.\n---@param item any Item to preview.\n---@param opts table|nil Options. Possible values:\n---   - <n_context_lines> `(number)` - number of lines to load past target position\n---     when reading from disk. Useful to explore context. Default: 'lines' twice.\n---   - <line_position> `(string)` - where in the window to show item position.\n---     One of \"top\", \"center\", \"bottom\". Default: \"top\".\nMiniPick.default_preview = function(buf_id, item, opts)\n  opts = vim.tbl_deep_extend('force', { n_context_lines = 2 * vim.o.lines, line_position = 'top' }, opts or {})\n  local item_data = H.parse_item(item)\n  if item_data.type == 'file' then return H.preview_file(buf_id, item_data, opts) end\n  if item_data.type == 'directory' then return H.preview_directory(buf_id, item_data) end\n  if item_data.type == 'buffer' then return H.preview_buffer(buf_id, item_data, opts) end\n  if item_data.type == 'uri' then return H.preview_uri(buf_id, item_data, opts) end\n  H.preview_inspect(buf_id, item)\nend\n\n--- Default choose\n---\n--- Choose item. Logic follows the rules in |MiniPick-source.items-common|:\n--- - File uses |bufadd()| and sets cursor at the start of line/position/region.\n--- - Buffer is set as current in target window and sets cursor similarly.\n--- - Directory is called with |:edit| in the target window.\n--- - Others have the output of |vim.inspect()| printed in Command line.\n---\n--- Implements default value for |MiniPick-source.choose|.\n---\n---@param item any Item to choose.\nMiniPick.default_choose = function(item)\n  if item == nil then return end\n  local picker_state = MiniPick.get_picker_state()\n  local win_target = picker_state ~= nil and picker_state.windows.target or vim.api.nvim_get_current_win()\n  if not H.is_valid_win(win_target) then win_target = H.get_first_valid_normal_window() end\n\n  local item_data = H.parse_item(item)\n  if item_data.type == 'file' or item_data.type == 'directory' or item_data.type == 'uri' then\n    return H.choose_path(win_target, item_data)\n  end\n  if item_data.type == 'buffer' then return H.choose_buffer(win_target, item_data) end\n  H.choose_print(item)\nend\n\n--- Default choose marked items\n---\n--- Choose marked items. Logic follows the rules in |MiniPick-source.items-common|:\n--- - If among items there is at least one file or buffer, quickfix list is opened\n---   with all file or buffer lines/positions/regions.\n--- - Otherwise, picker's `source.choose` is called on the first item.\n---\n--- Implements default value for |MiniPick-source.choose_marked|.\n---\n---@param items table Array of items to choose.\n---@param opts table|nil Options. Possible fields:\n---   - <list_type> `(string)` - which type of list to open. One of \"quickfix\"\n---     or \"location\". Default: \"quickfix\".\nMiniPick.default_choose_marked = function(items, opts)\n  if not H.islist(items) then H.error('`items` should be an array') end\n  if #items == 0 then return end\n  opts = vim.tbl_deep_extend('force', { list_type = 'quickfix' }, opts or {})\n\n  -- Construct a potential quickfix/location list\n  local list = {}\n  for _, item in ipairs(items) do\n    local item_data = H.parse_item(item)\n    if item_data.type == 'file' or item_data.type == 'buffer' or item_data.type == 'uri' then\n      local entry = { bufnr = item_data.buf_id, filename = H.parse_uri(item_data.path) or item_data.path }\n      entry.lnum, entry.col = item_data.lnum or 1, item_data.col or 1\n      entry.text = (item_data.text or ''):gsub('%z', '│')\n      entry.end_lnum, entry.end_col = item_data.end_lnum, item_data.end_col\n      table.insert(list, entry)\n    end\n  end\n\n  -- Fall back to choosing first item if no quickfix list was constructed\n  local is_active = MiniPick.is_picker_active()\n  if #list == 0 then\n    if not is_active then return end\n    local choose = MiniPick.get_picker_opts().source.choose\n    return choose(items[1])\n  end\n\n  -- Set as quickfix or location list\n  local title = '<No picker>'\n  if is_active then\n    ---@diagnostic disable:param-type-mismatch\n    local source_name, prompt = MiniPick.get_picker_opts().source.name, table.concat(MiniPick.get_picker_query())\n    title = source_name .. (prompt == '' and '' or (' : ' .. prompt))\n  end\n  local list_data = { items = list, title = title, nr = '$' }\n\n  if opts.list_type == 'location' then\n    local win_target = MiniPick.get_picker_state().windows.target\n    if not H.is_valid_win(win_target) then win_target = H.get_first_valid_normal_window() end\n    vim.fn.setloclist(win_target, {}, ' ', list_data)\n    vim.schedule(function() vim.cmd('lopen') end)\n  else\n    vim.fn.setqflist({}, ' ', list_data)\n    vim.schedule(function() vim.cmd('copen') end)\n  end\nend\n\n--- Select rewrite\n---\n--- Function which can be used to directly override |vim.ui.select()| to use\n--- 'mini.pick' for any \"select\" type of tasks.\n--- Set automatically in |MiniPick.setup()|.\n---\n--- Implements required by `vim.ui.select()` signature, with some differencies:\n--- - Allows `opts.preview_item` that returns an array of lines for item preview.\n--- - Allows fourth `start_opts` argument to customize |MiniPick.start()| call.\n---\n--- Notes:\n--- - `on_choice` is called when target window is current.\n---\n---@usage >lua\n---   -- Customize with fourth argument inside a function wrapper\n---   vim.ui.select = function(items, opts, on_choice)\n---     local start_opts = { window = { config = { width = vim.o.columns } } }\n---     return MiniPick.ui_select(items, opts, on_choice, start_opts)\n---   end\n--- <\n--- To preserve original `vim.ui.select()`: >lua\n---\n---   local ui_select_orig = vim.ui.select\n---   require('mini.pick').setup()\n---   vim.ui.select = ui_select_orig\n--- <\nMiniPick.ui_select = function(items, opts, on_choice, start_opts)\n  local format_item = opts.format_item or H.item_to_string\n  local items_ext = {}\n  for i = 1, #items do\n    table.insert(items_ext, { text = format_item(items[i]), item = items[i], index = i })\n  end\n\n  local preview_item = vim.is_callable(opts.preview_item) and opts.preview_item\n    or function(x) return vim.split(vim.inspect(x), '\\n') end\n  local preview = function(buf_id, item) H.set_buflines(buf_id, preview_item(item.item)) end\n\n  local was_aborted = true\n  local choose = function(item)\n    was_aborted = false\n    if item == nil then return end\n    local win_target = MiniPick.get_picker_state().windows.target\n    if not H.is_valid_win(win_target) then win_target = H.get_first_valid_normal_window() end\n    vim.api.nvim_win_call(win_target, function()\n      on_choice(items[item.index], item.index)\n      MiniPick.set_picker_target_window(vim.api.nvim_get_current_win())\n    end)\n  end\n\n  local source = { items = items_ext, name = opts.prompt or opts.kind, preview = preview, choose = choose }\n  start_opts = vim.tbl_deep_extend('force', start_opts or {}, { source = source })\n  local item = MiniPick.start(start_opts)\n  if item == nil and was_aborted then on_choice(nil) end\nend\n\n--- Table with built-in pickers\nMiniPick.builtin = {}\n\n--- Pick from files\n---\n--- Lists all files recursively in all subdirectories. Tries to use one of the\n--- CLI tools to create items (see |MiniPick-cli-tools|): `rg`, `fd`, `git`.\n--- If none is present, uses fallback which utilizes |vim.fs.dir()|.\n---\n--- To customize CLI tool search, either use tool's global configuration approach\n--- or directly |MiniPick.builtin.cli()| with specific command.\n---\n---@param local_opts __pick_builtin_local_opts\n---   Possible fields:\n---   - <tool> `(string)` - which tool to use. One of \"rg\", \"fd\", \"git\", \"fallback\".\n---     Default: whichever tool is present, trying in that same order.\n---@param opts __pick_builtin_opts\nMiniPick.builtin.files = function(local_opts, opts)\n  local_opts = vim.tbl_deep_extend('force', { tool = nil }, local_opts or {})\n  local tool = local_opts.tool or H.files_get_tool()\n  local show = H.get_config().source.show or H.show_with_icons\n  local default_opts = { source = { name = string.format('Files (%s)', tool), show = show } }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  if tool == 'fallback' then\n    local cwd = H.full_path(opts.source.cwd or vim.fn.getcwd())\n    opts.source.items = function() H.files_fallback_items(cwd) end\n    return MiniPick.start(opts)\n  end\n\n  return MiniPick.builtin.cli({ command = H.files_get_command(tool) }, opts)\nend\n\n--- Pick from pattern matches\n---\n--- Lists all pattern matches recursively in all subdirectories.\n--- Tries to use one of the CLI tools to create items (see |MiniPick-cli-tools|):\n--- `rg`, `git`. If none is present, uses fallback which utilizes |vim.fs.dir()| and\n--- Lua pattern matches (NOT recommended in large directories).\n---\n--- To customize CLI tool search, either use tool's global configuration approach\n--- or directly |MiniPick.builtin.cli()| with specific command.\n--- Options 'ignorecase' and 'smartcase' are respected via forcing appropriate\n--- flags to CLI tool (i.e. overriding tool's global config).\n---\n---@param local_opts __pick_builtin_local_opts\n---   Possible fields:\n---   - <tool> `(string)` - which tool to use. One of \"rg\", \"git\", \"fallback\".\n---     Default: whichever tool is present, trying in that same order.\n---   - <pattern> `(string)` - string pattern to search. If not given, asks user\n---     interactively with |input()|.\n---   - __pick_builtin_grep_globs\n---@param opts __pick_builtin_opts\nMiniPick.builtin.grep = function(local_opts, opts)\n  local_opts = vim.tbl_extend('force', { tool = nil, pattern = nil, globs = {} }, local_opts or {})\n  local tool = local_opts.tool or H.grep_get_tool()\n  local globs = H.is_array_of(local_opts.globs, 'string') and local_opts.globs or {}\n  local name_suffix = #globs == 0 and '' or (' | ' .. table.concat(globs, ', '))\n  local show = H.get_config().source.show or H.show_with_icons\n  local default_opts = { source = { name = string.format('Grep (%s%s)', tool, name_suffix), show = show } }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  local pattern = type(local_opts.pattern) == 'string' and local_opts.pattern or H.user_input('Grep pattern')\n  if pattern == nil then return end\n  if tool == 'fallback' then\n    local cwd = H.full_path(opts.source.cwd or vim.fn.getcwd())\n    opts.source.items = function() H.grep_fallback_items(pattern, cwd) end\n    return MiniPick.start(opts)\n  end\n\n  return MiniPick.builtin.cli({ command = H.grep_get_command(tool, pattern, globs) }, opts)\nend\n\n--- Pick from pattern matches with live feedback\n---\n--- Perform pattern matching treating prompt as pattern. Gives live feedback on\n--- which matches are found. Use |MiniPick-actions-refine| to revert to regular\n--- matching. Use `<C-o>` to restrict search to files matching glob patterns.\n--- Tries to use one of the CLI tools to create items (see |MiniPick-cli-tools|):\n--- `rg`, `git`. If none is present, error is thrown (for performance reasons).\n---\n--- To customize search, use tool's global configuration approach.\n--- Options 'ignorecase' and 'smartcase' are respected via forcing appropriate\n--- flags to CLI tool (i.e. overriding tool's global config).\n---\n---@param local_opts __pick_builtin_local_opts\n---   Possible fields:\n---   - <tool> `(string)` - which tool to use. One of \"rg\", \"git\".\n---     Default: whichever tool is present, trying in that same order.\n---   - __pick_builtin_grep_globs\n---     Use `<C-o>` custom mapping to add glob to the array.\n---@param opts __pick_builtin_opts\nMiniPick.builtin.grep_live = function(local_opts, opts)\n  local_opts = vim.tbl_extend('force', { tool = nil, globs = {} }, local_opts or {})\n  local tool = local_opts.tool or H.grep_get_tool()\n  if tool == 'fallback' or not H.is_executable(tool) then H.error('`grep_live` needs non-fallback executable tool.') end\n\n  local globs = H.is_array_of(local_opts.globs, 'string') and local_opts.globs or {}\n  local name_suffix = #globs == 0 and '' or (' | ' .. table.concat(globs, ', '))\n  local show = H.get_config().source.show or H.show_with_icons\n  local default_source = { name = string.format('Grep live (%s%s)', tool, name_suffix), show = show }\n  opts = vim.tbl_deep_extend('force', { source = default_source }, opts or {})\n\n  local cwd = H.full_path(opts.source.cwd or vim.fn.getcwd())\n  local set_items_opts, spawn_opts = { do_match = false, querytick = H.querytick }, { cwd = cwd }\n  local sys = { kill = function() end }\n  local match = function(_, _, query)\n    sys:kill()\n    if H.querytick == set_items_opts.querytick then return end\n    if #query == 0 then\n      sys = { kill = function() end }\n      return MiniPick.set_picker_items({}, set_items_opts)\n    end\n\n    set_items_opts.querytick = H.querytick\n    local command = H.grep_get_command(tool, table.concat(query), globs)\n    sys = MiniPick.set_picker_items_from_cli(command, { set_items_opts = set_items_opts, spawn_opts = spawn_opts })\n  end\n\n  local add_glob = function()\n    local ok, glob = pcall(vim.fn.input, 'Glob pattern: ')\n    if ok then table.insert(globs, glob) end\n    name_suffix = #globs == 0 and '' or (' | ' .. table.concat(globs, ', '))\n    MiniPick.set_picker_opts({ source = { name = string.format('Grep live (%s%s)', tool, name_suffix) } })\n    MiniPick.set_picker_query(MiniPick.get_picker_query())\n  end\n  local mappings = { add_glob = { char = '<C-o>', func = add_glob } }\n\n  opts = vim.tbl_deep_extend('force', opts or {}, { source = { items = {}, match = match }, mappings = mappings })\n  return MiniPick.start(opts)\nend\n\n--- Pick from help tags\n---\n--- Notes:\n--- - On choose directly executes |:help| command with appropriate modifier\n---   (none, |:vertical|, |:tab|). This is done through custom mappings named\n---   `show_help_in_{split,vsplit,tab}`. Not `choose_in_{split,vsplit,tab}` because\n---   there is no split guarantee (like if there is already help window opened).\n---\n---@param local_opts __pick_builtin_local_opts\n---   Possible fields:\n---   - <default_split> `(string)` - direction of a split for `choose` action.\n---     One of \"horizontal\", \"vertical\", \"tab\". Default: \"horizontal\".\n---@param opts __pick_builtin_opts\nMiniPick.builtin.help = function(local_opts, opts)\n  local_opts = vim.tbl_deep_extend('force', { default_split = 'horizontal' }, local_opts or {})\n  local default_modifier = ({ horizontal = '', vertical = 'vert ', tab = 'tab ' })[local_opts.default_split]\n  if default_modifier == nil then H.error('`opts.default_split` should be one of \"horizontal\", \"vertical\", \"tab\"') end\n\n  -- Get all tags\n  local help_buf = vim.api.nvim_create_buf(false, true)\n  vim.bo[help_buf].buftype = 'help'\n  -- - NOTE: no dedicated buffer name because it is immediately wiped out\n  local tags = vim.api.nvim_buf_call(help_buf, function() return vim.fn.taglist('.*') end)\n  vim.api.nvim_buf_delete(help_buf, { force = true })\n  vim.tbl_map(function(t) t.text = t.name end, tags)\n\n  -- NOTE: Choosing is done on next event loop to properly overcome special\n  -- nature of `:help {subject}` command. For example, it didn't quite work\n  -- when choosing tags in same file consecutively.\n  local choose = function(item, modifier)\n    if item == nil then return end\n    vim.schedule(function() vim.cmd((modifier or default_modifier) .. 'help ' .. (item.name or '')) end)\n  end\n  local preview = function(buf_id, item)\n    -- Take advantage of `taglist` output on how to open tag\n    vim.api.nvim_buf_call(buf_id, function()\n      vim.cmd('noautocmd edit ' .. vim.fn.fnameescape(item.filename))\n      vim.bo.buftype, vim.bo.buflisted, vim.bo.bufhidden = 'nofile', false, 'wipe'\n      local has_ts = pcall(vim.treesitter.start, 0)\n      if not has_ts then vim.bo.syntax = 'help' end\n\n      local cache_hlsearch = vim.v.hlsearch\n      -- Make a \"very nomagic\" search to account for special characters in tag\n      local search_cmd = string.gsub(item.cmd, '^/', '/\\\\V')\n      vim.cmd('silent keeppatterns ' .. search_cmd)\n      -- Here `vim.v` doesn't work: https://github.com/neovim/neovim/issues/25294\n      vim.cmd('let v:hlsearch=' .. cache_hlsearch)\n      vim.cmd('normal! zt')\n    end)\n  end\n\n  -- Modify default mappings to work with special `:help` command\n  local map_custom = function(char, modifier)\n    local f = function()\n      choose(MiniPick.get_picker_matches().current, modifier)\n      return true\n    end\n    return { char = char, func = f }\n  end\n\n  local config_mappings = H.get_config().mappings\n  --stylua: ignore\n  local mappings = {\n    choose_in_split   = '', show_help_in_split   = map_custom(config_mappings.choose_in_split, ''),\n    choose_in_vsplit  = '', show_help_in_vsplit  = map_custom(config_mappings.choose_in_vsplit, 'vertical '),\n    choose_in_tabpage = '', show_help_in_tabpage = map_custom(config_mappings.choose_in_tabpage, 'tab '),\n  }\n\n  local source = { items = tags, name = 'Help', choose = choose, preview = preview }\n  opts = vim.tbl_deep_extend('force', { source = source, mappings = mappings }, opts or {})\n  return MiniPick.start(opts)\nend\n\n--- Pick from buffers\n---\n--- Notes:\n--- - There are not built-in mappings for buffer manipulation. Here is an example\n---   of how to call this function with mapping to wipeout the current item: >lua\n---\n---   local wipeout_cur = function()\n---     vim.api.nvim_buf_delete(MiniPick.get_picker_matches().current.bufnr, {})\n---   end\n---   local buffer_mappings = { wipeout = { char = '<C-d>', func = wipeout_cur } }\n---   MiniPick.builtin.buffers(local_opts, { mappings = buffer_mappings })\n--- <\n---@param local_opts __pick_builtin_local_opts\n---   Possible fields:\n---   - <include_current> `(boolean)` - whether to include current buffer in\n---     the output. Default: `true`.\n---   - <include_unlisted> `(boolean)` - whether to include |unlisted-buffer|s in\n---     the output. Default: `false`.\n---@param opts __pick_builtin_opts\nMiniPick.builtin.buffers = function(local_opts, opts)\n  local_opts = vim.tbl_deep_extend('force', { include_current = true, include_unlisted = false }, local_opts or {})\n\n  local buffers_output = vim.api.nvim_exec('buffers' .. (local_opts.include_unlisted and '!' or ''), true)\n  local cur_buf_id, include_current = vim.api.nvim_get_current_buf(), local_opts.include_current\n  local items = {}\n  for _, l in ipairs(vim.split(buffers_output, '\\n')) do\n    local buf_str, name = l:match('^%s*%d+'), l:match('\"(.*)\"')\n    local buf_id = tonumber(buf_str)\n    local item = { text = name, bufnr = buf_id }\n    if buf_id ~= cur_buf_id or include_current then table.insert(items, item) end\n  end\n\n  local show = H.get_config().source.show or H.show_with_icons\n  local default_opts = { source = { name = 'Buffers', show = show } }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {}, { source = { items = items } })\n  return MiniPick.start(opts)\nend\n\n--- Pick from CLI output\n---\n--- Executes command line tool and constructs items based on its output.\n--- Uses |MiniPick.set_picker_items_from_cli()|.\n---\n--- Example: `MiniPick.builtin.cli({ command = { 'echo', 'a\\nb\\nc' } })`\n---\n---@param local_opts __pick_builtin_local_opts\n---   Possible fields:\n---   - <command> `(table)` - forwarded to `set_picker_items_from_cli()`.\n---   - <postprocess> `(function)` - forwarded to `set_picker_items_from_cli()`.\n---   - <spawn_opts> `(table)` - forwarded to `set_picker_items_from_cli()`.\n---     Note: if `cwd` field is absent, it is inferred from |MiniPick-source.cwd|.\n---@param opts __pick_builtin_opts\nMiniPick.builtin.cli = function(local_opts, opts)\n  local_opts = vim.tbl_deep_extend('force', { command = {}, postprocess = nil, spawn_opts = {} }, local_opts or {})\n  local name = string.format('CLI (%s)', tostring(local_opts.command[1] or ''))\n  opts = vim.tbl_deep_extend('force', { source = { name = name } }, opts or {})\n  -- Explicitly use full path to not conflict with `set_picker_items_from_cli`\n  -- behavior of treating `spawn_opts.cwd` relative to source's cwd\n  local_opts.spawn_opts.cwd = H.full_path(local_opts.spawn_opts.cwd or opts.source.cwd or vim.fn.getcwd())\n\n  local command = local_opts.command\n  local set_from_cli_opts = { postprocess = local_opts.postprocess, spawn_opts = local_opts.spawn_opts }\n  opts.source.items = vim.schedule_wrap(function() MiniPick.set_picker_items_from_cli(command, set_from_cli_opts) end)\n  return MiniPick.start(opts)\nend\n\n--- Resume latest picker\nMiniPick.builtin.resume = function()\n  local picker = H.pickers.latest\n  if picker == nil then H.error('There is no picker to resume.') end\n\n  H.cache = {}\n  local buf_id = H.picker_new_buf()\n  local win_target = vim.api.nvim_get_current_win()\n  local win_id = H.picker_new_win(buf_id, picker.opts.window.config, picker.opts.source.cwd)\n  picker.buffers = { main = buf_id }\n  picker.windows = { main = win_id, target = win_target }\n  picker.view_state = 'main'\n  H.pickers.active = picker\n\n  return H.picker_advance(picker)\nend\n\n--- Picker registry\n---\n--- Place for users and extensions to manage pickers with their commonly used\n--- local options. By default contains all |MiniPick.builtin| pickers.\n--- All entries should accept only a single `local_opts` table argument.\n---\n--- Serves as a source for |:Pick| command.\n---\n--- Customization examples: >lua\n---\n---   -- Adding custom picker to pick `register` entries\n---   MiniPick.registry.registry = function()\n---     local items = vim.tbl_keys(MiniPick.registry)\n---     table.sort(items)\n---     local source = {items = items, name = 'Registry', choose = function() end}\n---     local chosen_picker_name = MiniPick.start({ source = source })\n---     if chosen_picker_name == nil then return end\n---     return MiniPick.registry[chosen_picker_name]()\n---   end\n---\n---   -- Make `:Pick files` accept `cwd`\n---   MiniPick.registry.files = function(local_opts)\n---     local opts = { source = { cwd = local_opts.cwd } }\n---     local_opts.cwd = nil\n---     return MiniPick.builtin.files(local_opts, opts)\n---   end\n--- <\nMiniPick.registry = {}\n\nfor name, f in pairs(MiniPick.builtin) do\n  MiniPick.registry[name] = function(local_opts) return f(local_opts) end\nend\n\n--- Get items of active picker\n---\n---@return table|nil Picker items or `nil` if no active picker.\n---\n---@seealso |MiniPick.set_picker_items()| and |MiniPick.set_picker_items_from_cli()|\nMiniPick.get_picker_items = function() return H.copy_tables((H.pickers.active or {}).items) end\n\n--- Get stritems of active picker\n---\n---@return table|nil Picker stritems (|MiniPick-source.items-stritems|) or `nil` if\n---   no active picker.\n---\n---@seealso |MiniPick.set_picker_items()| and |MiniPick.set_picker_items_from_cli()|\nMiniPick.get_picker_stritems = function() return vim.deepcopy((H.pickers.active or {}).stritems) end\n\n--- Get matches of active picker\n---\n---@return table|nil Picker matches or `nil` if no active picker. Matches is a table\n---   with the following fields:\n---   - <all> `(table|nil)` - all currently matched items.\n---   - <all_inds> `(table|nil)` - indexes of all currently matched items.\n---   - <current> `(any)` - current matched item.\n---   - <current_ind> `(number|nil)` - index of current matched item.\n---   - <marked> `(table|nil)` - marked items.\n---   - <marked_inds> `(table|nil)` - indexes of marked items.\n---   - <shown> `(table|nil)` - shown items (from top to bottom).\n---   - <shown_inds> `(table|nil)` - indexes of shown items (from top to bottom).\n---\n---@seealso |MiniPick.set_picker_match_inds()|\nMiniPick.get_picker_matches = function()\n  if not MiniPick.is_picker_active() then return end\n  local picker = H.pickers.active\n  local items = picker.items\n  if items == nil or #items == 0 then return {} end\n\n  local match_inds = vim.deepcopy(picker.match_inds)\n  local res = { all_inds = match_inds, current_ind = match_inds[picker.current_ind] }\n  res.all = vim.tbl_map(function(ind) return items[ind] end, match_inds)\n  res.current = picker.items[res.current_ind]\n  local marked_inds = vim.tbl_keys(picker.marked_inds_map)\n  table.sort(marked_inds)\n  res.marked_inds, res.marked = marked_inds, vim.tbl_map(function(ind) return items[ind] end, marked_inds)\n  res.shown_inds = vim.tbl_map(function(ind) return match_inds[ind] end, picker.shown_inds)\n  res.shown = vim.tbl_map(function(ind) return items[ind] end, res.shown_inds)\n  return res\nend\n\n--- Get config of active picker\n---\n---@return table|nil Picker config (`start()`'s input `opts` table) or `nil` if\n---   no active picker.\n---\n---@seealso |MiniPick.set_picker_opts()|\nMiniPick.get_picker_opts = function() return vim.deepcopy((H.pickers.active or {}).opts) end\n\n--- Get state data of active picker\n---\n---@return table|nil Table with picker state data or `nil` if no active picker.\n---   State data is a table with the following fields:\n---   - <buffers> `(table)` - table with `main`, `preview`, `info` fields representing\n---     buffer identifier (or `nil`) for corresponding view.\n---   - <windows> `(table)` - table with `main` and `target` fields representing\n---     window identifiers for main and target windows.\n---   - <caret> `(number)` - caret column.\n---   - <is_busy> `(boolean)` - whether picker is busy with computations.\n---\n---@seealso |MiniPick.set_picker_target_window()|\nMiniPick.get_picker_state = function()\n  if not MiniPick.is_picker_active() then return end\n  local picker = H.pickers.active\n  --stylua: ignore\n  return vim.deepcopy({\n    buffers = picker.buffers, windows = picker.windows, caret = picker.caret, is_busy = picker.is_busy\n  })\nend\n\n--- Get query of active picker\n---\n---@return table|nil Array of picker query or `nil` if no active picker.\n---\n---@seealso |MiniPick.set_picker_query()|\nMiniPick.get_picker_query = function() return vim.deepcopy((H.pickers.active or {}).query) end\n\n--- Set items for active picker\n---\n--- Note: sets items asynchronously in non-blocking fashion.\n---\n---@param items table Array of items.\n---@param opts table|nil Options. Possible fields:\n---   - <do_match> `(boolean)` - whether to perform match after setting items.\n---     Default: `true`.\n---   - <querytick> `(number|nil)` - value of querytick (|MiniPick.get_querytick()|)\n---     to periodically check against when setting items. If checked querytick\n---     differs from supplied, no items are set.\n---\n---@seealso |MiniPick.get_picker_items()| and |MiniPick.get_picker_stritems()|\nMiniPick.set_picker_items = function(items, opts)\n  if not H.islist(items) then H.error('`items` should be an array.') end\n  opts = vim.tbl_deep_extend('force', { do_match = true, querytick = nil }, opts or {})\n  if not MiniPick.is_picker_active() then return end\n\n  -- Set items in async because computing lower `stritems` can block much time\n  coroutine.wrap(H.picker_set_items)(H.pickers.active, items, opts)\nend\n\n--- Set items for active picker based on CLI output\n---\n--- Asynchronously executes `command` and sets items to its postprocessed output.\n---\n--- Example: >lua\n---\n---   local items = vim.schedule_wrap(function()\n---     MiniPick.set_picker_items_from_cli({ 'echo', 'a\\nb\\nc' })\n---   end)\n---   MiniPick.start({ source = { items = items, name = 'Echo abc' } })\n--- <\n---@param command table Array with (at least one) string command parts.\n---@param opts table|nil Options. Possible fields:\n---   - <postprocess> `(function)` - callable performing postprocessing of output.\n---     Will be called with array of lines as input, should return array of items.\n---     Default: removes trailing empty lines and uses rest as string items.\n---   - <spawn_opts> `(table)` - `options` for |uv.spawn()|, except `args` and `stdio`.\n---     Note: relative `cwd` path is resolved against active picker's `cwd`.\n---   - <set_items_opts> `(table)` - table forwarded to |MiniPick.set_picker_items()|.\n---\n---@seealso |MiniPick.get_picker_items()| and |MiniPick.get_picker_stritems()|\nMiniPick.set_picker_items_from_cli = function(command, opts)\n  local is_valid_command = H.is_array_of(command, 'string') and #command >= 1\n  if not is_valid_command then H.error('`command` should be an array of strings.') end\n  local default_opts = { postprocess = H.cli_postprocess, set_items_opts = {}, spawn_opts = {} }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n  if not MiniPick.is_picker_active() then return end\n\n  local executable, args = command[1], vim.list_slice(command, 2, #command)\n  local stdout, data_feed = vim.loop.new_pipe(), {}\n  local spawn_opts = vim.tbl_deep_extend('force', opts.spawn_opts, { args = args, stdio = { nil, stdout, nil } })\n  if type(spawn_opts.cwd) == 'string' then spawn_opts.cwd = H.full_path(spawn_opts.cwd) end\n\n  local process, pid\n  process, pid = vim.loop.spawn(executable, spawn_opts, function()\n    if not process:is_closing() then process:close() end\n  end)\n  -- NOTE: `cancel` is better name, but go with `vim.system():kill` for future\n  local kill = function()\n    if stdout:is_active() then stdout:read_stop() end\n    data_feed = nil\n    if not stdout:is_closing() then stdout:close() end\n    if process:is_active() then process:kill() end\n  end\n\n  -- Make sure to fully stop the process if picker is stopped\n  vim.api.nvim_create_autocmd('User', { pattern = 'MiniPickStop', once = true, callback = kill })\n\n  stdout:read_start(function(err, data)\n    assert(not err, err)\n    if data ~= nil then return table.insert(data_feed, data) end\n    stdout:close()\n    coroutine.wrap(H.set_picker_items_from_feed)(data_feed, '\\r?\\n', opts)\n  end)\n\n  return { pid = pid, kill = kill }\nend\n\n--- Set match indexes for active picker\n---\n--- There are two intended use cases:\n--- - Inside custom asynchronous |MiniPick-source.match| function to set which of\n---   picker's stritems match the query. See |MiniPick.poke_is_picker_active()|.\n--- - To programmatically set current match and marked items.\n---   See |MiniPick.get_picker_matches()|.\n---\n---@param match_inds table Array of numbers with picker's items indexes.\n---@param match_type string|nil Type of match indexes to set. One of:\n---   - `\"all\"` (default) - indexes of items that match query.\n---   - `\"current\"` - index of current match. Only first element is used and should\n---     also be present among query matches.\n---   - `\"marked\"` - indexes of marked items. Values can be not among query matches.\n---     Will make only input indexes be marked, i.e. current marks are reset.\n---   Note: no `\"shown\"` match type as those indexes are computed automatically.\n---\n---@seealso |MiniPick.get_picker_matches()|\nMiniPick.set_picker_match_inds = function(match_inds, match_type)\n  if not H.is_array_of(match_inds, 'number') then H.error('`match_inds` should be an array of numbers.') end\n  local set = H.picker_set_inds[match_type or 'all']\n  if set == nil then H.error('`match_type` should be one of \"all\", \"marked\", \"current\"') end\n  if not MiniPick.is_picker_active() then return end\n\n  set(H.pickers.active, match_inds)\n  H.picker_update(H.pickers.active, false)\nend\n\n--- Set config for active picker\n---\n---@param opts table Table overriding initial `opts` input of |MiniPick.start()|.\n---\n---@seealso |MiniPick.get_picker_opts()|\nMiniPick.set_picker_opts = function(opts)\n  if not MiniPick.is_picker_active() then return end\n  local picker, cur_cwd = H.pickers.active, H.pickers.active.opts.source.cwd\n  picker.opts = vim.tbl_deep_extend('force', picker.opts, opts or {})\n  picker.action_keys = H.normalize_mappings(picker.opts.mappings)\n  if cur_cwd ~= picker.opts.source.cwd then H.win_set_cwd(picker.windows.main, picker.opts.source.cwd) end\n  local do_match = ((opts or {}).source or {}).match ~= nil\n  H.picker_update(picker, do_match, true)\nend\n\n--- Set target window for active picker\n---\n---@param win_id number Valid window identifier to be used as the new target window.\n---\n---@seealso |MiniPick.get_picker_state()|\nMiniPick.set_picker_target_window = function(win_id)\n  if not H.is_valid_win(win_id) then H.error('`win_id` is not a valid window identifier.') end\n  if not MiniPick.is_picker_active() then return end\n  H.pickers.active.windows.target = win_id\nend\n\n--- Set query for active picker\n---\n---@param query table Array of strings to be set as the new picker query.\n---\n---@seealso |MiniPick.get_picker_query()|\nMiniPick.set_picker_query = function(query)\n  if not H.is_array_of(query, 'string') then H.error('`query` should be an array of strings.') end\n  if not MiniPick.is_picker_active() then return end\n\n  H.pickers.active.query, H.pickers.active.caret = vim.deepcopy(query), #query + 1\n  H.querytick = H.querytick + 1\n  H.pickers.active.match_inds = H.seq_along(MiniPick.get_picker_items())\n  H.picker_update(H.pickers.active, true)\nend\n\n--- Get query tick\n---\n--- Query tick is a unique query identifier. Intended to be used to detect user\n--- activity during and between |MiniPick.start()| calls for efficient non-blocking\n--- functionality. Updates after any query change, picker start and stop.\n---\n--- See |MiniPick.poke_is_picker_active()| for usage example.\n---\n---@return number Query tick.\nMiniPick.get_querytick = function() return H.querytick end\n\n--- Check if there is an active picker\n---\n---@return boolean Whether there is currently an active picker.\n---\n---@seealso |MiniPick.poke_is_picker_active()|\nMiniPick.is_picker_active = function() return H.pickers.active ~= nil end\n\n--- Poke if picker is active\n---\n--- Intended to be used for non-blocking implementation of source methods.\n--- Returns an output of |MiniPick.is_picker_active()|, but depending on\n--- whether there is a coroutine running:\n--- - If no, return it immediately.\n--- - If yes, return it after `coroutine.yield()` with `coroutine.resume()`\n---   called \"soon\" by the main event-loop (see |vim.schedule()|).\n---\n--- Example of non-blocking exact `match` (as demo; can be optimized further): >lua\n---\n---   local match_nonblock = function(match_inds, stritems, query)\n---     local prompt, querytick = table.concat(query), MiniPick.get_querytick()\n---     local f = function()\n---       local res = {}\n---       for _, ind in ipairs(match_inds) do\n---         local should_stop = not MiniPick.poke_is_picker_active() or\n---           MiniPick.get_querytick() ~= querytick\n---         if should_stop then return end\n---\n---         if stritems[ind]:find(prompt) ~= nil then table.insert(res, ind) end\n---       end\n---\n---       MiniPick.set_picker_match_inds(res)\n---     end\n---\n---     coroutine.resume(coroutine.create(f))\n---   end\n--- <\n---@return boolean Whether there is an active picker.\n---\n---@seealso |MiniPick.is_picker_active()|\nMiniPick.poke_is_picker_active = function()\n  local co = coroutine.running()\n  if co == nil then return MiniPick.is_picker_active() end\n  H.schedule_resume_is_active(co)\n  return coroutine.yield()\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniPick.config)\n\n-- Namespaces\nH.ns_id = {\n  matches = vim.api.nvim_create_namespace('MiniPickMatches'),\n  headers = vim.api.nvim_create_namespace('MiniPickHeaders'),\n  preview = vim.api.nvim_create_namespace('MiniPickPreview'),\n  ranges = vim.api.nvim_create_namespace('MiniPickRanges'),\n  input = vim.api.nvim_create_namespace('MiniPickInput'),\n}\n\n-- Timers\nH.timers = {\n  busy = vim.loop.new_timer(),\n  focus = vim.loop.new_timer(),\n  redraw = vim.loop.new_timer(),\n}\n\n-- Pickers\nH.pickers = { active = nil, latest = nil }\n\n-- Picker-independent counter of query updates\nH.querytick = 0\n\n-- General purpose cache\nH.cache = {}\n\n-- File system information\nH.is_windows = vim.loop.os_uname().sysname == 'Windows_NT'\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('delay', config.delay, 'table')\n  H.check_type('delay.async', config.delay.async, 'number')\n  H.check_type('delay.busy', config.delay.busy, 'number')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.caret_left', config.mappings.caret_left, 'string')\n  H.check_type('mappings.caret_right', config.mappings.caret_right, 'string')\n  H.check_type('mappings.choose', config.mappings.choose, 'string')\n  H.check_type('mappings.choose_in_split', config.mappings.choose_in_split, 'string')\n  H.check_type('mappings.choose_in_tabpage', config.mappings.choose_in_tabpage, 'string')\n  H.check_type('mappings.choose_in_vsplit', config.mappings.choose_in_vsplit, 'string')\n  H.check_type('mappings.choose_marked', config.mappings.choose_marked, 'string')\n  H.check_type('mappings.delete_char', config.mappings.delete_char, 'string')\n  H.check_type('mappings.delete_char_right', config.mappings.delete_char_right, 'string')\n  H.check_type('mappings.delete_left', config.mappings.delete_left, 'string')\n  H.check_type('mappings.delete_word', config.mappings.delete_word, 'string')\n  H.check_type('mappings.mark', config.mappings.mark, 'string')\n  H.check_type('mappings.mark_all', config.mappings.mark_all, 'string')\n  H.check_type('mappings.move_down', config.mappings.move_down, 'string')\n  H.check_type('mappings.move_start', config.mappings.move_start, 'string')\n  H.check_type('mappings.move_up', config.mappings.move_up, 'string')\n  H.check_type('mappings.paste', config.mappings.paste, 'string')\n  H.check_type('mappings.refine', config.mappings.refine, 'string')\n  H.check_type('mappings.refine_marked', config.mappings.refine_marked, 'string')\n  H.check_type('mappings.scroll_down', config.mappings.scroll_down, 'string')\n  H.check_type('mappings.scroll_up', config.mappings.scroll_up, 'string')\n  H.check_type('mappings.scroll_left', config.mappings.scroll_left, 'string')\n  H.check_type('mappings.scroll_right', config.mappings.scroll_right, 'string')\n  H.check_type('mappings.stop', config.mappings.stop, 'string')\n  H.check_type('mappings.toggle_info', config.mappings.toggle_info, 'string')\n  H.check_type('mappings.toggle_preview', config.mappings.toggle_preview, 'string')\n\n  H.check_type('options', config.options, 'table')\n  H.check_type('options.content_from_bottom', config.options.content_from_bottom, 'boolean')\n  H.check_type('options.use_cache', config.options.use_cache, 'boolean')\n\n  H.check_type('source', config.source, 'table')\n  H.check_type('source.items', config.source.items, 'table', true)\n  H.check_type('source.name', config.source.name, 'string', true)\n  H.check_type('source.cwd', config.source.cwd, 'string', true)\n  H.check_type('source.match', config.source.match, 'function', true)\n  H.check_type('source.show', config.source.show, 'function', true)\n  H.check_type('source.preview', config.source.preview, 'function', true)\n  H.check_type('source.choose', config.source.choose, 'function', true)\n  H.check_type('source.choose_marked', config.source.choose_marked, 'function', true)\n\n  H.check_type('window', config.window, 'table')\n  local is_table_or_callable = function(x) return x == nil or type(x) == 'table' or vim.is_callable(x) end\n  if not is_table_or_callable(config.window.config) then\n    H.error('`window.config` should be table or callable, not ' .. type(config.window.config))\n  end\n  -- TODO: Remove after releasing 'mini.nvim' 0.16.0\n  if config.window.prompt_cursor ~= nil then\n    local msg = '`prompt_cursor` in `config.window` is renamed to `prompt_caret` for better naming consistency.'\n      .. ' It works for now, but will stop in the next release. Sorry for the inconvenience.'\n    H.notify(msg, 'WARN')\n    config.window.prompt_caret = config.window.prompt_cursor\n    config.window.prompt_cursor = nil\n  end\n  H.check_type('window.prompt_caret', config.window.prompt_caret, 'string')\n  H.check_type('window.prompt_prefix', config.window.prompt_prefix, 'string')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniPick.config = config\n\n  -- Register 'mini.extra' pickers\n  if type(_G.MiniExtra) == 'table' then\n    for name, f in pairs(_G.MiniExtra.pickers) do\n      MiniPick.registry[name] = MiniPick.registry[name] or function(local_opts) return f(local_opts) end\n    end\n  end\nend\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniPick.config, vim.b.minipick_config or {}, config or {})\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniPick', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('VimResized', '*', MiniPick.refresh, 'Refresh on resize')\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local hi = function(name, opts)\n    opts.default = true\n    vim.api.nvim_set_hl(0, name, opts)\n  end\n\n  hi('MiniPickBorder',        { link = 'FloatBorder' })\n  hi('MiniPickBorderBusy',    { link = 'DiagnosticFloatingWarn' })\n  hi('MiniPickBorderText',    { link = 'FloatTitle' })\n  hi('MiniPickCursor',        { blend = 100, nocombine = true })\n  hi('MiniPickIconDirectory', { link = 'Directory' })\n  hi('MiniPickIconFile',      { link = 'MiniPickNormal' })\n  hi('MiniPickHeader',        { link = 'DiagnosticFloatingHint' })\n  hi('MiniPickMatchCurrent',  { link = 'CursorLine' })\n  hi('MiniPickMatchMarked',   { link = 'Visual' })\n  hi('MiniPickMatchRanges',   { link = 'DiagnosticFloatingHint' })\n  hi('MiniPickNormal',        { link = 'NormalFloat' })\n  hi('MiniPickPreviewLine',   { link = 'CursorLine' })\n  hi('MiniPickPreviewRegion', { link = 'IncSearch' })\n  hi('MiniPickPrompt',        { link = 'DiagnosticFloatingInfo' })\n  hi('MiniPickPromptCaret',   { link = 'MiniPickPrompt' })\n  hi('MiniPickPromptPrefix',  { link = 'MiniPickPrompt' })\nend\n\nH.create_user_commands = function()\n  local callback = function(input)\n    local name, local_opts = H.command_parse_fargs(input.fargs)\n    local f = MiniPick.registry[name]\n    if f == nil then H.error(string.format('There is no picker named \"%s\" in registry.', name)) end\n    f(local_opts)\n  end\n  local opts = { nargs = '+', complete = H.command_complete, desc = \"Pick from 'mini.pick' registry\" }\n  vim.api.nvim_create_user_command('Pick', callback, opts)\nend\n\n-- Command --------------------------------------------------------------------\nH.command_parse_fargs = function(fargs)\n  local name, opts_parts = fargs[1], vim.tbl_map(H.expandcmd, vim.list_slice(fargs, 2, #fargs))\n  local tbl_string = string.format('{ %s }', table.concat(opts_parts, ', '))\n  local lua_load = loadstring('return ' .. tbl_string)\n  if lua_load == nil then H.error('Could not convert extra command arguments to table: ' .. tbl_string) end\n  return name, lua_load()\nend\n\nH.command_complete = function(_, line, col)\n  local prefix_from, prefix_to, prefix = string.find(line, '^%S+%s+(%S*)')\n  if col < prefix_from or prefix_to < col then return {} end\n  local candidates = vim.tbl_filter(\n    function(x) return tostring(x):find(prefix, 1, true) ~= nil end,\n    vim.tbl_keys(MiniPick.registry)\n  )\n  table.sort(candidates)\n  return candidates\nend\n\n-- Picker object --------------------------------------------------------------\nH.validate_picker_opts = function(opts)\n  opts = opts or {}\n  if type(opts) ~= 'table' then H.error('Picker options should be table.') end\n\n  opts = H.copy_tables(H.get_config(opts))\n\n  local validate_callable = function(x, x_name)\n    if not vim.is_callable(x) then H.error(string.format('`%s` should be callable.', x_name)) end\n  end\n\n  -- Source\n  local source = opts.source\n\n  local items = source.items or {}\n  local is_valid_items = H.islist(items) or vim.is_callable(items)\n  if not is_valid_items then H.error('`source.items` should be array or callable.') end\n\n  source.name = tostring(source.name or '<No name>')\n\n  if type(source.cwd) == 'string' then source.cwd = H.full_path(source.cwd) end\n  if source.cwd == nil then source.cwd = vim.fn.getcwd() end\n  if vim.fn.isdirectory(source.cwd) == 0 then H.error('`source.cwd` should be a valid directory path.') end\n\n  source.match = source.match or MiniPick.default_match\n  validate_callable(source.match, 'source.match')\n\n  source.show = source.show or MiniPick.default_show\n  validate_callable(source.show, 'source.show')\n\n  source.preview = source.preview or MiniPick.default_preview\n  validate_callable(source.preview, 'source.preview')\n\n  source.choose = source.choose or MiniPick.default_choose\n  validate_callable(source.choose, 'source.choose')\n\n  source.choose_marked = source.choose_marked or MiniPick.default_choose_marked\n  validate_callable(source.choose_marked, 'source.choose_marked')\n\n  -- Delay\n  for key, value in pairs(opts.delay) do\n    local is_valid_value = type(value) == 'number' and value > 0\n    if not is_valid_value then H.error(string.format('`delay.%s` should be a positive number.', key)) end\n  end\n\n  -- Mappings\n  local default_mappings = H.default_config.mappings\n  for field, x in pairs(opts.mappings) do\n    if type(field) ~= 'string' then H.error('`mappings` should have only string fields.') end\n    local is_builtin_action = default_mappings[field] ~= nil\n    if is_builtin_action and type(x) ~= 'string' then\n      H.error(string.format('Mapping for built-in action \"%s\" should be string.', field))\n    end\n    if not is_builtin_action and not (type(x) == 'table' and type(x.char) == 'string' and vim.is_callable(x.func)) then\n      H.error(string.format('Mapping for custom action \"%s\" should be table with `char` and `func`.', field))\n    end\n  end\n\n  -- Options\n  local options = opts.options\n  if type(options.content_from_bottom) ~= 'boolean' then H.error('`options.content_from_bottom` should be boolean.') end\n  if type(options.use_cache) ~= 'boolean' then H.error('`options.use_cache` should be boolean.') end\n\n  -- Window\n  local win_config = opts.window.config\n  local is_valid_winconfig = win_config == nil or type(win_config) == 'table' or vim.is_callable(win_config)\n  if not is_valid_winconfig then H.error('`window.config` should be table or callable.') end\n\n  return opts\nend\n\nH.picker_new = function(opts)\n  -- Create buffer\n  local buf_id = H.picker_new_buf()\n\n  -- Create window\n  local win_target = vim.api.nvim_get_current_win()\n  local win_id = H.picker_new_win(buf_id, opts.window.config, opts.source.cwd)\n\n  -- Construct and return object\n  local picker = {\n    -- Permanent data about picker (should not change)\n    opts = opts,\n\n    -- Items to pick from\n    items = nil,\n    stritems = nil,\n    stritems_ignorecase = nil,\n\n    -- Associated Neovim objects\n    buffers = { main = buf_id, preview = nil, info = nil },\n    windows = { main = win_id, target = win_target },\n\n    -- Query data\n    query = {},\n    -- - Query index at which new entry will be inserted\n    caret = 1,\n    -- - Array of `stritems` indexes matching current query\n    match_inds = nil,\n    -- - Map of of currently marked `stritems` indexes (as keys)\n    marked_inds_map = {},\n    -- - Action keys which should be processed as described in mappings\n    action_keys = H.normalize_mappings(opts.mappings),\n\n    -- Whether picker is currently busy processing data\n    is_busy = false,\n\n    -- Cache for `matches` per prompt for more performant querying\n    cache = {},\n\n    -- View data\n    -- - Which buffer should currently be shown\n    view_state = 'main',\n\n    -- - Index range of `match_inds` currently visible. Present for significant\n    --   performance increase to render only what is visible.\n    visible_range = { from = nil, to = nil },\n\n    -- - Index of `match_inds` pointing at current item\n    current_ind = nil,\n    -- - Array of indexes of `match_inds` pointing at currently shown items\n    shown_inds = {},\n  }\n\n  H.querytick = H.querytick + 1\n\n  return picker\nend\n\nH.picker_advance = function(picker)\n  vim.schedule(function() vim.api.nvim_exec_autocmds('User', { pattern = 'MiniPickStart' }) end)\n\n  local do_match, is_aborted = false, false\n  local lmap = H.get_lmap()\n  for _ = 1, 1000000 do\n    if H.cache.is_force_stop_advance then break end\n    H.picker_update(picker, do_match)\n\n    local char = H.getcharstr(lmap)\n    if H.cache.is_force_stop_advance then break end\n\n    is_aborted = char == nil\n    if is_aborted then break end\n\n    local cur_action = picker.action_keys[char] or {}\n    do_match = cur_action.name == nil or vim.startswith(cur_action.name, 'delete') or cur_action.name == 'paste'\n    is_aborted = cur_action.name == 'stop'\n\n    local should_stop\n    if cur_action.is_custom then\n      should_stop = cur_action.func()\n    else\n      should_stop = (cur_action.func or H.picker_query_add)(picker, char)\n    end\n    if should_stop then break end\n  end\n\n  local item\n  if not is_aborted then item = H.picker_get_current_item(picker) end\n  H.cache.is_force_stop_advance = nil\n  H.picker_stop(picker)\n  return item\nend\n\nH.picker_update = function(picker, do_match, update_window)\n  if do_match then H.picker_match(picker) end\n  if update_window then\n    local config = H.picker_compute_win_config(picker.opts.window.config)\n    vim.api.nvim_win_set_config(picker.windows.main, config)\n    H.picker_set_current_ind(picker, picker.current_ind, true)\n  end\n  H.picker_set_bordertext(picker)\n  H.picker_set_lines(picker)\n  vim.cmd('redraw')\nend\n\nH.picker_new_buf = function()\n  local buf_id = H.create_scratch_buf('main')\n  vim.bo[buf_id].filetype = 'minipick'\n  return buf_id\nend\n\nH.picker_new_win = function(buf_id, win_config, cwd)\n  -- Hide cursor while picker is active (to not be visible in the window)\n  -- This mostly follows a hack from 'folke/noice.nvim'\n  H.cache.guicursor = vim.o.guicursor\n  vim.o.guicursor = 'a:MiniPickCursor'\n\n  -- Create window and focus on it\n  local win_id = vim.api.nvim_open_win(buf_id, true, H.picker_compute_win_config(win_config, true))\n\n  -- Set window-local data\n  local opts_scope = { scope = 'local', win = win_id }\n  vim.wo[win_id].foldenable = false\n  vim.wo[win_id].foldmethod = 'manual'\n  -- TODO: Use vim.wo[win_id][0] after compatibility with Neovim=0.9 is dropped\n  vim.api.nvim_set_option_value('list', true, opts_scope)\n  vim.api.nvim_set_option_value('listchars', 'extends:…,precedes:…', opts_scope)\n  vim.wo[win_id].scrolloff = 0\n  vim.wo[win_id].wrap = false\n  H.win_update_hl(win_id, 'NormalFloat', 'MiniPickNormal')\n  H.win_update_hl(win_id, 'FloatBorder', 'MiniPickBorder')\n  vim.fn.clearmatches(win_id)\n\n  -- Set window's local \"current directory\" for easier choose/preview/etc.\n  H.win_set_cwd(nil, cwd)\n\n  return win_id\nend\n\nH.picker_compute_win_config = function(win_config, is_for_open)\n  local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)\n  local has_statusline = vim.o.laststatus > 0\n  local max_height = vim.o.lines - vim.o.cmdheight - (has_tabline and 1 or 0) - (has_statusline and 1 or 0)\n  local max_width = vim.o.columns\n\n  local winborder = vim.fn.exists('+winborder') == 0 and '' or vim.o.winborder\n  local default_config = {\n    relative = 'editor',\n    anchor = 'SW',\n    width = math.floor(0.618 * max_width),\n    height = math.floor(0.618 * max_height),\n    col = 0,\n    row = max_height + (has_tabline and 1 or 0),\n    border = winborder == '' and 'single' or nil,\n    style = 'minimal',\n    noautocmd = is_for_open,\n    -- Use high enough value to be on top of built-in windows (pmenu, etc.)\n    zindex = 251,\n  }\n  local config = vim.tbl_deep_extend('force', default_config, H.expand_callable(win_config) or {})\n\n  -- Tweak config values to ensure they are proper\n  if (config.border or winborder) == 'none' then config.border = { '', ' ', '', '', '', ' ', '', '' } end\n  -- - Adjust dimensions accounting for actually present border parts\n  local bor, n = config.border, type(config.border) == 'table' and #config.border or 0\n  local height_offset = n == 0 and 2 or ((bor[1 % n + 1] == '' and 0 or 1) + (bor[5 % n + 1] == '' and 0 or 1))\n  local width_offset = n == 0 and 2 or ((bor[3 % n + 1] == '' and 0 or 1) + (bor[7 % n + 1] == '' and 0 or 1))\n  config.height = math.max(math.min(config.height, max_height - height_offset), 1)\n  config.width = math.max(math.min(config.width, max_width - width_offset), 1)\n\n  return config\nend\n\nH.picker_track_lost_focus = function(picker)\n  local track = vim.schedule_wrap(function()\n    local is_cur_win = vim.api.nvim_get_current_win() == picker.windows.main\n    local is_proper_focus = is_cur_win and (H.cache.is_in_getcharstr or vim.fn.mode() ~= 'n')\n    if is_proper_focus then return end\n    if H.cache.is_in_getcharstr then return vim.api.nvim_feedkeys('\\3', 't', true) end\n    H.picker_stop(picker, true)\n  end)\n  H.timers.focus:start(1000, 1000, track)\nend\n\nH.picker_set_items = function(picker, items, opts)\n  -- Compute string items to work with (along with their lower variants)\n  local stritems, stritems_ignorecase, tolower = {}, {}, H.tolower\n  local poke_picker = H.poke_picker_throttle(opts.querytick)\n  for i, x in ipairs(items) do\n    if not poke_picker() then return end\n    local to_add = H.item_to_string(x)\n    table.insert(stritems, to_add)\n    table.insert(stritems_ignorecase, tolower(to_add))\n  end\n\n  picker.items, picker.stritems, picker.stritems_ignorecase = items, stritems, stritems_ignorecase\n  picker.cache, picker.marked_inds_map = {}, {}\n  H.picker_set_busy(picker, false)\n\n  H.picker_set_match_inds(picker, H.seq_along(items))\n  -- Force update visible range for correct \"show\" lines computation\n  H.picker_set_current_ind(picker, picker.current_ind, true)\n  H.picker_update(picker, opts.do_match)\nend\n\nH.item_to_string = function(item)\n  item = H.expand_callable(item)\n  if type(item) == 'string' then return item end\n  if type(item) == 'table' and type(item.text) == 'string' then return item.text end\n  return vim.inspect(item, { newline = ' ', indent = '' })\nend\n\nH.picker_set_busy = function(picker, value)\n  picker.is_busy = value\n\n  -- NOTE: Don't precompute highlight group to always set a valid one\n  local update_border_hl = function()\n    H.timers.busy:stop()\n    H.win_update_hl(picker.windows.main, 'FloatBorder', picker.is_busy and 'MiniPickBorderBusy' or 'MiniPickBorder')\n  end\n\n  if value then return H.timers.busy:start(picker.opts.delay.busy, 0, vim.schedule_wrap(update_border_hl)) end\n  update_border_hl()\nend\n\nH.picker_set_match_inds = function(picker, inds)\n  if inds == nil then return end\n  H.picker_set_busy(picker, false)\n\n  picker.match_inds = inds\n\n  local cache_prompt = table.concat(picker.query)\n  if picker.opts.options.use_cache then picker.cache[cache_prompt] = { inds = inds } end\n\n  -- Always show result of updated matches\n  H.picker_show_main(picker)\n\n  -- Reset current index if match indexes are updated\n  H.picker_set_current_ind(picker, 1)\n\n  -- Trigger relevant event if not already inside it\n  if not H.inside_minipickmatch then\n    H.inside_minipickmatch = true\n    vim.api.nvim_exec_autocmds('User', { pattern = 'MiniPickMatch' })\n    H.inside_minipickmatch = nil\n  end\nend\n\nH.picker_set_current_ind = function(picker, ind, force_update)\n  if picker.items == nil or #picker.match_inds == 0 then\n    picker.current_ind, picker.visible_range = nil, {}\n    return\n  end\n\n  -- Wrap index around edges\n  local n_matches = #picker.match_inds\n  ind = (ind - 1) % n_matches + 1\n\n  -- (Re)Compute visible range (centers current index if it is currently outside)\n  local from, to, querytick = picker.visible_range.from, picker.visible_range.to, picker.visible_range.querytick\n  local needs_update = H.querytick ~= querytick or from == nil or to == nil or not (from <= ind and ind <= to)\n  if (force_update or needs_update) and H.is_valid_win(picker.windows.main) then\n    local win_height = vim.api.nvim_win_get_height(picker.windows.main)\n    to = math.min(n_matches, math.floor(ind + 0.5 * win_height))\n    from = math.max(1, to - win_height + 1)\n    to = from + math.min(win_height, n_matches) - 1\n  end\n\n  -- Set data\n  picker.current_ind = ind\n  picker.visible_range = { from = from, to = to, querytick = H.querytick }\nend\n\nH.picker_set_inds = {\n  all = function(picker, inds) H.picker_set_match_inds(H.pickers.active, inds) end,\n  current = function(picker, inds)\n    if inds[1] == nil or picker.match_inds == nil then return end\n    local current_match_ind, current_abs_ind = nil, inds[1]\n    for i, match_abs_ind in ipairs(picker.match_inds) do\n      if match_abs_ind == current_abs_ind then current_match_ind = i end\n    end\n    if current_match_ind == nil then H.error('Current match index should be present among all current matches') end\n    H.picker_set_current_ind(picker, current_match_ind, true)\n  end,\n  marked = function(picker, inds)\n    if picker.items == nil then return end\n    local marked_inds_map, n_items = {}, #picker.items\n    for _, ind in ipairs(inds) do\n      if not (1 <= ind and ind <= n_items) then H.error('Marked indexes should be from 1 to number of items') end\n      marked_inds_map[ind] = true\n    end\n    picker.marked_inds_map = marked_inds_map\n  end,\n}\n\nH.picker_set_lines = function(picker)\n  local buf_id, win_id = picker.buffers.main, picker.windows.main\n  if not (H.is_valid_buf(buf_id) and H.is_valid_win(win_id)) then return end\n\n  if picker.is_busy then return end\n\n  local visible_range, query = picker.visible_range, picker.query\n  if picker.items == nil or visible_range.from == nil or visible_range.to == nil then\n    picker.shown_inds = {}\n    picker.opts.source.show(buf_id, {}, query)\n    H.clear_namespace(buf_id, H.ns_id.matches)\n    return\n  end\n\n  -- Construct target items\n  local items_to_show, items, shown_inds, match_inds = {}, picker.items, {}, picker.match_inds\n  local cur_ind, cur_line = picker.current_ind, nil\n  local marked_inds_map, marked_lnums = picker.marked_inds_map, {}\n  local is_from_bottom = picker.opts.options.content_from_bottom\n  local from = is_from_bottom and visible_range.to or visible_range.from\n  local to = is_from_bottom and visible_range.from or visible_range.to\n  for i = from, to, (from <= to and 1 or -1) do\n    table.insert(shown_inds, i)\n    table.insert(items_to_show, items[match_inds[i]])\n    if i == cur_ind then cur_line = #items_to_show end\n    if marked_inds_map[match_inds[i]] then table.insert(marked_lnums, #items_to_show) end\n  end\n\n  local n_empty_top_lines = is_from_bottom and (vim.api.nvim_win_get_height(win_id) - #items_to_show) or 0\n  cur_line = cur_line + n_empty_top_lines\n  marked_lnums = vim.tbl_map(function(x) return x + n_empty_top_lines end, marked_lnums)\n\n  -- Update visible lines accounting for \"from_bottom\" direction\n  picker.shown_inds = shown_inds\n  picker.opts.source.show(buf_id, items_to_show, query)\n  if n_empty_top_lines > 0 then\n    local empty_lines = vim.fn['repeat']({ '' }, n_empty_top_lines)\n    vim.api.nvim_buf_set_lines(buf_id, 0, 0, true, empty_lines)\n  end\n\n  local ns_id = H.ns_id.matches\n  H.clear_namespace(buf_id, ns_id)\n\n  -- Add highlighting for marked lines\n  local marked_opts = { end_col = 0, hl_group = 'MiniPickMatchMarked', priority = 202 }\n  for _, lnum in ipairs(marked_lnums) do\n    marked_opts.end_row = lnum\n    H.set_extmark(buf_id, ns_id, lnum - 1, 0, marked_opts)\n  end\n\n  -- Update current item\n  if cur_line > vim.api.nvim_buf_line_count(buf_id) then return end\n\n  local cur_opts = { end_row = cur_line, end_col = 0, hl_eol = true, hl_group = 'MiniPickMatchCurrent', priority = 201 }\n  H.set_extmark(buf_id, ns_id, cur_line - 1, 0, cur_opts)\n\n  -- - Update cursor if showing item matches (needed for 'scroll_{left,right}')\n  local cursor = vim.api.nvim_win_get_cursor(win_id)\n  if picker.view_state == 'main' and cursor[1] ~= cur_line then H.set_cursor(win_id, cur_line, cursor[2] + 1) end\nend\n\nH.picker_match = function(picker)\n  if picker.items == nil then return end\n\n  -- Try to use cache first\n  local prompt_cache\n  if picker.opts.options.use_cache then prompt_cache = picker.cache[table.concat(picker.query)] end\n  if prompt_cache ~= nil then return H.picker_set_match_inds(picker, prompt_cache.inds) end\n\n  local is_ignorecase = H.query_is_ignorecase(picker.query)\n  local stritems = is_ignorecase and picker.stritems_ignorecase or picker.stritems\n  local query = is_ignorecase and vim.tbl_map(H.tolower, picker.query) or picker.query\n\n  H.picker_set_busy(picker, true)\n  local new_inds = picker.opts.source.match(stritems, picker.match_inds, query)\n  H.picker_set_match_inds(picker, new_inds)\nend\n\nH.query_is_ignorecase = function(query)\n  if not vim.o.ignorecase then return false end\n  if not vim.o.smartcase then return true end\n  local prompt = table.concat(query)\n  return prompt == vim.fn.tolower(prompt)\nend\n\nH.normalize_mappings = function(mappings, skip_alternatives)\n  local res = {}\n  local add_to_res = function(char, data)\n    local key = H.replace_termcodes(char)\n    -- Omit disabled keys and prefer custom actions over built-ins\n    if (key == nil or key == '') or (res[key] ~= nil and res[key].is_custom) then return end\n    if res[key] ~= nil then H.notify('Duplicating mapping keys: ' .. data.name .. ' and ' .. res[key].name, 'WARN') end\n    res[key] = data\n  end\n\n  -- Use alternative keys for some common actions\n  local alt_chars = {}\n  if not skip_alternatives then alt_chars = { move_down = '<Down>', move_start = '<Home>', move_up = '<Up>' } end\n\n  -- Process\n  for name, rhs in pairs(mappings) do\n    local is_custom = type(rhs) == 'table'\n    local char = is_custom and rhs.char or rhs\n    local data = { char = char, name = name, func = is_custom and rhs.func or H.actions[name], is_custom = is_custom }\n    add_to_res(char, data)\n    add_to_res(alt_chars[name], data)\n  end\n\n  return res\nend\n\nH.picker_set_bordertext = function(picker)\n  local opts = picker.opts\n  local win_id = picker.windows.main\n  if not H.is_valid_win(win_id) then return end\n\n  -- Compute main text managing views separately and truncating from left\n  local view_state, win_width = picker.view_state, vim.api.nvim_win_get_width(win_id)\n  local config\n  if view_state == 'main' then\n    local caret, query = picker.caret, picker.query\n    local prompt_prefix, prompt_caret = opts.window.prompt_prefix, opts.window.prompt_caret\n    local max_width = math.max(1, win_width - vim.fn.strchars(prompt_prefix) - vim.fn.strchars(prompt_caret))\n\n    -- Try to put caret in the center if there is not enough room to show the\n    -- whole query (as in 'mini.tabline'). Do that after concatenating query\n    -- parts as (after `set_picker_query()`) they can have multiple characters.\n    local before_caret = table.concat(vim.list_slice(query, 1, caret - 1))\n    local after_caret = table.concat(vim.list_slice(query, caret, #query))\n    local w_before, w_after = vim.fn.strchars(before_caret), vim.fn.strchars(after_caret)\n\n    local w_right = math.min(math.floor(0.5 * max_width), w_after)\n    local w_left = math.min(math.max(max_width - w_right, 0), w_before)\n    w_right = math.min(math.max(max_width - w_left, 0), w_after)\n\n    -- Show standard \"there is more\" padding symbols if needed\n    local pad_left, pad_right = w_left == w_before and '' or '…', w_right == w_after and '' or '…'\n    w_left, w_right = w_left - (pad_left == '' and 0 or 1), w_right - (pad_right == '' and 0 or 1)\n\n    before_caret = vim.fn.strcharpart(before_caret, w_before - w_left, w_left)\n    after_caret = vim.fn.strcharpart(after_caret, 0, w_right)\n\n    local prompt = { { prompt_prefix, 'MiniPickPromptPrefix' }, { prompt_caret, 'MiniPickPromptCaret' } }\n    if after_caret ~= '' then table.insert(prompt, 3, { after_caret .. pad_right, 'MiniPickPrompt' }) end\n    if before_caret ~= '' then table.insert(prompt, 2, { pad_left .. before_caret, 'MiniPickPrompt' }) end\n    config = { title = prompt }\n  end\n\n  local has_items = picker.items ~= nil\n  if view_state == 'preview' and has_items then\n    local stritem_cur = picker.stritems[picker.match_inds[picker.current_ind]] or ''\n    -- Sanitize title\n    stritem_cur = stritem_cur:gsub('%z', '│'):gsub('%s', ' ')\n    config = { title = { { H.fit_to_width(' ' .. stritem_cur .. ' ', win_width), 'MiniPickBorderText' } } }\n  end\n\n  if view_state == 'info' then\n    config = { title = { { H.fit_to_width(' Info ', win_width), 'MiniPickBorderText' } } }\n  end\n\n  -- Compute helper footer only if Neovim version permits and not in busy\n  -- picker (otherwise it will flicker number of matches data on char delete)\n  local nvim_has_window_footer = vim.fn.has('nvim-0.10') == 1\n  if nvim_has_window_footer and not picker.is_busy then\n    config.footer, config.footer_pos = H.picker_compute_footer(picker, win_id), 'left'\n  end\n\n  -- Respect `options.content_from_bottom`\n  if nvim_has_window_footer and opts.options.content_from_bottom then\n    config.title, config.footer = config.footer, config.title\n  end\n\n  local win_list_option = vim.api.nvim_get_option_value('list', { scope = 'local', win = win_id })\n  vim.api.nvim_win_set_config(win_id, config)\n  vim.api.nvim_set_option_value('list', win_list_option, { scope = 'local', win = win_id })\nend\n\nH.picker_compute_footer = function(picker, win_id)\n  local info = H.picker_get_general_info(picker)\n  local source_name = string.format(' %s ', info.source_name):gsub('[%z%s]', ' ')\n  local n_marked_text = info.n_marked == 0 and '' or (info.n_marked .. '/')\n  local inds = string.format(' %s|%s|%s%s ', info.relative_current_ind, info.n_matched, n_marked_text, info.n_total)\n  local win_width, source_width, inds_width =\n    vim.api.nvim_win_get_width(win_id), vim.fn.strchars(source_name), vim.fn.strchars(inds)\n\n  local footer = { { H.fit_to_width(source_name, win_width), 'MiniPickBorderText' } }\n  local n_spaces_between = win_width - (source_width + inds_width)\n  if n_spaces_between > 0 then\n    local border_hl = picker.is_busy and 'MiniPickBorderBusy' or 'MiniPickBorder'\n    local part_id = picker.opts.options.content_from_bottom and 2 or 6\n    footer[2] = { H.win_get_bottom_border(win_id, part_id):rep(n_spaces_between), border_hl }\n    footer[3] = { inds, 'MiniPickBorderText' }\n  end\n  return footer\nend\n\nH.picker_stop = function(picker, abort)\n  vim.tbl_map(function(timer) pcall(vim.loop.timer_stop, timer) end, H.timers)\n\n  -- Show cursor (work around `guicursor=''` actually leaving cursor hidden)\n  if H.cache.guicursor == '' then vim.cmd('set guicursor=a: | redraw') end\n  pcall(function() vim.o.guicursor = H.cache.guicursor end)\n\n  if picker == nil then return end\n\n  vim.api.nvim_exec_autocmds('User', { pattern = 'MiniPickStop' })\n\n  if abort then\n    H.pickers = {}\n  else\n    local new_latest = H.copy_tables(picker)\n    H.picker_free(H.pickers.latest)\n    H.pickers = { active = nil, latest = new_latest }\n  end\n\n  H.set_curwin(picker.windows.target)\n  pcall(vim.api.nvim_win_close, picker.windows.main, true)\n  pcall(vim.api.nvim_buf_delete, picker.buffers.main, { force = true })\n  pcall(vim.api.nvim_buf_delete, picker.buffers.info, { force = true })\n  picker.windows, picker.buffers = {}, {}\n\n  H.querytick = H.querytick + 1\nend\n\nH.picker_free = function(picker)\n  if picker == nil then return end\n  picker.match_inds = nil\n  picker.shown_inds = {}\n  picker.cache = nil\n  picker.stritems, picker.stritems_ignorecase, picker.marked_inds_map = nil, nil, nil\n  picker.items = nil\n  picker = nil\n  vim.schedule(function() collectgarbage('collect') end)\nend\n\n--stylua: ignore\nH.actions = {\n  caret_left  = function(picker, _) H.picker_move_caret(picker, -1) end,\n  caret_right = function(picker, _) H.picker_move_caret(picker, 1)  end,\n\n  choose            = function(picker, _) return H.picker_choose(picker, nil)      end,\n  choose_in_split   = function(picker, _) return H.picker_choose(picker, 'split')  end,\n  choose_in_tabpage = function(picker, _) return H.picker_choose(picker, 'tab split') end,\n  choose_in_vsplit  = function(picker, _) return H.picker_choose(picker, 'vsplit') end,\n  choose_marked     = function(picker, _)\n    local ok, res = pcall(picker.opts.source.choose_marked, MiniPick.get_picker_matches().marked)\n    if not ok then vim.schedule(function() H.error('Error during choose marked:\\n' .. res) end) end\n    return not (ok and res)\n  end,\n\n  delete_char       = function(picker, _) H.picker_query_delete(picker, 1)                end,\n  delete_char_right = function(picker, _) H.picker_query_delete(picker, 0)                end,\n  delete_left       = function(picker, _) H.picker_query_delete(picker, picker.caret - 1) end,\n  delete_word = function(picker, _)\n    local init, n_del = picker.caret - 1, 0\n    if init == 0 then return end\n    local ref_is_keyword = vim.fn.match(picker.query[init], '[[:keyword:]]') >= 0\n    for i = init, 1, -1 do\n      local cur_is_keyword = vim.fn.match(picker.query[i], '[[:keyword:]]') >= 0\n      if (ref_is_keyword and not cur_is_keyword) or (not ref_is_keyword and cur_is_keyword) then break end\n      n_del = n_del + 1\n    end\n    H.picker_query_delete(picker, n_del)\n  end,\n\n  mark     = function(picker, _) H.picker_mark_indexes(picker, 'current') end,\n  mark_all = function(picker, _) H.picker_mark_indexes(picker, 'all') end,\n\n  move_down  = function(picker, _) H.picker_move_current(picker, 1)  end,\n  move_start = function(picker, _) H.picker_move_current(picker, nil, 1)  end,\n  move_up    = function(picker, _) H.picker_move_current(picker, -1) end,\n\n  paste = function(picker, _)\n    local reg_contents = H.picker_get_register_contents(picker):gsub('[\\n\\t]', ' ')\n    for i = 1, vim.fn.strchars(reg_contents) do\n      H.picker_query_add(picker, vim.fn.strcharpart(reg_contents, i - 1, 1))\n    end\n  end,\n\n  refine        = function(picker, _) H.picker_refine(picker, 'all') end,\n  refine_marked = function(picker, _) H.picker_refine(picker, 'marked') end,\n\n  scroll_down  = function(picker, _) H.picker_scroll(picker, 'down')  end,\n  scroll_up    = function(picker, _) H.picker_scroll(picker, 'up')    end,\n  scroll_left  = function(picker, _) H.picker_scroll(picker, 'left')  end,\n  scroll_right = function(picker, _) H.picker_scroll(picker, 'right') end,\n\n  toggle_info = function(picker, _)\n    if picker.view_state == 'info' then return H.picker_show_main(picker) end\n    H.picker_show_info(picker)\n  end,\n\n  toggle_preview = function(picker, _)\n    if picker.view_state == 'preview' then return H.picker_show_main(picker) end\n    H.picker_show_preview(picker)\n  end,\n\n  stop = function(_, _) return true end,\n}\n\nH.picker_query_add = function(picker, char)\n  -- Determine if it **is** proper single character\n  if not H.is_query_char(char) then return end\n  table.insert(picker.query, picker.caret, char)\n  picker.caret = picker.caret + 1\n  H.querytick = H.querytick + 1\n\n  -- Adding character inside query might not result into narrowing matches, so\n  -- reset match indexes. Use cache to speed this up.\n  local should_reset = picker.items ~= nil and picker.caret <= #picker.query\n  if should_reset then picker.match_inds = H.seq_along(picker.items) end\nend\n\nH.is_query_char = function(char) return vim.fn.strchars(char) == 1 and vim.fn.char2nr(char) > 31 end\n\nH.picker_query_delete = function(picker, n)\n  local delete_to_left = n > 0\n  local left = delete_to_left and math.max(picker.caret - n, 1) or picker.caret\n  local right = delete_to_left and picker.caret - 1 or math.min(picker.caret + n, #picker.query)\n  for i = right, left, -1 do\n    table.remove(picker.query, i)\n  end\n  picker.caret = left\n  H.querytick = H.querytick + 1\n\n  -- Deleting query character increases number of possible matches, so need to\n  -- reset already matched indexes prior deleting. Use cache to speed this up.\n  if picker.items ~= nil then picker.match_inds = H.seq_along(picker.items) end\nend\n\nH.picker_choose = function(picker, pre_command)\n  local cur_item = H.picker_get_current_item(picker)\n  if cur_item == nil then return true end\n\n  local win_id_target = picker.windows.target\n  if pre_command ~= nil and H.is_valid_win(win_id_target) then\n    -- Work around Neovim not preserving cwd during `nvim_win_call`\n    -- See: https://github.com/neovim/neovim/issues/32203\n    local picker_cwd, global_cwd = vim.fn.getcwd(0), vim.fn.getcwd(-1, -1)\n    vim.fn.chdir(global_cwd)\n    vim.api.nvim_win_call(win_id_target, function()\n      vim.cmd(pre_command)\n      picker.windows.target = vim.api.nvim_get_current_win()\n    end)\n    vim.fn.chdir(picker_cwd)\n  end\n\n  local ok, res = pcall(picker.opts.source.choose, cur_item)\n  -- Delay error to have time to hide picker window\n  if not ok then vim.schedule(function() H.error('Error during choose:\\n' .. res) end) end\n  -- Error or returning nothing, `nil`, or `false` should lead to picker stop\n  return not (ok and res)\nend\n\nH.picker_mark_indexes = function(picker, range_type)\n  if picker.items == nil then return end\n  local test_inds = range_type == 'current' and { picker.match_inds[picker.current_ind] } or picker.match_inds\n\n  -- Mark if not all marked, unmark otherwise\n  local marked_inds_map, is_all_marked = picker.marked_inds_map, true\n  for _, ind in ipairs(test_inds) do\n    is_all_marked = is_all_marked and marked_inds_map[ind]\n  end\n\n  -- NOTE: Set to `nil` and not `false` for easier counting of present values\n  local new_val\n  if not is_all_marked then new_val = true end\n  for _, ind in ipairs(test_inds) do\n    marked_inds_map[ind] = new_val\n  end\n\n  if picker.view_state == 'info' then H.picker_show_info(picker) end\nend\n\nH.picker_move_caret = function(picker, n) picker.caret = math.min(math.max(picker.caret + n, 1), #picker.query + 1) end\n\nH.picker_move_current = function(picker, by, to)\n  if picker.items == nil then return end\n  local n_matches = #picker.match_inds\n  if n_matches == 0 then return end\n\n  if to == nil then\n    -- Account for content direction\n    by = (picker.opts.options.content_from_bottom and -1 or 1) * by\n\n    -- Wrap around edges only if current index is at edge\n    to = picker.current_ind\n    if to == 1 and by < 0 then\n      to = n_matches\n    elseif to == n_matches and by > 0 then\n      to = 1\n    else\n      to = to + by\n    end\n    to = math.min(math.max(to, 1), n_matches)\n  end\n\n  H.picker_set_current_ind(picker, to)\n\n  -- Update not main buffer(s)\n  if picker.view_state == 'info' then H.picker_show_info(picker) end\n  if picker.view_state == 'preview' then H.picker_show_preview(picker) end\nend\n\nH.picker_refine = function(picker, refine_type)\n  if picker.items == nil then return end\n\n  -- Make current matches be new items to be matched with default match\n  picker.opts.source.match = H.get_config().source.match or MiniPick.default_match\n  picker.query, picker.caret = {}, 1\n  MiniPick.set_picker_items(MiniPick.get_picker_matches()[refine_type] or {})\n\n  picker._refine = picker._refine or { orig_name = picker.opts.source.name, count = 0 }\n  picker._refine.count = picker._refine.count + 1\n  local count_suffix = picker._refine.count == 1 and '' or (' ' .. picker._refine.count)\n  picker.opts.source.name = string.format('%s (Refine%s)', picker._refine.orig_name, count_suffix)\nend\n\nH.picker_scroll = function(picker, direction)\n  local win_id = picker.windows.main\n  if picker.view_state == 'main' and (direction == 'down' or direction == 'up') then\n    local n = (direction == 'down' and 1 or -1) * vim.api.nvim_win_get_height(win_id)\n    H.picker_move_current(picker, n)\n  else\n    local keys = ({ down = '<C-f>', up = '<C-b>', left = 'zH', right = 'zL' })[direction]\n    vim.api.nvim_win_call(win_id, function() vim.cmd('normal! ' .. H.replace_termcodes(keys)) end)\n  end\nend\n\nH.picker_get_current_item = function(picker)\n  if picker.items == nil then return nil end\n  return picker.items[picker.match_inds[picker.current_ind]]\nend\n\nH.picker_get_register_contents = function(picker)\n  local register = H.getcharstr({})\n  -- Mimic some \"insert object under cursor\" behavior of Command-line mode\n  local expand_var = ({ ['\\1'] = '<cWORD>', ['\\6'] = '<cfile>', ['\\23'] = '<cword>' })[register]\n  if expand_var then\n    return vim.api.nvim_win_call(picker.windows.target, function() return vim.fn.expand(expand_var) end)\n  end\n  if register == '\\f' then\n    return vim.api.nvim_win_call(picker.windows.target, function() return vim.fn.getline('.') end)\n  end\n  local has_register, res = pcall(vim.fn.getreg, register)\n  return has_register and res or ''\nend\n\nH.picker_show_main = function(picker)\n  H.set_winbuf(picker.windows.main, picker.buffers.main)\n  vim.api.nvim_set_option_value('list', true, { scope = 'local', win = picker.windows.main })\n  picker.view_state = 'main'\nend\n\nH.picker_show_info = function(picker)\n  -- General information\n  local info = H.picker_get_general_info(picker)\n  local lines = {\n    'General',\n    'Source name   │ ' .. info.source_name,\n    'Source cwd    │ ' .. info.source_cwd,\n    'Total items   │ ' .. info.n_total,\n    'Matched items │ ' .. info.n_matched,\n    'Marked items  │ ' .. info.n_marked,\n    'Current index │ ' .. info.relative_current_ind,\n  }\n  local hl_lines = { 1 }\n\n  local append_char_data = function(data, header)\n    if #data == 0 then return end\n    table.insert(lines, '')\n    table.insert(lines, header)\n    table.insert(hl_lines, #lines)\n\n    local width_max = 0\n    for _, t in ipairs(data) do\n      local desc = t.name:gsub('[%s%p]', ' ')\n      t.desc = vim.fn.toupper(desc:sub(1, 1)) .. desc:sub(2)\n      t.width = vim.fn.strchars(t.desc)\n      width_max = math.max(width_max, t.width)\n    end\n    table.sort(data, function(a, b) return a.desc < b.desc end)\n\n    for _, t in ipairs(data) do\n      table.insert(lines, string.format('%s%s │ %s', t.desc, string.rep(' ', width_max - t.width), t.char))\n    end\n  end\n\n  local action_keys = H.normalize_mappings(picker.opts.mappings, true)\n  append_char_data(vim.tbl_filter(function(x) return x.is_custom end, action_keys), 'Mappings (custom)')\n  append_char_data(vim.tbl_filter(function(x) return not x.is_custom end, action_keys), 'Mappings (built-in)')\n\n  -- Manage buffer/window/state\n  local buf_id_info = picker.buffers.info\n  if not H.is_valid_buf(buf_id_info) then buf_id_info = H.create_scratch_buf('info') end\n  picker.buffers.info = buf_id_info\n\n  H.set_buflines(buf_id_info, lines)\n  H.set_winbuf(picker.windows.main, buf_id_info)\n  picker.view_state = 'info'\n\n  local ns_id = H.ns_id.headers\n  H.clear_namespace(buf_id_info, ns_id)\n  for _, lnum in ipairs(hl_lines) do\n    H.set_extmark(buf_id_info, ns_id, lnum - 1, 0, { end_row = lnum, end_col = 0, hl_group = 'MiniPickHeader' })\n  end\nend\n\nH.picker_get_general_info = function(picker)\n  local has_items = picker.items ~= nil\n  return {\n    source_name = picker.opts.source.name or '---',\n    source_cwd = vim.fn.fnamemodify(picker.opts.source.cwd, ':~') or '---',\n    n_total = has_items and #picker.items or '-',\n    n_matched = has_items and #picker.match_inds or '-',\n    n_marked = has_items and vim.tbl_count(picker.marked_inds_map) or '-',\n    relative_current_ind = has_items and picker.current_ind or '-',\n  }\nend\n\nH.picker_show_preview = function(picker)\n  local preview = picker.opts.source.preview\n  local item = H.picker_get_current_item(picker)\n  if item == nil then return end\n\n  local win_id, buf_id = picker.windows.main, H.create_scratch_buf('preview')\n  vim.bo[buf_id].bufhidden = 'wipe'\n  H.set_winbuf(win_id, buf_id)\n  vim.api.nvim_set_option_value('list', vim.go.list, { scope = 'local', win = win_id })\n  preview(buf_id, item)\n  picker.buffers.preview = vim.api.nvim_win_get_buf(win_id)\n  picker.view_state = 'preview'\n  H.ensure_redraw(picker)\nend\n\n-- Default match --------------------------------------------------------------\nH.match_filter = function(inds, stritems, query)\n  -- 'abc' and '*abc' - fuzzy; \"'abc\" and 'a' - exact substring;\n  -- 'ab c' - grouped fuzzy; '^abc' and 'abc$' - exact substring at start/end.\n  local is_fuzzy_forced, is_exact_plain, is_exact_start, is_exact_end =\n    query[1] == '*', query[1] == \"'\", query[1] == '^', query[#query] == '$'\n  local is_grouped, grouped_parts = H.match_query_group(query)\n\n  if is_fuzzy_forced or is_exact_plain or is_exact_start or is_exact_end then\n    local start_offset = (is_fuzzy_forced or is_exact_plain or is_exact_start) and 2 or 1\n    local end_offset = #query - ((not is_fuzzy_forced and not is_exact_plain and is_exact_end) and 1 or 0)\n    query = vim.list_slice(query, start_offset, end_offset)\n  elseif is_grouped then\n    query = grouped_parts\n  end\n\n  if #query == 0 then return {}, 'useall', query end\n\n  local is_fuzzy_plain = not (is_exact_plain or is_exact_start or is_exact_end) and #query > 1\n  if is_fuzzy_forced or is_fuzzy_plain then return H.match_filter_fuzzy(inds, stritems, query), 'fuzzy', query end\n\n  local prefix = is_exact_start and '^' or ''\n  local suffix = is_exact_end and '$' or ''\n  local pattern = prefix .. vim.pesc(table.concat(query)) .. suffix\n\n  return H.match_filter_exact(inds, stritems, query, pattern), 'exact', query\nend\n\nH.match_filter_exact = function(inds, stritems, query, pattern)\n  local match_single = H.match_filter_exact_single\n  local poke_picker = H.poke_picker_throttle(H.querytick)\n  local match_data = {}\n  for _, ind in ipairs(inds) do\n    if not poke_picker() then return nil end\n    local data = match_single(stritems[ind], ind, pattern)\n    if data ~= nil then table.insert(match_data, data) end\n  end\n\n  return match_data\nend\n\nH.match_filter_exact_single = function(candidate, index, pattern)\n  local start = string.find(candidate, pattern)\n  if start == nil then return nil end\n\n  return { 0, start, index }\nend\n\nH.match_ranges_exact = function(match_data, query)\n  -- All matches have same match ranges relative to match start\n  local cur_start, rel_ranges = 0, {}\n  for i = 1, #query do\n    rel_ranges[i] = { cur_start, cur_start + query[i]:len() - 1 }\n    cur_start = rel_ranges[i][2] + 1\n  end\n\n  local res = {}\n  for i = 1, #match_data do\n    local start = match_data[i][2]\n    res[i] = vim.tbl_map(function(x) return { start + x[1], start + x[2] } end, rel_ranges)\n  end\n\n  return res\nend\n\nH.match_filter_fuzzy = function(inds, stritems, query)\n  local match_single, find_query = H.match_filter_fuzzy_single, H.match_find_query\n  local poke_picker = H.poke_picker_throttle(H.querytick)\n  local match_data = {}\n  for _, ind in ipairs(inds) do\n    if not poke_picker() then return nil end\n    local data = match_single(stritems[ind], ind, query, find_query)\n    if data ~= nil then table.insert(match_data, data) end\n  end\n  return match_data\nend\n\nH.match_filter_fuzzy_single = function(candidate, index, query, find_query)\n  -- Search for query chars match positions with the following properties:\n  -- - All are present in `candidate` in the same order.\n  -- - Has smallest width among all such match positions.\n  -- - Among same width has smallest first match.\n\n  -- Search forward to find matching positions with left-most last char match\n  local first, last = find_query(candidate, query, 1)\n  if first == nil then return nil end\n  if first == last then return { 0, first, index, { first } } end\n\n  -- NOTE: This approach doesn't iterate **all** query matches. It is fine for\n  -- width optimization but maybe not for more (like contiguous groups number).\n  -- Example: for query {'a', 'b', 'c'} candidate 'aaxbbbc' will be matched as\n  -- having 3 groups (indexes 2, 4, 7) but correct one is 2 groups (2, 6, 7).\n\n  -- Iteratively try to find better matches by advancing last match\n  local best_first, best_last, best_width = first, last, last - first\n  while last do\n    local width = last - first\n    if width < best_width then\n      best_first, best_last, best_width = first, last, width\n    end\n\n    first, last = find_query(candidate, query, first + 1)\n  end\n\n  -- NOTE: No field names is not clear code, but consistently better performant\n  return { best_last - best_first, best_first, index }\nend\n\nH.match_ranges_fuzzy = function(match_data, query, stritems)\n  local res, n_query, query_lens = {}, #query, vim.tbl_map(string.len, query)\n  for i_match, data in ipairs(match_data) do\n    local s, from, to = stritems[data[3]], data[2], data[2] + query_lens[1] - 1\n    local ranges = { { from, to } }\n    for j_query = 2, n_query do\n      from, to = string.find(s, query[j_query], to + 1, true)\n      ranges[j_query] = { from, to }\n    end\n    res[i_match] = ranges\n  end\n  return res\nend\n\nH.match_find_query = function(s, query, init)\n  local first, to = string.find(s, query[1], init, true)\n  if first == nil then return nil, nil end\n\n  -- Both `first` and `last` indicate the start byte of first and last match\n  local last = first\n  for i = 2, #query do\n    last, to = string.find(s, query[i], to + 1, true)\n    if not last then return nil, nil end\n  end\n  return first, last\nend\n\nH.match_query_group = function(query)\n  local parts = { {} }\n  for _, x in ipairs(query) do\n    local is_whitespace = x:find('^%s+$') ~= nil\n    if is_whitespace then table.insert(parts, {}) end\n    if not is_whitespace then table.insert(parts[#parts], x) end\n  end\n  return #parts > 1, vim.tbl_map(table.concat, parts)\nend\n\nH.match_sort = function(match_data)\n  -- Spread indexes in width-start buckets\n  local buckets, max_width, width_max_start = {}, 0, {}\n  for i = 1, #match_data do\n    local data, width, start = match_data[i], match_data[i][1], match_data[i][2]\n    local buck_width = buckets[width] or {}\n    local buck_start = buck_width[start] or {}\n    table.insert(buck_start, data[3])\n    buck_width[start] = buck_start\n    buckets[width] = buck_width\n\n    max_width = math.max(max_width, width)\n    width_max_start[width] = math.max(width_max_start[width] or 0, start)\n  end\n\n  -- Sort index in place (to make stable sort) within buckets\n  local poke_picker = H.poke_picker_throttle(H.querytick)\n  for _, buck_width in pairs(buckets) do\n    for _, buck_start in pairs(buck_width) do\n      if not poke_picker() then return nil end\n      table.sort(buck_start)\n    end\n  end\n\n  -- Gather indexes back in order\n  local res = {}\n  for width = 0, max_width do\n    local buck_width = buckets[width]\n    for start = 1, (width_max_start[width] or 0) do\n      local buck_start = buck_width[start] or {}\n      for i = 1, #buck_start do\n        table.insert(res, buck_start[i])\n      end\n    end\n  end\n\n  return res\nend\n\nH.match_no_sort = function(match_data)\n  return vim.tbl_map(function(x) return x[3] end, match_data)\nend\n\n-- Default show ---------------------------------------------------------------\nH.get_icon = function(x, icons)\n  local item_data = H.parse_item(x)\n  local path = item_data.path or item_data.text or ''\n  local path_type = H.get_fs_type(path)\n  if path_type == 'none' then return { text = icons.none, hl = 'MiniPickNormal' } end\n\n  -- Prefer 'mini.icons'\n  if _G.MiniIcons ~= nil then\n    local category = path_type == 'directory' and 'directory' or 'file'\n    local icon, hl = _G.MiniIcons.get(category, path)\n    return { text = icon .. ' ', hl = hl }\n  end\n\n  -- Try falling back to 'nvim-web-devicons'\n  if path_type == 'directory' then return { text = icons.directory, hl = 'MiniPickIconDirectory' } end\n  local has_devicons, devicons = pcall(require, 'nvim-web-devicons')\n  if not has_devicons then return { text = icons.file, hl = 'MiniPickIconFile' } end\n\n  local icon, hl = devicons.get_icon(vim.fn.fnamemodify(path, ':t'), nil, { default = false })\n  icon = type(icon) == 'string' and (icon .. ' ') or icons.file\n  return { text = icon, hl = hl or 'MiniPickIconFile' }\nend\n\nH.show_with_icons = function(buf_id, items, query) MiniPick.default_show(buf_id, items, query, { show_icons = true }) end\n\n-- Items helpers for default functions ----------------------------------------\nH.parse_item = function(item)\n  -- Try parsing table item first\n  if type(item) == 'table' then return H.parse_item_table(item) end\n\n  -- Parse item's string representation\n  local stritem = H.item_to_string(item)\n\n  -- - Buffer\n  local ok, numitem = pcall(tonumber, stritem)\n  if ok and H.is_valid_buf(numitem) then return { type = 'buffer', buf_id = numitem } end\n\n  -- File or Directory\n  local path_type, path, lnum, col, rest = H.parse_path(stritem)\n  if path_type ~= 'none' then return { type = path_type, path = path, lnum = lnum, col = col, text = rest } end\n\n  return {}\nend\n\nH.parse_item_table = function(item)\n  -- Buffer\n  local buf_id = item.bufnr or item.buf_id or item.buf\n  if H.is_valid_buf(buf_id) then\n    --stylua: ignore\n    return {\n      type = 'buffer',  buf_id   = buf_id, path = item.path or vim.api.nvim_buf_get_name(buf_id),\n      lnum = item.lnum, end_lnum = item.end_lnum,\n      col  = item.col,  end_col  = item.end_col,\n      text = item.text,\n    }\n  end\n\n  -- File or Directory\n  if type(item.path) == 'string' then\n    local path_type = H.get_fs_type(item.path)\n    if path_type == 'file' or path_type == 'uri' then\n      --stylua: ignore\n      return {\n        type = path_type, path     = item.path,\n        lnum = item.lnum, end_lnum = item.end_lnum,\n        col  = item.col,  end_col  = item.end_col,\n        text = item.text,\n      }\n    end\n\n    if path_type == 'directory' then return { type = 'directory', path = item.path } end\n  end\n\n  return {}\nend\n\nH.parse_path = function(x)\n  if type(x) ~= 'string' or x == '' then return nil end\n  -- Allow inputs like 'aa/bb', 'aa-5'. Also allow inputs for line/position\n  -- separated by null character:\n  -- - 'aa/bb\\00010' (line 10).\n  -- - 'aa/bb\\00010\\0005' (line 10, col 5).\n  -- - 'aa/bb\\00010\\0005\\000xx' (line 10, col 5, with \"xx\" description).\n  local location_pattern = '()%z(%d+)%z?(%d*)%z?(.*)$'\n  local from, lnum, col, rest = x:match(location_pattern)\n  local path = x:sub(1, (from or 0) - 1)\n  path = path:sub(1, 1) == '~' and ((vim.loop.os_homedir() or '~') .. path:sub(2)) or path\n\n  -- Verify that path is real\n  local path_type = H.get_fs_type(path)\n  if path_type == 'none' and path ~= '' then\n    local cwd = H.pickers.active == nil and vim.fn.getcwd() or H.pickers.active.opts.source.cwd\n    path = string.format('%s/%s', cwd, path)\n    path_type = H.get_fs_type(path)\n  end\n\n  return path_type, path, tonumber(lnum), tonumber(col), rest or ''\nend\n\nH.get_fs_type = function(path)\n  if path == '' then return 'none' end\n  if vim.fn.filereadable(path) == 1 then return 'file' end\n  if vim.fn.isdirectory(path) == 1 then return 'directory' end\n  if H.parse_uri(path) ~= nil then return 'uri' end\n  return 'none'\nend\n\n-- Default preview ------------------------------------------------------------\nH.preview_file = function(buf_id, item_data, opts)\n  -- Fully preview only accessible text files\n  local is_text = H.is_file_text(item_data.path)\n  if not is_text then return H.set_buflines(buf_id, { is_text == nil and '-No-access-' or '-Non-text-file-' }) end\n\n  -- Compute lines. Limit number of read lines to work better on large files.\n  local has_lines, lines = pcall(vim.fn.readfile, item_data.path, '', (item_data.lnum or 1) + opts.n_context_lines)\n  if not has_lines then return end\n\n  item_data.line_position = opts.line_position\n  H.preview_set_lines(buf_id, lines, item_data)\nend\n\nH.preview_directory = function(buf_id, item_data)\n  local path = item_data.path\n  local format = function(x) return x .. (vim.fn.isdirectory(path .. '/' .. x) == 1 and '/' or '') end\n  local lines = vim.tbl_map(format, vim.fn.readdir(path))\n  H.set_buflines(buf_id, lines)\nend\n\nH.preview_buffer = function(buf_id, item_data, opts)\n  -- NOTE: ideally just setting target buffer to window would be enough, but it\n  -- has side effects. See https://github.com/neovim/neovim/issues/24973 .\n  -- Reading lines and applying custom styling is a passable alternative.\n  local buf_id_source = item_data.buf_id\n\n  -- Get lines from buffer ensuring it is loaded without important consequences\n  local cache_eventignore = vim.o.eventignore\n  vim.o.eventignore = 'BufEnter'\n  vim.fn.bufload(buf_id_source)\n  vim.o.eventignore = cache_eventignore\n  local lines = vim.api.nvim_buf_get_lines(buf_id_source, 0, (item_data.lnum or 1) + opts.n_context_lines, false)\n\n  item_data.filetype, item_data.line_position = vim.bo[buf_id_source].filetype, opts.line_position\n  H.preview_set_lines(buf_id, lines, item_data)\nend\n\nH.preview_uri = function(buf_id, item_data, opts)\n  item_data.buf_id = vim.uri_to_bufnr(item_data.path)\n  H.preview_buffer(buf_id, item_data, opts)\nend\n\nH.preview_inspect = function(buf_id, obj) H.set_buflines(buf_id, vim.split(vim.inspect(obj), '\\n')) end\n\nH.preview_set_lines = function(buf_id, lines, extra)\n  -- Lines\n  H.set_buflines(buf_id, lines)\n\n  -- Highlighting\n  H.preview_highlight_region(buf_id, extra.lnum, extra.col, extra.end_lnum, extra.end_col)\n\n  if H.preview_should_highlight(buf_id) then\n    local ft = extra.filetype or vim.filetype.match({ buf = buf_id, filename = extra.path })\n    local has_lang, lang = pcall(vim.treesitter.language.get_lang, ft)\n    lang = has_lang and lang or ft\n    -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n    local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, lang, { error = false })\n    has_parser = has_parser and parser ~= nil\n    if has_parser then has_parser = pcall(vim.treesitter.start, buf_id, lang) end\n    if not has_parser then vim.bo[buf_id].syntax = ft end\n  end\n\n  -- Cursor position and window view. Find window (and not use picker window)\n  -- for \"outside window preview\" (preview and main are different) to work.\n  local win_id = vim.fn.bufwinid(buf_id)\n  if win_id == -1 then return end\n  H.set_cursor(win_id, extra.lnum, extra.col)\n  local pos_keys = ({ top = 'zt', center = 'zz', bottom = 'zb' })[extra.line_position] or 'zt'\n  pcall(vim.api.nvim_win_call, win_id, function() vim.cmd('normal! ' .. pos_keys) end)\nend\n\nH.preview_should_highlight = function(buf_id)\n  -- Highlight if buffer size is not too big, both in total and per line\n  local buf_size = vim.api.nvim_buf_call(buf_id, function() return vim.fn.line2byte(vim.fn.line('$') + 1) end)\n  return buf_size <= 1000000 and buf_size <= 1000 * vim.api.nvim_buf_line_count(buf_id)\nend\n\nH.preview_highlight_region = function(buf_id, lnum, col, end_lnum, end_col)\n  -- Highlight line\n  if lnum == nil then return end\n  local hl_line_opts = { end_row = lnum, end_col = 0, hl_eol = true, hl_group = 'MiniPickPreviewLine', priority = 201 }\n  H.set_extmark(buf_id, H.ns_id.preview, lnum - 1, 0, hl_line_opts)\n\n  -- Highlight position/region\n  if col == nil then return end\n\n  local ext_end_row, ext_end_col = lnum - 1, col\n  if end_lnum ~= nil and end_col ~= nil then\n    ext_end_row, ext_end_col = end_lnum - 1, end_col - 1\n  end\n  ext_end_col = H.get_next_char_bytecol(vim.fn.getbufline(buf_id, ext_end_row + 1)[1], ext_end_col)\n\n  local hl_region_opts = { end_row = ext_end_row, end_col = ext_end_col, priority = 202 }\n  hl_region_opts.hl_group = 'MiniPickPreviewRegion'\n  H.set_extmark(buf_id, H.ns_id.preview, lnum - 1, col - 1, hl_region_opts)\nend\n\n-- Default choose -------------------------------------------------------------\nH.choose_path = function(win_target, item_data)\n  local path = H.parse_uri(item_data.path) or item_data.path\n  if item_data.type == 'directory' then\n    return vim.api.nvim_win_call(win_target, function() vim.cmd('edit ' .. vim.fn.fnameescape(path)) end)\n  end\n  pcall(vim.api.nvim_win_call, win_target, function() vim.cmd(\"normal! m'\") end)\n  H.edit(path, win_target)\n  H.choose_set_cursor(win_target, item_data.lnum, item_data.col)\nend\n\nH.choose_buffer = function(win_target, item_data)\n  pcall(vim.api.nvim_win_call, win_target, function() vim.cmd(\"normal! m'\") end)\n  H.set_winbuf(win_target, item_data.buf_id)\n  H.choose_set_cursor(win_target, item_data.lnum, item_data.col)\nend\n\nH.choose_print = function(x) print(vim.inspect(x)) end\n\nH.choose_set_cursor = function(win_id, lnum, col)\n  if lnum == nil then return end\n  H.set_cursor(win_id, lnum, col)\n  pcall(vim.api.nvim_win_call, win_id, function() vim.cmd('normal! zvzz') end)\nend\n\n-- Builtins -------------------------------------------------------------------\n-- Stdout feed is the final result split into unknown places. This function is\n-- a longer version of `vim.split(table.concat(feed, ''), '\\r?\\n')` but allows\n-- to interrupt computation and doesn't create big string for the whole feed.\nH.set_picker_items_from_feed = function(feed, pattern, opts)\n  -- Check active picker as `poke_picker()` will always be `true` in this case\n  if not MiniPick.is_picker_active() then return end\n\n  -- Reuse input querytick to preserve intended reaction to query change\n  -- NOTE: For intended effect, relies on presence of the active coroutine\n  local poke_picker = H.poke_picker_throttle(opts.set_items_opts.querytick)\n\n  -- Realign feed so that each one ends in a pattern\n  for i = 2, #feed do\n    if not poke_picker() then return end\n    local _, to = feed[i]:find(pattern)\n    -- Account for chunks with no matches. Possibly several in a row.\n    to = to or feed[i]:len()\n    local j = i - 1\n    while j > 1 and feed[j] == '' do\n      j = j - 1\n    end\n    feed[j], feed[i] = feed[j] .. feed[i]:sub(1, to), feed[i]:sub(to + 1)\n  end\n\n  local res, insert = {}, table.insert\n  for i = 1, #feed do\n    -- Poke once per feed item and not match, because latter is too much and\n    -- might be less performant as each poke computes time.\n    if not poke_picker() then return end\n    for s in vim.gsplit(feed[i], pattern, { trimempty = true }) do\n      insert(res, s)\n    end\n    -- Cleanup\n    feed[i] = nil\n  end\n\n  vim.schedule(function() MiniPick.set_picker_items(opts.postprocess(res), opts.set_items_opts) end)\nend\n\nH.cli_postprocess = function(items)\n  while items[#items] == '' do\n    items[#items] = nil\n  end\n  return items\nend\n\nH.is_executable = function(tool)\n  if tool == 'fallback' then return true end\n  return vim.fn.executable(tool) == 1\nend\n\nH.files_get_tool = function()\n  if H.is_executable('rg') then return 'rg' end\n  if H.is_executable('fd') then return 'fd' end\n  if H.is_executable('git') then return 'git' end\n  return 'fallback'\nend\n\nH.files_get_command = function(tool)\n  if tool == 'rg' then return { 'rg', '--files', '--color=never' } end\n  if tool == 'fd' then return { 'fd', '--type=f', '--color=never' } end\n  if tool == 'git' then\n    return { 'git', '-c', 'core.quotepath=false', 'ls-files', '--cached', '--others', '--exclude-standard' }\n  end\n  H.error([[Wrong 'tool' for `files` builtin.]])\nend\n\nH.files_fallback_items = function(cwd)\n  local poke_picker = H.poke_picker_throttle()\n  local f = function()\n    local items = {}\n    for path, path_type in vim.fs.dir(cwd, { depth = math.huge }) do\n      if not poke_picker() then return end\n      if path_type == 'file' and H.is_file_text(string.format('%s/%s', cwd, path)) then table.insert(items, path) end\n    end\n    MiniPick.set_picker_items(items)\n  end\n\n  vim.schedule(coroutine.wrap(f))\nend\n\nH.grep_get_tool = function()\n  if H.is_executable('rg') then return 'rg' end\n  if H.is_executable('git') then return 'git' end\n  return 'fallback'\nend\n\n--stylua: ignore\nH.grep_get_command = function(tool, pattern, globs)\n  if tool == 'rg' then\n    local res = {\n      'rg', '--column', '--line-number', '--no-heading', '--field-match-separator', '\\\\x00', '--color=never'\n    }\n    for _, g in ipairs(globs) do\n      table.insert(res, '--glob')\n      -- NOTE: no `*` as default is important to not \"override\" ignoring files\n      table.insert(res, g)\n    end\n    local case = vim.o.ignorecase and (vim.o.smartcase and 'smart-case' or 'ignore-case') or 'case-sensitive'\n    vim.list_extend(res, { '--' .. case,  '--', pattern })\n    return res\n  end\n  if tool == 'git' then\n    local res = { 'git', 'grep', '--column', '--line-number', '--null', '--color=never', '-e', pattern, '--', unpack(globs) }\n    if vim.o.ignorecase then table.insert(res, 6, '--ignore-case') end\n    return res\n  end\n  H.error([[Wrong 'tool' for `grep` builtin.]])\nend\n\nH.grep_fallback_items = function(pattern, cwd)\n  local poke_picker = H.poke_picker_throttle()\n  local f = function()\n    local files, files_full = {}, {}\n    for path, path_type in vim.fs.dir(cwd, { depth = math.huge }) do\n      if not poke_picker() then return end\n      local path_full = string.format('%s/%s', cwd, path)\n      if path_type == 'file' and H.is_file_text(path_full) then\n        table.insert(files, path)\n        table.insert(files_full, path_full)\n      end\n    end\n\n    local items = {}\n    for i, path in ipairs(files_full) do\n      local file = files[i]\n      if not poke_picker() then return end\n      for lnum, l in ipairs(vim.fn.readfile(path)) do\n        local col = string.find(l, pattern)\n        if col ~= nil then table.insert(items, string.format('%s\\0%d\\0%d\\0%s', file, lnum, col, l)) end\n      end\n    end\n\n    MiniPick.set_picker_items(items)\n  end\n\n  vim.schedule(coroutine.wrap(f))\nend\n\n-- Async ----------------------------------------------------------------------\nH.schedule_resume_is_active = vim.schedule_wrap(function(co) coroutine.resume(co, MiniPick.is_picker_active()) end)\n\nH.poke_picker_throttle = function(querytick_ref)\n  -- Allow calling this even if no picker is active\n  if not MiniPick.is_picker_active() then\n    return function() return true end\n  end\n\n  local latest_time, dont_check_querytick = vim.loop.hrtime(), querytick_ref == nil\n  local threshold = 1000000 * H.pickers.active.opts.delay.async\n  local hrtime = vim.loop.hrtime\n  local poke_is_picker_active = MiniPick.poke_is_picker_active\n  return function()\n    local now = hrtime()\n    if (now - latest_time) < threshold then return true end\n    latest_time = now\n    -- Return positive if picker is active and no query updates (if asked)\n    return poke_is_picker_active() and (dont_check_querytick or querytick_ref == H.querytick)\n  end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.pick) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minipick://' .. buf_id .. '/' .. name) end\n\nH.notify = function(msg, level_name) vim.notify('(mini.pick) ' .. msg, vim.log.levels[level_name]) end\n\nH.edit = function(path, win_id)\n  if type(path) ~= 'string' then return end\n  local b = vim.api.nvim_win_get_buf(win_id or 0)\n  local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)\n    and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))\n  local buf_id = vim.fn.bufadd(vim.fn.fnamemodify(path, ':.'))\n  -- Showing in window also loads. Use `pcall` to not error with swap messages.\n  pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)\n  vim.bo[buf_id].buflisted = true\n  if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end\n  return buf_id\nend\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end\n\nH.is_array_of = function(x, ref_type)\n  if not H.islist(x) then return false end\n  for i = 1, #x do\n    if type(x[i]) ~= ref_type then return false end\n  end\n  return true\nend\n\nH.create_scratch_buf = function(name)\n  local buf_id = vim.api.nvim_create_buf(false, true)\n  H.set_buf_name(buf_id, name)\n  vim.bo[buf_id].matchpairs = ''\n  vim.b[buf_id].minicursorword_disable = true\n  vim.b[buf_id].miniindentscope_disable = true\n  return buf_id\nend\n\nH.get_first_valid_normal_window = function()\n  for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do\n    if vim.api.nvim_win_get_config(win_id).relative == '' then return win_id end\n  end\nend\n\nH.set_buflines = function(buf_id, lines) pcall(vim.api.nvim_buf_set_lines, buf_id, 0, -1, false, lines) end\n\nH.set_winbuf = function(win_id, buf_id) vim.api.nvim_win_set_buf(win_id, buf_id) end\n\nH.set_extmark = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end\n\nH.set_cursor = function(win_id, lnum, col) pcall(vim.api.nvim_win_set_cursor, win_id, { lnum or 1, (col or 1) - 1 }) end\n\nH.set_curwin = function(win_id)\n  if not H.is_valid_win(win_id) then return end\n  -- Explicitly preserve cursor to fix Neovim<0.10 after choosing position in\n  -- already shown buffer\n  local buf_id, cursor = vim.api.nvim_win_get_buf(win_id), vim.api.nvim_win_get_cursor(win_id)\n  vim.api.nvim_set_current_win(win_id)\n  if buf_id == vim.api.nvim_win_get_buf(win_id) then H.set_cursor(win_id, cursor[1], cursor[2] + 1) end\nend\n\nH.clear_namespace = function(buf_id, ns_id) pcall(vim.api.nvim_buf_clear_namespace, buf_id, ns_id, 0, -1) end\n\nH.replace_termcodes = function(x)\n  if x == nil then return nil end\n  return vim.api.nvim_replace_termcodes(x, true, true, true)\nend\n\nH.expand_callable = function(x, ...)\n  if vim.is_callable(x) then return x(...) end\n  return x\nend\n\nH.expandcmd = function(x)\n  local ok, res = pcall(vim.fn.expandcmd, x)\n  return ok and res or x\nend\n\nH.getcharstr = function(lmap)\n  H.cache.is_in_getcharstr = true\n  local ok, char = pcall(vim.fn.getcharstr)\n  H.cache.is_in_getcharstr = nil\n\n  -- Terminate if no input, on hard-coded <C-c>, or outside mouse click\n  local main_win_id\n  if H.pickers.active ~= nil then main_win_id = H.pickers.active.windows.main end\n  local is_bad_mouse_click = vim.v.mouse_winid ~= 0 and vim.v.mouse_winid ~= main_win_id\n  if not ok or char == '' or char == '\\3' or is_bad_mouse_click then return end\n  -- Respect language mappings only if needed\n  return vim.o.iminsert == 0 and char or (lmap[char] or char)\nend\n\nH.ensure_redraw = function(picker)\n  -- Ensure only one sequence of scheduled redraws\n  H.timers.redraw:stop()\n  local n = 0\n  local f = function()\n    vim.cmd('redraw')\n    -- Do several (but limited) `:redraw` for slow async changes\n    n = n + 1\n    if n >= 100 then H.timers.redraw:stop() end\n  end\n  H.timers.redraw:start(0, picker.opts.delay.async, vim.schedule_wrap(f))\nend\n\nH.tolower = (function()\n  -- Cache `tolower` for speed\n  local tolower = vim.fn.tolower\n  return function(x)\n    -- `vim.fn.tolower` can throw errors on bad string (like with '\\0')\n    local ok, res = pcall(tolower, x)\n    return ok and res or string.lower(x)\n  end\nend)()\n\nH.win_update_hl = function(win_id, new_from, new_to)\n  if not H.is_valid_win(win_id) then return end\n\n  local new_entry = new_from .. ':' .. new_to\n  local replace_pattern = string.format('(%s:[^,]*)', vim.pesc(new_from))\n  local new_winhighlight, n_replace = vim.wo[win_id].winhighlight:gsub(replace_pattern, new_entry)\n  if n_replace == 0 then new_winhighlight = new_winhighlight .. ',' .. new_entry end\n\n  vim.wo[win_id].winhighlight = new_winhighlight\nend\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.win_get_bottom_border = function(win_id, border_part_id)\n  local border = vim.api.nvim_win_get_config(win_id).border or {}\n  local res = border[border_part_id]\n  return (type(res) == 'table' and res[1] or res) or ' '\nend\n\nH.win_set_cwd = function(win_id, cwd)\n  -- Avoid needlessly setting cwd as it has side effects (like for `:buffers`)\n  if cwd == nil or vim.fn.getcwd(win_id or 0) == cwd then return end\n  local f = function() vim.cmd('lcd ' .. vim.fn.fnameescape(cwd)) end\n  if win_id == nil or win_id == vim.api.nvim_get_current_win() then return f() end\n  vim.api.nvim_win_call(win_id, f)\nend\n\nH.seq_along = function(arr)\n  if arr == nil then return nil end\n  local res = {}\n  for i = 1, #arr do\n    table.insert(res, i)\n  end\n  return res\nend\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.str_byteindex = function(s, i) return vim.str_byteindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_byteindex = function(s, i) return vim.str_byteindex(s, i) end end\n\nH.get_next_char_bytecol = function(line_str, col)\n  if type(line_str) ~= 'string' then return col end\n  local utf_index = H.str_utfindex(line_str, math.min(line_str:len(), col))\n  return H.str_byteindex(line_str, utf_index)\nend\n\nH.is_file_text = function(path)\n  local fd = vim.loop.fs_open(path, 'r', 1)\n  if fd == nil then return nil end\n  local is_text = vim.loop.fs_read(fd, 1024):find('\\0') == nil\n  vim.loop.fs_close(fd)\n  return is_text\nend\n\nH.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('(.)/$', '%1')) end\nif H.is_windows then\n  H.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('(.)[\\\\/]$', '%1')) end\nend\n\nH.parse_uri = function(x)\n  local ok, path = pcall(vim.uri_to_fname, x)\n  if not ok then return nil end\n  -- Don't accept Windows paths with volume letter as URI\n  if H.is_windows and x:find('^%a:') ~= nil and path:find('^%a:') ~= nil then return nil end\n  return path\nend\n\nH.user_input = function(prompt, text)\n  -- Use `on_key` to distinguish cancel with `<Esc>` and immediate `<CR>`\n  local was_cancelled = false\n  vim.on_key(function(key) was_cancelled = was_cancelled or key == '\\27' end, H.ns_id.input)\n\n  -- Ask for input. Use `pcall` to allow `<C-c>` to cancel user input\n  vim.cmd('echohl Question')\n  local ok, res = pcall(vim.fn.input, { prompt = '(mini.pick) ' .. prompt .. ': ', default = text or '' })\n  vim.cmd('echohl None | echo \"\" | redraw')\n\n  vim.on_key(nil, H.ns_id.input)\n  return (ok and not was_cancelled) and res or nil\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nH.get_lmap = function()\n  local lmap = {}\n  for _, map in ipairs(vim.fn.maplist()) do\n    -- NOTE: Account only for characters that resolve to proper query character\n    local is_query_lmap = map.mode == 'l' and H.is_query_char(map.rhs)\n    if is_query_lmap then lmap[map.lhs] = map.rhs end\n  end\n  return lmap\nend\nif vim.fn.has('nvim-0.10') == 0 then H.get_lmap = function() return {} end end\n\n-- A copy of `vim.deepcopy()` that doesn't error on userdata and threads\nH.copy_tables = function(x) return type(x) == 'table' and vim.tbl_map(H.copy_tables, x) or x end\n\nreturn MiniPick\n"
  },
  {
    "path": "lua/mini/sessions.lua",
    "content": "--- *mini.sessions* Session management\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Read, write, and delete sessions. Uses |:mksession| (meaning 'sessionoptions'\n--- is fully respected). This is intended as a drop-in Lua replacement for\n--- [mhinz/vim-startify](https://github.com/mhinz/vim-startify) session management\n--- (works out of the box with sessions created by it). Implements both global\n--- (from configured directory) and local (from current directory) sessions.\n---\n--- Key design ideas:\n--- - Sessions are represented by readable files (results of applying |:mksession|).\n---   There are two kinds of sessions:\n---     - Global: any file inside a configurable directory.\n---     - Local: configurable file inside current working directory (|getcwd()|).\n---\n--- - All session files are detected during `MiniSessions.setup()` and during\n---   relevant actions (`read`, `delete`, `select`) with file names as session\n---   names (including possible extension).\n---\n--- - No automated new session creation. Use |MiniSessions.write()| manually.\n---\n--- - Store information about detected sessions in separate table\n---   (|MiniSessions.detected|) and operate only on it. Meaning if this information\n---   changes, there will be no effect until next detection. To avoid confusion,\n---   don't directly use |:mksession| / |:source| for writing / reading session files.\n---\n--- Features:\n--- - Autoread default session (local if detected, else latest written global) if\n---   Neovim was called without intention to show something else.\n---\n--- - Autowrite currently read session before leaving it (quit Neovim or read\n---   another session).\n---\n--- - Configurable severity level of all actions.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.sessions').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniSessions` which you can use for scripting or manually (with\n--- `:lua MiniSessions.*`).\n---\n--- See |MiniSessions.config| for `config` structure and default values.\n---\n--- This module doesn't benefit from buffer local configuration, so using\n--- `vim.b.minisessions_config` will have no effect here.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.minisessions_disable` (globally) or\n--- `vim.b.minisessions_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniSessions\n\n-- Module definition ==========================================================\nlocal MiniSessions = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniSessions.config|.\n---\n---@usage >lua\n---   require('mini.sessions').setup() -- use default config\n---   -- OR\n---   require('mini.sessions').setup({}) -- replace {} with your config table\n--- <\nMiniSessions.setup = function(config)\n  -- Export module\n  _G.MiniSessions = MiniSessions\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniSessions.config = {\n  -- Whether to read default session if Neovim opened without file arguments\n  autoread = false,\n\n  -- Whether to write currently read session before leaving it\n  autowrite = true,\n\n  -- Directory where global sessions are stored (use `''` to disable)\n  --minidoc_replace_start directory = --<\"session\" subdir of user data directory from |stdpath()|>,\n  directory = vim.fn.stdpath('data') .. '/session',\n  --minidoc_replace_end\n\n  -- File for local session (use `''` to disable)\n  file = 'Session.vim',\n\n  -- Whether to force possibly harmful actions (meaning depends on function)\n  force = { read = false, write = true, delete = false },\n\n  -- Hook functions for actions. Default `nil` means 'do nothing'.\n  -- Takes table with active session data as argument.\n  hooks = {\n    -- Before successful action\n    pre = { read = nil, write = nil, delete = nil },\n    -- After successful action\n    post = { read = nil, write = nil, delete = nil },\n  },\n\n  -- Whether to print session path after action\n  verbose = { read = false, write = true, delete = true },\n}\n--minidoc_afterlines_end\n\n-- Module data ================================================================\n--- Table of detected sessions. Keys represent session name. Values are tables\n--- with session information that currently has these fields (but subject to\n--- change):\n--- - <modify_time> `(number)` modification time (see |getftime()|) of session file.\n--- - <name> `(string)` name of session (should be equal to table key).\n--- - <path> `(string)` full path to session file.\n--- - <type> `(string)` type of session ('global' or 'local').\nMiniSessions.detected = {}\n\n-- Module functionality =======================================================\n--- Read detected session\n---\n--- What it does:\n--- - If there is an active session and `autowrite` is `true` in |MiniSessions.config|,\n---   write it with |MiniSessions.write()|.\n--- - Delete all current buffers with |:bwipeout|. This is needed to correctly\n---   restore buffers from target session. If `force` is not `true`, checks\n---   beforehand for unsaved listed buffers and stops if there are any.\n--- - Source session with supplied name.\n---\n---@param session_name string|nil Name of detected session file to read. Default:\n---   `nil` for default session: local (if detected) or latest session (see\n---   |MiniSessions.get_latest()|).\n---@param opts table|nil Table with options. Current allowed keys:\n---   - <force> (whether to delete unsaved buffers; default:\n---     `MiniSessions.config.force.read`).\n---   - <verbose> (whether to print session path after action; default\n---     `MiniSessions.config.verbose.read`).\n---   - <hooks> (a table with <pre> and <post> function hooks to be executed\n---     with session data argument before and after successful read; overrides\n---     `MiniSessions.config.hooks.pre.read` and\n---     `MiniSessions.config.hooks.post.read`).\nMiniSessions.read = function(session_name, opts)\n  if H.is_disabled() then return end\n\n  -- Make sessions up to date\n  H.detect_sessions()\n  if vim.tbl_count(MiniSessions.detected) == 0 then\n    return H.message('There are no detected sessions. Change configuration and rerun `MiniSessions.setup()`.')\n  end\n\n  -- Get session data\n  if session_name == nil then\n    if MiniSessions.detected[MiniSessions.config.file] ~= nil then\n      session_name = MiniSessions.config.file\n    else\n      session_name = MiniSessions.get_latest()\n    end\n  end\n\n  opts = vim.tbl_deep_extend('force', H.default_opts('read'), opts or {})\n\n  if not H.validate_detected(session_name) then return end\n\n  local data = MiniSessions.detected[session_name]\n\n  -- Possibly check for unsaved listed buffers and do nothing if present\n  if not opts.force then\n    local unsaved_listed_buffers = H.get_unsaved_listed_buffers()\n\n    if #unsaved_listed_buffers > 0 then\n      local buf_list = table.concat(unsaved_listed_buffers, ', ')\n      H.error(('There are unsaved listed buffers: %s.'):format(buf_list))\n    end\n  end\n\n  -- Write current session to allow proper switching between sessions\n  if H.get_this_session() ~= '' and MiniSessions.config.autowrite then\n    MiniSessions.write(nil, { force = true, verbose = false })\n  end\n\n  -- Execute 'pre' hook\n  H.possibly_execute(opts.hooks.pre, data)\n\n  -- Wipeout all buffers\n  vim.cmd('silent! %bwipeout!')\n\n  -- Read session file\n  local session_path = data.path\n  vim.cmd(('silent! source %s'):format(vim.fn.fnameescape(session_path)))\n  vim.v.this_session = session_path\n\n  -- Possibly notify\n  if opts.verbose then H.message(('Read session %s'):format(session_path)) end\n\n  -- Ensure correct detected local session\n  H.detect_sessions()\n\n  -- Execute 'post' hook\n  H.possibly_execute(opts.hooks.post, data)\nend\n\n--- Write session\n---\n--- What it does:\n--- - Check if file for supplied session name already exists. If it does and\n---   `force` is not `true`, then stop.\n--- - Write session with |:mksession| to a file named `session_name`. Its\n---   directory is determined based on type of session:\n---     - It is at location |v:this_session| if `session_name` is `nil` and\n---       there is currently read session.\n---     - It is current working directory (|getcwd()|) if `session_name` is equal\n---       to `MiniSessions.config.file` (represents local session).\n---     - It is `MiniSessions.config.directory` otherwise (represents global\n---       session).\n--- - Update |MiniSessions.detected|.\n---\n---@param session_name string|nil Name of session file to write. Default: `nil` for\n---   currently read session (|v:this_session|).\n---@param opts table|nil Table with options. Current allowed keys:\n---   - <force> (whether to ignore existence of session file; default:\n---     `MiniSessions.config.force.write`).\n---   - <verbose> (whether to print session path after action; default\n---     `MiniSessions.config.verbose.write`).\n---   - <hooks> (a table with <pre> and <post> function hooks to be executed\n---     with session data argument before and after successful write; overrides\n---     `MiniSessions.config.hooks.pre.write` and\n---     `MiniSessions.config.hooks.post.write`).\nMiniSessions.write = function(session_name, opts)\n  if H.is_disabled() then return end\n\n  opts = vim.tbl_deep_extend('force', H.default_opts('write'), opts or {})\n\n  local session_path = H.name_to_path(session_name)\n\n  if not opts.force and H.is_readable_file(session_path) then\n    H.error([[Can't write to existing session when `opts.force` is not `true`.]])\n  end\n\n  local data = H.new_session(session_path)\n\n  -- Execute 'pre' hook\n  H.possibly_execute(opts.hooks.pre, data)\n\n  -- Make session file\n  local command = string.format('mksession%s %s', opts.force and '!' or '', vim.fn.fnameescape(session_path))\n  vim.cmd(command)\n  data.modify_time = vim.fn.getftime(session_path)\n\n  -- Update detected sessions\n  MiniSessions.detected[data.name] = data\n\n  -- Update current session\n  vim.v.this_session = session_path\n\n  -- Possibly notify\n  if opts.verbose then H.message(('Written session %s'):format(session_path)) end\n\n  -- Execute 'post' hook\n  H.possibly_execute(opts.hooks.post, data)\nend\n\n--- Delete detected session\n---\n--- What it does:\n--- - Check if session name is a current one. If yes and `force` is not `true`,\n---   then stop.\n--- - Delete session.\n--- - Update |MiniSessions.detected|.\n---\n---@param session_name string|nil Name of detected session file to delete. Default:\n---   `nil` for name of currently read session (taken from |v:this_session|).\n---@param opts table|nil Table with options. Current allowed keys:\n---   - <force> (whether to allow deletion of current session; default:\n---     `MiniSessions.config.force.delete`).\n---   - <verbose> (whether to print session path after action; default\n---     `MiniSessions.config.verbose.delete`).\n---   - <hooks> (a table with <pre> and <post> function hooks to be executed\n---     with session data argument before and after successful delete; overrides\n---     `MiniSessions.config.hooks.pre.delete` and\n---     `MiniSessions.config.hooks.post.delete`).\nMiniSessions.delete = function(session_name, opts)\n  if H.is_disabled() then return end\n  if vim.tbl_count(MiniSessions.detected) == 0 then\n    H.error('There are no detected sessions. Change configuration and rerun `MiniSessions.setup()`.')\n  end\n\n  opts = vim.tbl_deep_extend('force', H.default_opts('delete'), opts or {})\n\n  local session_path = H.name_to_path(session_name)\n\n  -- Make sessions up to date\n  H.detect_sessions()\n\n  -- Make sure to delete only detected session (matters for local session)\n  session_name = vim.fn.fnamemodify(session_path, ':t')\n  if not H.validate_detected(session_name) then return end\n  session_path = MiniSessions.detected[session_name].path\n\n  local is_current_session = session_path == H.get_this_session()\n  if not opts.force and is_current_session then\n    H.error([[Can't delete current session when `opts.force` is not `true`.]])\n  end\n\n  local data = MiniSessions.detected[session_name]\n\n  -- Execute 'pre' hook\n  H.possibly_execute(opts.hooks.pre, data)\n\n  -- Delete and update detected sessions\n  vim.fn.delete(session_path)\n  MiniSessions.detected[session_name] = nil\n  if is_current_session then vim.v.this_session = '' end\n\n  -- Possibly notify\n  if opts.verbose then H.message(('Deleted session %s'):format(session_path)) end\n\n  -- Execute 'pre' hook\n  H.possibly_execute(opts.hooks.post, data)\nend\n\n--- Select session interactively and perform action\n---\n--- Note: this uses |vim.ui.select()| function. For more user-friendly\n--- experience, override it (for example, see |MiniPick.ui_select()|).\n---\n---@param action string|nil Action to perform. Should be one of \"read\" (default),\n---   \"write\", or \"delete\".\n---@param opts table|nil Options for specified action.\nMiniSessions.select = function(action, opts)\n  if not (type(vim.ui) == 'table' and type(vim.ui.select) == 'function') then\n    H.error('`MiniSessions.select()` requires `vim.ui.select()` function.')\n  end\n\n  action = action or 'read'\n  if not vim.tbl_contains({ 'read', 'write', 'delete' }, action) then\n    H.error(\"`action` should be one of 'read', 'write', or 'delete'.\")\n  end\n\n  -- Make sessions up to date\n  H.detect_sessions()\n\n  -- Ensure consistent order of items\n  local detected = {}\n  for _, session in pairs(MiniSessions.detected) do\n    table.insert(detected, session)\n  end\n  local sort_fun = function(a, b)\n    -- Put local session first, others - increasing alphabetically\n    local a_name = a.type == 'local' and '' or a.name\n    local b_name = b.type == 'local' and '' or b.name\n    return a_name < b_name\n  end\n  table.sort(detected, sort_fun)\n  local detected_names = vim.tbl_map(function(x) return x.name end, detected)\n\n  vim.ui.select(detected_names, {\n    prompt = 'Select session to ' .. action,\n    format_item = function(x) return ('%s (%s)'):format(x, MiniSessions.detected[x].type) end,\n  }, function(item, idx)\n    if item == nil then return end\n    MiniSessions[action](item, opts)\n  end)\nend\n\n--- Get name of latest detected session\n---\n--- Latest session is the session with the latest modification time determined\n--- by |getftime()|.\n---\n---@return string|nil Name of latest session or `nil` if there is no sessions.\nMiniSessions.get_latest = function()\n  if vim.tbl_count(MiniSessions.detected) == 0 then return end\n\n  local latest_time, latest_name = -1, nil\n  for name, data in pairs(MiniSessions.detected) do\n    if data.modify_time > latest_time then\n      latest_time, latest_name = data.modify_time, name\n    end\n  end\n\n  return latest_name\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniSessions.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('autoread', config.autoread, 'boolean')\n  H.check_type('autowrite', config.autowrite, 'boolean')\n  H.check_type('directory', config.directory, 'string')\n  H.check_type('file', config.file, 'string')\n\n  H.check_type('force', config.force, 'table')\n  H.check_type('force.read', config.force.read, 'boolean')\n  H.check_type('force.write', config.force.write, 'boolean')\n  H.check_type('force.delete', config.force.delete, 'boolean')\n\n  H.check_type('hooks', config.hooks, 'table')\n  H.check_type('hooks.pre', config.hooks.pre, 'table')\n  H.check_type('hooks.pre.read', config.hooks.pre.read, 'function', true)\n  H.check_type('hooks.pre.write', config.hooks.pre.write, 'function', true)\n  H.check_type('hooks.pre.delete', config.hooks.pre.delete, 'function', true)\n  H.check_type('hooks.post', config.hooks.post, 'table')\n  H.check_type('hooks.post.read', config.hooks.post.read, 'function', true)\n  H.check_type('hooks.post.write', config.hooks.post.write, 'function', true)\n  H.check_type('hooks.post.delete', config.hooks.post.delete, 'function', true)\n\n  H.check_type('verbose', config.verbose, 'table')\n  H.check_type('verbose.read', config.verbose.read, 'boolean')\n  H.check_type('verbose.write', config.verbose.write, 'boolean')\n  H.check_type('verbose.delete', config.verbose.delete, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniSessions.config = config\n\n  H.detect_sessions(config)\nend\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniSessions', {})\n\n  if config.autoread then\n    local autoread = function()\n      if not H.is_something_shown() then MiniSessions.read() end\n    end\n    local opts = { group = gr, nested = true, once = true, callback = autoread, desc = 'Autoread latest session' }\n    vim.api.nvim_create_autocmd('VimEnter', opts)\n  end\n\n  if config.autowrite then\n    local autowrite = function()\n      if H.get_this_session() ~= '' then MiniSessions.write(nil, { force = true }) end\n    end\n    local opts = { group = gr, callback = autowrite, desc = 'Autowrite current session' }\n    vim.api.nvim_create_autocmd('VimLeavePre', opts)\n  end\nend\n\nH.is_disabled = function() return vim.g.minisessions_disable == true or vim.b.minisessions_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniSessions.config, vim.b.minisessions_config or {}, config or {})\nend\n\n-- Work with sessions ---------------------------------------------------------\nH.detect_sessions = function(config)\n  config = H.get_config(config)\n\n  local res_global = config.directory == '' and {} or H.detect_sessions_global(config.directory)\n  local res_local = config.file == '' and {} or H.detect_sessions_local(config.file)\n\n  -- If there are both local and global session with same name, prefer local\n  MiniSessions.detected = vim.tbl_deep_extend('force', res_global, res_local)\nend\n\nH.detect_sessions_global = function(global_dir)\n  -- Ensure correct directory path: create if doesn't exist\n  global_dir = H.full_path(global_dir)\n  if vim.fn.isdirectory(global_dir) ~= 1 then\n    local ok, _ = pcall(vim.fn.mkdir, global_dir, 'p')\n\n    if not ok then\n      H.message(('%s is not a directory path.'):format(vim.inspect(global_dir)))\n      return {}\n    end\n  end\n\n  -- Find global sessions\n  local res = {}\n  for name in vim.fs.dir(global_dir) do\n    local f = global_dir .. '/' .. name\n    if H.is_readable_file(f) then\n      local s = H.new_session(f, 'global')\n      res[s.name] = s\n    end\n  end\n  return res\nend\n\nH.detect_sessions_local = function(local_file)\n  local f = vim.fn.getcwd() .. '/' .. local_file\n  if not H.is_readable_file(f) then return {} end\n\n  local s = H.new_session(f, 'local')\n  return { [s.name] = s }\nend\n\nH.new_session = function(session_path, session_type)\n  return {\n    modify_time = vim.fn.getftime(session_path),\n    name = vim.fn.fnamemodify(session_path, ':t'),\n    path = H.full_path(session_path),\n    type = session_type or H.get_session_type(session_path),\n  }\nend\n\nH.get_session_type = function(session_path)\n  if MiniSessions.config.directory == '' then return 'local' end\n\n  local session_dir = H.full_path(session_path)\n  local global_dir = H.full_path(MiniSessions.config.directory)\n  return session_dir == global_dir and 'global' or 'local'\nend\n\nH.validate_detected = function(session_name)\n  local is_detected = vim.tbl_contains(vim.tbl_keys(MiniSessions.detected), session_name)\n  if is_detected then return true end\n\n  H.error(('%s is not a name for detected session.'):format(vim.inspect(session_name)))\nend\n\nH.get_unsaved_listed_buffers = function()\n  return vim.tbl_filter(\n    function(buf_id) return vim.bo[buf_id].modified and vim.bo[buf_id].buflisted end,\n    vim.api.nvim_list_bufs()\n  )\nend\n\nH.get_this_session = function() return vim.fs.normalize(vim.v.this_session) end\n\nH.name_to_path = function(session_name)\n  if session_name == nil then\n    local this_session = H.get_this_session()\n    if this_session == '' then H.error('There is no active session. Supply non-nil session name.') end\n    return this_session\n  end\n\n  session_name = tostring(session_name)\n  if session_name == '' then H.error('Supply non-empty session name.') end\n\n  local session_dir = (session_name == MiniSessions.config.file) and vim.fn.getcwd() or MiniSessions.config.directory\n  return H.full_path(session_dir .. '/' .. session_name)\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.sessions) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg, is_important)\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.sessions) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n  local chunks, tot_width = {}, 0\n  for _, ch in ipairs(msg) do\n    local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n    table.insert(chunks, new_ch)\n    tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n    if tot_width >= max_width then break end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, is_important, {})\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.default_opts = function(action)\n  local config = MiniSessions.config\n  return {\n    force = config.force[action],\n    verbose = config.verbose[action],\n    hooks = { pre = config.hooks.pre[action], post = config.hooks.post[action] },\n  }\nend\n\nH.is_readable_file = function(path) return vim.fn.isdirectory(path) ~= 1 and vim.fn.getfperm(path):sub(1, 1) == 'r' end\n\nH.full_path = function(path) return vim.fs.normalize(vim.fn.resolve(vim.fn.fnamemodify(path, ':p'))) end\n\nH.is_something_shown = function()\n  -- Don't autoread session if Neovim is opened to show something. That is\n  -- when at least one of the following is true:\n  -- - There are files in arguments (like `nvim foo.txt` with new file).\n  if vim.fn.argc() > 0 then return true end\n\n  -- - Several buffers are listed (like session with placeholder buffers). That\n  --   means unlisted buffers (like from `nvim-tree`) don't affect decision.\n  local listed_buffers = vim.tbl_filter(\n    function(buf_id) return vim.fn.buflisted(buf_id) == 1 end,\n    vim.api.nvim_list_bufs()\n  )\n  if #listed_buffers > 1 then return true end\n\n  -- - Current buffer is meant to show something else\n  if vim.bo.filetype ~= '' then return true end\n\n  -- - Current buffer has any lines (something opened explicitly).\n  -- NOTE: Usage of `line2byte(line('$') + 1) < 0` seemed to be fine, but it\n  -- doesn't work if some automated changed was made to buffer while leaving it\n  -- empty (returns 2 instead of -1). This was also the reason of not being\n  -- able to test with child Neovim process from 'tests/helpers'.\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  if n_lines > 1 then return true end\n  local first_line = vim.api.nvim_buf_get_lines(0, 0, 1, true)[1]\n  if string.len(first_line) > 0 then return true end\n\n  return false\nend\n\nH.possibly_execute = function(f, ...)\n  if f == nil then return end\n  return f(...)\nend\n\nreturn MiniSessions\n"
  },
  {
    "path": "lua/mini/snippets.lua",
    "content": "--- *mini.snippets* Manage and expand snippets\n---\n--- MIT License Copyright (c) 2024 Evgeni Chasnovski\n\n--- Snippet is a template for a frequently used text. Typical workflow is to type\n--- snippet's (configurable) prefix and expand it into a snippet session.\n---\n--- The template usually contains both pre-defined text and places (called\n--- \"tabstops\") for user to interactively change/add text during snippet session.\n---\n--- This module supports (only) snippet syntax defined in LSP specification (with\n--- small deviations). See |MiniSnippets-syntax-specification|.\n---\n--- Features:\n--- - Manage snippet collection by adding it explicitly or with a flexible set of\n---   performant built-in loaders. See |MiniSnippets.gen_loader|.\n---\n--- - Configured snippets are efficiently resolved before every expand based on\n---   current local context. This, for example, allows using different snippets\n---   in different local tree-sitter languages (like in markdown code blocks).\n---   See |MiniSnippets.default_prepare()|.\n---\n--- - Match which snippet to insert based on the currently typed text.\n---   Supports both exact and fuzzy matching. See |MiniSnippets.default_match()|.\n---\n--- - Select from several matched snippets via `vim.ui.select()`.\n---   See |MiniSnippets.default_select()|.\n---\n--- - Start specialized in-process LSP server to show loaded snippets inside\n---   (auto)completion engines (like |mini.completion|).\n---   See |MiniSnippets.start_lsp_server()|.\n---\n--- - Insert, jump, and edit during snippet session in a configurable manner:\n---     - Configurable mappings for jumping and stopping.\n---     - Jumping wraps around the tabstops for easier navigation.\n---     - Easy to reason rules for when session automatically stops.\n---     - Text synchronization of linked tabstops preserving relative indent.\n---     - Dynamic tabstop state visualization (current/visited/unvisited, etc.)\n---     - Inline visualization of empty tabstops (requires Neovim>=0.10).\n---     - Works inside comments by preserving comment leader on new lines.\n---     - Supports nested sessions (expand snippet while there is an active one).\n---   See |MiniSnippets.default_insert()|.\n---\n--- - Exported function to parse snippet body into easy-to-reason data structure.\n---   See |MiniSnippets.parse()|.\n---\n--- Notes:\n--- - It does not set up any snippet collection by default. Explicitly populate\n---   `config.snippets` to have snippets to match from.\n--- - It does not come with a built-in snippet collection. It is expected from\n---   users to add their own snippets, manually or with dedicated plugin(s).\n--- - It does not support variable/tabstop transformations in default snippet\n---   session. This requires ECMAScript Regular Expression parser which can not\n---   be implemented concisely.\n---\n--- Sources with more details:\n--- - |MiniSnippets-glossary|\n--- - |MiniSnippets-overview|\n--- - |MiniSnippets-examples|\n--- - |MiniSnippets-in-other-plugins| (for plugin authors)\n---\n--- # Dependencies ~\n---\n--- This module doesn't come with snippet collection. Either create it manually\n--- or install a dedicated plugin. For example,\n--- [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.snippets').setup({})` (replace `{}`\n--- with your `config` table). It will create global Lua table `MiniSnippets` which\n--- you can use for scripting or manually (with `:lua MiniSnippets.*`).\n---\n--- See |MiniSnippets.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minisnippets_config` which should have same structure as\n--- `MiniSnippets.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip):\n---     - Both contain functionality to load snippets from file system.\n---       This module provides several common loader generators while 'LuaSnip'\n---       contains a more elaborate loading setup.\n---       Also both require explicit opt-in for which snippets to load.\n---     - Both support LSP snippet format. 'LuaSnip' also provides own more\n---       elaborate snippet format which is out of scope for this module.\n---     - 'LuaSnip' can autoexpand snippets, while this module always requires\n---       an explicit user action to expand (by design).\n---     - Both contain snippet expand functionality which differs in some aspects:\n---         - 'LuaSnip' has an elaborate dynamic tabstop visualization config.\n---           This module provides a handful of dedicated highlight groups.\n---         - This module provides configurable visualization of empty tabstops.\n---         - 'LusSnip' implements nested sessions by essentially merging them\n---           into one. This module treats each nested session separately (to not\n---           visually overload) while storing them in stack (first in last out).\n---         - 'LuaSnip' uses |Select-mode| to power replacing current tabstop,\n---           while this module always stays in |Insert-mode|. This enables easier\n---           mapping understanding and more targeted highlighting.\n---         - This module implements jumping which wraps after final tabstop\n---           for more flexible navigation (enhanced with by a more flexible\n---           autostopping rules), while 'LuaSnip' autostops session once\n---           jumping reached the final tabstop.\n---\n--- - Built-in |vim.snippet| (on Neovim>=0.10):\n---     - Does not contain functionality to load or match snippets (by design),\n---       while this module does.\n---     - Both contain expand functionality based on LSP snippet format.\n---       Differences in how snippet sessions are handled are similar to\n---       comparison with 'LuaSnip'.\n---\n--- - [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets):\n---     - A snippet collection plugin without features to manage or expand them.\n---       This module is designed with 'friendly-snippets' compatibility in mind.\n---\n--- - [abeldekat/cmp-mini-snippets](https://github.com/abeldekat/cmp-mini-snippets):\n---     - A source for [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n---       that integrates 'mini.snippets'.\n---\n--- # Highlight groups ~\n---\n--- - `MiniSnippetsCurrent` - current tabstop.\n--- - `MiniSnippetsCurrentReplace` - current tabstop, placeholder is to be replaced.\n--- - `MiniSnippetsFinal` - special `$0` tabstop.\n--- - `MiniSnippetsUnvisited` - not yet visited tabstop(s).\n--- - `MiniSnippetsVisited` - visited tabstop(s).\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.minisnippets_disable` (globally) or\n--- `vim.b.minisnippets_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniSnippets\n\n--- POSITION ~\n--- Table representing position in a buffer. Fields:\n--- - <line> `(number)` - line number (starts at 1).\n--- - <col> `(number)` - column number (starts at 1).\n---\n--- REGION ~\n--- Table representing region in a buffer.\n--- Fields: <from> and <to> for inclusive start/end POSITIONs.\n---\n--- SNIPPET ~\n--- Data about template to insert. Should contain fields:\n--- - <prefix> - string snippet identifier.\n--- - <body> - string snippet content with appropriate syntax.\n--- - <desc> - string snippet description in human readable form.\n---\n--- Can also be used to mean snippet body if distinction is clear.\n---\n--- SNIPPET SESSION ~\n--- Interactive state for user to adjust inserted snippet.\n---\n--- MATCHED SNIPPET ~\n--- Snippet which contains <region> field with region that matched it.\n--- Usually region needs to be removed.\n---\n--- SNIPPET NODE ~\n--- Unit of parsed snippet body. See |MiniSnippets.parse()|.\n---\n--- TABSTOP ~\n--- Dedicated places in snippet body for users to interactively adjust.\n--- Specified in snippet body with `$` followed by digit(s).\n---\n--- LINKED TABSTOPS ~\n--- Different nodes assigned the same tabstop. Updated in sync.\n---\n--- REFERENCE NODE ~\n--- First (from left to right) node of linked tabstops. Used to determine\n--- synced text and cursor placement after jump.\n---\n--- EXPAND ~\n--- Action to start snippet session based on currently typed text.\n--- Always done in current buffer at cursor. Executed steps:\n--- - `PREPARE` - resolve raw config snippets at context.\n--- - `MATCH` - match resolved snippets at cursor position.\n--- - `SELECT` - possibly choose among matched snippets.\n--- - `INSERT` - insert selected snippet and start snippet session.\n---@tag MiniSnippets-glossary\n\n--- Snippet is a template for a frequently used text. Typical workflow is to type\n--- snippet's (configurable) prefix and expand it into a snippet session: add some\n--- pre-defined text and allow user to interactively change/add at certain places.\n---\n--- This overview assumes default config for mappings and expand.\n--- See |MiniSnippets.config| and |MiniSnippets-examples| for more details.\n---\n--- # Snippet structure ~\n---\n--- Snippet consists from three parts:\n--- - `Prefix` - identifier used to match against current text.\n--- - `Body` - actually inserted content with appropriate syntax.\n--- - `Desc` - description in human readable form.\n---\n--- Example: `{ prefix = 'tis', body = 'This is snippet', desc = 'Snip' }`\n--- Typing `tis` and pressing \"expand\" mapping (<C-j> by default) will remove \"tis\",\n--- add \"This is snippet\", and place cursor at the end in Insert mode.\n---\n--- # Syntax ~\n--- *MiniSnippets-syntax-specification*\n---\n--- Inserting just text after typing smaller prefix is already powerful enough.\n--- For more flexibility, snippet body can be formatted in a special way to\n--- provide extra features. This module implements support for syntax defined\n--- in LSP specification (with small deviations). See this link for reference:\n--- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#snippet_syntax\n---\n--- A quick overview of basic syntax features:\n---\n--- - Tabstops are snippet parts meant for interactive editing at their location.\n---   They are denoted as `$1`, `$2`, etc.\n---   Navigating between them is called \"jumping\" and is done in numerical order\n---   of tabstop identifiers by pressing special keys: <C-l> and <C-h> to jump\n---   to next and previous tabstop respectively.\n---   Special tabstop `$0` is called \"final tabstop\": it is used to decide when\n---   snippet session is automatically stopped and is visited last during jumping.\n---\n---   Example: `T1=$1 T2=$2 T0=$0` is expanded as `T1= T2= T0=` with three tabstops.\n---\n--- - Tabstop can have placeholder: a text used if tabstop is not yet edited.\n---   Text is preserved if no editing is done. It follows this same syntax, which\n---   means it can itself contain tabstops with placeholders (i.e. be nested).\n---   Tabstop with placeholder is denoted as `${1:placeholder}` (`$1` is `${1:}`).\n---\n---   Example: `T1=${1:text} T2=${2:<$1>}` is expanded as `T1=text T2=<text>`;\n---            typing `x` at first placeholder results in `T1=x T2=<x>`;\n---            jumping once and typing `y` results in `T1=x T2=y`.\n---\n--- - There can be several tabstops with same identifier. They are linked and\n---   updated in sync during text editing. Can also have different placeholders;\n---   they are forced to be the same as in the first (from left to right) tabstop.\n---\n---   Example: `T1=${1:text} T1=$1` is expanded as `T1=text T1=text`;\n---            typing `x` at first placeholder results in `T1=x T1=x`.\n---\n--- - Tabstop can also have choices: suggestions about tabstop text. It is denoted\n---   as `${1|a,b,c|}`. First choice is used as placeholder.\n---\n---   Example: `T1=${1|left,right|}` is expanded as `T1=left`.\n---\n--- - Variables can be used to automatically insert text without user interaction.\n---   As tabstops, each one can have a placeholder which is used if variable is\n---   not defined. There is a special set of variables describing editor state.\n---\n---   Example: `V1=$TM_FILENAME V2=${NOTDEFINED:placeholder}` is expanded as\n---            `V1=current-file-basename V2=placeholder`.\n---\n--- What's different from LSP specification:\n--- - Special set of variables is wider and is taken from VSCode specification:\n---   https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables\n---   Exceptions are `BLOCK_COMMENT_START` and `BLOCK_COMMENT_END` as Neovim doesn't\n---   provide this information.\n--- - Variable `TM_SELECTED_TEXT` is resolved as contents of |quote_quote| register.\n---   It assumes that text is put there prior to expanding. For example, visually\n---   select, press |c|, type prefix, and expand.\n---   See |MiniSnippets-examples| for how to adjust this.\n--- - Environment variables are recognized and supported: `V1=$VIMRUNTIME` will\n---   use an actual value of |$VIMRUNTIME|.\n--- - Variable transformations are not supported during snippet session. It would\n---   require interacting with ECMAScript-like regular expressions for which there\n---   is no easy way in Neovim. It may change in the future.\n---   Transformations are recognized during parsing, though, with some exceptions:\n---     - The `}` inside `if` of `${1:?if:else}` needs escaping (for technical reasons).\n---\n--- There is a |MiniSnippets.parse()| function for programmatically parsing\n--- snippet body into a comprehensible data structure.\n---\n--- # Expand ~\n---\n--- Using snippets is done via what is called \"expanding\". It goes like this:\n--- - Type snippet prefix or its recognizable part.\n--- - Press <C-j> to expand. It will perform the following steps:\n---     - Prepare available snippets in current context (buffer + local language).\n---       This allows snippet setup to have general function loaders which return\n---       different snippets in different contexts.\n---     - Match text to the left of cursor with available prefixes. It first tries\n---       to do exact match and falls back to fuzzy matching.\n---     - If there are several matches, use `vim.ui.select()` to choose one.\n---     - Insert single matching snippet. If snippet contains tabstops, start\n---       snippet session.\n---\n--- For more details about each step see:\n--- - |MiniSnippets.default_prepare()|\n--- - |MiniSnippets.default_match()|\n--- - |MiniSnippets.default_select()|\n--- - |MiniSnippets.default_insert()|\n---\n--- Snippet session allows interactive editing at tabstop locations:\n---\n--- - All tabstop locations are visualized depending on tabstop \"state\" (whether\n---   it is current/visited/unvisited/final and whether it was already edited).\n---   Empty tabstops are visualized with inline virtual text (\"•\"/\"∎\" for\n---   regular/final tabstops). It is removed after session is stopped.\n---\n--- - Start session at first tabstop. Type text to replace placeholder.\n---   When finished with current tabstop, jump to next with <C-l>. Repeat.\n---   If changed mind about some previous tabstop, jump back with <C-h>.\n---   Jumping also wraps around the edge (first tabstop is next after final).\n---\n--- - If tabstop has choices, use <C-n> / <C-p> to select next / previous item.\n---\n--- - Starting another snippet session while there is an active one is allowed.\n---   This creates nested sessions: suspend current, start the new one.\n---   After newly created is stopped, resume the suspended one.\n---\n--- - Stop session manually by pressing <C-c> or make it stop automatically:\n---   if final tabstop is current either make a text edit or exit to Normal mode.\n---   If snippet doesn't explicitly define final tabstop, it is added at the end\n---   of the snippet.\n---\n--- For more details about snippet session see |MiniSnippets-session|.\n---\n--- To select and insert snippets via completion engine (that supports LSP\n--- completion; like |mini.completion| or |lsp-autocompletion|),\n--- call |MiniSnippets.start_lsp_server()| after |MiniSnippets.setup()|. This sets up\n--- an LSP server that matches and provides snippets loaded with 'mini.snippets'.\n--- To match with completion engine, use `start_lsp_server({ match = false })`.\n---\n--- # Management ~\n---\n--- Out of the box 'mini.snippets' doesn't load any snippets, it should be done\n--- explicitly inside |MiniSnippets.setup()| following |MiniSnippets.config|.\n---\n--- The suggested approach to snippet management is to create dedicated files with\n--- snippet data and load them through function loaders in `config.snippets`.\n--- See |MiniSnippets-examples| for basic (yet capable) snippet management config.\n---\n--- ## File specification ~\n--- *MiniSnippets-file-specification*\n---\n--- General idea of supported files is to have at least out of the box experience\n--- with common snippet collections. Namely \"rafamadriz/friendly-snippets\".\n--- The following files are supported:\n---\n--- - Extensions:\n---     - Read/decoded as JSON object (|vim.json.decode()|): `*.json`, `*.code-snippets`\n---     - Executed as Lua file (|dofile()|) and uses returned value: `*.lua`\n---\n--- - Content:\n---     - Dict-like: object in JSON; returned table in Lua; no order guarantees.\n---     - Array-like: array in JSON; returned array table in Lua; preserves order.\n---\n--- Example of file content with a single snippet:\n--- - Lua dict-like:   `return { name = { prefix = 't', body = 'Text' } }`\n--- - Lua array-like:  `return { { prefix = 't', body = 'Text', desc = 'name' } }`\n--- - JSON dict-like:  `{ \"name\": { \"prefix\": \"t\", \"body\": \"Text\" } }`\n--- - JSON array-like: `[ { \"prefix\": \"t\", \"body\": \"Text\", \"desc\": \"name\" } ]`\n---\n--- Notes:\n--- - There is no built-in support for VSCode-like \"package.json\" files. Define\n---   structure manually in |MiniSnippets.setup()| via built-in or custom loaders.\n--- - There is no built-in support for `scope` field of snippet data. Snippets are\n---   expected to be manually separated into smaller files and loaded on demand.\n---\n--- For supported snippet syntax see |MiniSnippets-syntax-specification|.\n---\n--- ## General advice ~\n---\n--- - Put files in \"snippets\" subdirectory of any path in 'runtimepath' (like\n---   '`$XDG_CONFIG_HOME`/nvim/snippets/global.json').\n---   This is compatible with |MiniSnippets.gen_loader.from_runtime()| and\n---   example from |MiniSnippets-examples|.\n--- - Prefer `*.json` files with dict-like content if you want more cross platfrom\n---   setup. Otherwise use `*.lua` files with array-like content.\n--- - To implement \"dynamic snippet\" that changes data (usually <body>) depending\n---   on the context, use `*.lua` file with function returning snippet data.\n---   It should be an element in the output table (dict or array like).\n---\n--- # Demo ~\n---\n--- The best way to grasp the design of snippet management and expansion is to\n--- try them out yourself. Here are steps for a basic demo:\n--- - Create 'snippets/global.json' file in the config directory with the content: >json\n---\n---   {\n---     \"Basic\":        { \"prefix\": \"ba\", \"body\": \"T1=$1 T2=$2 T0=$0\"         },\n---     \"Placeholders\": { \"prefix\": \"pl\", \"body\": \"T1=${1:aa}\\nT2=${2:<$1>}\"  },\n---     \"Choices\":      { \"prefix\": \"ch\", \"body\": \"T1=${1|a,b|} T2=${2|c,d|}\" },\n---     \"Linked\":       { \"prefix\": \"li\", \"body\": \"T1=$1\\n\\tT1=$1\"            },\n---     \"Variables\":    { \"prefix\": \"va\", \"body\": \"Runtime: $VIMRUNTIME\\n\"    },\n---     \"Complex\":      {\n---       \"prefix\": \"co\",\n---       \"body\": [ \"T1=${1:$RANDOM}\", \"T3=${3:$1_${2:$1}}\", \"T2=$2\" ]\n---     }\n---   }\n--- <\n--- - Set up 'mini.snippets' as recommended in |MiniSnippets-examples|.\n--- - Open Neovim. Type each snippet prefix and press <C-j> (even if there is\n---   still active session). Explore from there.\n---@tag MiniSnippets-overview\n\n--- # Basic snippet management config ~\n---\n--- Example of snippet management setup that should cover most cases: >lua\n---\n---   -- Setup\n---   local gen_loader = require('mini.snippets').gen_loader\n---   require('mini.snippets').setup({\n---     snippets = {\n---       -- Load custom file with global snippets first\n---       gen_loader.from_file('~/.config/nvim/snippets/global.json'),\n---\n---       -- Load snippets based on current language by reading files from\n---       -- \"snippets/\" subdirectories from 'runtimepath' directories.\n---       gen_loader.from_lang(),\n---     },\n---   })\n--- <\n--- This setup allows having single file with custom \"global\" snippets (will be\n--- present in every buffer) and snippets which will be loaded based on the local\n--- language (see |MiniSnippets.gen_loader.from_lang()|).\n---\n--- Create language snippets manually (by creating and populating\n--- '`$XDG_CONFIG_HOME`/nvim/snippets/lua.json' file) or by installing dedicated\n--- snippet collection plugin (like 'rafamadriz/friendly-snippets').\n---\n--- Note: all built-in loaders and |MiniSnippets.read_file()| cache their output\n--- by default. It means that after a file is first read, changing it won't have\n--- effect during current Neovim session. See |MiniSnippets.gen_loader| about how\n--- to reset cache if necessary.\n---\n--- # Select from all available snippets in current context ~\n---\n--- With |MiniSnippets.default_match()|, expand snippets (<C-j> by default) at line\n--- start or after whitespace. To be able to always select from all current\n--- context snippets, make mapping similar to the following: >lua\n---\n---   local rhs = function() MiniSnippets.expand({ match = false }) end\n---   vim.keymap.set('i', '<C-g><C-j>', rhs, { desc = 'Expand all' })\n--- <\n--- # \"Supertab\"-like <Tab> / <S-Tab> mappings ~\n---\n--- This module intentionally by default uses separate keys to expand and jump as\n--- it enables cleaner use of nested sessions. Here is an example of setting up\n--- custom <Tab> to \"expand or jump\" and <S-Tab> to \"jump to previous\": >lua\n---\n---   local snippets = require('mini.snippets')\n---   local match_strict = function(snips)\n---     -- Do not match with whitespace to cursor's left\n---     return snippets.default_match(snips, { pattern_fuzzy = '%S+' })\n---   end\n---   snippets.setup({\n---     -- ... Set up snippets ...\n---     mappings = { expand = '', jump_next = '', jump_prev = '' },\n---     expand   = { match = match_strict },\n---   })\n---   local expand_or_jump = function()\n---     local can_expand = #MiniSnippets.expand({ insert = false }) > 0\n---     if can_expand then vim.schedule(MiniSnippets.expand); return '' end\n---     local is_active = MiniSnippets.session.get() ~= nil\n---     if is_active then MiniSnippets.session.jump('next'); return '' end\n---     return '\\t'\n---   end\n---   local jump_prev = function() MiniSnippets.session.jump('prev') end\n---   vim.keymap.set('i', '<Tab>', expand_or_jump, { expr = true })\n---   vim.keymap.set('i', '<S-Tab>', jump_prev)\n--- <\n--- # Stop session immediately after jumping to final tabstop ~\n---\n--- Utilize a dedicated |MiniSnippets-events|: >lua\n---\n---   local fin_stop = function(args)\n---     if args.data.tabstop_to == '0' then MiniSnippets.session.stop() end\n---   end\n---   local au_opts = { pattern = 'MiniSnippetsSessionJump', callback = fin_stop }\n---   vim.api.nvim_create_autocmd('User', au_opts)\n--- <\n--- # Stop all sessions on Normal mode exit ~\n---\n--- Use |ModeChanged| and |MiniSnippets-events| events: >lua\n---\n---   local make_stop = function()\n---     local au_opts = { pattern = '*:n', once = true }\n---     au_opts.callback = function()\n---       while MiniSnippets.session.get() do\n---         MiniSnippets.session.stop()\n---       end\n---     end\n---     vim.api.nvim_create_autocmd('ModeChanged', au_opts)\n---   end\n---   local opts = { pattern = 'MiniSnippetsSessionStart', callback = make_stop }\n---   vim.api.nvim_create_autocmd('User', opts)\n--- <\n--- # Customize variable evaluation ~\n---\n--- Create environment variables and `config.expand.insert` wrapper: >lua\n---\n---   -- Use evnironment variables with value is same for all snippet sessions\n---   vim.loop.os_setenv('USERNAME', 'user')\n---\n---   -- Compute custom lookup for variables with dynamic values\n---   local insert_with_lookup = function(snippet)\n---     local lookup = {\n---       TM_SELECTED_TEXT = table.concat(vim.fn.getreg('a', true, true), '\\n'),\n---     }\n---     return MiniSnippets.default_insert(snippet, { lookup = lookup })\n---   end\n---\n---   require('mini.snippets').setup({\n---     -- ... Set up snippets ...\n---     expand = { insert = insert_with_lookup },\n---   })\n--- <\n--- # Using Neovim's built-ins to insert snippet ~\n---\n--- Define custom `expand.insert` in |MiniSnippets.config| and mappings: >lua\n---\n---   require('mini.snippets').setup({\n---     -- ... Set up snippets ...\n---     expand = {\n---       insert = function(snippet, _) vim.snippet.expand(snippet.body) end\n---     }\n---   })\n---   -- Make jump mappings or skip to use built-in <Tab>/<S-Tab> in Neovim>=0.11\n---   local jump_next = function()\n---     if vim.snippet.active({direction = 1}) then return vim.snippet.jump(1) end\n---   end\n---   local jump_prev = function()\n---     if vim.snippet.active({direction = -1}) then vim.snippet.jump(-1) end\n---   end\n---   vim.keymap.set({ 'i', 's' }, '<C-l>', jump_next)\n---   vim.keymap.set({ 'i', 's' }, '<C-h>', jump_prev)\n--- <\n--- # Using 'mini.snippets' in other plugins ~\n--- *MiniSnippets-in-other-plugins*\n---\n--- - Perform a `_G.MiniSnippets ~= nil` check before using any feature. This\n---   ensures that user explicitly set up 'mini.snippets'.\n---\n--- - To insert snippet given its body (like |vim.snippet.expand()|), use: >lua\n---\n---      -- Use configured `insert` method with falling back to default\n---      local insert = MiniSnippets.config.expand.insert\n---        or MiniSnippets.default_insert\n---      -- Insert at cursor\n---      insert({ body = snippet })\n--- <\n--- - To get available snippets, use: >lua\n---\n---   -- Get snippets matched at cursor\n---   MiniSnippets.expand({ insert = false })\n---\n---   -- Get all snippets available at cursor context\n---   MiniSnippets.expand({ match = false, insert = false })\n--- <\n---@tag MiniSnippets-examples\n\n---@alias __minisnippets_cache_opt <cache> `(boolean)` - whether to use cached output. Default: `true`.\n---@alias __minisnippets_silent_opt <silent> `(boolean)` - whether to hide non-error messages. Default: `false`.\n---@alias __minisnippets_loader_return function Snippet loader.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniSnippets = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniSnippets.config|.\n---\n---@usage >lua\n---   require('mini.snippets').setup({}) -- replace {} with your config table\n---                                      -- needs `snippets` field present\n--- <\nMiniSnippets.setup = function(config)\n  -- Export module\n  _G.MiniSnippets = MiniSnippets\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Loaded snippets ~\n---\n--- `config.snippets` is an array containing snippet data which can be: snippet\n--- table, function loader, or (however deeply nested) array of snippet data.\n---\n--- Snippet is a table with the following fields:\n---\n--- - <prefix> `(string|table|nil)` - string used to match against current text.\n---    If array, all strings should be used as separate prefixes.\n--- - <body> `(string|table|nil)` - content of a snippet which should follow\n---    the |MiniSnippets-syntax-specification|. Array is concatenated with `\"\\n\"`.\n--- - <desc> `(string|table|nil)` - description of snippet. Can be used to display\n---   snippets in a more human readable form. Array is concatenated with `\"\\n\"`.\n---\n--- Function loaders are expected to be called with single `context` table argument\n--- (containing any data about current context) and return same as `config.snippets`\n--- data structure.\n---\n--- `config.snippets` is resolved with `config.prepare` on every expand.\n--- See |MiniSnippets.default_prepare()| for how it is done by default.\n---\n--- For a practical example see |MiniSnippets-examples|.\n--- Here is an illustration of `config.snippets` customization capabilities: >lua\n---\n---   local gen_loader = require('mini.snippets').gen_loader\n---   require('mini.snippets').setup({\n---     snippets = {\n---       -- Load custom file with global snippets first (order matters)\n---       gen_loader.from_file('~/.config/nvim/snippets/global.json'),\n---\n---       -- Or add them here explicitly\n---       { prefix='cdate', body='$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE' },\n---\n---       -- Load snippets based on current language by reading files from\n---       -- \"snippets/\" subdirectories from 'runtimepath' directories.\n---       gen_loader.from_lang(),\n---\n---       -- Load project-local snippets with `gen_loader.from_file()`\n---       -- and relative path (file doesn't have to be present)\n---       gen_loader.from_file('.vscode/project.code-snippets'),\n---\n---       -- Custom loader for language-specific project-local snippets\n---       function(context)\n---         local rel_path = '.vscode/' .. context.lang .. '.code-snippets'\n---         if vim.fn.filereadable(rel_path) == 0 then return end\n---         return MiniSnippets.read_file(rel_path)\n---       end,\n---\n---       -- Ensure that some prefixes are not used (as there is no `body`)\n---       { prefix = { 'bad', 'prefix' } },\n---     }\n---   })\n--- <\n--- # Mappings ~\n---\n--- `config.mappings` describes which mappings are automatically created.\n---\n--- `mappings.expand` is created globally in Insert mode and is used to expand\n--- snippet at cursor. Use |MiniSnippets.expand()| for custom mappings.\n---\n--- `mappings.jump_next`, `mappings.jump_prev`, and `mappings.stop` are created for\n--- the duration of active snippet session(s) from |MiniSnippets.default_insert()|.\n--- Used to jump to next/previous tabstop and stop active session respectively.\n--- Use |MiniSnippets.session.jump()| and |MiniSnippets.session.stop()| for custom\n--- Insert mode mappings.\n--- Note: do not use `\"<C-n>\"` or `\"<C-p>\"` for any action as they conflict with\n--- built-in completion: it forces them to mean \"change focus to next/previous\n--- completion item\". This matters more frequently than when there is a tabstop\n--- with choices due to how this module handles built-in completion during jumps.\n---\n--- # Expand ~\n---\n--- `config.expand` defines expand steps (see |MiniSnippets-glossary|), either after\n--- pressing `mappings.expand` or starting manually via |MiniSnippets.expand()|.\n---\n--- `expand.prepare` is a function that takes `raw_snippets` in the form of\n--- `config.snippets` and should return a plain array of snippets (as described\n--- in |MiniSnippets-glossary|). Will be called on every |MiniSnippets.expand()| call.\n--- If returns second value, it will be used as context for warning messages.\n--- Default: |MiniSnippets.default_prepare()|.\n---\n--- `expand.match` is a function that takes `expand.prepare` output and returns\n--- an array of matched snippets: one or several snippets user might intend to\n--- eventually insert. Should sort matches in output from best to worst.\n--- Entries can contain `region` field with current buffer region used to do\n--- the match; usually it needs to be removed (similar to how |ins-completion|\n--- and |abbreviations| work).\n--- Default: |MiniSnippets.default_match()|\n---\n--- `expand.select` is a function that takes output of `expand.match` and function\n--- that inserts snippet (and also ensures Insert mode and removes snippet's match\n--- region). Should allow user to perform interactive snippet selection and\n--- insert the chosen one. Designed to be compatible with |vim.ui.select()|.\n--- Called for any non-empty `expand.match` output (even with single entry).\n--- Default: |MiniSnippets.default_select()|\n---\n--- `expand.insert` is a function that takes single snippet table as input and\n--- inserts snippet at cursor position. This is a main entry point for adding\n--- text template to buffer and starting a snippet session.\n--- If called inside |MiniSnippets.expand()| (which is a usual interactive case),\n--- all it has to do is insert snippet at cursor position. Ensuring Insert mode\n--- and removing matched snippet region is done beforehand.\n--- Default: |MiniSnippets.default_insert()|\n---\n--- Illustration of `config.expand` customization: >lua\n---\n---   -- Supply extra data as context\n---   local my_p = function(raw_snippets)\n---     local _, cont = MiniSnippets.default_prepare({})\n---     cont.cursor = vim.api.nvim_win_get_cursor()\n---     return MiniSnippets.default_prepare(raw_snippets, { context = cont })\n---   end\n---   -- Perform fuzzy match based only on alphanumeric characters\n---   local my_m = function(snippets)\n---     return MiniSnippets.default_match(snippets, { pattern_fuzzy = '%w*' })\n---   end\n---   -- Always insert the best matched snippet\n---   local my_s = function(snippets, insert) return insert(snippets[1]) end\n---   -- Use different string to show empty tabstop as inline virtual text\n---   local my_i = function(snippet)\n---     return MiniSnippets.default_insert(snippet, { empty_tabstop = '$' })\n---   end\n---\n---   require('mini.snippets').setup({\n---     -- ... Set up snippets ...\n---     expand = { prepare = my_p, match = my_m, select = my_s, insert = my_i }\n---   })\n--- <\nMiniSnippets.config = {\n  -- Array of snippets and loaders (see |MiniSnippets.config| for details).\n  -- Nothing is defined by default. Add manually to have snippets to match.\n  snippets = {},\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Expand snippet at cursor position. Created globally in Insert mode.\n    expand = '<C-j>',\n\n    -- Interact with default `expand.insert` session.\n    -- Created for the duration of active session(s)\n    jump_next = '<C-l>',\n    jump_prev = '<C-h>',\n    stop = '<C-c>',\n  },\n\n  -- Functions describing snippet expansion. If `nil`, default values\n  -- are `MiniSnippets.default_<field>()`.\n  expand = {\n    -- Resolve raw config snippets at context\n    prepare = nil,\n    -- Match resolved snippets at cursor position\n    match = nil,\n    -- Possibly choose among matched snippets\n    select = nil,\n    -- Insert selected snippet\n    insert = nil,\n  },\n}\n--minidoc_afterlines_end\n\n--- Expand snippet at cursor position\n---\n--- Perform expand steps (see |MiniSnippets-glossary|).\n--- Initial raw snippets are taken from `config.snippets` in current buffer.\n--- Snippets from `vim.b.minisnippets_config` are appended to global snippet array.\n---\n---@param opts table|nil Options. Same structure as `expand` in |MiniSnippets.config|\n---   and uses its values as default. There are differences in allowed values:\n---   - Use `match = false` to have all buffer snippets as matches.\n---   - Use `select = false` to always expand the best match (if any).\n---   - Use `insert = false` to return all matches without inserting.\n---\n---   Note: `opts.insert` is called after ensuring Insert mode, removing snippet's\n---   match region, and positioning cursor.\n---\n---@return table|nil If `insert` is `false`, an array of matched snippets (`expand.match`\n---   output). Otherwise `nil`.\n---\n---@usage >lua\n---   -- Match, maybe select, and insert\n---   MiniSnippets.expand()\n---\n---   -- Match and force expand the best match (if any)\n---   MiniSnippets.expand({ select = false })\n---\n---   -- Use all current context snippets as matches\n---   MiniSnippets.expand({ match = false })\n---\n---   -- Get all matched snippets\n---   local matches = MiniSnippets.expand({ insert = false })\n---\n---   -- Get all current context snippets\n---   local all = MiniSnippets.expand({ match = false, insert = false })\n--- <\n---\n---@seealso |MiniSnippets.start_lsp_server()| to instead show loaded snippets\n---   in (auto)completion engines (like |mini.completion|).\nMiniSnippets.expand = function(opts)\n  if H.is_disabled() then return end\n  local config = H.get_config()\n  opts = vim.tbl_extend('force', config.expand, opts or {})\n\n  -- Validate\n  local prepare = opts.prepare or MiniSnippets.default_prepare\n  if not vim.is_callable(prepare) then H.error('`opts.prepare` should be callable') end\n\n  local match = false\n  if opts.match ~= false then match = opts.match or MiniSnippets.default_match end\n  if not (match == false or vim.is_callable(match)) then H.error('`opts.match` should be `false` or callable') end\n\n  local select = false\n  if opts.select ~= false then select = opts.select or MiniSnippets.default_select end\n  if not (select == false or vim.is_callable(select)) then H.error('`opts.select` should be `false` or callable') end\n\n  local insert = false\n  if opts.insert ~= false then insert = opts.insert or MiniSnippets.default_insert end\n  if not (insert == false or vim.is_callable(insert)) then H.error('`opts.insert` should be `false` or callable') end\n\n  -- Match\n  local all_snippets, context = prepare(config.snippets)\n  if not H.is_array_of(all_snippets, H.is_snippet) then H.error('`prepare` should return array of snippets') end\n  local matches = match == false and all_snippets or match(all_snippets)\n  if not H.is_array_of(matches, H.is_snippet) then H.error('`match` should return array of snippets') end\n\n  -- Act\n  if insert == false then return matches end\n  if #all_snippets == 0 then return H.notify('No snippets in context:\\n' .. vim.inspect(context), 'WARN') end\n  if #matches == 0 then return H.notify('No matches in context:\\n' .. vim.inspect(context), 'WARN') end\n\n  local insert_ext = H.make_extended_insert(insert)\n\n  if select == false then return insert_ext(matches[1]) end\n  select(matches, insert_ext)\nend\n\n--- Generate snippet loader\n---\n--- This is a table with function elements. Call to actually get a loader.\n---\n--- Common features for all produced loaders:\n--- - Designed to work with |MiniSnippets-file-specification|.\n--- - Cache output by default, i.e. second and later calls with same input value\n---   don't read file system. Different loaders from same generator share cache.\n---   Disable by setting `opts.cache` to `false`.\n---   To clear all cache, call |MiniSnippets.setup()|. For example:\n---   `MiniSnippets.setup(MiniSnippets.config)`\n--- - Use |vim.notify()| to show problems during loading while trying to load as\n---   much correctly defined snippet data as possible.\n---   Disable by setting `opts.silent` to `true`.\nMiniSnippets.gen_loader = {}\n\n--- Generate language loader\n---\n--- Output loads files from \"snippets/\" subdirectories of 'runtimepath' matching\n--- configured language patterns.\n--- See |MiniSnippets.gen_loader.from_runtime()| for runtime loading details.\n---\n--- Language is taken from <lang> field (if present with string value) of `context`\n--- argument used in loader calls during \"prepare\" stage.\n--- This is compatible with |MiniSnippets.default_prepare()| and most snippet\n--- collection plugins.\n---\n---@param opts table|nil Options. Possible values:\n---   - <lang_patterns> `(table)` - map from language to array of runtime patterns\n---     used to find snippet files, as in |MiniSnippets.gen_loader.from_runtime()|.\n---     Patterns will be processed in order. With |MiniSnippets.default_prepare()|\n---     it means if snippets have same prefix, data from later patterns is used.\n---     To interactively check the current language with default context, execute\n---     `:=MiniSnippets.default_prepare({})` and see data in the second table.\n---\n---     Default pattern array (for non-empty language) is constructed as to read\n---     `*.json` and `*.lua` files that are:\n---     - Inside \"snippets/\" subdirectory named as language (files can be however\n---       deeply nested).\n---     - Named as language and is in \"snippets/\" directory (however deep).\n---     Example for \"lua\" language: >lua\n---         { 'lua/**/*.json', 'lua/**/*.lua', '**/lua.json', '**/lua.lua' }\n--- <\n---     Add entry for `\"\"` (empty string) as language to be sourced when `lang`\n---     context is empty string (which is usually temporary scratch buffers).\n---\n---   - __minisnippets_cache_opt\n---     Note: caching is done per used runtime pattern, not `lang` value to allow\n---     different `from_lang()` loaders to share cache.\n---   - __minisnippets_silent_opt\n---\n---@return __minisnippets_loader_return\n---\n---@usage >lua\n---   -- Adjust language patterns\n---   local latex_patterns = { 'latex/**/*.json', '**/latex.json' }\n---   local lang_patterns = {\n---     tex = latex_patterns, plaintex = latex_patterns,\n---     -- Recognize special injected language of markdown tree-sitter parser\n---     markdown_inline = { 'markdown.json' },\n---   }\n---   local gen_loader = require('mini.snippets').gen_loader\n---   require('mini.snippets').setup({\n---     snippets = {\n---       gen_loader.from_lang({ lang_patterns = lang_patterns }),\n---     },\n---   })\n--- <\nMiniSnippets.gen_loader.from_lang = function(opts)\n  opts = vim.tbl_extend('force', { lang_patterns = {}, cache = true, silent = false }, opts or {})\n  for lang, tbl in pairs(opts.lang_patterns) do\n    if type(lang) ~= 'string' then H.error('Keys of `opts.lang_patterns` should be string language names') end\n    if not H.is_array_of(tbl, H.is_string) then H.error('Values of `opts.lang_patterns` should be string arrays') end\n  end\n\n  local loaders, loader_opts = {}, { cache = opts.cache, silent = opts.silent }\n\n  return function(context)\n    local lang = (context or {}).lang\n    if type(lang) ~= 'string' then return {} end\n\n    local patterns = opts.lang_patterns[lang]\n    if patterns == nil and lang == '' then return {} end\n    -- NOTE: Don't use `{json,lua}` for better compatibility, as it seems that\n    -- its support might depend on the shell (and might not work on Windows).\n    -- Which is shame because fewer patterns used mean fewer calls to cache.\n    patterns = patterns\n      or { lang .. '/**/*.json', lang .. '/**/*.lua', '**/' .. lang .. '.json', '**/' .. lang .. '.lua' }\n\n    local res = {}\n    for _, pat in ipairs(patterns) do\n      local loader = loaders[pat] or MiniSnippets.gen_loader.from_runtime(pat, loader_opts)\n      loaders[pat] = loader\n      table.insert(res, loader(context))\n    end\n    return res\n  end\nend\n\n--- Generate runtime loader\n---\n--- Output loads files which match `pattern` inside \"snippets/\" directories from\n--- 'runtimepath'. This is useful to simultaneously read several similarly\n--- named files from different sources. Order from 'runtimepath' is preserved.\n---\n--- Typical case is loading snippets for a language from files like `xxx.{json,lua}`\n--- but located in different \"snippets/\" directories inside 'runtimepath'.\n--- - `<config>`/snippets/lua.json - manually curated snippets in user config.\n--- - `<path/to/installed/plugin>`/snippets/lua.json - from installed plugin.\n--- - `<config>`/after/snippets/lua.json - used to adjust snippets from plugins.\n---   For example, remove some snippets by using prefixes and no body.\n---\n---@param pattern string Pattern of files to read. Can have wildcards as described\n---   in |nvim_get_runtime_file()|. Example for \"lua\" language: `'lua.{json,lua}'`.\n---@param opts table|nil Options. Possible fields:\n---   - <all> `(boolean)` - whether to load from all matching runtime files.\n---     Default: `true`.\n---   - __minisnippets_cache_opt\n---     Note: caching is done per `pattern` value, which assumes that both\n---     'runtimepath' value and snippet files do not change during Neovim session.\n---     Caching this way gives significant speed improvement by reducing the need\n---     to traverse file system on every snippet expand.\n---   - __minisnippets_silent_opt\n---\n---@return __minisnippets_loader_return\nMiniSnippets.gen_loader.from_runtime = function(pattern, opts)\n  if type(pattern) ~= 'string' then H.error('`pattern` should be string') end\n  opts = vim.tbl_extend('force', { all = true, cache = true, silent = false }, opts or {})\n\n  pattern = 'snippets/' .. pattern\n  local cache, read_opts = opts.cache, { cache = opts.cache, silent = opts.silent }\n  local read = function(p) return MiniSnippets.read_file(p, read_opts) end\n  return function()\n    if cache and H.cache.runtime[pattern] ~= nil then return vim.deepcopy(H.cache.runtime[pattern]) end\n\n    local res = vim.tbl_map(read, vim.api.nvim_get_runtime_file(pattern, opts.all))\n    if cache then H.cache.runtime[pattern] = vim.deepcopy(res) end\n    return res\n  end\nend\n\n--- Generate single file loader\n---\n--- Output is a thin wrapper around |MiniSnippets.read_file()| which will skip\n--- warning if file is absent (other messages are still shown). Use it to load\n--- file which is not guaranteed to exist (like project-local snippets).\n---\n---@param path string Same as in |MiniSnippets.read_file()|.\n---@param opts table|nil Same as in |MiniSnippets.read_file()|.\n---\n---@return __minisnippets_loader_return\nMiniSnippets.gen_loader.from_file = function(path, opts)\n  if type(path) ~= 'string' then H.error('`path` should be string') end\n  opts = vim.tbl_extend('force', { cache = true, silent = false }, opts or {})\n\n  return function()\n    local full_path = vim.fn.fnamemodify(path, ':p')\n    if vim.fn.filereadable(full_path) ~= 1 then return {} end\n    return MiniSnippets.read_file(full_path, opts) or {}\n  end\nend\n\n--- Read file with snippet data\n---\n---@param path string Path to file with snippets. Can be relative.\n---   See |MiniSnippets-file-specification| for supported file formats.\n---@param opts table|nil Options. Possible fields:\n---   - __minisnippets_cache_opt\n---     Note: Caching is done per full path only after successful reading.\n---   - __minisnippets_silent_opt\n---\n---@return table|nil Array of snippets or `nil` if failed (also warn with |vim.notify()|\n---   about the reason).\nMiniSnippets.read_file = function(path, opts)\n  if type(path) ~= 'string' then H.error('`path` should be string') end\n  opts = vim.tbl_extend('force', { cache = true, silent = false }, opts or {})\n\n  path = vim.fn.fnamemodify(path, ':p')\n  local problem_prefix = 'There were problems reading file ' .. path .. ':\\n'\n  if opts.cache and H.cache.file[path] ~= nil then return vim.deepcopy(H.cache.file[path]) end\n\n  if vim.fn.filereadable(path) ~= 1 then\n    return H.notify(problem_prefix .. 'File is absent or not readable', 'WARN', opts.silent)\n  end\n  local ext = path:match('%.([^%.]+)$')\n  if ext == nil or not (ext == 'lua' or ext == 'json' or ext == 'code-snippets') then\n    return H.notify(problem_prefix .. 'Extension is not supported', 'WARN', opts.silent)\n  end\n\n  local res = H.file_readers[ext](path, opts.silent)\n\n  -- Notify about problems but still cache if there are read snippets\n  local prob = table.concat(res.problems, '\\n')\n  if prob ~= '' then H.notify(problem_prefix .. prob, 'WARN', opts.silent) end\n\n  if res.snippets == nil then return nil end\n  if opts.cache then H.cache.file[path] = vim.deepcopy(res.snippets) end\n  return res.snippets\nend\n\n--- Default prepare\n---\n--- Normalize raw snippets (as in `snippets` from |MiniSnippets.config|) based on\n--- supplied context:\n--- - Traverse and flatten nested arrays. Function loaders are executed with\n---   `opts.context` as argument and output is processed recursively.\n--- - Ensure unique non-empty prefixes: later ones completely override earlier\n---   ones (similar to how |ftplugin| and similar runtime design behave).\n---   Empty string prefixes are all added (to allow inserting without matching).\n--- - Transform and infer fields:\n---     - Multiply array `prefix` into several snippets with same body/description.\n---       Infer absent `prefix` as empty string.\n---     - Concatenate array `body` with `\"\\n\"`. Do not infer absent `body` to have\n---       it remove previously added snippet with the same prefix.\n---     - Concatenate array `desc` with `\"\\n\"`. Infer `desc` field from `description`\n---       (for compatibility) or `body` fields, in that order.\n--- - Sort output by prefix.\n---\n--- Unlike |MiniSnippets.gen_loader| entries, there is no output caching. This\n--- avoids duplicating data from `gen_loader` cache and reduces memory usage.\n--- It also means that every |MiniSnippets.expand()| call prepares snippets, which\n--- is usually fast enough. If not, consider manual caching: >lua\n---\n---   local cache = {}\n---   local prepare_cached = function(raw_snippets)\n---     local _, cont = MiniSnippets.default_prepare({})\n---     local id = 'buf=' .. cont.buf_id .. ',lang=' .. cont.lang\n---     if cache[id] then return unpack(vim.deepcopy(cache[id])) end\n---     local snippets = MiniSnippets.default_prepare(raw_snippets)\n---     cache[id] = vim.deepcopy({ snippets, cont })\n---     return snippets, cont\n---   end\n--- <\n---@param raw_snippets table Array of snippet data as from |MiniSnippets.config|.\n---@param opts table|nil Options. Possible fields:\n---   - <context> `(any)` - Context used as an argument for callable snippet data.\n---     Default: table with <buf_id> (current buffer identifier) and <lang> (local\n---     language) fields. Language is computed from tree-sitter parser at cursor\n---     (allows different snippets in injected languages), 'filetype' otherwise.\n---\n---@return ... Array of snippets and supplied context (default if none was supplied).\nMiniSnippets.default_prepare = function(raw_snippets, opts)\n  if not H.islist(raw_snippets) then H.error('`raw_snippets` should be array') end\n  opts = vim.tbl_extend('force', { context = nil }, opts or {})\n  local context = opts.context\n  if context == nil then context = H.get_default_context() end\n\n  -- Traverse snippets to have unique non-empty prefixes\n  local res = {}\n  H.traverse_raw_snippets(raw_snippets, res, context)\n\n  -- Convert to array ordered by prefix\n  res = vim.tbl_values(res)\n  table.sort(res, function(a, b) return a.prefix < b.prefix end)\n  return res, context\nend\n\n--- Default match\n---\n--- Match snippets based on the line before cursor.\n---\n--- Tries two matching approaches consecutively:\n--- - Find exact snippet prefix (if present and non-empty) to the left of cursor.\n---   It should also be preceded with a byte that matches `pattern_exact_boundary`.\n---   In case of any match, return the one with the longest prefix.\n--- - Match fuzzily snippet prefixes against the base (text to the left of cursor\n---   extracted via `opts.pattern_fuzzy`). Matching is done via |matchfuzzy()|.\n---   Empty base results in all snippets being matched. Return all fuzzy matches.\n---\n---@param snippets table Array of snippets which can be matched.\n---@param opts table|nil Options. Possible fields:\n---   - <pattern_exact_boundary> `(string)` - Lua pattern for the byte to the left\n---     of exact match to accept it. Line start is matched against empty string;\n---     use `?` quantifier to allow it as boundary.\n---     Default: `[%s%p]?` (accept only whitespace and punctuation as boundary,\n---     allow match at line start).\n---     Example: prefix \"l\" matches in lines `l`, `_l`, `x l`; but not `1l`, `ll`.\n---   - <pattern_fuzzy> `(string)` - Lua pattern to extract base to the left of\n---     cursor for fuzzy matching. Supply empty string to skip this step.\n---     Default: `'%S*'` (as many as possible non-whitespace; allow empty string).\n---\n---@return table Array of matched snippets ordered from best to worst match.\n---\n---@usage >lua\n---   -- Accept any exact match\n---   MiniSnippets.default_match(snippets, { pattern_exact_boundary = '.?' })\n---\n---   -- Perform fuzzy match based only on alphanumeric characters\n---   MiniSnippets.default_match(snippets, { pattern_fuzzy = '%w*' })\n--- <\nMiniSnippets.default_match = function(snippets, opts)\n  if not H.is_array_of(snippets, H.is_snippet) then H.error('`snippets` should be array of snippets') end\n  opts = vim.tbl_extend('force', { pattern_exact_boundary = '[%s%p]?', pattern_fuzzy = '%S*' }, opts or {})\n  if not H.is_string(opts.pattern_exact_boundary) then H.error('`opts.pattern_exact_boundary` should be string') end\n\n  -- Compute line before cursor. Treat Insert mode as exclusive for right edge.\n  local lnum, col = vim.fn.line('.'), vim.fn.col('.')\n  local to = col - (vim.fn.mode() == 'i' and 1 or 0)\n  local line = vim.fn.getline(lnum):sub(1, to)\n\n  -- Exact. Use 0 as initial best match width to not match empty prefixes.\n  local best_id, best_match_width = nil, 0\n  local pattern_boundary = '^' .. opts.pattern_exact_boundary .. '$'\n  for i, s in pairs(snippets) do\n    local w = (s.prefix or ''):len()\n    if best_match_width < w and line:sub(-w) == s.prefix and line:sub(-w - 1, -w - 1):find(pattern_boundary) then\n      best_id, best_match_width = i, w\n    end\n  end\n  if best_id ~= nil then\n    local res = vim.deepcopy(snippets[best_id])\n    res.region = { from = { line = lnum, col = to - best_match_width + 1 }, to = { line = lnum, col = to } }\n    return { res }\n  end\n\n  -- Fuzzy\n  if not H.is_string(opts.pattern_fuzzy) then H.error('`opts.pattern_fuzzy` should be string') end\n  if opts.pattern_fuzzy == '' then return {} end\n\n  local base = string.match(line, opts.pattern_fuzzy .. '$')\n  if base == nil then return {} end\n  if base == '' then return vim.deepcopy(snippets) end\n\n  local snippets_with_prefix = vim.tbl_filter(function(s) return s.prefix ~= nil end, snippets)\n  local fuzzy_matches = vim.fn.matchfuzzy(snippets_with_prefix, base, { key = 'prefix' })\n  local from_col = to - base:len() + 1\n  for _, s in ipairs(fuzzy_matches) do\n    s.region = { from = { line = lnum, col = from_col }, to = { line = lnum, col = to } }\n  end\n\n  return fuzzy_matches\nend\n\n--- Default select\n---\n--- Show snippets as |vim.ui.select()| items and insert the chosen one.\n--- For best interactive experience requires `vim.ui.select()` to work from Insert\n--- mode (be properly called and restore Insert mode after choice).\n--- This is the case for at least |MiniPick.ui_select()| and Neovim's default.\n---\n---@param snippets table Array of snippets (as an output of `config.expand.match`).\n---@param insert function|nil Function to insert chosen snippet (passed as the only\n---   argument). Expected to remove snippet's match region (if present as a field)\n---   and ensure proper cursor position in Insert mode.\n---   Default: |MiniSnippets.default_insert()|.\n---@param opts table|nil Options. Possible fields:\n---   - <insert_single> `(boolean)` - whether to skip |vim.ui.select()| for `snippets`\n---     with a single entry and insert it directly. Default: `true`.\nMiniSnippets.default_select = function(snippets, insert, opts)\n  if not H.is_array_of(snippets, H.is_snippet) then H.error('`snippets` should be an array of snippets') end\n  if #snippets == 0 then return H.notify('No snippets to select from', 'WARN') end\n  insert = insert or MiniSnippets.default_insert\n  if not vim.is_callable(insert) then H.error('`insert` should be callable') end\n  opts = opts or {}\n\n  if #snippets == 1 and (opts.insert_single == nil or opts.insert_single == true) then\n    insert(snippets[1])\n    return\n  end\n\n  -- Format\n  local prefix_width = 0\n  for i, s in ipairs(snippets) do\n    local prefix = s.prefix or '<No prefix>'\n    prefix_width = math.max(prefix_width, vim.fn.strdisplaywidth(prefix))\n  end\n  local format_item = function(s)\n    local prefix, desc = s.prefix or '<No prefix>', s.desc or s.description or '<No description>'\n    local pad = string.rep(' ', prefix_width - vim.fn.strdisplaywidth(prefix))\n    return prefix .. pad .. ' │ ' .. desc\n  end\n\n  -- Schedule insert to allow `vim.ui.select` override to restore window/cursor\n  local on_choice = vim.schedule_wrap(function(item, _) insert(item) end)\n  vim.ui.select(snippets, { prompt = 'Snippets', format_item = format_item }, on_choice)\nend\n\n--- Default insert\n---\n--- Prepare for snippet insert and do it:\n--- - Ensure Insert mode.\n--- - Delete snippet's match region (if present as <region> field). Ensure cursor.\n--- - Parse snippet body with |MiniSnippets.parse()| and enabled `normalize`.\n---   In particular, evaluate variables, ensure final node presence and same\n---   text for nodes with same tabstops. Stop if not able to.\n--- - Insert snippet at cursor:\n---     - Add snippet's text. Lines are split at \"\\n\".\n---       Indent and left comment leaders (inferred from 'commentstring' and\n---       'comments') of current line are repeated on the next.\n---       Tabs (\"\\t\") are expanded according to 'expandtab' and 'shiftwidth'.\n---     - If there is an actionable tabstop (not final), start snippet session.\n---\n--- # Session life cycle ~\n--- *MiniSnippets-session*\n---\n--- - Start with cursor at first tabstop. If there are linked tabstops, cursor\n---   is placed at start of reference node (see |MiniSnippets-glossary|).\n---   All tabstops are visualized with dedicated highlight groups (see \"Highlight\n---   groups\" section in |mini.snippets|).\n---   Empty tabstops are visualized with inline virtual text (\"•\"/\"∎\" for\n---   regular/final tabstops) meaning that it is not an actual text in the\n---   buffer and will be removed after session is stopped.\n---\n--- - Decide whether you want to replace the placeholder. If not, jump to next or\n---   previous tabstop. If yes, edit it: add new and/or delete already added text.\n---   While doing so, several things happen in all linked tabstops (if any):\n---\n---     - After first typed character the placeholder is removed and highlighting\n---       changes from `MiniSnippetsCurrentReplace` to `MiniSnippetsCurrent`.\n---     - Text in all tabstop nodes is synchronized with the reference one.\n---       Relative indent of reference tabstop's text is preserved: all but first\n---       lines in linked tabstops are reindented based on the first line indent.\n---       Note: text sync is forced only for current tabstop (for performance).\n---\n--- - Jump with <C-l> / <C-h> to next / previous tabstop. Exact keys can be\n---   adjusted in |MiniSnippets.config| `mappings`.\n---   See |MiniSnippets.session.jump()| for jumping details.\n---\n--- - If tabstop has choices, all of them are shown after each jump and deleting\n---   tabstop text. It is done with |complete()|, so use <C-n> / <C-p> to select\n---   next / previous choice. Type text to narrow down the list.\n---   Works best when 'completeopt' option contains `menuone` and `noselect` flags.\n---   Note: deleting character hides the list due to how |complete()| works;\n---   delete whole tabstop text (for example with one or more |i_CTRL-W|) for\n---   full list to reappear.\n---\n--- - Nest another session by expanding snippet in the same way as without\n---   active session (can be even done in another buffer). If snippet has no\n---   actionable tabstop, text is just inserted. Otherwise start nested session:\n---\n---     - Suspend current session: hide highlights, keep text change tracking.\n---     - Start new session and act as if it is the only one (edit/jump/nest).\n---     - When ready (possibly after even more nested sessions), stop the session.\n---       This will resume previous one: sync text for its current tabstop and\n---       show highlighting.\n---       The experience of text synchronization only after resuming session is\n---       similar to how editing in |visual-block| mode works.\n---       Nothing else (like cursor/mode/buffer) is changed for a smoother\n---       automated session stop.\n---\n---   Notes about the choice of the \"session stack\" approach to nesting over more\n---   common \"merge into single session\" approach:\n---   - Does not overload with highlighting.\n---   - Allows nested sessions in different buffers.\n---   - Doesn't need a complex logic of injecting one session into another.\n---\n--- - Repeat edit/jump/nest steps any number of times.\n---\n--- - Stop. It can be done in two ways:\n---\n---     - Manually by pressing <C-c> or calling |MiniSnippets.session.stop()|.\n---       Exact key can be adjusted in |MiniSnippets.config| `mappings`.\n---     - Automatically: any text edit or switching to Normal mode stops session\n---       if final tabstop (`$0`) is current. Its presence is ensured after insert.\n---       Not stopping session right away after jumping to final mode (as most\n---       other snippet plugins do) allows going back to other tabstops in case\n---       of a late missed typo. Wrapping around the edge during jumping also\n---       helps with that.\n---       If current tabstop is not final, exiting into Normal mode for quick edit\n---       outside of snippets range (or carefully inside) is fine. Later get back\n---       into Insert mode and jump to next tabstop or manually stop session.\n---   See |MiniSnippets-examples| for how to set up custom stopping rules.\n---\n--- Use |MiniSnippets.session.get()| to get data about active/nested session(s).\n--- Use |MiniSnippets.session.jump()| / |MiniSnippets.session.stop()| in mappings.\n---\n--- What is allowed but not officially supported/recommended:\n---\n--- - Editing text within snippet range but outside of session life cycle. Mostly\n---   behaves as expected, but may harm tracking metadata (|extmarks|).\n---   In general anything but deleting tabstop range should be OK.\n---   Text synchronization of current tabstop would still be active.\n---\n--- # Events ~\n--- *MiniSnippets-events*\n---\n--- General session activity (autocommand data contains <session> field):\n--- - `MiniSnippetsSessionStart` - after a session is started.\n--- - `MiniSnippetsSessionStop` - before a session is stopped.\n---\n--- Nesting session activity (autocommand data contains <session> field):\n--- - `MiniSnippetsSessionSuspend` - before a session is suspended.\n--- - `MiniSnippetsSessionResume` - after a session is resumed.\n---\n--- Jumping between tabstops (autocommand data contains <tabstop_from> and\n--- <tabstop_new> fields):\n--- - `MiniSnippetsSessionJumpPre` - before jumping to a new tabstop.\n--- - `MiniSnippetsSessionJump` - after jumping to a new tabstop.\n---\n---@param snippet table Snippet table. Field <body> is mandatory.\n---@param opts table|nil Options. Possible fields:\n---   - <empty_tabstop> `(string)` - used to visualize empty regular tabstops.\n---     Default: \"•\".\n---   - <empty_tabstop_final> `(string)` - used to visualize empty final tabstop(s).\n---     Default: \"∎\".\n---   - <lookup> `(table)` - passed to |MiniSnippets.parse()|. Use it to adjust\n---     how variables are evaluated. Default: `{}`.\nMiniSnippets.default_insert = function(snippet, opts)\n  if not H.is_snippet(snippet) then H.error('`snippet` should be a snippet table') end\n\n  local default_opts = { empty_tabstop = '•', empty_tabstop_final = '∎', lookup = {} }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n  if not H.is_string(opts.empty_tabstop) then H.error('`empty_tabstop` should be string') end\n  if not H.is_string(opts.empty_tabstop_final) then H.error('`empty_tabstop_final` should be string') end\n  if type(opts.lookup) ~= 'table' then H.error('`lookup` should be table') end\n\n  local nodes = MiniSnippets.parse(snippet.body, { normalize = true, lookup = opts.lookup })\n\n  -- Ensure insert in Insert mode (for proper cursor positioning at EOL)\n  H.call_in_insert_mode(function()\n    H.delete_region(snippet.region)\n    H.session_init(H.session_new(nodes, snippet, opts), true)\n  end)\nend\n\n--- Work with snippet session from |MiniSnippets.default_insert()|\nMiniSnippets.session = {}\n\n--- Get data about active session\n---\n---@param all boolean|nil Whether to return array with the whole session stack.\n---   Default: `false`.\n---\n---@return table Single table with session data (if `all` is `false`) or array of them.\n---   Session data contains the following fields:\n---    - <buf_id> `(number)` - identifier of session's buffer.\n---    - <cur_tabstop> `(string)` - identifier of session's current tabstop.\n---    - <extmark_id> `(number)` - |extmark| identifier which track session range.\n---    - <insert_args> `(table)` - |MiniSnippets.default_insert()| arguments used to\n---      create the session. A table with <snippet> and <opts> fields.\n---    - <nodes> `(table)` - parsed array of snippet nodes which is kept up to date\n---      during session. Has the structure of a normalized |MiniSnippets.parse()|\n---      output, plus every node contains `extmark_id` field with |extmark| identifier\n---      which can be used to get data about the current node state.\n---    - <ns_id> `(number)` - |namespace| identifier for all session's extmarks.\n---    - <tabstops> `(table)` - data about session's tabstops. Fields are string\n---      tabstop identifiers and values are tables with the following fields:\n---        - <is_visited> `(boolean)` - whether tabstop was visited.\n---        - <next> `(string)` - identifier of the next tabstop.\n---        - <prev> `(string)` - identifier of the previous tabstop.\nMiniSnippets.session.get = function(all) return vim.deepcopy(all and H.sessions or H.get_active_session()) end\n\n--- Jump to next/previous tabstop\n---\n--- Make next/previous tabstop be current. Executes the following steps:\n--- - Mark current tabstop as visited.\n--- - Find the next/previous tabstop id assuming they are sorted as numbers.\n---   Tabstop \"0\" is always last. Search is wrapped around the edges: first and\n---   final tabstops are next/previous for one another.\n--- - Focus on target tabstop:\n---     - Ensure session's buffer is current.\n---     - Adjust highlighting of affected nodes.\n---     - Set cursor at tabstop's reference node (first node among linked).\n---       Cursor is placed on left edge if tabstop has not been edited yet (so\n---       typing text replaces placeholder), on right edge otherwise (to update\n---       already edited text).\n---     - Show all choices for tabstop with choices. Navigating through choices\n---       will update tabstop's text.\n---\n---@param direction string One of \"next\" or \"prev\".\nMiniSnippets.session.jump = function(direction)\n  if not (direction == 'prev' or direction == 'next') then H.error('`direction` should be one of \"prev\", \"next\"') end\n  H.call_in_insert_mode(function() H.session_jump(H.get_active_session(), direction) end)\nend\n\n--- Stop (only) active session\n---\n--- To stop all nested sessions use the following code: >lua\n---\n---   while MiniSnippets.session.get() do\n---     MiniSnippets.session.stop()\n---   end\n--- <\nMiniSnippets.session.stop = function()\n  local cur_session = H.get_active_session()\n  if cur_session == nil then return end\n  H.session_deinit(cur_session, true)\n  H.sessions[#H.sessions] = nil\n  if #H.sessions == 0 then\n    vim.api.nvim_del_augroup_by_name('MiniSnippetsTrack')\n    H.unmap_in_sessions()\n  end\n  H.clean_sessions()\n  H.session_init(H.get_active_session(), false)\nend\n\n--- Parse snippet\n---\n---@param snippet_body string|table Snippet body as string or array of strings.\n---   Should follow |MiniSnippets-syntax-specification|.\n---@param opts table|nil Options. Possible fields:\n---   - <normalize> `(boolean)` - whether to normalize nodes:\n---     - Evaluate variable nodes and add output as a `text` field.\n---       If variable is not set, `text` field is `nil`.\n---       Values from `opts.lookup` are preferred over evaluation output.\n---       See |MiniSnippets-syntax-specification| for more info about variables.\n---     - Add `text` field for tabstops present in `opts.lookup`.\n---     - Ensure every node contains exactly one of `text` or `placeholder` fields.\n---       If there are none, add default `placeholder` (one text node with first\n---       choice or empty string). If there are both, remove `placeholder` field.\n---     - Ensure present final tabstop: append to end if absent.\n---     - Ensure that nodes for same tabstop have same placeholder. Use the one\n---       from the first node.\n---     Default: `false`.\n---   - <lookup> `(table)` - map from variable/tabstop (string) name to its value.\n---     Default: `{}`.\n---\n---@return table Array of nodes. Node is a table with fields depending on node type:\n---   - Text node:\n---     - <text> `(string)` - node's text.\n---   - Tabstop node:\n---     - <tabstop> `(string)` - tabstop identifier.\n---     - <text> `(string|nil)` - tabstop value (if present in <lookup>).\n---     - <placeholder> `(table|nil)` - array of nodes to be used as placeholder.\n---     - <choices> `(table|nil)` - array of string choices.\n---     - <transform> `(table|nil)` - array of transformation string parts.\n---   - Variable node:\n---     - <var> `(string)` - variable name.\n---     - <text> `(string|nil)` - variable value.\n---     - <placeholder> `(table|nil)` - array of nodes to be used as placeholder.\n---     - <transform> `(table|nil)` - array of transformation string parts.\nMiniSnippets.parse = function(snippet_body, opts)\n  if H.is_array_of(snippet_body, H.is_string) then snippet_body = table.concat(snippet_body, '\\n') end\n  if type(snippet_body) ~= 'string' then H.error('Snippet body should be string or array of strings') end\n\n  opts = vim.tbl_extend('force', { normalize = false, lookup = {} }, opts or {})\n\n  -- Overall idea: implement a state machine which updates on every character.\n  -- This leads to a bit spaghetti code, but doesn't require `vim.lpeg` DSL\n  -- knowledge and can provide more information in error messages.\n  -- Output is array of nodes representing the snippet body.\n  -- Format is mostly based on grammar in LSP spec 3.18 with small differences.\n\n  -- State table. Each future string is tracked as array and merged later.\n  --stylua: ignore\n  local state = {\n    name = 'text',\n    -- Node array for depths of currently processed nested placeholders.\n    -- Depth 1 is the original snippet.\n    depth_arrays = { { { text = {} } } },\n    set_name = function(self, name) self.name = name; return self end,\n    add_node = function(self, node) table.insert(self.depth_arrays[#self.depth_arrays], node); return self end,\n    set_in = function(self, node, field, value) node[field] = value; return self end,\n    is_not_top_level = function(self) return #self.depth_arrays > 1 end,\n  }\n\n  for i = 0, vim.fn.strchars(snippet_body) - 1 do\n    -- Infer helper data (for more concise manipulations inside processor)\n    local depth = #state.depth_arrays\n    local arr = state.depth_arrays[depth]\n    local processor, node = H.parse_processors[state.name], arr[#arr]\n    processor(vim.fn.strcharpart(snippet_body, i, 1), state, node)\n  end\n\n  -- Verify, post-process, normalize\n  H.parse_verify(state)\n  local nodes = H.parse_post_process(state.depth_arrays[1], state.name)\n  return opts.normalize and H.parse_normalize(nodes, opts) or nodes\nend\n\n--- Start completion LSP server\n---\n--- This starts (|vim.lsp.start()|) an LSP server with the purpose of displaying\n--- snippets in (auto)completion engines (|mini.completion| in particular).\n--- The server:\n--- - Only implements `textDocument/completion` method which prepares and matches\n---   snippets at cursor (via |MiniSnippets.expand()|).\n--- - Auto-attaches to all loaded buffers by default.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <before_attach> `(function)` - function executed before every attach to\n---     the buffer. Takes buffer id as input and can return `false` (not `nil`) to\n---     cancel attaching to the buffer. Default: attach to loaded normal buffers.\n---   - <match> `(false|function)` - value of `opts.match` forwarded to\n---     the |MiniSnippets.expand()| when computing completion candidates.\n---     Supply `false` to not do matching at cursor, return all available snippets\n---     in cursor context, and rely on completion engine to match and sort items.\n---     Default: `nil` (equivalent to |MiniSnippets.default_match()|).\n---   - <server_config> `(table)` - server config to be used as basis for first\n---     argument to |vim.lsp.start()| (`cmd` will be overridden). Default: `{}`.\n---   - <triggers> `(table)` - array of trigger characters to be used as\n---     `completionProvider.triggerCharacters` server capability. Default: `{}`.\n---\n---@return integer|nil Identifier of started LSP server.\nMiniSnippets.start_lsp_server = function(opts)\n  local default_opts = { before_attach = H.lsp_default_before_attach, match = nil, server_config = {}, triggers = {} }\n  opts = vim.tbl_extend('force', default_opts, opts or {})\n  H.check_type('opts.before_attch', opts.before_attach, 'callable')\n  H.check_type('opts.server_config', opts.server_config, 'table')\n  H.check_type('opts.triggers', opts.triggers, 'table')\n\n  local config = vim.deepcopy(opts.server_config)\n  -- NOTE: set `root_dir` for a working `reuse_client` on Neovim<0.11\n  config.name, config.root_dir = config.name or 'mini.snippets', config.root_dir or vim.fn.getcwd()\n  config.cmd = H.lsp_make_cmd(opts)\n  local ok, client_id = pcall(vim.lsp.start, config, { attach = false })\n  if not (ok and type(client_id) == 'number') then H.error(\"Could not start 'mini.snippets' in-process LSP server\") end\n  if vim.fn.has('nvim-0.11') == 0 then pcall(vim.lsp.buf_detach_client, 0, client_id) end\n\n  local attach = function(buf_id)\n    if not vim.api.nvim_buf_is_valid(buf_id) or opts.before_attach(buf_id) == false then return end\n    vim.lsp.buf_attach_client(buf_id, client_id)\n  end\n  for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n    attach(buf_id)\n  end\n\n  local gr = vim.api.nvim_create_augroup('MiniSnippetsLsp', {})\n  -- NOTE: schedule to auto-attach only on explicit buffer ente (not temporary\n  -- from script) and have buffer properties (like 'filetype') set up.\n  local auto_attach = vim.schedule_wrap(function(ev)\n    if ev.buf ~= vim.api.nvim_get_current_buf() then return end\n    attach(ev.buf)\n  end)\n  vim.api.nvim_create_autocmd('BufEnter', { callback = auto_attach, desc = \"Auto attach 'mini.snippets' LSP server\" })\n\n  return client_id\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniSnippets.config)\n\n-- Namespaces for extmarks\nH.ns_id = {\n  nodes = vim.api.nvim_create_namespace('MiniSnippetsNodes'),\n}\n\n-- Array of current (nested) snippet sessions from `default_insert`\nH.sessions = {}\n\n-- Various cache\nH.cache = {\n  -- Loaders output\n  runtime = {},\n  file = {},\n  -- Data for possibly overridden session mappings\n  mappings = {},\n}\n\n-- Capabilties of current Neovim version\nH.nvim_supports_inline_extmarks = vim.fn.has('nvim-0.10') == 1\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('snippets', config.snippets, 'table')\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.expand', config.mappings.expand, 'string')\n  H.check_type('mappings.jump_next', config.mappings.jump_next, 'string')\n  H.check_type('mappings.jump_prev', config.mappings.jump_prev, 'string')\n  H.check_type('mappings.stop', config.mappings.stop, 'string')\n\n  H.check_type('expand', config.expand, 'table')\n  H.check_type('expand.prepare', config.expand.prepare, 'function', true)\n  H.check_type('expand.match', config.expand.match, 'function', true)\n  H.check_type('expand.select', config.expand.select, 'function', true)\n  H.check_type('expand.insert', config.expand.insert, 'function', true)\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniSnippets.config = config\n\n  -- Reset loader cache\n  H.cache = { runtime = {}, file = {}, mappings = {} }\n\n  -- Make mappings\n  local mappings = config.mappings\n  local map = function(lhs, rhs, desc)\n    if lhs == '' then return end\n    vim.keymap.set('i', lhs, rhs, { desc = desc })\n  end\n  map(mappings.expand, '<Cmd>lua MiniSnippets.expand()<CR>', 'Expand snippet')\n\n  -- Register 'code-snippets' extension as JSON (helps with highlighting)\n  vim.schedule(function() vim.filetype.add({ extension = { ['code-snippets'] = 'json' } }) end)\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniSnippets', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\n\n  -- Clean up invalid sessions (i.e. which have outdated or corrupted data)\n  -- - Use `vim.schedule_wrap` to make it work with `:edit` command\n  au('BufUnload', '*', vim.schedule_wrap(H.clean_sessions), 'Clean sessions stack')\nend\n\nH.create_default_hl = function()\n  local hi_link_underdouble = function(to, from)\n    local data = vim.api.nvim_get_hl(0, { name = from, link = false })\n    data.default = true\n    data.underdouble, data.underline, data.undercurl, data.underdotted, data.underdashed =\n      true, false, false, false, false\n    data.cterm = { underdouble = true }\n    data.fg, data.bg, data.ctermfg, data.ctermbg = 'NONE', 'NONE', 'NONE', 'NONE'\n    vim.api.nvim_set_hl(0, to, data)\n  end\n  hi_link_underdouble('MiniSnippetsCurrent', 'DiagnosticUnderlineWarn')\n  hi_link_underdouble('MiniSnippetsCurrentReplace', 'DiagnosticUnderlineError')\n  hi_link_underdouble('MiniSnippetsFinal', 'DiagnosticUnderlineOk')\n  hi_link_underdouble('MiniSnippetsUnvisited', 'DiagnosticUnderlineHint')\n  hi_link_underdouble('MiniSnippetsVisited', 'DiagnosticUnderlineInfo')\nend\n\nH.is_disabled = function() return vim.g.minisnippets_disable == true or vim.b.minisnippets_disable == true end\n\nH.get_config = function()\n  local global, buf = MiniSnippets.config, vim.b.minisnippets_config\n  -- Fast path for most common case\n  if buf == nil then return vim.deepcopy(global) end\n  -- Manually reconstruct to allow snippet array to be concatenated\n  buf = buf or {}\n  return {\n    snippets = vim.list_extend(vim.deepcopy(global.snippets), buf.snippets or {}),\n    mappings = vim.tbl_extend('force', global.mappings, buf.mappings or {}),\n    expand = vim.tbl_extend('force', global.expand, buf.expand or {}),\n  }\nend\n\n-- Read -----------------------------------------------------------------------\nH.file_readers = {}\n\nH.file_readers.lua = function(path, silent)\n  local ok, contents = pcall(dofile, path)\n  if not ok then return { problems = { 'Could not execute Lua file' } } end\n  if type(contents) ~= 'table' then return { problems = { 'Returned object is not a table' } } end\n  return H.read_snippet_data(contents)\nend\n\nH.file_readers.json = function(path, silent)\n  local file = io.open(path)\n  if file == nil then return { problems = { 'Could not open file' } } end\n  local raw = file:read('*all')\n  file:close()\n\n  local ok, contents = pcall(vim.json.decode, raw)\n  if not (ok and type(contents) == 'table') then\n    local msg = ok and 'Object is not a dictionary or array' or contents\n    return { problems = { 'File does not contain a valid JSON object. Reason: ' .. msg } }\n  end\n\n  return H.read_snippet_data(contents)\nend\n\nH.file_readers['code-snippets'] = H.file_readers.json\n\nH.read_snippet_data = function(contents)\n  local res, problems = {}, {}\n  for name, t in pairs(contents) do\n    if H.is_snippet(t) then\n      -- Try inferring description from dict's field (if appropriate)\n      if type(name) == 'string' and (t.desc == nil and t.description == nil) then t.desc = name end\n      table.insert(res, t)\n    elseif vim.is_callable(t) then\n      -- Allow entries to be functions (relevant for Lua files)\n      table.insert(res, t)\n    else\n      table.insert(problems, 'The following is not a valid snippet data:\\n' .. vim.inspect(t))\n    end\n  end\n  return { snippets = res, problems = problems }\nend\n\n-- Context snippets -----------------------------------------------------------\nH.get_default_context = function()\n  local buf_id = vim.api.nvim_get_current_buf()\n\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, nil, { error = false })\n  if not has_parser or parser == nil then return { buf_id = buf_id, lang = vim.bo[buf_id].filetype } end\n\n  -- Compute local (at cursor) TS language\n  local pos = vim.api.nvim_win_get_cursor(0)\n  local lang_tree = parser:language_for_range({ pos[1] - 1, pos[2], pos[1] - 1, pos[2] })\n  local lang = lang_tree:lang() or vim.bo[buf_id].filetype\n  return { buf_id = buf_id, lang = lang }\nend\n\nH.traverse_raw_snippets = function(x, target, context)\n  if H.is_snippet(x) then\n    local body\n    if x.body ~= nil then body = type(x.body) == 'string' and x.body or table.concat(x.body, '\\n') end\n\n    local desc = x.desc or x.description or body\n    if desc ~= nil then desc = type(desc) == 'string' and desc or table.concat(desc, '\\n') end\n\n    local prefix = x.prefix or ''\n    prefix = type(prefix) == 'string' and { prefix } or prefix\n\n    for _, pr in ipairs(prefix) do\n      -- Add snippets with empty prefixes separately\n      local index = pr == '' and (#target + 1) or pr\n      -- Allow absent `body` to result in completely removing prefix(es)\n      target[index] = body ~= nil and { prefix = pr, body = body, desc = desc } or nil\n    end\n  end\n\n  if H.islist(x) then\n    for _, v in ipairs(x) do\n      H.traverse_raw_snippets(v, target, context)\n    end\n  end\n\n  if vim.is_callable(x) then H.traverse_raw_snippets(x(context), target, context) end\nend\n\n-- Expand ---------------------------------------------------------------------\nH.make_extended_insert = function(insert)\n  return function(snippet)\n    if snippet == nil then return end\n\n    -- Ensure Insert mode. This helps to properly position cursor at EOL.\n    H.call_in_insert_mode(function()\n      -- Delete snippet's region and remove the data from the snippet (as it\n      -- wouldn't need to be removed and will represent outdated information)\n      H.delete_region(snippet.region)\n      snippet = vim.deepcopy(snippet)\n      snippet.region = nil\n\n      -- Insert snippet at cursor\n      insert(snippet)\n    end)\n  end\nend\n\n-- Parse ----------------------------------------------------------------------\nH.parse_verify = function(state)\n  if state.name == 'dollar_lbrace' then H.error('\"${\" should be closed with \"}\"') end\n  if state.name == 'choice' then H.error('Tabstop with choices should be closed with \"|}\"') end\n  if vim.startswith(state.name, 'transform_') then\n    H.error('Transform should contain 3 \"/\" outside of `${...}` and be closed with \"}\"')\n  end\n  if #state.depth_arrays > 1 then H.error('Placeholder should be closed with \"}\"') end\nend\n\nH.parse_post_process = function(node_arr, state_name)\n  -- Allow \"$\" at the end of the snippet\n  if state_name == 'dollar' then table.insert(node_arr, { text = { '$' } }) end\n\n  -- Process\n  local traverse\n  traverse = function(arr)\n    for _, node in ipairs(arr) do\n      -- Clean up trailing `\\`\n      if node.after_slash and node.text ~= nil then table.insert(node.text, '\\\\') end\n      node.after_slash = nil\n\n      -- Convert arrays to strings\n      if node.text then node.text = table.concat(node.text) end\n      if node.tabstop then node.tabstop = table.concat(node.tabstop) end\n      if node.choices then node.choices = vim.tbl_map(table.concat, node.choices) end\n      if node.var then node.var = table.concat(node.var) end\n      if node.transform then node.transform = vim.tbl_map(table.concat, node.transform) end\n\n      -- Recursively post-process placeholders\n      if node.placeholder ~= nil then node.placeholder = traverse(node.placeholder) end\n    end\n    arr = vim.tbl_filter(function(n) return n.text == nil or (n.text ~= nil and n.text:len() > 0) end, arr)\n    if #arr == 0 then return { { text = '' } } end\n    return arr\n  end\n\n  return traverse(node_arr)\nend\n\nH.parse_normalize = function(node_arr, opts)\n  local lookup = {}\n  for key, val in pairs(opts.lookup) do\n    if type(key) == 'string' then lookup[key] = tostring(val) end\n  end\n\n  local has_final_tabstop = false\n  local normalize = function(n)\n    -- Evaluate variable\n    local var_value\n    if n.var ~= nil then var_value = H.parse_eval_var(n.var, lookup) end\n    if type(var_value) == 'string' then n.text = var_value end\n\n    -- Look up tabstop\n    if n.tabstop ~= nil then n.text = lookup[n.tabstop] end\n\n    -- Ensure text-or-placeholder (use first choice for choice node)\n    if n.text == nil and n.placeholder == nil then n.placeholder = { { text = (n.choices or {})[1] or '' } } end\n    if n.text ~= nil and n.placeholder ~= nil then n.placeholder = nil end\n\n    -- Track presence of final tabstop\n    has_final_tabstop = has_final_tabstop or n.tabstop == '0'\n  end\n  -- - Ensure proper random random variables\n  math.randomseed(vim.loop.hrtime())\n  H.nodes_traverse(node_arr, normalize)\n\n  -- Possibly append final tabstop as a regular normalized tabstop\n  if not has_final_tabstop then table.insert(node_arr, { tabstop = '0', placeholder = { { text = '' } } }) end\n\n  -- Ensure same resolved text in linked tabstops\n  local tabstop_ref = {}\n  local sync_linked_tabstops = function(n)\n    if n.tabstop == nil then return end\n    local ref = tabstop_ref[n.tabstop]\n    if ref ~= nil then\n      -- Set data for repeated tabstops. Do not sync transforms (for future).\n      n.text, n.placeholder, n.choices = ref.text, vim.deepcopy(ref.placeholder), vim.deepcopy(ref.choices)\n      return\n    end\n    -- Compute reference data for repeated tabstops\n    if n.placeholder ~= nil and H.parse_nodes_contain_tabstop(n.placeholder, n.tabstop) then\n      H.error('Placeholder can not contain its tabstop')\n    end\n    tabstop_ref[n.tabstop] = { text = n.text, placeholder = n.placeholder, choices = n.choices }\n  end\n  H.nodes_traverse(node_arr, sync_linked_tabstops)\n\n  return node_arr\nend\n\nH.parse_nodes_contain_tabstop = function(node_arr, tabstop)\n  for _, n in ipairs(node_arr) do\n    if n.tabstop == tabstop then return true end\n    if n.placeholder ~= nil and H.parse_nodes_contain_tabstop(n.placeholder, tabstop) then return true end\n  end\n  return false\nend\n\nH.parse_get_text = function(node_arr)\n  local parts = {}\n  for _, n in ipairs(node_arr) do\n    table.insert(parts, n.text or H.parse_get_text(n.placeholder))\n  end\n  return table.concat(parts, '')\nend\n\nH.parse_rise_depth = function(state)\n  -- Set the deepest array as a placeholder of the last node in previous layer.\n  -- This can happen only after `}` which does not close current node.\n  local depth = #state.depth_arrays\n  local cur_layer, prev_layer = state.depth_arrays[depth], state.depth_arrays[depth - 1]\n  prev_layer[#prev_layer].placeholder = vim.deepcopy(cur_layer)\n  state.depth_arrays[depth] = nil\n  state:add_node({ text = {} }):set_name('text')\nend\n\n-- Each method processes single character based on the character (`c`),\n-- state (`s`), and current node (`n`).\nH.parse_processors = {}\n\nH.parse_processors.text = function(c, s, n)\n  if n.after_slash then\n    -- Escape `$}\\` and allow unescaped '\\\\' to preceed any character\n    if not (c == '$' or c == '}' or c == '\\\\') then table.insert(n.text, '\\\\') end\n    n.text[#n.text + 1], n.after_slash = c, nil\n    return\n  end\n  if c == '}' and s:is_not_top_level() then return H.parse_rise_depth(s) end\n  if c == '\\\\' then return s:set_in(n, 'after_slash', true) end\n  if c == '$' then return s:set_name('dollar') end\n  table.insert(n.text, c)\nend\n\nH.parse_processors.dollar = function(c, s, n)\n  if c == '}' and s:is_not_top_level() then\n    if n.text ~= nil then table.insert(n.text, '$') end\n    if n.text == nil then s:add_node({ text = { '$' } }) end\n    s:set_name('text')\n    H.parse_rise_depth(s)\n    return\n  end\n\n  if c:find('^[0-9]$') then return s:add_node({ tabstop = { c } }):set_name('dollar_tabstop') end -- Tabstops\n  if c:find('^[_a-zA-Z]$') then return s:add_node({ var = { c } }):set_name('dollar_var') end -- Variables\n  if c == '{' then return s:set_name('dollar_lbrace') end -- Cases of `${...}`\n  table.insert(n.text, '$') -- Case of unescaped `$`\n  if c == '$' then return end -- Case of `$$1` and `$${1}`\n  table.insert(n.text, c)\n  s:set_name('text')\nend\n\nH.parse_processors.dollar_tabstop = function(c, s, n)\n  if c:find('^[0-9]$') then return table.insert(n.tabstop, c) end\n  if c == '}' and s:is_not_top_level() then return H.parse_rise_depth(s) end\n  local new_node = { text = {} }\n  s:add_node(new_node)\n  if c == '$' then return s:set_name('dollar') end -- Case of `$1$2` and `$1$a`\n  s:set_name('text')\n  if c == '\\\\' then return s:set_in(new_node, 'after_slash', true) end -- Case of `${1:{$2\\}}`\n  table.insert(new_node.text, c) -- Case of `$1a`\nend\n\nH.parse_processors.dollar_var = function(c, s, n)\n  if c:find('^[_a-zA-Z0-9]$') then return table.insert(n.var, c) end\n  if c == '}' and s:is_not_top_level() then return H.parse_rise_depth(s) end\n  local new_node = { text = {} }\n  s:add_node(new_node)\n  if c == '$' then return s:set_name('dollar') end -- Case of `$a$b` and `$a$1`\n  s:set_name('text')\n  if c == '\\\\' then return s:set_in(new_node, 'after_slash', true) end -- Case of `${AAA:{$1\\}}`\n  table.insert(new_node.text, c) -- Case of `$a-`\nend\n\nH.parse_processors.dollar_lbrace = function(c, s, n)\n  if n.tabstop == nil and n.var == nil then -- Detect the type of `${...}`\n    if c:find('^[0-9]$') then return s:add_node({ tabstop = { c } }) end\n    if c:find('^[_a-zA-Z]$') then return s:add_node({ var = { c } }) end\n    H.error('`${` should be followed by digit (in tabstop) or letter/underscore (in variable), not ' .. vim.inspect(c))\n  end\n  if c == '}' then return s:add_node({ text = {} }):set_name('text') end -- Cases of `${1}` and `${a}`\n  if c == ':' then -- Placeholder\n    table.insert(s.depth_arrays, { { text = {} } })\n    return s:set_name('text')\n  end\n  if c == '/' then return s:set_in(n, 'transform', { {}, {}, {} }):set_name('transform_regex') end -- Transform\n  if n.var ~= nil then -- Variable\n    if c:find('^[_a-zA-Z0-9]$') then return table.insert(n.var, c) end\n    H.error('Variable name should be followed by \"}\", \":\" or \"/\", not ' .. vim.inspect(c))\n  else -- Tabstop\n    if c:find('^[0-9]$') then return table.insert(n.tabstop, c) end\n    if c == '|' then return s:set_name('choice') end\n    H.error('Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not ' .. vim.inspect(c))\n  end\nend\n\nH.parse_processors.choice = function(c, s, n)\n  n.choices = n.choices or { {} }\n  if n.after_bar then\n    if c ~= '}' then H.error('Tabstop with choices should be closed with \"|}\"') end\n    return s:set_in(n, 'after_bar', nil):add_node({ text = {} }):set_name('text')\n  end\n\n  local cur = n.choices[#n.choices]\n  if n.after_slash then\n    -- Escape `$}\\` and allow unescaped '\\\\' to preceed any character\n    if not (c == ',' or c == '|' or c == '\\\\') then table.insert(cur, '\\\\') end\n    cur[#cur + 1], n.after_slash = c, nil\n    return\n  end\n  if c == ',' then return table.insert(n.choices, {}) end\n  if c == '\\\\' then return s:set_in(n, 'after_slash', true) end\n  if c == '|' then return s:set_in(n, 'after_bar', true) end\n  table.insert(cur, c)\nend\n\n-- Silently gather all the transform data and wait until proper `}`\nH.parse_processors.transform_regex = function(c, s, n)\n  table.insert(n.transform[1], c)\n  if n.after_slash then return s:set_in(n, 'after_slash', nil) end\n  if c == '\\\\' then return s:set_in(n, 'after_slash', true) end\n  if c == '/' then return s:set_in(n.transform[1], #n.transform[1], nil):set_name('transform_format') end -- Assumes any `/` is escaped in regex\nend\n\nH.parse_processors.transform_format = function(c, s, n)\n  table.insert(n.transform[2], c)\n  if n.after_slash then return s:set_in(n, 'after_slash', nil) end\n  if n.after_dollar then\n    n.after_dollar = nil\n    -- Inside `${}` wait until the first (unescaped) `}`. Techincally, this\n    -- breaks LSP spec in `${1:?if:else}` (`if` doesn't have to escape `}`).\n    -- Accept this as known limitation and ask to escape `}` in such cases.\n    if c == '{' and not n.inside_braces then return s:set_in(n, 'inside_braces', true) end\n  end\n  if c == '\\\\' then return s:set_in(n, 'after_slash', true) end\n  if c == '$' then return s:set_in(n, 'after_dollar', true) end\n  if c == '}' and n.inside_braces then return s:set_in(n, 'inside_braces', nil) end\n  if c == '/' and not n.inside_braces then\n    return s:set_in(n.transform[2], #n.transform[2], nil):set_name('transform_options')\n  end\nend\n\nH.parse_processors.transform_options = function(c, s, n)\n  table.insert(n.transform[3], c)\n  if n.after_slash then return s:set_in(n, 'after_slash', nil) end\n  if c == '\\\\' then return s:set_in(n, 'after_slash', true) end\n  if c == '}' then return s:set_in(n.transform[3], #n.transform[3], nil):add_node({ text = {} }):set_name('text') end\nend\n\n--stylua: ignore\nH.parse_eval_var = function(var, lookup)\n  -- Always prefer using lookup\n  if lookup[var] ~= nil then return lookup[var] end\n\n  -- Evaluate variable\n  local value\n  if H.var_evaluators[var] ~= nil then value = H.var_evaluators[var]() end\n  -- - Fall back to environment variable or `-1` to not evaluate twice\n  if value == nil then value = vim.loop.os_getenv(var) or -1 end\n\n  -- Skip caching random variables (to allow several different in one snippet)\n  if not (var == 'RANDOM' or var == 'RANDOM_HEX' or var == 'UUID') then lookup[var] = value end\n  return value\nend\n\n--stylua: ignore\nH.var_evaluators = {\n  -- LSP\n  TM_SELECTED_TEXT = function() return table.concat(vim.fn.getreg('\"', true, true), '\\n') end,\n  TM_CURRENT_LINE  = function() return vim.api.nvim_get_current_line() end,\n  TM_CURRENT_WORD  = function() return vim.fn.expand('<cword>') end,\n  TM_LINE_INDEX    = function() return tostring(vim.fn.line('.') - 1) end,\n  TM_LINE_NUMBER   = function() return tostring(vim.fn.line('.')) end,\n  TM_FILENAME      = function() return vim.fn.expand('%:t') end,\n  TM_FILENAME_BASE = function() return vim.fn.expand('%:t:r') end,\n  TM_DIRECTORY     = function() return vim.fn.expand('%:p:h') end,\n  TM_FILEPATH      = function() return vim.fn.expand('%:p') end,\n\n  -- VS Code\n  CLIPBOARD         = function() return vim.fn.getreg('+') end,\n  CURSOR_INDEX      = function() return tostring(vim.fn.col('.') - 1) end,\n  CURSOR_NUMBER     = function() return tostring(vim.fn.col('.')) end,\n  RELATIVE_FILEPATH = function() return vim.fn.expand('%:.') end,\n  WORKSPACE_FOLDER  = function() return vim.fn.getcwd() end,\n\n  LINE_COMMENT      = function() return vim.bo.commentstring:gsub('%s*%%s.*$', '') end,\n  -- No BLOCK_COMMENT_{START,END} as there is no built-in way to get them\n\n  CURRENT_YEAR             = function() return vim.fn.strftime('%Y') end,\n  CURRENT_YEAR_SHORT       = function() return vim.fn.strftime('%y') end,\n  CURRENT_MONTH            = function() return vim.fn.strftime('%m') end,\n  CURRENT_MONTH_NAME       = function() return vim.fn.strftime('%B') end,\n  CURRENT_MONTH_NAME_SHORT = function() return vim.fn.strftime('%b') end,\n  CURRENT_DATE             = function() return vim.fn.strftime('%d') end,\n  CURRENT_DAY_NAME         = function() return vim.fn.strftime('%A') end,\n  CURRENT_DAY_NAME_SHORT   = function() return vim.fn.strftime('%a') end,\n  CURRENT_HOUR             = function() return vim.fn.strftime('%H') end,\n  CURRENT_MINUTE           = function() return vim.fn.strftime('%M') end,\n  CURRENT_SECOND           = function() return vim.fn.strftime('%S') end,\n  CURRENT_TIMEZONE_OFFSET  = function() return vim.fn.strftime('%z') end,\n\n  CURRENT_SECONDS_UNIX = function() return tostring(os.time()) end,\n\n  -- Random\n  RANDOM     = function() return string.format('%06d', math.random(0, 999999)) end,\n  RANDOM_HEX = function() return string.format('%06x', math.random(0, 16777216 - 1)) end,\n  UUID       = function()\n    -- Source: https://gist.github.com/jrus/3197011\n    local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'\n    return string.gsub(template, '[xy]', function (c)\n      local v = c == 'x' and math.random(0, 0xf) or math.random(8, 0xb)\n      return string.format('%x', v)\n    end)\n  end\n}\n\n-- Session --------------------------------------------------------------------\nH.get_active_session = function() return H.sessions[#H.sessions] end\n\nH.session_new = function(nodes, snippet, opts)\n  -- Compute all present tabstops in session traverse order\n  local taborder = H.compute_tabstop_order(nodes)\n  local tabstops = {}\n  for i, id in ipairs(taborder) do\n    tabstops[id] =\n      { prev = taborder[i - 1] or taborder[#taborder], next = taborder[i + 1] or taborder[1], is_visited = false }\n  end\n\n  return {\n    buf_id = vim.api.nvim_get_current_buf(),\n    cur_tabstop = taborder[1],\n    extmark_id = H.extmark_new(0, vim.fn.line('.') - 1, vim.fn.col('.') - 1),\n    insert_args = vim.deepcopy({ snippet = snippet, opts = opts }),\n    nodes = nodes,\n    ns_id = H.ns_id.nodes,\n    tabstops = tabstops,\n  }\nend\n\nH.session_init = function(session, full)\n  if session == nil then return end\n  local buf_id = session.buf_id\n\n  -- Prepare\n  if full then\n    -- Set buffer text preserving snippet text relative indent\n    local indent = H.get_indent(vim.fn.getline('.'):sub(1, vim.fn.col('.') - 1))\n    H.nodes_set_text(buf_id, session.nodes, session.extmark_id, indent)\n\n    -- No session if no input needed: single final tabstop without placeholder\n    if session.cur_tabstop == '0' then\n      local ref_node = H.session_get_ref_node(session)\n      local row, col, opts = H.extmark_get(buf_id, ref_node.extmark_id)\n      local is_empty = row == opts.end_row and col == opts.end_col\n      if is_empty then\n        -- Clean up\n        H.nodes_traverse(session.nodes, function(n) H.extmark_del(buf_id, n.extmark_id) end)\n        H.extmark_del(buf_id, session.extmark_id)\n        return H.set_cursor({ row + 1, col })\n      end\n    end\n\n    -- Register new session\n    local cur_session = H.get_active_session()\n    if cur_session ~= nil then\n      -- Sync before deinit to allow removing current placeholder\n      H.session_sync_current_tabstop(cur_session)\n      H.session_deinit(cur_session, false)\n    end\n    table.insert(H.sessions, session)\n\n    -- Focus on the current tabstop\n    H.session_tabstop_focus(session, session.cur_tabstop)\n\n    -- Possibly set behavior for all sessions\n    H.track_sessions()\n    H.map_in_sessions()\n  else\n    -- Sync current tabstop for resumed session. This is useful when nested\n    -- session was done inside reference tabstop node (most common case).\n    -- On purpose don't change cursor/buffer/focus to allow smoother typing.\n    H.session_sync_current_tabstop(session)\n    H.session_update_hl(session)\n    H.session_ensure_gravity(session)\n  end\n\n  -- Trigger proper event\n  H.trigger_event('MiniSnippetsSession' .. (full and 'Start' or 'Resume'), { session = vim.deepcopy(session) })\nend\n\nH.track_sessions = function()\n  -- Create tracking autocommands only once for all nested sessions\n  if #H.sessions > 1 then return end\n  local gr = vim.api.nvim_create_augroup('MiniSnippetsTrack', { clear = true })\n\n  -- React to text changes. NOTE: Use 'TextChangedP' to update linked tabstops\n  -- with visible popup. It has downsides though:\n  -- - Placeholder is removed after selecting first choice. Together with\n  --   showing choices in empty tabstops, feels like a good compromise.\n  -- - Tabstop sync runs more frequently (especially with 'mini.completion'),\n  --   because of how built-in completion constantly 'delete-add' completion\n  --   leader text (which is treated as text change).\n  local on_textchanged = function(args)\n    local session, buf_id = H.get_active_session(), args.buf\n    -- React only to text changes in session's buffer for performance\n    if session.buf_id ~= buf_id then return end\n    -- Ensure that session is valid, like no extmarks got corrupted\n    if not H.session_is_valid(session) then\n      H.notify('Session contains corrupted data (deleted or out of range extmarks). It is stopped.', 'WARN')\n      return MiniSnippets.session.stop()\n    end\n    H.session_sync_current_tabstop(session)\n  end\n  local text_events = { 'TextChanged', 'TextChangedI', 'TextChangedP' }\n  vim.api.nvim_create_autocmd(text_events, { group = gr, callback = on_textchanged, desc = 'React to text change' })\n\n  -- Stop if final tabstop is current: exit to Normal mode or *any* text change\n  local latest_changedtick = vim.b.changedtick\n  local stop_if_final = function(args)\n    -- *Actual* text change check is a workaround for `TextChangedI` sometimes\n    -- getting triggered unnecessarily and too late with built-in completion\n    if vim.b.changedtick == latest_changedtick and args.event ~= 'ModeChanged' then return end\n    latest_changedtick = vim.b.changedtick\n\n    -- React only on text changes in session's buffer\n    local session, buf_id = H.get_active_session(), args.buf\n    if not ((session or {}).buf_id == buf_id and session.cur_tabstop == '0') then return end\n\n    -- Stop without forcing to hide completion\n    H.cache.stop_is_auto = true\n    MiniSnippets.session.stop()\n    H.cache.stop_is_auto = nil\n  end\n  local modechanged_opts = { group = gr, pattern = '*:n', callback = stop_if_final, desc = 'Stop on final tabstop' }\n  vim.api.nvim_create_autocmd('ModeChanged', modechanged_opts)\n  vim.api.nvim_create_autocmd(text_events, { group = gr, callback = stop_if_final, desc = 'Stop on final tabstop' })\nend\n\nH.clean_sessions = function()\n  for i = #H.sessions - 1, 1, -1 do\n    if not H.session_is_valid(H.sessions[i]) then\n      H.session_deinit(H.sessions[i], true)\n      table.remove(H.sessions, i)\n    end\n  end\n  if #H.sessions > 0 and not H.session_is_valid(H.get_active_session()) then MiniSnippets.session.stop() end\nend\n\nH.map_in_sessions = function()\n  -- Create mapping only once for all nested sessions\n  if #H.sessions > 1 then return end\n  local mappings = H.get_config().mappings\n  local map_with_cache = function(lhs, call, desc)\n    if lhs == '' then return end\n    H.cache.mappings[lhs] = vim.fn.maparg(lhs, 'i', false, true)\n    -- NOTE: Map globally to work in nested sessions in different buffers\n    vim.keymap.set('i', lhs, '<Cmd>lua MiniSnippets.session.' .. call .. '<CR>', { desc = desc })\n  end\n  map_with_cache(mappings.jump_next, 'jump(\"next\")', 'Jump to next snippet tabstop')\n  map_with_cache(mappings.jump_prev, 'jump(\"prev\")', 'Jump to previous snippet tabstop')\n  map_with_cache(mappings.stop, 'stop()', 'Stop active snippet session')\nend\n\nH.unmap_in_sessions = function()\n  for lhs, data in pairs(H.cache.mappings) do\n    local needs_restore = vim.tbl_count(data) > 0\n    if needs_restore then vim.fn.mapset('i', false, data) end\n    if not needs_restore then vim.keymap.del('i', lhs) end\n  end\n  H.cache.mappings = {}\nend\n\nH.session_tabstop_focus = function(session, tabstop_id)\n  session.cur_tabstop = tabstop_id\n  session.tabstops[tabstop_id].is_visited = true\n\n  -- Ensure target buffer is current\n  H.ensure_cur_buf(session.buf_id)\n\n  -- Update highlighting\n  H.session_update_hl(session)\n\n  -- Ensure proper gravity as reference node has changed\n  H.session_ensure_gravity(session)\n\n  -- Set cursor based on reference node: left side if there is placeholder (and\n  -- will be replaced), right side otherwise (to append).\n  local ref_node = H.session_get_ref_node(session)\n  local row, col, end_row, end_col = H.extmark_get_range(session.buf_id, ref_node.extmark_id)\n  local pos = ref_node.placeholder ~= nil and { row + 1, col } or { end_row + 1, end_col }\n  H.set_cursor(pos)\n\n  -- Show choices: if present and match node text (or all if still placeholder)\n  H.show_completion(ref_node.choices, col + 1)\nend\n\nH.session_ensure_gravity = function(session)\n  -- Ensure proper gravity relative to reference node (first node with current\n  -- tabstop): \"left\" before, \"expand\" at and all its parents, \"right\" after.\n  -- This accounts for typing in snippets like `$1$2$1$2$1` (in both 1 and 2)\n  -- and correct tracking of $2 in `${2:$1}` (should expand if typing in 1).\n  local buf_id, cur_tabstop, base_gravity = session.buf_id, session.cur_tabstop, 'left'\n  local parent_extmarks = {}\n  local ensure = function(n)\n    local is_ref_node = n.tabstop == cur_tabstop and base_gravity == 'left'\n    if is_ref_node then\n      for _, extmark_id in ipairs(parent_extmarks) do\n        H.extmark_set_gravity(buf_id, extmark_id, 'expand')\n      end\n      -- Disable parent stack tracking, as reference node is accounted for\n      parent_extmarks = nil\n    end\n    H.extmark_set_gravity(buf_id, n.extmark_id, is_ref_node and 'expand' or base_gravity)\n    base_gravity = (is_ref_node or base_gravity == 'right') and 'right' or 'left'\n  end\n\n  local ensure_in_nodes\n  ensure_in_nodes = function(nodes)\n    for _, n in ipairs(nodes) do\n      -- NOTE: apply first to the node and only later to placeholder nodes,\n      -- which makes them have \"right\" gravity and thus being removable during\n      -- replacing placeholder (as they will not cover newly inserted text).\n      ensure(n)\n      if n.placeholder ~= nil then\n        if parent_extmarks ~= nil then table.insert(parent_extmarks, n.extmark_id) end\n        ensure_in_nodes(n.placeholder)\n        if parent_extmarks ~= nil then parent_extmarks[#parent_extmarks] = nil end\n      end\n    end\n  end\n  ensure_in_nodes(session.nodes)\nend\n\nH.session_get_ref_node = function(session)\n  local res, cur_tabstop = nil, session.cur_tabstop\n  local find = function(n) res = res or (n.tabstop == cur_tabstop and n or nil) end\n  H.nodes_traverse(session.nodes, find)\n  return res\nend\n\nH.session_is_valid = function(session)\n  local buf_id = session.buf_id\n  if not H.is_loaded_buf(buf_id) then return false end\n  local res, f, n_lines = true, nil, vim.api.nvim_buf_line_count(buf_id)\n  f = function(n)\n    -- NOTE: Invalid extmark tracking (via `invalidate=true`) should be doable,\n    -- but comes with constraints: manually making tabstop empty should be\n    -- allowed; deleting placeholder also deletes extmark's range. Both make\n    -- extmark invalid, so deligate to users to see that extmarks are broken.\n    local ok, row, _, _ = pcall(H.extmark_get, buf_id, n.extmark_id)\n    res = res and (ok and row < n_lines)\n  end\n  H.nodes_traverse(session.nodes, f)\n  return res\nend\n\nH.session_sync_current_tabstop = function(session)\n  if session._no_sync then return end\n\n  local buf_id, ref_node = session.buf_id, H.session_get_ref_node(session)\n  local ref_extmark_id = ref_node.extmark_id\n\n  -- With present placeholder, decide whether there was a valid change (then\n  -- remove placeholder) or not (then no sync)\n  -- NOTE: Only current tabstop is synced *and* only after its first edit is\n  -- mostly done to limit code complexity. This is a reasonable compromise\n  -- together with `parse()` syncing all tabstops in its normalization. Doing\n  -- more is better for cases which are outside of suggested workflow (like\n  -- editing text outside of \"jump-edit-jump-edit-stop\" loop).\n  if ref_node.placeholder ~= nil then\n    local ref_row, ref_col = H.extmark_get_range(buf_id, ref_extmark_id)\n    local phd_row, phd_col = H.extmark_get_range(buf_id, ref_node.placeholder[1].extmark_id)\n    if ref_row == phd_row and ref_col == phd_col then return end\n\n    -- Remove placeholder to get extmark representing newly added text\n    H.nodes_del(buf_id, ref_node.placeholder)\n    ref_node.placeholder = nil\n  end\n\n  -- Compute reference text: dedented version of reference node's text to later\n  -- reindent linked tabstops so that they preserve relative indent\n  local row, col, end_row, end_col = H.extmark_get_range(buf_id, ref_extmark_id)\n  local ref_text = vim.api.nvim_buf_get_text(0, row, col, end_row, end_col, {})\n  ref_node.text = table.concat(ref_text, '\\n')\n\n  ref_text = H.dedent(ref_text, row, col)\n\n  -- Sync nodes with current tabstop to have text from reference node\n  local cur_tabstop = session.cur_tabstop\n  local sync = function(n)\n    -- Make expanding extmark for all nodes because current tabstop might be\n    -- placed inside any placeholder. This allows proper extmark tracking.\n    H.extmark_set_gravity(buf_id, n.extmark_id, 'expand')\n    if not (n.tabstop == cur_tabstop and n.extmark_id ~= ref_extmark_id) then return end\n\n    -- Ensure no placeholder because reference doesn't have one\n    if n.placeholder ~= nil then H.nodes_del(buf_id, n.placeholder) end\n\n    -- Set reference text reindented based on the start line's indent\n    local cur_row, cur_col, cur_end_row, cur_end_col = H.extmark_get_range(buf_id, n.extmark_id)\n    local cur_text = H.reindent(vim.deepcopy(ref_text), cur_row, cur_col)\n    vim.api.nvim_buf_set_text(buf_id, cur_row, cur_col, cur_end_row, cur_end_col, cur_text)\n    n.placeholder, n.text = nil, table.concat(cur_text, '\\n')\n  end\n  local sync_cleanup = function(n)\n    -- Make sure node's extmark doesn't move when setting later text\n    -- Set this *after* traversing placeholder to have proper tracking in\n    -- cases like `$1 ${2:$1}` - $2 extmark should be still expanding to track\n    -- setting new text in $1.\n    H.extmark_set_gravity(buf_id, n.extmark_id, 'left')\n  end\n  -- - Temporarily disable running this function (as autocommands will trigger)\n  session._no_sync = true\n  H.nodes_traverse(session.nodes, sync, sync_cleanup)\n  session._no_sync = nil\n  H.session_ensure_gravity(session)\n\n  -- Maybe show choices for empty tabstop at cursor\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  if ref_node.text == '' and cur_pos[1] == (row + 1) and cur_pos[2] == col then H.show_completion(ref_node.choices) end\n\n  -- Make highlighting up to date\n  H.session_update_hl(session)\nend\n\nH.session_jump = vim.schedule_wrap(function(session, direction)\n  -- NOTE: Use `schedule_wrap` to workaround some edge cases when used inside\n  -- expression mapping (as recommended for `<Tab>`)\n  if session == nil then return end\n\n  -- Compute target tabstop accounting for possibly missing ones.\n  -- Example why needed: `${1:$2}$3`, setting text in $1 removes $2 tabstop\n  -- and jumping should be done from 1 to 3.\n  local present_tabstops, all_tabstops = {}, session.tabstops\n  H.nodes_traverse(session.nodes, function(n) present_tabstops[n.tabstop or true] = true end)\n  local cur_tabstop, new_tabstop = session.cur_tabstop, nil\n  -- - NOTE: This can't be infinite as `prev`/`next` traverse all tabstops\n  if not present_tabstops[cur_tabstop] then return end\n  while not present_tabstops[new_tabstop] do\n    new_tabstop = all_tabstops[new_tabstop or cur_tabstop][direction]\n  end\n\n  local event_data = { tabstop_from = cur_tabstop, tabstop_to = new_tabstop }\n  H.trigger_event('MiniSnippetsSessionJumpPre', event_data)\n  H.session_tabstop_focus(session, new_tabstop)\n  H.trigger_event('MiniSnippetsSessionJump', event_data)\nend)\n\nH.session_update_hl = function(session)\n  local buf_id, insert_opts = session.buf_id, session.insert_args.opts\n  local empty_tabstop, empty_tabstop_final = insert_opts.empty_tabstop, insert_opts.empty_tabstop_final\n  local cur_tabstop, tabstops = session.cur_tabstop, session.tabstops\n  local is_replace = H.session_get_ref_node(session).placeholder ~= nil\n  local current_hl = 'MiniSnippetsCurrent' .. (is_replace and 'Replace' or '')\n  local priority = 101\n\n  local update_hl = function(n, is_in_cur_tabstop)\n    if n.tabstop == nil then return end\n\n    -- Compute tabstop's features\n    local row, col, opts = H.extmark_get(buf_id, n.extmark_id)\n    local is_empty = row == opts.end_row and col == opts.end_col\n    local is_final = n.tabstop == '0'\n    local is_visited = tabstops[n.tabstop].is_visited\n    local hl_group = (n.tabstop == cur_tabstop or is_in_cur_tabstop) and current_hl\n      or (is_final and 'MiniSnippetsFinal' or (is_visited and 'MiniSnippetsVisited' or 'MiniSnippetsUnvisited'))\n\n    -- Ensure up to date highlighting\n    opts.hl_group, opts.virt_text_pos, opts.virt_text = nil, nil, nil\n\n    if is_empty then\n      if H.nvim_supports_inline_extmarks then\n        opts.virt_text_pos = 'inline'\n        opts.virt_text = { { is_final and empty_tabstop_final or empty_tabstop, hl_group } }\n      end\n    else\n      opts.hl_group = hl_group\n    end\n\n    -- Make inline extmarks preserve order if placed at same position\n    priority = priority + 1\n    opts.priority = priority\n\n    -- Update extmark\n    vim.api.nvim_buf_set_extmark(buf_id, H.ns_id.nodes, row, col, opts)\n  end\n\n  -- Use custom traversing to ensure that nested tabstops inside current\n  -- tabstop's placeholder are highlighted the same, even inline virtual text.\n  local update_hl_in_nodes\n  update_hl_in_nodes = function(nodes, is_in_cur_tabstop)\n    for _, n in ipairs(nodes) do\n      update_hl(n, is_in_cur_tabstop)\n      if n.placeholder ~= nil then update_hl_in_nodes(n.placeholder, is_in_cur_tabstop or n.tabstop == cur_tabstop) end\n    end\n  end\n  update_hl_in_nodes(session.nodes, false)\nend\n\nH.session_deinit = function(session, full)\n  if session == nil then return end\n\n  -- Trigger proper event\n  H.trigger_event('MiniSnippetsSession' .. (full and 'Stop' or 'Suspend'), { session = vim.deepcopy(session) })\n  if not H.is_loaded_buf(session.buf_id) then return end\n\n  -- Delete or hide (make invisible) extmarks\n  local extmark_fun = full and H.extmark_del or H.extmark_hide\n  extmark_fun(session.buf_id, session.extmark_id)\n  H.nodes_traverse(session.nodes, function(n) extmark_fun(session.buf_id, n.extmark_id) end)\n\n  -- Hide completion if stopping was done manually\n  if not H.cache.stop_is_auto then H.hide_completion() end\nend\n\nH.nodes_set_text = function(buf_id, nodes, tracking_extmark_id, indent, cur_body_line)\n  local sw = vim.bo.shiftwidth\n  local tab_text = vim.bo.expandtab and string.rep(' ', sw == 0 and vim.bo.tabstop or sw) or '\\t'\n\n  cur_body_line = cur_body_line or ''\n  for _, n in ipairs(nodes) do\n    -- Add tracking extmark\n    local _, _, row, col = H.extmark_get_range(buf_id, tracking_extmark_id)\n    n.extmark_id = H.extmark_new(buf_id, row, col)\n\n    -- Adjust node's text and append it to currently set text\n    if n.text ~= nil then\n      -- Make variable/tabstop lines preserve relative indent\n      local body_indent = (n.var == nil and n.tabstop == nil) and '' or H.get_indent(cur_body_line)\n      local new_text = n.text:gsub('\\n', '\\n' .. indent .. body_indent):gsub('\\t', tab_text)\n      H.extmark_set_text(buf_id, tracking_extmark_id, 'right', new_text)\n\n      -- NOTE: Compute current body line *before* setting node's actual text\n      cur_body_line = (cur_body_line .. n.text):match('[^\\n]*$')\n      n.text = new_text\n    end\n\n    -- Process (possibly nested) placeholder nodes\n    if n.placeholder ~= nil then H.nodes_set_text(buf_id, n.placeholder, tracking_extmark_id, indent, cur_body_line) end\n\n    -- Make sure that node's extmark doesn't move when adding next node text\n    H.extmark_set_gravity(buf_id, n.extmark_id, 'left')\n  end\nend\n\nH.nodes_del = function(buf_id, nodes)\n  local del = function(n)\n    H.extmark_set_text(buf_id, n.extmark_id, 'inside', {})\n    H.extmark_del(buf_id, n.extmark_id)\n  end\n  H.nodes_traverse(nodes, del)\nend\n\nH.nodes_traverse = function(nodes, f, f_post)\n  for i, n in ipairs(nodes) do\n    -- Prefer visiting whole node first to allow `f` to modify placeholder.\n    -- It is also important to ensure proper gravity inside placeholder nodes.\n    n = f(n) or n\n    if n.placeholder ~= nil then n.placeholder = H.nodes_traverse(n.placeholder, f, f_post) end\n    if f_post then n = f_post(n) or n end\n    nodes[i] = n\n  end\n  return nodes\nend\n\nH.compute_tabstop_order = function(nodes)\n  local tabstops_map = {}\n  H.nodes_traverse(nodes, function(n) tabstops_map[n.tabstop or true] = true end)\n  tabstops_map[true] = nil\n\n  -- Order as numbers while allowing leading zeros. Put special `$0` last.\n  local tabstops = vim.tbl_map(function(x) return { tonumber(x), x } end, vim.tbl_keys(tabstops_map))\n  table.sort(tabstops, function(a, b)\n    if a[2] == '0' then return false end\n    if b[2] == '0' then return true end\n    return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2])\n  end)\n  return vim.tbl_map(function(x) return x[2] end, tabstops)\nend\n\n-- Extmarks -------------------------------------------------------------------\n-- All extmark functions work in current buffer with same global namespace.\n-- This is because interaction with snippets eventually requires buffer to be\n-- current, so instead rely on it becoming such as soon as possible.\nH.extmark_new = function(buf_id, row, col)\n  -- Create expanding extmark by default\n  local opts = { end_row = row, end_col = col, right_gravity = false, end_right_gravity = true }\n  return vim.api.nvim_buf_set_extmark(buf_id, H.ns_id.nodes, row, col, opts)\nend\n\nH.extmark_get = function(buf_id, ext_id)\n  local data = vim.api.nvim_buf_get_extmark_by_id(buf_id, H.ns_id.nodes, ext_id, { details = true })\n  data[3].id, data[3].ns_id = ext_id, nil\n  return data[1], data[2], data[3]\nend\n\nH.extmark_get_range = function(buf_id, ext_id)\n  local row, col, opts = H.extmark_get(buf_id, ext_id)\n  return row, col, opts.end_row, opts.end_col\nend\n\nH.extmark_del = function(buf_id, ext_id) vim.api.nvim_buf_del_extmark(buf_id, H.ns_id.nodes, ext_id or -1) end\n\nH.extmark_hide = function(buf_id, ext_id)\n  local row, col, opts = H.extmark_get(buf_id, ext_id)\n  opts.hl_group, opts.virt_text, opts.virt_text_pos = nil, nil, nil\n  vim.api.nvim_buf_set_extmark(buf_id, H.ns_id.nodes, row, col, opts)\nend\n\nH.extmark_set_gravity = function(buf_id, ext_id, gravity)\n  local row, col, opts = H.extmark_get(buf_id, ext_id)\n  opts.right_gravity, opts.end_right_gravity = gravity == 'right', gravity ~= 'left'\n  vim.api.nvim_buf_set_extmark(buf_id, H.ns_id.nodes, row, col, opts)\nend\n\n--stylua: ignore\nH.extmark_set_text = function(buf_id, ext_id, side, text)\n  local row, col, end_row, end_col = H.extmark_get_range(buf_id, ext_id)\n  if side == 'left'  then end_row, end_col = row,     col     end\n  if side == 'right' then row,     col     = end_row, end_col end\n  text = type(text) == 'string' and vim.split(text, '\\n') or text\n  vim.api.nvim_buf_set_text(buf_id, row, col, end_row, end_col, text)\nend\n\n-- Indent ---------------------------------------------------------------------\nH.get_indent = function(line)\n  line = line or vim.fn.getline('.')\n  local comment_indent = ''\n  -- Treat comment leaders as part of indent\n  for _, leader in ipairs(H.get_comment_leaders()) do\n    local cur_match = line:match('^%s*' .. vim.pesc(leader) .. '%s*')\n    -- Use biggest match in case of several matches. Allows respecting \"nested\"\n    -- comment leaders like \"---\" and \"--\".\n    if type(cur_match) == 'string' and comment_indent:len() < cur_match:len() then comment_indent = cur_match end\n  end\n  return comment_indent ~= '' and comment_indent or line:match('^%s*')\nend\n\nH.get_comment_leaders = function()\n  local res = {}\n\n  -- From 'commentstring'\n  local main_leader = vim.split(vim.bo.commentstring, '%%s')[1]\n  table.insert(res, vim.trim(main_leader))\n\n  -- From 'comments'\n  for _, comment_part in ipairs(vim.opt_local.comments:get()) do\n    local prefix, suffix = comment_part:match('^(.*):(.*)$')\n    suffix = vim.trim(suffix)\n    if prefix:find('b') then\n      -- Respect `b` flag (for blank) requiring space, tab or EOL after it\n      table.insert(res, suffix .. ' ')\n      table.insert(res, suffix .. '\\t')\n    elseif prefix:find('f') == nil then\n      -- Add otherwise ignoring `f` flag (only first line should have it)\n      table.insert(res, suffix)\n    end\n  end\n\n  return res\nend\n\nH.dedent = function(lines, row, col)\n  if #lines <= 1 then return lines end\n  -- Compute common (smallest) indent width. Not accounting for actual indent\n  -- characters is easier and works for common cases but breaks for weird ones,\n  -- like `# a\\n\\t# b`.\n  local init_line_at_pos = vim.fn.getline(row + 1):sub(1, col)\n  local indent_width = H.get_indent(init_line_at_pos):len()\n  for i = 2, #lines do\n    -- Don't count \"only indent\" lines (i.e. blank with/without comment leader)\n    local cur_indent = H.get_indent(lines[i])\n    if cur_indent:len() < indent_width and cur_indent ~= lines[i] then indent_width = cur_indent:len() end\n  end\n\n  for i = 2, #lines do\n    lines[i] = lines[i]:sub(indent_width + 1)\n  end\n\n  return lines\nend\n\nH.reindent = function(lines, row, col)\n  if #lines <= 1 then return lines end\n  local init_line_at_pos = vim.fn.getline(row + 1):sub(1, col)\n  local indent = H.get_indent(init_line_at_pos)\n  for i = 2, #lines do\n    -- NOTE: reindent even \"pure indent\" lines, as it seems more natural\n    lines[i] = indent .. lines[i]\n  end\n  return lines\nend\n\n-- LSP server -----------------------------------------------------------------\nH.lsp_make_cmd = function(opts)\n  local capabilities = {\n    capabilities = { completionProvider = { triggerCharacters = opts.triggers, resolveProvider = false } },\n  }\n  local textdocument_completion = H.lsp_make_textdocument_completion(opts)\n\n  return function(dispatchers)\n    -- Loose adaptation of https://github.com/neovim/neovim/pull/24338\n    local is_closing, request_id = false, 0\n    return {\n      request = function(method, params, callback, notify_reply_callback)\n        if method == 'initialize' then callback(nil, capabilities) end\n        if method == 'textDocument/completion' then textdocument_completion(params, callback) end\n        if method == 'shutdown' then callback(nil, nil) end\n        request_id = request_id + 1\n        -- NOTE: This is needed to not accumulated \"pending\" `Client.requests`\n        if notify_reply_callback then vim.schedule(function() pcall(notify_reply_callback, request_id) end) end\n        return true, request_id\n      end,\n      notify = function(method, params)\n        if method == 'exit' then dispatchers.on_exit(0, 15) end\n        return false\n      end,\n      is_closing = function() return is_closing end,\n      terminate = function() is_closing = true end,\n    }\n  end\nend\n\nH.lsp_make_textdocument_completion = function(opts)\n  local expand_opts = { match = opts.match, insert = false }\n  local insert_text_format_snippet = vim.lsp.protocol.InsertTextFormat.Snippet\n  local kind_snippet = vim.lsp.protocol.CompletionItemKind.Snippet\n\n  return vim.schedule_wrap(function(params, callback)\n    local res = {}\n    for _, s in ipairs(MiniSnippets.expand(expand_opts)) do\n      local candidate = { label = s.prefix, insertText = s.body, documentation = s.desc }\n      -- NOTE: set `detail` along with `documentation` if it provides new info\n      candidate.detail = s.body ~= s.desc and s.body or nil\n      candidate.insertTextFormat, candidate.kind = insert_text_format_snippet, kind_snippet\n      if s.region ~= nil then\n        local from, to = s.region.from, s.region.to\n        local range_start = { line = from.line - 1, character = from.col - 1 }\n        local range_end = { line = to.line - 1, character = to.col }\n        candidate.textEdit = { newText = s.body, range = { start = range_start, ['end'] = range_end } }\n        candidate.insertText = nil\n      end\n      table.insert(res, candidate)\n    end\n\n    callback(nil, res)\n  end)\nend\n\nH.lsp_default_before_attach = function(buf_id)\n  return vim.api.nvim_buf_is_loaded(buf_id) and vim.bo[buf_id].buftype == ''\nend\n\n-- Validators -----------------------------------------------------------------\nH.is_string = function(x) return type(x) == 'string' end\n\nH.is_maybe_string_or_arr = function(x) return x == nil or H.is_string(x) or H.is_array_of(x, H.is_string) end\n\nH.is_snippet = function(x)\n  return type(x) == 'table'\n    -- Allow nil `prefix`: inferred as empty string\n    and H.is_maybe_string_or_arr(x.prefix)\n    -- Allow nil `body` to remove snippet with `prefix`\n    and H.is_maybe_string_or_arr(x.body)\n    -- Allow nil `desc` / `description`, in which case \"prefix\" is used\n    and H.is_maybe_string_or_arr(x.desc)\n    and H.is_maybe_string_or_arr(x.description)\n    -- Allow nil `region` because it is not mandatory\n    and (x.region == nil or H.is_region(x.region))\nend\n\nH.is_position = function(x) return type(x) == 'table' and type(x.line) == 'number' and type(x.col) == 'number' end\n\nH.is_region = function(x) return type(x) == 'table' and H.is_position(x.from) and H.is_position(x.to) end\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.snippets) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.notify = function(msg, level_name, silent)\n  if not silent then vim.notify('(mini.snippets) ' .. msg, vim.log.levels[level_name]) end\nend\n\nH.trigger_event = function(event_name, data) vim.api.nvim_exec_autocmds('User', { pattern = event_name, data = data }) end\n\nH.is_array_of = function(x, predicate)\n  if not H.islist(x) then return false end\n  for i = 1, #x do\n    if not predicate(x[i]) then return false end\n  end\n  return true\nend\n\nH.is_loaded_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_loaded(buf_id) end\n\nH.ensure_cur_buf = function(buf_id)\n  if buf_id == 0 or buf_id == vim.api.nvim_get_current_buf() or not H.is_loaded_buf(buf_id) then return end\n  local win_id = vim.fn.win_findbuf(buf_id)[1]\n  if win_id == nil then return vim.api.nvim_win_set_buf(0, buf_id) end\n  vim.api.nvim_set_current_win(win_id)\nend\n\nH.set_cursor = function(pos)\n  -- Ensure no built-in completion window\n  -- HACK: Always clearing (and not *only* when pumvisible) accounts for weird\n  -- edge case when it is not visible (i.e. candidates *just* got exhausted)\n  -- but will still \"clear and restore\" text leading to squashing of extmarks.\n  H.hide_completion()\n\n  -- NOTE: This won't put cursor past enf of line (for cursor in Insert mode to\n  -- append text to the line). Ensure that Insert mode is active prior.\n  vim.api.nvim_win_set_cursor(0, pos)\nend\n\nH.call_in_insert_mode = function(f)\n  if vim.fn.mode() == 'i' then return f() end\n\n  -- This is seemingly the only \"good\" way to ensure Insert mode.\n  -- Mostly because it works with `vim.snippet.expand()` as its implementation\n  -- uses `vim.api.nvim_feedkeys(k, 'n', true)` to select text in Select mode.\n  vim.api.nvim_feedkeys('\\28\\14i', 'n', false)\n\n  -- NOTE: mode changing is not immediate, only on some next tick. So schedule\n  -- to execute `f` precisely when Insert mode is active.\n  local cb = function() f() end\n  vim.api.nvim_create_autocmd('ModeChanged', { pattern = '*:i*', once = true, callback = cb, desc = 'Call in Insert' })\nend\n\nH.delete_region = function(region)\n  if not H.is_region(region) then return end\n  vim.api.nvim_buf_set_text(0, region.from.line - 1, region.from.col - 1, region.to.line - 1, region.to.col, {})\n  H.set_cursor({ region.from.line, region.from.col - 1 })\nend\n\nH.show_completion = function(items, startcol)\n  if items == nil or #items == 0 or vim.fn.mode() ~= 'i' then return end\n  vim.fn.complete(startcol or vim.fn.col('.'), items)\nend\n\nH.hide_completion = function()\n  -- NOTE: `complete()` instead of emulating <C-y> has immediate effect\n  -- (without the need to `vim.schedule()`). The downsides are that `fn.mode(1)`\n  -- returns 'ic' (i.e. not \"i\" for clean Insert mode) and <C-n>/<C-p> act as if\n  -- there is completion active (thus not allowing them as custom mappings).\n  -- Appending ` | call feedkeys(\"\\\\<C-y>\", \"n\")` removes that, but still would\n  -- require workarounds to work in edge cases.\n  -- NOTE: Use `silent` to not show \"Pattern not found\" messages. It also hides\n  -- '--INSERT--' temporarily when 'showmode' is active, but seems acceptable.\n  if vim.fn.mode() == 'i' then vim.cmd('silent noautocmd call complete(col(\".\"), [])') end\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nreturn MiniSnippets\n"
  },
  {
    "path": "lua/mini/splitjoin.lua",
    "content": "--- *mini.splitjoin* Split and join arguments\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n--- - Mappings and Lua functions that modify arguments (regions inside brackets\n---   between allowed separators) under cursor.\n---\n---   Supported actions:\n---     - Toggle - split if arguments are on single line, join otherwise.\n---       Main supported function of the module. See |MiniSplitjoin.toggle()|.\n---     - Split - make every argument separator be on end of separate line.\n---       See |MiniSplitjoin.split()|.\n---     - Join - make all arguments be on single line.\n---       See |MiniSplitjoin.join()|.\n---\n--- - Mappings are dot-repeatable in Normal mode and work in Visual mode.\n---\n--- - Customizable argument detection (see |MiniSplitjoin.config.detect|):\n---     - Which brackets can contain arguments.\n---     - Which strings can separate arguments.\n---     - Which regions are excluded when looking for separators (like inside\n---       nested brackets or quotes).\n---\n--- - Customizable pre and post hooks for both split and join. See `split` and\n---   `join` in |MiniSplitjoin.config|. There are several built-in ones\n---   in |MiniSplitjoin.gen_hook|.\n---\n--- - Works inside comments by using modified notion of indent.\n---   See |MiniSplitjoin.get_indent_part()|.\n---\n--- - Provides low-level Lua functions for split and join at positions.\n---   See |MiniSplitjoin.split_at()| and |MiniSplitjoin.join_at()|.\n---\n--- Notes:\n--- - Search for arguments is done using Lua patterns (regex-like approach).\n---   Certain amount of false positives is to be expected.\n---\n--- - This module is mostly designed around |MiniSplitjoin.toggle()|. If target\n---   split positions are on different lines, join first and then split.\n---\n--- - Actions can be done on Visual mode selection, which mostly present as\n---   a safety route in case of incorrect detection of initial region.\n---   It uses |MiniSplitjoin.get_visual_region()| which treats selection as full\n---   brackets (include brackets in selection).\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.splitjoin').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniSplitjoin`\n--- which you can use for scripting or manually (with `:lua MiniSplitjoin.*`).\n---\n--- See |MiniSplitjoin.config| for available config settings.\n---\n--- You can override runtime config settings (like action hooks) locally to\n--- buffer inside `vim.b.minisplitjoin_config` which should have same structure\n--- as `MiniSplitjoin.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [FooSoft/vim-argwrap](https://github.com/FooSoft/vim-argwrap):\n---     - Mostly has the same design as this module.\n---     - Doesn't work inside comments, while this module does.\n---     - Has more built-in ways to control split and join, while this module\n---       intentionally provides only handful.\n--- - [AndrewRadev/splitjoin.vim](https://github.com/AndrewRadev/splitjoin.vim):\n---     - More oriented towards language-depended transformations, while this\n---       module intntionally deals with more generic text-related functionality.\n--- - [Wansmer/treesj](https://github.com/Wansmer/treesj):\n---     - Operates based on tree-sitter nodes. This is more accurate in\n---       some edge cases, but **requires** tree-sitter parser.\n---     - Doesn't work inside comments or strings.\n---\n--- # Disabling ~\n---\n--- To disable, set `g:minisplitjoin_disable` (globally) or `b:minisplitjoin_disable`\n--- (for a buffer) to `v:true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniSplitjoin\n\n--- POSITION ~\n--- Table with fields <line> and <col> containing line and column numbers\n--- respectively. Both are 1-indexed. Example: `{ line = 2, col = 1 }`.\n---\n--- REGION ~\n--- Table representing region in a buffer. Fields: <from> and <to> for\n--- inclusive start and end positions. Example: >lua\n---\n---   { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }\n--- <\n---@tag MiniSplitjoin-glossary\n\n---@alias __splitjoin_options table|nil Options. Has structure from |MiniSplitjoin.config|\n---   inheriting its default values.\n---\n---   Following extra optional fields are allowed:\n---   - <position> `(table)` - position at which to find smallest bracket region.\n---     See |MiniSplitjoin-glossary| for the structure.\n---     Default: cursor position.\n---   - <region> `(table)` - region at which to perform action. Assumes inclusive\n---     both start at left bracket and end at right bracket.\n---     See |MiniSplitjoin-glossary| for the structure.\n---     Default: `nil` to automatically detect region.\n---@alias __splitjoin_hook_brackets - <brackets> `(table)` - array of bracket patterns indicating on which\n---      brackets action should be made. Has same structure as `brackets`\n---      in |MiniSplitjoin.config.detect|.\n---      Default: `MiniSplitjoin.config.detect.brackets`.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n\n-- Module definition ==========================================================\nlocal MiniSplitjoin = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniSplitjoin.config|.\n---\n---@usage >lua\n---   require('mini.splitjoin').setup() -- use default config\n---   -- OR\n---   require('mini.splitjoin').setup({}) -- replace {} with your config table\n--- <\nMiniSplitjoin.setup = function(config)\n  -- Export module\n  _G.MiniSplitjoin = MiniSplitjoin\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Detection ~\n--- *MiniSplitjoin.config.detect*\n---\n--- The table at `config.detect` controls how arguments are detected using Lua\n--- patterns. General idea is to convert whole buffer into a single line,\n--- perform string search, and convert results back into 2d positions.\n---\n--- Example configuration: >lua\n---\n---   require('mini.splitjoin').setup({\n---     detect = {\n---       -- Detect only inside balanced parenthesis\n---       brackets = { '%b()' },\n---\n---       -- Allow both `,` and `;` to separate arguments\n---       separator = '[,;]',\n---\n---       -- Make any separator define an argument\n---       exclude_regions = {},\n---     },\n---   })\n--- <\n--- ## Outer brackets ~\n---\n--- `detect.brackets` is an array of Lua patterns used to find enclosing region.\n--- It is done by traversing whole buffer to find the smallest region matching\n--- any supplied pattern.\n---\n--- Default: `nil`, inferred as `{ '%b()', '%b[]', '%b{}' }`.\n--- So an argument can be inside a balanced `()`, `[]`, or `{}`.\n---\n--- Example: `brackets = { '%b()' }` will search for arguments only inside\n--- balanced `()`.\n---\n--- ## Separator ~\n---\n--- `detect.separator` is a single Lua pattern defining which strings should be\n--- treated as argument separators.\n---\n--- Empty string in `detect.separator` will result in only surrounding brackets\n--- used as separators.\n---\n--- Only end of pattern match will be used as split/join positions.\n---\n--- Default: `','`. So an argument can be separated only with comma.\n---\n--- Example: `separator = { '[,;]' }` will treat both `,` and `;` as separators.\n---\n--- ## Excluded regions ~\n---\n--- `detect.exclude_regions` is an array of Lua patterns for sub-regions from which\n--- to exclude separators. Enables correct detection in case of nested brackets\n--- and quotes.\n---\n--- Default: `nil`; inferred as `{ '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" }`.\n--- So a separator **can not** be inside a balanced `()`, `[]`, `{}` (representing\n--- nested argument regions) or `\"\"`, `''` (representing strings).\n---\n--- Example: `exclude_regions = {}` will not exclude any regions. So in case of\n--- `f(a, { b, c })` it will detect both commas as argument separators.\n---\n--- # Hooks ~\n---\n--- `split.hooks_pre`, `split.hooks_post`, `join.hooks_pre`, and `join.hooks_post`\n--- are arrays of hook functions. If empty (default) no hook is applied.\n---\n--- Hooks should take and return array of positions. See |MiniSplitjoin-glossary|.\n---\n--- They can be used to tweak actions:\n---\n--- - Pre-hooks are called before action. Each is applied on the output of\n---   previous one. Input of first hook are detected split/join positions.\n---   Output of last one is actually used to perform split/join.\n---\n--- - Post-hooks are called after action. Each is applied on the output of\n---   previous one. Input of first hook are split/join positions from actual\n---   action plus its region's right end as last position (for easier hook code).\n---   Output of last one is used as action return value.\n---\n--- For more specific details see |MiniSplitjoin.split()| and |MiniSplitjoin.join()|.\n---\n--- See |MiniSplitjoin.gen_hook| for generating common hooks with examples.\nMiniSplitjoin.config = {\n  -- Module mappings. Use `''` (empty string) to disable one.\n  -- Created for both Normal and Visual modes.\n  mappings = {\n    toggle = 'gS',\n    split = '',\n    join = '',\n  },\n\n  -- Detection options: where split/join should be done\n  detect = {\n    -- Array of Lua patterns to detect region with arguments.\n    -- Default: { '%b()', '%b[]', '%b{}' }\n    brackets = nil,\n\n    -- String Lua pattern defining argument separator\n    separator = ',',\n\n    -- Array of Lua patterns for sub-regions to exclude separators from.\n    -- Enables correct detection in presence of nested brackets and quotes.\n    -- Default: { '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" }\n    exclude_regions = nil,\n  },\n\n  -- Split options\n  split = {\n    hooks_pre = {},\n    hooks_post = {},\n  },\n\n  -- Join options\n  join = {\n    hooks_pre = {},\n    hooks_post = {},\n  },\n}\n--minidoc_afterlines_end\n\n--- Toggle arguments\n---\n--- Overview:\n--- - Detect region at input position: either by using supplied `opts.region` or\n---   by finding smallest bracketed region surrounding position.\n---   See |MiniSplitjoin.config.detect| for more details.\n--- - If region spans single line, use |MiniSplitjoin.split()| with found region.\n---   Otherwise use |MiniSplitjoin.join()|.\n---\n---@param opts __splitjoin_options\n---\n---@return any Output of chosen `split()` or `join()` action.\nMiniSplitjoin.toggle = function(opts)\n  if H.is_disabled() then return end\n\n  opts = H.get_opts(opts)\n\n  local region = opts.region or H.find_smallest_bracket_region(opts.position, opts.detect.brackets)\n  if region == nil then return end\n\n  opts.region = region\n  if region.from.line == region.to.line then\n    return MiniSplitjoin.split(opts)\n  else\n    return MiniSplitjoin.join(opts)\n  end\nend\n\n--- Split arguments\n---\n--- Overview:\n--- - Detect region: either by using supplied `opts.region` or by finding smallest\n---   bracketed region surrounding input position (cursor position by default).\n---   See |MiniSplitjoin.config.detect| for more details.\n---\n--- - Find separator positions using `separator` and `exclude_regions` from `opts`.\n---   Both brackets are treated as separators.\n---   See |MiniSplitjoin.config.detect| for more details.\n---   Note: stop if no separator positions are found.\n---\n--- - Modify separator positions to represent split positions. Last split position\n---   (which is inferred from right bracket) is moved one column to left so that\n---   right bracket would move on new line.\n---\n--- - Apply all hooks from `opts.split.hooks_pre`. Each is applied on the output of\n---   previous one. Input of first hook is split positions from previous step.\n---   Output of last one is used as split positions in next step.\n---\n--- - Split and update split positions with |MiniSplitjoin.split_at()|.\n---\n--- - Apply all hooks from `opts.split.hooks_post`. Each is applied on the output of\n---   previous one. Input of first hook is split positions from previous step plus\n---   region's right end (for easier hook code).\n---   Output of last one is used as function return value.\n---\n--- Note:\n--- - By design, it doesn't detect if argument **should** be split, so application\n---   on arguments spanning multiple lines can lead to undesirable result.\n---\n---@param opts __splitjoin_options\n---\n---@return any Output of last `opts.split.hooks_post` or `nil` if no split positions\n---   found. Default: return value of |MiniSplitjoin.split_at()| application.\nMiniSplitjoin.split = function(opts)\n  if H.is_disabled() then return end\n\n  opts = H.get_opts(opts)\n\n  local region = opts.region or H.find_smallest_bracket_region(opts.position, opts.detect.brackets)\n  if region == nil then return nil end\n\n  local positions = H.find_split_positions(region, opts.detect.separator, opts.detect.exclude_regions)\n  if #positions == 0 then return nil end\n\n  -- Call pre-hooks\n  for _, hook in ipairs(opts.split.hooks_pre) do\n    positions = hook(positions)\n  end\n\n  -- Split at positions\n  local split_positions = MiniSplitjoin.split_at(positions)\n\n  -- Call post-hooks to tweak splits. Add right bracket for easier hook code.\n  local last = split_positions[#split_positions]\n  local last_next_line = vim.fn.getline(last.line + 1)\n  local new_col = MiniSplitjoin.get_indent_part(last_next_line):len() + 1\n  table.insert(split_positions, { line = last.line + 1, col = new_col })\n\n  for _, hook in ipairs(opts.split.hooks_post) do\n    split_positions = hook(split_positions)\n  end\n\n  return split_positions\nend\n\n--- Join arguments\n---\n--- Overview:\n--- - Detect region: either by using supplied `opts.region` or by finding smallest\n---   bracketed region surrounding input position (cursor position by default).\n---   See |MiniSplitjoin.config.detect| for more details.\n---\n--- - Compute join positions to be line ends of all but last region lines.\n---   Note: stop if no join positions are found.\n---\n--- - Apply all hooks from `opts.join.hooks_pre`. Each is applied on the output\n---   of previous one. Input of first hook is join positions from previous step.\n---   Output of last one is used as join positions in next step.\n---\n--- - Join and update join positions with |MiniSplitjoin.join_at()|.\n---\n--- - Apply all hooks from `opts.join.hooks_post`. Each is applied on the output\n---   of previous one. Input of first hook is join positions from previous step\n---   plus region's right end for easier hook code.\n---   Output of last one is used as function return value.\n---\n---@param opts __splitjoin_options\n---\n---@return any Output of last `opts.split.hooks_post` or `nil` of no join positions\n---   found. Default: return value of |MiniSplitjoin.join_at()| application.\nMiniSplitjoin.join = function(opts)\n  if H.is_disabled() then return end\n\n  opts = H.get_opts(opts)\n\n  local region = opts.region or H.find_smallest_bracket_region(opts.position, opts.detect.brackets)\n  if region == nil then return nil end\n\n  local positions = H.find_join_positions(region)\n  if #positions == 0 then return nil end\n\n  -- Call pre-hooks\n  for _, hook in ipairs(opts.join.hooks_pre) do\n    positions = hook(positions)\n  end\n\n  -- Join at positions\n  local join_positions = MiniSplitjoin.join_at(positions)\n\n  -- Call post-hooks to tweak joins. Add right bracket for easier hook code.\n  local last = join_positions[#join_positions]\n  table.insert(join_positions, { line = last.line, col = last.col + 1 })\n\n  for _, hook in ipairs(opts.join.hooks_post) do\n    join_positions = hook(join_positions)\n  end\n\n  return join_positions\nend\n\n--- Generate common hooks\n---\n--- This is a table with function elements. Call to actually get hook.\n---\n--- All generated post-hooks return updated versions of their input reflecting\n--- changes done inside hook.\n---\n--- Example for `lua` filetype (place it in 'lua.lua' filetype plugin, |ftplugin|): >lua\n---\n---   local gen_hook = MiniSplitjoin.gen_hook\n---   local curly = { brackets = { '%b{}' } }\n---\n---   -- Add trailing comma when splitting inside curly brackets\n---   local add_comma_curly = gen_hook.add_trailing_separator(curly)\n---\n---   -- Delete trailing comma when joining inside curly brackets\n---   local del_comma_curly = gen_hook.del_trailing_separator(curly)\n---\n---   -- Pad curly brackets with single space after join\n---   local pad_curly = gen_hook.pad_brackets(curly)\n---\n---   -- Create buffer-local config\n---   vim.b.minisplitjoin_config = {\n---     split = { hooks_post = { add_comma_curly } },\n---     join  = { hooks_post = { del_comma_curly, pad_curly } },\n---   }\n--- <\nMiniSplitjoin.gen_hook = {}\n\n--- Generate hook to pad brackets\n---\n--- This is a join post-hook. Use in `join.hooks_post` of |MiniSplitjoin.config|.\n---\n---@param opts table|nil Options. Possible fields:\n---    - <pad> `(string)` - pad to add after first and before last join positions.\n---      Default: `' '` (single space).\n---    __splitjoin_hook_brackets\n---\n---@return function A hook which adds inner pad to first and last join positions and\n---   returns updated input join positions.\nMiniSplitjoin.gen_hook.pad_brackets = function(opts)\n  opts = opts or {}\n  local pad = opts.pad or ' '\n  local brackets = opts.brackets or H.get_opts(opts).detect.brackets\n  local n_pad = pad:len()\n\n  return function(join_positions)\n    -- Act only on actual join\n    local n_pos = #join_positions\n    if n_pos == 0 or pad == '' then return join_positions end\n\n    -- Act only if brackets are matched. First join position should be exactly\n    -- on left bracket, last - just before right bracket.\n    local first, last = join_positions[1], join_positions[n_pos]\n    local brackets_matched = H.is_positions_inside_brackets(first, last, brackets)\n    if not brackets_matched then return join_positions end\n\n    -- Pad only in case of non-trivial join\n    if first.line == last.line and (last.col - first.col) <= 1 then return join_positions end\n\n    -- Add pad after left and before right edges\n    H.set_text(first.line - 1, last.col - 1, first.line - 1, last.col - 1, { pad })\n    H.set_text(first.line - 1, first.col, first.line - 1, first.col, { pad })\n\n    -- Update `join_positions` to reflect text change\n    -- - Account for left pad\n    for i = 2, n_pos do\n      join_positions[i].col = join_positions[i].col + n_pad\n    end\n    -- - Account for right pad\n    join_positions[n_pos].col = join_positions[n_pos].col + n_pad\n\n    return join_positions\n  end\nend\n\n--- Generate hook to add trailing separator\n---\n--- This is a split post-hook. Use in `split.hooks_post` of |MiniSplitjoin.config|.\n---\n---@param opts table|nil Options. Possible fields:\n---    - <sep> `(string)` - separator to add before last split position.\n---      Default: `','`.\n---    __splitjoin_hook_brackets\n---\n---@return function A hook which adds separator before last split position and\n---   returns updated input split positions.\nMiniSplitjoin.gen_hook.add_trailing_separator = function(opts)\n  opts = opts or {}\n  local sep = opts.sep or ','\n  local brackets = opts.brackets or H.get_opts(opts).detect.brackets\n\n  return function(split_positions)\n    -- Add only in case there is at least one argument\n    local n_pos = #split_positions\n    if n_pos < 3 then return split_positions end\n\n    -- Act only if brackets are matched\n    local first, last = split_positions[1], split_positions[n_pos]\n    local brackets_matched = H.is_positions_inside_brackets(first, last, brackets)\n    if not brackets_matched then return split_positions end\n\n    -- Act only if there is no trailing separator already\n    local target_line = vim.fn.getline(last.line - 1)\n    local target_col = target_line:find(vim.pesc(sep) .. '$')\n    if target_col ~= nil then return split_positions end\n\n    -- Add trailing separator\n    local col = target_line:len()\n    H.set_text(last.line - 2, col, last.line - 2, col, { sep })\n\n    -- Don't update `split_positions`, as appending to line has no effect\n    return split_positions\n  end\nend\n\n--- Generate hook to delete trailing separator\n---\n--- This is a join post-hook. Use in `join.hooks_post` of |MiniSplitjoin.config|.\n---\n---@param opts table|nil Options. Possible fields:\n---    - <sep> `(string)` - separator to remove before last join position.\n---      Default: `','`.\n---    __splitjoin_hook_brackets\n---\n---@return function A hook which adds separator before last split position and\n---   returns updated input split positions.\nMiniSplitjoin.gen_hook.del_trailing_separator = function(opts)\n  opts = opts or {}\n  local sep = opts.sep or ','\n  local brackets = opts.brackets or H.get_opts(opts).detect.brackets\n  local n_sep = sep:len()\n\n  return function(join_positions)\n    -- Act only on actual join\n    local n_pos = #join_positions\n    if n_pos == 0 then return join_positions end\n\n    -- Act only if brackets are matched\n    local first, last = join_positions[1], join_positions[n_pos]\n    local brackets_matched = H.is_positions_inside_brackets(first, last, brackets)\n    if not brackets_matched then return join_positions end\n\n    -- Act only if there is matched trailing separator\n    local target_line = vim.fn.getline(last.line):sub(1, last.col - 1)\n    local target_col = target_line:find(vim.pesc(sep) .. '%s*$')\n    if target_col == nil then return join_positions end\n\n    -- Remove trailing separator\n    H.set_text(last.line - 1, target_col - 1, last.line - 1, target_col - 1 + n_sep, {})\n\n    -- Update `join_positions` to reflect text change. Update last as it moved.\n    -- Do not update second to last because it didn't affect what was tracked.\n    join_positions[n_pos] = { line = last.line, col = last.col - n_sep }\n\n    return join_positions\n  end\nend\n\n--- Split at positions\n---\n--- Overview:\n--- - For each position move all characters after it to next line and make it have\n---   same indent as current one (see |MiniSplitjoin.get_indent_part()|).\n---   Also remove trailing whitespace at position line.\n---\n--- - Increase indent of inner lines by a single pad: tab in case of |'noexpandtab'|\n---   or |shiftwidth()| number of spaces otherwise.\n---\n--- Notes:\n--- - Cursor is adjusted to follow text updates.\n--- - Use output of this function to keep track of input positions.\n---\n---@param positions table Array of positions at which to perform split.\n---   See |MiniSplitjoin-glossary| for their structure. Note: they don't have\n---   to be ordered, but first and last ones will be used to infer lines for\n---   which indent will be increased.\n---\n---@return table Array of new positions to where input `positions` were moved.\nMiniSplitjoin.split_at = function(positions)\n  local n_pos = #positions\n  if n_pos == 0 then return {} end\n\n  -- Cache values that might change\n  local cursor_extmark = H.put_extmark_at_positions({ H.get_cursor_pos() })[1]\n  local input_extmarks = H.put_extmark_at_positions(positions)\n\n  -- Split at extmark positions\n  for i = 1, n_pos do\n    H.split_at_extmark(input_extmarks[i])\n  end\n\n  -- Increase indent of inner lines\n  local first_new_pos = H.get_extmark_pos(input_extmarks[1])\n  local last_new_pos = H.get_extmark_pos(input_extmarks[n_pos])\n  H.increase_indent(first_new_pos.line + 1, last_new_pos.line)\n\n  -- Put cursor back on tracked position\n  H.put_cursor_at_extmark(cursor_extmark)\n\n  -- Reconstruct input positions\n  local res = vim.tbl_map(H.get_extmark_pos, input_extmarks)\n  vim.api.nvim_buf_clear_namespace(0, H.ns_id, 0, -1)\n  return res\nend\n\n--- Join at positions\n---\n--- Overview:\n--- - For each position join its line with the next line. Joining is done by\n---   replacing trailing whitespace of the line and indent of its next line\n---   (see |MiniSplitjoin.get_indent_part()|) with a pad string (single space except\n---   empty string for first and last positions). To adjust this, use hooks\n---   (for example, see |MiniSplitjoin.gen_hook.pad_brackets()|).\n---\n--- Notes:\n--- - Cursor is adjusted to follow text updates.\n--- - Use output of this function to keep track of input positions.\n---\n---@param positions table Array of positions at which to perform join.\n---   See |MiniSplitjoin-glossary| for their structure. Note: they don't have\n---   to be ordered, but first and last ones will have different pad string.\n---\n---@return table Array of new positions to where input `positions` were moved.\nMiniSplitjoin.join_at = function(positions)\n  local n_pos = #positions\n  if n_pos == 0 then return {} end\n\n  -- Cache values that might change\n  local cursor_extmark = H.put_extmark_at_positions({ H.get_cursor_pos() })[1]\n  local input_extmarks = H.put_extmark_at_positions(positions)\n\n  -- Join at positions which are changing following extmarks\n  for i = 1, n_pos do\n    local cur_pad_string = (i == 1 or i == n_pos) and '' or ' '\n    H.join_at_extmark(input_extmarks[i], cur_pad_string)\n  end\n\n  -- Put cursor back on tracked position\n  H.put_cursor_at_extmark(cursor_extmark)\n\n  -- Reconstruct input positions\n  local res = vim.tbl_map(H.get_extmark_pos, input_extmarks)\n  vim.api.nvim_buf_clear_namespace(0, H.ns_id, 0, -1)\n  return res\nend\n\n--- Get previous visual region\n---\n--- Get previous visual selection using |'<| and |'>| marks in the format of\n--- region (see |MiniSplitjoin-glossary|). Used in Visual mode mappings.\n---\n--- Note:\n--- - Both marks are included in region.\n--- - In linewise mode start is at column 1 and end is at line's last character.\n---\n---@return table A region. See |MiniSplitjoin-glossary| for exact structure.\nMiniSplitjoin.get_visual_region = function()\n  local from_pos, to_pos = vim.fn.getpos(\"'<\"), vim.fn.getpos(\"'>\")\n  local from, to = { line = from_pos[2], col = from_pos[3] }, { line = to_pos[2], col = to_pos[3] }\n  -- Tweak for linewise Visual selection\n  if vim.fn.visualmode() == 'V' then\n    from.col, to.col = 1, vim.fn.col({ to.line, '$' }) - 1\n  end\n\n  return { from = from, to = to }\nend\n\n--- Get string's indent part\n---\n---@param line string String for which to compute indent.\n---@param respect_comments boolean|nil Whether to respect comments as indent part.\n---   Default: `true`.\n---\n---@return string Part of input representing line's indent. Can be empty string.\n---   Use `string.len()` to compute indent in bytes.\nMiniSplitjoin.get_indent_part = function(line, respect_comments)\n  if respect_comments == nil then respect_comments = true end\n  if not respect_comments then return line:match('^%s*') end\n\n  -- Make it respect various comment leaders\n  local comment_indent = H.get_comment_indent(line, H.get_comment_leaders())\n  if comment_indent ~= '' then return comment_indent end\n\n  return line:match('^%s*')\nend\n\n--- Operator for Normal mode mappings\n---\n--- Main function to be used in expression mappings. No need to use it\n--- directly, everything is setup in |MiniSplitjoin.setup()|.\n---\n---@param task string Name of task.\nMiniSplitjoin.operator = function(task)\n  local is_init_call = task == 'toggle' or task == 'split' or task == 'join'\n  if not is_init_call then\n    MiniSplitjoin[H.cache.operator_task]()\n    return ''\n  end\n\n  if H.is_disabled() then\n    -- Using `<Esc>` prevents moving cursor caused by current implementation\n    -- detail of adding `' '` inside expression mapping\n    return [[\\<Esc>]]\n  end\n\n  H.cache.operator_task = task\n  vim.o.operatorfunc = 'v:lua.MiniSplitjoin.operator'\n  return 'g@'\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniSplitjoin.config)\n\nH.ns_id = vim.api.nvim_create_namespace('MiniSplitjoin')\n\nH.cache = { operator_task = nil }\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('mappings.toggle', config.mappings.toggle, 'string', true)\n  H.check_type('mappings.split', config.mappings.split, 'string')\n  H.check_type('mappings.join', config.mappings.join, 'string', true)\n\n  H.check_type('detect', config.detect, 'table')\n  H.check_type('detect.brackets', config.detect.brackets, 'table', true)\n  H.check_type('detect.separator', config.detect.separator, 'string')\n  H.check_type('detect.exclude_regions', config.detect.exclude_regions, 'table', true)\n\n  H.check_type('split', config.split, 'table')\n  H.check_type('split.hooks_pre', config.split.hooks_pre, 'table')\n  H.check_type('split.hooks_post', config.split.hooks_post, 'table')\n\n  H.check_type('join', config.join, 'table')\n  H.check_type('join.hooks_pre', config.join.hooks_pre, 'table')\n  H.check_type('join.hooks_post', config.join.hooks_post, 'table')\n\n  return config\nend\n\n--stylua: ignore\nH.apply_config = function(config)\n  MiniSplitjoin.config = config\n\n  -- Make mappings\n  local maps = config.mappings\n\n  H.map('n', maps.toggle, 'v:lua.MiniSplitjoin.operator(\"toggle\") . \" \"', { expr = true, desc = 'Toggle arguments' })\n  H.map('n', maps.split,  'v:lua.MiniSplitjoin.operator(\"split\") . \" \"',  { expr = true, desc = 'Split arguments' })\n  H.map('n', maps.join,   'v:lua.MiniSplitjoin.operator(\"join\") . \" \"',   { expr = true, desc = 'Join arguments' })\n\n  H.map('x', maps.toggle, ':<C-u>lua MiniSplitjoin.toggle({ region = MiniSplitjoin.get_visual_region() })<CR>', { desc = 'Toggle arguments' })\n  H.map('x', maps.split,  ':<C-u>lua MiniSplitjoin.split({ region = MiniSplitjoin.get_visual_region() })<CR>',  { desc = 'Split arguments' })\n  H.map('x', maps.join,   ':<C-u>lua MiniSplitjoin.join({ region = MiniSplitjoin.get_visual_region() })<CR>',   { desc = 'Join arguments' })\nend\n\nH.is_disabled = function() return vim.g.minisplitjoin_disable == true or vim.b.minisplitjoin_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniSplitjoin.config, vim.b.minisplitjoin_config or {}, config or {})\nend\n\nH.get_opts = function(opts)\n  opts = opts or {}\n\n  -- Infer detect options. Can't use usual `vim.tbl_deep_extend()` because it\n  -- doesn't work properly on arrays\n  local default_detect = {\n    brackets = { '%b()', '%b[]', '%b{}' },\n    separator = ',',\n    exclude_regions = { '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" },\n  }\n  local config = H.get_config()\n\n  return {\n    position = opts.position or H.get_cursor_pos(),\n    region = opts.region,\n    -- Extend `detect` not deeply to avoid unwanted values from longer defaults\n    detect = vim.tbl_extend('force', default_detect, config.detect, opts.detect or {}),\n    split = vim.tbl_deep_extend('force', config.split, opts.split or {}),\n    join = vim.tbl_deep_extend('force', config.join, opts.join or {}),\n  }\nend\n\n-- Split ----------------------------------------------------------------------\nH.split_at_extmark = function(extmark_id)\n  local pos = H.get_extmark_pos(extmark_id)\n\n  -- Split\n  H.set_text(pos.line - 1, pos.col, pos.line - 1, pos.col, { '', '' })\n\n  -- Remove trailing whitespace on split line\n  local split_line = vim.fn.getline(pos.line)\n  local start_of_trailspace = split_line:find('%s*$')\n  H.set_text(pos.line - 1, start_of_trailspace - 1, pos.line - 1, split_line:len(), {})\n\n  -- Adjust indent on new line\n  local cur_indent = MiniSplitjoin.get_indent_part(vim.fn.getline(pos.line + 1))\n  local new_indent = MiniSplitjoin.get_indent_part(split_line)\n  H.set_text(pos.line, 0, pos.line, cur_indent:len(), { new_indent })\nend\n\nH.find_split_positions = function(region, separator, exclude_regions)\n  local sep_positions = H.find_separator_positions(region, separator, exclude_regions)\n  local n_pos = #sep_positions\n\n  sep_positions[n_pos].col = sep_positions[n_pos].col - 1\n  return sep_positions\nend\n\n-- Join -----------------------------------------------------------------------\nH.join_at_extmark = function(extmark_id, pad)\n  local line_num = H.get_extmark_pos(extmark_id).line\n  if vim.api.nvim_buf_line_count(0) <= line_num then return end\n\n  -- Join by replacing trailing whitespace of current line and indent of next\n  -- one with `pad`\n  local lines = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num + 1, true)\n  local above_start_col = lines[1]:len() - lines[1]:match('%s*$'):len()\n  local below_end_col = MiniSplitjoin.get_indent_part(lines[2]):len()\n\n  H.set_text(line_num - 1, above_start_col, line_num, below_end_col, { pad })\nend\n\nH.find_join_positions = function(region, separator, exclude_regions)\n  local lines = vim.api.nvim_buf_get_lines(0, region.from.line - 1, region.to.line, true)\n\n  -- Join whole region into single line\n  local res = {}\n  local init_line = region.from.line - 1\n  for i = 1, #lines - 1 do\n    table.insert(res, { line = init_line + i, col = lines[i]:len() })\n  end\n  return res\nend\n\n-- Detect ---------------------------------------------------------------------\nH.find_smallest_bracket_region = function(position, brackets)\n  local neigh = H.get_neighborhood()\n  local cur_offset = neigh.pos_to_offset(position)\n\n  local best_span = H.find_smallest_covering(neigh['1d'], cur_offset, brackets)\n  if best_span == nil then return nil end\n\n  return neigh.span_to_region(best_span)\nend\n\nH.find_smallest_covering = function(line, ref_offset, patterns)\n  local res, min_width = nil, math.huge\n  for _, pattern in ipairs(patterns) do\n    local cur_init = 0\n    local left, right = string.find(line, pattern, cur_init)\n    while left do\n      if left <= ref_offset and ref_offset <= right and (right - left) < min_width then\n        res, min_width = { from = left, to = right }, right - left\n      end\n\n      cur_init = left + 1\n      left, right = string.find(line, pattern, cur_init)\n    end\n  end\n\n  return res\nend\n\nH.find_separator_positions = function(region, separator, exclude_regions)\n  if separator == '' then return { region.from, region.to } end\n\n  local neigh = H.get_neighborhood()\n  local region_span = neigh.region_to_span(region)\n  local region_s = neigh['1d']:sub(region_span.from, region_span.to)\n\n  -- Match separator endings\n  local seps = {}\n  region_s:gsub(separator .. '()', function(r) table.insert(seps, r - 1) end)\n\n  -- Remove separators that are in excluded regions.\n  local inner_string, forbidden = region_s:sub(2, -2), {}\n  local add_to_forbidden = function(l, r) table.insert(forbidden, { from = l + 1, to = r }) end\n\n  for _, pat in ipairs(exclude_regions) do\n    inner_string:gsub('()' .. pat .. '()', add_to_forbidden)\n  end\n\n  -- - Also exclude trailing separator\n  inner_string:gsub('()' .. separator .. '%s*()$', add_to_forbidden)\n\n  local sub_offsets = vim.tbl_filter(function(x) return not H.is_offset_inside_spans(x, forbidden) end, seps)\n\n  -- Treat enclosing brackets as separators\n  if region_s:len() > 2 then\n    -- Use only last bracket in case of empty brackets\n    table.insert(sub_offsets, 1, 1)\n  end\n  table.insert(sub_offsets, region_s:len())\n\n  -- Convert offsets to positions\n  local start_offset = region_span.from\n  return vim.tbl_map(function(sub_off) return neigh.offset_to_pos(start_offset + sub_off - 1) end, sub_offsets)\nend\n\nH.is_offset_inside_spans = function(ref_point, spans)\n  for _, span in ipairs(spans) do\n    if span.from <= ref_point and ref_point <= span.to then return true end\n  end\n  return false\nend\n\nH.is_positions_inside_brackets = function(from_pos, to_pos, brackets)\n  local text_lines = vim.api.nvim_buf_get_text(0, from_pos.line - 1, from_pos.col - 1, to_pos.line - 1, to_pos.col, {})\n  local text = table.concat(text_lines, '\\n')\n\n  for _, b in ipairs(brackets) do\n    if text:find('^' .. b .. '$') ~= nil then return true end\n  end\n  return false\nend\n\nH.is_char_at_position = function(position, char)\n  local present_char = vim.fn.getline(position.line):sub(position.col, position.col)\n  return present_char == char\nend\n\n-- Simplified version of \"neighborhood\" from 'mini.ai':\n-- - Use whol buffer.\n-- - No empty regions or spans.\n--\n-- NOTEs:\n-- - `region = { from = { line = a, col = b }, to = { line = c, col = d } }`.\n--   End-inclusive charwise selection. All `a`, `b`, `c`, `d` are 1-indexed.\n-- - `offset` is the number between 1 to `neigh1d:len()`.\nH.get_neighborhood = function()\n  local neigh2d = vim.api.nvim_buf_get_lines(0, 0, -1, false)\n  -- Append 'newline' character to distinguish between lines in 1d case\n  -- (crucial for handling empty lines)\n  for k, v in pairs(neigh2d) do\n    neigh2d[k] = v .. '\\n'\n  end\n  local neigh1d = table.concat(neigh2d, '')\n  local n_lines = #neigh2d\n\n  -- Compute offsets for just before line starts\n  local line_offsets = {}\n  local cur_offset = 0\n  for i = 1, n_lines do\n    line_offsets[i] = cur_offset\n    cur_offset = cur_offset + neigh2d[i]:len()\n  end\n\n  -- Convert 2d buffer position to 1d offset\n  local pos_to_offset = function(pos) return line_offsets[pos.line] + pos.col end\n\n  -- Convert 1d offset to 2d buffer position\n  local offset_to_pos = function(offset)\n    for i = 1, n_lines - 1 do\n      if line_offsets[i] < offset and offset <= line_offsets[i + 1] then\n        return { line = i, col = offset - line_offsets[i] }\n      end\n    end\n\n    return { line = n_lines, col = offset - line_offsets[n_lines] }\n  end\n\n  -- Convert 2d region to 1d span\n  local region_to_span = function(region) return { from = pos_to_offset(region.from), to = pos_to_offset(region.to) } end\n\n  -- Convert 1d span to 2d region\n  local span_to_region = function(span) return { from = offset_to_pos(span.from), to = offset_to_pos(span.to) } end\n\n  return {\n    ['1d'] = neigh1d,\n    ['2d'] = neigh2d,\n    pos_to_offset = pos_to_offset,\n    offset_to_pos = offset_to_pos,\n    region_to_span = region_to_span,\n    span_to_region = span_to_region,\n  }\nend\n\n-- Extmarks -------------------------------------------------------------------\nH.put_extmark_at_positions = function(positions)\n  return vim.tbl_map(\n    function(pos) return vim.api.nvim_buf_set_extmark(0, H.ns_id, pos.line - 1, pos.col - 1, {}) end,\n    positions\n  )\nend\n\nH.get_extmark_pos = function(extmark_id)\n  local res = vim.api.nvim_buf_get_extmark_by_id(0, H.ns_id, extmark_id, {})\n  return { line = res[1] + 1, col = res[2] + 1 }\nend\n\nH.get_cursor_pos = function()\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  return { line = cur_pos[1], col = cur_pos[2] + 1 }\nend\n\nH.put_cursor_at_extmark = function(id)\n  local new_pos = vim.api.nvim_buf_get_extmark_by_id(0, H.ns_id, id, {})\n  vim.api.nvim_win_set_cursor(0, { new_pos[1] + 1, new_pos[2] })\n  vim.api.nvim_buf_del_extmark(0, H.ns_id, id)\nend\n\n-- Indent ---------------------------------------------------------------------\nH.increase_indent = function(from_line, to_line)\n  local lines = vim.api.nvim_buf_get_lines(0, from_line - 1, to_line, true)\n\n  -- Respect comment leaders only if all lines are commented\n  local comment_leaders = H.get_comment_leaders()\n  local respect_comments = H.is_comment_block(lines, comment_leaders)\n\n  -- Increase indent of all lines (end-inclusive)\n  local pad = vim.bo.expandtab and string.rep(' ', vim.fn.shiftwidth()) or '\\t'\n  for i, l in ipairs(lines) do\n    local n_indent = MiniSplitjoin.get_indent_part(l, respect_comments):len()\n\n    -- Don't increase indent of blank lines (possibly respecting comments)\n    local cur_by_string = l:len() == n_indent and '' or pad\n\n    local line_num = from_line + i - 1\n    H.set_text(line_num - 1, n_indent, line_num - 1, n_indent, { cur_by_string })\n  end\nend\n\nH.get_comment_indent = function(line, comment_leaders)\n  local res = ''\n\n  for _, leader in ipairs(comment_leaders) do\n    local cur_match = line:match('^%s*' .. vim.pesc(leader) .. '%s*')\n    -- Use biggest match in case of several matches. Allows respecting \"nested\"\n    -- comment leaders like \"---\" and \"--\".\n    if type(cur_match) == 'string' and res:len() < cur_match:len() then res = cur_match end\n  end\n\n  return res\nend\n\n-- Comments -------------------------------------------------------------------\nH.get_comment_leaders = function()\n  local res = {}\n\n  -- From 'commentstring'\n  local main_leader = vim.split(vim.bo.commentstring, '%%s')[1]\n  -- - Ensure there is no whitespace before or after\n  table.insert(res, vim.trim(main_leader))\n\n  -- From 'comments'\n  for _, comment_part in ipairs(vim.opt_local.comments:get()) do\n    local prefix, suffix = comment_part:match('^(.*):(.*)$')\n\n    -- Control whitespace around suffix\n    suffix = vim.trim(suffix)\n\n    if prefix:find('b') then\n      -- Respect `b` flag (for blank) requiring space, tab or EOL after it\n      table.insert(res, suffix .. ' ')\n      table.insert(res, suffix .. '\\t')\n    elseif prefix:find('f') == nil then\n      -- Add otherwise ignoring `f` flag (only first line should have it)\n      table.insert(res, suffix)\n    end\n  end\n\n  return res\nend\n\nH.is_comment_block = function(lines, comment_leaders)\n  for _, l in ipairs(lines) do\n    if not H.is_commented(l, comment_leaders) then return false end\n  end\n  return true\nend\n\nH.is_commented = function(line, comment_leaders)\n  for _, leader in ipairs(comment_leaders) do\n    if line:find('^%s*' .. vim.pesc(leader) .. '%s*') ~= nil then return true end\n  end\n  return false\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.splitjoin) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\nend\n\nH.set_text = function(start_row, start_col, end_row, end_col, replacement)\n  local ok = pcall(vim.api.nvim_buf_set_text, 0, start_row, start_col, end_row, end_col, replacement)\n  if not ok or #replacement == 0 then return end\n\n  -- Fix cursor position if it was exactly on start position.\n  -- See https://github.com/neovim/neovim/issues/22526.\n  local cursor = vim.api.nvim_win_get_cursor(0)\n  if (start_row + 1) == cursor[1] and start_col == cursor[2] then\n    vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + replacement[1]:len() })\n  end\nend\n\nreturn MiniSplitjoin\n"
  },
  {
    "path": "lua/mini/starter.lua",
    "content": "--- *mini.starter* Start screen\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Displayed items are fully customizable both in terms of what they do and\n--- how they look (with reasonable defaults). Item selection can be done using\n--- prefix query with instant visual feedback.\n---\n--- Key design ideas:\n--- - All available actions are defined inside items. Each item should have the\n---   following info:\n---     - <action> - function or string for |vim.cmd()| which is executed when\n---       item is chosen. Empty string result in placeholder \"inactive\" item.\n---     - <name> - string which will be displayed and used for choosing.\n---     - <section> - string representing to which section item belongs.\n---   There are pre-configured whole sections in |MiniStarter.sections|.\n---\n--- - Configure what items are displayed by supplying an array which can be\n---   normalized to an array of items. Read about how supplied items are\n---   normalized in |MiniStarter.refresh()|.\n---\n--- - Modify the final look by supplying content hooks: functions which take\n---   buffer content (see |MiniStarter.get_content()|) and identifier as input\n---   while returning buffer content as output. There are pre-configured\n---   content hook generators in |MiniStarter.gen_hook|.\n---\n--- - Choosing an item can be done in two ways:\n---     - Type prefix query to filter item by matching its name (ignoring\n---       case). Displayed information is updated after every typed character.\n---       For every item its unique prefix is highlighted.\n---     - Use Up/Down arrows and hit Enter.\n---\n--- - Allow multiple simultaneously open Starter buffers.\n---\n--- What is doesn't do:\n--- - It doesn't support fuzzy query for items. And probably will never do.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.starter').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniStarter` which you can use for scripting or manually (with\n--- `:lua MiniStarter.*`).\n---\n--- See |MiniStarter.config| for `config` structure and default values. For\n--- some configuration examples (including one similar to 'vim-startify' and\n--- 'dashboard-nvim'), see |MiniStarter-example-config|.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.ministarter_config` which should have same structure as\n--- `MiniStarter.config`. See |mini.nvim-buffer-local-config| for more details.\n--- Note: `vim.b.ministarter_config` is copied to Starter buffer from current\n--- buffer allowing full customization.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Highlight groups ~\n---\n--- - `MiniStarterCurrent` - current item.\n--- - `MiniStarterFooter` - footer units.\n--- - `MiniStarterHeader` - header units.\n--- - `MiniStarterInactive` - inactive item.\n--- - `MiniStarterItem` - item name.\n--- - `MiniStarterItemBullet` - units from |MiniStarter.gen_hook.adding_bullet()|.\n--- - `MiniStarterItemPrefix` - unique query for item.\n--- - `MiniStarterSection` - section units.\n--- - `MiniStarterQuery` - current query in active items.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable core functionality, set `vim.g.ministarter_disable` (globally) or\n--- `vim.b.ministarter_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniStarter\n\n--- # Similar to 'mhinz/vim-startify' ~\n--- >lua\n---   local starter = require('mini.starter')\n---   starter.setup({\n---     evaluate_single = true,\n---     items = {\n---       starter.sections.builtin_actions(),\n---       starter.sections.recent_files(10, false),\n---       starter.sections.recent_files(10, true),\n---       -- Use this if you set up 'mini.sessions'\n---       starter.sections.sessions(5, true)\n---     },\n---     content_hooks = {\n---       starter.gen_hook.adding_bullet(),\n---       starter.gen_hook.indexing('all', { 'Builtin actions' }),\n---       starter.gen_hook.padding(3, 2),\n---     },\n---   })\n--- <\n--- # Similar to 'glepnir/dashboard-nvim' ~\n--- >lua\n---   local starter = require('mini.starter')\n---   starter.setup({\n---     items = {\n---       starter.sections.telescope(),\n---     },\n---     content_hooks = {\n---       starter.gen_hook.adding_bullet(),\n---       starter.gen_hook.aligning('center', 'center'),\n---     },\n---   })\n--- <\n--- # Demo of capabilities ~\n--- >lua\n---   local my_items = {\n---     { name = 'Echo random number', action = 'lua print(math.random())', section = 'Section 1' },\n---     function()\n---       return {\n---         { name = 'Item #1 from function', action = [[echo 'Item #1']], section = 'From function' },\n---         { name = 'Placeholder (always inactive) item', action = '', section = 'From function' },\n---         function()\n---           return {\n---             name = 'Item #1 from double function',\n---             action = [[echo 'Double function']],\n---             section = 'From double function',\n---           }\n---         end,\n---       }\n---     end,\n---     { name = [[Another item in 'Section 1']], action = 'lua print(math.random() + 10)', section = 'Section 1' },\n---   }\n---\n---   local footer_n_seconds = (function()\n---     local timer = vim.loop.new_timer()\n---     local n_seconds = 0\n---     timer:start(0, 1000, vim.schedule_wrap(function()\n---       if vim.bo.filetype ~= 'ministarter' then\n---         timer:stop()\n---         return\n---       end\n---       n_seconds = n_seconds + 1\n---       MiniStarter.refresh()\n---     end))\n---\n---     return function()\n---       return 'Number of seconds since opening: ' .. n_seconds\n---     end\n---   end)()\n---\n---   local hook_top_pad_10 = function(content)\n---     -- Pad from top\n---     for _ = 1, 10 do\n---       -- Insert at start a line with single content unit\n---       table.insert(content, 1, { { type = 'empty', string = '' } })\n---     end\n---     return content\n---   end\n---\n---   local starter = require('mini.starter')\n---   starter.setup({\n---     items = my_items,\n---     footer = footer_n_seconds,\n---     content_hooks = { hook_top_pad_10 },\n---   })\n--- <\n---@tag MiniStarter-example-config\n\n--- - Open with |MiniStarter.open()|. It includes creating buffer with\n---   appropriate options, mappings, behavior; call to |MiniStarter.refresh()|;\n---   issue `MiniStarterOpened` |User| event.\n--- - Wait for user to choose an item. This is done using following logic:\n---     - Typing any character from `MiniStarter.config.query_updaters` leads\n---       to updating query. Read more in |MiniStarter.add_to_query()|.\n---     - <BS> deletes latest character from query.\n---     - <Down>/<Up>, <C-n>/<C-p>, <M-j>/<M-k> move current item.\n---     - <CR> executes action of current item.\n---     - <C-c> closes Starter buffer.\n--- - Evaluate current item when appropriate (after `<CR>` or when there is a\n---   single item and `MiniStarter.config.evaluate_single` is `true`). This\n---   executes item's `action`.\n---@tag MiniStarter-lifecycle\n\n---@alias __starter_buf_id number|nil Buffer identifier of a valid Starter buffer.\n---   Default: current buffer.\n---@alias __starter_section_fun function Function which returns array of items.\n\n-- Module definition ==========================================================\nlocal MiniStarter = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniStarter.config|.\n---\n---@usage >lua\n---   require('mini.starter').setup() -- use default config\n---   -- OR\n---   require('mini.starter').setup({}) -- replace {} with your config table\n--- <\nMiniStarter.setup = function(config)\n  -- Export module\n  _G.MiniStarter = MiniStarter\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniStarter.config = {\n  -- Whether to open Starter buffer on VimEnter. Not opened if Neovim was\n  -- started with intent to show something else.\n  autoopen = true,\n\n  -- Whether to evaluate action of single active item\n  evaluate_single = false,\n\n  -- Items to be displayed. Should be an array with the following elements:\n  -- - Item: table with <action>, <name>, and <section> keys.\n  -- - Function: should return one of these three categories.\n  -- - Array: elements of these three types (i.e. item, array, function).\n  -- If `nil` (default), default items will be used (see |mini.starter|).\n  items = nil,\n\n  -- Header to be displayed before items. Converted to single string via\n  -- `tostring` (use `\\n` to display several lines). If function, it is\n  -- evaluated first. If `nil` (default), polite greeting will be used.\n  header = nil,\n\n  -- Footer to be displayed after items. Converted to single string via\n  -- `tostring` (use `\\n` to display several lines). If function, it is\n  -- evaluated first. If `nil` (default), default usage help will be shown.\n  footer = nil,\n\n  -- Array  of functions to be applied consecutively to initial content.\n  -- Each function should take and return content for Starter buffer (see\n  -- |mini.starter| and |MiniStarter.get_content()| for more details).\n  content_hooks = nil,\n\n  -- Characters to update query. Each character will have special buffer\n  -- mapping overriding your global ones. Be careful to not add `:` as it\n  -- allows you to go into command mode.\n  query_updaters = 'abcdefghijklmnopqrstuvwxyz0123456789_-.',\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Open Starter buffer\n---\n--- - Create buffer if necessary and move into it.\n--- - Set buffer options. Note that settings are done with |:noautocmd| to\n---   achieve a massive speedup.\n--- - Set buffer mappings. Besides basic mappings (described inside \"Lifecycle\n---   of Starter buffer\" of |mini.starter|), map every character from\n---   `MiniStarter.config.query_updaters` to add itself to query with\n---   |MiniStarter.add_to_query()|.\n--- - Populate buffer with |MiniStarter.refresh()|.\n--- - Issue custom `MiniStarterOpened` event to allow acting upon opening\n---   Starter buffer. Use it with\n---   `autocmd User MiniStarterOpened <your command>`.\n---\n--- Note: to fully use it in autocommand, use |autocmd-nested|. Example: >lua\n---\n---   local starter_open = function() MiniStarter.open() end\n---   local au_opts = { nested = true, callback = starter_open }\n---   vim.api.nvim_create_autocmd('TabNewEntered', au_opts)\n--- <\n---@param buf_id number|nil Identifier of existing valid buffer (see |bufnr()|) to\n---   open inside. Default: create a new one.\nMiniStarter.open = function(buf_id)\n  if H.is_disabled() then return end\n\n  -- Ensure proper buffer and open it\n  if H.is_in_vimenter then\n    -- Use current buffer as it should be empty and not needed. This also\n    -- solves the issue of redundant buffer when opening a file from Starter.\n    buf_id = vim.api.nvim_get_current_buf()\n  end\n\n  if buf_id == nil or not vim.api.nvim_buf_is_valid(buf_id) then buf_id = vim.api.nvim_create_buf(false, true) end\n\n  -- Create buffer data entry\n  H.buffer_data[buf_id] = { current_item_id = 1, query = '' }\n\n  -- Ensure that local config in opened Starter buffer is the same as current.\n  -- This allow more advanced usage of buffer local configuration.\n  local config_local = vim.b.ministarter_config\n  vim.api.nvim_set_current_buf(buf_id)\n  vim.b.ministarter_config = config_local\n\n  -- Setup buffer behavior\n  H.set_buf_name(buf_id, 'welcome')\n  H.make_buffer_autocmd(buf_id)\n  H.apply_buffer_options(buf_id)\n  H.apply_buffer_mappings(buf_id)\n\n  -- Populate buffer\n  MiniStarter.refresh()\n\n  -- Issue custom event. Delay at startup, as it is executed with `noautocmd`.\n  local trigger_event = function() vim.api.nvim_exec_autocmds('User', { pattern = 'MiniStarterOpened' }) end\n  if H.is_in_vimenter then trigger_event = vim.schedule_wrap(trigger_event) end\n  trigger_event()\n\n  -- Ensure not being in VimEnter\n  H.is_in_vimenter = false\nend\n\n--- Refresh Starter buffer\n---\n--- - Normalize `MiniStarter.config.items`:\n---     - Flatten: recursively (in depth-first fashion) parse its elements. If\n---       function is found, execute it and continue with parsing its output\n---       (this allows deferring item collection up until it is actually\n---       needed).  If proper item is found (table with fields `action`,\n---       `name`, `section`), add it to output.\n---     - Sort: order first by section and then by item id (both in order of\n---       appearance).\n--- - Normalize `MiniStarter.config.header` and `MiniStarter.config.footer` to\n---   be multiple lines by splitting at `\\n`. If function - evaluate it first.\n--- - Make initial buffer content (see |MiniStarter.get_content()| for a\n---   description of what a buffer content is). It consist from content lines\n---   with single content unit:\n---     - First lines contain strings of normalized header.\n---     - Body is for normalized items. Section names have own lines preceded\n---       by empty line.\n---     - Last lines contain separate strings of normalized footer.\n--- - Sequentially apply hooks from `MiniStarter.config.content_hooks` to\n---   content. All hooks are applied with `(content, buf_id)` signature. Output\n---   of one hook serves as first argument to the next.\n--- - Gather final items from content with |MiniStarter.content_to_items()|.\n--- - Convert content to buffer lines with |MiniStarter.content_to_lines()| and\n---   add them to buffer.\n--- - Add highlighting of content units.\n--- - Position cursor.\n--- - Make current query. This results into some items being marked as\n---   \"inactive\" and updating highlighting of current query on \"active\" items.\n---\n--- Note: this function is executed on every |VimResized| to allow more\n--- responsive behavior.\n---\n---@param buf_id __starter_buf_id\nMiniStarter.refresh = function(buf_id)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'refresh()') then return end\n\n  local data = H.buffer_data[buf_id]\n  local config = H.get_config()\n\n  -- Normalize certain config values\n  data.header = H.normalize_header_footer(config.header or H.default_header)\n  local items = H.normalize_items(config.items or H.default_items)\n  data.footer = H.normalize_header_footer(config.footer or H.default_footer)\n\n  -- Evaluate content\n  local content = H.make_initial_content(data.header, items, data.footer)\n  local hooks = config.content_hooks or H.default_content_hooks\n  for _, f in ipairs(hooks) do\n    content = f(content, buf_id)\n  end\n  data.content = content\n\n  -- Set items. Possibly reset current item id if items have changed.\n  local old_items = data.items\n  data.items = MiniStarter.content_to_items(content)\n  if not vim.deep_equal(data.items, old_items) then data.current_item_id = 1 end\n\n  -- Add content\n  vim.bo[buf_id].modifiable = true\n  vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, MiniStarter.content_to_lines(content))\n  vim.bo[buf_id].modifiable = false\n\n  -- Add highlighting\n  H.content_highlight(buf_id)\n  H.items_highlight(buf_id)\n\n  -- -- Always position cursor on current item\n  H.position_cursor_on_current_item(buf_id)\n  H.add_hl_current_item(buf_id)\n\n  -- Apply current query (clear command line afterwards)\n  H.make_query(buf_id)\nend\n\n--- Close Starter buffer\n---\n---@param buf_id __starter_buf_id\nMiniStarter.close = function(buf_id)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'close()') then return end\n\n  -- Use `pcall` to allow calling for already non-existing buffer\n  pcall(vim.api.nvim_buf_delete, buf_id, {})\nend\n\n-- Sections -------------------------------------------------------------------\n--- Table of pre-configured sections\nMiniStarter.sections = {}\n\n--- Section with builtin actions\n---\n---@return table Array of items.\nMiniStarter.sections.builtin_actions = function()\n  return {\n    { name = 'Edit new buffer', action = 'enew', section = 'Builtin actions' },\n    { name = 'Quit Neovim', action = 'qall', section = 'Builtin actions' },\n  }\nend\n\n--- Section with |mini.sessions| sessions\n---\n--- Sessions are taken from |MiniSessions.detected|. Notes:\n--- - If it shows \"'mini.sessions' is not set up\", it means that you didn't\n---   call `require('mini.sessions').setup()`.\n--- - If it shows \"There are no detected sessions in 'mini.sessions'\", it means\n---   that there are no sessions at the current sessions directory. Either\n---   create session or supply different directory where session files are\n---   stored (see |MiniSessions.setup()|).\n--- - Local session (if detected) is always displayed first.\n---\n---@param n number|nil Number of returned items. Default: 5.\n---@param recent boolean|nil Whether to use recent sessions (instead of\n---   alphabetically by name). Default: true.\n---\n---@return __starter_section_fun\nMiniStarter.sections.sessions = function(n, recent)\n  n = n or 5\n  if recent == nil then recent = true end\n\n  return function()\n    if _G.MiniSessions == nil then\n      return { { name = [['mini.sessions' is not set up]], action = '', section = 'Sessions' } }\n    end\n\n    local items = {}\n    for session_name, session in pairs(_G.MiniSessions.detected) do\n      table.insert(items, {\n        _session = session,\n        name = ('%s%s'):format(session_name, session.type == 'local' and ' (local)' or ''),\n        action = ([[lua _G.MiniSessions.read('%s')]]):format(session_name),\n        section = 'Sessions',\n      })\n    end\n\n    if vim.tbl_count(items) == 0 then\n      return { { name = [[There are no detected sessions in 'mini.sessions']], action = '', section = 'Sessions' } }\n    end\n\n    local sort_fun\n    if recent then\n      sort_fun = function(a, b)\n        local a_time = a._session.type == 'local' and math.huge or a._session.modify_time\n        local b_time = b._session.type == 'local' and math.huge or b._session.modify_time\n        return a_time > b_time\n      end\n    else\n      sort_fun = function(a, b)\n        local a_name = a._session.type == 'local' and '' or a.name\n        local b_name = b._session.type == 'local' and '' or b.name\n        return a_name < b_name\n      end\n    end\n    table.sort(items, sort_fun)\n\n    -- Take only first `n` elements and remove helper fields\n    return vim.tbl_map(function(x)\n      x._session = nil\n      return x\n    end, vim.list_slice(items, 1, n))\n  end\nend\n\n--- Section with most recently used files\n---\n--- Files are taken from |v:oldfiles|.\n---\n---@param n number|nil Number of returned items. Default: 5.\n---@param current_dir boolean|nil Whether to return files only from current working\n---   directory and its subdirectories. Default: `false`.\n---@param show_path boolean|function|nil Whether to append file name with its path.\n---   If callable, will be called with full path and should return string to be\n---   directly appended to file name. Default: `true`.\n---\n---@return __starter_section_fun\nMiniStarter.sections.recent_files = function(n, current_dir, show_path)\n  n = n or 5\n  if current_dir == nil then current_dir = false end\n\n  if show_path == nil then show_path = true end\n  if show_path == false then show_path = function() return '' end end\n  if show_path == true then\n    show_path = function(path) return string.format(' (%s)', vim.fn.fnamemodify(path, ':~:.')) end\n  end\n  if not vim.is_callable(show_path) then H.error('`show_path` should be boolean or callable.') end\n\n  return function()\n    local section = string.format('Recent files%s', current_dir and ' (current directory)' or '')\n    local sep = vim.loop.os_uname().sysname == 'Windows_NT' and '\\\\' or '/'\n    local cwd = vim.fn.getcwd() .. sep\n\n    local files = {}\n    for _, f in ipairs(vim.v.oldfiles) do\n      -- Use only actually readable files possibly respecting current directory\n      if vim.fn.filereadable(f) == 1 and (not current_dir or vim.startswith(f, cwd)) then\n        table.insert(files, f)\n        if #files >= n then break end\n      end\n    end\n\n    if #files == 0 then\n      local suffix = current_dir and 'in current directory' or '(`v:oldfiles` is empty)'\n      local text = 'There are no recent files ' .. suffix\n      return { { name = text, action = '', section = section } }\n    end\n\n    -- Create items\n    local items = {}\n    for _, f in ipairs(files) do\n      local name = vim.fn.fnamemodify(f, ':t') .. show_path(f)\n      table.insert(items, { action = function() H.edit(f) end, name = name, section = section })\n    end\n\n    return items\n  end\nend\n\n-- stylua: ignore\n--- Section with |mini.pick| pickers\n---\n--- Notes:\n--- - All actions require 'mini.pick' module of 'mini.nvim'.\n--- - \"Command history\", \"Explorer\", and \"Visited paths\" items\n---   require |mini.extra| module of 'mini.nvim'.\n--- - \"Visited paths\" items requires |mini.visits| module of 'mini.nvim'.\n---\n---@return __starter_section_fun\nMiniStarter.sections.pick = function()\n  return function()\n    return {\n      { action = 'Pick history scope=\":\"', name = 'Command history', section = 'Pick' },\n      { action = 'Pick explorer',          name = 'Explorer',        section = 'Pick' },\n      { action = 'Pick files',             name = 'Files',           section = 'Pick' },\n      { action = 'Pick grep_live',         name = 'Grep live',       section = 'Pick' },\n      { action = 'Pick help',              name = 'Help tags',       section = 'Pick' },\n      { action = 'Pick visit_paths',       name = 'Visited paths',   section = 'Pick' },\n    }\n  end\nend\n\n-- stylua: ignore\n--- Section with basic Telescope pickers relevant to start screen\n---\n--- Notes:\n--- - All actions require\n---   [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim).\n--- - \"Browser\" item requires\n---   [nvim-telescope/telescope-file-browser.nvim](https://github.com/nvim-telescope/telescope-file-browser.nvim).\n---\n---@return __starter_section_fun\nMiniStarter.sections.telescope = function()\n  return function()\n    return {\n      { action = 'Telescope file_browser',    name = 'Browser',         section = 'Telescope' },\n      { action = 'Telescope command_history', name = 'Command history', section = 'Telescope' },\n      { action = 'Telescope find_files',      name = 'Files',           section = 'Telescope' },\n      { action = 'Telescope help_tags',       name = 'Help tags',       section = 'Telescope' },\n      { action = 'Telescope live_grep',       name = 'Live grep',       section = 'Telescope' },\n      { action = 'Telescope oldfiles',        name = 'Old files',       section = 'Telescope' },\n    }\n  end\nend\n\n-- Content hooks --------------------------------------------------------------\n--- Table with pre-configured content hook generators\n---\n--- Each element is a function which returns content hook. So to use them\n--- inside |MiniStarter.setup()|, call them.\nMiniStarter.gen_hook = {}\n\n--- Hook generator for padding\n---\n--- Output is a content hook which adds constant padding from left and top.\n--- This allows tweaking the screen position of buffer content.\n---\n---@param left number|nil Number of empty spaces to add to start of each content\n---   line. Default: 0.\n---@param top number|nil Number of empty lines to add to start of content.\n---   Default: 0.\n---\n---@return function Content hook.\nMiniStarter.gen_hook.padding = function(left, top)\n  left = math.max(left or 0, 0)\n  top = math.max(top or 0, 0)\n  return function(content, _)\n    -- Add left padding\n    local left_pad = string.rep(' ', left)\n    for _, line in ipairs(content) do\n      local is_empty_line = #line == 0 or (#line == 1 and line[1].string == '')\n      if not is_empty_line then table.insert(line, 1, H.content_unit(left_pad, 'empty', nil)) end\n    end\n\n    -- Add top padding\n    local top_lines = {}\n    for _ = 1, top do\n      table.insert(top_lines, { H.content_unit('', 'empty', nil) })\n    end\n    content = vim.list_extend(top_lines, content)\n\n    return content\n  end\nend\n\n--- Hook generator for adding bullet to items\n---\n--- Output is a content hook which adds supplied string to be displayed to the\n--- left of item.\n---\n---@param bullet string|nil String to be placed to the left of item name.\n---   Default: \"░ \".\n---@param place_cursor boolean|nil Whether to place cursor on the first character\n---   of bullet when corresponding item becomes current. Default: true.\n---\n---@return function Content hook.\nMiniStarter.gen_hook.adding_bullet = function(bullet, place_cursor)\n  bullet = bullet or '░ '\n  if place_cursor == nil then place_cursor = true end\n  return function(content)\n    local coords = MiniStarter.content_coords(content, 'item')\n    -- Go backwards to avoid conflict when inserting units\n    for i = #coords, 1, -1 do\n      local l_num, u_num = coords[i].line, coords[i].unit\n      local bullet_unit = {\n        string = bullet,\n        type = 'item_bullet',\n        hl = 'MiniStarterItemBullet',\n        -- Use `_item` instead of `item` because it is better to be 'private'\n        _item = content[l_num][u_num].item,\n        _place_cursor = place_cursor,\n      }\n      table.insert(content[l_num], u_num, bullet_unit)\n    end\n\n    return content\n  end\nend\n\n--- Hook generator for indexing items\n---\n--- Output is a content hook which adds unique index to the start of item's\n--- name. It results into shortening queries required to choose an item (at\n--- expense of clarity).\n---\n---@param grouping string|nil One of \"all\" (number indexing across all sections) or\n---   \"section\" (letter-number indexing within each section). Default: \"all\".\n---@param exclude_sections table|nil Array of section names (values of `section`\n---   element of item) for which index won't be added. Default: `{}`.\n---\n---@return function Content hook.\nMiniStarter.gen_hook.indexing = function(grouping, exclude_sections)\n  grouping = grouping or 'all'\n  exclude_sections = exclude_sections or {}\n  local per_section = grouping == 'section'\n\n  return function(content, _)\n    local cur_section, n_section, n_item = nil, 0, 0\n    local coords = MiniStarter.content_coords(content, 'item')\n\n    for _, c in ipairs(coords) do\n      local unit = content[c.line][c.unit]\n      local item = unit.item\n\n      if not vim.tbl_contains(exclude_sections, item.section) then\n        n_item = n_item + 1\n        if cur_section ~= item.section then\n          cur_section = item.section\n          -- Cycle through lower case letters\n          n_section = math.fmod(n_section, 26) + 1\n          n_item = per_section and 1 or n_item\n        end\n\n        local section_index = per_section and string.char(96 + n_section) or ''\n        unit.string = ('%s%s. %s'):format(section_index, n_item, unit.string)\n      end\n    end\n\n    return content\n  end\nend\n\n--- Hook generator for aligning content\n---\n--- Output is a content hook which independently aligns content horizontally\n--- and vertically. Window width and height are taken from first window in current\n--- tabpage displaying the Starter buffer.\n---\n--- Basically, this computes left and top pads for |MiniStarter.gen_hook.padding()|\n--- such that output lines would appear aligned in certain way.\n---\n---@param horizontal string|nil One of \"left\", \"center\", \"right\". Default: \"left\".\n---@param vertical string|nil One of \"top\", \"center\", \"bottom\". Default: \"top\".\n---\n---@return function Content hook.\nMiniStarter.gen_hook.aligning = function(horizontal, vertical)\n  horizontal = horizontal or 'left'\n  vertical = vertical or 'top'\n\n  local horiz_coef = ({ left = 0, center = 0.5, right = 1.0 })[horizontal]\n  local vert_coef = ({ top = 0, center = 0.5, bottom = 1.0 })[vertical]\n\n  return function(content, buf_id)\n    local win_id = vim.fn.bufwinid(buf_id)\n    if win_id < 0 then return end\n\n    local line_strings = MiniStarter.content_to_lines(content)\n\n    -- Align horizontally\n    -- Don't use `string.len()` to account for multibyte characters\n    local lines_width = vim.tbl_map(function(l) return vim.fn.strdisplaywidth(l) end, line_strings)\n    local min_right_space = vim.api.nvim_win_get_width(win_id) - math.max(unpack(lines_width))\n    local left_pad = math.max(math.floor(horiz_coef * min_right_space), 0)\n\n    -- Align vertically\n    local bottom_space = vim.api.nvim_win_get_height(win_id) - #line_strings\n    local top_pad = math.max(math.floor(vert_coef * bottom_space), 0)\n\n    return MiniStarter.gen_hook.padding(left_pad, top_pad)(content)\n  end\nend\n\n-- Work with content ----------------------------------------------------------\n--- Get content of Starter buffer\n---\n--- Generally, buffer content is a table in the form of \"2d array\" (or rather\n--- \"2d list\" because number of elements can differ):\n--- - Each element represents content line: an array with content units to be\n---   displayed in one buffer line.\n--- - Each content unit is a table with at least the following elements:\n---     - \"type\" - string with type of content. Something like \"item\",\n---       \"section\", \"header\", \"footer\", \"empty\", etc.\n---     - \"string\" - which string should be displayed. May be an empty string.\n---     - \"hl\" - which highlighting should be applied to content string. May be\n---       `nil` for no highlighting.\n---\n--- See |MiniStarter.content_to_lines()| for converting content to buffer lines\n--- and |MiniStarter.content_to_items()| - to list of parsed items.\n---\n--- Notes:\n--- - Content units with type \"item\" also have `item` element with all\n---   information about an item it represents. Those elements are used directly\n---   to create an array of items used for query.\n---\n---@param buf_id __starter_buf_id\nMiniStarter.get_content = function(buf_id)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'get_content()', 'error') then return end\n\n  return H.buffer_data[buf_id].content\nend\n\n--- Helper to iterate through content\n---\n--- Basically, this traverses content \"2d array\" (in depth-first fashion; top\n--- to bottom, left to right) and returns \"coordinates\" of units for which\n--- `predicate` is true-ish.\n---\n---@param content table|nil Content \"2d array\". Default: content of current buffer.\n---@param predicate function|string|nil Predictate to filter units. If it is:\n---    - Function, then it is evaluated with unit as input.\n---    - String, then it checks unit to have this type (allows easy getting of\n---      units with some type).\n---    - `nil`, all units are kept.\n---\n---@return table Array of resulting units' coordinates. Each coordinate is a\n---   table with <line> and <unit> keys. To retrieve actual unit from coordinate\n---   `c`, use `content[c.line][c.unit]`.\nMiniStarter.content_coords = function(content, predicate)\n  content = content or MiniStarter.get_content()\n  if predicate == nil then predicate = function(_) return true end end\n  if type(predicate) == 'string' then\n    local pred_type = predicate\n    predicate = function(unit) return unit.type == pred_type end\n  end\n\n  local res = {}\n  for l_num, line in ipairs(content) do\n    for u_num, unit in ipairs(line) do\n      if predicate(unit) then table.insert(res, { line = l_num, unit = u_num }) end\n    end\n  end\n  return res\nend\n\n-- stylua: ignore start\n--- Convert content to buffer lines\n---\n--- One buffer line is made by concatenating `string` element of units within\n--- same content line.\n---\n---@param content table|nil Content \"2d array\". Default: content of current buffer.\n---\n---@return table Array of strings for each buffer line.\nMiniStarter.content_to_lines = function(content)\n  return vim.tbl_map(\n    function(content_line)\n      return table.concat(\n      -- Ensure that each content line is indeed a single buffer line\n        vim.tbl_map(function(x) return x.string:gsub('\\n', ' ') end, content_line), ''\n      )\n    end,\n    content or MiniStarter.get_content()\n  )\nend\n-- stylua: ignore end\n\n--- Convert content to items\n---\n--- Parse content (in depth-first fashion) and retrieve each item from `item`\n--- element of content units with type \"item\". This also:\n--- - Computes some helper information about how item will be actually\n---   displayed (after |MiniStarter.content_to_lines()|) and minimum number of\n---   prefix characters needed for a particular item to be queried single.\n--- - Modifies item's `name` element taking it from corresponding `string`\n---   element of content unit. This allows modifying item's `name` at the stage\n---   of content hooks (like, for example, in |MiniStarter.gen_hook.indexing()|).\n---\n---@param content table|nil Content \"2d array\". Default: content of current buffer.\n---\n---@return table Array of items.\nMiniStarter.content_to_items = function(content)\n  content = content or MiniStarter.get_content()\n\n  -- NOTE: this havily utilizes 'modify by reference' nature of Lua tables\n  local items = {}\n  for l_num, line in ipairs(content) do\n    -- Track 0-based starting column of current unit (using byte length)\n    local start_col = 0\n    for _, unit in ipairs(line) do\n      -- Cursor position is (1, 0)-based\n      local cursorpos = { l_num, start_col }\n\n      if unit.type == 'item' then\n        local item = unit.item\n        -- Take item's name from content string\n        item.name = unit.string:gsub('\\n', ' ')\n        item._line = l_num - 1\n        item._start_col = start_col\n        item._end_col = start_col + unit.string:len()\n        -- Don't overwrite possible cursor position from item's bullet\n        item._cursorpos = item._cursorpos or cursorpos\n\n        table.insert(items, item)\n      end\n\n      -- Prefer placing cursor at start of item's bullet\n      if unit.type == 'item_bullet' and unit._place_cursor then\n        -- Item bullet uses 'private' `_item` element instead of `item`\n        unit._item._cursorpos = cursorpos\n      end\n\n      start_col = start_col + unit.string:len()\n    end\n  end\n\n  -- Compute length of unique prefix for every item's name (ignoring case)\n  local strings = vim.tbl_map(function(x) return x.name:lower() end, items)\n  local nprefix = H.unique_nprefix(strings)\n  for i, n in ipairs(nprefix) do\n    items[i]._nprefix = n\n  end\n\n  return items\nend\n\n-- Other exported functions ---------------------------------------------------\n--- Evaluate current item\n---\n--- Note that it resets current query before evaluation, as it is rarely needed\n--- any more.\n---\n---@param buf_id __starter_buf_id\nMiniStarter.eval_current_item = function(buf_id)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'eval_current_item()') then return end\n\n  -- Reset query before evaluation without query echo (avoids hit-enter-prompt)\n  H.make_query(vim.api.nvim_get_current_buf(), '', false)\n\n  local data = H.buffer_data[buf_id]\n  H.eval_fun_or_string(data.items[data.current_item_id].action, true)\nend\n\n--- Update current item\n---\n--- This makes next (with respect to `direction`) active item to be current.\n---\n---@param direction string One of \"next\" or \"previous\".\n---@param buf_id __starter_buf_id\nMiniStarter.update_current_item = function(direction, buf_id)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'update_current_item()') then return end\n\n  local data = H.buffer_data[buf_id]\n\n  -- Advance current item\n  local prev_current = data.current_item_id\n  data.current_item_id = H.next_active_item_id(buf_id, data.current_item_id, direction)\n  if data.current_item_id == prev_current then return end\n\n  -- Update cursor position\n  H.position_cursor_on_current_item(buf_id)\n\n  -- Highlight current item\n  vim.api.nvim_buf_clear_namespace(buf_id, H.ns.current_item, 0, -1)\n  H.add_hl_current_item(buf_id)\nend\n\n--- Add character to current query\n---\n--- - Update current query by appending `char` to its end (only if it results\n---   into at least one active item) or delete latest character if `char` is `nil`.\n--- - Recompute status of items: \"active\" if its name starts with new query,\n---   \"inactive\" otherwise.\n--- - Update highlighting: whole strings for \"inactive\" items, current query\n---   for \"active\" items.\n---\n---@param char string|nil Single character to be added to query. If `nil`, deletes\n---   latest character from query.\n---@param buf_id __starter_buf_id\nMiniStarter.add_to_query = function(char, buf_id)\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'add_to_query()') then return end\n\n  local data = H.buffer_data[buf_id]\n\n  local new_query\n  if char == nil then\n    new_query = data.query:sub(0, data.query:len() - 1)\n  else\n    new_query = ('%s%s'):format(data.query, char)\n  end\n  H.make_query(buf_id, new_query)\nend\n\n--- Set current query\n---\n---@param query string|nil Query to be set (only if it results into at least one\n---   active item). Default: `nil` for setting query to empty string, which\n---   essentially resets query.\n---@param buf_id __starter_buf_id\nMiniStarter.set_query = function(query, buf_id)\n  query = query or ''\n  if type(query) ~= 'string' then error('`query` should be either `nil` or string.') end\n\n  buf_id = buf_id or vim.api.nvim_get_current_buf()\n  if not H.validate_starter_buf_id(buf_id, 'add_to_query()') then return end\n\n  H.make_query(buf_id, query)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniStarter.config)\n\n-- Default config values\nH.default_items = {\n  function()\n    if _G.MiniSessions == nil then return {} end\n    return MiniStarter.sections.sessions(5, true)()\n  end,\n  MiniStarter.sections.recent_files(5, false, false),\n  MiniStarter.sections.builtin_actions(),\n}\n\nH.default_header = function()\n  local hour = tonumber(vim.fn.strftime('%H'))\n  -- [04:00, 12:00) - morning, [12:00, 20:00) - day, [20:00, 04:00) - evening\n  local part_id = math.floor((hour + 4) / 8) + 1\n  local day_part = ({ 'evening', 'morning', 'afternoon', 'evening' })[part_id]\n  local username = vim.loop.os_get_passwd()['username'] or 'USERNAME'\n\n  return ('Good %s, %s'):format(day_part, username)\nend\n\nH.default_footer = [[\nType query to filter items\n<BS> deletes latest character from query\n<Esc> resets current query\n<Down/Up>, <C-n/p>, <M-j/k> move current item\n<CR> executes action of current item\n<C-c> closes this buffer]]\n\nH.default_content_hooks = { MiniStarter.gen_hook.adding_bullet(), MiniStarter.gen_hook.aligning('center', 'center') }\n\n-- Storage for all Starter buffers. Fields - buffer number. Values - table:\n-- - <content> - buffer content (2d array of units)\n-- - <current_item_id> - identifier of current item\n-- - <footer> - table of strings\n-- - <header> - table of strings\n-- - <items> - normalized items gathered from final content\n-- - <query> - current search query\nH.buffer_data = {}\n\n-- Namespaces for highlighting\nH.ns = {\n  activity = vim.api.nvim_create_namespace(''),\n  current_item = vim.api.nvim_create_namespace(''),\n  general = vim.api.nvim_create_namespace(''),\n}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('autoopen', config.autoopen, 'boolean')\n  H.check_type('evaluate_single', config.evaluate_single, 'boolean')\n  H.check_type('items', config.items, 'table', true)\n  -- `header` and `footer` can have any type\n  H.check_type('content_hooks', config.content_hooks, 'table', true)\n  H.check_type('query_updaters', config.query_updaters, 'string')\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config) MiniStarter.config = config end\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniStarter', {})\n\n  if config.autoopen then\n    local on_vimenter = function()\n      if H.is_something_shown() then return end\n\n      -- Set indicator used to make different decision on startup\n      H.is_in_vimenter = true\n      -- Use 'noautocmd' for better startup time\n      vim.cmd('noautocmd lua MiniStarter.open()')\n    end\n\n    local au_opts = { group = gr, nested = true, once = true, callback = on_vimenter, desc = 'Open on VimEnter' }\n    vim.api.nvim_create_autocmd('VimEnter', au_opts)\n  end\n\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local set_default_hl = function(name, data)\n    data.default = true\n    vim.api.nvim_set_hl(0, name, data)\n  end\n\n  set_default_hl('MiniStarterCurrent',    { link = 'MiniStarterItem' })\n  set_default_hl('MiniStarterFooter',     { link = 'Title' })\n  set_default_hl('MiniStarterHeader',     { link = 'Title' })\n  set_default_hl('MiniStarterInactive',   { link = 'Comment' })\n  set_default_hl('MiniStarterItem',       { link = 'Normal' })\n  set_default_hl('MiniStarterItemBullet', { link = 'Delimiter' })\n  set_default_hl('MiniStarterItemPrefix', { link = 'WarningMsg' })\n  set_default_hl('MiniStarterSection',    { link = 'Delimiter' })\n  set_default_hl('MiniStarterQuery',      { link = 'MoreMsg' })\nend\n\nH.is_disabled = function() return vim.g.ministarter_disable == true or vim.b.ministarter_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniStarter.config, vim.b.ministarter_config or {}, config or {})\nend\n\n-- Normalize config elements --------------------------------------------------\nH.normalize_items = function(items)\n  local res = H.items_flatten(items)\n  if #res == 0 then return { { name = '`config.items` is empty', action = '', section = '' } } end\n  return H.items_sort(res)\nend\n\nH.normalize_header_footer = function(x)\n  if type(x) == 'function' then x = x() end\n  local res = tostring(x)\n  if res == '' then return {} end\n  return vim.split(res, '\\n')\nend\n\n-- Work with buffer content ---------------------------------------------------\nH.make_initial_content = function(header, items, footer)\n  local content = {}\n\n  -- Add header lines\n  for _, l in ipairs(header) do\n    H.content_add_line(content, { H.content_unit(l, 'header', 'MiniStarterHeader') })\n  end\n  H.content_add_empty_lines(content, #header > 0 and 1 or 0)\n\n  -- Add item lines\n  H.content_add_items(content, items)\n\n  -- Add footer lines\n  H.content_add_empty_lines(content, #footer > 0 and 1 or 0)\n  for _, l in ipairs(footer) do\n    H.content_add_line(content, { H.content_unit(l, 'footer', 'MiniStarterFooter') })\n  end\n\n  return content\nend\n\nH.content_unit = function(string, type, hl, extra)\n  return vim.tbl_extend('force', { string = string, type = type, hl = hl }, extra or {})\nend\n\nH.content_add_line = function(content, content_line) table.insert(content, content_line) end\n\nH.content_add_empty_lines = function(content, n)\n  for _ = 1, n do\n    H.content_add_line(content, { H.content_unit('', 'empty', nil) })\n  end\nend\n\nH.content_add_items = function(content, items)\n  local cur_section\n  for _, item in ipairs(items) do\n    -- Possibly add section line\n    if cur_section ~= item.section then\n      -- Don't add empty line before first section line\n      H.content_add_empty_lines(content, cur_section == nil and 0 or 1)\n      H.content_add_line(content, { H.content_unit(item.section, 'section', 'MiniStarterSection') })\n      cur_section = item.section\n    end\n\n    H.content_add_line(content, { H.content_unit(item.name, 'item', 'MiniStarterItem', { item = item }) })\n  end\nend\n\nH.content_highlight = function(buf_id)\n  for l_num, content_line in ipairs(MiniStarter.get_content(buf_id)) do\n    -- Track 0-based starting column of current unit (using byte length)\n    local start_col = 0\n    for _, unit in ipairs(content_line) do\n      if unit.hl ~= nil then\n        H.buf_hl(buf_id, H.ns.general, unit.hl, l_num - 1, start_col, start_col + unit.string:len(), 50)\n      end\n      start_col = start_col + unit.string:len()\n    end\n  end\nend\n\n-- Work with items -----------------------------------------------------------\nH.items_flatten = function(items)\n  local res, f = {}, nil\n  f = function(x)\n    -- Expand (possibly recursively) functions immediately\n    local n_nested = 0\n    while type(x) == 'function' and n_nested <= 100 do\n      n_nested = n_nested + 1\n      if n_nested > 100 then H.message('Too many nested functions in `config.items`.') end\n      x = x()\n    end\n\n    if H.is_item(x) then\n      -- Use deepcopy to allow adding fields to items without changing original\n      table.insert(res, vim.deepcopy(x))\n      return\n    end\n\n    if type(x) ~= 'table' then return end\n    return vim.tbl_map(f, x)\n  end\n\n  f(items)\n  return res\nend\n\nH.items_sort = function(items)\n  -- Order first by section and then by item id (both in order of appearance)\n  -- Gather items grouped per section in order of their appearance\n  local sections, section_order = {}, {}\n  for _, item in ipairs(items) do\n    local sec = item.section\n    if section_order[sec] == nil then\n      table.insert(sections, {})\n      section_order[sec] = #sections\n    end\n    table.insert(sections[section_order[sec]], item)\n  end\n\n  -- Unroll items in depth-first fashion\n  local res = {}\n  for _, section_items in ipairs(sections) do\n    for _, item in ipairs(section_items) do\n      table.insert(res, item)\n    end\n  end\n\n  return res\nend\n\nH.items_highlight = function(buf_id)\n  for _, item in ipairs(H.buffer_data[buf_id].items) do\n    H.buf_hl(\n      buf_id,\n      H.ns.general,\n      'MiniStarterItemPrefix',\n      item._line,\n      item._start_col,\n      item._start_col + item._nprefix,\n      52\n    )\n  end\nend\n\nH.next_active_item_id = function(buf_id, item_id, direction)\n  local items = H.buffer_data[buf_id].items\n\n  -- Advance in cyclic fashion\n  local id = item_id\n  local n_items = vim.tbl_count(items)\n  local increment = direction == 'next' and 1 or (n_items - 1)\n\n  -- Increment modulo `n` but for 1-based indexing\n  id = math.fmod(id + increment - 1, n_items) + 1\n  while not (items[id]._active or id == item_id) do\n    id = math.fmod(id + increment - 1, n_items) + 1\n  end\n\n  return id\nend\n\nH.position_cursor_on_current_item = function(buf_id)\n  local data = H.buffer_data[buf_id]\n  local cursorpos = data.items[data.current_item_id]._cursorpos\n  for _, win_id in ipairs(H.get_buffer_windows(buf_id)) do\n    vim.api.nvim_win_set_cursor(win_id, cursorpos)\n  end\nend\n\nH.item_is_active = function(item, query)\n  -- Item is active = item's name starts with query (ignoring case) and item's\n  -- action is non-empty\n  return vim.startswith(item.name:lower(), query) and item.action ~= ''\nend\n\n-- Work with queries ----------------------------------------------------------\nH.make_query = function(buf_id, query, echo_msg)\n  if echo_msg == nil then echo_msg = true end\n\n  local data = H.buffer_data[buf_id]\n  -- Ignore case\n  query = (query or data.query):lower()\n\n  -- Don't make query if it results into no active items\n  local n_active = 0\n  for _, item in ipairs(data.items) do\n    n_active = n_active + (H.item_is_active(item, query) and 1 or 0)\n  end\n\n  if n_active == 0 and query ~= '' then\n    H.message(('Query %s results into no active items. Current query: %s'):format(vim.inspect(query), data.query))\n    return\n  end\n\n  -- Update current query and active items\n  data.query = query\n  for _, item in ipairs(data.items) do\n    item._active = H.item_is_active(item, query)\n  end\n\n  -- Move to next active item if current is not active\n  if not data.items[data.current_item_id]._active then MiniStarter.update_current_item('next', buf_id) end\n\n  -- Update activity highlighting. This should go before `evaluate_single`\n  -- check because evaluation might not result into closing Starter buffer.\n  vim.api.nvim_buf_clear_namespace(buf_id, H.ns.activity, 0, -1)\n  H.add_hl_activity(buf_id, query)\n\n  -- Possibly evaluate single active item\n  if H.get_config().evaluate_single and n_active == 1 then\n    MiniStarter.eval_current_item(buf_id)\n    return\n  end\n\n  -- Notify about new query if not in VimEnter, where it might lead to\n  -- unpleasant flickering due to startup process (lazy loading, etc.).\n  if echo_msg and not H.is_in_vimenter and vim.o.cmdheight > 0 then\n    -- Make sure that output of `echo` will be shown\n    vim.cmd('redraw')\n\n    H.echo(('Query: %s'):format(query))\n  end\nend\n\n-- Work with Starter buffer ---------------------------------------------------\nH.make_buffer_autocmd = function(buf_id)\n  local augroup = vim.api.nvim_create_augroup('MiniStarterBuffer', {})\n\n  local au = function(event, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = augroup, buffer = buf_id, callback = callback, desc = desc })\n  end\n\n  au({ 'VimResized', 'BufEnter' }, function() MiniStarter.refresh(buf_id) end, 'Refresh')\n  au('CursorMoved', function() H.position_cursor_on_current_item(buf_id) end, 'Position cursor')\n\n  local cache_showtabline = vim.o.showtabline\n  au('BufLeave', function()\n    if vim.o.cmdheight > 0 then vim.cmd(\"echo ''\") end\n    if vim.o.showtabline == 1 then vim.o.showtabline = cache_showtabline end\n  end, 'On BufLeave')\nend\n\nH.apply_buffer_options = function(buf_id)\n  -- NOTE: assumed that it is executing with `buf_id` being current buffer\n\n  -- Force Normal mode. NOTEs:\n  -- - Using `vim.cmd('normal! \\28\\14')` weirdly does not work.\n  -- - Using `vim.api.nvim_input([[<C-\\><C-n>]])` doesn't play nice if `<C-\\>`\n  --   mapping is present (maybe due to non-blocking nature of `nvim_input()`).\n  vim.api.nvim_feedkeys('\\28\\14', 'nx', false)\n\n  -- Having `noautocmd` is crucial for performance: ~9ms without it, ~1.6ms with it\n  vim.cmd('noautocmd silent! set filetype=ministarter')\n\n  local options = {\n    -- Taken from 'vim-startify'\n    'bufhidden=wipe',\n    'colorcolumn=',\n    'foldcolumn=0',\n    'matchpairs=',\n    'nobuflisted',\n    'nocursorcolumn',\n    'nocursorline',\n    'nolist',\n    'nonumber',\n    'noreadonly',\n    'norelativenumber',\n    'nospell',\n    'noswapfile',\n    'signcolumn=no',\n    'statuscolumn=',\n    'synmaxcol&',\n    -- Differ from 'vim-startify'\n    'buftype=nofile',\n    'nomodeline',\n    'nomodifiable',\n    'foldlevel=999',\n    'nowrap',\n  }\n  -- Vim's `setlocal` is currently more robust compared to `opt_local`\n  vim.cmd(('silent! noautocmd setlocal %s'):format(table.concat(options, ' ')))\n\n  -- Hide tabline on single tab by setting `showtabline` to default value (but\n  -- not statusline as it weirdly feels 'naked' without it).\n  vim.o.showtabline = 1\n\n  -- Make it a better user experience with other modules\n  vim.b.minicursorword_disable = true\n  vim.b.minitrailspace_disable = true\n  if _G.MiniTrailspace ~= nil then _G.MiniTrailspace.unhighlight() end\nend\n\nH.apply_buffer_mappings = function(buf_id)\n  local buf_keymap = function(key, cmd)\n    vim.keymap.set('n', key, ('<Cmd>lua %s<CR>'):format(cmd), { buffer = buf_id, nowait = true, silent = true })\n  end\n\n  buf_keymap('<CR>', 'MiniStarter.eval_current_item()')\n\n  buf_keymap('<Up>', [[MiniStarter.update_current_item('prev')]])\n  buf_keymap('<C-p>', [[MiniStarter.update_current_item('prev')]])\n  buf_keymap('<M-k>', [[MiniStarter.update_current_item('prev')]])\n  buf_keymap('<Down>', [[MiniStarter.update_current_item('next')]])\n  buf_keymap('<C-n>', [[MiniStarter.update_current_item('next')]])\n  buf_keymap('<M-j>', [[MiniStarter.update_current_item('next')]])\n\n  -- Make all special symbols to update query\n  for _, key in ipairs(vim.split(H.get_config().query_updaters, '')) do\n    local key_string = vim.inspect(tostring(key))\n    buf_keymap(key, ('MiniStarter.add_to_query(%s)'):format(key_string))\n  end\n\n  buf_keymap('<Esc>', [[MiniStarter.set_query('')]])\n  buf_keymap('<BS>', 'MiniStarter.add_to_query()')\n  buf_keymap('<C-c>', 'MiniStarter.close()')\nend\n\nH.add_hl_activity = function(buf_id, query)\n  for _, item in ipairs(H.buffer_data[buf_id].items) do\n    local l = item._line\n    local s = item._start_col\n    local e = item._end_col\n    if item._active then\n      H.buf_hl(buf_id, H.ns.activity, 'MiniStarterQuery', l, s, s + query:len(), 53)\n    else\n      H.buf_hl(buf_id, H.ns.activity, 'MiniStarterInactive', l, s, e, 53)\n    end\n  end\nend\n\nH.add_hl_current_item = function(buf_id)\n  local data = H.buffer_data[buf_id]\n  local cur_item = data.items[data.current_item_id]\n  H.buf_hl(buf_id, H.ns.current_item, 'MiniStarterCurrent', cur_item._line, cur_item._start_col, cur_item._end_col, 51)\nend\n\n-- Predicates -----------------------------------------------------------------\nH.is_fun_or_string = function(x, allow_nil)\n  if allow_nil == nil then allow_nil = true end\n  return (allow_nil and x == nil) or type(x) == 'function' or type(x) == 'string'\nend\n\nH.is_item = function(x)\n  return type(x) == 'table'\n    and H.is_fun_or_string(x['action'], false)\n    and type(x['name']) == 'string'\n    and type(x['section']) == 'string'\nend\n\nH.is_something_shown = function()\n  -- Don't open Starter buffer if Neovim is opened to show something. That is\n  -- when at least one of the following is true:\n  -- - There are files in arguments (like `nvim foo.txt` with new file).\n  if vim.fn.argc() > 0 then return true end\n\n  -- - Several buffers are listed (like session with placeholder buffers). That\n  --   means unlisted buffers (like from `nvim-tree`) don't affect decision.\n  local listed_buffers = vim.tbl_filter(\n    function(buf_id) return vim.fn.buflisted(buf_id) == 1 end,\n    vim.api.nvim_list_bufs()\n  )\n  if #listed_buffers > 1 then return true end\n\n  -- - Current buffer is meant to show something else\n  if vim.bo.filetype ~= '' then return true end\n\n  -- - Current buffer has any lines (something opened explicitly).\n  -- NOTE: Usage of `line2byte(line('$') + 1) < 0` seemed to be fine, but it\n  -- doesn't work if some automated changed was made to buffer while leaving it\n  -- empty (returns 2 instead of -1). This was also the reason of not being\n  -- able to test with child Neovim process from 'tests/helpers'.\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  if n_lines > 1 then return true end\n  local first_line = vim.api.nvim_buf_get_lines(0, 0, 1, true)[1]\n  if string.len(first_line) > 0 then return true end\n\n  return false\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.starter) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'ministarter://' .. buf_id .. '/' .. name) end\n\nH.echo = function(msg, is_important)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.starter) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n  local chunks, tot_width = {}, 0\n  for _, ch in ipairs(msg) do\n    local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n    table.insert(chunks, new_ch)\n    tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n    if tot_width >= max_width then break end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, is_important, {})\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.edit = function(path, win_id)\n  if type(path) ~= 'string' then return end\n  local b = vim.api.nvim_win_get_buf(win_id or 0)\n  local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)\n    and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))\n  local buf_id = vim.fn.bufadd(vim.fn.fnamemodify(path, ':.'))\n  -- Showing in window also loads. Use `pcall` to not error with swap messages.\n  pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)\n  vim.bo[buf_id].buflisted = true\n  if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end\n  return buf_id\nend\n\nH.validate_starter_buf_id = function(buf_id, fun_name, severity)\n  local is_starter_buf_id = type(buf_id) == 'number'\n    and vim.tbl_contains(vim.tbl_keys(H.buffer_data), buf_id)\n    and vim.api.nvim_buf_is_valid(buf_id)\n  if is_starter_buf_id then return true end\n\n  local msg = string.format('`buf_id` in `%s` is not an identifier of valid Starter buffer.', fun_name)\n  if severity == 'error' then H.error(msg) end\n\n  H.message(msg)\n  return false\nend\n\nH.eval_fun_or_string = function(x, string_as_cmd)\n  if type(x) == 'function' then return x() end\n  if type(x) == 'string' then\n    if string_as_cmd then\n      vim.cmd(x)\n    else\n      return x\n    end\n  end\nend\n\n-- Use `priority` because of the regression bug (highlights are not stacked\n-- properly): https://github.com/neovim/neovim/issues/17358\nH.buf_hl = function(buf_id, ns_id, hl_group, line, col_start, col_end, priority)\n  local opts = { end_row = line, end_col = col_end, hl_group = hl_group, priority = priority }\n  vim.api.nvim_buf_set_extmark(buf_id, ns_id, line, col_start, opts)\nend\n\nH.get_buffer_windows = function(buf_id)\n  return vim.tbl_filter(\n    function(win_id) return vim.api.nvim_win_get_buf(win_id) == buf_id end,\n    vim.api.nvim_list_wins()\n  )\nend\n\nH.unique_nprefix = function(strings)\n  -- For every string compute minimum width of unique prefix. NOTE: this can be\n  -- done simpler but it would be O(n^2) which *will* have noticeable effect\n  -- when there are a) many items and b) some of them are identical and have\n  -- big length (like recent files with full paths).\n\n  -- Make copy because it will be modified\n  local str_set = vim.deepcopy(strings)\n  local res, cur_n = {}, 0\n  while vim.tbl_count(str_set) > 0 do\n    cur_n = cur_n + 1\n\n    -- `prefix_tbl`: string id's with current prefix\n    -- `nowhere_to_go` is `true` if all strings have lengths less than `cur_n`\n    local prefix_tbl, nowhere_to_go = {}, true\n    for id, s in pairs(str_set) do\n      nowhere_to_go = nowhere_to_go and (#s < cur_n)\n      local prefix = s:sub(1, cur_n)\n      prefix_tbl[prefix] = prefix_tbl[prefix] == nil and {} or prefix_tbl[prefix]\n      table.insert(prefix_tbl[prefix], id)\n    end\n\n    -- Output for non-unique string is its length\n    if nowhere_to_go then\n      for k, s in pairs(str_set) do\n        res[k] = #s\n      end\n      break\n    end\n\n    for _, keys_with_prefix in pairs(prefix_tbl) do\n      -- If prefix is seen only once, it is unique\n      if #keys_with_prefix == 1 then\n        local k = keys_with_prefix[1]\n        -- Use `math.min` to account for empty strings and non-unique ones\n        res[k] = math.min(#str_set[k], cur_n)\n        -- Remove this string as it already has final nprefix\n        str_set[k] = nil\n      end\n    end\n  end\n\n  return res\nend\n\nreturn MiniStarter\n"
  },
  {
    "path": "lua/mini/statusline.lua",
    "content": "--- *mini.statusline* Statusline\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Define own custom statusline structure for active and inactive windows.\n---   This is done with a function which should return string appropriate for\n---   |'statusline'|. Its code should be similar to default one with structure:\n---     - Compute string data for every section you want to be displayed.\n---     - Combine them in groups with |MiniStatusline.combine_groups()|.\n---\n--- - Built-in active mode indicator with colors.\n---\n--- - Sections can hide information when window is too narrow (specific window\n---   width is configurable per section).\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies (provide extra functionality, will work without them):\n---\n--- - Nerd font (to support extra icons).\n---\n--- - Enabled |mini.icons| module for |MiniStatusline.section_fileinfo()|.\n---   Falls back to using 'nvim-tree/nvim-web-devicons' plugin or shows nothing.\n---\n--- - Enabled |mini.git| module for |MiniStatusline.section_git()|.\n---   Falls back to using 'lewis6991/gitsigns.nvim' plugin or shows nothing.\n---\n--- - Enabled |mini.diff| module for |MiniStatusline.section_diff()|.\n---   Falls back to using 'lewis6991/gitsigns.nvim' plugin or shows nothing.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.statusline').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniStatusline` which you can use for scripting or manually (with\n--- `:lua MiniStatusline.*`).\n---\n--- See |MiniStatusline.config| for `config` structure and default values. For\n--- some content examples, see |MiniStatusline-example-content|.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.ministatusline_config` which should have same structure as\n--- `MiniStatusline.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Highlight groups ~\n---\n--- Highlight depending on mode (second |MiniStatusline.section_mode()| output):\n--- - `MiniStatuslineModeNormal` - Normal mode.\n--- - `MiniStatuslineModeInsert` - Insert mode.\n--- - `MiniStatuslineModeVisual` - Visual mode.\n--- - `MiniStatuslineModeReplace` - Replace mode.\n--- - `MiniStatuslineModeCommand` - Command mode.\n--- - `MiniStatuslineModeOther` - other modes (like Terminal, etc.).\n---\n--- Highlight used in default statusline:\n--- - `MiniStatuslineDevinfo` - for \"dev info\" group\n---   (|MiniStatusline.section_git()| and |MiniStatusline.section_diagnostics()|).\n--- - `MiniStatuslineFilename` - for |MiniStatusline.section_filename()| section.\n--- - `MiniStatuslineFileinfo` - for |MiniStatusline.section_fileinfo()| section.\n---\n--- Other groups:\n--- - `MiniStatuslineInactive` - highlighting in not focused window.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable (show empty statusline), set `vim.g.ministatusline_disable`\n--- (globally) or `vim.b.ministatusline_disable` (for a buffer) to `true`.\n--- Considering high number of different scenarios and customization\n--- intentions, writing exact rules for disabling module's functionality is\n--- left to user. See |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniStatusline\n\n--- Example content\n---\n--- # Default content ~\n---\n--- This function is used as default value for active content: >lua\n---\n---   function()\n---     local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 })\n---     local git           = MiniStatusline.section_git({ trunc_width = 40 })\n---     local diff          = MiniStatusline.section_diff({ trunc_width = 75 })\n---     local diagnostics   = MiniStatusline.section_diagnostics({ trunc_width = 75 })\n---     local lsp           = MiniStatusline.section_lsp({ trunc_width = 75 })\n---     local filename      = MiniStatusline.section_filename({ trunc_width = 140 })\n---     local fileinfo      = MiniStatusline.section_fileinfo({ trunc_width = 120 })\n---     local location      = MiniStatusline.section_location({ trunc_width = 75 })\n---     local search        = MiniStatusline.section_searchcount({ trunc_width = 75 })\n---\n---     return MiniStatusline.combine_groups({\n---       { hl = mode_hl,                  strings = { mode } },\n---       { hl = 'MiniStatuslineDevinfo',  strings = { git, diff, diagnostics, lsp } },\n---       '%<', -- Mark general truncate point\n---       { hl = 'MiniStatuslineFilename', strings = { filename } },\n---       '%=', -- End left alignment\n---       { hl = 'MiniStatuslineFileinfo', strings = { fileinfo } },\n---       { hl = mode_hl,                  strings = { search, location } },\n---     })\n---   end\n--- <\n--- # Show boolean options ~\n---\n--- To compute section string for boolean option use variation of this code\n--- snippet inside content function (you can modify option itself, truncation\n--- width, short and long displayed names): >lua\n---\n---   local spell = vim.wo.spell and (MiniStatusline.is_truncated(120) and 'S' or 'SPELL') or ''\n--- <\n--- Here `x and y or z` is a common Lua way of doing ternary operator: if `x`\n--- is `true`-ish then return `y`, if not - return `z`.\n---@tag MiniStatusline-example-content\n\n---@alias __statusline_args table Section arguments.\n---@alias __statusline_section string Section string.\n\n-- Module definition ==========================================================\nlocal MiniStatusline = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniStatusline.config|.\n---\n---@usage >lua\n---   require('mini.statusline').setup() -- use default config\n---   -- OR\n---   require('mini.statusline').setup({}) -- replace {} with your config table\n--- <\nMiniStatusline.setup = function(config)\n  -- Export module\n  _G.MiniStatusline = MiniStatusline\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- - Disable built-in statusline in Quickfix window\n  vim.g.qf_disable_statusline = 1\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniStatusline.config = {\n  -- Content of statusline as functions which return statusline string. See\n  -- `:h statusline` and code of default contents (used instead of `nil`).\n  content = {\n    -- Content for active window\n    active = nil,\n    -- Content for inactive window(s)\n    inactive = nil,\n  },\n\n  -- Whether to use icons by default\n  use_icons = true,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Compute content for active window\nMiniStatusline.active = function()\n  if H.is_disabled() then return '' end\n  return (H.get_config().content.active or H.default_content_active)()\nend\n\n--- Compute content for inactive window\nMiniStatusline.inactive = function()\n  if H.is_disabled() then return '' end\n  return (H.get_config().content.inactive or H.default_content_inactive)()\nend\n\n--- Combine groups of sections\n---\n--- Each group can be either a string or a table with fields `hl` (group's\n--- highlight group) and `strings` (strings representing sections).\n---\n--- General idea of this function is as follows;\n--- - String group is used as is (useful for special strings like `%<` or `%=`).\n--- - Each table group has own highlighting in `hl` field (if missing, the\n---   previous one is used) and string parts in `strings` field. Non-empty\n---   strings from `strings` are separated by one space. Non-empty groups are\n---   separated by two spaces (one for each highlighting).\n---\n---@param groups table Array of groups.\n---\n---@return string String suitable for 'statusline'.\nMiniStatusline.combine_groups = function(groups)\n  local parts = vim.tbl_map(function(s)\n    if type(s) == 'string' then return s end\n    if type(s) ~= 'table' then return '' end\n\n    local string_arr = vim.tbl_filter(function(x) return type(x) == 'string' and x ~= '' end, s.strings or {})\n    local str = table.concat(string_arr, ' ')\n\n    -- Use previous highlight group\n    if s.hl == nil then return ' ' .. str .. ' ' end\n\n    -- Allow using this highlight group later\n    if str:len() == 0 then return '%#' .. s.hl .. '#' end\n\n    return string.format('%%#%s# %s ', s.hl, str)\n  end, groups)\n\n  return table.concat(parts, '')\nend\n\n--- Decide whether to truncate\n---\n--- This basically computes window width and compares it to `trunc_width`: if\n--- window is smaller then truncate; otherwise don't. Don't truncate by\n--- default.\n---\n--- Use this to manually decide if section needs truncation or not.\n---\n---@param trunc_width number|nil Truncation width. If `nil`, output is `false`.\n---\n---@return boolean Whether to truncate.\nMiniStatusline.is_truncated = function(trunc_width)\n  -- Use -1 to default to 'not truncated'\n  local cur_width = vim.o.laststatus == 3 and vim.o.columns or vim.api.nvim_win_get_width(0)\n  return cur_width < (trunc_width or -1)\nend\n\n-- Sections ===================================================================\n-- Functions should return output text without whitespace on sides.\n-- Return empty string to omit section.\n\n--- Section for Vim |mode()|\n---\n--- Short output is returned if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args\n---\n---@return ... Section string and mode's highlight group.\nMiniStatusline.section_mode = function(args)\n  local mode_info = H.modes[vim.fn.mode()]\n\n  local mode = MiniStatusline.is_truncated(args.trunc_width) and mode_info.short or mode_info.long\n\n  return mode, mode_info.hl\nend\n\n--- Section for Git information\n---\n--- Shows Git summary from |mini.git| (should be set up; recommended). To tweak\n--- formatting of what data is shown, modify buffer-local summary string directly\n--- as described in |MiniGit-examples|.\n---\n--- If 'mini.git' is not set up, section falls back on 'lewis6991/gitsigns' data\n--- or showing empty string.\n---\n--- Empty string is returned if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args Use `args.icon` to supply your own icon.\n---\n---@return __statusline_section\nMiniStatusline.section_git = function(args)\n  if MiniStatusline.is_truncated(args.trunc_width) then return '' end\n\n  local summary = vim.b.minigit_summary_string or vim.b.gitsigns_head\n  if summary == nil then return '' end\n\n  local use_icons = H.use_icons or H.get_config().use_icons\n  local icon = args.icon or (use_icons and '' or 'Git')\n  return icon .. ' ' .. (summary == '' and '-' or summary)\nend\n\n--- Section for diff information\n---\n--- Shows diff summary from |mini.diff| (should be set up; recommended). To tweak\n--- formatting of what data is shown, modify buffer-local summary string directly\n--- as described in |MiniDiff-diff-summary|.\n---\n--- If 'mini.diff' is not set up, section falls back on 'lewis6991/gitsigns' data\n--- or showing empty string.\n---\n--- Empty string is returned if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args Use `args.icon` to supply your own icon.\n---\n---@return __statusline_section\nMiniStatusline.section_diff = function(args)\n  if MiniStatusline.is_truncated(args.trunc_width) then return '' end\n\n  local summary = vim.b.minidiff_summary_string or vim.b.gitsigns_status\n  if summary == nil then return '' end\n\n  local use_icons = H.use_icons or H.get_config().use_icons\n  local icon = args.icon or (use_icons and '' or 'Diff')\n  return icon .. ' ' .. (summary == '' and '-' or summary)\nend\n\n--- Section for Neovim's builtin diagnostics\n---\n--- Shows nothing if diagnostics is disabled, no diagnostic is set, or for short\n--- output. Otherwise uses |vim.diagnostic.get()| to compute and show number of\n--- errors ('E'), warnings ('W'), information ('I'), and hints ('H').\n---\n--- Short output is returned if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args Use `args.icon` to supply your own icon.\n---   Use `args.signs` to use custom signs per severity level name. For example: >lua\n---\n---   { ERROR = '!', WARN = '?', INFO = '@', HINT = '*' }\n--- <\n---@return __statusline_section\nMiniStatusline.section_diagnostics = function(args)\n  if MiniStatusline.is_truncated(args.trunc_width) then return '' end\n\n  -- Construct string parts. NOTE: call `diagnostic_is_disabled()` *after*\n  -- check for present `count` to not source `vim.diagnostic` on startup.\n  local count = H.diagnostic_counts[vim.api.nvim_get_current_buf()]\n  if count == nil or H.diagnostic_is_disabled() then return '' end\n\n  local severity, signs, t = vim.diagnostic.severity, args.signs or {}, {}\n  for _, level in ipairs(H.diagnostic_levels) do\n    local n = count[severity[level.name]] or 0\n    -- Add level info only if diagnostic is present\n    if n > 0 then table.insert(t, ' ' .. (signs[level.name] or level.sign) .. n) end\n  end\n  if #t == 0 then return '' end\n\n  local use_icons = H.use_icons or H.get_config().use_icons\n  local icon = args.icon or (use_icons and '' or 'Diag')\n  return icon .. table.concat(t, '')\nend\n\n--- Section for attached LSP servers\n---\n--- Shows number of LSP servers (each as separate \"+\" character) attached to\n--- current buffer or nothing if none is attached.\n--- Nothing is shown if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args Use `args.icon` to supply your own icon.\n---\n---@return __statusline_section\nMiniStatusline.section_lsp = function(args)\n  if MiniStatusline.is_truncated(args.trunc_width) then return '' end\n\n  local attached = H.attached_lsp[vim.api.nvim_get_current_buf()] or ''\n  if attached == '' then return '' end\n\n  local use_icons = H.use_icons or H.get_config().use_icons\n  local icon = args.icon or (use_icons and '󰰎' or 'LSP')\n  return icon .. ' ' .. attached\nend\n\n--- Section for file name\n---\n--- Show full file name or relative in short output.\n---\n--- Short output is returned if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args\n---\n---@return __statusline_section\nMiniStatusline.section_filename = function(args)\n  -- In terminal always use plain name\n  if vim.bo.buftype == 'terminal' then\n    return '%t'\n  elseif MiniStatusline.is_truncated(args.trunc_width) then\n    -- File name with 'truncate', 'modified', 'readonly' flags\n    -- Use relative path if truncated\n    return '%f%m%r'\n  else\n    -- Use fullpath if not truncated\n    return '%F%m%r'\n  end\nend\n\n--- Section for file information\n---\n--- Shows 'filetype', 'fileencoding' / 'encoding', 'fileformat', and buffer size.\n--- Short output has only non-empty 'filetype' and is returned if window width is\n--- lower than `args.trunc_width` or buffer is not normal (as per 'buftype').\n---\n--- Buffer size is computed based on current text, not file's saved version.\n---\n--- If `config.use_icons` is true and icon provider is present (see\n--- \"Dependencies\" section in |mini.statusline|), shows icon near the filetype.\n---\n---@param args __statusline_args\n---\n---@return __statusline_section\nMiniStatusline.section_fileinfo = function(args)\n  local filetype = vim.bo.filetype\n\n  -- Add filetype icon\n  H.ensure_get_icon()\n  if H.get_icon ~= nil and filetype ~= '' then filetype = H.get_icon(filetype) .. ' ' .. filetype end\n\n  -- Construct output string if truncated or buffer is not normal\n  if MiniStatusline.is_truncated(args.trunc_width) or vim.bo.buftype ~= '' then return filetype end\n\n  -- Construct output string with extra file info\n  local encoding = vim.bo.fileencoding or vim.bo.encoding\n  local format = vim.bo.fileformat\n  local size = H.get_filesize()\n\n  return string.format('%s%s%s[%s] %s', filetype, filetype == '' and '' or ' ', encoding, format, size)\nend\n\n--- Section for location inside buffer\n---\n--- Show location inside buffer in the form:\n--- - Normal: `'<cursor line>|<total lines>│<cursor column>|<total columns>'`\n--- - Short: `'<cursor line>│<cursor column>'`\n---\n--- Short output is returned if window width is lower than `args.trunc_width`.\n---\n---@param args __statusline_args\n---\n---@return __statusline_section\nMiniStatusline.section_location = function(args)\n  -- Use virtual column number to allow update when past last column\n  if MiniStatusline.is_truncated(args.trunc_width) then return '%l│%2v' end\n\n  -- Use `virtcol()` to correctly handle multi-byte characters\n  return '%l|%L│%2v|%-2{virtcol(\"$\") - 1}'\nend\n\n--- Section for current search count\n---\n--- Show the current status of |searchcount()|. Empty output is returned if\n--- window width is lower than `args.trunc_width`, search highlighting is not\n--- on (see |v:hlsearch|), or if number of search result is 0.\n---\n--- `args.options` is forwarded to |searchcount()|. By default it recomputes\n--- data on every call which can be computationally expensive (although still\n--- usually on 0.1 ms order of magnitude). To prevent this, supply\n--- `args.options = { recompute = false }`.\n---\n---@param args __statusline_args\n---\n---@return __statusline_section\nMiniStatusline.section_searchcount = function(args)\n  if vim.v.hlsearch == 0 or MiniStatusline.is_truncated(args.trunc_width) then return '' end\n  -- `searchcount()` can return errors because it is evaluated very often in\n  -- statusline. For example, when typing `/` followed by `\\(`, it gives E54.\n  local ok, s_count = pcall(vim.fn.searchcount, (args or {}).options or { recompute = true })\n  if not ok or s_count.current == nil or s_count.total == 0 then return '' end\n\n  if s_count.incomplete == 1 then return '?/?' end\n\n  local too_many = '>' .. s_count.maxcount\n  local current = s_count.current > s_count.maxcount and too_many or s_count.current\n  local total = s_count.total > s_count.maxcount and too_many or s_count.total\n  return current .. '/' .. total\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniStatusline.config)\n\n-- Showed diagnostic levels\nH.diagnostic_levels = {\n  { name = 'ERROR', sign = 'E' },\n  { name = 'WARN', sign = 'W' },\n  { name = 'INFO', sign = 'I' },\n  { name = 'HINT', sign = 'H' },\n}\n\n-- Diagnostic counts per buffer id\nH.diagnostic_counts = {}\n\n-- String representation of attached LSP clients per buffer id\nH.attached_lsp = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('content', config.content, 'table')\n  H.check_type('content.active', config.content.active, 'function', true)\n  H.check_type('content.inactive', config.content.inactive, 'function', true)\n\n  H.check_type('use_icons', config.use_icons, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniStatusline.config = config\n\n  -- Set statusline globally and dynamically decide which content to use\n  vim.go.statusline =\n    '%{%(nvim_get_current_win()==#g:actual_curwin || &laststatus==3) ? v:lua.MiniStatusline.active() : v:lua.MiniStatusline.inactive()%}'\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniStatusline', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  -- Use `schedule_wrap()` because at `LspDetach` server is still present\n  local track_lsp = vim.schedule_wrap(function(data)\n    H.attached_lsp[data.buf] = vim.api.nvim_buf_is_valid(data.buf) and H.compute_attached_lsp(data.buf) or nil\n    vim.cmd('redrawstatus')\n  end)\n  au({ 'LspAttach', 'LspDetach' }, '*', track_lsp, 'Track LSP clients')\n\n  -- Use `schedule_wrap()` because `redrawstatus` might error on `:bwipeout`\n  -- See: https://github.com/neovim/neovim/issues/32349\n  local track_diagnostics = vim.schedule_wrap(function(data)\n    H.diagnostic_counts[data.buf] = vim.api.nvim_buf_is_valid(data.buf) and H.get_diagnostic_count(data.buf) or nil\n    vim.cmd('redrawstatus')\n  end)\n  au('DiagnosticChanged', '*', track_diagnostics, 'Track diagnostics')\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local set_default_hl = function(name, data)\n    data.default = true\n    vim.api.nvim_set_hl(0, name, data)\n  end\n\n  set_default_hl('MiniStatuslineModeNormal',  { link = 'Cursor' })\n  set_default_hl('MiniStatuslineModeInsert',  { link = 'DiffChange' })\n  set_default_hl('MiniStatuslineModeVisual',  { link = 'DiffAdd' })\n  set_default_hl('MiniStatuslineModeReplace', { link = 'DiffDelete' })\n  set_default_hl('MiniStatuslineModeCommand', { link = 'DiffText' })\n  set_default_hl('MiniStatuslineModeOther',   { link = 'IncSearch' })\n\n  set_default_hl('MiniStatuslineDevinfo',  { link = 'StatusLine' })\n  set_default_hl('MiniStatuslineFilename', { link = 'StatusLineNC' })\n  set_default_hl('MiniStatuslineFileinfo', { link = 'StatusLine' })\n  set_default_hl('MiniStatuslineInactive', { link = 'StatusLineNC' })\nend\n\nH.is_disabled = function() return vim.g.ministatusline_disable == true or vim.b.ministatusline_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniStatusline.config, vim.b.ministatusline_config or {}, config or {})\nend\n\n-- Mode -----------------------------------------------------------------------\n-- Custom `^V` and `^S` symbols to make this file appropriate for copy-paste\n-- (otherwise those symbols are not displayed).\nlocal CTRL_S = vim.api.nvim_replace_termcodes('<C-S>', true, true, true)\nlocal CTRL_V = vim.api.nvim_replace_termcodes('<C-V>', true, true, true)\n\n-- stylua: ignore start\nH.modes = setmetatable({\n  ['n']    = { long = 'Normal',   short = 'N',   hl = 'MiniStatuslineModeNormal' },\n  ['v']    = { long = 'Visual',   short = 'V',   hl = 'MiniStatuslineModeVisual' },\n  ['V']    = { long = 'V-Line',   short = 'V-L', hl = 'MiniStatuslineModeVisual' },\n  [CTRL_V] = { long = 'V-Block',  short = 'V-B', hl = 'MiniStatuslineModeVisual' },\n  ['s']    = { long = 'Select',   short = 'S',   hl = 'MiniStatuslineModeVisual' },\n  ['S']    = { long = 'S-Line',   short = 'S-L', hl = 'MiniStatuslineModeVisual' },\n  [CTRL_S] = { long = 'S-Block',  short = 'S-B', hl = 'MiniStatuslineModeVisual' },\n  ['i']    = { long = 'Insert',   short = 'I',   hl = 'MiniStatuslineModeInsert' },\n  ['R']    = { long = 'Replace',  short = 'R',   hl = 'MiniStatuslineModeReplace' },\n  ['c']    = { long = 'Command',  short = 'C',   hl = 'MiniStatuslineModeCommand' },\n  ['r']    = { long = 'Prompt',   short = 'P',   hl = 'MiniStatuslineModeOther' },\n  ['!']    = { long = 'Shell',    short = 'Sh',  hl = 'MiniStatuslineModeOther' },\n  ['t']    = { long = 'Terminal', short = 'T',   hl = 'MiniStatuslineModeOther' },\n}, {\n  -- By default return 'Unknown' but this shouldn't be needed\n  __index = function()\n    return   { long = 'Unknown',  short = 'U',   hl = '%#MiniStatuslineModeOther#' }\n  end,\n})\n-- stylua: ignore end\n\n-- Default content ------------------------------------------------------------\n--stylua: ignore\nH.default_content_active = function()\n  H.use_icons = H.get_config().use_icons\n  local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 })\n  local git           = MiniStatusline.section_git({ trunc_width = 40 })\n  local diff          = MiniStatusline.section_diff({ trunc_width = 75 })\n  local diagnostics   = MiniStatusline.section_diagnostics({ trunc_width = 75 })\n  local lsp           = MiniStatusline.section_lsp({ trunc_width = 75 })\n  local filename      = MiniStatusline.section_filename({ trunc_width = 140 })\n  local fileinfo      = MiniStatusline.section_fileinfo({ trunc_width = 120 })\n  local location      = MiniStatusline.section_location({ trunc_width = 75 })\n  local search        = MiniStatusline.section_searchcount({ trunc_width = 75 })\n  H.use_icons = nil\n\n  -- Usage of `MiniStatusline.combine_groups()` ensures highlighting and\n  -- correct padding with spaces between groups (accounts for 'missing'\n  -- sections, etc.)\n  return MiniStatusline.combine_groups({\n    { hl = mode_hl,                  strings = { mode } },\n    { hl = 'MiniStatuslineDevinfo',  strings = { git, diff, diagnostics, lsp } },\n    '%<', -- Mark general truncate point\n    { hl = 'MiniStatuslineFilename', strings = { filename } },\n    '%=', -- End left alignment\n    { hl = 'MiniStatuslineFileinfo', strings = { fileinfo } },\n    { hl = mode_hl,                  strings = { search, location } },\n  })\nend\n\nH.default_content_inactive = function() return '%#MiniStatuslineInactive#%F%=' end\n\n-- LSP ------------------------------------------------------------------------\nH.compute_attached_lsp = function(buf_id) return string.rep('+', vim.tbl_count(H.get_buf_lsp_clients(buf_id))) end\n\nH.get_buf_lsp_clients = function(buf_id) return vim.lsp.get_clients({ bufnr = buf_id }) end\n-- NOTE: Use `has('nvim-0.xx')` instead of directly checking presence of target\n-- function to avoid loading `vim.xxx` modules at `require('mini.statusline')`.\n-- This visibly improves startup time.\nif vim.fn.has('nvim-0.10') == 0 then\n  H.get_buf_lsp_clients = function(buf_id) return vim.lsp.buf_get_clients(buf_id) end\nend\n\n-- Diagnostics ----------------------------------------------------------------\nH.get_diagnostic_count = function(buf_id) return vim.diagnostic.count(buf_id) end\nif vim.fn.has('nvim-0.10') == 0 then\n  H.get_diagnostic_count = function(buf_id)\n    local res = {}\n    for _, d in ipairs(vim.diagnostic.get(buf_id)) do\n      res[d.severity] = (res[d.severity] or 0) + 1\n    end\n    return res\n  end\nend\n\nH.diagnostic_is_disabled = function() return not vim.diagnostic.is_enabled({ bufnr = 0 }) end\nif vim.fn.has('nvim-0.10') == 0 then H.diagnostic_is_disabled = function() return vim.diagnostic.is_disabled(0) end end\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.statusline) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.get_filesize = function()\n  local size = math.max(vim.fn.line2byte(vim.fn.line('$') + 1) - 1, 0)\n  if size < 1024 then\n    return string.format('%dB', size)\n  elseif size < 1048576 then\n    return string.format('%.2fKiB', size / 1024)\n  else\n    return string.format('%.2fMiB', size / 1048576)\n  end\nend\n\nH.ensure_get_icon = function()\n  if not (H.use_icons or H.get_config().use_icons) then\n    -- Show no icon\n    H.get_icon = nil\n  elseif H.get_icon ~= nil then\n    -- Cache only once\n    return\n  elseif _G.MiniIcons ~= nil then\n    -- Prefer 'mini.icons'\n    H.get_icon = function(filetype) return (_G.MiniIcons.get('filetype', filetype)) end\n  else\n    -- Try falling back to 'nvim-web-devicons'\n    local has_devicons, devicons = pcall(require, 'nvim-web-devicons')\n    if not has_devicons then return end\n    H.get_icon = function() return (devicons.get_icon(vim.fn.expand('%:t'), nil, { default = true })) end\n  end\nend\n\nreturn MiniStatusline\n"
  },
  {
    "path": "lua/mini/surround.lua",
    "content": "--- *mini.surround* Surround actions\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Fast and feature-rich surrounding. Can be configured to have experience\n--- similar to [tpope/vim-surround](https://github.com/tpope/vim-surround)\n--- (see |MiniSurround-vim-surround-config|).\n---\n--- Features:\n--- - Actions (text editing actions are dot-repeatable out of the box and\n---   respect |[count]|) with configurable mappings:\n---     - Add surrounding with `sa` (in visual mode or on motion).\n---     - Delete surrounding with `sd`.\n---     - Replace surrounding with `sr`.\n---     - Find surrounding with `sf` or `sF` (move cursor right or left).\n---     - Highlight surrounding with `sh`.\n---\n--- - Surrounding is identified by a single character as both \"input\" (in\n---   `delete` and `replace` start, `find`, and `highlight`) and \"output\" (in\n---   `add` and `replace` end):\n---     - 'f' - function call (string of alphanumeric symbols or '_' or '.'\n---       followed by balanced '()'). In \"input\" finds function call, in\n---       \"output\" prompts user to enter function name.\n---     - 't' - tag. In \"input\" finds tag with same identifier, in \"output\"\n---       prompts user to enter tag name with possible attributes.\n---     - All symbols in brackets '()', '[]', '{}', '<>\". In \"input' represents\n---       balanced brackets (open - with whitespace pad, close - without), in\n---       \"output\" - left and right parts of brackets.\n---     - '?' - interactive. Prompts user to enter left and right parts.\n---     - All other single character identifiers (supported by |getcharstr()|)\n---       represent surrounding with identical left and right parts.\n---\n--- - Configurable search methods to find not only covering but possibly next,\n---   previous, or nearest surrounding. See more in |MiniSurround.config|.\n---\n--- - All actions involving finding surrounding (delete, replace, find,\n---   highlight) can be used with suffix that changes search method to find\n---   previous/last. See more in |MiniSurround.config|.\n---\n--- Known issues which won't be resolved:\n--- - Search for surrounding is done using Lua patterns (regex-like approach).\n---   So certain amount of false positives should be expected.\n---\n--- - When searching for \"input\" surrounding, there is no distinction if it is\n---   inside string or comment. So in this case there will be not proper match\n---   for a function call: 'f(a = \")\", b = 1)'.\n---\n--- - Tags are searched using regex-like methods, so issues are inevitable.\n---   Overall it is pretty good, but certain cases won't work. Like self-nested\n---   tags won't match correctly on both ends: '<a><a></a></a>'.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.surround').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniSurround` which you can use for scripting or manually (with\n--- `:lua MiniSurround.*`).\n---\n--- See |MiniSurround.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minisurround_config` which should have same structure as\n--- `MiniSurround.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Example usage ~\n---\n--- Regular mappings:\n--- - `saiw)` - add (`sa`) for inner word (`iw`) parenthesis (`)`).\n--- - `saiw?[[<CR>]]<CR>` - add (`sa`) for inner word (`iw`) interactive\n---   surrounding (`?`): `[[` for left and `]]` for right.\n--- - `2sdf` - delete (`sd`) second (`2`) surrounding function call (`f`).\n--- - `sr)tdiv<CR>` - replace (`sr`) surrounding parenthesis (`)`) with tag\n---   (`t`) with identifier 'div' (`div<CR>` in command line prompt).\n--- - `sff` - find right (`sf`) part of surrounding function call (`f`).\n--- - `sh}` - highlight (`sh`) for a brief period of time surrounding curly\n---   brackets (`}`).\n---\n--- Extended mappings (temporary force \"prev\"/\"next\" search methods):\n--- - `sdnf` - delete (`sd`) next (`n`) function call (`f`).\n--- - `srlf(` - replace (`sr`) last (`l`) function call (`f`) with padded\n---   bracket (`(`).\n--- - `2sfnt` - find (`sf`) second (`2`) next (`n`) tag (`t`).\n--- - `2shl}` - highlight (`sh`) last (`l`) second (`2`) curly bracket (`}`).\n---\n--- # Comparisons ~\n---\n--- - [tpope/vim-surround](https://github.com/tpope/vim-surround):\n---     - 'vim-surround' has completely different, with other focus set of\n---       default mappings, while 'mini.surround' has a more coherent set.\n---     - 'mini.surround' supports dot-repeat, customized search path (see\n---       |MiniSurround.config|), customized specifications (see\n---       |MiniSurround-surrounding-specification|) allowing usage of tree-sitter\n---       queries (see |MiniSurround.gen_spec.input.treesitter()|),\n---       highlighting and finding surrounding, \"last\"/\"next\" extended\n---       mappings. While 'vim-surround' does not.\n--- - [machakann/vim-sandwich](https://github.com/machakann/vim-sandwich):\n---     - Both have same keybindings for common actions (add, delete, replace).\n---     - Otherwise same differences as with 'tpope/vim-surround' (except\n---       dot-repeat because 'vim-sandwich' supports it).\n--- - [kylechui/nvim-surround](https://github.com/kylechui/nvim-surround):\n---     - 'nvim-surround' is designed after 'tpope/vim-surround' with same\n---       default mappings and logic, while 'mini.surround' has mappings\n---       similar to 'machakann/vim-sandwich'.\n---     - 'mini.surround' has more flexible customization of input surrounding\n---       (with composed patterns, region pair(s), search methods).\n---     - 'mini.surround' supports |[count]| in both input and output\n---       surrounding (see |MiniSurround-count-with-actions|) while\n---       'nvim-surround' doesn't.\n---     - 'mini.surround' supports \"last\"/\"next\" extended mappings.\n--- - |mini.ai|:\n---     - Both use similar logic for finding target: textobject in 'mini.ai'\n---       and surrounding pair in 'mini.surround'. While 'mini.ai' uses\n---       extraction pattern for separate `a` and `i` textobjects,\n---       'mini.surround' uses it to select left and right surroundings\n---       (basically a difference between `a` and `i` textobjects).\n---     - Some builtin specifications are slightly different:\n---         - Quotes in 'mini.ai' are balanced, in 'mini.surround' they are not.\n---         - The 'mini.surround' doesn't have argument surrounding.\n---         - Default behavior in 'mini.ai' selects one of the edges into `a`\n---           textobject, while 'mini.surround' - both.\n---\n--- # Highlight groups ~\n---\n--- - `MiniSurround` - highlighting of requested surrounding.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minisurround_disable` (globally) or\n--- `vim.b.minisurround_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniSurround\n\n--- This table describes all builtin surroundings along with what they\n--- represent. Explanation:\n--- - `Key` represents the surrounding identifier: single character which should\n---   be typed after action mappings (see \"Mappings\" in |MiniSurround.config|).\n--- - `Name` is a description of surrounding.\n--- - `Example line` contains a string for which examples are constructed. The\n---   `*` denotes the cursor position over `a` character.\n--- - `Delete` shows the result of typing `sd` followed by surrounding identifier.\n---   It aims to demonstrate \"input\" surrounding which is also used in replace\n---   with `sr` (surrounding id is typed first), highlight with `sh`, find with\n---   `sf` and `sF`.\n--- - `Replace` shows the result of typing `sr!` followed by surrounding\n---   identifier (with possible follow up from user). It aims to demonstrate\n---   \"output\" surrounding which is also used in adding with `sa` (followed by\n---   textobject/motion or in Visual mode).\n---\n--- Example: typing `sd)` with cursor on `*` (covers `a` character) changes line\n--- `!( *a (bb) )!` into `! aa (bb) !`. Typing `sr!)` changes same initial line\n--- into `(( aa (bb) ))`.\n--- >\n---  ┌───┬───────────────┬───────────────┬─────────────┬─────────────────┐\n---  │Key│     Name      │  Example line │    Delete   │     Replace     │\n---  ├───┴───────────────┴───────────────┴─────────────┴─────────────────┤\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ ( │  Balanced ()  │ !( *a (bb) )! │  !aa (bb)!  │ ( ( aa (bb) ) ) │\n---  │ [ │  Balanced []  │ ![ *a [bb] ]! │  !aa [bb]!  │ [ [ aa [bb] ] ] │\n---  │ { │  Balanced {}  │ !{ *a {bb} }! │  !aa {bb}!  │ { { aa {bb} } } │\n---  │ < │  Balanced <>  │ !< *a <bb> >! │  !aa <bb>!  │ < < aa <bb> > > │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ ) │  Balanced ()  │ !( *a (bb) )! │ ! aa (bb) ! │ (( aa (bb) ))   │\n---  │ ] │  Balanced []  │ ![ *a [bb] ]! │ ! aa [bb] ! │ [[ aa [bb] ]]   │\n---  │ } │  Balanced {}  │ !{ *a {bb} }! │ ! aa {bb} ! │ {{ aa {bb} }}   │\n---  │ > │  Balanced <>  │ !< *a <bb> >! │ ! aa <bb> ! │ << aa <bb> >>   │\n---  │ b │  Alias for    │ !( *a {bb} )! │ ! aa {bb} ! │ (( aa {bb} ))   │\n---  │   │  ), ], or }   │               │             │                 │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ q │  Alias for    │ !'aa'*a'aa'!  │ !'aaaaaa'!  │ \"'aa'aa'aa'\"    │\n---  │   │  \", ', or `   │               │             │                 │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ ? │  User prompt  │ !e * o!       │ ! a !       │ ee a oo         │\n---  │   │(typed e and o)│               │             │                 │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ t │      Tag      │ !<x>*</x>!    │ !a!         │ <y><x>a</x></y> │\n---  │   │               │               │             │ (typed y)       │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │ f │ Function call │ !f(*a, bb)!   │ !aa, bb!    │ g(f(*a, bb))    │\n---  │   │               │               │             │ (typed g)       │\n---  ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤\n---  │   │    Default    │ !_a*a_!       │ !aaa!       │ __aaa__         │\n---  │   │   (typed _)   │               │             │                 │\n---  └┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘\n--- <\n--- Notes:\n--- - All examples assume default `config.search_method`.\n--- - Open brackets differ from close brackets by how they treat inner edge\n---   whitespace: open includes it left and right parts, close does not.\n--- - Output value of `b` alias is same as `)`. For `q` alias - same as `\"`.\n--- - Default surrounding is activated for all characters which are not\n---   configured surrounding identifiers. Notes:\n---     - Due to special handling of underlying `x.-x` Lua pattern\n---       (see |MiniSurround-search-algorithm|), it doesn't really support\n---       non-trivial `[count]` for \"cover\" search method.\n---     - When cursor is exactly on the identifier character while there are\n---       two matching candidates on both left and right, the one resulting in\n---       region with smaller width is preferred.\n---@tag MiniSurround-builtin-surroundings\n\n--- Note: this is similar to |MiniAi-glossary|.\n---\n--- REGION ~\n--- Table representing region in a buffer. Fields: <from> and <to> for\n--- inclusive start and end positions (<to> might be `nil` to describe empty\n--- region). Each position is also a table with line <line> and column <col>\n--- (both start at 1). Examples: >lua\n---\n---   { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }\n---\n---   -- Empty region\n---   { from = { line = 10, col = 10 } }\n--- <\n--- REGION PAIR ~\n--- Table representing regions for left and right surroundings. Fields: <left>\n--- and <right> with regions. Example: >lua\n---\n---   {\n---     left  = { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } },\n---     right = { from = { line = 1, col = 3 } },\n---   }\n--- <\n--- PATTERN ~\n--- String describing Lua pattern.\n---\n--- SPAN ~\n--- Interval inside a string (end-exclusive). Like [1, 5). Equal `from` and `to` edges\n--- describe empty span at that point.\n---\n--- Span `A = [a1, a2)` covers `B = [b1, b2)` if every element of `B` is within\n--- `A` (`a1 <= b < a2`). It also is described as \"B is nested inside A\".\n---\n--- NESTED PATTERN ~\n--- Array of patterns aimed to describe nested spans.\n---\n--- SPAN MATCHES NESTED PATTERN ~\n--- If there is a sequence of consecutively nested spans each matching\n--- corresponding pattern within substring of previous span (or input string\n--- for first span). Example: >lua\n---\n---   -- Nested patterns for balanced `()` with inner space\n---   { '%b()', '^. .* .$' }\n---\n---   -- Example input string (with columns underneath for easier reading):\n---      \"( ( () ( ) ) )\"\n---   --  12345678901234\n--- <\n--- Here are all matching spans [1, 15) and [3, 13). Both [5, 7) and [8, 10)\n--- match first pattern but not second. All other combinations of `(` and `)`\n--- don't match first pattern (not balanced).\n---\n--- COMPOSED PATTERN ~\n--- Array with each element describing possible pattern (or array of them) at\n--- that place. Composed pattern basically defines all possible combinations of\n--- nested pattern (their cartesian product). Examples:\n---\n--- 1. Either balanced `()` or balanced `[]` but both with inner edge space: >lua\n---\n---     -- Composed pattern\n---     { { '%b()', '%b[]' }, '^. .* .$' }\n---\n---     -- Composed pattern expanded into equivalent array of nested patterns\n---     { '%b()', '^. .* .$' } -- and\n---     { '%b[]', '^. .* .$' }\n--- <\n--- 2. Either \"balanced `()` with inner edge space\" or \"balanced `[]` with no\n---    inner edge space\", both with 5 or more characters: >lua\n---\n---     -- Composed pattern\n---     { { { '%b()', '^. .* .$' }, { '%b[]', '^.[^ ].*[^ ].$' } }, '.....' }\n---\n---     -- Composed pattern expanded into equivalent array of nested patterns\n---     { '%b()', '^. .* .$', '.....' } -- and\n---     { '%b[]', '^.[^ ].*[^ ].$', '.....' }\n--- <\n--- SPAN MATCHES COMPOSED PATTERN ~\n--- If it matches at least one nested pattern from expanded composed pattern.\n---@tag MiniSurround-glossary\n\n--- Surround specification is a table with keys:\n--- - <input> - defines how to find and extract surrounding for \"input\"\n---   operations (like `delete`). See more in \"Input surrounding\" section.\n--- - <output> - defines what to add on left and right for \"output\" operations\n---   (like `add`). See more in \"Output surrounding\" section.\n---\n--- Example of surround info for builtin `)` identifier: >lua\n---\n---   {\n---     input = { '%b()', '^.().*().$' },\n---     output = { left = '(', right = ')' }\n---   }\n--- <\n--- # Input surrounding ~\n---\n--- Specification for input surrounding has a structure of composed pattern\n--- (see |MiniSurround-glossary|) with two differences:\n--- - Last pattern(s) should have two or four empty capture groups denoting\n---   how the last string should be processed to extract surrounding parts:\n---     - Two captures represent left part from start of string to first\n---       capture and right part - from second capture to end of string.\n---       Example: `a()b()c` defines left surrounding as 'a', right - 'c'.\n---     - Four captures define left part inside captures 1 and 2, right part -\n---       inside captures 3 and 4. Example: `a()()b()c()` defines left part as\n---       empty, right part as 'c'.\n--- - Allows callable objects (see |vim.is_callable()|) in certain places\n---   (enables more complex surroundings in exchange of increase in configuration\n---   complexity and computations):\n---     - If specification itself is a callable, it will be called without\n---       arguments and should return one of:\n---         - Composed pattern. Useful for implementing user input. Example of\n---           simplified variant of input surrounding for function call with\n---           name taken from user prompt: >lua\n---\n---             function()\n---               local left_edge = vim.pesc(vim.fn.input('Function name: '))\n---               return { left_edge .. '%b()', '^.-%(().*()%)$' }\n---             end\n--- <\n---         - Single region pair (see |MiniSurround-glossary|). Useful to allow\n---           full control over surrounding. Will be taken as is. Example of\n---           returning first and last lines of a buffer: >lua\n---\n---             function()\n---               local n_lines = vim.fn.line('$')\n---               return {\n---                 left = {\n---                   from = { line = 1, col = 1 },\n---                   to = { line = 1, col = vim.fn.getline(1):len() }\n---                 },\n---                 right = {\n---                   from = { line = n_lines, col = 1 },\n---                   to = { line = n_lines, col = vim.fn.getline(n_lines):len() }\n---                 },\n---               }\n---             end\n--- <\n---         - Array of region pairs. Useful for incorporating other instruments,\n---           like treesitter (see |MiniSurround.gen_spec.input.treesitter()|). The\n---           best region pair will be picked in the same manner as with composed\n---           pattern (respecting options `n_lines`, `search_method`, etc.) using\n---           output region (from start of left region to end of right region).\n---           Example using edges of \"best\" line with display width more than 80: >lua\n---\n---             function()\n---               local make_line_region_pair = function(n)\n---                 local left = { line = n, col = 1 }\n---                 local right = { line = n, col = vim.fn.getline(n):len() }\n---                 return {\n---                   left = { from = left, to = left },\n---                   right = { from = right, to = right },\n---                 }\n---               end\n---\n---               local res = {}\n---               for i = 1, vim.fn.line('$') do\n---                 if vim.fn.getline(i):len() > 80 then\n---                   table.insert(res, make_line_region_pair(i))\n---                 end\n---               end\n---               return res\n---             end\n--- <\n---     - If there is a callable instead of assumed string pattern, it is expected\n---       to have signature `(line, init)` and behave like `pattern:find()`.\n---       It should return two numbers representing span in `line` next after\n---       or at `init` (`nil` if there is no such span).\n---       !IMPORTANT NOTE!: it means that output's `from` shouldn't be strictly\n---       to the left of `init` (it will lead to infinite loop). Not allowed as\n---       last item (as it should be pattern with captures).\n---       Example of matching only balanced parenthesis with big enough width: >lua\n---\n---         {\n---           '%b()',\n---           function(s, init)\n---             if init > 1 or s:len() < 5 then return end\n---             return 1, s:len()\n---           end,\n---           '^.().*().$'\n---         }\n--- <\n--- More examples: >lua\n---\n---   -- Pair of balanced brackets from set (used for builtin `b` identifier)\n---   { { '%b()', '%b[]', '%b{}' }, '^.().*().$' }\n---\n---   -- Lua block string\n---   { '%[%[().-()%]%]' }\n--- <\n--- See |MiniSurround.gen_spec| for function wrappers to create commonly used\n--- surrounding specifications.\n---\n--- # Output surrounding ~\n---\n--- Specification for output can be either a table with <left> and <right> fields,\n--- or a callable returning such table (will be called with no arguments).\n--- Strings can contain new lines character \"\\n\" to add multiline parts.\n---\n--- Examples: >lua\n---\n---   -- Lua block string\n---   { left = '[[', right = ']]' }\n---\n---   -- Brackets on separate lines (indentation is not preserved)\n---   { left = '(\\n', right = '\\n)' }\n---\n---   -- Function call\n---   function()\n---     local function_name = MiniSurround.user_input('Function name')\n---     return { left = function_name .. '(', right = ')' }\n---   end\n--- <\n---@tag MiniSurround-surrounding-specification\n\n--- |[count]| is supported by all actions in the following ways:\n---\n--- - In add, two types of `[count]` is supported in Normal mode:\n---   `[count1]sa[count2][textobject]`. The `[count1]` defines how many times\n---   left and right parts of output surrounding will be repeated and `[count2]` is\n---   used for textobject.\n---   In Visual mode `[count]` is treated as `[count1]`.\n---   Example: `2sa3aw)` and `v3aw2sa)` will result into textobject `3aw` being\n---   surrounded by `((` and `))`.\n---\n--- - In delete/replace/find/highlight `[count]` means \"find n-th surrounding\n---   and execute operator on it\".\n---   Example: `2sd)` on line `(a(b(c)b)a)` with cursor on `c` will result into\n---   `(ab(c)ba)` (and not in `(abcba)` if it would have meant \"delete n times\").\n---@tag MiniSurround-count-with-actions\n\n--- Search for the input surrounding relies on these principles:\n--- - Input surrounding specification is constructed based on surrounding\n---   identifier (see |MiniSurround-surrounding-specification|).\n--- - General search is done by converting some 2d buffer region (neighborhood\n---   of reference region) into 1d string (each line is appended with `\\n`).\n---   Then search for a best span matching specification is done inside string\n---   (see |MiniSurround-glossary|). After that, span is converted back into 2d\n---   region. Note: first search is done inside reference region lines, and\n---   only after that - inside its neighborhood within `config.n_lines` (see\n---   |MiniSurround.config|).\n--- - The best matching span is chosen by iterating over all spans matching\n---   surrounding specification and comparing them with \"current best\".\n---   Comparison also depends on reference region (tighter covering is better,\n---   otherwise closer is better) and search method (if span is even considered).\n--- - Extract pair of spans (for left and right regions in region pair) based\n---   on extraction pattern (last item in nested pattern).\n--- - For |[count]| greater than 1, steps are repeated with current best match\n---   becoming reference region. One such additional step is also done if final\n---   region is equal to reference region.\n---\n--- Notes:\n--- - Iteration over all matched spans is done in depth-first fashion with\n---   respect to nested pattern.\n--- - It is guaranteed that span is compared only once.\n--- - For the sake of increasing functionality, during iteration over all\n---   matching spans, some Lua patterns in composed pattern are handled\n---   specially.\n---     - `%bxx` (`xx` is two identical characters). It denotes balanced pair\n---       of identical characters and results into \"paired\" matches. For\n---       example, `%b\"\"` for `\"aa\" \"bb\"` would match `\"aa\"` and `\"bb\"`, but\n---       not middle `\" \"`.\n---     - `x.-y` (`x` and `y` are different strings). It results only in matches with\n---       smallest width. For example, `e.-o` for `e e o o` will result only in\n---       middle `e o`. Note: it has some implications for when parts have\n---       quantifiers (like `+`, etc.), which usually can be resolved with\n---       frontier pattern `%f[]`.\n---@tag MiniSurround-search-algorithm\n\n-- Module definition ==========================================================\nlocal MiniSurround = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniSurround.config|.\n---\n---@usage >lua\n---   require('mini.surround').setup() -- use default config\n---   -- OR\n---   require('mini.surround').setup({}) -- replace {} with your config table\n--- <\nMiniSurround.setup = function(config)\n  -- Export module\n  _G.MiniSurround = MiniSurround\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Mappings ~\n---\n--- `config.mappings` defines what mappings are set up for particular actions.\n--- By default it uses \"prefix style\" left hand side starting with \"s\" (for\n--- \"surround\"): `sa` - \"surround add\", `sd` - \"surround delete\", etc.\n---\n--- Note: if any of the mappings start with \"s\" (as is by default), it is mapped\n--- to |<Nop>| to prevent accidental trigger of built-in |s| (can happen if there\n--- is a long enough delay between pressing \"s\" and the next key). Use `cl` instead.\n---\n--- # Custom surroundings ~\n---\n--- User can define own surroundings by supplying `config.custom_surroundings`.\n--- It should be a **table** with keys being single character surrounding\n--- identifier (supported by |getcharstr()|) and values - surround specification\n--- (see |MiniSurround-surrounding-specification|).\n---\n--- General recommendations:\n--- - In `config.custom_surroundings` only some data can be defined (like only\n---   `output`). Other fields will be taken from builtin surroundings.\n--- - Function returning surround info at <input> or <output> fields of\n---   specification is helpful when user input is needed (like asking for\n---   function name). Use |input()| or |MiniSurround.user_input()|. Return\n---   `nil` to stop any current surround operation.\n--- - Keys should use character representation which can be |getcharstr()| output.\n---   For example, `'\\r'` and not `'<CR>'`.\n---\n--- Examples of using `config.custom_surroundings` (see more examples at\n--- |MiniSurround.gen_spec|): >lua\n---\n---   local surround = require('mini.surround')\n---   surround.setup({\n---     custom_surroundings = {\n---       -- Make `)` insert parts with spaces. `input` pattern stays the same.\n---       [')'] = { output = { left = '( ', right = ' )' } },\n---\n---       -- Use function to compute surrounding info\n---       ['*'] = {\n---         input = function()\n---           local n_star = MiniSurround.user_input('Number of * to find')\n---           local many_star = string.rep('%*', tonumber(n_star) or 1)\n---           return { many_star .. '().-()' .. many_star }\n---         end,\n---         output = function()\n---           local n_star = MiniSurround.user_input('Number of * to output')\n---           local many_star = string.rep('*', tonumber(n_star) or 1)\n---           return { left = many_star, right = many_star }\n---         end,\n---       },\n---     },\n---   })\n---\n---   -- Create custom surrounding for Lua's block string `[[...]]`\n---   -- Use this inside autocommand or 'after/ftplugin/lua.lua' file\n---   vim.b.minisurround_config = {\n---     custom_surroundings = {\n---       s = {\n---         input = { '%[%[().-()%]%]' },\n---         output = { left = '[[', right = ']]' },\n---       },\n---     },\n---   }\n--- <\n--- # Respect selection type ~\n---\n--- Boolean option `config.respect_selection_type` controls whether to respect\n--- selection type when adding and deleting surrounding. When enabled:\n--- - Linewise adding places surroundings on separate lines while indenting\n---   surrounded lines ones.\n--- - Deleting surroundings which look like they were the result of linewise\n---   adding will act to revert it: delete lines with surroundings and dedent\n---   surrounded lines ones.\n--- - Blockwise adding places surroundings on whole edges, not only start and\n---   end of selection. Note: it doesn't really work outside of text and in\n---   presence of multibyte characters; and probably won't due to\n---   implementation difficulties.\n---\n--- # Search method ~\n---\n--- Value of `config.search_method` defines how best match search is done.\n--- Based on its value, one of the following matches will be selected:\n--- - Covering match. Left/right edge is before/after left/right edge of\n---   reference region.\n--- - Previous match. Left/right edge is before left/right edge of reference\n---   region.\n--- - Next match. Left/right edge is after left/right edge of reference region.\n--- - Nearest match. Whichever is closest among previous and next matches.\n---\n--- Possible values are:\n--- - `'cover'` (default) - use only covering match. Don't use either previous or\n---   next; report that there is no surrounding found.\n--- - `'cover_or_next'` - use covering match. If not found, use next.\n--- - `'cover_or_prev'` - use covering match. If not found, use previous.\n--- - `'cover_or_nearest'` - use covering match. If not found, use nearest.\n--- - `'next'` - use next match.\n--- - `'previous'` - use previous match.\n--- - `'nearest'` - use nearest match.\n---\n--- Note: search is first performed on the reference region lines and only\n--- after failure - on the whole neighborhood defined by `config.n_lines`. This\n--- means that with `config.search_method` not equal to `'cover'`, \"previous\"\n--- or \"next\" surrounding will end up as search result if they are found on\n--- first stage although covering match might be found in bigger, whole\n--- neighborhood. This design is based on observation that most of the time\n--- operation is done within reference region lines (usually cursor line).\n---\n--- Here is an example of how replacing `)` with `]` surrounding is done based\n--- on a value of `'config.search_method'` when cursor is inside `bbb` word:\n--- - `'cover'`:         `(a) bbb (c)` -> `(a) bbb (c)` (with message)\n--- - `'cover_or_next'`: `(a) bbb (c)` -> `(a) bbb [c]`\n--- - `'cover_or_prev'`: `(a) bbb (c)` -> `[a] bbb (c)`\n--- - `'cover_or_nearest'`: depends on cursor position.\n---   For first and second `b` - as in `cover_or_prev` (as previous match is\n---   nearer), for third - as in `cover_or_next` (as next match is nearer).\n--- - `'next'`:          `(a) bbb (c)` -> `(a) bbb [c]`. Same outcome for `(bbb)`.\n--- - `'prev'`:          `(a) bbb (c)` -> `[a] bbb (c)`. Same outcome for `(bbb)`.\n--- - `'nearest'`: depends on cursor position (same as in `'cover_or_nearest'`).\n---\n--- # Search suffixes ~\n---\n--- To provide more searching possibilities, 'mini.surround' creates extended\n--- mappings force \"prev\" and \"next\" methods for particular search. It does so\n--- by appending mapping with certain suffix: `config.mappings.suffix_last` for\n--- mappings which will use \"prev\" search method, `config.mappings.suffix_next`\n--- - \"next\" search method.\n---\n--- Notes:\n--- - It creates new mappings only for actions involving surrounding search:\n---   delete, replace, find (right and left), highlight.\n--- - All new mappings behave the same way as if `config.search_method` is set\n---   to certain search method. They preserve dot-repeat support, respect |[count]|.\n--- - Supply empty string to disable creation of corresponding set of mappings.\n---\n--- Example with default values (`n` for `suffix_next`, `l` for `suffix_last`)\n--- and initial line `(aa) (bb) (cc)`.\n--- - Typing `sdn)` with cursor inside `(aa)` results into `(aa) bb (cc)`.\n--- - Typing `sdl)` with cursor inside `(cc)` results into `(aa) bb (cc)`.\n--- - Typing `2srn)]` with cursor inside `(aa)` results into `(aa) (bb) [cc]`.\n---\n--- # Setup similar to 'tpope/vim-surround' ~\n--- *MiniSurround-vim-surround-config*\n---\n--- This module is primarily designed after 'machakann/vim-sandwich'. To get\n--- behavior closest to 'tpope/vim-surround' (but not identical), use this setup: >lua\n---\n---   require('mini.surround').setup({\n---     mappings = {\n---       add = 'ys',\n---       delete = 'ds',\n---       find = '',\n---       find_left = '',\n---       highlight = '',\n---       replace = 'cs',\n---\n---       -- Add this only if you don't want to use extended mappings\n---       suffix_last = '',\n---       suffix_next = '',\n---     },\n---     search_method = 'cover_or_next',\n---   })\n---\n---   -- Remap adding surrounding to Visual mode selection\n---   vim.keymap.del('x', 'ys')\n---   vim.keymap.set('x', 'S', [[:<C-u>lua MiniSurround.add('visual')<CR>]], { silent = true })\n---\n---   -- Make special mapping for \"add surrounding for line\"\n---   vim.keymap.set('n', 'yss', 'ys_', { remap = true })\n--- <\nMiniSurround.config = {\n  -- Add custom surroundings to be used on top of builtin ones. For more\n  -- information with examples, see `:h MiniSurround.config`.\n  custom_surroundings = nil,\n\n  -- Duration (in ms) of highlight when calling `MiniSurround.highlight()`\n  highlight_duration = 500,\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    add = 'sa', -- Add surrounding in Normal and Visual modes\n    delete = 'sd', -- Delete surrounding\n    find = 'sf', -- Find surrounding (to the right)\n    find_left = 'sF', -- Find surrounding (to the left)\n    highlight = 'sh', -- Highlight surrounding\n    replace = 'sr', -- Replace surrounding\n\n    suffix_last = 'l', -- Suffix to search with \"prev\" method\n    suffix_next = 'n', -- Suffix to search with \"next\" method\n  },\n\n  -- Number of lines within which surrounding is searched\n  n_lines = 20,\n\n  -- Whether to respect selection type:\n  -- - Place surroundings on separate lines in linewise mode.\n  -- - Place surroundings on each line in blockwise mode.\n  respect_selection_type = false,\n\n  -- How to search for surrounding (first inside current line, then inside\n  -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev',\n  -- 'cover_or_nearest', 'next', 'prev', 'nearest'. For more details,\n  -- see `:h MiniSurround.config`.\n  search_method = 'cover',\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Add surrounding\n---\n--- No need to use it directly, everything is setup in |MiniSurround.setup()|.\n---\n---@param mode string Mapping mode (normal by default).\nMiniSurround.add = function(mode)\n  -- Needed to disable in visual mode\n  if H.is_disabled() then return '<Esc>' end\n\n  -- Get marks' positions based on current mode\n  local marks = H.get_marks_pos(mode)\n\n  -- Get surround info. Try take from cache only in not visual mode (as there\n  -- is no intended dot-repeatability).\n  local surr_info\n  if mode == 'visual' then\n    surr_info = H.get_surround_spec('output', false)\n  else\n    surr_info = H.get_surround_spec('output', true)\n  end\n  if surr_info == nil then return '<Esc>' end\n\n  -- Extend parts based on provided `[count]` before operator (if this is not\n  -- from dot-repeat and was done already)\n  if not surr_info.did_count then\n    local count = H.cache.count or vim.v.count1\n    surr_info.left, surr_info.right = surr_info.left:rep(count), surr_info.right:rep(count)\n    surr_info.did_count = true\n  end\n\n  -- Add surrounding.\n  -- Possibly deal with linewise and blockwise addition separately\n  local respect_selection_type = H.get_config().respect_selection_type\n\n  if not respect_selection_type or marks.selection_type == 'charwise' then\n    -- Begin insert from right to not break column numbers\n    -- Insert after the right mark (`+ 1` is for that)\n    H.region_replace({ from = { line = marks.second.line, col = marks.second.col + 1 } }, surr_info.right)\n    H.region_replace({ from = marks.first }, surr_info.left)\n\n    -- Set cursor to be on the right of left surrounding\n    H.set_cursor(marks.first.line, marks.first.col + surr_info.left:len())\n\n    return\n  end\n\n  if marks.selection_type == 'linewise' then\n    local from_line, to_line = marks.first.line, marks.second.line\n\n    -- Save current range indent and indent surrounded lines\n    local init_indent = H.get_range_indent(from_line, to_line)\n    H.shift_indent('>', from_line, to_line)\n\n    -- Put cursor on the start of first surrounded line\n    H.set_cursor_nonblank(from_line)\n\n    -- Put surroundings on separate lines\n    vim.fn.append(to_line, init_indent .. surr_info.right)\n    vim.fn.append(from_line - 1, init_indent .. surr_info.left)\n\n    return\n  end\n\n  if marks.selection_type == 'blockwise' then\n    -- NOTE: this doesn't work with mix of multibyte and normal characters, as\n    -- well as outside of text lines.\n    local from_col, to_col = marks.first.col, marks.second.col\n    -- - Ensure that `to_col` is to the right of `from_col`. Can be not the\n    --   case if visual block was selected from \"south-west\" to \"north-east\".\n    from_col, to_col = math.min(from_col, to_col), math.max(from_col, to_col)\n\n    for i = marks.first.line, marks.second.line do\n      H.region_replace({ from = { line = i, col = to_col + 1 } }, surr_info.right)\n      H.region_replace({ from = { line = i, col = from_col } }, surr_info.left)\n    end\n\n    H.set_cursor(marks.first.line, from_col + surr_info.left:len())\n\n    return\n  end\nend\n\n--- Delete surrounding\n---\n--- No need to use it directly, everything is setup in |MiniSurround.setup()|.\nMiniSurround.delete = function()\n  -- Find input surrounding region\n  local surr = H.find_surrounding(H.get_surround_spec('input', true))\n  if surr == nil then return '<Esc>' end\n\n  -- Delete surrounding region. Begin with right to not break column numbers.\n  H.region_replace(surr.right, {})\n  H.region_replace(surr.left, {})\n\n  -- Set cursor to be on the right of deleted left surrounding\n  local from = surr.left.from\n  H.set_cursor(from.line, from.col)\n\n  -- Possibly tweak deletion of linewise surrounding. Should act as reverse to\n  -- linewise addition.\n  if not H.get_config().respect_selection_type then return end\n\n  local from_line, to_line = surr.left.from.line, surr.right.from.line\n  local is_linewise_delete = from_line < to_line and H.is_line_blank(from_line) and H.is_line_blank(to_line)\n  if is_linewise_delete then\n    -- Dedent surrounded lines\n    H.shift_indent('<', from_line, to_line)\n\n    -- Place cursor on first surrounded line\n    H.set_cursor_nonblank(from_line + 1)\n\n    -- Delete blank lines left after deleting surroundings\n    local buf_id = vim.api.nvim_get_current_buf()\n    vim.fn.deletebufline(buf_id, to_line)\n    vim.fn.deletebufline(buf_id, from_line)\n  end\nend\n\n--- Replace surrounding\n---\n--- No need to use it directly, everything is setup in |MiniSurround.setup()|.\nMiniSurround.replace = function()\n  -- Find input surrounding region\n  local surr = H.find_surrounding(H.get_surround_spec('input', true))\n  if surr == nil then return '<Esc>' end\n\n  -- Get output surround info\n  local new_surr_info = H.get_surround_spec('output', true)\n  if new_surr_info == nil then return '<Esc>' end\n\n  -- Replace by parts starting from right to not break column numbers\n  H.region_replace(surr.right, new_surr_info.right)\n  H.region_replace(surr.left, new_surr_info.left)\n\n  -- Set cursor to be on the right of left surrounding\n  local from = surr.left.from\n  H.set_cursor(from.line, from.col + new_surr_info.left:len())\nend\n\n--- Find surrounding\n---\n--- No need to use it directly, everything is setup in |MiniSurround.setup()|.\nMiniSurround.find = function()\n  -- Find surrounding region\n  local surr = H.find_surrounding(H.get_surround_spec('input', true))\n  if surr == nil then return end\n\n  -- Make array of unique positions to cycle through\n  local pos_array = H.surr_to_pos_array(surr)\n\n  -- Cycle cursor through positions\n  local dir = H.cache.direction or 'right'\n  H.cursor_cycle(pos_array, dir)\n\n  -- Open 'enough folds' to show cursor\n  vim.cmd('normal! zv')\nend\n\n--- Highlight surrounding\n---\n--- No need to use it directly, everything is setup in |MiniSurround.setup()|.\nMiniSurround.highlight = function()\n  -- Find surrounding region\n  local surr = H.find_surrounding(H.get_surround_spec('input', true))\n  if surr == nil then return end\n\n  -- Highlight surrounding region\n  local config = H.get_config()\n  local buf_id = vim.api.nvim_get_current_buf()\n\n  H.region_highlight(buf_id, surr.left)\n  H.region_highlight(buf_id, surr.right)\n\n  vim.defer_fn(function()\n    H.region_unhighlight(buf_id, surr.left)\n    H.region_unhighlight(buf_id, surr.right)\n  end, config.highlight_duration)\nend\n\n--- Update `MiniSurround.config.n_lines` from user input\n---\n--- Mapping example: >lua\n---\n---   vim.keymap.set('n', 'sn', '<Cmd>lua MiniSurround.update_n_lines()<CR>')\n--- <\nMiniSurround.update_n_lines = function()\n  local n_lines = MiniSurround.user_input('New number of neighbor lines', MiniSurround.config.n_lines)\n  MiniSurround.config.n_lines = math.floor(tonumber(n_lines) or MiniSurround.config.n_lines)\nend\n\n--- Ask user for input\n---\n--- This is mainly a wrapper for |input()| which allows empty string as input,\n--- cancelling with `<Esc>` and `<C-c>`, and slightly modifies prompt. Use it\n--- to ask for input inside function custom surrounding (see |MiniSurround.config|).\nMiniSurround.user_input = function(prompt, text)\n  -- Major issue with both `vim.fn.input()` is that the only way to distinguish\n  -- cancelling with `<Esc>` and entering empty string with immediate `<CR>` is\n  -- through `cancelreturn` option (see `:h input()`). In that case the return\n  -- of `cancelreturn` will mean actual cancel, which removes possibility of\n  -- using that string. Although doable with very obscure string, this is not\n  -- very clean.\n  -- Overcome this by adding temporary keystroke listener.\n  local was_cancelled = false\n  vim.on_key(function(key) was_cancelled = was_cancelled or key == '\\27' end, H.ns_id.input)\n\n  -- Ask for input. Use `pcall` to allow `<C-c>` to cancel user input\n  -- NOTE: it would be GREAT to make this work with `vim.ui.input()` but I\n  -- didn't find a way to make it work without major refactor of whole module.\n  -- The main issue is that `vim.ui.input()` is designed to perform action in\n  -- callback and current module design is to get output immediately. Although\n  -- naive approach of\n  -- `local res; vim.ui.input({...}, function(input) res = input end)`\n  -- works in default `vim.ui.input`, its reimplementations can return from it\n  -- immediately and proceed in main event loop. Couldn't find a relatively\n  -- simple way to stop execution of this current function until `ui.input()`'s\n  -- callback finished execution.\n  vim.cmd('echohl Question')\n  local ok, res = pcall(vim.fn.input, { prompt = '(mini.surround) ' .. prompt .. ': ', default = text or '' })\n  vim.cmd('echohl None | echo \"\" | redraw')\n\n  vim.on_key(nil, H.ns_id.input)\n  return (ok and not was_cancelled) and res or nil\nend\n\n--- Generate common surrounding specifications\n---\n--- This is a table with two sets of generator functions: <input> and <output>\n--- (currently empty). Each is a table with function values generating\n--- corresponding surrounding specification.\n---\n---@seealso |MiniAi.gen_spec|\nMiniSurround.gen_spec = { input = {}, output = {} }\n\n--- Treesitter specification for input surrounding\n---\n--- This is a specification in function form. When called with a pair of\n--- treesitter captures, it returns a specification function outputting an\n--- array of region pairs derived from <outer> and <inner> captures. It first\n--- searches for all matched nodes of outer capture and then completes each one\n--- with the biggest match of inner capture inside that node (if any). The result\n--- region pair is a difference between regions of outer and inner captures.\n---\n--- In order for this to work, apart from working treesitter parser for desired\n--- language, user should have a reachable language-specific 'textobjects'\n--- query (see |vim.treesitter.query.get()|).\n--- The most straightforward way for this is to have 'textobjects.scm' query\n--- file with treesitter captures stored in some recognized path. This is\n--- primarily designed to be compatible with plugin\n--- 'nvim-treesitter/nvim-treesitter-textobjects', but can be used without it.\n---\n--- Two most common approaches for having a query file:\n--- - Install 'nvim-treesitter/nvim-treesitter-textobjects'. It has curated and\n---   well maintained builtin query files for many languages with a standardized\n---   capture names, like `call.outer`, `call.inner`, etc.\n--- - Manually create file 'after/queries/<language name>/textobjects.scm' in\n---   your |$XDG_CONFIG_HOME| directory. It should contain queries with\n---   captures (later used to define surrounding parts). See |lua-treesitter-query|.\n--- To verify that query file is reachable, run (example for \"lua\" language,\n--- output should have at least an intended file): >vim\n---\n---   :lua print(vim.inspect(vim.treesitter.query.get_files('lua','textobjects')))\n--- <\n--- Example configuration for function definition textobject with\n--- 'nvim-treesitter/nvim-treesitter-textobjects' captures: >lua\n---\n---   local ts_input = require('mini.surround').gen_spec.input.treesitter\n---   require('mini.surround').setup({\n---     custom_surroundings = {\n---       -- Use tree-sitter to search for function call\n---       f = {\n---         input = ts_input({ outer = '@call.outer', inner = '@call.inner' })\n---       },\n---     }\n---   })\n--- <\n--- Notes:\n--- - Be sure that query files don't contain unknown |treesitter-directives|\n---   (like `#make-range!`, for example). Otherwise surrounding with such captures\n---   might not be found as |lua-treesitter-core| won't treat them as captures.\n---   Verify with `:=vim.treesitter.query.get('lang', 'textobjects')` and see\n---   if the target capture is recognized as one.\n--- - It uses buffer's |filetype| to determine query language.\n--- - On large files it is slower than pattern-based textobjects. Still very\n---   fast though (one search should be magnitude of milliseconds or tens of\n---   milliseconds on really large file).\n---\n---@param captures table Captures for outer and inner parts of region pair:\n---   table with <outer> and <inner> fields with captures for outer\n---   (`[left.form; right.to]`) and inner (`(left.to; right.from)` both edges\n---   exclusive, i.e. they won't be a part of surrounding) regions. Each value\n---   should be a string capture starting with `'@'`.\n---@param opts table|nil Options. Possible values:\n---   - <use_nvim_treesitter> - whether to try to use 'nvim-treesitter' plugin\n---     (if present) to do the query. It used to implement more advanced behavior\n---     and more coherent experience if 'nvim-treesitter-textobjects' queries are\n---     used. However, as |lua-treesitter-core| methods are more capable now,\n---     the option will soon be removed. Only present for backward compatibility.\n---     Default: `false`.\n---\n---@return function Function which returns array of current buffer region pairs\n---   representing differences between outer and inner captures.\n---\n---@seealso - |MiniSurround-surrounding-specification| for how this type of\n---   surrounding specification is processed.\n--- - |vim.treesitter.query.get()| for how query is fetched.\n--- - |Query:iter_captures()| for how all query captures are iterated in case of\n---   no 'nvim-treesitter'.\n--- - |MiniAi.gen_spec.treesitter()| for similar 'mini.ai' generator.\nMiniSurround.gen_spec.input.treesitter = function(captures, opts)\n  -- TODO: Remove after releasing 'mini.nvim' 0.17.0\n  opts = vim.tbl_deep_extend('force', { use_nvim_treesitter = false }, opts or {})\n  captures = H.prepare_captures(captures)\n\n  -- Tree-sitter ranges are 0-based, end-exclusive, and usually\n  -- `row1-col1-byte1-row2-col2-byte2` (i.e. \"range six\") format.\n  local ts_range_to_region = function(r)\n    -- The `master` branch of 'nvim-treesitter' can return \"range four\" format\n    -- if it uses custom directives, like `#make-range!`. Due to the fact that\n    -- it doesn't fully mock the `TSNode:range()` method to return \"range six\".\n    -- TODO: Remove after 'nvim-treesitter' `master` branch support is dropped.\n    local offset = #r == 4 and -1 or 0\n    local res = { from = { line = r[1] + 1, col = r[2] + 1 }, to = { line = r[4 + offset] + 1, col = r[5 + offset] } }\n\n    -- NOTE: Adjust \"row-exclusive, col-0\" range that means \"all previous row\n    -- including the newline character\"\n    if res.to.col == 0 then\n      res.to.line = res.to.line - 1\n      res.to.col = vim.fn.col({ res.to.line, '$' })\n    end\n\n    return res\n  end\n\n  return function()\n    local has_nvim_treesitter = pcall(require, 'nvim-treesitter') and pcall(require, 'nvim-treesitter.query')\n    local range_pair_querier = (has_nvim_treesitter and opts.use_nvim_treesitter) and H.get_matched_range_pairs_plugin\n      or H.get_matched_range_pairs_builtin\n    local matched_range_pairs = range_pair_querier(captures)\n\n    -- Return array of region pairs\n    return vim.tbl_map(function(range_pair)\n      local outer_region = ts_range_to_region(range_pair.outer)\n      local left_from, right_to = outer_region.from, outer_region.to\n\n      local left_to, right_from\n      if range_pair.inner == nil then\n        left_to = right_to\n        right_from = H.pos_to_right(right_to)\n        right_to = nil\n      else\n        local inner_region = ts_range_to_region(range_pair.inner)\n        left_to, right_from = inner_region.from, inner_region.to\n        -- Take into account that inner capture should be both edges exclusive\n        left_to, right_from = H.pos_to_left(left_to), H.pos_to_right(right_from)\n      end\n\n      return { left = { from = left_from, to = left_to }, right = { from = right_from, to = right_to } }\n    end, matched_range_pairs)\n  end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniSurround.config)\n\n-- Namespaces to be used within module\nH.ns_id = {\n  highlight = vim.api.nvim_create_namespace('MiniSurroundHighlight'),\n  input = vim.api.nvim_create_namespace('MiniSurroundInput'),\n}\n\n--stylua: ignore\n-- Builtin surroundings\nH.builtin_surroundings = {\n  -- Use balanced pair for brackets. Use opening ones to possibly\n  -- replace/delete innder edge whitespace.\n  ['('] = { input = { '%b()', '^.%s*().-()%s*.$' }, output = { left = '( ', right = ' )' } },\n  [')'] = { input = { '%b()', '^.().*().$' },       output = { left = '(',  right = ')' } },\n  ['['] = { input = { '%b[]', '^.%s*().-()%s*.$' }, output = { left = '[ ', right = ' ]' } },\n  [']'] = { input = { '%b[]', '^.().*().$' },       output = { left = '[',  right = ']' } },\n  ['{'] = { input = { '%b{}', '^.%s*().-()%s*.$' }, output = { left = '{ ', right = ' }' } },\n  ['}'] = { input = { '%b{}', '^.().*().$' },       output = { left = '{',  right = '}' } },\n  ['<'] = { input = { '%b<>', '^.%s*().-()%s*.$' }, output = { left = '< ', right = ' >' } },\n  ['>'] = { input = { '%b<>', '^.().*().$' },       output = { left = '<',  right = '>' } },\n  -- Derived from user prompt\n  ['?'] = {\n    input = function()\n      local left = MiniSurround.user_input('Left surrounding')\n      if left == nil or left == '' then return end\n      local right = MiniSurround.user_input('Right surrounding')\n      if right == nil or right == '' then return end\n\n      return { vim.pesc(left) .. '().-()' .. vim.pesc(right) }\n    end,\n    output = function()\n      local left = MiniSurround.user_input('Left surrounding')\n      if left == nil then return end\n      local right = MiniSurround.user_input('Right surrounding')\n      if right == nil then return end\n      return { left = left, right = right }\n    end,\n  },\n  -- Brackets\n  ['b'] = { input = { { '%b()', '%b[]', '%b{}' }, '^.().*().$' }, output = { left = '(', right = ')' } },\n  -- Function call\n  ['f'] = {\n    input = { '%f[%w_%.][%w_%.]+%b()', '^.-%(().*()%)$' },\n    output = function()\n      local fun_name = MiniSurround.user_input('Function name')\n      if fun_name == nil then return nil end\n      return { left = ('%s('):format(fun_name), right = ')' }\n    end,\n  },\n  -- Tag\n  ['t'] = {\n    input = { '<(%w-)%f[^<%w][^<>]->.-</%1>', '^<.->().*()</[^/]->$' },\n    output = function()\n      local tag_full = MiniSurround.user_input('Tag')\n      if tag_full == nil then return nil end\n      local tag_name = tag_full:match('^%S*')\n      return { left = '<' .. tag_full .. '>', right = '</' .. tag_name .. '>' }\n    end,\n  },\n  -- Quotes\n  ['q'] = { input = { { \"'.-'\", '\".-\"', '`.-`' }, '^.().*().$' }, output = { left = '\"', right = '\"' } },\n}\n\n-- Cache for dot-repeatability. This table is currently used with these keys:\n-- - 'input' - surround info for searching (in 'delete' and 'replace' start).\n-- - 'output' - surround info for adding (in 'add' and 'replace' end).\n-- - 'direction' - direction in which `MiniSurround.find()` should go.\n--   Currently is not used for dot-repeat, but for easier mappings.\n-- - 'search_method' - search method.\n-- - 'msg_shown' - whether helper message was shown.\nH.cache = {}\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('custom_surroundings', config.custom_surroundings, 'table', true)\n  H.check_type('highlight_duration', config.highlight_duration, 'number')\n  H.check_type('mappings', config.mappings, 'table')\n  H.check_type('n_lines', config.n_lines, 'number')\n  H.check_type('respect_selection_type', config.respect_selection_type, 'boolean')\n  H.validate_search_method(config.search_method)\n  H.check_type('silent', config.silent, 'boolean')\n\n  H.check_type('mappings.add', config.mappings.add, 'string')\n  H.check_type('mappings.delete', config.mappings.delete, 'string')\n  H.check_type('mappings.find', config.mappings.find, 'string')\n  H.check_type('mappings.find_left', config.mappings.find_left, 'string')\n  H.check_type('mappings.highlight', config.mappings.highlight, 'string')\n  H.check_type('mappings.replace', config.mappings.replace, 'string')\n\n  H.check_type('mappings.suffix_last', config.mappings.suffix_last, 'string')\n  H.check_type('mappings.suffix_next', config.mappings.suffix_next, 'string')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniSurround.config = config\n\n  local maps, maps_l, maps_n = config.mappings, {}, {}\n  local suf_l, suf_n = maps.suffix_last, maps.suffix_next\n  for k, v in pairs(maps) do\n    -- Don't create extended mapping if user chose not to create a regular one\n    maps_l[k] = (v ~= '' and suf_l ~= '') and (v .. suf_l) or ''\n    maps_n[k] = (v ~= '' and suf_n ~= '') and (v .. suf_n) or ''\n  end\n\n  local m = function(mode, lhs, rhs, desc) H.map(mode, lhs, rhs, { expr = true, desc = desc }) end\n\n  --stylua: ignore start\n  m('n', maps.add, H.make_operator('add', nil, true), 'Add surrounding')\n  H.map('x', maps.add, ':<C-u>lua MiniSurround.add(\"visual\")<CR>', { desc = 'Add surrounding to selection' })\n\n  m('n', maps.delete,   H.make_operator('delete', nil),    'Delete surrounding')\n  m('n', maps_l.delete, H.make_operator('delete', 'prev'), 'Delete previous surrounding')\n  m('n', maps_n.delete, H.make_operator('delete', 'next'), 'Delete next surrounding')\n\n  m('n', maps.replace,   H.make_operator('replace', nil),    'Replace surrounding')\n  m('n', maps_l.replace, H.make_operator('replace', 'prev'), 'Replace previous surrounding')\n  m('n', maps_n.replace, H.make_operator('replace', 'next'), 'Replace next surrounding')\n\n  m('n', maps.find,   H.make_action('find', 'right', nil),    'Find right surrounding')\n  m('x', maps.find,   H.make_action('find', 'right', nil),    'Find right surrounding')\n  m('o', maps.find,   H.make_action('find', 'right', nil),    'Find right surrounding')\n  m('n', maps_l.find, H.make_action('find', 'right', 'prev'), 'Find previous right surrounding')\n  m('x', maps_l.find, H.make_action('find', 'right', 'prev'), 'Find previous right surrounding')\n  m('o', maps_l.find, H.make_action('find', 'right', 'prev'), 'Find previous right surrounding')\n  m('n', maps_n.find, H.make_action('find', 'right', 'next'), 'Find next right surrounding')\n  m('x', maps_n.find, H.make_action('find', 'right', 'next'), 'Find next right surrounding')\n  m('o', maps_n.find, H.make_action('find', 'right', 'next'), 'Find next right surrounding')\n\n  m('n', maps.find_left,   H.make_action('find', 'left', nil),    'Find left surrounding')\n  m('x', maps.find_left,   H.make_action('find', 'left', nil),    'Find left surrounding')\n  m('o', maps.find_left,   H.make_action('find', 'left', nil),    'Find left surrounding')\n  m('n', maps_l.find_left, H.make_action('find', 'left', 'prev'), 'Find previous left surrounding')\n  m('x', maps_l.find_left, H.make_action('find', 'left', 'prev'), 'Find previous left surrounding')\n  m('o', maps_l.find_left, H.make_action('find', 'left', 'prev'), 'Find previous left surrounding')\n  m('n', maps_n.find_left, H.make_action('find', 'left', 'next'), 'Find next left surrounding')\n  m('x', maps_n.find_left, H.make_action('find', 'left', 'next'), 'Find next left surrounding')\n  m('o', maps_n.find_left, H.make_action('find', 'left', 'next'), 'Find next left surrounding')\n\n  m('n', maps.highlight,   H.make_action('highlight', nil, nil),    'Highlight surrounding')\n  m('n', maps_l.highlight, H.make_action('highlight', nil, 'prev'), 'Highlight previous surrounding')\n  m('n', maps_n.highlight, H.make_action('highlight', nil, 'next'), 'Highlight next surrounding')\n  --stylua: ignore end\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniSurround', {})\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\nend\n\nH.create_default_hl = function() vim.api.nvim_set_hl(0, 'MiniSurround', { default = true, link = 'IncSearch' }) end\n\nH.is_disabled = function() return vim.g.minisurround_disable == true or vim.b.minisurround_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniSurround.config, vim.b.minisurround_config or {}, config or {})\nend\n\nH.validate_search_method = function(x)\n  local allowed_methods = vim.tbl_keys(H.span_compare_methods)\n  if vim.tbl_contains(allowed_methods, x) then return end\n\n  table.sort(allowed_methods)\n  local allowed_methods_string = table.concat(vim.tbl_map(vim.inspect, allowed_methods), ', ')\n  H.error('`search_method` should be one of ' .. allowed_methods_string)\nend\n\n-- Mappings -------------------------------------------------------------------\nH.make_operator = function(task, search_method, ask_for_textobject)\n  return function()\n    if H.is_disabled() then\n      -- Using `<Esc>` helps to stop moving cursor caused by current\n      -- implementation detail of adding `' '` inside expression mapping\n      return [[\\<Esc>]]\n    end\n\n    H.cache = { count = vim.v.count1, search_method = search_method }\n\n    vim.o.operatorfunc = 'v:lua.MiniSurround.' .. task\n\n    -- NOTEs:\n    -- - Prepend with command to reset `vim.v.count1` to allow\n    -- `[count1]sa[count2][textobject]`.\n    -- - Concatenate `' '` to operator output to \"disable\" motion\n    --   required by `g@`. It is used to enable dot-repeatability.\n    return '<Cmd>redraw<CR>g@' .. (ask_for_textobject and '' or ' ')\n  end\nend\n\nH.make_action = function(task, direction, search_method)\n  return function()\n    if H.is_disabled() then return '<Esc>' end\n    H.cache = { count = vim.v.count1, direction = direction, search_method = search_method }\n    return '<Cmd>lua MiniSurround.' .. task .. '()<CR>'\n  end\nend\n\n-- Work with surrounding info -------------------------------------------------\nH.get_surround_spec = function(sur_type, use_cache)\n  local res\n\n  -- Try using cache\n  if use_cache then\n    res = H.cache[sur_type]\n    if res ~= nil then return res end\n  else\n    H.cache = {}\n  end\n\n  -- Prompt user to enter identifier of surrounding\n  local char = H.user_surround_id(sur_type)\n  if char == nil then return nil end\n\n  -- Get surround specification\n  res = H.make_surrounding_table()[char][sur_type]\n\n  -- Allow function returning spec or surrounding region(s)\n  if vim.is_callable(res) then res = res() end\n\n  -- Do nothing if supplied not appropriate structure\n  if not H.is_surrounding_info(res, sur_type) then return nil end\n\n  -- Wrap callable tables to be an actual functions. Otherwise they might be\n  -- confused with list of patterns.\n  if H.is_composed_pattern(res) then res = vim.tbl_map(H.wrap_callable_table, res) end\n\n  -- Track id for possible messages. Use metatable to pass \"islist\" check.\n  res = setmetatable(res, { __index = { id = char } })\n\n  -- Cache result\n  if use_cache then H.cache[sur_type] = res end\n\n  return res\nend\n\nH.make_surrounding_table = function()\n  -- Extend builtins with data from `config`\n  local surroundings = vim.deepcopy(H.builtin_surroundings)\n  for char, spec in pairs(H.get_config().custom_surroundings or {}) do\n    local cur_spec = surroundings[char] or {}\n    local default = H.get_default_surrounding_info(char)\n    -- NOTE: Don't use `tbl_deep_extend` to prefer full `input` arrays\n    cur_spec.input = spec.input or cur_spec.input or default.input\n    cur_spec.output = spec.output or cur_spec.output or default.output\n    surroundings[char] = cur_spec\n  end\n\n  -- Use default surrounding info for not supplied single character identifier\n  return setmetatable(surroundings, {\n    __index = function(_, key) return H.get_default_surrounding_info(key) end,\n  })\nend\n\nH.get_default_surrounding_info = function(char)\n  local char_esc = vim.pesc(char)\n  return { input = { char_esc .. '().-()' .. char_esc }, output = { left = char, right = char } }\nend\n\nH.is_surrounding_info = function(x, sur_type)\n  if sur_type == 'input' then\n    return H.is_composed_pattern(x) or H.is_region_pair(x) or H.is_region_pair_array(x)\n  elseif sur_type == 'output' then\n    return (type(x) == 'table' and type(x.left) == 'string' and type(x.right) == 'string')\n  end\nend\n\nH.is_region = function(x)\n  if type(x) ~= 'table' then return false end\n  local from_is_valid = type(x.from) == 'table' and type(x.from.line) == 'number' and type(x.from.col) == 'number'\n  -- Allow `to` to be `nil` to describe empty regions\n  local to_is_valid = true\n  if x.to ~= nil then\n    to_is_valid = type(x.to) == 'table' and type(x.to.line) == 'number' and type(x.to.col) == 'number'\n  end\n  return from_is_valid and to_is_valid\nend\n\nH.is_region_pair = function(x)\n  if type(x) ~= 'table' then return false end\n  return H.is_region(x.left) and H.is_region(x.right)\nend\n\nH.is_region_pair_array = function(x)\n  if not H.islist(x) then return false end\n  for _, v in ipairs(x) do\n    if not H.is_region_pair(v) then return false end\n  end\n  return true\nend\n\nH.is_composed_pattern = function(x)\n  if not (H.islist(x) and #x > 0) then return false end\n  for _, val in ipairs(x) do\n    local val_type = type(val)\n    if not (val_type == 'table' or val_type == 'string' or vim.is_callable(val)) then return false end\n  end\n  return true\nend\n\n-- Work with finding surrounding ----------------------------------------------\n---@param surr_spec table Composed pattern. Last item(s) - extraction template.\n---@param opts table|nil Options.\n---@private\nH.find_surrounding = function(surr_spec, opts)\n  if surr_spec == nil then return end\n  if H.is_region_pair(surr_spec) then return surr_spec end\n\n  opts = vim.tbl_deep_extend('force', H.get_default_opts(), opts or {})\n  H.validate_search_method(opts.search_method)\n\n  local region_pair = H.find_surrounding_region_pair(surr_spec, opts)\n  if region_pair == nil then\n    local msg = ([[No surrounding %s found within %d line%s and `config.search_method = '%s'`.]]):format(\n      vim.inspect((opts.n_times > 1 and opts.n_times or '') .. surr_spec.id),\n      opts.n_lines,\n      opts.n_lines > 1 and 's' or '',\n      opts.search_method\n    )\n    H.message(msg)\n  end\n\n  return region_pair\nend\n\nH.find_surrounding_region_pair = function(surr_spec, opts)\n  local reference_region, n_times, n_lines = opts.reference_region, opts.n_times, opts.n_lines\n\n  if n_times == 0 then return end\n\n  -- Find `n_times` matching spans evolving from reference region span\n  -- First try to find inside 0-neighborhood\n  local neigh = H.get_neighborhood(reference_region, 0)\n  local reference_span = neigh.region_to_span(reference_region)\n\n  local find_next = function(cur_reference_span)\n    local res = H.find_best_match(neigh, surr_spec, cur_reference_span, opts)\n\n    -- If didn't find in 0-neighborhood, possibly try extend one\n    if res.span == nil then\n      -- Stop if no need to extend neighborhood\n      if n_lines == 0 or neigh.n_neighbors > 0 then return {} end\n\n      -- Update data with respect to new neighborhood\n      local cur_reference_region = neigh.span_to_region(cur_reference_span)\n      neigh = H.get_neighborhood(reference_region, n_lines)\n      reference_span = neigh.region_to_span(reference_region)\n      cur_reference_span = neigh.region_to_span(cur_reference_region)\n\n      -- Recompute based on new neighborhood\n      res = H.find_best_match(neigh, surr_spec, cur_reference_span, opts)\n    end\n\n    return res\n  end\n\n  local find_res = { span = reference_span }\n  for _ = 1, n_times do\n    find_res = find_next(find_res.span)\n    if find_res.span == nil then return end\n  end\n\n  -- Extract final span\n  local extract = function(span, extract_pattern)\n    -- Use table extract pattern to allow array of regions as surrounding spec\n    -- Pair of spans is constructed based on best region pair\n    if type(extract_pattern) == 'table' then return extract_pattern end\n\n    -- First extract local (with respect to best matched span) surrounding spans\n    local s = neigh['1d']:sub(span.from, span.to - 1)\n    local local_surr_spans = H.extract_surr_spans(s, extract_pattern)\n\n    -- Convert local spans to global\n    local off = span.from - 1\n    local left, right = local_surr_spans.left, local_surr_spans.right\n    return {\n      left = { from = left.from + off, to = left.to + off },\n      right = { from = right.from + off, to = right.to + off },\n    }\n  end\n\n  local final_spans = extract(find_res.span, find_res.extract_pattern)\n  local outer_span = { from = final_spans.left.from, to = final_spans.right.to }\n\n  -- Ensure that output region is different from reference.\n  if H.is_span_covering(reference_span, outer_span) then\n    find_res = find_next(find_res.span)\n    if find_res.span == nil then return end\n    final_spans = extract(find_res.span, find_res.extract_pattern)\n    outer_span = { from = final_spans.left.from, to = final_spans.right.to }\n    if H.is_span_covering(reference_span, outer_span) then return end\n  end\n\n  -- Convert to region pair\n  return { left = neigh.span_to_region(final_spans.left), right = neigh.span_to_region(final_spans.right) }\nend\n\nH.get_default_opts = function()\n  local config = H.get_config()\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  return {\n    n_lines = config.n_lines,\n    n_times = H.cache.count or vim.v.count1,\n    -- Empty region at cursor position\n    reference_region = { from = { line = cur_pos[1], col = cur_pos[2] + 1 } },\n    search_method = H.cache.search_method or config.search_method,\n  }\nend\n\n-- Work with treesitter surrounding -------------------------------------------\nH.prepare_captures = function(captures)\n  local is_capture = function(x) return type(x) == 'string' and x:sub(1, 1) == '@' end\n\n  if not (type(captures) == 'table' and is_capture(captures.outer) and is_capture(captures.inner)) then\n    H.error('Wrong format for `captures`. See `MiniSurround.gen_spec.input.treesitter()` for details.')\n  end\n\n  return { outer = captures.outer, inner = captures.inner }\nend\n\nH.get_matched_range_pairs_plugin = function(captures)\n  local ts_queries = require('nvim-treesitter.query')\n  local buf_id = vim.api.nvim_get_current_buf()\n  local outer_matches = ts_queries.get_capture_matches_recursively(buf_id, captures.outer, 'textobjects')\n\n  -- Make sure that found matches contain `node` field that is actually a node,\n  -- otherwise later `get_capture_matches` will error as it requires an actual\n  -- `TSNode` object. This is needed as capture might be defined with custom\n  -- directive (like `#make-range!`) which 'nvim-treesitter' handles manually\n  -- by returning \"extended range\" and not `TSNode`.\n  outer_matches = vim.tbl_filter(function(x) return x.node.tree ~= nil end, outer_matches)\n\n  -- Pick inner range as the biggest range for node matching inner query. This\n  -- is needed because query output is not guaranteed to come in order, so just\n  -- picking first one is not enough.\n  return vim.tbl_map(function(m_outer)\n    local outer_range = vim.treesitter.get_range(m_outer.node, buf_id, m_outer.metadata)\n    local inner = ts_queries.get_capture_matches(0, captures.inner, 'textobjects', m_outer.node, nil)\n    local inner_ranges = vim.tbl_map(function(m) return vim.treesitter.get_range(m.node, buf_id, m.metadata) end, inner)\n    return { outer = outer_range, inner = H.get_biggest_nested_range(inner_ranges, outer_range) }\n  end, outer_matches)\nend\n\nH.get_matched_range_pairs_builtin = function(captures)\n  -- Get buffer's parser (LanguageTree)\n  local buf_id = vim.api.nvim_get_current_buf()\n  -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped\n  local has_parser, parser = pcall(vim.treesitter.get_parser, buf_id, nil, { error = false })\n  if not has_parser or parser == nil then H.error_treesitter('parser') end\n\n  -- Get parser (LanguageTree) at cursor (important for injected languages)\n  local pos = vim.api.nvim_win_get_cursor(0)\n  local lang_tree = parser:language_for_range({ pos[1] - 1, pos[2], pos[1] - 1, pos[2] })\n\n  local missing_query_langs = {}\n  -- Compute matched ranges for both outer and inner captures\n  -- Maybe go up parent trees to work with injected languages\n  local outer_ranges, inner_ranges = {}, {}\n  while (vim.tbl_isempty(inner_ranges) or vim.tbl_isempty(outer_ranges)) and lang_tree ~= nil do\n    local lang = lang_tree:lang()\n    -- Get query file depending on the local language\n    local query = vim.treesitter.query.get(lang, 'textobjects')\n\n    if query ~= nil then\n      for _, tree in ipairs(lang_tree:trees()) do\n        local root = tree:root()\n        vim.list_extend(outer_ranges, H.get_match_ranges_builtin(root, buf_id, query, captures.outer:sub(2)))\n        vim.list_extend(inner_ranges, H.get_match_ranges_builtin(root, buf_id, query, captures.inner:sub(2)))\n      end\n    end\n    if query == nil then missing_query_langs[lang] = true end\n\n    -- `LanguageTree:parent()` was added in Neovim<0.10\n    -- TODO: Drop extra check after compatibility with Neovim=0.9 is dropped\n    lang_tree = lang_tree.parent and lang_tree:parent() or nil\n  end\n\n  -- Match outer and inner ranges: for each outer range pick the biggest inner\n  -- range that lies within outer\n  local res = {}\n  for i, outer in ipairs(outer_ranges) do\n    res[i] = { outer = outer, inner = H.get_biggest_nested_range(inner_ranges, outer) }\n  end\n\n  if vim.tbl_isempty(res) and not vim.tbl_isempty(missing_query_langs) then\n    H.error_treesitter('query', vim.tbl_keys(missing_query_langs))\n  end\n\n  return res\nend\n\nH.get_match_ranges_builtin = function(root, buf_id, query, capture)\n  local res = {}\n  -- TODO: Remove `opts.all`after compatibility with Neovim=0.10 is dropped\n  for _, match, metadata in query:iter_matches(root, buf_id, nil, nil, { all = true }) do\n    for capture_id, nodes in pairs(match) do\n      local mt = metadata[capture_id]\n      if query.captures[capture_id] == capture then table.insert(res, H.get_nodes_range_builtin(nodes, buf_id, mt)) end\n    end\n  end\n\n  return res\nend\n\nH.get_nodes_range_builtin = function(nodes, buf_id, metadata)\n  -- In Neovim<0.10 `Query:iter_matches()` has `match` map to single node.\n  -- TODO: Remove `opts.all`after compatibility with Neovim=0.9 is dropped\n  nodes = type(nodes) == 'table' and nodes or { nodes }\n\n  -- Get matched range as spanning from left most node start to right most node\n  -- end. This accounts for several matched nodes that are intentionally there\n  -- to cover complex cases. Approach is named \"quantified captures\".\n  local left, right\n  for _, node in ipairs(nodes) do\n    local range = vim.treesitter.get_range(node, buf_id, metadata)\n    if left == nil or range[3] < left[3] then left = range end\n    if right == nil or range[6] > right[6] then right = range end\n  end\n  return { left[1], left[2], left[3], right[4], right[5], right[6] }\nend\n\nH.get_biggest_nested_range = function(ranges, parent)\n  local best_range, best_byte_count = nil, -math.huge\n  for _, r in ipairs(ranges) do\n    local byte_count = r[6] - r[3] + 1\n    if parent[3] <= r[3] and r[6] <= parent[6] and best_byte_count < byte_count then\n      best_range, best_byte_count = r, byte_count\n    end\n  end\n\n  return best_range\nend\n\nH.error_treesitter = function(failed_get, langs)\n  local buf_id, ft = vim.api.nvim_get_current_buf(), vim.bo.filetype\n  if langs == nil then\n    local has_lang, ft_lang = pcall(vim.treesitter.language.get_lang, ft)\n    -- `vim.treesitter.language.get_lang()` defaults to `ft` on Neovim>0.11\n    -- TODO: Drop check after compatibility with Neovim=0.10 is dropped\n    langs = (has_lang and ft_lang ~= nil) and { ft_lang } or { ft }\n  end\n  table.sort(langs)\n  local langs_str = table.concat(vim.tbl_map(vim.inspect, langs), ', ')\n  local langs_noun = #langs == 1 and 'language' or 'languages'\n  local msg = string.format('Can not get %s for buffer %d and %s %s.', failed_get, buf_id, langs_noun, langs_str)\n  H.error(msg)\nend\n\n-- Work with matching spans ---------------------------------------------------\n---@param neighborhood table Output of `get_neighborhood()`.\n---@param surr_spec table\n---@param reference_span table Span to cover.\n---@param opts table Fields: <search_method>.\n---@private\nH.find_best_match = function(neighborhood, surr_spec, reference_span, opts)\n  local best_span, best_nested_pattern, current_nested_pattern\n  local f = function(span)\n    if H.is_better_span(span, best_span, reference_span, opts) then\n      best_span = span\n      best_nested_pattern = current_nested_pattern\n    end\n  end\n\n  if H.is_region_pair_array(surr_spec) then\n    -- Iterate over all spans representing outer regions in array\n    for _, region_pair in ipairs(surr_spec) do\n      -- Construct outer region used to find best region pair\n      local outer_region = { from = region_pair.left.from, to = region_pair.right.to or region_pair.right.from }\n\n      -- Consider outer region only if it is completely within neighborhood\n      if neighborhood.is_region_inside(outer_region) then\n        -- Make future extract pattern based directly on region pair\n        current_nested_pattern = {\n          {\n            left = neighborhood.region_to_span(region_pair.left),\n            right = neighborhood.region_to_span(region_pair.right),\n          },\n        }\n\n        f(neighborhood.region_to_span(outer_region))\n      end\n    end\n  else\n    -- Iterate over all matched spans\n    for _, nested_pattern in ipairs(H.cartesian_product(surr_spec)) do\n      current_nested_pattern = nested_pattern\n      H.iterate_matched_spans(neighborhood['1d'], nested_pattern, f)\n    end\n  end\n\n  local extract_pattern\n  if best_nested_pattern ~= nil then extract_pattern = best_nested_pattern[#best_nested_pattern] end\n  return { span = best_span, extract_pattern = extract_pattern }\nend\n\nH.iterate_matched_spans = function(line, nested_pattern, f)\n  local max_level = #nested_pattern\n  -- Keep track of visited spans to ensure only one call of `f`.\n  -- Example: `((a) (b))`, `{'%b()', '%b()'}`\n  local visited = {}\n\n  local process\n  process = function(level, level_line, level_offset)\n    local pattern = nested_pattern[level]\n    local next_span = function(s, init) return H.string_find(s, pattern, init) end\n    if vim.is_callable(pattern) then next_span = pattern end\n\n    local is_same_balanced = type(pattern) == 'string' and pattern:match('^%%b(.)%1$') ~= nil\n    local init = 1\n    while init <= level_line:len() do\n      local from, to = next_span(level_line, init)\n      if from == nil then break end\n\n      if level == max_level then\n        local found_match = H.new_span(from + level_offset, to + level_offset)\n        local found_match_id = string.format('%s_%s', found_match.from, found_match.to)\n        if not visited[found_match_id] then\n          f(found_match)\n          visited[found_match_id] = true\n        end\n      else\n        local next_level_line = level_line:sub(from, to)\n        local next_level_offset = level_offset + from - 1\n        process(level + 1, next_level_line, next_level_offset)\n      end\n\n      -- Start searching from right end to implement \"balanced\" pair.\n      -- This doesn't work with regular balanced pattern because it doesn't\n      -- capture nested brackets.\n      init = (is_same_balanced and to or from) + 1\n    end\n  end\n\n  process(1, line, 0)\nend\n\n-- NOTE: spans are end-exclusive to allow empty spans via `from == to`\nH.new_span = function(from, to) return { from = from, to = to == nil and from or (to + 1) } end\n\n---@param candidate table Candidate span to test against `current`.\n---@param current table|nil Current best span.\n---@param reference table Reference span to cover.\n---@param opts table Fields: <search_method>.\n---@private\nH.is_better_span = function(candidate, current, reference, opts)\n  -- Candidate should be never equal or nested inside reference\n  if H.is_span_covering(reference, candidate) or H.is_span_equal(candidate, reference) then return false end\n\n  return H.span_compare_methods[opts.search_method](candidate, current, reference)\nend\n\nH.span_compare_methods = {\n  cover = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n    -- If both are not covering, `candidate` is not better (as it must cover)\n    return false\n  end,\n\n  cover_or_next = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n\n    -- If not covering, `candidate` must be \"next\" and closer to reference\n    if not H.is_span_on_left(reference, candidate) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.next\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  cover_or_prev = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n\n    -- If not covering, `candidate` must be \"previous\" and closer to reference\n    if not H.is_span_on_left(candidate, reference) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.prev\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  cover_or_nearest = function(candidate, current, reference)\n    local res = H.is_better_covering_span(candidate, current, reference)\n    if res ~= nil then return res end\n\n    -- If not covering, `candidate` must be closer to reference\n    if current == nil then return true end\n\n    local dist = H.span_distance.near\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  next = function(candidate, current, reference)\n    if H.is_span_covering(candidate, reference) then return false end\n\n    -- `candidate` must be \"next\" and closer to reference\n    if not H.is_span_on_left(reference, candidate) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.next\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  prev = function(candidate, current, reference)\n    if H.is_span_covering(candidate, reference) then return false end\n\n    -- `candidate` must be \"previous\" and closer to reference\n    if not H.is_span_on_left(candidate, reference) then return false end\n    if current == nil then return true end\n\n    local dist = H.span_distance.prev\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n\n  nearest = function(candidate, current, reference)\n    if H.is_span_covering(candidate, reference) then return false end\n\n    -- `candidate` must be closer to reference\n    if current == nil then return true end\n\n    local dist = H.span_distance.near\n    return dist(candidate, reference) < dist(current, reference)\n  end,\n}\n\nH.span_distance = {\n  -- Other possible choices of distance between [a1, a2] and [b1, b2]:\n  -- - Hausdorff distance: max(|a1 - b1|, |a2 - b2|).\n  --   Source:\n  --   https://math.stackexchange.com/questions/41269/distance-between-two-ranges\n  -- - Minimum distance: min(|a1 - b1|, |a2 - b2|).\n\n  -- Distance is chosen so that \"next span\" in certain direction is the closest\n  next = function(span_1, span_2) return math.abs(span_1.from - span_2.from) end,\n  prev = function(span_1, span_2) return math.abs(span_1.to - span_2.to) end,\n  near = function(span_1, span_2) return math.min(math.abs(span_1.from - span_2.from), math.abs(span_1.to - span_2.to)) end,\n}\n\nH.is_better_covering_span = function(candidate, current, reference)\n  local candidate_is_covering = H.is_span_covering(candidate, reference)\n  local current_is_covering = H.is_span_covering(current, reference)\n\n  if candidate_is_covering and current_is_covering then\n    -- Covering candidate is better than covering current if it is narrower\n    return (candidate.to - candidate.from) < (current.to - current.from)\n  end\n  if candidate_is_covering and not current_is_covering then return true end\n  if not candidate_is_covering and current_is_covering then return false end\n\n  -- Return `nil` if neither span is covering\n  return nil\nend\n\n--stylua: ignore\nH.is_span_covering = function(span, span_to_cover)\n  if span == nil or span_to_cover == nil then return false end\n  if span.from == span.to then\n    return (span.from == span_to_cover.from) and (span_to_cover.to == span.to)\n  end\n  if span_to_cover.from == span_to_cover.to then\n    return (span.from <= span_to_cover.from) and (span_to_cover.to < span.to)\n  end\n\n  return (span.from <= span_to_cover.from) and (span_to_cover.to <= span.to)\nend\n\nH.is_span_equal = function(span_1, span_2)\n  if span_1 == nil or span_2 == nil then return false end\n  return (span_1.from == span_2.from) and (span_1.to == span_2.to)\nend\n\nH.is_span_on_left = function(span_1, span_2)\n  if span_1 == nil or span_2 == nil then return false end\n  return (span_1.from <= span_2.from) and (span_1.to <= span_2.to)\nend\n\nH.is_point_inside_spans = function(point, spans)\n  for _, span in ipairs(spans) do\n    if span[1] <= point and point <= span[2] then return true end\n  end\n  return false\nend\n\nH.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end\n\nH.str_byteindex = function(s, i) return vim.str_byteindex(s, 'utf-32', i) end\nif vim.fn.has('nvim-0.11') == 0 then H.str_byteindex = function(s, i) return vim.str_byteindex(s, i) end end\n\n-- Work with operator marks ---------------------------------------------------\nH.get_marks_pos = function(mode)\n  -- Region is inclusive on both ends\n  local mark1, mark2\n  if mode == 'visual' then\n    mark1, mark2 = '<', '>'\n  else\n    mark1, mark2 = '[', ']'\n  end\n\n  local pos1 = vim.api.nvim_buf_get_mark(0, mark1)\n  local pos2 = vim.api.nvim_buf_get_mark(0, mark2)\n\n  local selection_type = H.get_selection_type(mode)\n\n  -- Tweak position in linewise mode as marks are placed on the first column\n  if selection_type == 'linewise' then\n    -- Move start mark past the indent\n    local _, line1_indent = vim.fn.getline(pos1[1]):find('^%s*')\n    pos1[2] = line1_indent\n\n    -- Move end mark to the last non-whitespace character\n    pos2[2] = vim.fn.getline(pos2[1]):find('%s*$') - 2\n  end\n\n  -- Make columns 1-based instead of 0-based. This is needed because\n  -- `nvim_buf_get_mark()` returns the first 0-based byte of mark symbol and\n  -- all the following operations are done with Lua's 1-based indexing.\n  pos1[2], pos2[2] = pos1[2] + 1, pos2[2] + 1\n\n  -- Tweak second position to respect multibyte characters. Reasoning:\n  -- - These positions will be used with `region_replace()` to add some text,\n  --   which operates on byte columns.\n  -- - For the first mark we want the first byte of symbol, then text will be\n  --   insert to the left of the mark.\n  -- - For the second mark we want last byte of symbol. To add surrounding to\n  --   the right, use `pos2[2] + 1`.\n  if mode == 'visual' and vim.o.selection == 'exclusive' then\n    -- Respect 'selection' option\n    pos2[2] = pos2[2] - 1\n  else\n    local line2 = vim.fn.getline(pos2[1])\n    -- Use `math.min()` because it might lead to 'index out of range' error\n    -- when mark is positioned at the end of line (that extra space which is\n    -- selected when selecting with `v$`)\n    local utf_index = H.str_utfindex(line2, math.min(#line2, pos2[2]))\n    -- This returns the last byte inside character because `vim.str_byteindex()`\n    -- 'rounds upwards to the end of that sequence'.\n    pos2[2] = H.str_byteindex(line2, utf_index)\n  end\n\n  return {\n    first = { line = pos1[1], col = pos1[2] },\n    second = { line = pos2[1], col = pos2[2] },\n    selection_type = selection_type,\n  }\nend\n\nH.get_selection_type = function(mode)\n  if (mode == 'char') or (mode == 'visual' and vim.fn.visualmode() == 'v') then return 'charwise' end\n  if (mode == 'line') or (mode == 'visual' and vim.fn.visualmode() == 'V') then return 'linewise' end\n  if (mode == 'block') or (mode == 'visual' and vim.fn.visualmode() == '\\22') then return 'blockwise' end\nend\n\n-- Work with cursor -----------------------------------------------------------\nH.set_cursor = function(line, col) vim.api.nvim_win_set_cursor(0, { line, col - 1 }) end\n\nH.set_cursor_nonblank = function(line)\n  H.set_cursor(line, 1)\n  vim.cmd('normal! ^')\nend\n\nH.compare_pos = function(pos1, pos2)\n  if pos1.line < pos2.line then return '<' end\n  if pos1.line > pos2.line then return '>' end\n  if pos1.col < pos2.col then return '<' end\n  if pos1.col > pos2.col then return '>' end\n  return '='\nend\n\nH.cursor_cycle = function(pos_array, dir)\n  local cur_pos = vim.api.nvim_win_get_cursor(0)\n  cur_pos = { line = cur_pos[1], col = cur_pos[2] + 1 }\n\n  local compare, to_left, to_right, res_pos\n  -- NOTE: `pos_array` should be an increasingly ordered array of positions\n  for _, pos in pairs(pos_array) do\n    compare = H.compare_pos(cur_pos, pos)\n    -- Take position when moving to left if cursor is strictly on right.\n    -- This will lead to updating `res_pos` until the rightmost such position.\n    to_left = compare == '>' and dir == 'left'\n    -- Take position when moving to right if cursor is strictly on left.\n    -- This will update result only once leading to the leftmost such position.\n    to_right = res_pos == nil and compare == '<' and dir == 'right'\n    if to_left or to_right then res_pos = pos end\n  end\n\n  res_pos = res_pos or (dir == 'right' and pos_array[1] or pos_array[#pos_array])\n  H.set_cursor(res_pos.line, res_pos.col)\nend\n\n-- Work with user input -------------------------------------------------------\nH.user_surround_id = function(sur_type)\n  -- Get from user single character surrounding identifier\n  local needs_reminder = true\n  vim.defer_fn(function()\n    if not needs_reminder then return end\n\n    local msg = string.format('Reminder to press %s surrounding id ', sur_type)\n    H.echo(msg)\n    H.cache.msg_shown = true\n  end, 1000)\n  local ok, char = pcall(vim.fn.getcharstr)\n  needs_reminder = false\n  H.unecho()\n\n  -- Terminate if couldn't get input (like with <C-c>) or it is `<Esc>`\n  if not ok or char == '\\27' then return nil end\n  return char\nend\n\n-- Work with positions --------------------------------------------------------\nH.pos_to_left = function(pos)\n  if pos.line == 1 and pos.col == 1 then return { line = pos.line, col = pos.col } end\n  if pos.col == 1 then return { line = pos.line - 1, col = H.get_line_cols(pos.line - 1) } end\n  return { line = pos.line, col = pos.col - 1 }\nend\n\nH.pos_to_right = function(pos)\n  local n_cols = H.get_line_cols(pos.line)\n  -- Using `>` and not `>=` helps with removing '\\n' and in the last line\n  if pos.line == vim.api.nvim_buf_line_count(0) and pos.col > n_cols then return { line = pos.line, col = n_cols } end\n  if pos.col > n_cols then return { line = pos.line + 1, col = 1 } end\n  return { line = pos.line, col = pos.col + 1 }\nend\n\n-- Work with regions ----------------------------------------------------------\nH.region_replace = function(region, text)\n  -- Compute start and end position for `vim.api.nvim_buf_set_text()`.\n  -- Indexing is zero-based. Rows - end-inclusive, columns - end-exclusive.\n  local start_row, start_col = region.from.line - 1, region.from.col - 1\n\n  local end_row, end_col\n  -- Allow empty region\n  if H.region_is_empty(region) then\n    end_row, end_col = start_row, start_col\n  else\n    end_row, end_col = region.to.line - 1, region.to.col\n\n    -- Possibly correct to allow removing new line character\n    if end_row < vim.api.nvim_buf_line_count(0) and H.get_line_cols(end_row + 1) < end_col then\n      end_row, end_col = end_row + 1, 0\n    end\n  end\n\n  -- Allow single string as replacement\n  if type(text) == 'string' then text = { text } end\n\n  -- Allow `\\n` in string to denote new lines\n  if #text > 0 then text = vim.split(table.concat(text, '\\n'), '\\n') end\n\n  -- Replace. Use `pcall()` to do nothing if some position is out of bounds.\n  pcall(vim.api.nvim_buf_set_text, 0, start_row, start_col, end_row, end_col, text)\nend\n\nH.surr_to_pos_array = function(surr)\n  local res = {}\n\n  local append_position = function(pos, correction_direction)\n    if pos == nil then return end\n    -- Don't go past the line if it is not empty\n    if H.get_line_cols(pos.line) < pos.col and pos.col > 1 then\n      pos = correction_direction == 'left' and H.pos_to_left(pos) or H.pos_to_right(pos)\n    end\n\n    -- Don't add duplicate. Assumes that positions are used increasingly.\n    local line, col = pos.line, pos.col\n    local last = res[#res]\n    if not (last ~= nil and last.line == line and last.col == col) then\n      table.insert(res, { line = line, col = col })\n    end\n  end\n\n  -- Possibly correct position towards inside of surrounding region\n  -- Also don't add positions from empty regions\n  if not H.region_is_empty(surr.left) then\n    append_position(surr.left.from, 'right')\n    append_position(surr.left.to, 'right')\n  end\n  if not H.region_is_empty(surr.right) then\n    append_position(surr.right.from, 'left')\n    append_position(surr.right.to, 'left')\n  end\n\n  return res\nend\n\nH.region_highlight = function(buf_id, region)\n  -- Don't highlight empty region\n  if H.region_is_empty(region) then return end\n  local ns_id = H.ns_id.highlight\n\n  -- Indexing is zero-based. Rows - end-inclusive, columns - end-exclusive.\n  local from_line, from_col, to_line, to_col =\n    region.from.line - 1, region.from.col - 1, region.to.line - 1, region.to.col\n  H.highlight_range(buf_id, ns_id, 'MiniSurround', { from_line, from_col }, { to_line, to_col })\nend\n\nH.region_unhighlight = function(buf_id, region)\n  local ns_id = H.ns_id.highlight\n\n  -- Remove highlights from whole lines as it is the best available granularity\n  vim.api.nvim_buf_clear_namespace(buf_id, ns_id, region.from.line - 1, (region.to or region.from).line)\nend\n\nH.region_is_empty = function(region) return region.to == nil end\n\n-- Work with text -------------------------------------------------------------\nH.get_range_indent = function(from_line, to_line)\n  local n_indent, indent = math.huge, nil\n\n  local lines = vim.api.nvim_buf_get_lines(0, from_line - 1, to_line, true)\n  local n_indent_cur, indent_cur\n  for _, l in ipairs(lines) do\n    _, n_indent_cur, indent_cur = l:find('^(%s*)')\n\n    -- Don't indent blank lines\n    if n_indent_cur < n_indent and n_indent_cur < l:len() then\n      n_indent, indent = n_indent_cur, indent_cur\n    end\n  end\n\n  return indent or ''\nend\n\nH.shift_indent = function(command, from_line, to_line)\n  if to_line < from_line then return end\n  vim.cmd('silent ' .. from_line .. ',' .. to_line .. command)\nend\n\nH.is_line_blank = function(line_num) return vim.fn.nextnonblank(line_num) ~= line_num end\n\n-- Work with Lua patterns -----------------------------------------------------\nH.extract_surr_spans = function(s, extract_pattern)\n  local positions = { s:match(extract_pattern) }\n\n  local is_all_numbers = true\n  for _, pos in ipairs(positions) do\n    if type(pos) ~= 'number' then is_all_numbers = false end\n  end\n\n  local is_valid_positions = is_all_numbers and (#positions == 2 or #positions == 4)\n  if not is_valid_positions then\n    local msg = 'Could not extract proper positions (two or four empty captures) from '\n      .. string.format([[string '%s' with extraction pattern '%s'.]], s, extract_pattern)\n    H.error(msg)\n  end\n\n  if #positions == 2 then\n    return { left = H.new_span(1, positions[1] - 1), right = H.new_span(positions[2], s:len()) }\n  end\n  return { left = H.new_span(positions[1], positions[2] - 1), right = H.new_span(positions[3], positions[4] - 1) }\nend\n\n-- Work with cursor neighborhood ----------------------------------------------\n---@param reference_region table Reference region.\n---@param n_neighbors number Maximum number of neighbors to include before\n---   start line and after end line.\n---@private\nH.get_neighborhood = function(reference_region, n_neighbors)\n  -- Compute '2d neighborhood' of (possibly empty) region\n  local from_line, to_line = reference_region.from.line, (reference_region.to or reference_region.from).line\n  local line_start = math.max(1, from_line - n_neighbors)\n  local line_end = math.min(vim.api.nvim_buf_line_count(0), to_line + n_neighbors)\n  local neigh2d = vim.api.nvim_buf_get_lines(0, line_start - 1, line_end, false)\n  -- Append 'newline' character to distinguish between lines in 1d case\n  for k, v in pairs(neigh2d) do\n    neigh2d[k] = v .. '\\n'\n  end\n\n  -- '1d neighborhood': position is determined by offset from start\n  local neigh1d = table.concat(neigh2d, '')\n\n  -- Convert 2d buffer position to 1d offset\n  local pos_to_offset = function(pos)\n    if pos == nil then return nil end\n    local line_num = line_start\n    local offset = 0\n    while line_num < pos.line do\n      offset = offset + neigh2d[line_num - line_start + 1]:len()\n      line_num = line_num + 1\n    end\n\n    return offset + pos.col\n  end\n\n  -- Convert 1d offset to 2d buffer position\n  local offset_to_pos = function(offset)\n    if offset == nil then return nil end\n    local line_num = 1\n    local line_offset = 0\n    while line_num <= #neigh2d and line_offset + neigh2d[line_num]:len() < offset do\n      line_offset = line_offset + neigh2d[line_num]:len()\n      line_num = line_num + 1\n    end\n\n    return { line = line_start + line_num - 1, col = offset - line_offset }\n  end\n\n  -- Convert 2d region to 1d span\n  local region_to_span = function(region)\n    if region == nil then return nil end\n    local is_empty = region.to == nil\n    local to = region.to or region.from\n    return { from = pos_to_offset(region.from), to = pos_to_offset(to) + (is_empty and 0 or 1) }\n  end\n\n  -- Convert 1d span to 2d region\n  local span_to_region = function(span)\n    if span == nil then return nil end\n    -- NOTE: this might lead to outside of line positions due to added `\\n` at\n    -- the end of lines in 1d-neighborhood.\n    local res = { from = offset_to_pos(span.from) }\n\n    -- Convert empty span to empty region\n    if span.from < span.to then res.to = offset_to_pos(span.to - 1) end\n    return res\n  end\n\n  local is_region_inside = function(region)\n    local res = line_start <= region.from.line\n    if region.to ~= nil then res = res and (region.to.line <= line_end) end\n    return res\n  end\n\n  return {\n    n_neighbors = n_neighbors,\n    region = reference_region,\n    ['1d'] = neigh1d,\n    ['2d'] = neigh2d,\n    pos_to_offset = pos_to_offset,\n    offset_to_pos = offset_to_pos,\n    region_to_span = region_to_span,\n    span_to_region = span_to_region,\n    is_region_inside = is_region_inside,\n  }\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.surround) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg, is_important)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.surround) ', 'WarningMsg' })\n\n  -- Avoid hit-enter-prompt\n  local max_width = vim.o.columns * math.max(vim.o.cmdheight - 1, 0) + vim.v.echospace\n  local chunks, tot_width = {}, 0\n  for _, ch in ipairs(msg) do\n    local new_ch = { vim.fn.strcharpart(ch[1], 0, max_width - tot_width), ch[2] }\n    table.insert(chunks, new_ch)\n    tot_width = tot_width + vim.fn.strdisplaywidth(new_ch[1])\n    if tot_width >= max_width then break end\n  end\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(chunks, is_important, {})\nend\n\nH.unecho = function()\n  if H.cache.msg_shown then vim.cmd([[echo '' | redraw]]) end\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.map = function(mode, lhs, rhs, opts)\n  if lhs == '' then return end\n  opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})\n  vim.keymap.set(mode, lhs, rhs, opts)\n  local no_global_s_mapping = not H.has_global_mapping(mode, 's')\n  if no_global_s_mapping and lhs:find('^s.') ~= nil then vim.keymap.set(mode, 's', '<Nop>') end\nend\n\nH.has_global_mapping = function(mode, lhs)\n  for _, map in ipairs(vim.api.nvim_get_keymap(mode)) do\n    if map.lhs == lhs then return true end\n  end\n  return false\nend\n\nH.get_line_cols = function(line_num) return vim.fn.getline(line_num):len() end\n\nH.string_find = function(s, pattern, init)\n  init = init or 1\n\n  -- Match only start of full string if pattern says so.\n  -- This is needed because `string.find()` doesn't do this.\n  -- Example: `string.find('(aaa)', '^.*$', 4)` returns `4, 5`\n  if pattern:sub(1, 1) == '^' then\n    if init > 1 then return nil end\n    return string.find(s, pattern)\n  end\n\n  -- Handle patterns `x.-y` differently: make match as small as possible. This\n  -- doesn't allow `x` be present inside `.-` match, just as with `yyy`. Which\n  -- also leads to a behavior similar to punctuation id (like with `va_`): no\n  -- covering is possible, only next, previous, or nearest.\n  local check_left, _, prev = string.find(pattern, '(.)%.%-')\n  local is_pattern_special = check_left ~= nil and prev ~= '%'\n  if not is_pattern_special then return string.find(s, pattern, init) end\n\n  -- Make match as small as possible\n  local from, to = string.find(s, pattern, init)\n  if from == nil then return end\n\n  local cur_from, cur_to = from, to\n  while cur_to == to do\n    from, to = cur_from, cur_to\n    cur_from, cur_to = string.find(s, pattern, cur_from + 1)\n  end\n\n  return from, to\nend\n\n---@param arr table List of items. If item is list, consider as set for\n---   product. Else - make it single item list.\n---@private\nH.cartesian_product = function(arr)\n  if not (type(arr) == 'table' and #arr > 0) then return {} end\n  arr = vim.tbl_map(function(x) return H.islist(x) and x or { x } end, arr)\n\n  local res, cur_item = {}, {}\n  local process\n  process = function(level)\n    for i = 1, #arr[level] do\n      table.insert(cur_item, arr[level][i])\n      if level == #arr then\n        -- Flatten array to allow tables as elements of step tables\n        table.insert(res, H.tbl_flatten(cur_item))\n      else\n        process(level + 1)\n      end\n      table.remove(cur_item, #cur_item)\n    end\n  end\n\n  process(1)\n  return res\nend\n\nH.wrap_callable_table = function(x)\n  if vim.is_callable(x) and type(x) == 'table' then\n    return function(...) return x(...) end\n  end\n  return x\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\nH.tbl_flatten = vim.fn.has('nvim-0.10') == 1 and function(x) return vim.iter(x):flatten(math.huge):totable() end\n  or vim.tbl_flatten\n\n-- TODO: Remove after compatibility with Neovim=0.10 is dropped\nH.highlight_range = function(...) vim.hl.range(...) end\nif vim.fn.has('nvim-0.11') == 0 then H.highlight_range = function(...) vim.highlight.range(...) end end\n\nreturn MiniSurround\n"
  },
  {
    "path": "lua/mini/tabline.lua",
    "content": "--- *mini.tabline* Tabline\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Key idea: show all listed buffers in readable way with minimal total width.\n---\n--- Features:\n--- - Buffers are listed in the order of their identifier (see |bufnr()|).\n---\n--- - Different highlight groups for \"states\" of buffer affecting 'buffer tabs'.\n---\n--- - Buffer names are made unique by extending paths to files or appending\n---   unique identifier to buffers without name.\n---\n--- - Current buffer is displayed \"optimally centered\" (in center of screen\n---   while maximizing the total number of buffers shown) when there are many\n---   buffers open.\n---\n--- - 'Buffer tabs' are clickable if Neovim allows it.\n---\n--- - Extra information section in case of multiple Neovim tabpages.\n---\n--- - Truncation symbols which show if there are tabs to the left and/or right.\n---   Exact characters are taken from 'listchars' global value (`precedes` and\n---   `extends` fields) and are shown only if 'list' option is enabled.\n---\n--- What it doesn't do:\n--- - Custom buffer order is not supported.\n---\n--- # Dependencies ~\n---\n--- Suggested dependencies (provide extra functionality, will work without them):\n---\n--- - Enabled |mini.icons| module to show icons near file names.\n---   Falls back to [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n---   or shows nothing.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.tabline').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniTabline` which you can use for scripting or manually (with\n--- `:lua MiniTabline.*`).\n---\n--- See |MiniTabline.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minitabline_config` which should have same structure as\n--- `MiniTabline.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Suggested option values ~\n---\n--- Some options are set automatically by |MiniTabline.setup()|:\n--- - 'showtabline' is set to 2 to always show tabline.\n---\n--- # Highlight groups ~\n---\n--- - `MiniTablineCurrent` - buffer is current (has cursor in it).\n--- - `MiniTablineVisible` - buffer is visible (displayed in some window).\n--- - `MiniTablineHidden` - buffer is hidden (not displayed).\n--- - `MiniTablineModifiedCurrent` - buffer is modified and current.\n--- - `MiniTablineModifiedVisible` - buffer is modified and visible.\n--- - `MiniTablineModifiedHidden` - buffer is modified and hidden.\n--- - `MiniTablineFill` - unused right space of tabline.\n--- - `MiniTablineTabpagesection` - section with tabpage information.\n--- - `MiniTablineTrunc` - truncation symbols indicating more left/right tabs.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable (show empty tabline), set `vim.g.minitabline_disable` (globally) or\n--- `vim.b.minitabline_disable` (for a buffer) to `true`. Considering high number\n--- of different scenarios and customization intentions, writing exact rules\n--- for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniTabline\n\n-- Module definition ==========================================================\nlocal MiniTabline = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniTabline.config|.\n---\n---@usage >lua\n---   require('mini.tabline').setup() -- use default config\n---   -- OR\n---   require('mini.tabline').setup({}) -- replace {} with your config table\n--- <\nMiniTabline.setup = function(config)\n  -- Export module\n  _G.MiniTabline = MiniTabline\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\n\n  -- Function to make tabs clickable\n  vim.api.nvim_exec(\n    [[function! MiniTablineSwitchBuffer(buf_id, clicks, button, mod)\n        execute 'buffer' a:buf_id\n      endfunction]],\n    false\n  )\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # Format ~\n---\n--- `config.format` is a callable that takes buffer identifier and pre-computed\n--- label as arguments and returns a string with formatted label. Output will be\n--- treated strictly as text (i.e. no 'statusline' like constructs is allowed).\n--- This function will be called for all displayable in tabline buffers.\n--- Default: |MiniTabline.default_format()|.\n---\n--- Example of adding \"+\" suffix for modified buffers: >lua\n---\n---   function(buf_id, label)\n---     local suffix = vim.bo[buf_id].modified and '+ ' or ''\n---     return MiniTabline.default_format(buf_id, label) .. suffix\n---   end\n--- <\nMiniTabline.config = {\n  -- Whether to show file icons (requires 'mini.icons')\n  show_icons = true,\n\n  -- Function which formats the tab label\n  -- By default surrounds with space and possibly prepends with icon\n  format = nil,\n\n  -- Where to show tabpage section in case of multiple vim tabpages.\n  -- One of 'left', 'right', 'none'.\n  tabpage_section = 'left',\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Make string for |'tabline'|\nMiniTabline.make_tabline_string = function()\n  if H.is_disabled() then return '' end\n\n  H.make_tabpage_section()\n  H.list_tabs()\n  H.finalize_labels()\n  H.fit_width()\n\n  return H.concat_tabs()\nend\n\n--- Default tab format\n---\n--- Used by default as `config.format`.\n--- Prepends label with padded icon based on buffer's name (if `show_icon`\n--- in |MiniTabline.config| is `true`) and surrounds label with single space.\n--- Note: it is meant to be used only as part of `format` in |MiniTabline.config|.\n---\n---@param buf_id number Buffer identifier.\n---@param label string Pre-computed label.\n---\n---@return string Formatted label.\nMiniTabline.default_format = function(buf_id, label)\n  if H.get_icon == nil then return string.format(' %s ', label) end\n  return string.format(' %s %s ', H.get_icon(vim.api.nvim_buf_get_name(buf_id)), label)\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniTabline.config)\n\n-- Table to keep track of tabs\nH.tabs = {}\n\n-- Keep track of initially unnamed buffers\nH.unnamed_buffers_seq_ids = {}\n\n-- Separator of file path\nH.path_sep = package.config:sub(1, 1)\n\n-- String with tabpage prefix\nH.tabpage_section = ''\n\n-- Data about truncation characters used when there are too much tabs\nH.trunc = { left = '', right = '', needs_left = false, needs_right = false }\n\n-- Buffer number of center buffer\nH.center_buf_id = nil\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('show_icons', config.show_icons, 'boolean')\n  H.check_type('format', config.format, 'function', true)\n  H.check_type('tabpage_section', config.tabpage_section, 'string')\n\n  return config\nend\n\nH.apply_config = function(config)\n  MiniTabline.config = config\n\n  -- Make tabline always visible (essential for custom tabline)\n  vim.o.showtabline = 2\n\n  -- Cache truncation characters\n  H.cache_trunc_chars()\n\n  -- Set tabline string\n  vim.o.tabline = '%!v:lua.MiniTabline.make_tabline_string()'\nend\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniTabline', {})\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\n\n  local trunc_opts = { group = gr, pattern = { 'list', 'listchars' }, callback = H.cache_trunc_chars }\n  trunc_opts.desc = 'Ensure truncation characters'\n  vim.api.nvim_create_autocmd('OptionSet', trunc_opts)\nend\n\n--stylua: ignore\nH.create_default_hl = function()\n  local set_default_hl = function(name, data)\n    data.default = true\n    vim.api.nvim_set_hl(0, name, data)\n  end\n\n  set_default_hl('MiniTablineCurrent', { link = 'TabLineSel' })\n  set_default_hl('MiniTablineVisible', { link = 'TabLineSel' })\n  set_default_hl('MiniTablineHidden',  { link = 'TabLine' })\n\n  set_default_hl('MiniTablineModifiedCurrent', { link = 'StatusLine' })\n  set_default_hl('MiniTablineModifiedVisible', { link = 'StatusLine' })\n  set_default_hl('MiniTablineModifiedHidden',  { link = 'StatusLineNC' })\n\n  set_default_hl('MiniTablineTabpagesection', { link = 'Search' })\n  set_default_hl('MiniTablineFill', { link = 'Normal' })\n  set_default_hl('MiniTablineTrunc', { link = 'MiniTablineHidden' })\nend\n\nH.is_disabled = function() return vim.g.minitabline_disable == true or vim.b.minitabline_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniTabline.config, vim.b.minitabline_config or {}, config or {})\nend\n\n-- Work with tabpages ---------------------------------------------------------\nH.make_tabpage_section = function()\n  local n_tabpages = vim.fn.tabpagenr('$')\n  if n_tabpages == 1 or H.get_config().tabpage_section == 'none' then\n    H.tabpage_section = ''\n    return\n  end\n\n  local cur_tabpagenr = vim.fn.tabpagenr()\n  H.tabpage_section = string.format(' Tab %s/%s ', cur_tabpagenr, n_tabpages)\nend\n\n-- Work with tabs -------------------------------------------------------------\n-- List tabs\nH.list_tabs = function()\n  local tabs = {}\n  for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do\n    if vim.bo[buf_id].buflisted then\n      local tab = { buf_id = buf_id }\n      tab['hl'] = H.construct_highlight(buf_id)\n      tab['tabfunc'] = '%' .. buf_id .. '@MiniTablineSwitchBuffer@'\n      tab['label'], tab['label_extender'] = H.construct_label_data(buf_id)\n\n      table.insert(tabs, tab)\n    end\n  end\n\n  H.tabs = tabs\nend\n\n-- Tab's highlight group\nH.construct_highlight = function(buf_id)\n  local hl_type = buf_id == vim.api.nvim_get_current_buf() and 'Current'\n    or (vim.fn.bufwinnr(buf_id) > 0 and 'Visible' or 'Hidden')\n  if vim.bo[buf_id].modified then hl_type = 'Modified' .. hl_type end\n\n  return '%#MiniTabline' .. hl_type .. '#'\nend\n\n-- Tab's label and label extender\nH.construct_label_data = function(buf_id)\n  local label, label_extender\n\n  local bufpath = vim.api.nvim_buf_get_name(buf_id)\n  if bufpath ~= '' then\n    -- Process path buffer\n    label = vim.fn.fnamemodify(bufpath, ':t')\n    label_extender = H.make_path_extender(buf_id)\n  else\n    -- Process unnamed buffer\n    label = H.make_unnamed_label(buf_id)\n    label_extender = function(x) return x end\n  end\n\n  return label, label_extender\nend\n\nH.make_path_extender = function(buf_id)\n  -- Add parent to current label (if possible)\n  return function(label)\n    local full_path = vim.api.nvim_buf_get_name(buf_id)\n    -- Using `vim.pesc` prevents effect of problematic characters (like '.')\n    local pattern = string.format('[^%s]+%s%s$', H.path_sep, H.path_sep, vim.pesc(label))\n    return string.match(full_path, pattern) or label\n  end\nend\n\n-- Work with unnamed buffers --------------------------------------------------\n-- Unnamed buffers are tracked in `H.unnamed_buffers_seq_ids` for\n-- disambiguation. This table is designed to store 'sequential' buffer\n-- identifier. This approach allows to have the following behavior:\n-- - Create three unnamed buffers.\n-- - Delete second one.\n-- - Tab label for third one remains the same.\nH.make_unnamed_label = function(buf_id)\n  local buftype = vim.bo[buf_id].buftype\n  -- Differentiate quickfix/location lists and scratch/other unnamed buffers\n  local label = buftype == 'quickfix'\n      -- There can be only one quickfix buffer and many location buffers\n      and (vim.fn.getqflist({ qfbufnr = true }).qfbufnr == buf_id and '*quickfix*' or '*location*')\n    or ((buftype == 'nofile' or buftype == 'acwrite') and '!' or '*')\n\n  -- Possibly add tracking id\n  local unnamed_id = H.get_unnamed_id(buf_id)\n  if unnamed_id > 1 then label = string.format('%s(%d)', label, unnamed_id) end\n\n  return label\nend\n\nH.get_unnamed_id = function(buf_id)\n  -- Use existing sequential id if possible\n  local seq_id = H.unnamed_buffers_seq_ids[buf_id]\n  if seq_id ~= nil then return seq_id end\n\n  -- Cache sequential id for currently unnamed buffer `buf_id`\n  H.unnamed_buffers_seq_ids[buf_id] = vim.tbl_count(H.unnamed_buffers_seq_ids) + 1\n  return H.unnamed_buffers_seq_ids[buf_id]\nend\n\n-- Work with labels -----------------------------------------------------------\nH.finalize_labels = function()\n  if #H.tabs == 0 then return end\n\n  -- Deduplicate\n  local nonunique_buf_ids = H.get_nonunique_buf_ids()\n  while #nonunique_buf_ids > 0 do\n    local nothing_changed = true\n\n    -- Extend labels\n    for _, buf_id in ipairs(nonunique_buf_ids) do\n      local tab = H.tabs[buf_id]\n      local old_label = tab.label\n      tab.label = tab.label_extender(tab.label)\n      if old_label ~= tab.label then nothing_changed = false end\n    end\n\n    if nothing_changed then break end\n\n    nonunique_buf_ids = H.get_nonunique_buf_ids()\n  end\n\n  -- Format labels\n  local config = H.get_config()\n\n  -- - Ensure cached `get_icon` for `default_format` (for better performance)\n  H.ensure_get_icon(config)\n\n  -- - Apply formatting\n  local format = config.format or MiniTabline.default_format\n  for _, tab in pairs(H.tabs) do\n    tab.label = format(tab.buf_id, tab.label)\n  end\nend\n\nH.get_nonunique_buf_ids = function()\n  local label_counts = {}\n  for _, tab in ipairs(H.tabs) do\n    label_counts[tab.label] = (label_counts[tab.label] or 0) + 1\n  end\n\n  local res = {}\n  for i, tab in ipairs(H.tabs) do\n    if label_counts[tab.label] > 1 then table.insert(res, i) end\n  end\n  return res\nend\n\n-- Fit tabline to maximum displayed width -------------------------------------\nH.fit_width = function()\n  if #H.tabs == 0 then return end\n\n  local cur_buf = vim.api.nvim_get_current_buf()\n  if vim.bo[cur_buf].buflisted then H.center_buf_id = cur_buf end\n\n  -- Compute label width data\n  local center_offset = 1\n  local tot_width = 0\n  for _, tab in pairs(H.tabs) do\n    tab.label_width = H.strwidth(tab.label)\n    tab.chars_on_left = tot_width\n\n    tot_width = tot_width + tab.label_width\n\n    if tab.buf_id == H.center_buf_id then\n      -- Make right end of 'center tab' to be always displayed in center in\n      -- case of truncation\n      center_offset = tot_width\n    end\n  end\n\n  local display_interval = H.compute_display_interval(center_offset, tot_width)\n\n  H.truncate_tabs_display(display_interval)\nend\n\nH.compute_display_interval = function(center_offset, tabline_width)\n  -- left - first character to be displayed (starts with 1)\n  -- right - last character to be displayed\n  -- Conditions to be satisfied:\n  -- 1) right - left + 1 = math.min(tot_width, tabline_width)\n  -- 2) 1 <= left <= tabline_width; 1 <= right <= tabline_width\n\n  local tot_width = vim.o.columns - H.strwidth(H.tabpage_section)\n\n  -- Usage of `math.floor` is crucial to avoid non-integer values which might\n  -- affect total width of output tabline string.\n  -- Using `floor` instead of `ceil` has effect when `tot_width` is odd:\n  -- - `floor` makes \"true center\" to be between second to last and last label\n  --   character (usually non-space and space).\n  -- - `ceil` - between last character of center label and first character of\n  --   next label (both whitespaces).\n  local right = math.min(tabline_width, math.floor(center_offset + 0.5 * tot_width))\n  local left = math.max(1, right - tot_width + 1)\n  right = left + math.min(tot_width, tabline_width) - 1\n\n  return { left, right }\nend\n\nH.truncate_tabs_display = function(display_interval)\n  local display_left, display_right = display_interval[1], display_interval[2]\n\n  local tabs, first, last = {}, nil, nil\n  for i, tab in ipairs(H.tabs) do\n    local tab_left = tab.chars_on_left + 1\n    local tab_right = tab.chars_on_left + tab.label_width\n    if (display_left <= tab_right) and (tab_left <= display_right) then\n      -- Process tab that should be displayed (even partially)\n      local n_trunc_left = math.max(0, display_left - tab_left)\n      local n_trunc_right = math.max(0, tab_right - display_right)\n\n      -- Take desired amount of characters starting from `n_trunc_left`\n      tab.label = vim.fn.strcharpart(tab.label, n_trunc_left, tab.label_width - n_trunc_right)\n\n      table.insert(tabs, tab)\n\n      -- Keep track of the shown tab range for truncation characters\n      first, last = first or i, i\n    end\n  end\n\n  -- Truncate first and/or last tabs if there is anything to the left/right\n  H.trunc.needs_left = H.trunc.left ~= '' and (first > 1 or H.strwidth(tabs[1].label) < tabs[1].label_width)\n  if H.trunc.needs_left then tabs[1].label = vim.fn.strcharpart(tabs[1].label, 1) end\n\n  local n = #tabs\n  H.trunc.needs_right = H.trunc.right ~= '' and (last < #H.tabs or H.strwidth(tabs[n].label) < tabs[n].label_width)\n  if H.trunc.needs_right then tabs[n].label = vim.fn.strcharpart(tabs[n].label, 0, H.strwidth(tabs[n].label) - 1) end\n\n  H.tabs = tabs\nend\n\nH.cache_trunc_chars = function()\n  local trunc_chars = { left = '', right = '' }\n  if vim.go.list then\n    local listchars = vim.go.listchars\n    trunc_chars.left = listchars:match('precedes:(.[^,]*)') or ''\n    trunc_chars.right = listchars:match('extends:(.[^,]*)') or ''\n  end\n  H.trunc = trunc_chars\nend\n\n-- Concatenate tabs into single tablien string --------------------------------\nH.concat_tabs = function()\n  -- NOTE: it is assumed that all padding is incorporated into labels\n  local t = {}\n  if H.trunc.needs_left then table.insert(t, '%#MiniTablineTrunc#' .. H.trunc.left:gsub('%%', '%%%%')) end\n  for _, tab in ipairs(H.tabs) do\n    -- Escape '%' in labels\n    table.insert(t, tab.hl .. tab.tabfunc .. tab.label:gsub('%%', '%%%%'))\n  end\n  if H.trunc.needs_right then table.insert(t, '%#MiniTablineTrunc#' .. H.trunc.right:gsub('%%', '%%%%')) end\n\n  -- Usage of `%X` makes filled space to the right \"non-clickable\"\n  local res = table.concat(t, '') .. '%X%#MiniTablineFill#'\n\n  -- Add tabpage section\n  if H.tabpage_section ~= '' then\n    local position = H.get_config().tabpage_section\n    if position == 'left' then res = '%#MiniTablineTabpagesection#' .. H.tabpage_section .. res end\n    if position == 'right' then res = res .. '%=%#MiniTablineTabpagesection#' .. H.tabpage_section end\n  end\n\n  return res\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.tabline) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.strwidth = function(x) return vim.api.nvim_strwidth(x) end\n\nH.ensure_get_icon = function(config)\n  if not config.show_icons then\n    -- Show no icon\n    H.get_icon = nil\n  elseif H.get_icon ~= nil then\n    -- Cache only once\n    return\n  elseif _G.MiniIcons ~= nil then\n    -- Prefer 'mini.icons'\n    H.get_icon = function(name) return (_G.MiniIcons.get('file', name)) end\n  else\n    -- Try falling back to 'nvim-web-devicons'\n    local has_devicons, devicons = pcall(require, 'nvim-web-devicons')\n    if not has_devicons then return end\n    -- Use basename because it makes exact file name matching work\n    H.get_icon = function(name) return (devicons.get_icon(vim.fn.fnamemodify(name, ':t'), nil, { default = true })) end\n  end\nend\n\nreturn MiniTabline\n"
  },
  {
    "path": "lua/mini/test.lua",
    "content": "--- *mini.test* Test Neovim plugins\n---\n--- MIT License Copyright (c) 2022 Evgeni Chasnovski\n\n--- Features:\n--- - Test action is defined as a named callable entry of a table.\n---\n--- - Helper for creating child Neovim process which is designed to be used in\n---   tests (including taking and verifying screenshots). See\n---   |MiniTest.new_child_neovim()| and |MiniTest.expect.reference_screenshot()|.\n---\n--- - Hierarchical organization of tests with custom hooks, parametrization,\n---   and user data. See |MiniTest.new_set()|.\n---\n--- - Emulation of [lunarmodules/busted](https://github.com/lunarmodules/busted)\n---   interface (`describe`, `it`, etc.).\n---\n--- - Predefined small yet usable set of expectations (`assert`-like functions).\n---   See |MiniTest.expect|.\n---\n--- - Customizable definition of what files should be tested.\n---\n--- - Test case filtering. There are predefined wrappers for testing a file\n---   (|MiniTest.run_file()|) and case at a location like current cursor position\n---   (|MiniTest.run_at_location()|).\n---\n--- - Customizable reporter of output results. There are two predefined ones:\n---     - |MiniTest.gen_reporter.buffer()| for interactive usage.\n---     - |MiniTest.gen_reporter.stdout()| for headless Neovim.\n---\n--- - Customizable project specific testing script.\n---\n--- - Works on Unix (Linux, MacOS, etc.) and Windows.\n---\n--- What it doesn't support:\n--- - Parallel execution. Due to idea of limiting implementation complexity.\n---\n--- - Mocks, stubs, etc. Use child Neovim process and manually override what is\n---   needed. Reset child process it afterwards.\n---\n--- - \"Overly specific\" expectations. Tests for (no) equality and (absence of)\n---   errors usually cover most of the needs. Adding new expectations is a\n---   subject to weighing its usefulness against additional implementation\n---   complexity. Use |MiniTest.new_expectation()| to create custom ones.\n---\n--- For more information see:\n--- - 'TESTING.md' file for a hands-on introduction based on examples.\n---\n--- - Code of this plugin's tests. Consider it to be an example of intended\n---   way to use 'mini.test' for test organization and creation.\n---\n--- # Workflow ~\n---\n--- - Organize tests in separate files. Each test file should return a test set\n---   (explicitly or implicitly by using \"busted\" style functions).\n---\n--- - Write test actions as callable entries of test set. Use child process\n---   inside test actions (see |MiniTest.new_child_neovim()|) and builtin\n---   expectations (see |MiniTest.expect|).\n---\n--- - Run tests. This does two steps:\n---     - *Collect*. This creates single hierarchical test set, flattens into\n---       array of test cases (see |MiniTest-test-case|) while expanding with\n---       parametrization, and possibly filters them.\n---     - *Execute*. This safely calls hooks and main test actions in specified\n---       order while allowing reporting progress in asynchronous fashion.\n---       Detected errors means test case fail; otherwise - pass.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.test').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniTest`\n--- which you can use for scripting or manually (with `:lua MiniTest.*`).\n---\n--- See |MiniTest.config| for available config settings.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minitest_config` which should have same structure as `MiniTest.config`.\n--- See |mini.nvim-buffer-local-config| for more details.\n---\n--- To stop module from showing non-error feedback, set `config.silent = true`.\n---\n--- # Comparisons ~\n---\n--- - Testing infrastructure from\n---   [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim):\n---     - Executes each file in separate headless Neovim process with customizable\n---       'init.vim' file. While 'mini.test' executes everything in current\n---       Neovim process encouraging writing tests with help of manually\n---       managed child Neovim process (see |MiniTest.new_child_neovim()|).\n---     - Tests are expected to be written with embedded simplified versions of\n---       'lunarmodules/busted' and 'lunarmodules/luassert'. While 'mini.test'\n---       uses concepts of test set (see |MiniTest.new_set()|) and test case\n---       (see |MiniTest-test-case|). It also can emulate bigger part of\n---       \"busted\" framework.\n---     - Has single way of reporting progress (shows result after every case\n---       without summary). While 'mini.test' can have customized reporters\n---       with defaults for interactive and headless usage (provide more\n---       compact and user-friendly summaries).\n---     - Allows parallel execution, while 'mini.test' does not.\n---     - Allows making mocks, stubs, and spies, while 'mini.test' does not in\n---       favor of manually overwriting functionality in child Neovim process.\n---\n--- Although 'mini.test' supports emulation of \"busted style\" testing, it will\n--- be more stable to use its designed approach of defining tests (with\n--- `MiniTest.new_set()` and explicit table fields). Couple of reasons:\n--- - \"Busted\" syntax doesn't support full capabilities offered by 'mini.test'.\n---   Mainly it is about parametrization and supplying user data to test sets.\n--- - It is an emulation, not full support. So some subtle things might not\n---   work the way you expect.\n---\n--- Some hints for converting from 'plenary.nvim' tests to 'mini.test':\n--- - Rename files from \"***_spec.lua\" to \"test_***.lua\" and put them in\n---   \"tests\" directory.\n--- - Replace `assert` calls with 'mini.test' expectations. See |MiniTest.expect|.\n--- - Create main test set `T = MiniTest.new_set()` and eventually return it.\n--- - Make new sets (|MiniTest.new_set()|) from `describe` blocks. Convert\n---   `before_each()` and `after_each` to `pre_case` and `post_case` hooks.\n--- - Make test cases from `it` blocks.\n---\n--- # Highlight groups ~\n---\n--- - `MiniTestEmphasis` - emphasis highlighting. By default it is a bold text.\n--- - `MiniTestFail` - highlighting of failed cases. By default it is a bold\n---   text with `vim.g.terminal_color_1` color (red).\n--- - `MiniTestPass` - highlighting of passed cases. By default it is a bold\n---   text with `vim.g.terminal_color_2` color (green).\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minitest_disable` (globally) or `vim.b.minitest_disable`\n--- (for a buffer) to `true`. Considering high number of different scenarios\n--- and customization intentions, writing exact rules for disabling module's\n--- functionality is left to user. See |mini.nvim-disabling-recipes| for common\n--- recipes.\n---@tag MiniTest\n\n---@alias __test_expect_fail_reason - <fail_reason> `(string|function)` - reason for failing expectation.\n---     a function is called with expectation input and should return a string.\n---     Default: `nil` for default reason like \"Failed expectation for ...\".\n\n-- Module definition ==========================================================\nlocal MiniTest = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniTest.config|.\n---\n---@usage >lua\n---   require('mini.test').setup() -- use default config\n---   -- OR\n---   require('mini.test').setup({}) -- replace {} with your config table\n--- <\nMiniTest.setup = function(config)\n  -- Export module\n  _G.MiniTest = MiniTest\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands()\n\n  -- Create default highlighting\n  H.create_default_hl()\nend\n\n--stylua: ignore start\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniTest.config = {\n  -- Options for collection of test cases. See `:h MiniTest.collect()`.\n  collect = {\n    -- Temporarily emulate functions from 'busted' testing framework\n    -- (`describe`, `it`, `before_each`, `after_each`, and more)\n    emulate_busted = true,\n\n    -- Function returning array of file paths to be collected.\n    -- Default: all Lua files in 'tests' directory starting with 'test_'.\n    find_files = function()\n      return vim.fn.globpath('tests', '**/test_*.lua', true, true)\n    end,\n\n    -- Predicate function indicating if test case should be executed\n    filter_cases = function(case) return true end,\n  },\n\n  -- Options for execution of test cases. See `:h MiniTest.execute()`.\n  execute = {\n    -- Table with callable fields `start()`, `update()`, and `finish()`\n    reporter = nil,\n\n    -- Whether to stop execution after first error\n    stop_on_error = false,\n  },\n\n  -- Path (relative to current directory) to script which handles project\n  -- specific test running\n  script_path = 'scripts/minitest.lua',\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n--minidoc_afterlines_end\n--stylua: ignore end\n\n-- Module data ================================================================\n--- Table with information about current state of test execution\n---\n--- Use it to examine result of |MiniTest.execute()|. It is reset at the\n--- beginning of every call.\n---\n--- At least these keys are supported:\n--- - <all_cases> - array with all cases being currently executed. Basically,\n---   an input of `MiniTest.execute()`.\n--- - <case> - currently executed test case. See |MiniTest-test-case|. Use it\n---   to customize execution output (like adding custom notes, etc).\nMiniTest.current = { all_cases = nil, case = nil }\n\n-- Module functionality =======================================================\n--- Create test set\n---\n--- Test set is one of the two fundamental data structures. It is a table that\n--- defines hierarchical test organization as opposed to sequential\n--- organization with |MiniTest-test-case|.\n---\n--- All its elements are one of three categories:\n--- - A callable (object that can be called; function or table with `__call`\n---   metatble entry) is considered to define a test action. It will be called\n---   with \"current arguments\" (result of all nested `parametrize` values, read\n---   further). If it throws error, test has failed.\n--- - A test set (output of this function) defines nested structure. Its\n---   options during collection (see |MiniTest.collect()|) will be extended\n---   with options of this (parent) test set.\n--- - Any other elements are considered helpers and don't directly participate\n---   in test structure.\n---\n--- Set options allow customization of test collection and execution (more\n--- details in `opts` description):\n--- - `hooks` - table with elements that will be called without arguments at\n---   predefined stages of test execution.\n--- - `parametrize` - array defining different arguments with which main test\n---   actions will be called. Any non-trivial parametrization will lead to\n---   every element (even nested) be \"multiplied\" and processed with every\n---   element of `parametrize`. This allows handling many different combination\n---   of tests with little effort.\n--- - `data` - table with user data that will be forwarded to cases. Primary\n---   objective is to be used for customized case filtering.\n---\n--- Notes:\n--- - Preferred way of adding elements is by using syntax `T[name] = element`.\n---   This way order of added elements will be preserved. Any other way won't\n---   guarantee any order.\n--- - Supplied options `opts` are stored in `opts` field of metatable\n---   (`getmetatable(set).opts`).\n---\n---@param opts table|nil Allowed options:\n---   - <hooks> - table with fields:\n---       - <pre_once> - executed before first filtered node.\n---       - <pre_case> - executed before each case (even nested).\n---       - <post_case> - executed after each case (even nested).\n---       - <post_once> - executed after last filtered node.\n---   - <parametrize> - array where each element is itself an array of\n---     parameters to be appended to \"current parameters\" of callable fields.\n---     Note: don't use plain `{}` as it is equivalent to \"parametrization into\n---     zero cases\", so no cases will be collected from this set. Calling test\n---     actions with no parameters is equivalent to `{{}}` or not supplying\n---     `parametrize` option at all.\n---   - <data> - user data to be forwarded to cases. Can be used for a more\n---     granular filtering.\n---   - <n_retry> - number of times to retry each case until success.\n---     Default: 1.\n---@param tbl table|nil Initial test items (possibly nested). Will be executed\n---   without any guarantees on order.\n---\n---@return table A single test set.\n---\n---@usage >lua\n---   -- Use with defaults\n---   T = MiniTest.new_set()\n---   T['works'] = function() MiniTest.expect.equality(1, 1) end\n---\n---   -- Use with custom options. This will result into two actual cases: first\n---   -- will pass, second - fail after two attempts.\n---   T['nested'] = MiniTest.new_set({\n---     hooks = { pre_case = function() _G.x = 1 end },\n---     parametrize = { { 1 }, { 2 } },\n---     n_retry = 2,\n---   })\n---\n---   T['nested']['works'] = function(x) MiniTest.expect.equality(_G.x, x) end\n--- <\nMiniTest.new_set = function(opts, tbl)\n  opts = opts or {}\n  tbl = tbl or {}\n\n  -- Keep track of new elements order. This allows to iterate through elements\n  -- in order they were added.\n  local metatbl = { class = 'testset', key_order = vim.tbl_keys(tbl), opts = opts }\n  metatbl.__newindex = function(t, key, value)\n    table.insert(metatbl.key_order, key)\n    rawset(t, key, value)\n  end\n\n  return setmetatable(tbl, metatbl)\nend\n\n--- Test case\n---\n--- An item of sequential test organization, as opposed to hierarchical with\n--- test set (see |MiniTest.new_set()|). It is created as result of test\n--- collection with |MiniTest.collect()| to represent all necessary information\n--- of test execution.\n---\n--- Execution of test case goes by the following rules:\n--- - Call functions in order:\n---     - All elements of `hooks.pre` from first to last without arguments.\n---     - Field `test` with arguments unpacked from `args`. If execution fails,\n---       retry it (along with hooks that come from `pre_case` and `post_case`)\n---       at most `n_retry` times until first success (if any).\n---     - All elements of `hooks.post` from first to last without arguments.\n--- - Error in any call gets appended to `exec.fails`, meaning error in any\n---   hook will lead to test fail.\n--- - State (`exec.state`) is changed before every call and after last call.\n---\n---@class Test-case\n---\n---@field args table Array of arguments with which `test` will be called.\n---@field data table User data: all fields of `opts.data` from nested test sets.\n---@field desc table Description: array of fields from nested test sets.\n---@field exec table|nil Information about test case execution. Value of `nil` means\n---   that this particular case was not (yet) executed. Has following fields:\n---   - <fails> - array of strings with failing information.\n---   - <notes> - array of strings with non-failing information.\n---   - <state> - state of test execution. One of:\n---       - 'Executing <name of what is being executed>' (during execution).\n---       - 'Pass' (no fails, no notes).\n---       - 'Pass with notes' (no fails, some notes).\n---       - 'Fail' (some fails, no notes).\n---       - 'Fail with notes' (some fails, some notes).\n---@field hooks table Hooks to be executed as part of test case. Has fields:\n---   - <pre> and <post> - arrays of functions to be consecutively executed\n---     before and after every execution of `test`.\n---   - <pre_source> and <post_source> - arrays of strings with sources of\n---     corresponding elements in <pre> and <post> arrays. Source is one of\n---     `\"once\"` (for `pre_once` and `post_once` hooks) and\n---     `\"case\"` (for `pre_case` and `post_case` hooks).\n---@field test function|table Main callable object representing test action.\n---@tag MiniTest-test-case\n\n--- Skip the rest of current case\n---\n--- Notes:\n--- - When called inside test case, stops execution while adding message to notes.\n--- - When called inside `pre_case` hook, registers skip at the start of its\n---   test case. Calling in other hooks has no effect.\n--- - Currently implemented as a specially handled type of error.\n---\n---@param msg string|nil Message to be added to current case notes.\nMiniTest.skip = function(msg)\n  H.cache.skip_message = msg or 'Skip test'\n  error(H.cache.skip_message, 0)\nend\n\n--- Add note to currently executed test case\n---\n--- Appends `msg` to `exec.notes` field of `case` in |MiniTest.current|.\n---\n---@param msg string Note to add.\nMiniTest.add_note = function(msg)\n  local case = MiniTest.current.case\n  case.exec = case.exec or {}\n  case.exec.notes = case.exec.notes or {}\n  table.insert(case.exec.notes, msg)\nend\n\n--- Register callable execution after current callable\n---\n--- Can be used several times inside hooks and main test callable of test case.\n---\n---@param f function|table Callable to be executed after current callable is\n---   finished executing (regardless of whether it ended with error or not).\nMiniTest.finally = function(f) table.insert(H.cache.finally, f) end\n\n--- Run tests\n---\n--- - Try executing project specific script at path `opts.script_path`. If\n---   successful (no errors), then stop.\n--- - Collect cases with |MiniTest.collect()| and `opts.collect`.\n--- - Execute collected cases with |MiniTest.execute()| and `opts.execute`.\n---\n---@param opts table|nil Options with structure similar to |MiniTest.config|.\n---   Absent values are inferred from there.\nMiniTest.run = function(opts)\n  if H.is_disabled() then return end\n\n  -- Try sourcing project specific script first\n  local success = H.execute_project_script(opts)\n  if success then return end\n\n  -- Collect and execute\n  opts = H.get_config(opts)\n  local cases = MiniTest.collect(opts.collect)\n  MiniTest.execute(cases, opts.execute)\nend\n\n--- Run specific test file\n---\n--- Basically a |MiniTest.run()| wrapper with custom `collect.find_files` option.\n---\n---@param file string|nil Path to test file. By default a path of current buffer.\n---@param opts table|nil Options for |MiniTest.run()|.\nMiniTest.run_file = function(file, opts)\n  file = vim.fn.fnamemodify(file or vim.api.nvim_buf_get_name(0), ':p:.')\n\n  local stronger_opts = { collect = { find_files = function() return { file } end } }\n  opts = vim.tbl_deep_extend('force', opts or {}, stronger_opts)\n\n  MiniTest.run(opts)\nend\n\n--- Run case(s) covering location\n---\n--- Try filtering case(s) covering location, meaning that definition of its\n--- main `test` action (as taken from builtin `debug.getinfo`) is located in\n--- specified file and covers specified line. Note that it can result in\n--- multiple cases if they come from parametrized test set (see `parametrize`\n--- option in |MiniTest.new_set()|).\n---\n--- Basically a |MiniTest.run()| wrapper with custom `collect.find_files` option.\n---\n---@param location table|nil Table with fields <file> (path to file) and <line>\n---   (line number in that file). Default is taken from current cursor position.\nMiniTest.run_at_location = function(location, opts)\n  if location == nil then\n    local cur_file = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(0), ':.')\n    local cur_pos = vim.api.nvim_win_get_cursor(0)\n    location = { file = cur_file, line = cur_pos[1] }\n  end\n\n  local stronger_opts = {\n    collect = {\n      find_files = function() return { location.file } end,\n      filter_cases = function(case)\n        local info = debug.getinfo(case.test)\n\n        return info.short_src == location.file\n          and info.linedefined <= location.line\n          and location.line <= info.lastlinedefined\n      end,\n    },\n  }\n  opts = vim.tbl_deep_extend('force', opts or {}, stronger_opts)\n\n  MiniTest.run(opts)\nend\n\n--- Collect test cases\n---\n--- Overview of collection process:\n--- - If `opts.emulate_busted` is `true`, temporary make special global\n---   functions (removed at the end of collection). They can be used inside\n---   test files to create hierarchical structure of test cases.\n--- - Source each file from array output of `opts.find_files`. It should output\n---   a test set (see |MiniTest.new_set()|) or `nil` (if \"busted\" style is used;\n---   test set is created implicitly).\n--- - Combine all test sets into single set with fields equal to its file path.\n--- - Convert from hierarchical test configuration to sequential: from single\n---   test set to array of test cases (see |MiniTest-test-case|). Conversion is\n---   done in the form of \"for every table element do: for every `parametrize`\n---   element do: ...\". Details:\n---     - If element is a callable, construct test case with it being main\n---       `test` action. Description is appended with key of element in current\n---       test set table. Hooks, arguments, and data are taken from \"current\n---       nested\" ones. Add case to output array.\n---     - If element is a test set, process it in similar, recursive fashion.\n---       The \"current nested\" information is expanded:\n---         - `args` is extended with \"current element\" from `parametrize`.\n---         - `desc` is appended with element key.\n---         - `hooks` are appended to their appropriate places. `*_case` hooks\n---           will be inserted closer to all child cases than hooks from parent\n---           test sets: `pre_case` at end, `post_case` at start.\n---         - `data` is extended via |vim.tbl_deep_extend()|.\n---     - Any other element is not processed.\n--- - Filter array with `opts.filter_cases`. Note that input case doesn't contain\n---   all hooks, as `*_once` hooks will be added after filtration.\n--- - Add `*_once` hooks to appropriate cases.\n---\n---@param opts table|nil Options controlling case collection. Possible fields:\n---   - <emulate_busted> - whether to emulate 'lunarmodules/busted' interface.\n---     It emulates these global functions: `describe`, `it`, `setup`, `teardown`,\n---     `before_each`, `after_each`. Use |MiniTest.skip()| instead of `pending()`\n---     and |MiniTest.finally()| instead of `finally`.\n---   - <find_files> - function which when called without arguments returns\n---     array with file paths. Each file should be a Lua file returning single\n---     test set or `nil`.\n---   - <filter_cases> - function which when called with single test case\n---     (see |MiniTest-test-case|) returns `false` if this case should be filtered\n---     out; `true` otherwise.\n---\n---@return table Array of test cases ready to be used by |MiniTest.execute()|.\nMiniTest.collect = function(opts)\n  opts = vim.tbl_deep_extend('force', H.get_config().collect, opts or {})\n\n  -- Make single test set\n  local set = MiniTest.new_set()\n\n  for _, file in ipairs(opts.find_files()) do\n    -- Possibly emulate 'busted' with current file. This allows to wrap all\n    -- implicit cases from that file into single set with file's name.\n    if opts.emulate_busted then\n      set[file] = MiniTest.new_set()\n      H.busted_emulate(set[file])\n    end\n\n    -- Execute file\n    local ok, t = pcall(dofile, file)\n\n    -- Catch errors\n    if not ok then\n      local msg = string.format('Sourcing %s resulted into following error: %s', vim.inspect(file), t)\n      H.error(msg)\n    end\n    local is_output_correct = (opts.emulate_busted and vim.tbl_count(set[file]) > 0) or H.is_instance(t, 'testset')\n    if not is_output_correct then\n      local msg = string.format(\n        [[%s does not define a test set. Did you return `MiniTest.new_set()` or created 'busted' tests?]],\n        vim.inspect(file)\n      )\n      H.error(msg)\n    end\n\n    -- If output is test set, always use it (even if 'busted' tests were added)\n    if H.is_instance(t, 'testset') then set[file] = t end\n  end\n\n  H.busted_deemulate()\n\n  -- Convert to test cases. This also creates separate aligned array of hooks\n  -- which should be executed once regarding test case. This is needed to\n  -- correctly inject those hooks after filtering is done.\n  local raw_cases, raw_hooks_once = H.set_to_testcases(set)\n\n  -- Filter cases (at this stage don't have injected `hooks_once`)\n  local cases, hooks_once = {}, {}\n  for i, c in ipairs(raw_cases) do\n    if opts.filter_cases(c) then\n      table.insert(cases, c)\n      table.insert(hooks_once, raw_hooks_once[i])\n    end\n  end\n\n  -- Inject `hooks_once` into appropriate cases\n  H.inject_hooks_once(cases, hooks_once)\n\n  return cases\nend\n\n--- Execute array of test cases\n---\n--- Overview of execution process:\n--- - Reset `all_cases` in |MiniTest.current| with `cases` input.\n--- - Call `reporter.start(cases)` (if present).\n--- - Execute each case in natural array order (aligned with their integer\n---   keys). Set `MiniTest.current.case` to currently executed case. Detailed\n---   test case execution is described in |MiniTest-test-case|. After any state\n---   change (including case retry attempts), call `reporter.update(case_num)`\n---   (if present), where `case_num` is an integer key of current test case.\n--- - Call `reporter.finish()` (if present).\n---\n--- Notes:\n--- - Execution is done in asynchronous fashion with scheduling. This allows\n---   making meaningful progress report during execution.\n--- - This function doesn't return anything. Instead, it updates `cases` in\n---   place with proper `exec` field. Use `all_cases` at |MiniTest.current| to\n---   look at execution result.\n---\n---@param cases table Array of test cases (see |MiniTest-test-case|).\n---@param opts table|nil Options controlling case collection. Possible fields:\n---   - <reporter> - table with possible callable fields `start`, `update`,\n---     `finish`. Default: |MiniTest.gen_reporter.buffer()| in interactive\n---     usage and |MiniTest.gen_reporter.stdout()| in headless usage.\n---   - <stop_on_error> - whether to stop execution (see |MiniTest.stop()|)\n---     after first error. Default: `false`.\nMiniTest.execute = function(cases, opts)\n  H.check_type('cases', cases, 'table')\n\n  MiniTest.current.all_cases = cases\n\n  -- Verify correct arguments\n  if #cases == 0 then\n    H.message('No cases to execute.')\n    return\n  end\n\n  opts = vim.tbl_deep_extend('force', H.get_config().execute, opts or {})\n  local reporter = opts.reporter or (H.is_headless and MiniTest.gen_reporter.stdout() or MiniTest.gen_reporter.buffer())\n  if type(reporter) ~= 'table' then\n    H.message('`opts.reporter` should be table or `nil`.')\n    return\n  end\n  opts.reporter = reporter\n\n  -- Start execution\n  H.cache = { is_executing = true }\n\n  vim.schedule(function() H.exec_callable(reporter.start, cases) end)\n\n  for case_num, cur_case in ipairs(cases) do\n    H.schedule_case(cur_case, case_num, opts)\n  end\n\n  vim.schedule(function() H.exec_callable(reporter.finish) end)\n  -- Use separate call to ensure that `reporter.finish` error won't interfere\n  vim.schedule(function() H.cache.is_executing = false end)\nend\n\n--- Stop test execution\n---\n---@param opts table|nil Options with fields:\n---   - <close_all_child_neovim> - whether to close all child neovim processes\n---     created with |MiniTest.new_child_neovim()|. Default: `true`.\nMiniTest.stop = function(opts)\n  opts = vim.tbl_deep_extend('force', { close_all_child_neovim = true }, opts or {})\n\n  -- Register intention to stop execution\n  H.cache.should_stop_execution = true\n\n  -- Possibly stop all child Neovim processes\n  if not opts.close_all_child_neovim then return end\n\n  for _, child in ipairs(H.child_neovim_registry) do\n    pcall(child.stop)\n  end\n  H.child_neovim_registry = {}\nend\n\n--- Check if tests are being executed\n---\n---@return boolean\nMiniTest.is_executing = function() return H.cache.is_executing == true end\n\n-- Expectations ---------------------------------------------------------------\n--- Table with expectation functions\n---\n--- Each function has the following behavior:\n--- - Silently returns `true` if expectation is fulfilled.\n--- - Throws an informative error with information helpful for debugging.\n---   Allows customizable fail reason to provide more context.\n---\n--- Mostly designed to be used within 'mini.test' framework.\n---\n---@usage >lua\n---   local x = 1 + 1\n---   MiniTest.expect.equality(x, 2) -- passes\n---   MiniTest.expect.equality(x, 1, { fail_reason = 'Not equal' }) -- fails\n--- <\nMiniTest.expect = {}\n\n--- Expect equality of two objects\n---\n--- Equality is tested via |vim.deep_equal()|. It also tries to compute more\n--- detailed cause for equality (for easier spotting the difference):\n--- - If they have different types.\n--- - For strings if they have different length or if some character is different.\n--- - For tables it shows a \"key branch\" at which values are different along with\n---   the actual values. A single difference is shown, there might be more.\n---   For not nested tables key branch is just a key. If the difference is inside\n---   nested tables, the key branch shows a \"path through nested tables\" to\n---   a different value. Examples: >lua\n---\n---     local eq = MiniTest.expect.equality\n---     eq({ 1, 2 }, { 1, 3 })         -- Key branch is `2`\n---     eq({ 1, { 2 } }, { 1, 'c' })   -- Key branch is `2` ('c' is not a table)\n---     eq({ 1, { 2 } }, { 1, { 3 } }) -- Key branch is `2->1`\n---\n---     -- Key branch is either `1->1->\"a\"` or `1->1->\"b\"`\n---     eq({ { { a = 1 } } }, { { { b = 2 } } })\n--- <\n---@param left any First object.\n---@param right any Second object.\n---@param opts table|nil Options. Possible fields:\n---   __test_expect_fail_reason\nMiniTest.expect.equality = function(left, right, opts)\n  if vim.deep_equal(left, right) then return true end\n\n  opts = opts or {}\n  local fail_reason = H.normalize_reason(opts.fail_reason, 'Failed expectation for equality', left, right)\n  local cause = H.compute_no_equality_cause(left, right)\n  local context = string.format('Cause: %s\\nLeft:  %s\\nRight: %s', cause, vim.inspect(left), vim.inspect(right))\n  H.error_with_emphasis(fail_reason, context)\nend\n\n--- Expect no equality of two objects\n---\n--- Equality is tested via |vim.deep_equal()|.\n---\n---@param left any First object.\n---@param right any Second object.\n---@param opts table|nil Options. Possible fields:\n---   __test_expect_fail_reason\nMiniTest.expect.no_equality = function(left, right, opts)\n  if not vim.deep_equal(left, right) then return true end\n\n  opts = opts or {}\n  local fail_reason = H.normalize_reason(opts.fail_reason, 'Failed expectation for *no* equality', left, right)\n  local context = string.format('Object: %s', vim.inspect(left))\n  H.error_with_emphasis(fail_reason, context)\nend\n\n--- Expect function call to raise error\n---\n---@param f function Function to be tested for raising error.\n---@param pattern string|nil Pattern which error message should match.\n---   Use `nil` or empty string to not test for pattern matching.\n---@param opts table|nil Options. Possible fields:\n---   __test_expect_fail_reason\nMiniTest.expect.error = function(f, pattern, opts, ...)\n  H.check_type('pattern', pattern, 'string', true)\n\n  -- Provide backward compatibility for `(f, pattern, ...)` signature.\n  -- TODO: Remove after releasing 'mini.nvim' 0.18.0\n  local args = { ... }\n  local is_valid_opts = type(opts) == 'table'\n    and (opts.fail_reason == nil or type(opts.fail_reason) == 'string' or vim.is_callable(opts.fail_reason))\n  if select('#', ...) > 0 or not (opts == nil or is_valid_opts) then\n    table.insert(args, 1, opts)\n    opts = {}\n    vim.notify(\n      '(mini.test) `expect.error` now does not accept extra arguments for tested function.'\n        .. \" It will mostly work until the next 'mini.nvim' release, but not after that.\"\n        .. ' Use them explicitly inside anonymous function: `expect.error(f, \"\", 1, 2)` ->'\n        .. ' `expect.error(function() f(1, 2) end, \"\")`.'\n        .. '\\nSorry for the inconvenience.',\n      vim.log.levels.WARN\n    )\n  end\n  local ok, err = pcall(f, unpack(args))\n\n  err = tostring(err)\n  local has_matched_error = not ok and string.find(err, pattern or '') ~= nil\n  if has_matched_error then return true end\n\n  opts = opts or {}\n  local pattern_suffix = pattern == nil and '' or (' matching pattern ' .. vim.inspect(pattern))\n  local fail_reason = H.normalize_reason(opts.fail_reason, 'Failed expectation for error' .. pattern_suffix, f, pattern)\n  local context = ok and 'Observed no error' or ('Observed error: ' .. err)\n  H.error_with_emphasis(fail_reason, context)\nend\n\n--- Expect function call to not raise error\n---\n---@param f function Function to be tested for not raising error.\n---@param opts table|nil Options. Possible fields:\n---   __test_expect_fail_reason\nMiniTest.expect.no_error = function(f, opts, ...)\n  -- Provide backward compatibility for `(f, ...)` signature.\n  -- TODO: Remove after releasing 'mini.nvim' 0.18.0\n  local args = { ... }\n  local is_valid_opts = type(opts) == 'table' and (opts.fail_prefix == nil or type(opts.fail_prefix) == 'string')\n  if select('#', ...) > 0 or not (opts == nil or is_valid_opts) then\n    table.insert(args, 1, opts)\n    opts = {}\n    vim.notify(\n      '(mini.test) `expect.no_error` now does not accept extra arguments for tested function.'\n        .. \" It will mostly work until the next 'mini.nvim' release, but not after that.\"\n        .. ' Use them explicitly inside anonymous function: `expect.no_error(f, 1, 2)` ->'\n        .. ' `expect.no_error(function() f(1, 2) end)`.'\n        .. '\\nSorry for the inconvenience.',\n      vim.log.levels.WARN\n    )\n  end\n  local ok, err = pcall(f, unpack(args))\n  if ok then return true end\n\n  opts = opts or {}\n  local fail_reason = H.normalize_reason(opts.fail_reason, 'Failed expectation for *no* error', f)\n  H.error_with_emphasis(fail_reason, 'Observed error: ' .. tostring(err))\nend\n\n--- Expect equality to reference screenshot\n---\n---@param screenshot table|nil Array with screenshot information. Usually an output\n---   of `child.get_screenshot()` (see |MiniTest-child-neovim-get_screenshot()|).\n---   If `nil`, expectation passed.\n---@param path string|nil Path to reference screenshot. If `nil`, constructed\n---   automatically in directory `opts.directory` from current case info and\n---   total number of times it was called inside current case. If there is no\n---   file at `path`, it is created with content of `screenshot`.\n---@param opts table|nil Options:\n---   - <force> `(boolean)` - whether to forcefully create reference screenshot.\n---     Temporary useful during test writing. Default: `false`.\n---   - <ignore_text> `(boolean|table)` - whether to ignore all or some text lines.\n---     If `true` - ignore all, if number array - ignore text of those lines,\n---     if `false` - do not ignore any. Default: `false`.\n---   - <ignore_attr> `(boolean|table)` - whether to ignore all or some attr lines.\n---     If `true` - ignore all, if number array - ignore attr of those lines,\n---     if `false` - do not ignore any. Default: `false`.\n---   - <directory> `(string)` - directory where automatically constructed `path`\n---     is located. Default: \"tests/screenshots\".\n---   __test_expect_fail_reason\nMiniTest.expect.reference_screenshot = function(screenshot, path, opts)\n  if screenshot == nil then return true end\n\n  local default_opts = { force = false, ignore_text = false, ignore_attr = false, directory = 'tests/screenshots' }\n  opts = vim.tbl_extend('force', default_opts, opts or {})\n\n  H.cache.n_screenshots = H.cache.n_screenshots + 1\n\n  if path == nil then\n    -- Sanitize path. Replace any control characters, whitespace, OS specific\n    -- forbidden characters with '-' (with some useful exception)\n    local linux_forbidden = [[/]]\n    local windows_forbidden = [[<>:\"/\\|?*]]\n    local pattern = string.format('[%%c%%s%s%s]', vim.pesc(linux_forbidden), vim.pesc(windows_forbidden))\n    local replacements = setmetatable({ ['\"'] = \"'\" }, { __index = function() return '-' end })\n    local name = H.case_to_stringid(MiniTest.current.case):gsub(pattern, replacements)\n\n    -- Don't end with whitespace or dot (forbidden on Windows)\n    name = name:gsub('[%s%.]$', '-')\n    path = vim.fs.normalize(opts.directory) .. '/' .. name\n\n    -- Deal with multiple screenshots\n    if H.cache.n_screenshots > 1 then path = path .. string.format('-%03d', H.cache.n_screenshots) end\n  end\n\n  -- If there is no readable screenshot file, create it. Pass with note.\n  if opts.force or vim.fn.filereadable(path) == 0 then\n    local dir_path = vim.fn.fnamemodify(path, ':p:h')\n    vim.fn.mkdir(dir_path, 'p')\n    H.screenshot_write(screenshot, path)\n\n    MiniTest.add_note('Created reference screenshot at path ' .. vim.inspect(path))\n    return true\n  end\n\n  local reference = H.screenshot_read(path)\n\n  -- Compare\n  local same_text, cause_text = H.screenshot_compare_part('text', reference, screenshot, opts)\n  local same_attr, cause_attr = H.screenshot_compare_part('attr', reference, screenshot, opts)\n  if same_text and same_attr then return true end\n\n  local fail_reason_fallback = 'Failed expectation for screenshot equality to reference at ' .. vim.inspect(path)\n  local fail_reason = H.normalize_reason(opts.fail_reason, fail_reason_fallback, screenshot, path)\n  local cause = same_text and cause_attr or cause_text\n  local context = string.format('%s\\nReference:\\n%s\\n\\nObserved:\\n%s', cause, tostring(reference), tostring(screenshot))\n  H.error_with_emphasis(fail_reason, context)\nend\n\n--- Create new expectation function\n---\n--- Helper for writing custom functions with behavior similar to other methods\n--- of |MiniTest.expect|.\n---\n---@param subject string|function|table Subject of expectation. If callable,\n---   called with expectation input arguments to produce string value.\n---@param predicate function|table Predicate callable. Called with expectation\n---   input arguments. Output `false` or `nil` means failed expectation.\n---@param fail_context string|function|table Information about fail. If callable,\n---   called with expectation input arguments to produce string value.\n---\n---@return function Expectation function.\n---\n---@usage >lua\n---   local expect_truthy = MiniTest.new_expectation(\n---     'truthy',\n---     function(x) return x end,\n---     function(x) return 'Object: ' .. vim.inspect(x) end\n---   )\n--- <\nMiniTest.new_expectation = function(subject, predicate, fail_context)\n  return function(...)\n    if predicate(...) then return true end\n\n    local cur_subject = vim.is_callable(subject) and subject(...) or subject\n    local cur_context = vim.is_callable(fail_context) and fail_context(...) or fail_context\n    H.error_with_emphasis('Failed expectation for ' .. cur_subject, cur_context)\n  end\nend\n\n-- Reporters ------------------------------------------------------------------\n--- Table with pre-configured report generators\n---\n--- Each element is a function which returns reporter - table with callable\n--- `start`, `update`, and `finish` fields.\nMiniTest.gen_reporter = {}\n\n--- Generate buffer reporter\n---\n--- This is a default choice for interactive (not headless) usage. Opens a window\n--- with dedicated non-terminal buffer and updates it with throttled redraws.\n---\n--- Opened buffer has the following helpful Normal mode mappings:\n--- - `<Esc>` - stop test execution if executing (see |MiniTest.is_executing()|\n---   and |MiniTest.stop()|). Close window otherwise.\n--- - `q` - same as `<Esc>` for convenience and compatibility.\n---\n--- General idea:\n--- - Group cases by concatenating first `opts.group_depth` elements of case\n---   description (`desc` field). Groups by collected files if using default values.\n--- - In `start()` show some stats to know how much is scheduled to be executed.\n--- - In `update()` show symbolic overview of current group and state of current\n---   case. Each symbol represents one case and its state:\n---     - `?` - case didn't finish executing.\n---     - `o` - pass.\n---     - `O` - pass with notes.\n---     - `x` - fail.\n---     - `X` - fail with notes.\n--- - In `finish()` show all fails and notes ordered by case.\n---\n---@param opts table|nil Table with options. Used fields:\n---   - <group_depth> - number of first elements of case description (can be zero)\n---     used for grouping. Higher values mean higher granularity of output.\n---     Default: 1.\n---   - <throttle_delay> - minimum number of milliseconds to wait between\n---     redrawing. Reduces screen flickering but not amount of computations.\n---     Default: 10.\n---   - <window> - definition of window to open. Can take one of the forms:\n---       - Callable. It is called expecting output to be target window id\n---         (current window is used if output is `nil`). Use this to open in\n---         \"normal\" window (like `function() vim.cmd('vsplit') end`).\n---       - Table. Used as `config` argument in |nvim_open_win()|.\n---     Default: table for centered floating window.\nMiniTest.gen_reporter.buffer = function(opts)\n  -- NOTE: another choice of implementing this is to use terminal buffer\n  -- `vim.api.nvim_open_term()`.\n  -- Pros:\n  -- - Renders ANSI escape sequences (mostly) correctly, i.e. no need in\n  --   replacing them with Neovim range highlights.\n  -- - This reporter and `stdout` one can share more of a codebase.\n  -- Cons:\n  -- - Couldn't manage to implement \"redraw on every update\".\n  -- - Extra steps still are needed in order to have richer output information.\n  --   This involves ANSI sequences that move cursor, which have same issues as\n  --   in `stdout`, albeit easier to overcome:\n  --     - Handling of scroll.\n  --     - Hard wrapping of lines leading to need of using window width.\n  local default_opts = { group_depth = 1, throttle_delay = 10, window = H.buffer_reporter.default_window_opts() }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  local buf_id, win_id\n  local is_valid_buf_win = function() return vim.api.nvim_buf_is_valid(buf_id) and vim.api.nvim_win_is_valid(win_id) end\n\n  -- Helpers\n  local set_cursor = function(line)\n    vim.api.nvim_win_set_cursor(win_id, { line or vim.api.nvim_buf_line_count(buf_id), 0 })\n  end\n\n  -- Define \"write from cursor line\" function with throttled redraw\n  local latest_draw_time = 0\n  local replace_last = function(n_replace, lines, force)\n    H.buffer_reporter.set_lines(buf_id, lines, -n_replace - 1, -1)\n\n    -- Throttle redraw to reduce flicker\n    local cur_time = vim.loop.hrtime()\n    local is_enough_time_passed = (cur_time - latest_draw_time) > opts.throttle_delay * 1000000\n    if is_enough_time_passed or force then\n      vim.cmd('redraw')\n      latest_draw_time = cur_time\n    end\n  end\n\n  -- Create reporter functions\n  local res = {}\n  local all_cases, all_groups, latest_group_name\n\n  res.start = function(cases)\n    -- Set up buffer and window\n    buf_id, win_id = H.buffer_reporter.setup_buf_and_win(opts.window)\n\n    -- Set up data (taking into account possible not first time run)\n    all_cases = cases\n    all_groups = H.overview_reporter.compute_groups(cases, opts.group_depth)\n    latest_group_name = nil\n\n    -- Write lines\n    local lines = H.overview_reporter.start_lines(all_cases, all_groups)\n    replace_last(1, lines)\n    set_cursor()\n  end\n\n  res.update = function(case_num)\n    if not is_valid_buf_win() then return end\n\n    local case, cur_group_name = all_cases[case_num], all_groups[case_num].name\n\n    -- Update symbol\n    local state = type(case.exec) == 'table' and case.exec.state or nil\n    all_groups[case_num].symbol = H.reporter_symbols[state]\n\n    local n_replace = H.buffer_reporter.update_step_n_replace(latest_group_name, cur_group_name)\n    local lines = H.buffer_reporter.update_step_lines(case_num, all_cases, all_groups)\n    replace_last(n_replace, lines)\n    set_cursor()\n\n    latest_group_name = cur_group_name\n  end\n\n  res.finish = function()\n    if not is_valid_buf_win() then return end\n\n    -- Cache final cursor position to overwrite 'Current case state' header\n    local start_line = vim.api.nvim_buf_line_count(buf_id) - 1\n\n    -- Force writing lines\n    local lines = H.overview_reporter.finish_lines(all_cases)\n    replace_last(2, lines, true)\n    set_cursor(start_line)\n  end\n\n  return res\nend\n\n--- Generate stdout reporter\n---\n--- This is a default choice for headless usage. Writes to `stdout`. Uses\n--- coloring ANSI escape sequences to make pretty and informative output\n--- (should work in most modern terminals and continuous integration providers).\n---\n--- It has same general idea as |MiniTest.gen_reporter.buffer()| with slightly\n--- less output (it doesn't overwrite previous text) to overcome typical\n--- terminal limitations.\n---\n---@param opts table|nil Table with options. Used fields:\n---   - <group_depth> - number of first elements of case description (can be zero)\n---     used for grouping. Higher values mean higher granularity of output.\n---     Default: 1.\n---   - <quit_on_finish> - whether to quit after finishing test execution.\n---     Default: `true`.\nMiniTest.gen_reporter.stdout = function(opts)\n  opts = vim.tbl_deep_extend('force', { group_depth = 1, quit_on_finish = true }, opts or {})\n\n  local write = function(text)\n    text = type(text) == 'table' and table.concat(text, '\\n') or text\n    io.stdout:write(text)\n    io.flush()\n  end\n\n  local all_cases, all_groups, latest_group_name\n  local default_symbol = H.reporter_symbols[nil]\n\n  local res = {}\n\n  res.start = function(cases)\n    -- Set up data\n    all_cases = cases\n    all_groups = H.overview_reporter.compute_groups(cases, opts.group_depth)\n\n    -- Write lines\n    local lines = H.overview_reporter.start_lines(all_cases, all_groups)\n    write(lines)\n  end\n\n  res.update = function(case_num)\n    local cur_case = all_cases[case_num]\n    local cur_group_name = all_groups[case_num].name\n\n    -- Possibly start overview of new group\n    if cur_group_name ~= latest_group_name then\n      write('\\n')\n      write(cur_group_name)\n      if cur_group_name ~= '' then write(': ') end\n    end\n\n    -- Possibly show new symbol\n    local state = type(cur_case.exec) == 'table' and cur_case.exec.state or nil\n    local cur_symbol = H.reporter_symbols[state]\n    if cur_symbol ~= default_symbol then write(cur_symbol) end\n\n    latest_group_name = cur_group_name\n  end\n\n  res.finish = function()\n    write('\\n\\n')\n    local lines = H.overview_reporter.finish_lines(all_cases)\n    write(lines)\n    write('\\n')\n\n    -- Possibly quit\n    if not opts.quit_on_finish then return end\n    local command = string.format('silent! %scquit', H.has_fails(all_cases) and 1 or 0)\n    vim.cmd(command)\n  end\n\n  return res\nend\n\n-- Exported utility functions -------------------------------------------------\n--- Create child Neovim process\n---\n--- This creates an object designed to be a fundamental piece of 'mini.test'\n--- methodology. It can start/stop/restart a separate (child) Neovim process\n--- (headless, but fully functioning) together with convenience helpers to\n--- interact with it through |RPC| messages.\n---\n--- For more information see |MiniTest-child-neovim|.\n---\n---@return MiniTest.child Object of |MiniTest-child-neovim|.\n---\n---@usage >lua\n---   -- Initiate\n---   local child = MiniTest.new_child_neovim()\n---   child.start()\n---\n---   -- Use API functions\n---   child.api.nvim_buf_set_lines(0, 0, -1, true, { 'Line inside child Neovim' })\n---\n---   -- Execute Lua code, Vimscript commands, etc.\n---   child.lua('_G.n = 0')\n---   child.cmd('au CursorMoved * lua _G.n = _G.n + 1')\n---   child.type_keys('l')\n---   print(child.lua_get('_G.n')) -- Should be 1\n---\n---   -- Use other `vim.xxx` Lua wrappers (executed inside child process)\n---   vim.b.aaa = 'current process'\n---   child.b.aaa = 'child process'\n---   print(child.lua_get('vim.b.aaa')) -- Should be 'child process'\n---\n---   -- Always stop process after it is not needed\n---   child.stop()\n--- <\nMiniTest.new_child_neovim = function()\n  local child = {}\n  local start_args, start_opts\n\n  local ensure_running = function()\n    if child.is_running() then return end\n    H.error('Child process is not running. Did you call `child.start()`?')\n  end\n\n  local prevent_hanging = function(method)\n    if not child.is_blocked() then return end\n\n    local msg = string.format('Can not use `child.%s` because child process is blocked.', method)\n    H.error_with_emphasis(msg)\n  end\n\n  -- Start headless Neovim instance\n  child.start = function(args, opts)\n    if child.is_running() then\n      H.message('Child process is already running. Use `child.restart()`.')\n      return\n    end\n\n    args = args or {}\n    opts = vim.tbl_deep_extend('force', { nvim_executable = vim.v.progpath, connection_timeout = 5000 }, opts or {})\n\n    -- Make unique name for `--listen` pipe\n    local job = { address = vim.fn.tempname() }\n\n    if vim.fn.has('win32') == 1 then\n      -- Use special local pipe prefix on Windows with (hopefully) unique name\n      -- Source: https://learn.microsoft.com/en-us/windows/win32/ipc/pipe-names\n      job.address = [[\\\\.\\pipe\\mininvim]] .. vim.fn.fnamemodify(job.address, ':t')\n    end\n\n    --stylua: ignore\n    local full_args = {\n      opts.nvim_executable, '--clean', '-n', '--listen', job.address,\n      -- Setting 'lines' and 'columns' makes headless process more like\n      -- interactive for closer to reality testing\n      '--headless', '--cmd', 'set lines=24 columns=80'\n    }\n    vim.list_extend(full_args, args)\n\n    -- Using 'jobstart' for creating a job is crucial for getting this to work\n    -- in Github Actions. Other approaches:\n    -- - Using `{ pty = true }` seems crucial to make this work on GitHub CI.\n    -- - Using `vim.loop.spawn()` is doable, but has some issues:\n    --     - https://github.com/neovim/neovim/issues/21630\n    --     - https://github.com/neovim/neovim/issues/21886\n    job.id = vim.fn.jobstart(full_args)\n\n    local step = 10\n    local connected, i, max_tries = nil, 0, math.floor(opts.connection_timeout / step)\n    repeat\n      i = i + 1\n      vim.loop.sleep(step)\n      connected, job.channel = pcall(vim.fn.sockconnect, 'pipe', job.address, { rpc = true })\n    until connected or i >= max_tries\n\n    if not connected then\n      local err = '  ' .. job.channel:gsub('\\n', '\\n  ')\n      H.error('Failed to make connection to child Neovim with the following error:\\n' .. err)\n      child.stop()\n    end\n\n    child.job = job\n    start_args, start_opts = args, opts\n  end\n\n  child.stop = function()\n    if not child.is_running() then return end\n\n    -- Properly exit Neovim. `pcall` avoids `channel closed by client` error.\n    -- Also wait for it to actually close. This reduces simultaneously opened\n    -- Neovim instances and CPU load (overall reducing flacky tests).\n    pcall(child.cmd, 'silent! 0cquit')\n    vim.fn.jobwait({ child.job.id }, 1000)\n\n    -- Close all used channels. Prevents `too many open files` type of errors.\n    pcall(vim.fn.chanclose, child.job.channel)\n    pcall(vim.fn.chanclose, child.job.id)\n\n    -- Remove file for address to reduce chance of \"can't open file\" errors, as\n    -- address uses temporary unique files\n    pcall(vim.fn.delete, child.job.address)\n\n    child.job = nil\n  end\n\n  child.restart = function(args, opts)\n    args = args or start_args\n    opts = vim.tbl_deep_extend('force', start_opts or {}, opts or {})\n\n    child.stop()\n    child.start(args, opts)\n  end\n\n  -- Wrappers for common `vim.xxx` objects (will get executed inside child)\n  child.api = setmetatable({}, {\n    __index = function(_, key)\n      ensure_running()\n      return function(...) return vim.rpcrequest(child.job.channel, key, ...) end\n    end,\n  })\n\n  -- Variant of `api` functions called with `vim.rpcnotify`. Useful for making\n  -- blocking requests (like `getcharstr()`).\n  child.api_notify = setmetatable({}, {\n    __index = function(_, key)\n      ensure_running()\n      return function(...) return vim.rpcnotify(child.job.channel, key, ...) end\n    end,\n  })\n\n  ---@return table Emulates `vim.xxx` table (like `vim.fn`)\n  ---@private\n  local redirect_to_child = function(tbl_name)\n    -- TODO: try to figure out the best way to operate on tables with function\n    -- values (needs \"deep encode/decode\" of function objects)\n    return setmetatable({}, {\n      __index = function(_, key)\n        ensure_running()\n\n        local short_name = ('%s.%s'):format(tbl_name, key)\n        local obj_name = ('vim[%s][%s]'):format(vim.inspect(tbl_name), vim.inspect(key))\n\n        prevent_hanging(short_name)\n        local value_type = child.api.nvim_exec_lua(('return type(%s)'):format(obj_name), {})\n\n        if value_type == 'function' then\n          -- This allows syntax like `child.fn.mode(1)`\n          return function(...)\n            prevent_hanging(short_name)\n            return child.api.nvim_exec_lua(('return %s(...)'):format(obj_name), { ... })\n          end\n        end\n\n        -- This allows syntax like `child.bo.buftype`\n        prevent_hanging(short_name)\n        return child.api.nvim_exec_lua(('return %s'):format(obj_name), {})\n      end,\n      __newindex = function(_, key, value)\n        ensure_running()\n\n        local short_name = ('%s.%s'):format(tbl_name, key)\n        local obj_name = ('vim[%s][%s]'):format(vim.inspect(tbl_name), vim.inspect(key))\n\n        -- This allows syntax like `child.b.aaa = function(x) return x + 1 end`\n        -- (inherits limitations of `string.dump`: no upvalues, etc.)\n        if type(value) == 'function' then\n          local dumped = vim.inspect(string.dump(value))\n          value = ('loadstring(%s)'):format(dumped)\n        else\n          value = vim.inspect(value)\n        end\n\n        prevent_hanging(short_name)\n        child.api.nvim_exec_lua(('%s = %s'):format(obj_name, value), {})\n      end,\n    })\n  end\n\n  --stylua: ignore start\n  local supported_vim_tables = {\n    -- Collections\n    'diagnostic', 'fn', 'highlight', 'hl', 'json', 'loop', 'lsp', 'mpack', 'spell', 'treesitter', 'ui', 'fs',\n    -- Variables\n    'g', 'b', 'w', 't', 'v', 'env',\n    -- Options (no 'opt' because not really useful due to use of metatables)\n    'o', 'go', 'bo', 'wo',\n  }\n  --stylua: ignore end\n  for _, v in ipairs(supported_vim_tables) do\n    child[v] = redirect_to_child(v)\n  end\n\n  -- Convenience wrappers\n  child.type_keys = function(wait, ...)\n    ensure_running()\n\n    local has_wait = type(wait) == 'number'\n    local keys = has_wait and { ... } or { wait, ... }\n    keys = H.tbl_flatten(keys)\n\n    -- From `nvim_input` docs: \"On execution error: does not fail, but\n    -- updates v:errmsg.\". So capture it manually. NOTE: Have it global to\n    -- allow sending keys which will block in the middle (like `[[<C-\\>]]` and\n    -- `<C-n>`). Otherwise, later check will assume that there was an error.\n    local cur_errmsg\n    for _, k in ipairs(keys) do\n      if type(k) ~= 'string' then\n        error('In `type_keys()` each argument should be either string or array of strings.')\n      end\n\n      -- But do that only if Neovim is not \"blocked\". Otherwise, usage of\n      -- `child.v` will block execution.\n      if not child.is_blocked() then\n        cur_errmsg = child.v.errmsg\n        child.v.errmsg = ''\n      end\n\n      -- Need to escape bare `<` (see `:h nvim_input`)\n      child.api.nvim_input(k == '<' and '<LT>' or k)\n\n      -- Possibly throw error manually\n      if not child.is_blocked() then\n        if child.v.errmsg ~= '' then\n          error(child.v.errmsg, 2)\n        else\n          child.v.errmsg = cur_errmsg or ''\n        end\n      end\n\n      -- Possibly wait\n      if has_wait and wait > 0 then vim.loop.sleep(wait) end\n    end\n  end\n\n  child.cmd = function(str)\n    ensure_running()\n    prevent_hanging('cmd')\n    return child.api.nvim_exec(str, false)\n  end\n\n  child.cmd_capture = function(str)\n    ensure_running()\n    prevent_hanging('cmd_capture')\n    return child.api.nvim_exec(str, true)\n  end\n\n  child.lua = function(str, args)\n    ensure_running()\n    prevent_hanging('lua')\n    return child.api.nvim_exec_lua(str, args or {})\n  end\n\n  child.lua_notify = function(str, args)\n    ensure_running()\n    return child.api_notify.nvim_exec_lua(str, args or {})\n  end\n\n  child.lua_get = function(str, args)\n    ensure_running()\n    prevent_hanging('lua_get')\n    return child.api.nvim_exec_lua('return ' .. str, args or {})\n  end\n\n  child.lua_func = function(f, ...)\n    ensure_running()\n    prevent_hanging('lua_func')\n    return child.api.nvim_exec_lua(\n      'local f = ...; return assert(loadstring(f))(select(2, ...))',\n      { string.dump(f), ... }\n    )\n  end\n\n  child.is_blocked = function()\n    ensure_running()\n    return child.api.nvim_get_mode()['blocking']\n  end\n\n  child.is_running = function() return child.job ~= nil end\n\n  -- Various wrappers\n  child.ensure_normal_mode = function()\n    ensure_running()\n    child.type_keys([[<C-\\>]], '<C-n>')\n  end\n\n  child.get_screenshot = function(opts)\n    ensure_running()\n    prevent_hanging('get_screenshot')\n\n    opts = vim.tbl_deep_extend('force', { redraw = true }, opts or {})\n\n    if opts.redraw then child.cmd('redraw') end\n\n    local res = child.lua([[\n      local text, attr = {}, {}\n      for i = 1, vim.o.lines do\n        local text_line, attr_line = {}, {}\n        for j = 1, vim.o.columns do\n          table.insert(text_line, vim.fn.screenstring(i, j))\n          table.insert(attr_line, vim.fn.screenattr(i, j))\n        end\n        table.insert(text, text_line)\n        table.insert(attr, attr_line)\n      end\n      return { text = text, attr = attr }\n    ]])\n    res.attr = H.screenshot_encode_attr(res.attr)\n\n    return H.screenshot_new(res)\n  end\n\n  -- Register `child` for automatic stop in case of emergency\n  table.insert(H.child_neovim_registry, child)\n\n  return child\nend\n\n--- Child class\n---\n--- It offers a great set of tools to write reliable and reproducible tests by\n--- allowing to use fresh process in any test action. Interaction with it is done\n--- through |RPC| protocol.\n---\n--- Although quite flexible, at the moment it has certain limitations:\n--- - Doesn't allow using functions or userdata for child's both inputs and\n---   outputs. Usual solution is to move computations from current Neovim process\n---   to child process. Use `child.lua()` and `child.lua_get()` for that.\n--- - When writing tests, it is common to end up with \"hanging\" process: it\n---   stops executing without any output. Most of the time it is because Neovim\n---   process is \"blocked\", i.e. it waits for user input and won't return from\n---   other call (like `child.api.nvim_exec_lua()`). Common causes are active\n---   |hit-enter-prompt| (increase prompt height to a bigger value) or\n---   Operator-pending mode (exit it). To mitigate this experience, most helpers\n---   will throw an error if its immediate execution will lead to hanging state.\n---   Also in case of hanging state try `child.api_notify` instead of `child.api`.\n---\n--- Notes:\n--- - An important type of field is a \"redirection table\". It acts as a\n---   convenience wrapper for corresponding `vim.*` table. Can be used both to\n---   return and set values. Examples:\n---     - `child.api.nvim_buf_line_count(0)` will execute\n---       `vim.api.nvim_buf_line_count(0)` inside child process and return its\n---       output to current process.\n---     - `child.bo.filetype = 'lua'` will execute `vim.bo.filetype = 'lua'`\n---       inside child process.\n---   They still have same limitations listed above, so are not perfect. In\n---   case of a doubt, use `child.lua()`.\n--- - Almost all methods use |vim.rpcrequest()| (i.e. wait for call to finish and\n---   then return value). See for `*_notify` variant to use |vim.rpcnotify()|.\n--- - All fields and methods should be called with `.`, not `:`.\n---\n---@class MiniTest.child\n---\n---@field start function Start child process. See |MiniTest-child-neovim-start()|.\n---@field stop function Stop current child process.\n---@field restart function Restart child process: stop if running and then\n---   start a new one. Takes same arguments as `child.start()` but uses values\n---   from most recent `start()` call as defaults.\n---\n---@field type_keys function Emulate typing keys.\n---   See |MiniTest-child-neovim-type_keys()|. Doesn't check for blocked state.\n---\n---@field cmd function Execute Vimscript code from a string.\n---   A wrapper for |nvim_exec()| without capturing output.\n---@field cmd_capture function Execute Vimscript code from a string and\n---   capture output. A wrapper for |nvim_exec()| with capturing output.\n---\n---@field lua function Execute Lua code. A wrapper for |nvim_exec_lua()|.\n---@field lua_notify function Execute Lua code without waiting for output.\n---@field lua_get function Execute Lua code and return result. A wrapper\n---   for |nvim_exec_lua()| but prepends string code with `return`.\n---@field lua_func function Execute Lua function and return it's result.\n---   Function will be called with all extra parameters (second one and later).\n---   Note: usage of upvalues (data from outside function scope) is not allowed.\n---\n---@field is_blocked function Check whether child process is blocked.\n---@field is_running function Check whether child process is currently running.\n---\n---@field ensure_normal_mode function Ensure normal mode.\n---@field get_screenshot function Returns table with two \"2d arrays\" of single\n---   characters representing what is displayed on screen and how it looks.\n---   Has `opts` table argument for optional configuratnion.\n---\n---@field job table|nil Information about current job. If `nil`, child is not running.\n---\n---@field api table Redirection table for `vim.api`. Doesn't check for blocked state.\n---@field api_notify table Same as `api`, but uses |vim.rpcnotify()|.\n---\n---@field diagnostic table Redirection table for |vim.diagnostic|.\n---@field fn table Redirection table for |vim.fn|.\n---@field highlight table Redirection table for |vim.highlight|.\n---@field hl table Redirection table for |vim.hl|.\n---@field json table Redirection table for `vim.json`.\n---@field loop table Redirection table for |vim.loop|.\n---@field lsp table Redirection table for `vim.lsp` (|lsp-core|).\n---@field mpack table Redirection table for |vim.mpack|.\n---@field spell table Redirection table for |vim.spell|.\n---@field treesitter table Redirection table for `vim.treesitter` (|lua-treesitter-core|).\n---@field ui table Redirection table for |vim.ui|. Currently of no\n---   use because it requires sending function through RPC, which is impossible\n---   at the moment.\n---@field fs table Redirection table for |vim.fs|.\n---\n---@field g table Redirection table for |vim.g|.\n---@field b table Redirection table for |vim.b|.\n---@field w table Redirection table for |vim.w|.\n---@field t table Redirection table for |vim.t|.\n---@field v table Redirection table for |vim.v|.\n---@field env table Redirection table for |vim.env|.\n---\n---@field o table Redirection table for |vim.o|.\n---@field go table Redirection table for |vim.go|.\n---@field bo table Redirection table for |vim.bo|.\n---@field wo table Redirection table for |vim.wo|.\n---@tag MiniTest-child-neovim\n\n---                           `child.start`({args}, {opts})\n---\n--- Start child process and connect to it. Won't work if child is already running.\n---\n---@param args table Array with arguments for executable. Will be prepended with\n---   the following default arguments (see |startup-options|): >lua\n---   { '--clean', '-n', '--listen', <some address>,\n---     '--headless', '--cmd', 'set lines=24 columns=80' }\n--- <\n---@param opts table|nil Options:\n---   - <nvim_executable> - name of Neovim executable. Default: |v:progpath|.\n---   - <connection_timeout> - stop trying to connect after this amount of\n---     milliseconds. Default: 5000.\n---\n---@usage >lua\n---   child = MiniTest.new_child_neovim()\n---\n---   -- Start default clean Neovim instance\n---   child.start()\n---\n---   -- Start with custom 'init.lua' file\n---   child.start({ '-u', 'scripts/minimal_init.lua' })\n--- <\n---@tag MiniTest-child-neovim-start()\n\n---                        `child.type_keys`({wait}, {...})\n---\n--- Basically a wrapper for |nvim_input()| applied inside child process.\n--- Differences:\n--- - Can wait after each group of characters.\n--- - Raises error if typing keys resulted into error in child process (i.e. its\n---   |v:errmsg| was updated).\n--- - Key '<' as separate entry may not be escaped as '<LT>'.\n---\n---@param wait number|nil Number of milliseconds to wait after each entry. May be\n---   omitted, in which case no waiting is done.\n---@param ... string|table<number,string> Separate entries for |nvim_input()|,\n---   after which `wait` will be applied. Can be either string or array of strings.\n---\n---@usage >lua\n---   -- All of these type keys 'c', 'a', 'w'\n---   child.type_keys('caw')\n---   child.type_keys('c', 'a', 'w')\n---   child.type_keys('c', { 'a', 'w' })\n---\n---   -- Waits 5 ms after `c` and after 'w'\n---   child.type_keys(5, 'c', { 'a', 'w' })\n---\n---   -- Special keys can also be used\n---   child.type_keys('i', 'Hello world', '<Esc>')\n--- <\n---@tag MiniTest-child-neovim-type_keys()\n\n---                         `child.get_screenshot`({opts})\n---\n--- Compute what is displayed on (default TUI) screen and how it is displayed.\n--- This basically calls |screenstring()| and |screenattr()| for every visible\n--- cell (row from 1 to 'lines', column from 1 to 'columns').\n---\n--- Notes:\n--- - To make output more portable and visually useful, outputs of\n---   `screenattr()` are coded with single character symbols. Those are taken from\n---   94 characters (ASCII codes between 33 and 126), so there will be duplicates\n---   in case of more than 94 different ways text is displayed on screen.\n---\n---@param opts table|nil Options. Possieble fields:\n---   - <redraw> `(boolean)` - whether to call |:redraw| prior to computing\n---     screenshot. Default: `true`.\n---\n---@return table|nil Screenshot table with the following fields:\n---   - <text> - \"2d array\" (row-column) of single characters displayed at\n---     particular cells.\n---   - <attr> - \"2d array\" (row-column) of symbols representing how text is\n---     displayed (basically, \"coded\" appearance/highlighting). They should be\n---     used only in relation to each other: same/different symbols for two\n---     cells mean same/different visual appearance. Note: there will be false\n---     positives if there are more than 94 different attribute values.\n---   It also can be used with `tostring()` to convert to single string (used\n---   for writing to reference file). It results into two visual parts\n---   (separated by empty line), for `text` and `attr`. Each part has \"ruler\"\n---   above content and line numbers for each line.\n---   Returns `nil` if couldn't get a reasonable screenshot.\n---\n---@usage >lua\n---   local screenshot = child.get_screenshot()\n---\n---   -- Show character displayed row=3 and column=4\n---   print(screenshot.text[3][4])\n---\n---   -- Convert to string\n---   tostring(screenshot)\n--- <\n---@tag MiniTest-child-neovim-get_screenshot()\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniTest.config)\n\n-- Whether instance is running in headless mode\nH.is_headless = #vim.api.nvim_list_uis() == 0\n\n-- Cache for various data\nH.cache = {\n  -- Message with which case is meant to be skipped\n  skip_message = nil,\n  -- Queue of callables to be executed after step (hook or test function)\n  finally = {},\n  -- Whether to stop async execution\n  should_stop_execution = false,\n  -- Number of screenshots made in current case\n  n_screenshots = 0,\n}\n\n-- Registry of all Neovim child processes\nH.child_neovim_registry = {}\n\n-- ANSI codes for common cases\nH.ansi_codes = {\n  fail = '\\27[1;31m', -- Bold red\n  pass = '\\27[1;32m', -- Bold green\n  emphasis = '\\27[1m', -- Bold\n  reset = '\\27[0m',\n}\n\n-- Highlight groups for common ANSI codes\nH.hl_groups = {\n  ['\\27[1;31m'] = 'MiniTestFail',\n  ['\\27[1;32m'] = 'MiniTestPass',\n  ['\\27[1m'] = 'MiniTestEmphasis',\n}\n\n-- Symbols used in reporter output\n--stylua: ignore\nH.reporter_symbols = setmetatable({\n  ['Pass']            = H.ansi_codes.pass .. 'o' .. H.ansi_codes.reset,\n  ['Pass with notes'] = H.ansi_codes.pass .. 'O' .. H.ansi_codes.reset,\n  ['Fail']            = H.ansi_codes.fail .. 'x' .. H.ansi_codes.reset,\n  ['Fail with notes'] = H.ansi_codes.fail .. 'X' .. H.ansi_codes.reset,\n}, {\n  __index = function() return H.ansi_codes.emphasis .. '?' .. H.ansi_codes.reset end,\n})\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('collect', config.collect, 'table')\n  H.check_type('collect.emulate_busted', config.collect.emulate_busted, 'boolean')\n  H.check_type('collect.find_files', config.collect.find_files, 'function')\n  H.check_type('collect.filter_cases', config.collect.filter_cases, 'function')\n\n  H.check_type('execute', config.execute, 'table')\n  H.check_type('execute.reporter', config.execute.reporter, 'table', true)\n  H.check_type('execute.stop_on_error', config.execute.stop_on_error, 'boolean')\n\n  H.check_type('script_path', config.script_path, 'string')\n  H.check_type('silent', config.silent, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config) MiniTest.config = config end\n\nH.create_autocommands = function()\n  local gr = vim.api.nvim_create_augroup('MiniTest', {})\n  vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })\nend\n\nH.create_default_hl = function()\n  local set_default_hl = function(name, data)\n    data.default = true\n    vim.api.nvim_set_hl(0, name, data)\n  end\n\n  set_default_hl('MiniTestFail', { fg = vim.g.terminal_color_1 or '#FF0000', bold = true })\n  set_default_hl('MiniTestPass', { fg = vim.g.terminal_color_2 or '#00FF00', bold = true })\n  set_default_hl('MiniTestEmphasis', { bold = true })\nend\n\nH.is_disabled = function() return vim.g.minitest_disable == true or vim.b.minitest_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniTest.config, vim.b.minitest_config or {}, config or {})\nend\n\n-- Work with collection -------------------------------------------------------\nH.busted_emulate = function(set)\n  local cur_set = set\n\n  _G.describe = function(name, f)\n    local cur_set_parent = cur_set\n    cur_set_parent[name] = MiniTest.new_set()\n    cur_set = cur_set_parent[name]\n    f()\n    cur_set = cur_set_parent\n  end\n\n  _G.it = function(name, f) cur_set[name] = f end\n\n  local setting_hook = function(hook_name)\n    return function(hook)\n      local metatbl = getmetatable(cur_set)\n      metatbl.opts.hooks = metatbl.opts.hooks or {}\n      metatbl.opts.hooks[hook_name] = hook\n    end\n  end\n\n  _G.setup = setting_hook('pre_once')\n  _G.before_each = setting_hook('pre_case')\n  _G.after_each = setting_hook('post_case')\n  _G.teardown = setting_hook('post_once')\nend\n\nH.busted_deemulate = function()\n  local fun_names = { 'describe', 'it', 'setup', 'before_each', 'after_each', 'teardown' }\n  for _, f_name in ipairs(fun_names) do\n    _G[f_name] = nil\n  end\nend\n\n-- Work with execution --------------------------------------------------------\nH.execute_project_script = function(...)\n  -- Don't process script if there are more than one active `run` calls\n  if H.is_inside_script then return false end\n\n  -- Don't process script if at least one argument is not default (`nil`)\n  if #{ ... } > 0 then return end\n\n  -- Store information\n  local config_cache = vim.deepcopy(MiniTest.config)\n  local local_config_cache = vim.b.minitest_config\n\n  -- Pass information to a possible `run()` call inside script\n  H.is_inside_script = true\n\n  -- Execute script\n  local success = pcall(vim.cmd, 'luafile ' .. H.get_config().script_path)\n\n  -- Restore information\n  MiniTest.config = config_cache\n  vim.b.minitest_config = local_config_cache\n  H.is_inside_script = nil\n\n  return success\nend\n\nH.schedule_case = function(case, case_num, opts)\n  local update_state = function(state)\n    case.exec.state = state\n    H.exec_callable(opts.reporter.update, case_num)\n  end\n\n  local is_case_executed = false\n  local on_err = function(e)\n    if H.cache.skip_message ~= nil then\n      -- Add skip message to notes (not fails) only during main case execution\n      if is_case_executed then\n        table.insert(case.exec.notes, H.cache.skip_message)\n        H.cache.skip_message = nil\n      end\n      return true\n    end\n\n    -- Append traceback to error message and indent lines for pretty print\n    local error_lines = { tostring(e), 'Traceback:', unpack(H.traceback()) }\n    local error_msg = table.concat(error_lines, '\\n'):gsub('\\n', '\\n  ')\n    table.insert(case.exec.fails, error_msg)\n\n    return false\n  end\n\n  local exec_step = function(f, state)\n    update_state(state)\n\n    H.cache.finally, H.cache.n_screenshots = {}, 0\n    local ok_f, ok_err = xpcall(f, on_err)\n\n    for _, fin in ipairs(H.cache.finally) do\n      H.exec_callable(fin)\n    end\n\n    return ok_f or ok_err\n  end\n\n  local exec_hooks = function(name, source)\n    local source_arr = case.hooks[name .. '_source']\n    local state_prefix = \"Executing '\" .. name .. \"' hook #\"\n    for i, h in ipairs(case.hooks[name]) do\n      if source_arr[i] == source then exec_step(h, state_prefix .. i) end\n    end\n  end\n\n  vim.schedule(function()\n    if H.cache.should_stop_execution then return end\n\n    case.exec = { fails = {}, notes = {} }\n    MiniTest.current.case = case\n\n    exec_hooks('pre', 'once')\n    local exec_data = case.exec\n\n    local ok_case\n    for cur_try = 1, case.n_retry do\n      -- Ensure that fails and notes are not accumulated during retries\n      case.exec = vim.deepcopy(exec_data)\n\n      -- Ensure that `skip()` affects only `pre_case` hooks and case\n      H.cache.skip_message = nil\n\n      -- Executing `*_case` hooks on every retry should ensure same case setup\n      -- (like cleanly restarted child process)\n      exec_hooks('pre', 'case')\n\n      local case_f = function() case.test(unpack(case.args)) end\n      if #case.exec.fails > 0 then\n        case_f = function() table.insert(case.exec.notes, 'Skip case due to error(s) in hooks.') end\n      end\n      if H.cache.skip_message ~= nil then case_f = function() MiniTest.skip(H.cache.skip_message) end end\n\n      is_case_executed = true\n      ok_case = exec_step(case_f, 'Executing test')\n      is_case_executed = false\n\n      exec_hooks('post', 'case')\n\n      if ok_case then break end\n    end\n\n    exec_hooks('post', 'once')\n\n    update_state(H.case_final_state(case))\n\n    if not ok_case and opts.stop_on_error then MiniTest.stop() end\n  end)\nend\n\n-- Work with test cases -------------------------------------------------------\n--- Convert test set to array of test cases\n---\n---@return ... Tuple of aligned arrays: with test cases and hooks that should\n---   be executed only once before corresponding item.\n---@private\nH.set_to_testcases = function(set, template, hooks_once)\n  template = template or { args = {}, desc = {}, hooks = { pre = {}, post = {} }, data = {}, n_retry = 1 }\n  hooks_once = hooks_once or { pre = {}, post = {} }\n\n  local metatbl = getmetatable(set)\n  local opts, key_order = metatbl.opts, metatbl.key_order\n  local hooks, parametrize, data, n_retry = opts.hooks or {}, opts.parametrize or { {} }, opts.data or {}, opts.n_retry\n\n  -- Convert to steps only callable or test set nodes\n  -- Ensure that all elements of `set` are being considered (might not be the\n  -- case if `table.insert` was used, for example)\n  key_order = H.ensure_all_vals(key_order, vim.tbl_keys(set))\n  local node_keys = vim.tbl_filter(function(key)\n    local node = set[key]\n    return vim.is_callable(node) or H.is_instance(node, 'testset')\n  end, key_order)\n\n  if #node_keys == 0 then return {}, {} end\n\n  -- Ensure that newly added hooks are represented by new functions.\n  -- This is needed to count them later only within current set. Example: use\n  -- the same function in several `_once` hooks. In `H.inject_hooks_once` it\n  -- will be injected only once overall whereas it should be injected only once\n  -- within corresponding test set.\n  hooks_once =\n    H.extend_hooks(hooks_once, { pre = H.wrap_callable(hooks.pre_once), post = H.wrap_callable(hooks.post_once) })\n\n  local testcase_arr, hooks_once_arr = {}, {}\n  -- Process nodes in order they were added as `T[...] = x`\n  for _, key in ipairs(node_keys) do\n    local node = set[key]\n    for _, args in ipairs(parametrize) do\n      if type(args) ~= 'table' then H.error('`parametrize` should have only tables. Got ' .. vim.inspect(args)) end\n\n      local cur_template = H.extend_template(template, {\n        args = args,\n        desc = type(key) == 'string' and key:gsub('\\n', '\\\\n') or key,\n        hooks = { pre = hooks.pre_case, post = hooks.post_case },\n        data = data,\n        n_retry = n_retry,\n      })\n\n      if vim.is_callable(node) then\n        table.insert(testcase_arr, H.new_testcase(cur_template, node))\n        table.insert(hooks_once_arr, hooks_once)\n      elseif H.is_instance(node, 'testset') then\n        local nest_testcase_arr, nest_hooks_once_arr = H.set_to_testcases(node, cur_template, hooks_once)\n        vim.list_extend(testcase_arr, nest_testcase_arr)\n        vim.list_extend(hooks_once_arr, nest_hooks_once_arr)\n      end\n    end\n  end\n\n  return testcase_arr, hooks_once_arr\nend\n\nH.ensure_all_vals = function(arr_subset, arr_all)\n  local vals_registry = {}\n  for _, v in ipairs(arr_subset) do\n    vals_registry[v] = true\n  end\n\n  for _, v in ipairs(arr_all) do\n    if not vals_registry[v] then\n      table.insert(arr_subset, v)\n      vals_registry[v] = true\n    end\n  end\n\n  return arr_subset\nend\n\nH.inject_hooks_once = function(cases, hooks_once)\n  -- NOTE: this heavily relies on the equivalence of \"have same object id\" and\n  -- \"are same hooks\"\n  local already_injected, n = {}, #cases\n\n  -- Inject 'pre' hooks moving forwards\n  for i = 1, n do\n    local case, hooks = cases[i], hooks_once[i].pre\n    case.hooks.pre_source = vim.tbl_map(function() return 'case' end, case.hooks.pre)\n    local target_tbl_id = 1\n    for j = 1, #hooks do\n      local h = hooks[j]\n      if not already_injected[h] then\n        table.insert(case.hooks.pre, target_tbl_id, h)\n        table.insert(case.hooks.pre_source, target_tbl_id, 'once')\n        target_tbl_id, already_injected[h] = target_tbl_id + 1, true\n      end\n    end\n  end\n\n  -- Inject 'post' hooks moving backwards\n  for i = n, 1, -1 do\n    local case, hooks = cases[i], hooks_once[i].post\n    case.hooks.post_source = vim.tbl_map(function() return 'case' end, case.hooks.post)\n    local target_tbl_id = #case.hooks.post + 1\n    for j = #hooks, 1, -1 do\n      local h = hooks[j]\n      if not already_injected[h] then\n        table.insert(case.hooks.post, target_tbl_id, h)\n        table.insert(case.hooks.post_source, target_tbl_id, 'once')\n        already_injected[h] = true\n      end\n    end\n  end\n\n  return cases\nend\n\nH.new_testcase = function(template, test)\n  template.test = test\n  return template\nend\n\nH.extend_template = function(template, layer)\n  local res = vim.deepcopy(template)\n\n  vim.list_extend(res.args, layer.args)\n  table.insert(res.desc, layer.desc)\n  res.hooks = H.extend_hooks(res.hooks, layer.hooks, false)\n  res.data = vim.tbl_deep_extend('force', res.data, layer.data)\n  res.n_retry = layer.n_retry or res.n_retry or 1\n\n  return res\nend\n\nH.extend_hooks = function(hooks, layer, do_deepcopy)\n  local res = hooks\n  if do_deepcopy == nil or do_deepcopy then res = vim.deepcopy(hooks) end\n\n  -- Closer (in terms of nesting) hooks should be closer to test callable\n  if vim.is_callable(layer.pre) then table.insert(res.pre, layer.pre) end\n  if vim.is_callable(layer.post) then table.insert(res.post, 1, layer.post) end\n\n  return res\nend\n\nH.case_to_stringid = function(case)\n  local desc = table.concat(case.desc, ' | ')\n  if #case.args == 0 then return desc end\n  local args = vim.inspect(case.args, { newline = '', indent = '' })\n  return ('%s + args %s'):format(desc, args)\nend\n\nH.case_final_state = function(case)\n  local pass_fail = #case.exec.fails == 0 and 'Pass' or 'Fail'\n  local with_notes = #case.exec.notes == 0 and '' or ' with notes'\n  return string.format('%s%s', pass_fail, with_notes)\nend\n\n-- Dynamic overview reporter --------------------------------------------------\nH.overview_reporter = {}\n\nH.overview_reporter.compute_groups = function(cases, group_depth)\n  local default_symbol = H.reporter_symbols[nil]\n  return vim.tbl_map(function(c)\n    local desc_trunc = vim.list_slice(c.desc, 1, group_depth)\n    local name = table.concat(desc_trunc, ' | ')\n    return { name = name, symbol = default_symbol }\n  end, cases)\nend\n\nH.overview_reporter.start_lines = function(cases, groups)\n  local unique_names = {}\n  for _, g in ipairs(groups) do\n    unique_names[g.name] = true\n  end\n  local n_groups = #vim.tbl_keys(unique_names)\n\n  return {\n    string.format('%s %s', H.add_style('Total number of cases:', 'emphasis'), #cases),\n    string.format('%s %s', H.add_style('Total number of groups:', 'emphasis'), n_groups),\n    '',\n  }\nend\n\nH.overview_reporter.finish_lines = function(cases)\n  -- Gather fails and notes (colored based on case fail/pass)\n  local fails, notes = {}, {}\n  local n_fails, n_notes = 0, 0\n  for _, c in ipairs(cases) do\n    local stringid = H.case_to_stringid(c)\n    local exec = c.exec == nil and { fails = {}, notes = {} } or c.exec\n\n    if #exec.fails > 0 then\n      table.insert(fails, '')\n      local fail_prefix = string.format('%s in %s: ', H.add_style('FAIL', 'fail'), stringid)\n      vim.list_extend(fails, H.add_prefix(exec.fails, fail_prefix))\n      n_fails = n_fails + #exec.fails\n    end\n\n    if #exec.notes > 0 then\n      table.insert(notes, '')\n      local note_color = #exec.fails > 0 and 'fail' or 'pass'\n      local note_prefix = string.format('%s in %s: ', H.add_style('NOTE', note_color), stringid)\n      vim.list_extend(notes, H.add_prefix(exec.notes, note_prefix))\n      n_notes = n_notes + #exec.notes\n    end\n  end\n\n  -- Show all fails first, then all notes\n  local header = string.format('Fails (%s) and Notes (%s)', n_fails, n_notes)\n  local res = { H.add_style(header, 'emphasis') }\n  vim.list_extend(res, fails)\n  vim.list_extend(res, notes)\n\n  return vim.split(table.concat(res, '\\n'), '\\n')\nend\n\n-- Buffer reporter utilities --------------------------------------------------\nH.buffer_reporter = { ns_id = vim.api.nvim_create_namespace('MiniTestBuffer'), n_buffer = 0 }\n\nH.buffer_reporter.setup_buf_and_win = function(window_opts)\n  local buf_id = vim.api.nvim_create_buf(true, true)\n  H.set_buf_name(buf_id, 'buffer-reporter')\n\n  local win_id\n  if vim.is_callable(window_opts) then\n    win_id = window_opts()\n  elseif type(window_opts) == 'table' then\n    -- Ensure proper title\n    if type(window_opts.title) == 'string' then\n      window_opts.title = H.fit_to_width(window_opts.title, window_opts.width)\n    end\n    win_id = vim.api.nvim_open_win(buf_id, true, window_opts)\n  end\n  win_id = win_id or vim.api.nvim_get_current_win()\n  vim.api.nvim_win_set_buf(win_id, buf_id)\n\n  H.buffer_reporter.set_options(buf_id, win_id)\n  H.buffer_reporter.set_mappings(buf_id)\n\n  return buf_id, win_id\nend\n\nH.buffer_reporter.default_window_opts = function()\n  return {\n    relative = 'editor',\n    width = math.floor(0.618 * vim.o.columns),\n    height = math.floor(0.618 * vim.o.lines),\n    row = math.floor(0.191 * vim.o.lines),\n    col = math.floor(0.191 * vim.o.columns),\n    border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil,\n    title = ' Test results ',\n  }\nend\n\nH.buffer_reporter.set_options = function(buf_id, win_id)\n  -- Set unique name\n  local n_buffer = H.buffer_reporter.n_buffer + 1\n  local suffix = n_buffer == 1 and '' or (' ' .. n_buffer)\n  H.buffer_reporter.n_buffer = n_buffer\n\n  vim.cmd('silent! set filetype=minitest')\n\n  --stylua: ignore start\n  -- Set options for \"temporary\" buffer\n  local buf_options = {\n    bufhidden = 'wipe', buflisted = false, buftype = 'nofile', modeline = false, swapfile = false,\n  }\n  for name, value in pairs(buf_options) do\n    vim.bo[buf_id][name] = value\n  end\n\n  -- Set options for \"clean\" window\n  local win_options = {\n    colorcolumn = '', fillchars = 'eob: ',    foldcolumn = '0', foldlevel = 999,\n    number = false,   relativenumber = false, spell = false,    signcolumn = 'no',\n    wrap = true,\n  }\n  for name, value in pairs(win_options) do\n    vim.wo[win_id][name] = value\n  end\n  --stylua: ignore end\nend\n\nH.buffer_reporter.set_mappings = function(buf_id)\n  local rhs = [[<Cmd>lua if MiniTest.is_executing() then MiniTest.stop() else vim.cmd('close') end<CR>]]\n  vim.keymap.set('n', '<Esc>', rhs, { buffer = buf_id, desc = 'Stop execution or close window' })\n  vim.keymap.set('n', 'q', rhs, { buffer = buf_id, desc = 'Stop execution or close window' })\nend\n\nH.buffer_reporter.set_lines = function(buf_id, lines, start, finish)\n  local ns_id = H.buffer_reporter.ns_id\n\n  local n_lines = vim.api.nvim_buf_line_count(buf_id)\n  start = (start < 0) and (n_lines + 1 + start) or start\n  finish = (finish < 0) and (n_lines + 1 + finish) or finish\n\n  -- Remove ANSI codes while tracking appropriate highlight data\n  local new_lines, hl_ranges = {}, {}\n  for i, l in ipairs(lines) do\n    local n_removed = 0\n    local new_l = l:gsub('\\n', '\\\\n'):gsub('()(\\27%[.-m)(.-)\\27%[0m', function(...)\n      local dots = { ... }\n      local left = dots[1] - n_removed\n      table.insert(\n        hl_ranges,\n        { hl = H.hl_groups[dots[2]], line = start + i - 1, left = left - 1, right = left + dots[3]:len() - 1 }\n      )\n\n      -- Here `4` is `string.len('\\27[0m')`\n      n_removed = n_removed + dots[2]:len() + 4\n      return dots[3]\n    end)\n    table.insert(new_lines, new_l)\n  end\n\n  -- Clear highlighting on updated lines. Crucial because otherwise it will\n  -- lead to A LOT of memory consumption.\n  vim.api.nvim_buf_clear_namespace(buf_id, H.buffer_reporter.ns_id, start, finish)\n\n  -- Set lines\n  vim.api.nvim_buf_set_lines(buf_id, start, finish, true, new_lines)\n\n  -- Add highlight\n  for _, hl_data in ipairs(hl_ranges) do\n    H.highlight_range(buf_id, ns_id, hl_data.hl, { hl_data.line, hl_data.left }, { hl_data.line, hl_data.right })\n  end\nend\n\nH.buffer_reporter.update_step_lines = function(case_num, cases, groups)\n  local cur_case = cases[case_num]\n  local cur_group = groups[case_num].name\n\n  -- Don't show anything before empty group name (when `group_depth` is 0)\n  local cur_group_suffix = cur_group == '' and '' or ': '\n  local cur_group_symbols = vim.tbl_map(\n    function(g) return g.symbol end,\n    vim.tbl_filter(function(g) return g.name == cur_group end, groups)\n  )\n\n  return {\n    -- Group overview\n    string.format('%s%s%s', cur_group, cur_group_suffix, table.concat(cur_group_symbols)),\n    '',\n    H.add_style('Current case state', 'emphasis'),\n    string.format('%s: %s', H.case_to_stringid(cur_case), cur_case.exec.state),\n  }\nend\n\nH.buffer_reporter.update_step_n_replace = function(latest_group_name, cur_group_name)\n  -- By default rewrite latest group symbol overview\n  local res = 4\n\n  if latest_group_name == nil then\n    -- Nothing to rewrite on first ever call\n    res = 0\n  elseif latest_group_name ~= cur_group_name then\n    -- Write just under latest group symbol overview\n    res = 3\n  end\n\n  return res\nend\n\n-- Predicates -----------------------------------------------------------------\nH.is_instance = function(x, class)\n  local metatbl = getmetatable(x)\n  return type(metatbl) == 'table' and metatbl.class == class\nend\n\nH.has_fails = function(cases)\n  for _, c in ipairs(cases) do\n    local n_fails = c.exec == nil and 0 or #c.exec.fails\n    if n_fails > 0 then return true end\n  end\n  return false\nend\n\n-- Expectation utilities ------------------------------------------------------\nH.normalize_reason = function(reason, fallback, ...)\n  if vim.is_callable(reason) then reason = reason(...) end\n  if type(reason) ~= 'string' then reason = fallback end\n  return reason\nend\n\nH.error_with_emphasis = function(msg, context)\n  local lines = { '', H.add_style(msg, 'emphasis'), context }\n  error(table.concat(lines, '\\n'), 0)\nend\n\nH.traceback = function()\n  local level, res = 1, {}\n  local info = debug.getinfo(level, 'Snl')\n  local this_short_src = info.short_src\n  while info ~= nil do\n    local is_from_file = info.source:sub(1, 1) == '@'\n    local is_from_this_file = info.short_src == this_short_src\n    if is_from_file and not is_from_this_file then\n      local line = string.format([[  %s:%s]], info.short_src, info.currentline)\n      table.insert(res, line)\n    end\n    level = level + 1\n    info = debug.getinfo(level, 'Snl')\n  end\n\n  return res\nend\n\nH.compute_no_equality_cause = function(left, right)\n  if type(left) ~= type(right) then return 'different types' end\n\n  if type(left) == 'string' then\n    if vim.fn.strchars(left) ~= vim.fn.strchars(right) then return 'different string length' end\n    for i = 1, vim.fn.strchars(left) do\n      local lchar, rchar = vim.fn.strcharpart(left, i - 1, 1), vim.fn.strcharpart(right, i - 1, 1)\n      if lchar ~= rchar then\n        return string.format('different character at position %s', i)\n          .. string.format(', left = %s, right = %s', vim.inspect(lchar), vim.inspect(rchar))\n      end\n    end\n  end\n\n  if type(left) ~= 'table' then return 'different values' end\n\n  -- Find key branch with different values\n  local traverse\n  traverse = function(branch, diff, a, b)\n    if not (type(a) == 'table' and type(b) == 'table') then return end\n    local keys = vim.tbl_keys(a)\n    table.sort(keys, function(x, y) return tostring(x) < tostring(y) end)\n    for _, k in ipairs(keys) do\n      if not vim.deep_equal(a[k], b[k]) then\n        table.insert(branch, k)\n        diff.left, diff.right = a[k], b[k]\n        return traverse(branch, diff, a[k], b[k])\n      end\n    end\n  end\n\n  -- - Traverse with both table orders to find the longest possible branch.\n  --   This also covers the \"present in one but not the other\" cases.\n  local left_branch, left_diff = {}, {}\n  traverse(left_branch, left_diff, left, right)\n  local right_branch, right_diff = {}, {}\n  traverse(right_branch, right_diff, right, left)\n\n  local branch, ldiff, rdiff = left_branch, left_diff.left, left_diff.right\n  if #left_branch < #right_branch then\n    branch, ldiff, rdiff = right_branch, right_diff.right, right_diff.left\n  end\n  ldiff = vim.inspect(ldiff, { newline = ' ', indent = '' })\n  rdiff = vim.inspect(rdiff, { newline = ' ', indent = '' })\n  local key_branch = table.concat(vim.tbl_map(vim.inspect, branch), '->')\n  return string.format('different values at key %s%s', #branch > 1 and 'branch ' or '', key_branch)\n    .. string.format(', left = %s, right = %s', ldiff, rdiff)\nend\n\n-- Screenshots ----------------------------------------------------------------\nH.screenshot_new = function(t)\n  local process_screen = function(arr_2d)\n    local n_lines, n_cols = #arr_2d, #arr_2d[1]\n\n    -- Prepend lines with line number of the form `01|`\n    local n_digits = math.floor(math.log10(n_lines)) + 1\n    local format = string.format('%%0%dd|%%s', n_digits)\n    local lines = {}\n    for i = 1, n_lines do\n      table.insert(lines, string.format(format, i, table.concat(arr_2d[i])))\n    end\n\n    -- Make ruler\n    local prefix = string.rep('-', n_digits) .. '|'\n    local ruler = prefix .. ('---------|'):rep(math.ceil(0.1 * n_cols)):sub(1, n_cols)\n\n    return string.format('%s\\n%s', ruler, table.concat(lines, '\\n'))\n  end\n\n  return setmetatable(t, {\n    __tostring = function(x) return string.format('%s\\n\\n%s', process_screen(x.text), process_screen(x.attr)) end,\n  })\nend\n\nH.screenshot_encode_attr = function(attr)\n  local attr_codes, res = {}, {}\n  -- Use 48 so that codes start from `'0'`\n  local cur_code_id = 48\n  for _, l in ipairs(attr) do\n    local res_line = {}\n    for _, s in ipairs(l) do\n      -- Assign character codes to numerical attributes in order of their\n      -- appearance on the screen. This leads to be a more reliable way of\n      -- comparing two different screenshots (at cost of bigger effect when\n      -- screenshot changes slightly).\n      if not attr_codes[s] then\n        attr_codes[s] = string.char(cur_code_id)\n        -- Cycle through 33...126\n        cur_code_id = math.fmod(cur_code_id + 1 - 33, 94) + 33\n      end\n      table.insert(res_line, attr_codes[s])\n    end\n    table.insert(res, res_line)\n  end\n\n  return res\nend\n\nH.screenshot_compare_part = function(part, ref, obs, opts)\n  local ignore_part = opts['ignore_' .. part]\n  if ignore_part == true then return true, '' end\n\n  local compare = function(x, y, desc)\n    if x == y then return true, '' end\n    return false, ('Cause: different %s, reference = %s, observed = %s'):format(desc, vim.inspect(x), vim.inspect(y))\n  end\n\n  local ok, cause\n  ok, cause = compare(#ref[part], #obs[part], 'number of `' .. part .. '` lines')\n  if not ok then return ok, cause end\n\n  local lines_to_check = {}\n  for i = 1, #ref[part] do\n    local is_ignore_part = type(ignore_part) == 'table' and vim.tbl_contains(ignore_part, i)\n    if not is_ignore_part then table.insert(lines_to_check, i) end\n  end\n\n  for _, i in ipairs(lines_to_check) do\n    ok, cause = compare(#ref[part][i], #obs[part][i], 'number of columns in `' .. part .. '` line ' .. i)\n    if not ok then return ok, cause end\n\n    for j = 1, #ref[part][i] do\n      ok, cause = compare(ref[part][i][j], obs[part][i][j], '`' .. part .. '` cell at line ' .. i .. ' column ' .. j)\n      if not ok then return ok, cause end\n    end\n  end\n\n  return true, ''\nend\n\nH.screenshot_write = function(screenshot, path) vim.fn.writefile(vim.split(tostring(screenshot), '\\n'), path) end\n\nH.screenshot_read = function(path)\n  -- General structure of screenshot with `n` lines:\n  -- 1: ruler-separator\n  -- 2, n+1: `prefix`|`text`\n  -- n+2: empty line\n  -- n+3: ruler-separator\n  -- n+4, 2n+3: `prefix`|`attr`\n  local lines = vim.fn.readfile(path)\n  local n = 0.5 * (#lines - 3)\n  local text_lines, attr_lines = vim.list_slice(lines, 2, n + 1), vim.list_slice(lines, n + 4, 2 * n + 3)\n\n  local f = function(x) return H.string_to_chars(x:gsub('^%d+|', '')) end\n  return H.screenshot_new({ text = vim.tbl_map(f, text_lines), attr = vim.tbl_map(f, attr_lines) })\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.test) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minitest://' .. buf_id .. '/' .. name) end\n\nH.echo = function(msg, is_important)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.test) ', 'WarningMsg' })\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(msg, is_important, {})\nend\n\nH.message = function(msg) H.echo(msg, true) end\n\nH.wrap_callable = function(f)\n  if not vim.is_callable(f) then return end\n  return function(...) return f(...) end\nend\n\nH.exec_callable = function(f, ...)\n  if not vim.is_callable(f) then return end\n  return f(...)\nend\n\nH.add_prefix = function(tbl, prefix)\n  return vim.tbl_map(function(x)\n    local p = prefix\n    -- Do not create trailing whitespace\n    if x:sub(1, 1) == '\\n' then p = p:gsub('%s*$', '') end\n    return ('%s%s'):format(p, x)\n  end, tbl)\nend\n\nH.add_style = function(x, ansi_code) return string.format('%s%s%s', H.ansi_codes[ansi_code], x, H.ansi_codes.reset) end\n\nH.fit_to_width = function(text, width)\n  local t_width = vim.fn.strchars(text)\n  return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))\nend\n\nH.string_to_chars = function(s)\n  -- Can't use `vim.split(s, '')` because of multibyte characters\n  local res = {}\n  for i = 1, vim.fn.strchars(s) do\n    table.insert(res, vim.fn.strcharpart(s, i - 1, 1))\n  end\n  return res\nend\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nH.tbl_flatten = vim.fn.has('nvim-0.10') == 1 and function(x) return vim.iter(x):flatten(math.huge):totable() end\n  or vim.tbl_flatten\n\n-- TODO: Remove after compatibility with Neovim=0.10 is dropped\nH.highlight_range = function(...) vim.hl.range(...) end\nif vim.fn.has('nvim-0.11') == 0 then H.highlight_range = function(...) vim.highlight.range(...) end end\n\nreturn MiniTest\n"
  },
  {
    "path": "lua/mini/trailspace.lua",
    "content": "--- *mini.trailspace* Trailspace (highlight and remove)\n---\n--- MIT License Copyright (c) 2021 Evgeni Chasnovski\n\n--- Features:\n--- - Highlighting is done only in modifiable buffer by default, only in Normal\n---   mode, and stops in Insert mode and when leaving window.\n---\n--- - Trim all trailing whitespace with |MiniTrailspace.trim()|.\n---\n--- - Trim all trailing empty lines with |MiniTrailspace.trim_last_lines()|.\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.trailspace').setup({})`\n--- (replace `{}` with your `config` table). It will create global Lua table\n--- `MiniTrailspace` which you can use for scripting or manually (with\n--- `:lua MiniTrailspace.*`).\n---\n--- See |MiniTrailspace.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minitrailspace_config` which should have same structure as\n--- `MiniTrailspace.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Highlight groups ~\n---\n--- - `MiniTrailspace` - highlight group for trailing space.\n---\n--- To change any highlight group, set it directly with |nvim_set_hl()|.\n---\n--- # Disabling ~\n---\n--- To disable, set `vim.g.minitrailspace_disable` (globally) or\n--- `vim.b.minitrailspace_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes. Note: after disabling\n--- there might be highlighting left; it will be removed after next\n--- highlighting update (see |events| and `MiniTrailspace` |:augroup|).\n---@tag MiniTrailspace\n\n-- Module definition ==========================================================\nlocal MiniTrailspace = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniTrailspace.config|.\n---\n---@usage >lua\n---   require('mini.trailspace').setup() -- use default config\n---   -- OR\n---   require('mini.trailspace').setup({}) -- replace {} with your config table\n--- <\nMiniTrailspace.setup = function(config)\n  -- Export module\n  _G.MiniTrailspace = MiniTrailspace\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\n\n  -- Create default highlighting\n  H.create_default_hl()\n\n  -- Initialize highlight (usually takes effect during startup)\n  vim.defer_fn(MiniTrailspace.highlight, 0)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nMiniTrailspace.config = {\n  -- Highlight only in normal buffers (ones with empty 'buftype'). This is\n  -- useful to not show trailing whitespace where it usually doesn't matter.\n  only_in_normal_buffers = true,\n}\n--minidoc_afterlines_end\n\n-- Module functionality =======================================================\n--- Highlight trailing whitespace in current window\nMiniTrailspace.highlight = function()\n  -- Highlight only in normal mode\n  if H.is_disabled() or vim.fn.mode() ~= 'n' then\n    MiniTrailspace.unhighlight()\n    return\n  end\n\n  -- Possibly work only in normal buffers\n  if H.get_config().only_in_normal_buffers and not H.is_buffer_normal() then return end\n\n  -- Don't add match id on top of existing one\n  if H.get_match_id() ~= nil then return end\n\n  vim.fn.matchadd('MiniTrailspace', [[\\s\\+$]])\nend\n\n--- Unhighlight trailing whitespace in current window\nMiniTrailspace.unhighlight = function()\n  -- Use `pcall` because there is an error if match id is not present. It can\n  -- happen if something else called `clearmatches`.\n  pcall(vim.fn.matchdelete, H.get_match_id())\nend\n\n--- Trim trailing whitespace\nMiniTrailspace.trim = function()\n  -- Save cursor position to later restore\n  local curpos = vim.api.nvim_win_get_cursor(0)\n  -- Search and replace trailing whitespace\n  vim.cmd([[keeppatterns %s/\\s\\+$//e]])\n  vim.api.nvim_win_set_cursor(0, curpos)\nend\n\n--- Trim last blank lines\nMiniTrailspace.trim_last_lines = function()\n  local n_lines = vim.api.nvim_buf_line_count(0)\n  local last_nonblank = vim.fn.prevnonblank(n_lines)\n  if last_nonblank < n_lines then vim.api.nvim_buf_set_lines(0, last_nonblank, n_lines, true, {}) end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = vim.deepcopy(MiniTrailspace.config)\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('only_in_normal_buffers', config.only_in_normal_buffers, 'boolean')\n\n  return config\nend\n\nH.apply_config = function(config) MiniTrailspace.config = config end\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniTrailspace', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  -- NOTE: Respecting both `WinEnter` and `BufEnter` seems to be useful to\n  -- account of different order of handling buffer opening in new window.\n  -- Notable example: 'nvim-tree' at commit a1600e5.\n  au({ 'WinEnter', 'BufEnter', 'InsertLeave' }, '*', MiniTrailspace.highlight, 'Highlight')\n  au({ 'WinLeave', 'BufLeave', 'InsertEnter' }, '*', MiniTrailspace.unhighlight, 'Unhighlight')\n\n  if config.only_in_normal_buffers then\n    -- Add tracking of 'buftype' changing because it can be set after events on\n    -- which highlighting is done. If not done, highlighting appears but\n    -- disappears if buffer is reentered.\n    au('OptionSet', 'buftype', H.track_normal_buffer, 'Track normal buffer')\n  end\n\n  au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')\nend\n\nH.create_default_hl = function() vim.api.nvim_set_hl(0, 'MiniTrailspace', { default = true, link = 'Error' }) end\n\nH.is_disabled = function() return vim.g.minitrailspace_disable == true or vim.b.minitrailspace_disable == true end\n\nH.get_config = function(config)\n  return vim.tbl_deep_extend('force', MiniTrailspace.config, vim.b.minitrailspace_config or {}, config or {})\nend\n\nH.track_normal_buffer = function()\n  if not H.get_config().only_in_normal_buffers then return end\n\n  -- This should be used with 'OptionSet' event for 'buftype' option\n  -- Empty 'buftype' means \"normal buffer\"\n  if vim.v.option_new == '' then\n    MiniTrailspace.highlight()\n  else\n    MiniTrailspace.unhighlight()\n  end\nend\n\nH.is_buffer_normal = function(buf_id) return vim.bo[buf_id or 0].buftype == '' end\n\nH.get_match_id = function()\n  -- NOTE: this can be replaced with more efficient custom tracking of id per\n  -- window but it will have more edge cases (like won't update on manual\n  -- `clearmatches()`)\n  for _, match in ipairs(vim.fn.getmatches()) do\n    if match.group == 'MiniTrailspace' then return match.id end\n  end\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.trailspace) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nreturn MiniTrailspace\n"
  },
  {
    "path": "lua/mini/visits.lua",
    "content": "--- *mini.visits* Track and reuse file system visits\n---\n--- MIT License Copyright (c) 2023 Evgeni Chasnovski\n\n--- Features:\n---\n--- - Persistently track file system visits (both files and directories)\n---   per project directory. Store visit index is human readable and editable.\n---\n--- - Visit index is normalized on every write to contain relevant information.\n---   Exact details can be customized. See |MiniVisits.normalize_index()|.\n---\n--- - Built-in ability to persistently add labels to path for later use.\n---   See |MiniVisits.add_label()| and |MiniVisits.remove_label()|.\n---\n--- - Exported functions to reuse visit data:\n---     - List visited paths/labels with custom filter and sort (uses \"robust\n---       frecency\" by default). Can be used as source for pickers.\n---       See |MiniVisits.list_paths()| and |MiniVisits.list_labels()|.\n---       See |MiniVisits.gen_filter| and |MiniVisits.gen_sort|.\n---\n---     - Select visited paths/labels using |vim.ui.select()|.\n---       See |MiniVisits.select_path()| and |MiniVisits.select_label()|.\n---\n---     - Iterate through visit paths in target direction (\"forward\", \"backward\",\n---       \"first\", \"last\"). See |MiniVisits.iterate_paths()|.\n---\n--- - Exported functions to manually update visit index allowing persistent\n---   track of any user information. See `*_index()` functions.\n---\n--- Notes:\n--- - All data is stored _only_ in in-session Lua variable (for quick operation)\n---   and at `config.store.path` on disk (for persistent usage).\n--- - Most of functions affect an in-session data which gets written to disk only\n---   before Neovim is closing or when users asks to.\n--- - It doesn't account for paths being renamed or moved (because there is no\n---   general way to detect that). Usually a manual intervention to the visit\n---   index is required after the change but _before_ the next writing to disk\n---   (usually before closing current session) because it will treat previous\n---   path as deleted and remove it from index.\n---   There is a |MiniVisits.rename_in_index()| helper for that.\n---   If rename/move is done with |mini.files|, index is autoupdated.\n---\n--- Sources with more details:\n--- - |MiniVisits-overview|\n--- - |MiniVisits-index-specification|\n--- - |MiniVisits-examples|\n---\n--- # Setup ~\n---\n--- This module needs a setup with `require('mini.visits').setup({})` (replace\n--- `{}` with your `config` table). It will create global Lua table `MiniVisits`\n--- which you can use for scripting or manually (with `:lua MiniVisits.*`).\n---\n--- See |MiniVisits.config| for `config` structure and default values.\n---\n--- You can override runtime config settings locally to buffer inside\n--- `vim.b.minivisits_config` which should have same structure as\n--- `MiniVisits.config`. See |mini.nvim-buffer-local-config| for more details.\n---\n--- # Comparisons ~\n---\n--- - [nvim-telescope/telescope-frecency.nvim](https://github.com/nvim-telescope/telescope-frecency.nvim):\n---     - It stores array of actual visit timestamps, while this module tracks\n---       only total number and latest timestamp of visits. This is by design\n---       as a different trade-off between how much data is being used/stored\n---       and complexity of underlying \"frecency\" sorting.\n---     - By default tracks a buffer only once per session, while this module\n---       tracks on every meaningful buffer enter. This leads to a more relevant\n---       in-session sorting.\n---     - Implements an original frecency algorithm of Firefox's address bar,\n---       while this module uses own \"robust frecency\" approach.\n---     - Mostly designed to work with 'nvim-telescope/telescope.nvim', while\n---       this module provides general function to list paths and select\n---       with |vim.ui.select()|.\n---     - Does not allow use of custom data (like labels), while this module does.\n---\n--- - [ThePrimeagen/harpoon](https://github.com/ThePrimeagen/harpoon):\n---     - Has slightly different concept than general labeling, which more\n---       resembles adding paths to an ordered stack. This module implements\n---       a more common labeling which does not imply order with ability to\n---       make it automated depending on the task and/or preference.\n---     - Implements marks as positions in a path, while this module labels paths.\n---     - Writes data on disk after every meaning change, while this module is\n---       more conservative and read only when Neovim closes or when asked to.\n---     - Has support for labeling terminals, while this modules is oriented\n---       only towards paths.\n---     - Has dedicated UI to manage marks, while this module does not by design.\n---       There are functions for adding and removing label from the path.\n---     - Does not provide functionality to track and reuse any visited path,\n---       while this module does.\n---\n--- # Disabling ~\n---\n--- To disable automated tracking, set `vim.g.minivisits_disable` (globally) or\n--- `vim.b.minivisits_disable` (for a buffer) to `true`. Considering high\n--- number of different scenarios and customization intentions, writing exact\n--- rules for disabling module's functionality is left to user. See\n--- |mini.nvim-disabling-recipes| for common recipes.\n---@tag MiniVisits\n\n--- # Tracking visits ~\n---\n--- File system visits (both directory and files) tracking is done in two steps:\n--- - On every dedicated event (`config.track.event`, |BufEnter| by default) timer\n---   is (re)started to actually register visit after certain amount of time\n---   (`config.track.delay` milliseconds, 1000 by default). It is not registered\n---   immediately to allow navigation to target buffer in several steps\n---   (for example, with series of |:bnext| / |:bprevious|).\n---\n--- - When delay time passes without any dedicated events being triggered\n---   (meaning user is \"settled\" on certain buffer), |MiniVisits.register_visit()|\n---   is called if all of the following conditions are met:\n---     - Module is not disabled (see \"Disabling\" section in |mini.visits|).\n---     - Buffer is normal with non-empty name (used as visit path).\n---     - Visit path does not equal to the latest tracked one. This is to allow\n---       temporary enter of non-normal buffers (like help, terminal, etc.)\n---       without artificial increase of visit count.\n---\n--- Visit is autoregistered for |current-directory| and leads to increase of count\n--- and latest time of visit. See |MiniVisits-index-specification| for more details.\n---\n--- Notes:\n--- - All data is stored _only_ in in-session Lua variable (for quick operation)\n---   and at `config.store.path` on disk (for persistent usage). It is automatically\n---   written to disk before every Neovim exit (if `config.store.autowrite` is set).\n---\n--- - Tracking can be disabled by supplying empty string as `track.event`.\n---   Then it is up to the user to properly call |MiniVisits.register_visit()|.\n---\n--- # Reusing visits ~\n---\n--- Visit data can be reused in at least these ways:\n---\n--- - Get a list of visited paths (see |MiniVisits.list_paths()|) and use it\n---   to visualize/pick/navigate visit history.\n---\n--- - Select one of the visited paths to open it (see |MiniVisits.select_path()|).\n---\n--- - Move along visit history (see |MiniVisits.iterate_paths()|).\n---\n--- - Utilize labels. Any visit can be added one or more labels (like \"core\",\n---   \"tmp\", etc.). They are bound to the visit (path registered for certain\n---   directory) and are stored persistently.\n---   Labels can be used to manually create groups of files and/or directories\n---   that have particular interest to the user.\n---   There is no one right way to use them, though. See |MiniVisits-examples|\n---   for some inspiration.\n---\n--- - Utilizing custom data. Visit index can be manipulated manually using\n---   `_index()` set of functions. All \"storable\" (i.e. not functions or\n---   metatables) user data inside index is then stored on disk, so it can be\n---   used to create any kind of workflow user wants.\n---\n--- See |MiniVisits-examples| for some actual configuration and workflow examples.\n---@tag MiniVisits-overview\n\n--- # Structure ~\n---\n--- Visit index is a table containing actual data in two level deep nested tables.\n---\n--- First level keys are paths of project directory (a.k.a \"cwd\") for which\n--- visits are registered.\n---\n--- Second level keys are actual visit paths. Their values are tables with visit\n--- data which should follow these requirements:\n--- - Field <count> should be present and be a number. It represents the number\n---   of times this path was visited under particular cwd.\n--- - Field <latest> should be present and be a number. It represents the time\n---   of latest path visit under particular cwd.\n---   By default computed with |os.time()| (up to a second).\n--- - Field <labels> might not be present. If present, it should be a table\n---   with string labels as keys and `true` as values. It represents labels of\n---   the path under particular cwd.\n---\n--- Notes:\n--- - All paths are absolute.\n--- - Visit path should not necessarily be a part of corresponding cwd.\n--- - Both `count` and `latest` can be any number: whole, fractional, negative, etc.\n---\n--- Example of an index data: >lua\n---\n---   {\n---     ['/home/user/project_1'] = {\n---       ['home/user/project_1/file'] = { count = 3, latest = 1699796000 },\n---       ['home/user/project_1/subdir'] = {\n---         count = 10, latest = 1699797000, labels = { core = true },\n---       },\n---     },\n---     ['/home/user/project_2'] = {\n---       ['home/user/project_1/file'] = {\n---         count = 0, latest = 0, labels = { other = true },\n---       },\n---       ['home/user/project_2/README'] = { count = 1, latest = 1699798000 },\n---     },\n---   }\n--- <\n--- # Storage ~\n---\n--- When stored on disk, visit index is a file containing Lua code returning\n--- visit index table. It can be edited by hand as long as it contains a valid\n--- Lua code (to be executed with |dofile()|).\n---\n--- Notes:\n--- - Storage is implemented in such a way that it doesn't really support more\n---   than one parallel Neovim processes. Meaning that if there are two or more\n---   simultaneous Neovim processes with same visit index storage path, the last\n---   one writing to it will preserve its visit history while others - won't.\n---\n--- # Normalization ~\n---\n--- To ensure that visit index contains mostly relevant data, it gets normalized:\n--- automatically inside |MiniVisits.write_index()| or\n--- via |MiniVisits.normalize_index()|.\n---\n--- What normalization actually does can be configured in `config.store.normalize`.\n---\n--- See |MiniVisits.gen_normalize.default()| for default normalization approach.\n---@tag MiniVisits-index-specification\n\n--- This module provides a flexible framework for working with file system visits.\n--- Exact choice of how to organize workflow is left to the user.\n--- Here are some examples for inspiration which can be combined together.\n---\n--- # Use different sorting ~\n---\n--- Default sorting in |MiniVisits.gen_sort.default()| allows flexible adjustment\n--- of which feature to prefer more: recency or frequency. Here is an example of\n--- how to make set of keymaps for three types of sorting combined with two types\n--- of scopes (all visits and only for current cwd): >lua\n---\n---   local make_select_path = function(select_global, recency_weight)\n---     local visits = require('mini.visits')\n---     local sort = visits.gen_sort.default({ recency_weight = recency_weight })\n---     local select_opts = { sort = sort }\n---     return function()\n---       local cwd = select_global and '' or vim.fn.getcwd()\n---       visits.select_path(cwd, select_opts)\n---     end\n---   end\n---\n---   local map = function(lhs, desc, ...)\n---     vim.keymap.set('n', lhs, make_select_path(...), { desc = desc })\n---   end\n---\n---   -- Adjust LHS and description to your liking\n---   map('<Leader>vr', 'Select recent (all)',   true,  1)\n---   map('<Leader>vR', 'Select recent (cwd)',   false, 1)\n---   map('<Leader>vy', 'Select frecent (all)',  true,  0.5)\n---   map('<Leader>vY', 'Select frecent (cwd)',  false, 0.5)\n---   map('<Leader>vf', 'Select frequent (all)', true,  0)\n---   map('<Leader>vF', 'Select frequent (cwd)', false, 0)\n--- <\n--- Note: If using |mini.pick|, consider |MiniExtra.pickers.visit_paths()|.\n---\n--- # Use manual labels ~\n---\n--- Labels is a powerful tool to create groups of associated paths.\n--- Usual workflow consists of:\n--- - Add label with |MiniVisits.add_label()| (prompts for actual label).\n--- - Remove label with |MiniVisits.remove_label()| (prompts for actual label).\n--- - When need to use labeled groups, call |MiniVisits.select_label()| which\n---   will then call |MiniVisits.select_path()| to select path among those\n---   having selected label.\n---   Note: If using |mini.pick|, consider |MiniExtra.pickers.visit_labels()|.\n---\n--- To make this workflow smoother, here is an example of keymaps: >lua\n---\n---   local map_vis = function(keys, call, desc)\n---     local rhs = '<Cmd>lua MiniVisits.' .. call .. '<CR>'\n---     vim.keymap.set('n', '<Leader>' .. keys, rhs, { desc = desc })\n---   end\n---\n---   map_vis('vv', 'add_label()',          'Add label')\n---   map_vis('vV', 'remove_label()',       'Remove label')\n---   map_vis('vl', 'select_label(\"\", \"\")', 'Select label (all)')\n---   map_vis('vL', 'select_label()',       'Select label (cwd)')\n--- <\n--- # Use fixed labels ~\n---\n--- During work on every project there is usually a handful of files where core\n--- activity is concentrated. This can be made easier by creating mappings\n--- which add/remove special fixed label (for example, \"core\") and select paths\n--- with that label for both all and current cwd. Example: >lua\n---\n---   -- Create and select\n---   local map_vis = function(keys, call, desc)\n---     local rhs = '<Cmd>lua MiniVisits.' .. call .. '<CR>'\n---     vim.keymap.set('n', '<Leader>' .. keys, rhs, { desc = desc })\n---   end\n---\n---   map_vis('vv', 'add_label(\"core\")',                     'Add to core')\n---   map_vis('vV', 'remove_label(\"core\")',                  'Remove from core')\n---   map_vis('vc', 'select_path(\"\", { filter = \"core\" })',  'Select core (all)')\n---   map_vis('vC', 'select_path(nil, { filter = \"core\" })', 'Select core (cwd)')\n---\n---   -- Iterate based on recency\n---   local sort_latest = MiniVisits.gen_sort.default({ recency_weight = 1 })\n---   local map_iterate_core = function(lhs, direction, desc)\n---     local opts = { filter = 'core', sort = sort_latest, wrap = true }\n---     local rhs = function()\n---       MiniVisits.iterate_paths(direction, vim.fn.getcwd(), opts)\n---     end\n---     vim.keymap.set('n', lhs, rhs, { desc = desc })\n---   end\n---\n---   map_iterate_core('[{', 'last',     'Core label (earliest)')\n---   map_iterate_core('[[', 'forward',  'Core label (earlier)')\n---   map_iterate_core(']]', 'backward', 'Core label (later)')\n---   map_iterate_core(']}', 'first',    'Core label (latest)')\n--- <\n--- # Use automated labels ~\n---\n--- When using version control system (such as Git), usually there is already\n--- an identifier that groups files you are working with - branch name.\n--- Here is an example of keymaps to add/remove label equal to branch name: >lua\n---\n---   local map_branch = function(keys, action, desc)\n---     local rhs = function()\n---       local branch = vim.fn.system('git rev-parse --abbrev-ref HEAD')\n---       if vim.v.shell_error ~= 0 then return nil end\n---       branch = vim.trim(branch)\n---       require('mini.visits')[action](branch)\n---     end\n---     vim.keymap.set('n', '<Leader>' .. keys, rhs, { desc = desc })\n---   end\n---\n---   map_branch('vb', 'add_label',    'Add branch label')\n---   map_branch('vB', 'remove_label', 'Remove branch label')\n--- <\n---@tag MiniVisits-examples\n\n---@alias __visits_path string|nil Visit path. Can be empty string to mean \"all visited\n---   paths for `cwd`\". Default: path of current buffer if normal, error otherwise.\n---@alias __visits_cwd string|nil Visit cwd (project directory). Can be empty string to mean\n---   \"all visited cwd\". Default: |current-directory|.\n---@alias __visits_filter - <filter> `(function)` - predicate to filter paths. For more information\n---     about how it is used, see |MiniVisits.config.list|.\n---     Default: value of `config.list.filter` with |MiniVisits.gen_filter.default()|\n---     as its default.\n---@alias __visits_sort - <sort> `(function)` - path data sorter. For more information about how\n---     it is used, see |MiniVisits.config.list|.\n---     Default: value of `config.list.sort` or |MiniVisits.gen_sort.default()|\n---     as its default.\n\n---@diagnostic disable:undefined-field\n---@diagnostic disable:discard-returns\n---@diagnostic disable:unused-local\n---@diagnostic disable:cast-local-type\n---@diagnostic disable:undefined-doc-name\n---@diagnostic disable:luadoc-miss-type-name\n\n-- Module definition ==========================================================\nlocal MiniVisits = {}\nlocal H = {}\n\n--- Module setup\n---\n---@param config table|nil Module config table. See |MiniVisits.config|.\n---\n---@usage >lua\n---   require('mini.visits').setup() -- use default config\n---   -- OR\n---   require('mini.visits').setup({}) -- replace {} with your config table\n--- <\nMiniVisits.setup = function(config)\n  -- Export module\n  _G.MiniVisits = MiniVisits\n\n  -- Setup config\n  config = H.setup_config(config)\n\n  -- Apply config\n  H.apply_config(config)\n\n  -- Define behavior\n  H.create_autocommands(config)\nend\n\n--- Defaults ~\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\n---@text # List ~\n--- *MiniVisits.config.list*\n---\n--- `config.list` defines how visit index is converted to a path list by default.\n---\n--- `list.filter` is a callable which should take a path data and return `true` if\n--- this path should be present in the list.\n--- Default: output of |MiniVisits.gen_filter.default()|.\n---\n--- Path data is a table with at least these fields:\n--- - <path> `(string)` - absolute path of visit.\n--- - <count> `(number)` - number of visits.\n--- - <latest> `(number)` - timestamp of latest visit.\n--- - <labels> `(table|nil)` - table of labels (has string keys with `true` values).\n---\n--- Notes:\n--- - Both `count` and `latest` (in theory) can be any number. But built-in tracking\n---   results into positive integer `count` and `latest` coming from |os.time()|.\n--- - There can be other entries if they are set by user as index entry.\n---\n--- `list.sort` is a callable which should take an array of path data and return\n--- a sorted array of path data (or at least tables each containing <path> field).\n--- Default: output of |MiniVisits.gen_sort.default()|.\n--- Single path data entry is a table with a same structure as for `list.filter`.\n---\n--- Note, that `list.sort` can be used both to filter, sort, or even return paths\n--- unrelated to the input.\n---\n--- # Silent ~\n---\n--- `config.silent` is a boolean controlling whether to show non-error feedback\n--- (like adding/removing labels, etc.). Default: `false`.\n---\n--- # Store ~\n---\n--- `config.store` defines how visit index is stored on disk to enable persistent\n--- data across several sessions.\n---\n--- `store.autowrite` is a boolean controlling whether to write visit data to\n--- disk on |VimLeavePre| event. Default: `true`.\n---\n--- `store.normalize` is a callable which should take visit index\n--- (see |MiniVisits-index-specification|) as input and return \"normalized\" visit\n--- index as output. This is used to ensure that visit index is up to date and\n--- contains only relevant data. For example, it controls how old and\n--- irrelevant visits are \"forgotten\", and more.\n--- Default: output of |MiniVisits.gen_normalize.default()|.\n---\n--- `store.path` is a path to which visit index is written. See \"Storage\" section\n--- of |MiniVisits-index-specification| for more details.\n--- Note: set to empty string to disable any writing with not explicitly set\n--- path (including the one on |VimLeavePre|).\n--- Default: \"mini-visits-index\" file inside |$XDG_DATA_HOME|.\n---\n--- # Track ~\n---\n--- `config.track` defines how visits are tracked (index entry is autoupdated).\n--- See \"Tracking visits\" section in |MiniVisits-overview| for more details.\n---\n--- `track.event` is a proper Neovim |{event}| on which track get triggered.\n--- Note: set to empty string to disable automated tracking.\n--- Default: |BufEnter|.\n---\n--- `track.delay` is a delay in milliseconds after event is triggered and visit\n--- is autoregistered.\n--- Default: 1000 (to allow navigation between buffers without tracking\n--- intermediate ones).\nMiniVisits.config = {\n  -- How visit index is converted to list of paths\n  list = {\n    -- Predicate for which paths to include (all by default)\n    filter = nil,\n\n    -- Sort paths based on the visit data (robust frecency by default)\n    sort = nil,\n  },\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n\n  -- How visit index is stored\n  store = {\n    -- Whether to write all visits before Neovim is closed\n    autowrite = true,\n\n    -- Function to ensure that written index is relevant\n    normalize = nil,\n\n    -- Path to store visit index\n    path = vim.fn.stdpath('data') .. '/mini-visits-index',\n  },\n\n  -- How visit tracking is done\n  track = {\n    -- Start visit register timer at this event\n    -- Supply empty string (`''`) to not do this automatically\n    event = 'BufEnter',\n\n    -- Debounce delay after event to register a visit\n    delay = 1000,\n  },\n}\n--minidoc_afterlines_end\n\n--- Register visit\n---\n--- Steps:\n--- - Ensure that there is an entry for path-cwd pair.\n--- - Add 1 to visit `count`.\n--- - Set `latest` visit time to equal current time.\n---\n---@param path string|nil Visit path. Default: path of current buffer if normal,\n---   error otherwise.\n---@param cwd string|nil Visit cwd (project directory). Default: |current-directory|.\nMiniVisits.register_visit = function(path, cwd)\n  path = H.validate_path(path)\n  cwd = H.validate_cwd(cwd)\n  if path == '' or cwd == '' then H.error('Both `path` and `cwd` should not be empty.') end\n\n  H.ensure_index_entry(path, cwd)\n  local path_tbl = H.index[cwd][path]\n  path_tbl.count = path_tbl.count + 1\n  path_tbl.latest = os.time()\nend\n\n--- Add path to index\n---\n--- Ensures that there is a (one or more) entry for path-cwd pair. If entry is\n--- already present, does nothing. If not - creates it with both `count` and\n--- `latest` set to 0.\n---\n---@param path __visits_path\n---@param cwd __visits_cwd\nMiniVisits.add_path = function(path, cwd)\n  path = H.validate_path(path)\n  cwd = H.validate_cwd(cwd)\n\n  local path_cwd_pairs = H.resolve_path_cwd(path, cwd)\n  for _, pair in ipairs(path_cwd_pairs) do\n    H.ensure_index_entry(pair.path, pair.cwd)\n  end\nend\n\n--- Add label to path\n---\n--- Steps:\n--- - Ensure that there is an entry for path-cwd pair.\n--- - Add label to the entry.\n---\n---@param label string|nil Label string. Default: `nil` to ask from user.\n---@param path __visits_path\n---@param cwd __visits_cwd\nMiniVisits.add_label = function(label, path, cwd)\n  path = H.validate_path(path)\n  cwd = H.validate_cwd(cwd)\n\n  if label == nil then\n    -- Suggest all labels from cwd in completion\n    label = H.get_label_from_user('Enter label to add', MiniVisits.list_labels('', cwd))\n    if label == nil then return end\n  end\n  label = H.validate_string(label, 'label')\n\n  -- Add label to all target path-cwd pairs\n  local path_cwd_pairs = H.resolve_path_cwd(path, cwd)\n  for _, pair in ipairs(path_cwd_pairs) do\n    H.ensure_index_entry(pair.path, pair.cwd)\n    local path_tbl = H.index[pair.cwd][pair.path]\n    local labels = path_tbl.labels or {}\n    labels[label] = true\n    path_tbl.labels = labels\n  end\n\n  H.echo(string.format('Added %s label.', vim.inspect(label)))\nend\n\n--- Remove path\n---\n--- Deletes a (one or more) entry for path-cwd pair from an index. If entry is\n--- already absent, does nothing.\n---\n--- Notes:\n--- - Affects only in-session Lua variable. Call |MiniVisits.write_index()| to\n---   make it persistent.\n---\n---@param path __visits_path\n---@param cwd __visits_cwd\nMiniVisits.remove_path = function(path, cwd)\n  path = H.validate_path(path)\n  cwd = H.validate_cwd(cwd)\n\n  -- Remove all target visits\n  H.ensure_read_index()\n  local path_cwd_pairs = H.resolve_path_cwd(path, cwd)\n  for _, pair in ipairs(path_cwd_pairs) do\n    local cwd_tbl = H.index[pair.cwd]\n    if type(cwd_tbl) == 'table' then cwd_tbl[pair.path] = nil end\n  end\n\n  for dir, _ in pairs(H.index) do\n    if vim.tbl_count(H.index[dir]) == 0 then H.index[dir] = nil end\n  end\nend\n\n--- Remove label from path\n---\n--- Steps:\n--- - Remove label from (one or more) index entry.\n--- - If it was last label in an entry, remove `labels` key.\n---\n---@param label string|nil Label string. Default: `nil` to ask from user.\n---@param path __visits_path\n---@param cwd __visits_cwd\nMiniVisits.remove_label = function(label, path, cwd)\n  path = H.validate_path(path)\n  cwd = H.validate_cwd(cwd)\n\n  if label == nil then\n    -- Suggest only labels from target path-cwd pairs\n    label = H.get_label_from_user('Enter label to remove', MiniVisits.list_labels(path, cwd))\n    if label == nil then return end\n  end\n  label = H.validate_string(label, 'label')\n\n  -- Remove label from all target path-cwd pairs (ignoring not present ones and\n  -- collapsing `labels` if removed last label)\n  H.ensure_read_index()\n  local path_cwd_pairs = H.resolve_path_cwd(path, cwd)\n  for _, pair in ipairs(path_cwd_pairs) do\n    local path_tbl = (H.index[pair.cwd] or {})[pair.path]\n    if type(path_tbl) == 'table' and type(path_tbl.labels) == 'table' then\n      path_tbl.labels[label] = nil\n      if vim.tbl_count(path_tbl.labels) == 0 then path_tbl.labels = nil end\n    end\n  end\n\n  H.echo(string.format('Removed %s label.', vim.inspect(label)))\nend\n\n--- List visit paths\n---\n--- Convert visit index for certain cwd into an ordered list of visited paths.\n--- Supports custom filtering and sorting.\n---\n--- Examples: >lua\n---\n---   -- Get paths sorted from most to least recent\n---   local sort_recent = MiniVisits.gen_sort.default({ recency_weight = 1 })\n---   MiniVisits.list_paths(nil, { sort = sort_recent })\n---\n---   -- Get paths from all cwd sorted from most to least frequent\n---   local sort_frequent = MiniVisits.gen_sort.default({ recency_weight = 0 })\n---   MiniVisits.list_paths('', { sort = sort_frequent })\n---\n---   -- Get paths not including hidden\n---   local is_not_hidden = function(path_data)\n---     return not vim.startswith(vim.fn.fnamemodify(path_data.path, ':t'), '.')\n---   end\n---   MiniVisits.list_paths(nil, { filter = is_not_hidden })\n--- <\n---@param cwd __visits_cwd\n---@param opts table|nil Options. Possible fields:\n---   __visits_filter\n---   __visits_sort\n---\n---@return table Array of visited paths.\nMiniVisits.list_paths = function(cwd, opts)\n  cwd = H.validate_cwd(cwd)\n\n  opts = vim.tbl_deep_extend('force', H.get_config().list, opts or {})\n  local filter = H.validate_filter(opts.filter)\n  local sort = H.validate_sort(opts.sort)\n\n  local path_data_arr = H.make_path_array('', cwd)\n  local res_arr = sort(vim.tbl_filter(filter, path_data_arr))\n  return vim.tbl_map(function(x) return x.path end, res_arr)\nend\n\n--- List visit labels\n---\n--- Convert visit index for certain path-cwd pair into an ordered list of labels.\n--- Supports custom filtering for paths. Result is ordered from most to least\n--- frequent label.\n---\n--- Examples: >lua\n---\n---   -- Get labels for current path-cwd pair\n---   MiniVisits.list_labels()\n---\n---   -- Get labels for current path across all cwd\n---   MiniVisits.list_labels(nil, '')\n---\n---   -- Get all available labels excluding ones from hidden files\n---   local is_not_hidden = function(path_data)\n---     return not vim.startswith(vim.fn.fnamemodify(path_data.path, ':t'), '.')\n---   end\n---   MiniVisits.list_labels('', '', { filter = is_not_hidden })\n--- <\n---@param path __visits_path\n---@param cwd __visits_cwd\n---@param opts table|nil Options. Possible fields:\n---   __visits_filter\n---   __visits_sort\n---\n---@return table Array of available labels.\nMiniVisits.list_labels = function(path, cwd, opts)\n  path = H.validate_path(path)\n  cwd = H.validate_cwd(cwd)\n\n  opts = vim.tbl_deep_extend('force', { filter = H.get_config().list.filter }, opts or {})\n  local filter = H.validate_filter(opts.filter)\n\n  local path_data_arr = H.make_path_array(path, cwd)\n  local res_arr = vim.tbl_filter(filter, path_data_arr)\n\n  -- Count labels\n  local label_counts = {}\n  for _, path_data in ipairs(res_arr) do\n    for label, _ in pairs(path_data.labels or {}) do\n      label_counts[label] = (label_counts[label] or 0) + 1\n    end\n  end\n\n  -- Sort from most to least common\n  local label_arr = {}\n  for label, count in pairs(label_counts) do\n    table.insert(label_arr, { count, label })\n  end\n  table.sort(label_arr, function(a, b) return a[1] > b[1] or (a[1] == b[1] and a[2] < b[2]) end)\n  return vim.tbl_map(function(x) return x[2] end, label_arr)\nend\n\n--- Select visit path\n---\n--- Uses |vim.ui.select()| with an output of |MiniVisits.list_paths()| and\n--- calls |:edit| on the chosen item.\n---\n--- Note: if you have |mini.pick|, consider using |MiniExtra.pickers.visit_labels()|\n--- and |MiniExtra.pickers.visit_paths()|.\n---\n--- Examples:\n---\n--- - Select from all visited paths: `MiniVisits.select_path('')`\n---\n--- - Select from paths under current directory sorted from most to least recent: >lua\n---\n---     local sort_recent = MiniVisits.gen_sort.default({ recency_weight = 1 })\n---     MiniVisits.select_path(nil, { sort = sort_recent })\n--- <\n---@param cwd string|nil Forwarded to |MiniVisits.list_paths()|.\n---@param opts table|nil Forwarded to |MiniVisits.list_paths()|.\nMiniVisits.select_path = function(cwd, opts)\n  local paths = MiniVisits.list_paths(cwd, opts)\n  local cwd_to_short = cwd == '' and vim.fn.getcwd() or cwd\n  local items = vim.tbl_map(function(path) return { path = path, text = H.short_path(path, cwd_to_short) } end, paths)\n  local select_opts = { prompt = 'Visited paths', format_item = function(item) return item.text end }\n  local on_choice = function(item) H.edit((item or {}).path) end\n\n  vim.ui.select(items, select_opts, on_choice)\nend\n\n--- Select visit label\n---\n--- Uses |vim.ui.select()| with an output of |MiniVisits.list_labels()| and\n--- calls |MiniVisits.select_path()| to get target paths with selected label.\n---\n--- Note: if you have |mini.pick|, consider using |MiniExtra.pickers.visit_labels()|.\n---\n--- Examples:\n---\n--- - Select from labels of current path: `MiniVisits.select_label()`\n---\n--- - Select from all visited labels: `MiniVisits.select_label('', '')`\n---\n--- - Select from current project labels and sort paths (after choosing) from most\n---   to least recent: >lua\n---\n---     local sort_recent = MiniVisits.gen_sort.default({ recency_weight = 1 })\n---     MiniVisits.select_label('', nil, { sort = sort_recent })\n--- <\n---@param path string|nil Forwarded to |MiniVisits.list_labels()|.\n---@param cwd string|nil Forwarded to |MiniVisits.list_labels()|.\n---@param opts table|nil Forwarded to both |MiniVisits.list_labels()|\n---  and |MiniVisits.select_path()| (after choosing a label).\nMiniVisits.select_label = function(path, cwd, opts)\n  local items = MiniVisits.list_labels(path, cwd, opts)\n  opts = opts or {}\n  local on_choice = function(label)\n    if label == nil then return end\n\n    -- Select among subset of paths with chosen label\n    local filter_cur = (opts or {}).filter or MiniVisits.gen_filter.default()\n    local new_opts = vim.deepcopy(opts)\n    new_opts.filter = function(path_data)\n      return filter_cur(path_data) and type(path_data.labels) == 'table' and path_data.labels[label]\n    end\n    MiniVisits.select_path(cwd, new_opts)\n  end\n\n  vim.ui.select(items, { prompt = 'Visited labels' }, on_choice)\nend\n\n--- Iterate visit paths\n---\n--- Steps:\n--- - Compute a sorted array of target paths using |MiniVisits.list_paths()|.\n--- - Identify the current index inside the array based on path of current buffer.\n--- - Iterate through the array certain amount of times in a dedicated direction:\n---     - For \"first\" direction - forward starting from index 0 (so that single\n---       first iteration leads to first path).\n---     - For \"backward\" direction - backward starting from current index.\n---     - For \"forward\" direction - forward starting from current index.\n---     - For \"last\" direction - backward starting from index after the last one\n---       (so that single first iteration leads to the last path).\n---\n--- Notes:\n--- - Mostly designed to be used as a mapping. See `MiniVisits-examples`.\n--- - If path from current buffer is not in the output of `MiniVisits.list_paths()`,\n---   starting index is inferred such that first iteration lands on first item\n---   (if iterating forward) or last item (if iterating backward).\n--- - Navigation with this function is not tracked (see |MiniVisits-overview|).\n---   This is done to allow consecutive application without affecting\n---   underlying list of paths.\n---\n--- Examples assuming underlying array of files `{ \"file1\", \"file2\", \"file3\" }`:\n---\n--- - `MiniVisits(\"first\")` results into focusing on \"file1\".\n--- - `MiniVisits(\"backward\", { n_times = 2 })` from \"file3\" results into \"file1\".\n--- - `MiniVisits(\"forward\", { n_times = 10 })` from \"file1\" results into \"file3\".\n--- - `MiniVisits(\"last\", { n_times = 4, wrap = true })` results into \"file3\".\n---\n---@param direction string One of \"first\", \"backward\", \"forward\", \"last\".\n---@param cwd string|nil Forwarded to |MiniVisits.list_paths()|.\n---@param opts table|nil Options. Possible fields:\n---   - <filter> `(function)` - forwarded to |MiniVisits.list_paths()|.\n---   - <sort> `(function)` - forwarded to |MiniVisits.list_paths()|.\n---   - <n_times> `(number)` - number of steps to go in certain direction.\n---     Default: |v:count1|.\n---   - <wrap> `(boolean)` - whether to wrap around list edges. Default: `false`.\nMiniVisits.iterate_paths = function(direction, cwd, opts)\n  if not (direction == 'first' or direction == 'backward' or direction == 'forward' or direction == 'last') then\n    H.error('`direction` should be one of \"first\", \"backward\", \"forward\", \"last\".')\n  end\n  local is_move_forward = (direction == 'first' or direction == 'forward')\n\n  local default_opts = { filter = nil, sort = nil, n_times = vim.v.count1, wrap = false }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n  local all_paths = MiniVisits.list_paths(cwd, { filter = opts.filter, sort = opts.sort })\n\n  local n_tot = #all_paths\n  if n_tot == 0 then return end\n\n  -- Compute current index\n  local cur_ind\n  if direction == 'first' then cur_ind = 0 end\n  if direction == 'last' then cur_ind = n_tot + 1 end\n  if direction == 'backward' or direction == 'forward' then\n    local cur_path = H.buf_get_path(vim.api.nvim_get_current_buf())\n    for i, path in ipairs(all_paths) do\n      if path == cur_path then\n        cur_ind = i\n        break\n      end\n    end\n  end\n\n  -- - If not on path from the list, make going forward start from the\n  --   beginning and backward - from end\n  if cur_ind == nil then cur_ind = is_move_forward and 0 or (n_tot + 1) end\n\n  -- Compute target index ensuring that it is inside `[1, #all_paths]`\n  local res_ind = cur_ind + opts.n_times * (is_move_forward and 1 or -1)\n  res_ind = opts.wrap and ((res_ind - 1) % n_tot + 1) or math.min(math.max(res_ind, 1), n_tot)\n\n  -- Open path with no visit track (for default `track.event`)\n  -- Use `vim.g` instead of `vim.b` to not register in **next** buffer\n  local cache_disabled = vim.g.minivisits_disable\n  vim.g.minivisits_disable = true\n  H.edit(all_paths[res_ind])\n  vim.g.minivisits_disable = cache_disabled\nend\n\n--- Get active visit index\n---\n---@return table Copy of currently active visit index table.\nMiniVisits.get_index = function()\n  H.ensure_read_index()\n  return vim.deepcopy(H.index)\nend\n\n--- Set active visit index\n---\n---@param index table Visit index table.\nMiniVisits.set_index = function(index)\n  H.validate_index(index, '`index`')\n  H.index = vim.deepcopy(index)\n  H.cache.needs_index_read = false\nend\n\n--- Reset active visit index\n---\n--- Set currently active visit index to the output of |MiniVisits.read_index()|.\n--- Does nothing if reading the index failed.\nMiniVisits.reset_index = function()\n  local ok, stored_index = pcall(MiniVisits.read_index)\n  if not ok or stored_index == nil then return end\n  MiniVisits.set_index(stored_index)\nend\n\n--- Normalize visit index\n---\n--- Applies `config.store.normalize` (|MiniVisits.gen_normalize.default()| by default)\n--- to the input index object and returns the output (if it fits in the definition\n--- of index object; see |MiniVisits-index-specification|).\n---\n---@param index table|nil Index object. Default: copy of the current index.\n---\n---@return table Normalized index object.\nMiniVisits.normalize_index = function(index)\n  index = index or MiniVisits.get_index()\n  H.validate_index(index, '`index`')\n\n  local config = H.get_config()\n  local normalize = config.store.normalize\n  if not vim.is_callable(normalize) then normalize = MiniVisits.gen_normalize.default() end\n  local new_index = normalize(vim.deepcopy(index))\n  H.validate_index(new_index, '`index` after normalization')\n\n  return new_index\nend\n\n--- Read visit index from disk\n---\n---@param store_path string|nil Path on the disk containing visit index data.\n---   Default: `config.store.path`.\n---   Notes:\n---   - Can return `nil` if path is empty string or file is not readable.\n---   - File is sourced with |dofile()| as a regular Lua file.\n---\n---@return table|nil Output of the file source.\nMiniVisits.read_index = function(store_path)\n  store_path = store_path or H.get_config().store.path\n  if store_path == '' then return nil end\n  H.validate_string(store_path, 'store_path')\n  if vim.fn.filereadable(store_path) == 0 then return nil end\n\n  return dofile(store_path)\nend\n\n--- Write visit index to disk\n---\n--- Steps:\n--- - Normalize index with |MiniVisits.normalize_index()|.\n--- - Ensure path is valid (all parent directories are created, etc.).\n--- - Write index object to the path so that it is readable\n---   with |MiniVisits.read_index()|.\n---\n---@param store_path string|nil Path on the disk where to write visit index data.\n---   Default: `config.store.path`. Note: if empty string, nothing is written.\n---@param index table|nil Index object to write to disk.\n---   Default: current session index.\nMiniVisits.write_index = function(store_path, index)\n  store_path = store_path or H.get_config().store.path\n  H.validate_string(store_path, 'store_path')\n  if store_path == '' then return end\n  index = index or MiniVisits.get_index()\n  H.validate_index(index, '`index`')\n\n  -- Normalize index\n  index = MiniVisits.normalize_index(index)\n\n  -- Ensure writable path\n  store_path = vim.fn.fnamemodify(store_path, ':p')\n  local path_dir = vim.fn.fnamemodify(store_path, ':h')\n  vim.fn.mkdir(path_dir, 'p')\n\n  -- Write\n  local lines = vim.split(vim.inspect(index), '\\n')\n  lines[1] = 'return ' .. lines[1]\n  vim.fn.writefile(lines, store_path)\nend\n\n--- Rename path in index\n---\n--- A helper to react for a path rename/move in order to preserve its visit data.\n--- It works both for file and directory paths.\n---\n--- Notes:\n--- - It does not update current index, but returns a modified index object.\n---   Use |MiniVisits.set_index()| to make it current.\n--- - Use only full paths.\n--- - Do not append `/` to directory paths. Use same format as for files.\n---\n--- Assuming `path_from` and `path_to` are variables containing full paths\n--- before and after rename/move, here is an example to update current index: >lua\n---\n---   local new_index = MiniVisits.rename_in_index(path_from, path_to)\n---   MiniVisits.set_index(new_index)\n--- <\n---@param path_from string Full path to be renamed.\n---@param path_to string Full path to be replaced with.\n---@param index table|nil Index object inside which to perform renaming.\n---   Default: current session index.\n---\n---@return table Index object with renamed path.\nMiniVisits.rename_in_index = function(path_from, path_to, index)\n  path_from = H.validate_string(path_from, 'path_from')\n  path_to = H.validate_string(path_to, 'path_to')\n  index = index or MiniVisits.get_index()\n  H.validate_index(index, '`index`')\n\n  local path_from_pattern = vim.pesc(path_from)\n  local pattern_from_full = string.format('^%s$', path_from_pattern)\n  local pattern_from_parent_dir = string.format('^(%s)/', path_from_pattern)\n  local path_to_parent_dir = path_to .. '/'\n\n  local replace = function(x)\n    if string.find(x, pattern_from_full) ~= nil then return path_to end\n    return string.gsub(x, pattern_from_parent_dir, path_to_parent_dir)\n  end\n\n  local res = {}\n  for cwd, cwd_tbl in pairs(index) do\n    local new_cwd_tbl = {}\n    for path, path_tbl in pairs(cwd_tbl) do\n      new_cwd_tbl[replace(path)] = vim.deepcopy(path_tbl)\n    end\n    res[replace(cwd)] = new_cwd_tbl\n  end\n\n  return res\nend\n\n--- Generate filter function\n---\n--- This is a table with function elements. Call to actually get specification.\nMiniVisits.gen_filter = {}\n\n--- Default filter\n---\n--- Always returns `true` resulting in no actual filter.\n---\n---@return function Visit filter function. See |MiniVisits.config.list| for more details.\nMiniVisits.gen_filter.default = function()\n  return function(path_data) return true end\nend\n\n--- Filter visits from current session\n---\n---@return function Visit filter function. See |MiniVisits.config.list| for more details.\nMiniVisits.gen_filter.this_session = function()\n  return function(path_data) return H.cache.session_start_time <= path_data.latest end\nend\n\n--- Generate sort function\n---\n--- This is a table with function elements. Call to actually get specification.\nMiniVisits.gen_sort = {}\n\n--- Default sort\n---\n--- Sort paths using \"robust frecency\" approach. It relies on the rank operation:\n--- based on certain reference number for every item, assign it a number\n--- between 1 (best) and number of items (worst). Ties are dealt with \"average\n--- rank\" approach: each element with a same reference number is assigned\n--- an average rank among such elements. This way total rank sum depends only\n--- on number of paths.\n---\n--- Here is an algorithm outline:\n--- - Rank paths based on frequency (`count` value): from most to least frequent.\n--- - Rank paths based on recency (`latest` value): from most to least recent.\n--- - Combine ranks from previous steps with weights:\n---   `score = (1 - w) * rank_frequency + w * rank_recency`, where `w` is\n---   \"recency weight\". The smaller this weight the less recency affects outcome.\n---\n--- Examples:\n--- - Default recency weight 0.5 results into \"robust frecency\" sorting: it\n---   combines both frequency and recency.\n---   This is called a \"robust frecency\" because actual values don't have direct\n---   effect on the outcome, only ordering matters. For example, if there is\n---   a very frequent file with `count = 100` while all others have `count = 5`,\n---   it will not massively dominate the outcome as long as it is not very recent.\n---\n--- - Having recency weight 1 results into \"from most to least recent\" sorting.\n---\n--- - Having recency weight 0 results into \"from most to least frequent\" sorting.\n---\n---@param opts table|nil Option. Possible fields:\n---   - <recency_weight> `(number)` - a number between 0 and 1 for recency weight.\n---     Default: 0.5.\n---\n---@return function Visit sort function. See |MiniVisits.config.list| for more details.\nMiniVisits.gen_sort.default = function(opts)\n  opts = vim.tbl_deep_extend('force', { recency_weight = 0.5 }, opts or {})\n  local recency_weight = opts.recency_weight\n  local is_weight = type(recency_weight) == 'number' and 0 <= recency_weight and recency_weight <= 1\n  if not is_weight then H.error('`opts.recency_weight` should be number between 0 and 1.') end\n\n  return function(path_data_arr)\n    path_data_arr = vim.deepcopy(path_data_arr)\n\n    -- Add ranks for `count` and `latest`\n    table.sort(path_data_arr, function(a, b) return a.count > b.count end)\n    H.tbl_add_rank(path_data_arr, 'count')\n    table.sort(path_data_arr, function(a, b) return a.latest > b.latest end)\n    H.tbl_add_rank(path_data_arr, 'latest')\n\n    -- Compute final rank and sort by it\n    for _, path_data in ipairs(path_data_arr) do\n      path_data.rank = (1 - recency_weight) * path_data.count_rank + recency_weight * path_data.latest_rank\n    end\n    table.sort(path_data_arr, function(a, b) return a.rank < b.rank or (a.rank == b.rank and a.path < b.path) end)\n    return path_data_arr\n  end\nend\n\n--- Z sort\n---\n--- Sort as in https://github.com/rupa/z.\n---\n---@return function Visit sort function. See |MiniVisits.config.list| for more details.\nMiniVisits.gen_sort.z = function()\n  return function(path_data_arr)\n    path_data_arr = vim.deepcopy(path_data_arr)\n    local now = os.time()\n    for _, path_data in ipairs(path_data_arr) do\n      -- Source: https://github.com/rupa/z/blob/master/z.sh#L151\n      local dtime = math.max(now - path_data.latest, 0.0001)\n      path_data.z = 10000 * path_data.count * (3.75 / ((0.0001 * dtime + 1) + 0.25))\n    end\n    table.sort(path_data_arr, function(a, b) return a.z > b.z or (a.z == b.z and a.path < b.path) end)\n    return path_data_arr\n  end\nend\n\n--- Generate normalize function\n---\n--- This is a table with function elements. Call to actually get specification.\nMiniVisits.gen_normalize = {}\n\n--- Generate default normalize function\n---\n--- Steps:\n--- - Prune visits, i.e. remove outdated visits:\n---     - If `count` number of visits is below prune threshold, remove that visit\n---       entry from particular cwd (it can still be present in others).\n---     - If either first (cwd) or second (path) level key doesn't represent an\n---       actual path on disk, remove the whole associated value.\n---     - NOTE: if visit has any label, it is not automatically pruned.\n---\n--- - Decay visits, i.e. possibly make visits more outdated. This is an important\n---   part to the whole usability: together with pruning it results into automated\n---   removing of paths which were visited long ago and are not relevant.\n---\n---   Decay is done per cwd if its total `count` values sum exceeds decay threshold.\n---   It is performed through multiplying each `count` by same coefficient so that\n---   the new total sum of `count` is equal to some smaller target value.\n---   Note: only two decimal places are preserved, so the sum might not be exact.\n---\n--- - Prune once more to ensure that there are no outdated paths after decay.\n---\n---@param opts table|nil Options. Possible fields:\n---   - <decay_threshold> `(number)` - decay threshold. Default: 1000.\n---   - <decay_target> `(number)` - decay target. Default: 800.\n---   - <prune_threshold> `(number)` - prune threshold. Default: 0.5.\n---   - <prune_paths> `(boolean)` - whether to prune outdated paths. Default: `true`.\n---\n---@return function Visit index normalize function. See \"Store\" in |MiniVisits.config|.\nMiniVisits.gen_normalize.default = function(opts)\n  local default_opts = { decay_threshold = 1000, decay_target = 800, prune_threshold = 0.5, prune_paths = true }\n  opts = vim.tbl_deep_extend('force', default_opts, opts or {})\n\n  return function(index)\n    H.validate_index(index)\n    local res = vim.deepcopy(index)\n    H.index_prune(res, opts.prune_paths, opts.prune_threshold)\n    for cwd, cwd_tbl in pairs(res) do\n      H.index_decay_cwd(cwd_tbl, opts.decay_threshold, opts.decay_target)\n    end\n    -- Ensure that no path has count smaller than threshold\n    H.index_prune(res, false, opts.prune_threshold)\n    return res\n  end\nend\n\n-- Helper data ================================================================\n-- Module default config\nH.default_config = MiniVisits.config\n\n-- Various timers\nH.timers = {\n  track = vim.loop.new_timer(),\n}\n\n-- Current visit index\nH.index = {}\n\n-- Various cache\nH.cache = {\n  -- Latest tracked path used to not autoregister same path in a row\n  latest_tracked_path = nil,\n\n  -- Whether index is yet to be read from the stored path, as it is not read\n  -- right away delaying until it is absolutely necessary\n  needs_index_read = true,\n\n  -- Start time of this session to be used in `gen_filter.this_session`\n  session_start_time = os.time(),\n}\n\n-- File system information\nH.is_windows = vim.loop.os_uname().sysname == 'Windows_NT'\n\n-- Helper functionality =======================================================\n-- Settings -------------------------------------------------------------------\nH.setup_config = function(config)\n  H.check_type('config', config, 'table', true)\n  config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})\n\n  H.check_type('list', config.list, 'table')\n  H.check_type('list.filter', config.list.filter, 'function', true)\n  H.check_type('list.sort', config.list.sort, 'function', true)\n\n  H.check_type('silent', config.silent, 'boolean')\n\n  H.check_type('store', config.store, 'table')\n  H.check_type('store.autowrite', config.store.autowrite, 'boolean')\n  H.check_type('store.normalize', config.store.normalize, 'function', true)\n  H.check_type('store.path', config.store.path, 'string')\n\n  H.check_type('track', config.track, 'table')\n  H.check_type('track.delay', config.track.delay, 'number')\n  H.check_type('track.event', config.track.event, 'string')\n\n  return config\nend\n\nH.apply_config = function(config) MiniVisits.config = config end\n\nH.create_autocommands = function(config)\n  local gr = vim.api.nvim_create_augroup('MiniVisits', {})\n\n  local au = function(event, pattern, callback, desc)\n    vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })\n  end\n\n  if config.track.event ~= '' then au(config.track.event, '*', H.autoregister_visit, 'Auto register visit') end\n  au('VimLeavePre', '*', function()\n    if not H.get_config().store.autowrite then return end\n    pcall(MiniVisits.write_index)\n  end, 'Autowrite visit index')\n\n  -- React to file manipulation with 'mini.files'\n  au('User', { 'MiniFilesActionRename', 'MiniFilesActionMove' }, function(args)\n    local cur_index = MiniVisits.get_index()\n    local ok, new_index = pcall(MiniVisits.rename_in_index, args.data.from, args.data.to, cur_index)\n    if not ok then return end\n    MiniVisits.set_index(new_index)\n  end, 'Rename in index')\nend\n\nH.is_disabled = function(buf_id)\n  local buf_disable = H.get_buf_var(buf_id, 'minivisits_disable')\n  return vim.g.minivisits_disable == true or buf_disable == true\nend\n\nH.get_config = function(config, buf_id)\n  local buf_config = H.get_buf_var(buf_id, 'minivisits_config') or {}\n  return vim.tbl_deep_extend('force', MiniVisits.config, buf_config, config or {})\nend\n\nH.get_buf_var = function(buf_id, name)\n  if not H.is_valid_buf(buf_id) then return nil end\n  return vim.b[buf_id or 0][name]\nend\n\n-- Autocommands ---------------------------------------------------------------\nH.autoregister_visit = function(data)\n  -- Recognize the register opportunity by stopping timer before check for\n  -- disabling. This is important for `iterate_paths` functionality.\n  H.timers.track:stop()\n  local buf_id = data.buf\n  if H.is_disabled(buf_id) then return end\n\n  local f = vim.schedule_wrap(function()\n    if H.is_disabled(buf_id) then return end\n\n    -- Register only normal buffer if it is not the latest registered (avoids\n    -- tracking visits from switching between normal and non-normal buffers)\n    local path = H.buf_get_path(buf_id)\n    if path == nil or path == H.cache.latest_tracked_path then return end\n\n    local ok = pcall(MiniVisits.register_visit, path, vim.fn.getcwd())\n    if not ok then return end\n\n    H.cache.latest_tracked_path = path\n  end)\n\n  H.timers.track:start(H.get_config(nil, buf_id).track.delay, 0, f)\nend\n\n-- Visit index ----------------------------------------------------------------\nH.ensure_read_index = function()\n  if not H.cache.needs_index_read then return end\n\n  -- Try reading previous index\n  local ok, res_index = pcall(MiniVisits.read_index)\n  if not ok then return end\n  local is_index = pcall(H.validate_index, res_index)\n  if not is_index then return end\n\n  -- Merge current index with stored\n  for cwd, cwd_tbl in pairs(H.index) do\n    local cwd_tbl_res = res_index[cwd] or {}\n    for path, path_tbl_new in pairs(cwd_tbl) do\n      local path_tbl_res = cwd_tbl_res[path] or { count = 0, latest = 0 }\n      cwd_tbl_res[path] = H.merge_path_tbls(path_tbl_res, path_tbl_new)\n    end\n    res_index[cwd] = cwd_tbl_res\n  end\n\n  H.index = res_index\n  H.cache.needs_index_read = false\nend\n\nH.ensure_index_entry = function(path, cwd)\n  local cwd_tbl = H.index[cwd] or {}\n  cwd_tbl[path] = cwd_tbl[path] or { count = 0, latest = 0 }\n  H.index[cwd] = cwd_tbl\nend\n\nH.resolve_path_cwd = function(path, cwd)\n  H.ensure_read_index()\n\n  -- Empty cwd means all available cwds\n  local cwd_arr = cwd == '' and vim.tbl_keys(H.index) or { cwd }\n\n  -- Empty path means all available paths in all target cwds\n  if path ~= '' then\n    return vim.tbl_map(function(x) return { path = path, cwd = x } end, cwd_arr)\n  end\n\n  local res = {}\n  for _, d in ipairs(cwd_arr) do\n    local cwd_tbl = H.index[d] or {}\n    for p, _ in pairs(cwd_tbl) do\n      table.insert(res, { path = p, cwd = d })\n    end\n  end\n  return res\nend\n\nH.make_path_array = function(path, cwd)\n  local index = MiniVisits.get_index()\n  local path_tbl = {}\n  for _, pair in ipairs(H.resolve_path_cwd(path, cwd)) do\n    local path_tbl_to_merge = (index[pair.cwd] or {})[pair.path]\n    if type(path_tbl_to_merge) == 'table' then\n      local p = pair.path\n      path_tbl[p] = path_tbl[p] or { path = p, count = 0, latest = 0 }\n      path_tbl[p] = H.merge_path_tbls(path_tbl[p], path_tbl_to_merge)\n    end\n  end\n\n  return vim.tbl_values(path_tbl)\nend\n\nH.merge_path_tbls = function(path_tbl_ref, path_tbl_new)\n  local path_tbl = vim.tbl_deep_extend('force', path_tbl_ref, path_tbl_new)\n\n  -- Add all counts together\n  path_tbl.count = path_tbl_ref.count + path_tbl_new.count\n\n  -- Compute the latest visit\n  path_tbl.latest = math.max(path_tbl_ref.latest, path_tbl_new.latest)\n\n  -- Labels should be already a proper union of both labels\n\n  return path_tbl\nend\n\nH.index_prune = function(index, prune_paths, threshold)\n  if type(threshold) ~= 'number' then H.error('Prune threshold should be number.') end\n\n  -- Possibly prune non-path cwds\n  for cwd, cwd_tbl in pairs(index) do\n    if prune_paths and vim.fn.isdirectory(cwd) == 0 then index[cwd] = nil end\n  end\n\n  -- Prune on path level\n  for cwd, cwd_tbl in pairs(index) do\n    for path, path_tbl in pairs(cwd_tbl) do\n      local should_prune_path = prune_paths and not (vim.fn.filereadable(path) == 1 or vim.fn.isdirectory(path) == 1)\n      local should_prune = should_prune_path or path_tbl.count < threshold\n      -- Don't prune if visit has labels (can happen if label was added\n      -- manually without actual visit, thus `count = 0`)\n      if path_tbl.labels == nil and should_prune then cwd_tbl[path] = nil end\n    end\n  end\n\n  -- Remove possible cwd tables which were only with non-paths entries\n  for cwd, cwd_tbl in pairs(index) do\n    if vim.tbl_count(cwd_tbl) == 0 then index[cwd] = nil end\n  end\nend\n\nH.index_decay_cwd = function(cwd_tbl, threshold, target)\n  if type(threshold) ~= 'number' then H.error('Decay threshold should be number.') end\n  if type(target) ~= 'number' then H.error('Decay target should be number.') end\n\n  -- Decide whether to decay (if total count exceeds threshold)\n  local total_count = 0\n  for _, path_tbl in pairs(cwd_tbl) do\n    total_count = total_count + path_tbl.count\n  end\n  if total_count == 0 or total_count <= threshold then return end\n\n  -- Decay (multiply counts by coefficient to have total count equal target)\n  local coef = target / total_count\n  for _, path_tbl in pairs(cwd_tbl) do\n    -- Round to preserve only two decimal places\n    path_tbl.count = math.floor(100 * coef * path_tbl.count + 0.5) / 100\n  end\nend\n\nH.get_label_from_user = function(prompt, labels_complete)\n  MiniVisits._complete = function(arg_lead)\n    return vim.tbl_filter(function(x) return x:find(arg_lead, 1, true) ~= nil end, labels_complete)\n  end\n  local completion = 'customlist,v:lua.MiniVisits._complete'\n  local input_opts = { prompt = prompt .. ': ', completion = completion, cancelreturn = false }\n  local ok, res = pcall(vim.fn.input, input_opts)\n  MiniVisits._complete = nil\n  if not ok or res == false then return nil end\n  return res\nend\n\n-- Validators -----------------------------------------------------------------\nH.validate_path = function(x)\n  x = x or H.buf_get_path(vim.api.nvim_get_current_buf())\n  if x == nil then H.error('Current buffer is not for a regular file') end\n  H.validate_string(x, 'path')\n  return x == '' and '' or H.full_path(x)\nend\n\nH.validate_cwd = function(x)\n  x = x or vim.fn.getcwd()\n  H.validate_string(x, 'cwd')\n  return x == '' and '' or H.full_path(x)\nend\n\nH.validate_filter = function(x)\n  x = x or MiniVisits.gen_filter.default()\n  if type(x) == 'string' then\n    local label = x\n    x = function(path_data) return (path_data.labels or {})[label] end\n  end\n  if not vim.is_callable(x) then H.error('`filter` should be callable or string label name.') end\n  return x\nend\n\nH.validate_sort = function(x)\n  x = x or MiniVisits.gen_sort.default()\n  if not vim.is_callable(x) then H.error('`sort` should be callable.') end\n  return x\nend\n\nH.validate_index = function(x, name)\n  name = name or '`index`'\n  if type(x) ~= 'table' then H.error(name .. ' should be a table.') end\n  for cwd, cwd_tbl in pairs(x) do\n    if type(cwd) ~= 'string' then H.error('First level keys in ' .. name .. ' should be strings.') end\n    if type(cwd_tbl) ~= 'table' then H.error('First level values in ' .. name .. ' should be tables.') end\n\n    for path, path_tbl in pairs(cwd_tbl) do\n      if type(path) ~= 'string' then H.error('Second level keys in ' .. name .. ' should be strings.') end\n      if type(path_tbl) ~= 'table' then H.error('Second level values in ' .. name .. ' should be tables.') end\n\n      if type(path_tbl.count) ~= 'number' then H.error('`count` entries in ' .. name .. ' should be numbers.') end\n      if type(path_tbl.latest) ~= 'number' then H.error('`latest` entries in ' .. name .. ' should be numbers.') end\n\n      H.validate_labels_field(path_tbl.labels)\n    end\n  end\nend\n\nH.validate_labels_field = function(x)\n  if x == nil then return end\n  if type(x) ~= 'table' then H.error('`labels` should be a table.') end\n\n  for key, value in pairs(x) do\n    if type(key) ~= 'string' then H.error('Keys in `labels` table should be strings.') end\n    if value ~= true then H.error('Values in `labels` table should only be `true`.') end\n  end\nend\n\nH.validate_string = function(x, name)\n  if type(x) == 'string' then return x end\n  H.error(string.format('`%s` should be string.', name))\nend\n\n-- Utilities ------------------------------------------------------------------\nH.error = function(msg) error('(mini.visits) ' .. msg, 0) end\n\nH.check_type = function(name, val, ref, allow_nil)\n  if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end\n  H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))\nend\n\nH.echo = function(msg)\n  if H.get_config().silent then return end\n\n  -- Construct message chunks\n  msg = type(msg) == 'string' and { { msg } } or msg\n  table.insert(msg, 1, { '(mini.visits) ', 'WarningMsg' })\n\n  -- Echo. Force redraw to ensure that it is effective (`:h echo-redraw`)\n  vim.cmd([[echo '' | redraw]])\n  vim.api.nvim_echo(msg, false, {})\nend\n\nH.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end\n\nH.buf_get_path = function(buf_id)\n  -- Get path only for valid normal buffers\n  if not (H.is_valid_buf(buf_id) and vim.bo[buf_id].buftype == '') then return nil end\n  local res = H.full_path(vim.api.nvim_buf_get_name(buf_id))\n  if res == '' then return end\n  return res\nend\n\nH.tbl_add_rank = function(arr, key)\n  local rank_key, ties = key .. '_rank', {}\n  for i, tbl in ipairs(arr) do\n    -- Assumes `arr` is an array of tables sorted from best to worst\n    tbl[rank_key] = i\n\n    -- Track ties\n    if i > 1 and tbl[key] == arr[i - 1][key] then\n      local val = tbl[key]\n      local data = ties[val] or { n = 1, sum = i - 1 }\n      data.n, data.sum = data.n + 1, data.sum + i\n      ties[val] = data\n    end\n  end\n\n  -- Correct for ties using mid-rank\n  for i, tbl in ipairs(arr) do\n    local tie_data = ties[tbl[key]]\n    if tie_data ~= nil then tbl[rank_key] = tie_data.sum / tie_data.n end\n  end\nend\n\nH.edit = function(path, win_id)\n  if type(path) ~= 'string' then return end\n  local b = vim.api.nvim_win_get_buf(win_id or 0)\n  local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)\n    and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))\n  local buf_id = vim.fn.bufadd(vim.fn.fnamemodify(path, ':.'))\n  -- Showing in window also loads. Use `pcall` to not error with swap messages.\n  pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)\n  vim.bo[buf_id].buflisted = true\n  if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end\n  return buf_id\nend\n\nH.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('/+', '/'):gsub('(.)/$', '%1')) end\nif H.is_windows then\n  H.full_path = function(path)\n    return (vim.fn.fnamemodify(path, ':p'):gsub('\\\\', '/'):gsub('/+', '/'):gsub('(.)/$', '%1'))\n  end\nend\n\nH.short_path = function(path, cwd)\n  cwd = cwd or vim.fn.getcwd()\n  -- Ensure `cwd` is treated as directory path (to not match similar prefix)\n  cwd = cwd:sub(-1) == '/' and cwd or (cwd .. '/')\n  if vim.startswith(path, cwd) then return path:sub(cwd:len() + 1) end\n  local res = vim.fn.fnamemodify(path, ':~')\n  if H.is_windows then res = res:gsub('\\\\', '/') end\n  return res\nend\n\nreturn MiniVisits\n"
  },
  {
    "path": "readmes/mini-ai.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-ai_readme.png?raw=true\" alt=\"mini.ai\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Extend and create `a`/`i` textobjects\n\n- It enhances some builtin textobjects (like `a(`, `a)`, `a'`, and more), creates new ones (like `a*`, `a<Space>`, `af`, `a?`, and more), and allows user to create their own (like based on treesitter, and more).\n- Supports dot-repeat, `v:count`, different search methods, consecutive application, and customization via Lua patterns or functions.\n- Has builtins for brackets, quotes, function call, argument, tag, user prompt, and any punctuation/digit/whitespace character.\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-ai.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-ai) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-ai.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/181909691-b6f6b677-c37f-468f-85db-8eb8b1e1314e.mp4\n\n## Features\n\n- Customizable creation of `a`/`i` textobjects using Lua patterns and functions. Supports:\n    - Dot-repeat.\n    - `v:count`.\n    - Different search methods (see `:h MiniAi.config`).\n    - Consecutive application (update selection without leaving Visual mode).\n    - Aliases for multiple textobjects.\n- Comprehensive builtin textobjects (see more at `:h MiniAi-builtin-textobjects`):\n    - Balanced brackets (with and without whitespace) plus alias.\n    - Balanced quotes plus alias.\n    - Function call.\n    - Argument.\n    - Tag.\n    - Derived from user prompt.\n    - Default for anything but Latin letters (to fall back to `:h text-objects`).\n- Motions for jumping to left/right edge of textobject.\n- Set of specification generators to tweak some builtin textobjects (see\n  help for `MiniAi.gen_spec`).\n- Treesitter textobjects (through `MiniAi.gen_spec.treesitter()` helper).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                 |\n    |--------|--------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.ai')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.ai', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                |\n    |--------|---------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.ai', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.ai', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                       |\n    |--------|----------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.ai'`                         |\n    | Stable | `Plug 'nvim-mini/mini.ai', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.ai').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Table with textobject id as fields, textobject specification as values.\n  -- Also use this to disable builtin textobjects. See |MiniAi.config|.\n  custom_textobjects = nil,\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Main textobject prefixes\n    around = 'a',\n    inside = 'i',\n\n    -- Next/last variants\n    -- NOTE: These override built-in LSP selection mappings on Neovim>=0.12\n    -- Map LSP selection manually to use it (see `:h MiniAi.config`)\n    around_next = 'an',\n    inside_next = 'in',\n    around_last = 'al',\n    inside_last = 'il',\n\n    -- Move cursor to corresponding edge of `a` textobject\n    goto_left = 'g[',\n    goto_right = 'g]',\n  },\n\n  -- Number of lines within which textobject is searched\n  n_lines = 50,\n\n  -- How to search for object (first inside current line, then inside\n  -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev',\n  -- 'cover_or_nearest', 'next', 'previous', 'nearest'.\n  search_method = 'cover_or_next',\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [wellle/targets.vim](https://github.com/wellle/targets.vim)\n- [nvim-treesitter/nvim-treesitter-textobjects](https://github.com/nvim-treesitter/nvim-treesitter-textobjects)\n- [kana/vim-textobj-user](https://github.com/kana/vim-textobj-user)\n"
  },
  {
    "path": "readmes/mini-align.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-align_readme.png?raw=true\" alt=\"mini.align\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Align text interactively\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-align.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-align) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-align.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/191686791-2c8b345a-2bcc-4de7-a065-5e7a36e2eb1a.mp4\n\n## Features\n\n- Alignment is done in three main steps:\n    - **Split** lines into parts based on Lua pattern(s) or user-supplied rule.\n    - **Justify** parts for certain side(s) to be same width inside columns.\n    - **Merge** parts to be lines, with customizable delimiter(s).\n\n    Each main step can be preceded by other steps (pre-steps) to achieve highly customizable outcome. See `steps` value in `:h MiniAlign.config`. For more details, see `:h MiniAlign-glossary` and `:h MiniAlign-algorithm`.\n- User can control alignment interactively by pressing customizable modifiers (single keys representing how alignment steps and/or options should change). Some of default modifiers:\n    - Press `s` to enter split Lua pattern.\n    - Press `j` to choose justification side from available ones (\"left\", \"center\", \"right\", \"none\").\n    - Press `m` to enter merge delimiter.\n    - Press `f` to enter filter Lua expression to configure which parts will be affected (like \"align only first column\").\n    - Press `i` to ignore some commonly unwanted split matches.\n    - Press `p` to pair neighboring parts so they be aligned together.\n    - Press `t` to trim whitespace from parts.\n    - Press `<BS>` (backspace) to delete some last pre-step.\n\n    For more details, see `:h MiniAlign-modifiers-builtin` and `:h MiniAlign-examples`.\n- Alignment can be done with instant preview (result is updated after each modifier) or without it (result is shown and accepted after non-default split pattern is set).\n- Every user interaction is accompanied with helper status message showing relevant information about current alignment process.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                    |\n    |--------|-----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.align')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.align', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                   |\n    |--------|------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.align', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.align', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                          |\n    |--------|-------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.align'`                         |\n    | Stable | `Plug 'nvim-mini/mini.align', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.align').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    start = 'ga',\n    start_with_preview = 'gA',\n  },\n\n  -- Modifiers changing alignment steps and/or options\n  modifiers = {\n    -- Main option modifiers\n    ['s'] = --<function: enter split pattern>,\n    ['j'] = --<function: choose justify side>,\n    ['m'] = --<function: enter merge delimiter>,\n\n    -- Modifiers adding pre-steps\n    ['f'] = --<function: filter parts by entering Lua expression>,\n    ['i'] = --<function: ignore some split matches>,\n    ['p'] = --<function: pair parts>,\n    ['t'] = --<function: trim parts>,\n\n    -- Delete some last pre-step\n    ['<BS>'] = --<function: delete some last pre-step>,\n\n    -- Special configurations for common splits\n    ['='] = --<function: enhanced setup for '='>,\n    [','] = --<function: enhanced setup for ','>,\n    ['|'] = --<function: enhanced setup for '|'>,\n    [' '] = --<function: enhanced setup for ' '>,\n  },\n\n  -- Default options controlling alignment process\n  options = {\n    split_pattern = '',\n    justify_side = 'left',\n    merge_delimiter = '',\n  },\n\n  -- Default steps performing alignment (if `nil`, default is used)\n  steps = {\n    pre_split = {},\n    split = nil,\n    pre_justify = {},\n    justify = nil,\n    pre_merge = {},\n    merge = nil,\n  },\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [junegunn/vim-easy-align](https://github.com/junegunn/vim-easy-align)\n- [godlygeek/tabular](https://github.com/godlygeek/tabular)\n- [tommcdo/vim-lion](https://github.com/tommcdo/vim-lion)\n- [Vonr/align.nvim](https://github.com/Vonr/align.nvim)\n"
  },
  {
    "path": "readmes/mini-animate.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-animate_readme.png?raw=true\" alt=\"mini.animate\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Animate common Neovim actions\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-animate.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-animate) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-animate.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/215829092-5aba4e8d-94a5-43da-8ef0-243bf0708f76.mp4\n\n## Features\n\n- Works out of the box with a single `require('mini.animate').setup()`. No extra mappings or commands needed.\n- Animate **cursor movement** inside same buffer by showing customizable path.\n- Animate **scrolling** with a series of subscrolls (\"smooth scrolling\").\n- Animate **window resize** by gradually changing sizes of all windows.\n- Animate **window open/close** with visually updating floating window.\n- Timings for all actions can be customized independently.\n- Action animations can be enabled/disabled independently.\n- All animations are asynchronous/non-blocking and trigger a targeted event which can be used to perform actions after animation is done.\n- `MiniAnimate.animate()` function which can be used to perform own animations.\n\nNotes:\n\n- Scroll and resize animations actually change Neovim state to achieve their effects and are asynchronous. This can cause following issues:\n    - If you have remapped any movement operation to center after it is done (like with `nzvzz` or `<C-d>zz`), you need to change those mappings. Either remove them or update to use `MiniAnimate.execute_after()` (see `:h MiniAnimate.config.scroll`)\n    - Using mouse wheel to scroll can appear slower or can have visual jitter. This usually happens due to high number of wheel turns per second: each turn is taking over previous one to start new animation. To mitigate this, you can either modify 'mousescroll' option (set vertical scroll to 1 and use high turn speed or set to high value and use one turn at a time) or `config.scroll` to fine tune when/how scroll animation is done.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                      |\n    |--------|-------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.animate')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.animate', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                     |\n    |--------|--------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.animate', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.animate', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                            |\n    |--------|---------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.animate'`                         |\n    | Stable | `Plug 'nvim-mini/mini.animate', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.animate').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Cursor path\n  cursor = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    timing = --<function: implements linear total 250ms animation duration>,\n\n    -- Path generator for visualized cursor movement\n    path = --<function: implements shortest line path no longer than 1000>,\n  },\n\n  -- Vertical scroll\n  scroll = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    timing = --<function: implements linear total 250ms animation duration>,\n\n    -- Subscroll generator based on total scroll\n    subscroll = --<function: implements equal scroll with at most 60 steps>,\n  },\n\n  -- Window resize\n  resize = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    timing = --<function: implements linear total 250ms animation duration>,\n\n    -- Subresize generator for all steps of resize animations\n    subresize = --<function: implements equal linear steps>,\n  },\n\n  -- Window open\n  open = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    timing = --<function: implements linear total 250ms animation duration>,\n\n    -- Floating window config generator visualizing specific window\n    winconfig = --<function: implements static window for 25 steps>,\n\n    -- 'winblend' (window transparency) generator for floating window\n    winblend = --<function: implements equal linear steps from 80 to 100>,\n  },\n\n  -- Window close\n  close = {\n    -- Whether to enable this animation\n    enable = true,\n\n    -- Timing of animation (how steps will progress in time)\n    timing = --<function: implements linear total 250ms animation duration>,\n\n    -- Floating window config generator visualizing specific window\n    winconfig = --<function: implements static window for 25 steps>,\n\n    -- 'winblend' (window transparency) generator for floating window\n    winblend = --<function: implements equal linear steps from 80 to 100>,\n  },\n}\n```\n\n## Similar plugins\n\n- [Neovide](https://neovide.dev/) (Neovim GUI, not a plugin)\n- [edluffy/specs.nvim](https://github.com/edluffy/specs.nvim)\n- [karb94/neoscroll.nvim](https://github.com/karb94/neoscroll.nvim)\n- [anuvyklack/windows.nvim](https://github.com/anuvyklack/windows.nvim)\n"
  },
  {
    "path": "readmes/mini-base16.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-base16_readme.png?raw=true\" alt=\"mini.base16\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Fast implementation of [chriskempson/base16](https://github.com/chriskempson/base16) theme for manually supplied palette\n\n- Supports 30+ plugin integrations.\n- Has unique palette generator which needs only background and foreground colors.\n- Comes with several hand-picked color schemes.\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-base16.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-base16) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\nUsing `minischeme` color scheme:\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minischeme-dark.png?raw=true\"> <img alt=\"minischeme dark\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minischeme-dark.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minischeme-light.png?raw=true\"> <img alt=\"minischeme light\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minischeme-light.png?raw=true\" style=\"width: 45%\"/> </a>\n\nUsing `minicyan` color scheme:\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minicyan-dark.png?raw=true\"> <img alt=\"minicyan dark\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minicyan-dark.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minicyan-light.png?raw=true\"> <img alt=\"minicyan light\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-base16_minicyan-light.png?raw=true\" style=\"width: 45%\"/> </a>\n\n## Features\n\nSupported highlight groups:\n\n- Built-in Neovim LSP and diagnostic.\n- Plugins (either with explicit definition or by verification that default\n  highlighting works appropriately):\n    - [nvim-mini/mini.nvim](https://nvim-mini.org/mini.nvim)\n    - [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n    - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n    - [DanilaMihailov/beacon.nvim](https://github.com/DanilaMihailov/beacon.nvim)\n    - [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n    - [folke/noice.nvim](https://github.com/folke/noice.nvim)\n    - [folke/snacks.nvim](https://github.com/folke/snacks.nvim)\n    - [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n    - [folke/trouble.nvim](https://github.com/folke/trouble.nvim)\n    - [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n    - [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n    - [ggandor/lightspeed.nvim](https://github.com/ggandor/lightspeed.nvim)\n    - [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n    - [glepnir/lspsaga.nvim](https://github.com/glepnir/lspsaga.nvim)\n    - [HiPhish/rainbow-delimiters.nvim](https://github.com/HiPhish/rainbow-delimiters.nvim)\n    - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n    - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n    - [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n    - [kevinhwang91/nvim-bqf](https://github.com/kevinhwang91/nvim-bqf)\n    - [kevinhwang91/nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n    - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n    - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n    - [MeanderingProgrammer/render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)\n    - [neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)\n    - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n    - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n    - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n    - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n    - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n    - [OXY2DEV/helpview.nvim](https://github.com/OXY2DEV/helpview.nvim)\n    - [OXY2DEV/markview.nvim](https://github.com/OXY2DEV/markview.nvim)\n    - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim)\n    - [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)\n    - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n    - [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n    - [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n    - [stevearc/aerial.nvim](https://github.com/stevearc/aerial.nvim)\n    - [williamboman/mason.nvim](https://github.com/williamboman/mason.nvim)\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.base16')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.base16', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.base16', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.base16', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.base16'`                         |\n    | Stable | `Plug 'nvim-mini/mini.base16', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.base16').setup()` with appropriate `palette` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n{\n  -- Table with names from `base00` to `base0F` and values being strings of\n  -- HEX colors with format \"#RRGGBB\". NOTE: this should be explicitly\n  -- supplied in `setup()`.\n  palette = nil,\n\n  -- Whether to support cterm colors. Can be boolean, `nil` (same as\n  -- `false`), or table with cterm colors. See `setup()` documentation for\n  -- more information.\n  use_cterm = nil,\n\n  -- Plugin integrations. Use `default = false` to disable all integrations.\n  -- Also can be set per plugin (see |MiniBase16.config|).\n  plugins = { default = true },\n}\n```\n\n## Similar plugins\n\n- [chriskempson/base16-vim](https://github.com/chriskempson/base16-vim)\n"
  },
  {
    "path": "readmes/mini-basics.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-basics_readme.png?raw=true\" alt=\"mini.basics\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Common configuration presets\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-basics.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-basics) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-basics.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/215277747-c0dea3eb-e8f7-4550-85ce-200b111fff55.mp4\n\n## Features\n\n- Presets for common options. It will only change option if it wasn't manually set before. See `:h MiniBasics.config.options` for more details.\n- Presets for common mappings. It will only add a mapping if it wasn't manually created before. See `:h MiniBasics.config.mappings` for more details.\n- Presets for common autocommands. See `:h MiniBasics.config.autocommands` for more details.\n- Reverse compatibility is a high priority. Any decision to change already present behavior will be made with great care.\n\nNotes:\n\n- Main goal of this module is to provide a relatively easier way for new-ish Neovim users to have better \"works out of the box\" experience while having documented relevant options/mappings/autocommands to study. It is based partially on survey among Neovim users and partially is coming from personal preferences.\n\n    However, more seasoned users almost surely will find something useful.\n\n    Still, it is recommended to read about used options/mappings/autocommands and decide if they are needed. The main way to do that is by reading Neovim's help pages (linked in help file) and this module's source code (thoroughly documented for easier comprehension).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.basics')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.basics', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.basics', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.basics', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.basics'`                         |\n    | Stable | `Plug 'nvim-mini/mini.basics', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.basics').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Options. Set field to `false` to disable.\n  options = {\n    -- Basic options ('number', 'ignorecase', and many more)\n    basic = true,\n\n    -- Extra UI features ('winblend', 'listchars', 'pumheight', ...)\n    extra_ui = false,\n\n    -- Presets for window borders ('single', 'double', ...)\n    -- Default 'auto' infers from 'winborder' option\n    win_borders = 'auto',\n  },\n\n  -- Mappings. Set field to `false` to disable.\n  mappings = {\n    -- Basic mappings (better 'jk', save with Ctrl+S, ...)\n    basic = true,\n\n    -- Prefix for mappings that toggle common options ('wrap', 'spell', ...).\n    -- Supply empty string to not create these mappings.\n    option_toggle_prefix = [[\\]],\n\n    -- Window navigation with <C-hjkl>, resize with <C-arrow>\n    windows = false,\n\n    -- Move cursor in Insert, Command, and Terminal mode with <M-hjkl>\n    move_with_alt = false,\n  },\n\n  -- Autocommands. Set field to `false` to disable\n  autocommands = {\n    -- Basic autocommands (highlight on yank, start Insert in terminal, ...)\n    basic = true,\n\n    -- Set 'relativenumber' only in linewise and blockwise Visual mode\n    relnum_in_visual_mode = false,\n  },\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [tpope/vim-sensible](https://github.com/tpope/vim-sensible)\n- [tpope/vim-unimpaired](https://github.com/tpope/vim-unimpaired)\n"
  },
  {
    "path": "readmes/mini-bracketed.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-bracketed_readme.png?raw=true\" alt=\"mini.bracketed\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Go forward/backward with square brackets\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-bracketed.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-bracketed) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-bracketed.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/220173251-cd905d8f-ad07-4654-bba5-971220fad80a.mp4\n\n## Features\n\n- Configurable Lua functions to go forward/backward to a certain target. Each function can be customized with:\n    - Direction. One of \"forward\", \"backward\", \"first\" (forward starting from first one), \"last\" (backward starting from last one).\n    - Number of times to go.\n    - Whether to wrap on edges (going forward on last one goes to first).\n    - Some other target specific options.\n\n- Mappings using square brackets. They are created using configurable target suffix and can be selectively disabled.\n\n  Each mapping supports |[count]|. Mappings are created in Normal mode; for targets which move cursor in current buffer also Visual and Operator-pending (with dot-repeat) modes are supported.\n\n  Using `lower-suffix` and `upper-suffix` (lower and upper case suffix) for a single target the following mappings are created:\n    - `[` + `upper-suffix` : go first.\n    - `[` + `lower-suffix` : go backward.\n    - `]` + `lower-suffix` : go forward.\n    - `]` + `upper-suffix` : go last.\n\n- Supported targets (for more information see help for corresponding Lua function):\n\n    | Target                                            | Mappings            | Lua function                 |\n    |---------------------------------------------------|---------------------|------------------------------|\n    | Buffer                                            | `[B` `[b` `]b` `]B` | `MiniBracketed.buffer()`     |\n    | Comment block                                     | `[C` `[c` `]c` `]C` | `MiniBracketed.comment()`    |\n    | Conflict marker                                   | `[X` `[x` `]x` `]X` | `MiniBracketed.conflict()`   |\n    | Diagnostic                                        | `[D` `[d` `]d` `]D` | `MiniBracketed.diagnostic()` |\n    | File on disk                                      | `[F` `[f` `]f` `]F` | `MiniBracketed.file()`       |\n    | Indent change                                     | `[I` `[i` `]i` `]I` | `MiniBracketed.indent()`     |\n    | Jump from jumplist inside current buffer          | `[J` `[j` `]j` `]J` | `MiniBracketed.jump()`       |\n    | Location from location list                       | `[L` `[l` `]l` `]L` | `MiniBracketed.location()`   |\n    | Old files                                         | `[O` `[o` `]o` `]O` | `MiniBracketed.oldfile()`    |\n    | Quickfix entry from quickfix list                 | `[Q` `[q` `]q` `]Q` | `MiniBracketed.quickfix()`   |\n    | Tree-sitter node and parents                      | `[T` `[t` `]t` `]T` | `MiniBracketed.treesitter()` |\n    | Undo states from specially tracked linear history | `[U` `[u` `]u` `]U` | `MiniBracketed.undo()`       |\n    | Window in current tab                             | `[W` `[w` `]w` `]W` | `MiniBracketed.window()`     |\n    | Yank selection replacing latest put region        | `[Y` `[y` `]y` `]Y` | `MiniBracketed.yank()`       |\n\nNotes:\n\n- The `undo` target remaps `u` and `<C-R>` keys to register undo state after undo and redo respectively. If this conflicts with your setup, either disable `undo` target or make your remaps after calling `MiniBracketed.setup()`. To use `undo` target, remap your undo/redo keys to call `MiniBracketed.register_undo_state()` after the action.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                        |\n    |--------|---------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.bracketed')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.bracketed', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                       |\n    |--------|----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.bracketed', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.bracketed', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                              |\n    |--------|-----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.bracketed'`                         |\n    | Stable | `Plug 'nvim-mini/mini.bracketed', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.bracketed').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- First-level elements are tables describing behavior of a target:\n  --\n  -- - <suffix> - single character suffix. Used after `[` / `]` in mappings.\n  --   For example, with `b` creates `[B`, `[b`, `]b`, `]B` mappings.\n  --   Supply empty string `''` to not create mappings.\n  --\n  -- - <options> - table overriding target options.\n  --\n  -- See `:h MiniBracketed.config` for more info.\n\n  buffer     = { suffix = 'b', options = {} },\n  comment    = { suffix = 'c', options = {} },\n  conflict   = { suffix = 'x', options = {} },\n  diagnostic = { suffix = 'd', options = {} },\n  file       = { suffix = 'f', options = {} },\n  indent     = { suffix = 'i', options = {} },\n  jump       = { suffix = 'j', options = {} },\n  location   = { suffix = 'l', options = {} },\n  oldfile    = { suffix = 'o', options = {} },\n  quickfix   = { suffix = 'q', options = {} },\n  treesitter = { suffix = 't', options = {} },\n  undo       = { suffix = 'u', options = {} },\n  window     = { suffix = 'w', options = {} },\n  yank       = { suffix = 'y', options = {} },\n}\n```\n\n## Similar plugins\n\n- [tpope/vim-unimpaired](https://github.com/tpope/vim-unimpaired)\n"
  },
  {
    "path": "readmes/mini-bufremove.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-bufremove_readme.png?raw=true\" alt=\"mini.bufremove\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Buffer removing (unshow, delete, wipeout), which saves window layout\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-bufremove.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-bufremove) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-bufremove.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044032-7874cf95-2e41-49fb-8abe-3aa73526972f.mp4\n\n## Features\n\nWhich buffer to show in window(s) after its current buffer is removed is decided by the algorithm:\n\n- If alternate buffer is listed, use it.\n- If previous listed buffer is different, use it.\n- Otherwise create a scratch one with `nvim_create_buf(true, true)` and use it.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                        |\n    |--------|---------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.bufremove')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.bufremove', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                       |\n    |--------|----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.bufremove', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.bufremove', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                              |\n    |--------|-----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.bufremove'`                         |\n    | Stable | `Plug 'nvim-mini/mini.bufremove', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: no need to call `require('mini.bufremove').setup()`, but it can be done to improve usability.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [mhinz/vim-sayonara](https://github.com/mhinz/vim-sayonara)\n- [moll/vim-bbye](https://github.com/moll/vim-bbye)\n"
  },
  {
    "path": "readmes/mini-clue.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-clue_readme.png?raw=true\" alt=\"mini.clue\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Show next key clues\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-clue.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-clue) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-clue.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/ea931966-067c-48af-93e9-36e9b8afb0ae\n\n## Features\n\n- Implement custom key query process to reach target key combination:\n    - Starts after customizable opt-in triggers (mode + keys).\n\n    - Each key press narrows down set of possible targets.\n\n      Pressing `<BS>` removes previous user entry.\n\n      Pressing `<Esc>` or `<C-c>` leads to an early stop.\n\n      Doesn't depend on 'timeoutlen' and has basic support for 'langmap'.\n\n    - Ends when there is at most one target left or user pressed `<CR>`. Results into emulating pressing all query keys plus possible postkeys.\n\n- Show window (after configurable delay) with clues. It lists available next keys along with their descriptions (auto generated from descriptions present keymaps and user-supplied clues; preferring the former).\n\n- Configurable \"postkeys\" for key combinations - keys which will be emulated after combination is reached during key query process.\n\n- Provide customizable sets of clues for common built-in keys/concepts:\n    - `g` key.\n    - `z` key.\n    - Window commands.\n    - Built-in completion.\n    - Marks.\n    - Registers.\n\n- Lua functions to disable/enable triggers globally or per buffer.\n\nFor more information see these parts of help:\n\n- `:h MiniClue-key-query-process`\n- `:h MiniClue-examples`\n- `:h MiniClue.config`\n- `:h MiniClue.gen_clues`\n\nNotes:\n\n- There is no functionality to create mappings in order to clearly separate two different tasks.\n\n  The best suggested practice is to manually create mappings with descriptions (`desc` field in options), as they will be automatically used inside clue window.\n\n- Triggers are implemented as special buffer-local mappings. This leads to several caveats:\n    - They will override same regular buffer-local mappings and have precedence over global one.\n\n      Example: having set `<C-w>` as Normal mode trigger means that there should not be another `<C-w>` mapping.\n\n    - They need to be the latest created buffer-local mappings or they will not function properly. Most common indicator of this is that some mapping starts to work only after clue window is shown.\n\n      Example: `g` is set as Normal mode trigger, but `gcc` from 'mini.comment' doesn't work right away. This is probably because there are some other buffer-local mappings starting with `g` which were created after mapping for `g` trigger. Most common places for this are in LSP server's `on_attach` or during tree-sitter start in buffer.\n\n      To check if trigger is the most recent buffer-local mapping, execute `:<mode-char>map <trigger-keys>` (like `:nmap g` for previous example). Mapping for trigger should be the first listed.\n\n      This module makes the best effort to work out of the box and cover most common cases, but it is not foolproof. The solution here is to ensure that triggers are created after making all buffer-local mappings: run either `MiniClue.setup()` or `MiniClue.ensure_buf_triggers()`.\n\n- Descriptions from existing mappings take precedence over user-supplied clues. This is to ensure that information shown in clue window is as relevant as possible. To add/customize description of an already existing mapping, use `MiniClue.set_mapping_desc()`.\n\n- Due to technical difficulties, there is no foolproof support for Operator-pending mode triggers (like `a`/`i` from 'mini.ai'):\n    - Doesn't work as part of a command in \"temporary Normal mode\" (like after `<C-o>` in Insert mode) due to implementation difficulties.\n    - Can have unexpected behavior with custom operators.\n\n- Has (mostly solved) issues with macros:\n    - All triggers are disabled during macro recording due to technical reasons.\n    - The `@` and `Q` keys are specially mapped inside `MiniClue.setup()` to temporarily disable triggers.\n\n## Config quick start\n\n```lua\nlocal miniclue = require('mini.clue')\nminiclue.setup({\n  triggers = {\n    -- Leader triggers\n    { mode = { 'n', 'x' }, keys = '<Leader>' },\n\n    -- `[` and `]` keys\n    { mode = 'n', keys = '[' },\n    { mode = 'n', keys = ']' },\n\n    -- Built-in completion\n    { mode = 'i', keys = '<C-x>' },\n\n    -- `g` key\n    { mode = { 'n', 'x' }, keys = 'g' },\n\n    -- Marks\n    { mode = { 'n', 'x' }, keys = \"'\" },\n    { mode = { 'n', 'x' }, keys = '`' },\n\n    -- Registers\n    { mode = { 'n', 'x' }, keys = '\"' },\n    { mode = { 'i', 'c' }, keys = '<C-r>' },\n\n    -- Window commands\n    { mode = 'n', keys = '<C-w>' },\n\n    -- `z` key\n    { mode = { 'n', 'x' }, keys = 'z' },\n  },\n\n  clues = {\n    -- Enhance this by adding descriptions for <Leader> mapping groups\n    miniclue.gen_clues.square_brackets(),\n    miniclue.gen_clues.builtin_completion(),\n    miniclue.gen_clues.g(),\n    miniclue.gen_clues.marks(),\n    miniclue.gen_clues.registers(),\n    miniclue.gen_clues.windows(),\n    miniclue.gen_clues.z(),\n  },\n})\n```\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.clue')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.clue', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.clue', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.clue', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.clue'`                         |\n    | Stable | `Plug 'nvim-mini/mini.clue', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.clue').setup()` to enable its functionality. **Needs to have triggers configured**.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Array of extra clues to show\n  clues = {},\n\n  -- Array of opt-in triggers which start custom key query process.\n  -- **Needs to have something in order to show clues**.\n  triggers = {},\n\n  -- Clue window settings\n  window = {\n    -- Floating window config\n    config = {},\n\n    -- Delay before showing clue window\n    delay = 1000,\n\n    -- Keys to scroll inside the clue window\n    scroll_down = '<C-d>',\n    scroll_up = '<C-u>',\n  },\n}\n```\n\n## Similar plugins\n\n- [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n- [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n"
  },
  {
    "path": "readmes/mini-cmdline.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-cmdline_readme.png?raw=true\" alt=\"mini.cmdline\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Command line tweaks\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-cmdline.txt).\n\n---\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-cmdline) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-cmdline.mp4 -->\nhttps://github.com/user-attachments/assets/9d3e12ac-ff17-4bdb-bbe8-3010c966c110\n\n## Features\n\n- Autocomplete with customizable delay. Enhances [`:h cmdline-completion`](https://neovim.io/doc/user/helptag.html?tag=cmdline-completion) and manual [`:h 'wildchar'`](https://neovim.io/doc/user/helptag.html?tag='wildchar') pressing experience. Requires Neovim>=0.11, though Neovim>=0.12 is recommended.\n\n- Autocorrect words as-you-type. Only words that must come from a fixed set of candidates (like commands and options) are autocorrected by default.\n\n- Autopeek command range as-you-type. Shows a floating window with range lines along with customizable context lines.\n\nWhat it doesn't do:\n\n- Customization of command line UI. Use [`:h vim._extui`](https://neovim.io/doc/user/helptag.html?tag=vim._extui) (on Neovim>=0.12).\n\n- Customization of autocompletion candidates. They are computed via [`:h cmdline-completion`](https://neovim.io/doc/user/helptag.html?tag=cmdline-completion).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nDuring beta-testing phase there is only one branch to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                      |\n    |--------|-------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.cmdline')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.cmdline', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                     |\n    |--------|--------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.cmdline', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.cmdline', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                            |\n    |--------|---------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.cmdline'`                         |\n    | Stable | `Plug 'nvim-mini/mini.cmdline', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.cmdline').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Autocompletion: show `:h 'wildmenu'` as you type\n  autocomplete = {\n    enable = true,\n\n    -- Delay (in ms) after which to trigger completion\n    -- Neovim>=0.12 is recommended for positive values\n    delay = 0,\n\n    -- Custom rule of when to trigger completion\n    predicate = nil,\n\n    -- Whether to map arrow keys for more consistent wildmenu behavior\n    map_arrows = true,\n  },\n\n  -- Autocorrection: adjust non-existing words (commands, options, etc.)\n  autocorrect = {\n    enable = true,\n\n    -- Custom autocorrection rule\n    func = nil,\n  },\n\n  -- Autopeek: show command's target range in a floating window\n  autopeek = {\n    enable = true,\n\n    -- Number of lines to show above and below range lines\n    n_context = 1,\n\n    -- Custom rule of when to show peek window\n    predicate = nil,\n\n    -- Window options\n    window = {\n      -- Floating window config\n      config = {},\n\n      -- Function to render statuscolumn\n      statuscolumn = nil,\n    },\n  },\n}\n```\n\n## Similar plugins\n\n- [folke/noice.nvim](https://github.com/folke/noice.nvim)\n- [nacro90/numb.nvim](https://github.com/nacro90/numb.nvim)\n- Built-in [cmdline-autocompletion](https://neovim.io/doc/user/helptag.html?tag=cmdline-autocompletion) (on Neovim>=0.12):\n"
  },
  {
    "path": "readmes/mini-colors.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-colors_readme.png?raw=true\" alt=\"mini.colors\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Tweak and save any color scheme\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-colors.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-colors) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-colors.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/232283566-9a51fa55-d20a-4650-8205-763b55e21366.mp4\n\n## Features\n\n- Create colorscheme object (see `:h MiniColors-colorscheme`): either manually (`:h MiniColors.as_colorscheme()`) or by querying present color schemes (including currently active one; see `:h MiniColors.get_colorscheme()`).\n\n- Infer data about color scheme and/or modify based on it:\n    - Add transparency by removing background color (requires transparency in terminal emulator).\n    - Infer cterm attributes based on gui colors making it compatible with 'notermguicolors'.\n    - Resolve highlight group links.\n    - Compress by removing redundant highlight groups.\n    - Extract palette of used colors and/or infer terminal colors based on it.\n\n- Modify colors to better fit your taste and/or goals:\n    - Apply any function to color hex string.\n    - Update channels (like lightness, saturation, hue, temperature, red, green, blue, etc.).\n      Use either own function or one of the implemented methods:\n        - Add value to channel or multiply it by coefficient. Like \"add 10 to saturation of every color\" or \"multiply saturation by 2\" to make colors more saturated (less gray).\n        - Invert. Like \"invert lightness\" to convert between dark/light theme.\n        - Set to one or more values (picks closest to current one). Like \"set to one or two hues\" to make mono- or dichromatic color scheme.\n        - Repel from certain source(s) with stronger effect for closer values. Like \"repel from hue 30\" to remove red color from color scheme. Repel hue (how much is removed) is configurable.\n    - Simulate color vision deficiency.\n\n- Once color scheme is ready, either apply it to see effects right away or write it into a Lua file as a fully functioning separate color scheme.\n\n- Experiment interactively with a feedback.\n\n- Animate transition between color schemes either with `MiniColors.animate()` or with `:Colorscheme` user command.\n\n- Convert within supported color spaces (`MiniColors.convert()`):\n    - Hex string.\n    - 8-bit number (terminal colors).\n    - RGB.\n    - Oklab, Oklch, Okhsl (https://bottosson.github.io/posts/oklab/).\n\n## Tweak quick start\n\n- Execute `:lua require('mini.colors').interactive()`.\n- Experiment by writing calls to exposed color scheme methods and applying them with `<M-a>`. For more information, see `:h MiniColors-colorscheme-methods` and `:h MiniColors-recipes`.\n- If you are happy with result, write color scheme with `<M-w>`. If not, reset to initial color scheme with `<M-r>`.\n- If only some highlight groups can be made better, adjust them manually inside written color scheme file.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.colors')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.colors', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.colors', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.colors', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.colors'`                         |\n    | Stable | `Plug 'nvim-mini/mini.colors', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: no need to call `require('mini.colors').setup()`, but it can be done to improve usability.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{}\n```\n\n## Similar plugins\n\n- [rktjmp/lush.nvim](https://github.com/rktjmp/lush.nvim)\n- [lifepillar/vim-colortemplate](https://github.com/lifepillar/vim-colortemplate)\n- [tjdevries/colorbuddy.nvim](https://github.com/tjdevries/colorbuddy.nvim)\n"
  },
  {
    "path": "readmes/mini-comment.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-comment_readme.png?raw=true\" alt=\"mini.comment\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Comment lines\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-comment.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-comment) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-comment.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044250-1a8bceae-8f14-40e2-a678-31aca0cd6c1a.mp4\n\n## Features\n\n- Commenting in Normal mode respects `v:count` and is dot-repeatable.\n- Comment structure is inferred from 'commentstring': either from current buffer or from locally active tree-sitter language. It can be customized via `options.custom_commentstring`.\n- Handles both tab and space indenting (but not when they are mixed).\n- Allows custom hooks before and after successful commenting.\n- Configurable options for some nuanced behavior.\n\nNotes:\n\n- To use tree-sitter aware commenting, global value of 'commentstring' should be `''` (empty string). This is the default value, so make sure to not set it manually to a different value.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                      |\n    |--------|-------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.comment')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.comment', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                     |\n    |--------|--------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.comment', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.comment', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                            |\n    |--------|---------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.comment'`                         |\n    | Stable | `Plug 'nvim-mini/mini.comment', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.comment').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Options which control module behavior\n  options = {\n    -- Function to compute custom 'commentstring' (optional)\n    custom_commentstring = nil,\n\n    -- Whether to ignore blank lines when commenting\n    ignore_blank_line = false,\n\n    -- Whether to ignore blank lines in actions and textobject\n    start_of_line = false,\n\n    -- Whether to force single space inner padding for comment parts\n    pad_comment_parts = true,\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Toggle comment (like `gcip` - comment inner paragraph) for both\n    -- Normal and Visual modes\n    comment = 'gc',\n\n    -- Toggle comment on current line\n    comment_line = 'gcc',\n\n    -- Toggle comment on visual selection\n    comment_visual = 'gc',\n\n    -- Define 'comment' textobject (like `dgc` - delete whole comment block)\n    -- Works also in Visual mode if mapping differs from `comment_visual`\n    textobject = 'gc',\n  },\n\n  -- Hook functions to be executed at certain stage of commenting\n  hooks = {\n    -- Before successful commenting. Does nothing by default.\n    pre = function() end,\n    -- After successful commenting. Does nothing by default.\n    post = function() end,\n  },\n}\n```\n\n## Similar plugins\n\n- Built-in commenting in Neovim>=0.10, see `:h commenting` (implemented with 'mini.comment' as reference)\n- [numToStr/Comment.nvim](https://github.com/numToStr/Comment.nvim)\n- [tpope/vim-commentary](https://github.com/tpope/vim-commentary)\n- [preservim/nerdcommenter](https://github.com/preservim/nerdcommenter)\n- [b3nj5m1n/kommentary](https://github.com/b3nj5m1n/kommentary)\n"
  },
  {
    "path": "readmes/mini-completion.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-completion_readme.png?raw=true\" alt=\"mini.completion\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Autocompletion and signature help plugin\n\n- Async (with customizable 'debounce' delay) 'two-stage chain completion': first builtin LSP, then configurable fallback.\n- Has functionality for completion item info and function signature (both in floating window appearing after customizable delay).\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-completion.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-completion) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-completion.mp4 -->\nhttps://github.com/user-attachments/assets/dd3fe2e2-9795-47c1-9479-0b3fa14c6e75\n\n## Features\n\n- Two-stage chain completion:\n    - First stage is an LSP completion. Supports `additionalTextEdits` (like auto-import, etc.) and snippets (see [\"Snippets\"](#snippets)) (best results require ['mini.snippets'](https://nvim-mini.org/mini.nvim/readmes/mini-snippets) dependency).\n    - If first stage is not set up or resulted into no candidates, fallback action is executed. The most tested actions are Neovim's built-in insert completion.\n- Automatic display in floating window of completion item info (via 'completionItem/resolve' request) and signature help (with highlighting of active parameter if LSP server provides such information). Scrolling is possible in both info/signature window (`<C-f>` / `<C-b>` by default).\n- Automatic actions are done after some configurable amount of delay. This reduces computational load and allows fast typing (completion and signature help) and item selection (item info)\n- User can force two-stage/fallback completion (`<C-Space>` / `<A-Space>` by default).\n- Customizable highlighting of LSP items. Requires Neovim>=0.11. Supported:\n    - Item label. By default only checks if item is marked as deprecated and sets `MiniCompletionDeprecated` highlight group.\n    - LSP kind (like \"Function\", \"Keyword\", etc.). Requires enabled ['mini.icons'](https://nvim-mini.org/mini.nvim/readmes/mini-icons) (uses its \"lsp\" category)\n\n## Dependencies\n\nFor full experience needs (still works without any of suggestions):\n\n- Enabled ['mini.icons'](https://nvim-mini.org/mini.nvim/readmes/mini-icons) module to highlight LSP kind (requires Neovim>=0.11). If absent, `MiniCompletion.default_process_items()` does not add highlighting. Also take a look at `MiniIcons.tweak_lsp_kind()`.\n- Enabled ['mini.snippets'](https://nvim-mini.org/mini.nvim/readmes/mini-snippets) module for better snippet handling (**much recommended**). If absent and custom snippet insert is not configured, `vim.snippet.expand()` is used on Neovim>=0.10 (nothing extra is done on earlier versions). See `:h MiniCompletion.default_snippet_insert()`.\n\n## Snippets\n\nAs per LSP specification, some completion items can be supplied in the form of snippet - a template with both pre-defined text and places (called \"tabstops\") for user to interactively change/add text during snippet session.\n\nIn 'mini.completion' items that will insert snippet have \"S\" symbol shown in the popup. To actually insert a snippet:\n\n- Select an item via `<C-n>` / `<C-p>`. This will insert item's label (usually not full snippet) first to reduce visual flicker. The full snippet text will be shown in info window if LSP server doesn't provide its own info for an item.\n\n- Press `<C-y>` or attempt inserting a non-keyword character (like `<CR>`; new character will be removed). It will clear text from previous step, set cursor, and call `lsp_completion.snippet_insert` with snippet text.\n\n- Press `<C-e>` to cancel snippet insert and properly end completion.\n\nSee `:h MiniCompletion.default_snippet_insert()` for overview of how to work with inserted snippets.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                         |\n    |--------|----------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.completion')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.completion', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.completion', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.completion', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                               |\n    |--------|------------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.completion'`                         |\n    | Stable | `Plug 'nvim-mini/mini.completion', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.completion').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Delay (debounce type, in ms) between certain Neovim event and action.\n  -- This can be used to (virtually) disable certain automatic actions by\n  -- setting very high delay time (like 10^7).\n  delay = { completion = 100, info = 100, signature = 50 },\n\n  -- Configuration for action windows:\n  -- - `height` and `width` are maximum dimensions.\n  -- - `border` defines border (as in `nvim_open_win()`; default \"single\").\n  window = {\n    info = { height = 25, width = 80, border = nil },\n    signature = { height = 25, width = 80, border = nil },\n  },\n\n  -- Way of how module does LSP completion\n  lsp_completion = {\n    -- `source_func` should be one of 'completefunc' or 'omnifunc'.\n    source_func = 'completefunc',\n\n    -- `auto_setup` should be boolean indicating if LSP completion is set up\n    -- on every `BufEnter` event.\n    auto_setup = true,\n\n    -- A function which takes LSP 'textDocument/completion' response items\n    -- (each with `client_id` field for item's server) and word to complete.\n    -- Output should be a table of the same nature as input. Common use case\n    -- is custom filter/sort. Default: `default_process_items`\n    process_items = nil,\n\n    -- A function which takes a snippet as string and inserts it at cursor.\n    -- Default: `default_snippet_insert` which tries to use 'mini.snippets'\n    -- and falls back to `vim.snippet.expand` (on Neovim>=0.10).\n    snippet_insert = nil,\n  },\n\n  -- Fallback action as function/string. Executed in Insert mode.\n  -- To use built-in completion (`:h ins-completion`), set its mapping as\n  -- string. Example: set '<C-x><C-l>' for 'whole lines' completion.\n  fallback_action = '<C-n>',\n\n  -- Module mappings. Use `''` (empty string) to disable one. Some of them\n  -- might conflict with system mappings.\n  mappings = {\n    -- Force two-step/fallback completions\n    force_twostep = '<C-Space>',\n    force_fallback = '<A-Space>',\n\n    -- Scroll info/signature window down/up. When overriding, check for\n    -- conflicts with built-in keys for popup menu (like `<C-u>`/`<C-o>`\n    -- for 'completefunc'/'omnifunc' source function; or `<C-n>`/`<C-p>`).\n    scroll_down = '<C-f>',\n    scroll_up = '<C-b>',\n  },\n}\n```\n\n## Similar plugins\n\n- [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n- [Shougo/ddc.vim](https://github.com/Shougo/ddc.vim)\n"
  },
  {
    "path": "readmes/mini-cursorword.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-cursorword_readme.png?raw=true\" alt=\"mini.cursorword\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Automatic highlighting of word under cursor\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-cursorword.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-cursorword) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-cursorword.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044454-0e4ab873-6e73-448d-838f-45f4b2be876b.mp4\n\n## Features\n\n- Current word under cursor can be highlighted differently.\n- \"Word under cursor\" is meant as in Vim's `<cword>`: something user would get as 'iw' text object.\n- Highlighting stops in insert and terminal modes.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                         |\n    |--------|----------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.cursorword')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.cursorword', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.cursorword', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.cursorword', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                               |\n    |--------|------------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.cursorword'`                         |\n    | Stable | `Plug 'nvim-mini/mini.cursorword', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.cursorword').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Delay (in ms) between when cursor moved and when highlighting appeared\n  delay = 100,\n}\n```\n\n## Similar plugins\n\n- [RRethy/vim-illuminate](https://github.com/RRethy/vim-illuminate)\n- [itchyny/vim-cursorword](https://github.com/itchyny/vim-cursorword)\n"
  },
  {
    "path": "readmes/mini-deps.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-deps_readme.png?raw=true\" alt=\"mini.deps\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Plugin manager\n\nDepends on [`git`](https://git-scm.com/) CLI tool being installed and callable. Make sure to have it set up.\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-deps.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-deps) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-deps.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/e3b0659b-ce79-4464-8601-e0117f38569f\n\n**Note**: This demo features custom `vim.notify()` from [mini.notify](https://nvim-mini.org/mini.nvim/readmes/mini-notify).\n\n## Features\n\n- Manage plugins utilizing Git and built-in packages with these actions:\n    - Add plugin to current session, download if absent.\n    - Update with/without confirm, with/without parallel download of new data.\n    - Delete unused plugins with/without confirm.\n    - Get / set / save / load snapshot.\n\n- Minimal yet flexible plugin specification:\n    - Plugin source.\n    - Name of target plugin directory.\n    - Checkout target: branch, commit, tag, etc.\n    - Monitor branch to track updates without checking out.\n    - Dependencies to be set up prior to the target plugin.\n    - Hooks to call before/after plugin is created/changed.\n\n- Helpers implementing two-stage startup: `now()` and `later()`.\n\nFor more information see these parts of help:\n\n- `:h MiniDeps-overview`\n- `:h MiniDeps-plugin-specification`\n- `:h MiniDeps-commands`\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nInstallation should be done manually with `git clone` in the proper directory. Here is a suggested snippet to put at the top of your 'init.lua':\n\n```lua\n-- Clone 'mini.nvim' manually in a way that it gets managed by 'mini.deps'\nlocal path_package = vim.fn.stdpath('data') .. '/site/'\nlocal mini_path = path_package .. 'pack/deps/start/mini.nvim'\nif not vim.loop.fs_stat(mini_path) then\n  vim.cmd('echo \"Installing `mini.nvim`\" | redraw')\n  local clone_cmd = {\n    'git', 'clone', '--filter=blob:none',\n    'https://github.com/nvim-mini/mini.nvim', mini_path\n  }\n  vim.fn.system(clone_cmd)\n  vim.cmd('packadd mini.nvim | helptags ALL')\n  vim.cmd('echo \"Installed `mini.nvim`\" | redraw')\nend\n\n-- Set up 'mini.deps' (customize to your liking)\nrequire('mini.deps').setup({ path = { package = path_package } })\n```\n\nUsing default 'main' branch is OK, as changes there rarely accidentally break something (so far). However, if you want to be extra safe and use only stable releases of 'mini.nvim', add `MiniDeps.add({ name = 'mini.nvim', checkout = 'stable' })` call after 'mini.deps' is set up and execute `:DepsUpdateOffline mini.nvim`.\n\nTo install from standalone repository, replace any occurrence of 'mini.nvim' in the code snippet to 'mini.deps'.\n\n**NOTE**: 'mini.nvim' is installed in 'pack/deps/start' and not 'pack/deps/opt' to always be included in 'mini.deps' session. If you want to make it \"opt\" plugin (as any other installed plugin), use 'pack/deps/opt' but add `MiniDeps.add('mini.nvim')` call after 'mini.deps' is set up.\n\n## Overview\n\nSee and use [example 'init.lua' file](../scripts/init-deps-example.lua) as a quick demo of how 'mini.deps' can be used:\n\n- Copy its contents into a '~/.config/nvim-deps/init.lua' file (on UNIX systems).\n- Run `NVIM_APPNAME=nvim-deps nvim -- ~/.config/nvim-deps/init.lua` (on Neovim<0.10 might display tree-sitter issues on first start). This will run Neovim with that 'init.lua' as the only config **while completely not affecting your current config**.\n\n### Directory structure\n\nThis module uses built-in packages to make plugins usable in current session. It works with \"pack/deps\" package inside `config.path.package` directory.\n\nBy default \"opt\" subdirectory is used to install optional plugins which are loaded on demand with `MiniDeps.add()`.\nNon-optional plugins in \"start\" subdirectory are supported but only if moved there manually after initial install.\n\n### Add plugin\n\nUse `MiniDeps.add()` to add plugin to current session. Supply plugin's URL source as a string or plugin specification in general. If plugin is not present in \"pack/deps\" package, it will be created (a.k.a. installed) before processing anything else.\n\nThe recommended way of adding a plugin is by calling `MiniDeps.add()` in the 'init.lua' file (make sure `MiniDeps.setup()` is called prior):\n\n```lua\nlocal add = MiniDeps.add\n\n-- Add to current session (install if absent)\nadd({\n  source = 'neovim/nvim-lspconfig',\n  -- Supply dependencies near target plugin\n  depends = { 'williamboman/mason.nvim' },\n})\n\nadd({\n  source = 'nvim-treesitter/nvim-treesitter',\n  -- Use 'master' while monitoring updates in 'main'\n  checkout = 'master',\n  monitor = 'main',\n  -- Perform action after every checkout\n  hooks = { post_checkout = function() vim.cmd('TSUpdate') end },\n})\n-- Possible to immediately execute code which depends on the added plugin\nrequire('nvim-treesitter.configs').setup({\n  ensure_installed = { 'lua', 'vimdoc' },\n  highlight = { enable = true },\n})\n```\n\nNOTE:\n\n- To increase performance, `add()` only ensures presence on disk and nothing else. In particular, it doesn't ensure `opts.checkout` state. Update or modify plugin state explicitly (see later sections).\n\n### Plugin specification\n\nSpecification can be a single string which is inferred as:\n\n- Plugin `name` if it doesn't contain \"/\".\n- Plugin `source` otherwise.\n\nPrimarily, specification is a table with the following fields (see `:h MiniDeps-plugin-specification` for more details):\n\n| Field      | Description                  |\n|------------|------------------------------|\n| `source`   | URI of plugin source         |\n| `name`     | Name to be used on disk      |\n| `checkout` | Target state                 |\n| `monitor`  | Monitor branch               |\n| `depends`  | Array of plugin dependencies |\n| `hooks`    | Table with hooks             |\n\n### Lazy loading\n\nAny lazy-loading is assumed to be done manually by calling `MiniDeps.add()` at appropriate time. This module provides helpers implementing special safe two-stage loading:\n\n- `MiniDeps.now()` safely executes code immediately. Use it to load plugins with UI necessary to make initial screen draw.\n- `MiniDeps.later()` schedules code to be safely executed later, preserving order. Use it (with caution) for everything else which doesn't need precisely timed effect, as it will be executed some time soon on one of the next event loops.\n\n```lua\nlocal now, later = MiniDeps.now, MiniDeps.later\n\n-- Safely execute immediately\nnow(function() vim.cmd('colorscheme miniwinter') end)\nnow(function() require('mini.statusline').setup() end)\n\n-- Safely execute later\nlater(function() require('mini.pick').setup() end)\n```\n\n### Update\n\nTo update plugins from current session with new data from their sources, use `:DepsUpdate`. This will download updates (utilizing multiple cores) and show confirmation buffer. Follow instructions at its top to finish an update.\n\nNOTE: This updates plugins on disk which most likely won't affect current session. Restart Nvim to have them properly loaded.\n\n### Modify\n\nTo change plugin's specification (like set different `checkout`, etc.):\n\n- Update corresponding `MiniDeps.add()` call.\n- Run `:DepsUpdateOffline <plugin_name>`.\n- Review changes and confirm.\n- Restart Nvim.\n\nNOTE: if `add()` prior used a single source string, make sure to convert its argument to `{ source = '<previous_argument>', checkout = '<state>'}`\n\n### Snapshots\n\nUse `:DepsSnapSave` to save state of all plugins from current session into a snapshot file (see `config.path.snapshot`).\n\nUse `:DepsSnapLoad` to load snapshot. This will change (without confirmation) state on disk. Plugins present in both snapshot file and current session will be affected. Restart Nvim to see the effect.\n\nNOTE: loading snapshot does not change plugin's specification defined inside `MiniDeps.add()` call. This means that next update might change plugin's state. To make it permanent, freeze plugin in target state manually.\n\n### Freeze\n\nModify plugin's specification to have `checkout` pointing to a static target: tag, state (commit hash), or 'HEAD' (to freeze in current state).\n\nFrozen plugins will not receive updates. You can monitor any new changes from its source by \"subscribing\" to `monitor` branch which will be shown inside confirmation buffer after `:DepsUpdate`.\n\nExample: use `checkout = 'v0.10.0'` to freeze plugin at tag \"v0.10.0\" while monitoring new versions in the log from `monitor` (usually default) branch.\n\n### Rollback\n\nTo roll back after an unfortunate update:\n\n- Get identifier of latest working state:\n    - Use `:DepsShowLog` to see update log, look for plugin's name, and copy\n      identifier listed as \"State before:\".\n    - See previously saved snapshot file for plugin's name and copy\n      identifier next to it.\n- Freeze plugin at that state while monitoring appropriate branch.\n  Revert to previous shape of `MiniDeps.add()` call to resume updating.\n\n### Remove\n\n- Make sure that target plugin is not registered in current session.\n  Usually it means removing corresponding `MiniDeps.add()` call.\n- Run `:DepsClean`. This will show confirmation buffer with a list of plugins to\n  be deleted from disk. Follow instructions at its top to finish cleaning.\n\nAlternatively, manually delete plugin's directory from \"pack/deps\" package.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Parameters of CLI jobs\n  job = {\n    -- Number of parallel threads to use. Default: 80% of all available.\n    n_threads = nil,\n\n    -- Timeout (in ms) for each job before force quit\n    timeout = 30000,\n  },\n\n  -- Paths describing where to store data\n  path = {\n    -- Directory for built-in package.\n    -- All plugins are actually stored in 'pack/deps' subdirectory.\n    package = vim.fn.stdpath('data') .. '/site',\n\n    -- Default file path for a snapshot\n    snapshot = vim.fn.stdpath('config') .. '/mini-deps-snap',\n\n    -- Log file\n    log = vim.fn.stdpath('log') .. '/mini-deps.log'\n  },\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n- [savq/paq-nvim](https://github.com/savq/paq-nvim)\n- [junegunn/vim-plug](https://github.com/junegunn/vim-plug)\n"
  },
  {
    "path": "readmes/mini-diff.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-diff_readme.png?raw=true\" alt=\"mini.diff\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Work with diff hunks\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-diff.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-diff) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-diff.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/77849127-ee9f-430b-9eff-5a8a724c21ea\n\n## Features\n\n- Visualize difference between buffer text and its configurable reference interactively (updates as you type). This is done per line showing whether it is inside added, changed, or deleted part of difference (called hunk). Visualization can be with customizable colored signs or line numbers.\n\n- Special toggleable overlay view with more hunk details inside text area.\n\n- Completely configurable per buffer source(s) of reference text used to keep it up to date and define interactions with it. Can be array of sources which are attempted to attach in order. By default uses Git source (buffer's file text from Git index as reference).\n\n- Configurable mappings to manage diff hunks:\n    - Apply and reset hunks inside region (selected visually or with a dot-repeatable operator).\n    - \"Hunk range under cursor\" textobject to be used as operator target.\n    - Navigate to first/previous/next/last hunk.\n\nWhat it doesn't do:\n\n- Provide functionality to work directly with Git outside of visualizing and staging (applying) hunks with (default) Git source. In particular, unstaging hunks is not supported.\n\nFor more information see these parts of help:\n\n- `:h MiniDiff-overview`\n- `:h MiniDiff-source-specification`\n- `:h MiniDiff-hunk-specification`\n- `:h MiniDiff-diff-summary`\n\n## Overview\n\n### Diffs and hunks\n\nThe \"diff\" (short for \"difference\") is a result of computing how two text strings differ from one another. This is done on per line basis, i.e. the goal is to compute sequences of lines common to both files, interspersed with groups of differing lines (called \"hunks\").\n\nAlthough computing diff is a general concept (used on its own, in Git, etc.), this module computes difference between current text in a buffer and some reference text which is kept up to date specifically for that buffer. For example, default reference text is computed as file content in Git index. This can be customized in `config.source`.\n\n### Life cycle\n\n- When entering proper (not already enabled, valid, showing text) buffer, it is attempted to be enabled for diff processing.\n- During enabling, attempt attaching the source. This should set up how reference text is kept up to date.\n- On every text change, diff computation is scheduled in debounced fashion after customizable delay (200 ms by default).\n- After the diff is computed, do the following:\n    - Update visualization based on configurable style: either by placing colored text in sign column or coloring line numbers. Colors for both styles are defined per hunk type in corresponding `MiniDiffSign*` highlight group and sign text for \"sign\" style can be configured in `config.view.signs`.\n    - Update overlay view (if it is enabled).\n    - Update `vim.b.minidiff_summary` and `vim.b.minidiff_summary_string` buffer-local variables. These can be used, for example, in statusline.\n    - Trigger `MiniDiffUpdated` `User` event. See `:h MiniDiff-diff-summary` for example of how to use it.\n\nNotes:\n\n- Use `:edit` to reset (disable and re-enable) current buffer.\n\n### Overlay\n\nAlong with basic visualization, there is a special view called \"overlay\". Although it is meant for temporary overview of diff details and can be manually toggled via `MiniDiff.toggle_overlay()`, text can be changed with overlay reacting accordingly.\n\nIt shows more diff details inside text area:\n\n- Added buffer lines are highlighted with `MiniDiffOverAdd` highlight group.\n- Deleted reference lines are shown as virtual text and highlighted with `MiniDiffOverDelete` highlight group.\n- Changed reference lines are shown as virtual text and highlighted with `MiniDiffOverChange` highlight group.\n\n  \"Change\" hunks with equal number of buffer and reference lines have special treatment and show \"word diff\". Reference line is shown next to its buffer counterpart and only changed parts of both lines are highlighted with `MiniDiffOverChange`. The rest of reference line has `MiniDiffOverContext` highlighting.\n\n  This usually is the case when `config.options.linematch` is enabled.\n\n### Mappings\n\nThis module provides mappings for common actions with diffs, like:\n\n- Apply and reset hunks.\n- \"Hunk range under cursor\" textobject.\n- Go to first/previous/next/last hunk range.\n\nExamples:\n\n- `vip` followed by `gh` / `gH` applies/resets hunks inside current paragraph. Same can be achieved in operator form `ghip` / `gHip`, which has the advantage of being dot-repeatable.\n- `gh_` / `gH_` applies/resets current line (even if it is not a full hunk).\n- `ghgh` / `gHgh` applies/resets hunk range under cursor.\n- `dgh` deletes hunk range under cursor.\n- `[H` / `[h` / `]h` / `]H` navigate cursor to the first / previous / next / last hunk range of the current buffer.\n\nMappings for some functionality are assumed to be done manually. See `:h MiniDiff.operator()`.\n\n### Buffer-local variables\n\nEach enabled buffer has the following buffer-local variables which can be used in custom statusline to show an overview of hunks in current buffer:\n\n- `vim.b.minidiff_summary` is a table with the following fields:\n    - `source_name` - name of the source.\n    - `n_ranges` - number of hunk ranges (sequences of contiguous hunks).\n    - `add` - number of added lines.\n    - `change` - number of changed lines.\n    - `delete` - number of deleted lines.\n\n- `vim.b.minidiff_summary_string` is a string representation of summary with a fixed format. It is expected to be used as is. To achieve different formatting, use `vim.b.minidiff_summary` to construct one. The best way to do this is by overriding `vim.b.minidiff_summary_string` in the callback for `MiniDiffUpdated` event:\n\n    ```lua\n    local format_summary = function(data)\n      local summary = vim.b[data.buf].minidiff_summary\n      local t = {}\n      if summary.add > 0 then table.insert(t, '+' .. summary.add) end\n      if summary.change > 0 then table.insert(t, '~' .. summary.change) end\n      if summary.delete > 0 then table.insert(t, '-' .. summary.delete) end\n      vim.b[data.buf].minidiff_summary_string = table.concat(t, ' ')\n    end\n    local au_opts = { pattern = 'MiniDiffUpdated', callback = format_summary }\n    vim.api.nvim_create_autocmd('User', au_opts)\n    ```\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.diff')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.diff', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.diff', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.diff', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.diff'`                         |\n    | Stable | `Plug 'nvim-mini/mini.diff', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.diff').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Options for how hunks are visualized\n  view = {\n    -- Visualization style. Possible values are 'sign' and 'number'.\n    -- Default: 'number' if line numbers are enabled, 'sign' otherwise.\n    style = vim.go.number and 'number' or 'sign',\n\n    -- Signs used for hunks with 'sign' view\n    signs = { add = '▒', change = '▒', delete = '▒' },\n\n    -- Priority of used visualization extmarks\n    priority = 199,\n  },\n\n  -- Source(s) for how reference text is computed/updated/etc\n  -- Uses content from Git index by default\n  source = nil,\n\n  -- Delays (in ms) defining asynchronous processes\n  delay = {\n    -- How much to wait before update following every text change\n    text_change = 200,\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Apply hunks inside a visual/operator region\n    apply = 'gh',\n\n    -- Reset hunks inside a visual/operator region\n    reset = 'gH',\n\n    -- Hunk range textobject to be used inside operator\n    -- Works also in Visual mode if mapping differs from apply and reset\n    textobject = 'gh',\n\n    -- Go to hunk range in corresponding direction\n    goto_first = '[H',\n    goto_prev = '[h',\n    goto_next = ']h',\n    goto_last = ']H',\n  },\n\n  -- Various options\n  options = {\n    -- Diff algorithm. See `:h vim.diff()`.\n    algorithm = 'histogram',\n\n    -- Whether to use \"indent heuristic\". See `:h vim.diff()`.\n    indent_heuristic = true,\n\n    -- The amount of second-stage diff to align lines\n    linematch = 60,\n\n    -- Whether to wrap around edges during hunk navigation\n    wrap_goto = false,\n  },\n}\n```\n\n## Similar plugins\n\n- [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n"
  },
  {
    "path": "readmes/mini-doc.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-doc_readme.png?raw=true\" alt=\"mini.doc\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Generation of help files from EmmyLua-like annotations\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-doc.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-doc) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-doc.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044513-755dec35-4f6c-4a51-aa96-5e380f6d744f.mp4\n\n## Features\n\n- Keep documentation next to code by writing EmmyLua-like annotation comments. They will be parsed as is, so formatting should follow built-in guide. However, custom hooks are allowed at many generation stages for more granular management of output help file.\n- Generation is done by processing a set of ordered files line by line. Each line can either be considered as a part of documentation block (if it matches certain configurable pattern) or not (considered to be an \"afterline\" of documentation block). See `MiniDoc.generate()` help for more details.\n- Processing is done by using nested data structures (section, block, file, doc) describing certain parts of help file. See `MiniDoc-data-structures` help page for more details.\n- Allow flexible customization of output via hook functions.\n- Project specific script can be written as plain Lua file with configuratble path. See `MiniDoc.generate()` help for more details.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                  |\n    |--------|---------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.doc')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.doc', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                 |\n    |--------|----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.doc', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.doc', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.doc'`                         |\n    | Stable | `Plug 'nvim-mini/mini.doc', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.doc').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Lua string pattern to determine if line has documentation annotation.\n  -- First capture group should describe possible section id. Default value\n  -- means that annotation line should:\n  -- - Start with `---` at first column.\n  -- - Any non-whitespace after `---` will be treated as new section id.\n  -- - Single whitespace at the start of main text will be ignored.\n  annotation_pattern = '^%-%-%-(%S*) ?',\n\n  -- Identifier of block annotation lines until first captured identifier\n  default_section_id = '@text',\n\n  -- Hooks to be applied at certain stage of document life cycle. Should\n  -- modify its input in place (and not return new one).\n  hooks = {\n    -- Applied to block before anything else\n    block_pre = --<function: infers header sections (tag and/or signature)>,\n\n    -- Applied to section before anything else\n    section_pre = --<function: replaces current aliases>,\n\n    -- Applied if section has specified captured id\n    sections = {\n      ['@alias'] = --<function: registers alias in MiniDoc.current.aliases>,\n      ['@class'] = --<function>,\n      -- For most typical usage see |MiniDoc.afterlines_to_code|\n      ['@eval'] = --<function: evaluates lines; replaces with their return>,\n      ['@field'] = --<function>,\n      ['@param'] = --<function>,\n      ['@private'] = --<function: registers block for removal>,\n      ['@return'] = --<function>,\n      ['@seealso'] = --<function>,\n      ['@signature'] = --<function: formats signature of documented object>,\n      ['@tag'] = --<function: turns its line in proper tag lines>,\n      ['@text'] = --<function: purposefully does nothing>,\n      ['@type'] = --<function>,\n      ['@usage'] = --<function>,\n    },\n\n    -- Applied to section after all previous steps\n    section_post = --<function: currently does nothing>,\n\n    -- Applied to block after all previous steps\n    block_post = --<function: does many things>,\n\n    -- Applied to file after all previous steps\n    file = --<function: adds separator>,\n\n    -- Applied to doc after all previous steps\n    doc = --<function: adds modeline>,\n\n    -- Applied before output file is written. Takes lines array as argument.\n    write_pre = --<function: removes delimiters at the top>,\n\n    -- Applied after output help file is written. Takes doc as argument.\n    write_post = --<function: various convenience actions>,\n  },\n\n  -- Path (relative to current directory) to script which handles project\n  -- specific help file generation (like custom input files, hooks, etc.).\n  script_path = 'scripts/minidoc.lua',\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [tjdevries/tree-sitter-lua](https://github.com/tjdevries/tree-sitter-lua)\n- [numToStr/lemmy-help](https://github.com/numToStr/lemmy-help) (command line tool)\n"
  },
  {
    "path": "readmes/mini-extra.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-extra_readme.png?raw=true\" alt=\"mini.extra\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Extra 'mini.nvim' functionality\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-extra.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-extra) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-extra.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/31ceb716-eefa-4858-b77f-5b6b3fe594f5\n\n## Features\n\nExtra useful functionality which is not essential enough for other 'mini.nvim' modules to include directly.\n\nFeatures:\n\n- Various pickers for ['mini.pick'](https://nvim-mini.org/mini.nvim/readmes/mini-pick):\n    - Built-in diagnostic (`MiniExtra.pickers.diagnostic()`).\n    - File explorer (`MiniExtra.pickers.explorer()`).\n    - Git branches/commits/files/hunks (`MiniExtra.pickers.git_hunks()`, etc.).\n    - Command/search/input history (`MiniExtra.pickers.history()`).\n    - LSP references/symbols/etc. (`MiniExtra.pickers.lsp()`).\n    - Tree-sitter nodes (`MiniExtra.pickers.treesitter()`).\n    - **And much more**.\n  See `:h MiniExtra.pickers` for more.\n\n- Various textobject specifications for ['mini.ai'](https://nvim-mini.org/mini.nvim/readmes/mini-ai). See `:h MiniExtra.gen_ai_spec`.\n\n- Various highlighters for ['mini.hipatterns'](https://nvim-mini.org/mini.nvim/readmes/mini-hipatterns). See `:h MiniExtra.gen_highlighter`.\n\nNotes:\n\n- This module requires only those 'mini.nvim' modules which are needed for a particular functionality: 'mini.pick' for pickers, etc.\n\nFor more information see these parts of help:\n\n- `:h MiniExtra.pickers`\n- `:h MiniExtra.gen_ai_spec`\n- `:h MiniExtra.gen_highlighter`\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                    |\n    |--------|-----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.extra')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.extra', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                   |\n    |--------|------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.extra', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.extra', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                          |\n    |--------|-------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.extra'`                         |\n    | Stable | `Plug 'nvim-mini/mini.extra', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.extra').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{}\n```\n\n## Similar plugins\n\n- [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n- [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n"
  },
  {
    "path": "readmes/mini-files.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-files_readme.png?raw=true\" alt=\"mini.files\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Navigate and manipulate file system\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-files.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-files) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-files.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/530483a5-fe9a-4e18-9813-a6d609fc89ff\n\n## Features\n\n- Navigate file system using column view (Miller columns) to display nested directories. See `:h MiniFiles-navigation` for overview.\n\n- Opt-in preview of file or directory under cursor.\n\n- Manipulate files and directories by editing text buffers: create, delete, copy, rename, move. See `:h MiniFiles-manipulation` for overview.\n\n- Use as default file explorer instead of `netrw`.\n\n- Configurable:\n    - Filter/prefix/sort of file system entries.\n    - Mappings used for common explorer actions.\n    - UI options: whether to show preview of file/directory under cursor, etc.\n    - Bookmarks for quicker navigation.\n\nSee `:h MiniFiles-examples` for some common configuration examples.\n\nNotes:\n\n- This module is written and thoroughly tested on Linux. Support for other platform/OS (like Windows or MacOS) is a goal, but there is no guarantee.\n\n- This module silently reacts to not enough permissions:\n    - In case of missing file, check its or its parent read permissions.\n    - In case of no manipulation result, check write permissions.\n\n## Dependencies\n\nFor full experience needs (still works without any of suggestions):\n\n- Enabled ['mini.icons'](https://nvim-mini.org/mini.nvim/readmes/mini-icons) module to show icons near file/directory names. Can fall back to using [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) plugin.\n\n## Quick start\n\n### Navigation\n\n- Run `:lua MiniFiles.open()`.\n\n- Navigate:\n    - Press `j`/`k` to navigate down/up.\n    - Press `l` to expand entry under cursor: show directory or open file in the most recent window.\n    - Press `h` to go to parent directory.\n    - Type `m<char>` to set directory path of focused window as bookmark `<char>`. Jump to it with `'<char>`. Go back to before the latest jump with `''`.\n    - Type `g?` for more information about other available mappings and bookmarks.\n    - Move as in any other buffer (`$`, `G`, `f`/`t`, etc.).\n\nFor deeper overview, see `:h MiniFiles-navigation`.\n\n### Manipulation\n\n- Navigate to the directory in which manipulation should be done.\n\n- Edit buffer in the way representing file system action:\n    - **Create file/directory**: create new line like `file` or `dir/`.\n    - **Create file/directory in the descendant directory**: create new line like `dir/file` or `dir/nested/`.\n    - **Delete file/directory**: delete whole line representing that entry.\n    - **Rename file/directory**: change text to the right of that entry's icon.\n    - **Copy file/directory**: copy whole line and paste it in target directory.\n    - **Move file/directory**: cut whole line and paste it in target directory.\n\n- Press `=`; **read confirmation dialog**; confirm with `y`/`<CR>` or not confirm with `n`/`<Esc>`.\n\nFor deeper overview, see `:h MiniFiles-manipulation`.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                    |\n    |--------|-----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.files')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.files', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                   |\n    |--------|------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.files', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.files', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                          |\n    |--------|-------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.files'`                         |\n    | Stable | `Plug 'nvim-mini/mini.files', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.files').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Customization of shown content\n  content = {\n    -- Predicate for which file system entries to show\n    filter = nil,\n    -- Highlight group to use for a file system entry\n    highlight = nil,\n    -- Prefix text and highlight to show to the left of file system entry\n    prefix = nil,\n    -- Order in which to show file system entries\n    sort = nil,\n  },\n\n  -- Module mappings created only inside explorer.\n  -- Use `''` (empty string) to not create one.\n  mappings = {\n    close       = 'q',\n    go_in       = 'l',\n    go_in_plus  = 'L',\n    go_out      = 'h',\n    go_out_plus = 'H',\n    mark_goto   = \"'\",\n    mark_set    = 'm',\n    reset       = '<BS>',\n    reveal_cwd  = '@',\n    show_help   = 'g?',\n    synchronize = '=',\n    trim_left   = '<',\n    trim_right  = '>',\n  },\n\n  -- General options\n  options = {\n    -- Whether to delete permanently or move into module-specific trash\n    permanent_delete = true,\n    -- Whether to use for editing directories\n    use_as_default_explorer = true,\n  },\n\n  -- Customization of explorer windows\n  windows = {\n    -- Maximum number of windows to show side by side\n    max_number = math.huge,\n    -- Whether to show preview of file/directory under cursor\n    preview = false,\n    -- Width of focused window\n    width_focus = 50,\n    -- Width of non-focused window\n    width_nofocus = 15,\n    -- Width of preview window\n    width_preview = 25,\n  },\n}\n```\n\n## Similar plugins\n\n- [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n- [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim)\n- [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n"
  },
  {
    "path": "readmes/mini-fuzzy.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-fuzzy_readme.png?raw=true\" alt=\"mini.fuzzy\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Minimal and fast fuzzy matching\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-fuzzy.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-fuzzy) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-fuzzy.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044594-3599fcec-02d6-4bb7-a47d-23f8400f6656.mp4\n\n## Features\n\n- Function to perform fuzzy matching of one string to others.\n- Sorter for [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                    |\n    |--------|-----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.fuzzy')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.fuzzy', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                   |\n    |--------|------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.fuzzy', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.fuzzy', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                          |\n    |--------|-------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.fuzzy'`                         |\n    | Stable | `Plug 'nvim-mini/mini.fuzzy', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: no need to call `require('mini.fuzzy').setup()`, but it can be done to improve usability.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Maximum allowed value of match features (width and first match). All\n  -- feature values greater than cutoff can be considered \"equally bad\".\n  cutoff = 100,\n}\n```\n\n## Similar plugins\n\n- [nvim-telescope/telescope-fzy-native.nvim](https://github.com/nvim-telescope/telescope-fzy-native.nvim)\n"
  },
  {
    "path": "readmes/mini-git.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-git_readme.png?raw=true\" alt=\"mini.git\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Git integration\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-git.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-git) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-git.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/3c2b34cd-f04f-4e30-9ca4-1ff51e2d65a2\n\n**Note**: This demo uses custom `vim.notify()` from [mini.notify](https://nvim-mini.org/mini.nvim/readmes/mini-notify) and diff line number highlighting from [mini.diff](https://nvim-mini.org/mini.nvim/readmes/mini-diff).\n\n## Features\n\n- Automated tracking of [Git](https://git-scm.com/) related data: root path, status, HEAD, etc. Exposes buffer-local variables for convenient use in statusline.\n\n- `:Git` command for executing any `git` call inside file's repository root with deeper current instance integration (show output as notification/buffer, use to edit commit messages, etc.).\n\n- Helper functions to inspect Git history:\n    - `MiniGit.show_range_history()` shows how certain line range evolved.\n    - `MiniGit.show_diff_source()` shows file state as it was at diff entry.\n    - `MiniGit.show_at_cursor()` shows Git related data depending on context.\n\nWhat it doesn't do:\n\n- Replace fully featured Git client. Rule of thumb: if feature does not rely on a state of current Neovim (opened buffers, etc.), it is out of scope. For more functionality, use either ['mini.diff'](https://nvim-mini.org/mini.nvim/readmes/mini-diff) or fully featured Git client.\n\nFor more information see these parts of help:\n\n- `:h :Git`\n- `:h MiniGit-examples`\n- `:h MiniGit.enable()`\n- `:h MiniGit.get_buf_data()`\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                  |\n    |--------|---------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini-git')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini-git', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                 |\n    |--------|----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini-git', version = false },` |\n    | Stable | `{ 'nvim-mini/mini-git', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini-git'`                         |\n    | Stable | `Plug 'nvim-mini/mini-git', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.git').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- General CLI execution\n  job = {\n    -- Path to Git executable\n    git_executable = 'git',\n\n    -- Timeout (in ms) for each job before force quit\n    timeout = 30000,\n  },\n\n  -- Options for `:Git` command\n  command = {\n    -- Default split direction\n    split = 'auto',\n  },\n}\n```\n\n## Similar plugins\n\n- [tpope/vim-fugitive](https://github.com/tpope/vim-fugitive)\n- [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n- [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n"
  },
  {
    "path": "readmes/mini-hipatterns.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-hipatterns_readme.png?raw=true\" alt=\"mini.hipatterns\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Highlight patterns in text\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-hipatterns.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-hipatterns) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-hipatterns.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/130374e2-4e6c-43cf-af33-43d816b4fa32\n\n## Features\n\n- Highlight text with configurable patterns and highlight groups (can be string or callable).\n\n- Highlighting is updated asynchronously with configurable debounce delay.\n\n- Function to get matches in a buffer.\n\nSee `:h MiniHipatterns-examples` for examples of common use cases.\n\nNotes:\n\n- It does not define any highlighters by default. Add to `config.highlighters` to have a visible effect.\n\n## Example usage\n\n```lua\nlocal hipatterns = require('mini.hipatterns')\nhipatterns.setup({\n  highlighters = {\n    -- Highlight standalone 'FIXME', 'HACK', 'TODO', 'NOTE'\n    fixme = { pattern = '%f[%w]()FIXME()%f[%W]', group = 'MiniHipatternsFixme' },\n    hack  = { pattern = '%f[%w]()HACK()%f[%W]',  group = 'MiniHipatternsHack'  },\n    todo  = { pattern = '%f[%w]()TODO()%f[%W]',  group = 'MiniHipatternsTodo'  },\n    note  = { pattern = '%f[%w]()NOTE()%f[%W]',  group = 'MiniHipatternsNote'  },\n\n    -- Highlight hex color strings (`#rrggbb`) using that color\n    hex_color = hipatterns.gen_highlighter.hex_color(),\n  },\n})\n```\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                         |\n    |--------|----------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.hipatterns')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.hipatterns', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.hipatterns', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.hipatterns', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                               |\n    |--------|------------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.hipatterns'`                         |\n    | Stable | `Plug 'nvim-mini/mini.hipatterns', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.hipatterns').setup()` with non-empty `highlighters` to auto-enable highlighting in all normal buffers.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Table with highlighters (see |MiniHipatterns.config| for more details).\n  -- Nothing is defined by default. Add manually for visible effect.\n  highlighters = {},\n\n  -- Delays (in ms) defining asynchronous highlighting process\n  delay = {\n    -- How much to wait for update after every text change\n    text_change = 200,\n\n    -- How much to wait for update after window scroll\n    scroll = 50,\n  },\n\n}\n```\n\n## Similar plugins\n\n- [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n- [folke/paint.nvim](https://github.com/folke/paint.nvim)\n- [NvChad/nvim-colorizer.lua](https://github.com/NvChad/nvim-colorizer.lua)\n- [uga-rosa/ccc.nvim](https://github.com/uga-rosa/ccc.nvim)\n"
  },
  {
    "path": "readmes/mini-hues.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-hues_readme.png?raw=true\" alt=\"mini.hues\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Generate configurable color scheme\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-hues.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-hues) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-hues.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/236634787-ab0c33df-f697-4d96-a754-d77eccee7513.mp4\n\n### Bundled color schemes\n\n#### Four seasons\n\n- `miniwinter`: \"icy winter\" palette with azure background\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniwinter-dark.png?raw=true\"> <img alt=\"miniwinter dark\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniwinter-dark.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniwinter-light.png?raw=true\"> <img alt=\"miniwinter light\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniwinter-light.png?raw=true\" style=\"width: 45%\"/> </a>\n\n- `minispring`: \"blooming spring\" palette with green background\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minispring-dark.png?raw=true\"> <img alt=\"minispring dark\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minispring-dark.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minispring-light.png?raw=true\"> <img alt=\"minispring light\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minispring-light.png?raw=true\" style=\"width: 45%\"/> </a>\n\n- `minisummer`: \"hot summer\" palette with brown/yellow background\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minisummer-dark.png?raw=true\"> <img alt=\"minisummer dark\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minisummer-dark.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minisummer-light.png?raw=true\"> <img alt=\"minisummer light\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-minisummer-light.png?raw=true\" style=\"width: 45%\"/> </a>\n\n- `miniautumn`: \"cooling autumn\" palette with purple background\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniautumn-dark.png?raw=true\"> <img alt=\"miniautumn dark\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniautumn-dark.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniautumn-light.png?raw=true\"> <img alt=\"miniautumn light\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-miniautumn-light.png?raw=true\" style=\"width: 45%\"/> </a>\n\n#### `randomhue`\n\n`randomhue` uses **randomly generated** background and foreground of same hue (color will change on every `:colorscheme randomhue` call):\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-purple.png?raw=true\"> <img alt=\"Dark purple\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-purple.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-purple.png?raw=true\"> <img alt=\"Light purple\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-purple.png?raw=true\" style=\"width: 45%\"/> </a>\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-azure.png?raw=true\"> <img alt=\"Dark azure\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-azure.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-azure.png?raw=true\"> <img alt=\"Light azure\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-azure.png?raw=true\" style=\"width: 45%\"/> </a>\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-green.png?raw=true\"> <img alt=\"Dark green\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-green.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-green.png?raw=true\"> <img alt=\"Light green\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-green.png?raw=true\" style=\"width: 45%\"/> </a>\n\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-orange.png?raw=true\"> <img alt=\"Dark orange\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_dark-orange.png?raw=true\" style=\"width: 45%\"/> </a>\n<a href=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-orange.png?raw=true\"> <img alt=\"Light orange\" src=\"https://github.com/nvim-mini/assets/blob/main/demo/demo-randomhue_light-orange.png?raw=true\" style=\"width: 45%\"/> </a>\n\n## Example configurations\n\n```lua\n-- Choose background and foreground\nrequire('mini.hues').setup({ background = '#351721', foreground = '#cdc4c6' }) -- red\nrequire('mini.hues').setup({ background = '#361a0d', foreground = '#cdc5c1' }) -- orange\nrequire('mini.hues').setup({ background = '#2c2101', foreground = '#c9c6c0' }) -- yellow\nrequire('mini.hues').setup({ background = '#17280e', foreground = '#c4c8c2' }) -- green\nrequire('mini.hues').setup({ background = '#002923', foreground = '#c0c9c7' }) -- cyan\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc' }) -- azure\nrequire('mini.hues').setup({ background = '#19213a', foreground = '#c4c6cd' }) -- blue\nrequire('mini.hues').setup({ background = '#2b1a33', foreground = '#c9c5cb' }) -- purple\n\n-- Different number of non-base hues\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', n_hues = 6 })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', n_hues = 4 })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', n_hues = 2 })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', n_hues = 0 })\n\n-- Different text saturation\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', saturation = 'low' })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', saturation = 'lowmedium' })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', saturation = 'medium' })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', saturation = 'mediumhigh' })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', saturation = 'high' })\n\n-- Choose accent color\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', accent = 'yellow' })\nrequire('mini.hues').setup({ background = '#002734', foreground = '#c0c8cc', accent = 'blue' })\n```\n\n## Features\n\n- Required to set two base colors: background and foreground. Their shades and other non-base colors are computed to be as much perceptually different as reasonably possible.\n\n- Configurable:\n    - Number of hues used for non-base colors (from 0 to 8).\n    - Saturation level ('low', 'lowmedium', 'medium', 'mediumhigh', 'high').\n    - Accent color used for some selected UI elements.\n    - Plugin integration (can be selectively enabled for faster startup).\n\n- Random generator for base colors. Powers `randomhue` color scheme.\n\n- Lua function to compute palette used in color scheme.\n\n- Bundled color schemes. See [bundled-color-schemes]().\n\nSupported highlight groups:\n\n- All built-in UI and syntax groups.\n\n- Built-in Neovim LSP and diagnostic.\n\n- Tree-sitter.\n\n- LSP semantic tokens.\n\n- Plugins (either with explicit definition or by verification that default highlighting works appropriately):\n    - [nvim-mini/mini.nvim](https://nvim-mini.org/mini.nvim)\n    - [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n    - [anuvyklack/hydra.nvim](https://github.com/anuvyklack/hydra.nvim)\n    - [DanilaMihailov/beacon.nvim](https://github.com/DanilaMihailov/beacon.nvim)\n    - [folke/lazy.nvim](https://github.com/folke/lazy.nvim)\n    - [folke/noice.nvim](https://github.com/folke/noice.nvim)\n    - [folke/snacks.nvim](https://github.com/folke/snacks.nvim)\n    - [folke/todo-comments.nvim](https://github.com/folke/todo-comments.nvim)\n    - [folke/trouble.nvim](https://github.com/folke/trouble.nvim)\n    - [folke/which-key.nvim](https://github.com/folke/which-key.nvim)\n    - [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n    - [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n    - [glepnir/lspsaga.nvim](https://github.com/glepnir/lspsaga.nvim)\n    - [HiPhish/rainbow-delimiters.nvim](https://github.com/HiPhish/rainbow-delimiters.nvim)\n    - [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp)\n    - [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n    - [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n    - [kevinhwang91/nvim-bqf](https://github.com/kevinhwang91/nvim-bqf)\n    - [kevinhwang91/nvim-ufo](https://github.com/kevinhwang91/nvim-ufo)\n    - [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)\n    - [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n    - [MeanderingProgrammer/render-markdown.nvim](https://github.com/MeanderingProgrammer/render-markdown.nvim)\n    - [neoclide/coc.nvim](https://github.com/neoclide/coc.nvim)\n    - [NeogitOrg/neogit](https://github.com/NeogitOrg/neogit)\n    - [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n    - [nvim-neo-tree/neo-tree.nvim](https://github.com/nvim-neo-tree/neo-tree.nvim)\n    - [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n    - [nvim-tree/nvim-tree.lua](https://github.com/nvim-tree/nvim-tree.lua)\n    - [OXY2DEV/helpview.nvim](https://github.com/OXY2DEV/helpview.nvim)\n    - [OXY2DEV/markview.nvim](https://github.com/OXY2DEV/markview.nvim)\n    - [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim)\n    - [rcarriga/nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)\n    - [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n    - [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n    - [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n    - [stevearc/aerial.nvim](https://github.com/stevearc/aerial.nvim)\n    - [williamboman/mason.nvim](https://github.com/williamboman/mason.nvim)\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.hues')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.hues', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.hues', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.hues', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.hues'`                         |\n    | Stable | `Plug 'nvim-mini/mini.hues', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.hues').setup()` **with `background` and `foreground` fields** to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- **Required** base colors as '#rrggbb' hex strings\n  background = nil,\n  foreground = nil,\n\n  -- Number of hues used for non-base colors\n  n_hues = 8,\n\n  -- Saturation. One of 'low', 'lowmedium', 'medium', 'mediumhigh', 'high'.\n  saturation = 'medium',\n\n  -- Accent color. One of: 'bg', 'fg', 'red', 'orange', 'yellow', 'green',\n  -- 'cyan', 'azure', 'blue', 'purple'\n  accent = 'bg',\n\n  -- Plugin integrations. Use `default = false` to disable all integrations.\n  -- Also can be set per plugin (see |MiniHues.config|).\n  plugins = { default = true },\n\n  -- Whether to auto adjust highlight groups based on certain events\n  autoadjust = true,\n}\n```\n\n## Similar plugins\n\n- [mini.base16](https://nvim-mini.org/mini.nvim/readmes/mini-base16)\n"
  },
  {
    "path": "readmes/mini-icons.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-icons_readme.png?raw=true\" alt=\"mini.icons\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Icon provider\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-icons.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-icons) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n![demo-icons_glyph-dark](https://github.com/nvim-mini/assets/blob/main/demo/demo-icons_glyph-dark.png?raw=true)\n\n![demo-icons_ascii](https://github.com/nvim-mini/assets/blob/main/demo/demo-icons_ascii.png?raw=true)\n\n![demo-icons_glyph-light](https://github.com/nvim-mini/assets/blob/main/demo/demo-icons_glyph-light.png?raw=true)\n\n## Features\n\n- Provide icons with their highlighting via a single `MiniIcons.get()` for various categories: filetype, file/directory path, extension, operating system, LSP kind values. Icons and category defaults can be overridden.\n\n- Configurable styles: \"glyph\" (icon glyphs) or \"ascii\" (non-glyph fallback).\n\n- Fixed set of highlight groups (linked to built-in groups by default) for better blend with color scheme.\n\n- Caching for maximum performance.\n\n- Integration with `vim.filetype.add()` and `vim.filetype.match()`.\n\n- Mocking methods of 'nvim-tree/nvim-web-devicons' for better integrations with plugins outside 'mini.nvim'. See `:h MiniIcons.mock_nvim_web_devicons()`.\n\n- Tweaking built-in maps for \"LSP kind\" to include icons. In particular, this makes ['mini.completion'](https://nvim-mini.org/mini.nvim/readmes/mini-completion) use icons in LSP step. See `:h MiniIcons.tweak_lsp_kind()`.\n\nNotes:\n\n- It is not a goal to become a collection of icons for as much use cases as possible. There are specific criteria for icon data to be included as built-in in each category (see `:h MiniIcons.get()`). The main supported category is \"filetype\".\n\nRecommendations for plugin authors using 'mini.icons' as a dependency:\n\n- Check if `_G.MiniIcons` table is present (which means that user explicitly enabled 'mini.icons') and provide icons only if it is.\n\n- Use `MiniIcons.get()` function to get icon string and more data about it.\n\n- For file icons prefer using full path instead of relative or only basename. It makes a difference if path matches pattern that uses parent directories. The `:h MiniIcons.config` has an example of that.\n\n## Dependencies\n\nSuggested dependencies:\n\n- Terminal emulator that supports showing special utf8 glyphs, possibly with \"overflow\" view (displaying is done not in one but two visual cells). Most modern feature-rich terminal emulators support this out of the box: WezTerm, Kitty, Alacritty, iTerm2, Ghostty.\n\n  Not having \"overflow\" feature only results into smaller icons. Not having support for special utf8 glyphs will result into seemingly random symbols (or question mark squares) instead of icon glyphs.\n\n- Font that supports [Nerd Fonts](https://www.nerdfonts.com) icons from version 3.0.0+ (in particular `nf-md-*` class).\n  This should be configured on terminal emulator level either by using font patched with Nerd Fonts icons or using [`NerdFontsSymbolsOnly`](https://github.com/ryanoasis/nerd-fonts/releases) font as a fallback for glyphs that are not supported in main font.\n\nIf using terminal emulator and/or font with icon support is impossible, use `config.style = 'ascii'`. It will use a (less visually appealing) set of non-glyph icons.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                    |\n    |--------|-----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.icons')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.icons', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                   |\n    |--------|------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.icons', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.icons', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                          |\n    |--------|-------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.icons'`                         |\n    | Stable | `Plug 'nvim-mini/mini.icons', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.icons').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Icon style: 'glyph' or 'ascii'\n  style = 'glyph',\n\n  -- Customize per category. See `:h MiniIcons.config` for details.\n  default   = {},\n  directory = {},\n  extension = {},\n  file      = {},\n  filetype  = {},\n  lsp       = {},\n  os        = {},\n\n  -- Control which extensions will be considered during \"file\" resolution\n  use_file_extension = function(ext, file) return true end,\n}\n```\n\n## Similar plugins\n\n- [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n- [onsails/lspkind.nvim](https://github.com/onsails/lspkind.nvim)\n"
  },
  {
    "path": "readmes/mini-indentscope.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-indentscope_readme.png?raw=true\" alt=\"mini.indentscope\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Visualize and work with indent scope\n\n- Customizable debounce delay, animation style, and scope computation options.\n- Implements scope-related motions and textobjects.\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-indentscope.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-indentscope) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-indentscope.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044654-f5f0b928-6bd9-4064-a916-1f980044c7ad.mp4\n\n## Features\n\n- Visualize scope with **animated** vertical line. It is very fast and done automatically in a non-blocking way (other operations can be performed, like moving cursor). You can customize debounce delay and animation rule.\n- Customization of scope computation options can be done on global level (in `MiniIndentscope.config`), for a certain buffer (using `vim.b.miniindentscope_config` buffer variable), or within a call (using `opts` variable in `MiniIndentscope.get_scope()`).\n- Customizable notion of a border: which adjacent lines with strictly lower indent are recognized as such. This is useful for a certain filetypes (for example, Python or plain text).\n- Customizable way of line to be considered \"border first\". This is useful if you want to place cursor on function header and get scope of its body.\n- There are textobjects and motions to operate on scope. Support `v:count` and dot-repeat (in operator pending mode).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                          |\n    |--------|-----------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.indentscope')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.indentscope', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.indentscope', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.indentscope', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                |\n    |--------|-------------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.indentscope'`                         |\n    | Stable | `Plug 'nvim-mini/mini.indentscope', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.indentscope').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Draw options\n  draw = {\n    -- Delay (in ms) between event and start of drawing scope indicator\n    delay = 100,\n\n    -- Animation rule for scope's first drawing. A function which, given\n    -- next and total step numbers, returns wait time (in ms). See\n    -- |MiniIndentscope.gen_animation| for builtin options. To disable\n    -- animation, use `require('mini.indentscope').gen_animation.none()`.\n    animation = --<function: implements constant 20ms between steps>,\n\n    -- Whether to auto draw scope: return `true` to draw, `false` otherwise.\n    -- Default draws only fully computed scope (see `options.n_lines`).\n    predicate = function(scope) return not scope.body.is_incomplete end,\n\n    -- Symbol priority. Increase to display on top of more symbols.\n    priority = 2,\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Textobjects\n    object_scope = 'ii',\n    object_scope_with_border = 'ai',\n\n    -- Motions (jump to respective border line; if not present - body line)\n    goto_top = '[i',\n    goto_bottom = ']i',\n  },\n\n  -- Options which control scope computation\n  options = {\n    -- Type of scope's border: which line(s) with smaller indent to\n    -- categorize as border. Can be one of: 'both', 'top', 'bottom', 'none'.\n    border = 'both',\n\n    -- Whether to use cursor column when computing reference indent.\n    -- Useful to see incremental scopes with horizontal cursor movements.\n    indent_at_cursor = true,\n\n    -- Maximum number of lines above or below within which scope is computed\n    n_lines = 10000,\n\n    -- Whether to first check input line to be a border of adjacent scope.\n    -- Use it if you want to place cursor on function header to get scope of\n    -- its body.\n    try_as_border = false,\n  },\n\n  -- Which character to use for drawing scope indicator\n  symbol = '╎',\n}\n```\n\n## Similar plugins\n\n- [lukas-reineke/indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim)\n- [michaeljsmith/vim-indent-object](https://github.com/michaeljsmith/vim-indent-object)\n"
  },
  {
    "path": "readmes/mini-jump.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-jump_readme.png?raw=true\" alt=\"mini.jump\"  style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Jump to next/previous single character\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-jump.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-jump) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\nInitial idea and implementation by [Adam Blažek](https://github.com/xigoi).\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-jump.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044762-f0f50a73-02df-4432-a79e-54b0ddaa1e48.mp4\n\n## Features\n\n- Extend f, F, t, T to work on multiple lines.\n- Repeat jump by pressing f, F, t, T again. It is reset when cursor moved as a result of not jumping or timeout after idle time (duration customizable).\n- Highlight (after customizable delay) all possible target characters and stop it after some (customizable) idle time.\n- Normal, Visual, and Operator-pending (with dot-repeat as in clean Neovim) modes are supported.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.jump')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.jump', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.jump', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.jump', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.jump'`                         |\n    | Stable | `Plug 'nvim-mini/mini.jump', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.jump').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    forward = 'f',\n    backward = 'F',\n    forward_till = 't',\n    backward_till = 'T',\n    repeat_jump = ';',\n  },\n\n  -- Delay values (in ms) for different functionalities. Set any of them to\n  -- a very big number (like 10^7) to virtually disable.\n  delay = {\n    -- Delay between jump and highlighting all possible jumps\n    highlight = 250,\n\n    -- Delay between jump and automatic stop if idle (no jump is done)\n    idle_stop = 10000000,\n  },\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [rhysd/clever-f.vim](https://github.com/rhysd/clever-f.vim)\n- [justinmk/vim-sneak](https://github.com/justinmk/vim-sneak)\n"
  },
  {
    "path": "readmes/mini-jump2d.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-jump2d_readme.png?raw=true\" alt=\"mini.jump2d\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Jump  within visible lines via iterative label filtering\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-jump2d.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-jump2d) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-jump2d.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/227734716-e7b6f2a8-4db1-441d-9b37-873da6772138.mp4\n\n## Features\n\n- Make jump by iterative filtering of possible, equally considered jump spots until there is only one. Filtering is done by typing a label character that is visualized at jump spot.\n- Customizable:\n    - Way of computing possible jump spots with opinionated default.\n    - Characters used to label jump spots during iterative filtering.\n    - Visual effects: how many steps ahead to show; dim lines with spots.\n    - Action hooks to be executed at certain events during jump.\n    - Allowed windows: current and/or not current.\n    - Allowed lines: whether to process blank or folded lines, lines before/at/after cursor line, etc. Example: user can configure to look for spots only inside current window at or after cursor line.\n    Example: user can configure to look for word starts only inside current window at or after cursor line with 'j' and 'k' labels performing some action after jump.\n- Works in Visual and Operator-pending (with dot-repeat) modes.\n- Preconfigured ways of computing jump spots (see help for `MiniJump2d.builtin_opts()`):\n    - Starts of lines.\n    - Starts of words.\n    - Single character from user input.\n    - Variable length query from user input.\n- Works with multibyte characters.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.jump2d')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.jump2d', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.jump2d', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.jump2d', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.jump2d'`                         |\n    | Stable | `Plug 'nvim-mini/mini.jump2d', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.jump2d').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Function producing jump spots (byte indexed) for a particular line.\n  -- For more information see |MiniJump2d.start|.\n  -- If `nil` (default) - use |MiniJump2d.default_spotter|\n  spotter = nil,\n\n  -- Characters used for labels of jump spots (in supplied order)\n  labels = 'abcdefghijklmnopqrstuvwxyz',\n\n  -- Options for visual effects\n  view = {\n    -- Whether to dim lines with at least one jump spot\n    dim = false,\n\n    -- How many steps ahead to show. Set to big number to show all steps.\n    n_steps_ahead = 0,\n  },\n\n  -- Which lines are used for computing spots\n  allowed_lines = {\n    blank = true, -- Blank line (not sent to spotter even if `true`)\n    cursor_before = true, -- Lines before cursor line\n    cursor_at = true, -- Cursor line\n    cursor_after = true, -- Lines after cursor line\n    fold = true, -- Start of fold (not sent to spotter even if `true`)\n  },\n\n  -- Which windows from current tabpage are used for visible lines\n  allowed_windows = {\n    current = true,\n    not_current = true,\n  },\n\n  -- Functions to be executed at certain events\n  hooks = {\n    before_start = nil, -- Before jump start\n    after_jump = nil, -- After jump was actually done\n  },\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    start_jumping = '<CR>',\n  },\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [phaazon/hop.nvim](https://github.com/phaazon/hop.nvim) (main inspiration behind this module)\n- [ggandor/lightspeed.nvim](https://github.com/ggandor/lightspeed.nvim)\n- [ggandor/leap.nvim](https://github.com/ggandor/leap.nvim)\n- [rlane/pounce.nvim](https://github.com/rlane/pounce.nvim)\n"
  },
  {
    "path": "readmes/mini-keymap.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-keymap_readme.png?raw=true\" alt=\"mini.keymap\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Special key mappings\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-keymap.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-keymap) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-keymap.mp4 -->\nhttps://github.com/user-attachments/assets/a3e34e9f-6901-4e57-a5bd-9508b2c6d065\n\n## Features\n\n- Map keys to perform configurable multi-step actions: if condition for step one is true - execute step one action, else check step two, and so on until falling back to executing original keys. This is usually referred to as \"smart\" keys (like \"smart tab\"). See `:h MiniKeymap.map_multistep()`.\n\n  There are many built-in steps targeted for Insert mode mappings of special keys like `<Tab>`, `<S-Tab>`, `<CR>`, and `<BS>`:\n  - Navigate and accept built-in Insert mode completion. Useful for [mini.completion](https://nvim-mini.org/mini.nvim/readmes/mini-completion).\n  - Navigate and expand [mini.snippets](https://nvim-mini.org/mini.nvim/readmes/mini-snippets).\n  - Execute `<CR>` and `<BS>` respecting [mini.pairs](https://nvim-mini.org/mini.nvim/readmes/mini-pairs).\n  - Jump before/after current tree-sitter node.\n  - Jump before opening and after closing characters (brackets and quotes).\n  - Increase/decrease indent when cursor is inside of it.\n  - Delete all whitespace to the left (\"hungry backspace\").\n  - Navigate built-in snippet engine (`:h vim.snippet`).\n  - Navigate and accept in [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) completion.\n  - Navigate and accept in [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp) completion.\n  - Navigate and expand [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip) snippets.\n  - Execute `<CR>` and `<BS>` respecting [windwp/nvim-autopairs](https://github.com/windwp/nvim-autopairs).\n\n- Map keys as \"combo\": each key acts immediately plus execute extra action if all are typed within configurable delay between each other. See `:h MiniKeymap.map_combo()`.\n\n  Some of the common use cases include:\n    - Map insertable keys (like \"jk\", \"kj\") in Insert and Command-line mode to exit into Normal mode.\n    - Fight against bad habits of pressing the same navigation key by showing a notification if there are too many of them pressed in a row.\n\nSources with more details:\n\n- `:h MiniKeymap-examples`\n\n## Quickstart\n\n### Multi-step\n\nSetup that works well with 'mini.completion' and 'mini.pairs':\n\n```lua\nlocal map_multistep = require('mini.keymap').map_multistep\n\nmap_multistep('i', '<Tab>',   { 'pmenu_next' })\nmap_multistep('i', '<S-Tab>', { 'pmenu_prev' })\nmap_multistep('i', '<CR>',    { 'pmenu_accept', 'minipairs_cr' })\nmap_multistep('i', '<BS>',    { 'minipairs_bs' })\n```\n\n### Combos\n\n\"Better escape\" to Normal mode without having to reach for `<Esc>` key:\n\n```lua\nlocal map_combo = require('mini.keymap').map_combo\n\n-- Support most common modes. This can also contain 't', but would\n-- only mean to press `<Esc>` inside terminal.\nlocal mode = { 'i', 'c', 'x', 's' }\nmap_combo(mode, 'jk', '<BS><BS><Esc>')\n\n-- To not have to worry about the order of keys, also map \"kj\"\nmap_combo(mode, 'kj', '<BS><BS><Esc>')\n\n-- Escape into Normal mode from Terminal mode\nmap_combo('t', 'jk', '<BS><BS><C-\\\\><C-n>')\nmap_combo('t', 'kj', '<BS><BS><C-\\\\><C-n>')\n```\n\nShow notification if there is too much movement by repeating same key:\n\n```lua\nlocal notify_many_keys = function(key)\n  local lhs = string.rep(key, 5)\n  local action = function() vim.notify('Too many ' .. key) end\n  require('mini.keymap').map_combo({ 'n', 'x' }, lhs, action)\nend\nnotify_many_keys('h')\nnotify_many_keys('j')\nnotify_many_keys('k')\nnotify_many_keys('l')\n```\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.keymap')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.keymap', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.keymap', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.keymap', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.keymap'`                         |\n    | Stable | `Plug 'nvim-mini/mini.keymap', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: no need to call `require('mini.keymap').setup()`, but it can be done to improve usability.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{}\n```\n\n## Similar plugins\n\n- [max397574/better-escape.nvim](https://github.com/max397574/better-escape.nvim)\n- [abecodes/tabout.nvim](https://github.com/abecodes/tabout.nvim)\n"
  },
  {
    "path": "readmes/mini-map.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-map_readme.png?raw=true\" alt=\"mini.map\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Window with buffer text overview, scrollbar, and highlights\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-map.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-map) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-map.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/195806215-10e05020-50b7-4bee-9447-ee5af3e971ec.mp4\n\n## Features\n\n- Show and manage special floating window displaying automatically updated overview of current buffer text. Window takes up whole height of Neovim instance and is fixed to a left/right side. Map content is computed by taking all current lines, converting it to binary whitespace/non-whitespace mask, rescaling to appropriate dimensions, and converting back to strings consisting from special encoding symbols. All this is done **very fast** and **asynchronously**.\n\n    See `:h MiniMap.open()`, `:h MiniMap.refresh()`, `:h MiniMap.close()`, `:h MiniMap.toggle()`, `:h MiniMap.toggle_side()`.\n\n    For a general overview and tips, see `:h mini.map-usage`.\n\n- Show scrollbar next to map content. It represents current line and view (top and bottom visible lines). Can be the only thing shown, making map window a \"pure scrollbar\".\n\n- Highlight map lines representing certain data in current buffer. This is done via extensible set of callables, called integrations. There are pre-built generators for common integrations:\n    - Builtin search.\n    - Builtin diagnostic.\n    - General diff hunks provided by ['mini.diff'](https://nvim-mini.org/mini.nvim/readmes/mini-diff).\n    - Hunks provided by ['lewis6991/gitsigns.nvim'](https://github.com/lewis6991/gitsigns.nvim).\n    For more details see `:h MiniMap.gen_integration`.\n\n- Focus on map window to quickly browse current (source) buffer. Moving inside map window updates cursor position in source window enabling fast and targeted buffer exploration. To focus back, hit `<CR>` to accept current explored position or `<Esc>` to go back to original position. See `:h MiniMap.toggle_focus()`.\n\n- Customizable:\n    - Encoding symbols used to display binary information of different resolution (default is 3x2). There are pre-built generators for different basic character families and resolutions. See `:h MiniMap.gen_encode_symbols`.\n    - Scrollbar symbols, separate for line and view. Can have any width (even zero, which virtually disables scrollbar).\n    - Integrations producing map line highlights.\n    - Window options: side (left/right), width, 'winblend', and more.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                  |\n    |--------|---------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.map')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.map', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                 |\n    |--------|----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.map', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.map', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.map'`                         |\n    | Stable | `Plug 'nvim-mini/mini.map', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.map').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Highlight integrations (none by default)\n  integrations = nil,\n\n  -- Symbols used to display data\n  symbols = {\n    -- Encode symbols. See `:h MiniMap.config` for specification and\n    -- `:h MiniMap.gen_encode_symbols` for pre-built ones.\n    -- Default: solid blocks with 3x2 resolution.\n    encode = nil,\n\n    -- Scrollbar parts for view and line. Use empty string to disable any.\n    scroll_line = '█',\n    scroll_view = '┃',\n  },\n\n  -- Window options\n  window = {\n    -- Whether window is focusable in normal way (with `wincmd` or mouse)\n    focusable = false,\n\n    -- Side to stick ('left' or 'right')\n    side = 'right',\n\n    -- Whether to show count of multiple integration highlights\n    show_integration_count = true,\n\n    -- Total width\n    width = 10,\n\n    -- Value of 'winblend' option\n    winblend = 25,\n\n    -- Z-index\n    zindex = 10,\n  },\n}\n```\n\n## Similar plugins\n\n- [wfxr/minimap.vim](https://github.com/wfxr/minimap.vim)\n- [dstein64/nvim-scrollview](https://github.com/dstein64/nvim-scrollview)\n- [petertriho/nvim-scrollbar](https://github.com/petertriho/nvim-scrollbar)\n- [lewis6991/satellite.nvim](https://github.com/lewis6991/satellite.nvim)\n"
  },
  {
    "path": "readmes/mini-misc.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-misc_readme.png?raw=true\" alt=\"mini.misc\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Miscellaneous useful functions\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-misc.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-misc) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-misc.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044891-69b0ccfd-3fe8-4639-bc70-f955bbf4a1a7.mp4\n\n## Features\n\n- `bench_time()` executes function several times and timing how long it took.\n- `log_add()` / `log_show()` and other helper functions to work with a special in-memory log array. Useful when debugging Lua code (instead of `print()`).\n- `put()` and `put_text()` print Lua objects in command line and current buffer respectively.\n- `resize_window()` resizes current window to its editable width.\n- `safely()` to execute a function on a condition and warn on error. Useful to organize 'init.lua' in fail-safe sections with simple lazy loading.\n- `setup_auto_root()` sets up automated change of current directory.\n- `setup_termbg_sync()` to set up terminal background synchronization (removes possible \"frame\" around current Neovim instance).\n- `setup_restore_cursor()` sets up automated restoration of cursor position on file reopen.\n- `stat_summary()` computes summary statistics of numerical array.\n- `tbl_head()` and `tbl_tail()` return first and last elements of table.\n- `zoom()` makes current buffer full screen in a floating window.\n- And more.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.misc')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.misc', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.misc', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.misc', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.misc'`                         |\n    | Stable | `Plug 'nvim-mini/mini.misc', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: no need to call `require('mini.misc').setup()`, but it can be done to improve usability.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Array of fields to make global (to be used as independent variables)\n  make_global = { 'put', 'put_text' },\n}\n```\n\n## Similar plugins\n\n- [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim)\n"
  },
  {
    "path": "readmes/mini-move.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-move_readme.png?raw=true\" alt=\"mini.move\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Move any selection in any direction\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-move.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-move) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-move.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/213466308-2e732d83-7c49-452d-8974-6b18b38bf89f.mp4\n\n## Features\n\n- Works in two modes:\n    - Visual mode. Select text (charwise with `v`, linewise with `V`, and blockwise with `CTRL-V`) and press customizable mapping to move in all four directions (left, right, down, up). It keeps Visual mode.\n    - Normal mode. Press customizable mapping to move current line in all four directions (left, right, down, up).\n    - Special handling of linewise movement:\n        - Vertical movement gets reindented with `=`.\n        - Horizontal movement is improved indent/dedent with `>` / `<`.\n        - Cursor moves along with selection.\n- Provides both mappings and Lua functions for motions. See `:h MiniMove.move_selection()` and `:h MiniMove.move_line()`.\n- Respects `v:count`. Movement mappings can be preceded by a number which multiplies command effect.\n- All consecutive moves (regardless of direction) can be undone by a single `u`.\n- Respects preferred column for vertical movement. It will vertically move selection as how cursor is moving (not strictly vertically if target column is not present in target line).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.move')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.move', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.move', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.move', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.move'`                         |\n    | Stable | `Plug 'nvim-mini/mini.move', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.move').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Move visual selection in Visual mode. Defaults are Alt (Meta) + hjkl.\n    left = '<M-h>',\n    right = '<M-l>',\n    down = '<M-j>',\n    up = '<M-k>',\n\n    -- Move current line in Normal mode\n    line_left = '<M-h>',\n    line_right = '<M-l>',\n    line_down = '<M-j>',\n    line_up = '<M-k>',\n  },\n\n  -- Options which control moving behavior\n  options = {\n    -- Automatically reindent selection during linewise vertical move\n    reindent_linewise = true,\n  },\n}\n```\n\n## Similar plugins\n\n- [matze/vim-move](https://github.com/matze/vim-move)\n- [booperlv/nvim-gomove](https://github.com/booperlv/nvim-gomove)\n"
  },
  {
    "path": "readmes/mini-notify.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-notify_readme.png?raw=true\" alt=\"mini.notify\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Show notifications\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-notify.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-notify) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-notify.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/81014300-3380-4b8c-9ab5-ba09345032d7\n\n## Features\n\n- Show one or more highlighted notifications in a single floating window.\n\n- Manage notifications (add, update, remove, clear).\n\n- Custom `vim.notify()` implementation. To adjust, use `MiniNotify.make_notify()` after calling `setup()`.\n\n- Automated show of LSP progress report.\n\n- Track history which can be accessed with `MiniNotify.get_all()` and shown with `MiniNotify.show_history()`.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.notify')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.notify', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.notify', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.notify', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.notify'`                         |\n    | Stable | `Plug 'nvim-mini/mini.notify', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.notify').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Content management\n  content = {\n    -- Function which formats the notification message\n    -- By default prepends message with notification time\n    format = nil,\n\n    -- Function which orders notification array from most to least important\n    -- By default orders first by level and then by update timestamp\n    sort = nil,\n  },\n\n  -- Notifications about LSP progress\n  lsp_progress = {\n    -- Whether to enable showing\n    enable = true,\n\n    -- Notification level\n    level = 'INFO',\n\n    -- Duration (in ms) of how long last message should be shown\n    duration_last = 1000,\n  },\n\n  -- Window options\n  window = {\n    -- Floating window config\n    config = {},\n\n    -- Maximum window width as share (between 0 and 1) of available columns\n    max_width_share = 0.382,\n\n    -- Value of 'winblend' option\n    winblend = 25,\n  },\n}\n```\n\n## Similar plugins\n\n- [j-hui/fidget.nvim](https://github.com/j-hui/fidget.nvim)\n- [rcarriga/nvim-notify](https://github.com/rcarriga/nvim-notify)\n"
  },
  {
    "path": "readmes/mini-operators.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-operators_readme.png?raw=true\" alt=\"mini.operators\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Text edit operators\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-operators.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-operators) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-operators.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/8a3656c4-c92a-4d9f-9711-8d6a751b3e5a\n\n## Features\n\n- Operators:\n    - Evaluate text and replace with output.\n    - Exchange text regions.\n    - Multiply (duplicate) text.\n    - Replace text with register.\n    - Sort text.\n\n- Automated configurable mappings to operate on textobject, line, selection. Can be disabled in favor of more control with `MiniOperators.make_mappings()`.\n\n- All operators support `[count]` and dot-repeat.\n\nFor more information see theses parts of help:\n- `:h MiniOperators-overview`\n- `:h MiniOperators.config`\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                        |\n    |--------|---------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.operators')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.operators', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                       |\n    |--------|----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.operators', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.operators', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                              |\n    |--------|-----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.operators'`                         |\n    | Stable | `Plug 'nvim-mini/mini.operators', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.operators').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Each entry configures one operator.\n  -- `prefix` defines keys mapped during `setup()`: in Normal mode\n  -- to operate on textobject and line, in Visual - on selection.\n\n  -- Evaluate text and replace with output\n  evaluate = {\n    prefix = 'g=',\n\n    -- Function which does the evaluation\n    func = nil,\n  },\n\n  -- Exchange text regions\n  exchange = {\n    -- NOTE: Default `gx` is remapped to `gX`\n    prefix = 'gx',\n\n    -- Whether to reindent new text to match previous indent\n    reindent_linewise = true,\n  },\n\n  -- Multiply (duplicate) text\n  multiply = {\n    prefix = 'gm',\n\n    -- Function which can modify text before multiplying\n    func = nil,\n  },\n\n  -- Replace text with register\n  replace = {\n    -- NOTE: Default `gr*` LSP mappings are removed\n    prefix = 'gr',\n\n    -- Whether to reindent new text to match previous indent\n    reindent_linewise = true,\n  },\n\n  -- Sort text\n  sort = {\n    prefix = 'gs',\n\n    -- Function which does the sort\n    func = nil,\n  }\n}\n```\n\n## Similar plugins\n\n- [gbprod/substitute.nvim](https://github.com/gbprod/substitute.nvim)\n- [svermeulen/vim-subversive](https://github.com/svermeulen/vim-subversive)\n- [tommcdo/vim-exchange](https://github.com/tommcdo/vim-exchange)\n- [christoomey/vim-sort-motion](https://github.com/christoomey/vim-sort-motion)\n"
  },
  {
    "path": "readmes/mini-pairs.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-pairs_readme.png?raw=true\" alt=\"mini.pairs\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Minimal and fast autopairs\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-pairs.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-pairs) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-pairs.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173044991-18653715-9b4e-444e-a4ba-14eb80bc4e38.mp4\n\n## Features\n\n- Functionality to work with two \"paired\" characters conditional on cursor's neighborhood (character to its left and character to its right).\n- Usage should be through making appropriate mappings using `MiniPairs.map()` or in `MiniPairs.setup()` (for global mapping), `MiniPairs.map_buf()` (for buffer mapping).\n- Pairs get automatically registered for special `<BS>` (all configured modes) and `<CR>` (only Insert mode) mappings. Pressing the key inside pair will delete whole pair and insert extra blank line inside pair respectively. Note: these mappings are autocreated if they do not override existing ones.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                    |\n    |--------|-----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.pairs')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.pairs', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                   |\n    |--------|------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.pairs', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.pairs', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                          |\n    |--------|-------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.pairs'`                         |\n    | Stable | `Plug 'nvim-mini/mini.pairs', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.pairs').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- In which modes mappings from this `config` should be created\n  modes = { insert = true, command = false, terminal = false },\n\n  -- Global mappings. Each right hand side should be a pair information, a\n  -- table with at least these fields (see more in |MiniPairs.map|):\n  -- - <action> - one of 'open', 'close', 'closeopen'.\n  -- - <pair> - two character string for pair to be used.\n  -- By default pair is not inserted after `\\`, quotes are not recognized by\n  -- <CR>, `'` does not insert the pair after a letter.\n  -- Only parts of tables can be tweaked (others will use these defaults).\n  mappings = {\n    ['('] = { action = 'open', pair = '()', neigh_pattern = '^[^\\\\]' },\n    ['['] = { action = 'open', pair = '[]', neigh_pattern = '^[^\\\\]' },\n    ['{'] = { action = 'open', pair = '{}', neigh_pattern = '^[^\\\\]' },\n\n    [')'] = { action = 'close', pair = '()', neigh_pattern = '^[^\\\\]' },\n    [']'] = { action = 'close', pair = '[]', neigh_pattern = '^[^\\\\]' },\n    ['}'] = { action = 'close', pair = '{}', neigh_pattern = '^[^\\\\]' },\n\n    ['\"'] = { action = 'closeopen', pair = '\"\"', neigh_pattern = '^[^\\\\]',   register = { cr = false } },\n    [\"'\"] = { action = 'closeopen', pair = \"''\", neigh_pattern = '^[^%a\\\\]', register = { cr = false } },\n    ['`'] = { action = 'closeopen', pair = '``', neigh_pattern = '^[^\\\\]',   register = { cr = false } },\n  },\n}\n```\n\n## Similar plugins\n\n- [windwp/nvim-autopairs](https://github.com/windwp/nvim-autopairs)\n- [jiangmiao/auto-pairs](https://github.com/jiangmiao/auto-pairs)\n"
  },
  {
    "path": "readmes/mini-pick.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-pick_readme.png?raw=true\" alt=\"mini.pick\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Pick anything\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-pick.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-pick) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-pick.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/65849d1e-3f96-4085-a4cf-f9962cfdbdfd\n\n## Features\n\n- Single window general purpose interface for picking element from any array.\n\n- On demand toggleable preview and info views.\n\n- Interactive query matching (filter+sort) with fast non-blocking default which does fuzzy matching and allows other modes.\n\n- Built-in pickers:\n    - Files.\n    - Pattern match (for fixed pattern or with live feedback; both allow file filtering via glob patterns).\n    - Buffers.\n    - Help tags.\n    - CLI output.\n    - Resume latest picker.\n\n- `:Pick` command to work with extensible `MiniPick.registry`.\n\n- `vim.ui.select()` implementation. To adjust, use `MiniPick.ui_select()` or save-restore `vim.ui.select` manually after calling `MiniPick.setup()`.\n\n- Rich and customizable built-in actions when picker is active:\n    - Manually change currently focused item.\n    - Scroll vertically and horizontally.\n    - Toggle preview or info view.\n    - Mark/unmark items to choose later.\n    - Refine current matches (make them part of a new picker).\n    - And many more.\n\n- Minimal yet flexible source specification with:\n    - Items (array, callable, or manually set later).\n    - Source name.\n    - Working directory.\n    - Matching algorithm.\n    - Way matches are shown in main window.\n    - Item preview.\n    - \"On choice\" action for current and marked items.\n\n- Custom actions/keys can be configured globally, per buffer, or per picker.\n\n- Out of the box support for 'ignorecase' and 'smartcase'.\n\n- Match caching to increase responsiveness on repeated prompts.\n\nNotes:\n\n- Works on all supported versions but Neovim>=0.10 will give more visual feedback in floating window footer.\n\n- For more pickers see ['mini.extra'](https://nvim-mini.org/mini.nvim/readmes/mini-extra).\n\n- CLI tools are called only with basic arguments needed to get items. To customize the output, use their respective configuration approaches. Here are some examples of where to start:\n  - [ripgrep](https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#configuration-file)\n  - [fd](https://github.com/sharkdp/fd#excluding-specific-files-or-directories)\n  - [git](https://git-scm.com/docs/gitignore)\n\nFor more information see these parts of help:\n\n- `:h MiniPick-overview`\n- `:h MiniPick-source`\n- `:h MiniPick-actions`\n- `:h MiniPick-examples`\n- `:h MiniPick.builtin`\n\n## Dependencies\n\nFor full experience needs (still works without any of suggestions):\n\n- Enabled ['mini.icons'](https://nvim-mini.org/mini.nvim/readmes/mini-icons) module for icons near the items representing actual paths. Can fall back to using [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) plugin.\n\n- Executable [BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep) CLI tool for faster file and pattern search on disk.\n\n## Overview\n\nGeneral idea is to take array of objects, display them with interactive filter/sort/navigate/preview, and allow to choose one or more items.\n\n### How to start a picker\n\n- Use `MiniPick.start()` with `opts.source` defining source.\n\n    Example: `MiniPick.start({ source = { items = vim.fn.readdir('.') } })`\n\n- Use any of `MiniPick.builtin` pickers directly.\n\n    Example: `MiniPick.builtin.files({ tool = 'git' })`\n\n- Use `:Pick` command which uses customizable pickers from `MiniPick.registry`.\n\n    Example: `:Pick files tool='git'`\n\n### User interface\n\nUI consists from a single window capable of displaying three different views:\n\n- \"Main\" - where current query matches are shown.\n- \"Preview\" - preview of current item (toggle with `<Tab>`).\n- \"Info\" - general info about picker and its state (toggle with `<S-Tab>`).\n\nCurrent prompt is displayed at the top left of the window border with vertical line indicating caret (current input position).\n\nBottom part of window border displays (in Neovim>=0.10) extra visual feedback:\n\n- Left part is a picker name.\n- Right part contains information in the format:\n\n    `<current index in matches> | <match count> | <marked count> / <total count>`\n\nWhen picker is busy (like if there are no items yet set or matching is active) window border changes color to be `MiniPickBorderBusy` after `config.delay.busy` milliseconds of idle time.\n\n### Life cycle\n\n- Type characters to filter and sort matches. It uses `MiniPick.default_match()` with `query` being an array of pressed characters. Overview of how it matches:\n    - If query starts with `'`, the match is exact.\n    - If query starts with `^`, the match is exact at start.\n    - If query ends with `$`, the match is exact at end.\n    - If query starts with `*`, the match is forced to be fuzzy.\n    - Otherwise match is fuzzy.\n    - Sorting is done to first minimize match width and then match start.\n      Nothing more: no favoring certain places in string, etc.\n\n- Type special keys to perform actions. Here are some basic ones:\n    - `<C-n>` / `<Down>` moves down; `<C-p>` / `<Up>` moves up.\n    - `<Left>` / `<Right>` moves prompt caret left / right.\n    - `<S-Tab>` toggles information window with all available mappings.\n    - `<Tab>` toggles preview.\n    - `<C-x>` / `<C-a>` toggles current / all item(s) as (un)marked.\n    - `<C-Space>` / `<M-Space>` makes all matches or marked items as new picker.\n    - `<CR>` / `<M-CR>` chooses current/marked item(s).\n    - `<Esc>` / `<C-c>` stops picker.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.pick')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.pick', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.pick', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.pick', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.pick'`                         |\n    | Stable | `Plug 'nvim-mini/mini.pick', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.pick').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Delays (in ms; should be at least 1)\n  delay = {\n    -- Delay between forcing asynchronous behavior\n    async = 10,\n\n    -- Delay between computation start and visual feedback about it\n    busy = 50,\n  },\n\n  -- Keys for performing actions. See `:h MiniPick-actions`.\n  mappings = {\n    caret_left  = '<Left>',\n    caret_right = '<Right>',\n\n    choose            = '<CR>',\n    choose_in_split   = '<C-s>',\n    choose_in_tabpage = '<C-t>',\n    choose_in_vsplit  = '<C-v>',\n    choose_marked     = '<M-CR>',\n\n    delete_char       = '<BS>',\n    delete_char_right = '<Del>',\n    delete_left       = '<C-u>',\n    delete_word       = '<C-w>',\n\n    mark     = '<C-x>',\n    mark_all = '<C-a>',\n\n    move_down  = '<C-n>',\n    move_start = '<C-g>',\n    move_up    = '<C-p>',\n\n    paste = '<C-r>',\n\n    refine        = '<C-Space>',\n    refine_marked = '<M-Space>',\n\n    scroll_down  = '<C-f>',\n    scroll_left  = '<C-h>',\n    scroll_right = '<C-l>',\n    scroll_up    = '<C-b>',\n\n    stop = '<Esc>',\n\n    toggle_info    = '<S-Tab>',\n    toggle_preview = '<Tab>',\n  },\n\n  -- General options\n  options = {\n    -- Whether to show content from bottom to top\n    content_from_bottom = false,\n\n    -- Whether to cache matches (more speed and memory on repeated prompts)\n    use_cache = false,\n  },\n\n  -- Source definition. See `:h MiniPick-source`.\n  source = {\n    items = nil,\n    name  = nil,\n    cwd   = nil,\n\n    match   = nil,\n    show    = nil,\n    preview = nil,\n\n    choose        = nil,\n    choose_marked = nil,\n  },\n\n  -- Window related options\n  window = {\n    -- Float window config (table or callable returning it)\n    config = nil,\n\n    -- String to use as caret in prompt\n    prompt_caret = '▏',\n\n    -- String to use as prefix in prompt\n    prompt_prefix = '> ',\n  },\n}\n```\n\n## Similar plugins\n\n- [nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)\n- [ibhagwan/fzf-lua](https://github.com/ibhagwan/fzf-lua)\n"
  },
  {
    "path": "readmes/mini-sessions.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-sessions_readme.png?raw=true\" alt=\"mini.sessions\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Session management (read, write, delete)\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-sessions.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-sessions) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-sessions.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173045087-3d18affc-c76f-4d22-8afc-fef687166ef0.mp4\n\n## Features\n\n- Works using `:mksession` (`'sessionoptions'` is fully respected).\n- Implements both global (from configured directory) and local (from current directory) sessions.\n- No automated new session creation. Use `MiniSessions.write()` manually.\n- Autoread default session (local if detected, else latest written global) if Neovim was called without intention to show something else.\n- Autowrite currently read session before quitting Neovim.\n- Configurable severity level of all actions.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                       |\n    |--------|--------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.sessions')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.sessions', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                      |\n    |--------|---------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.sessions', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.sessions', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                             |\n    |--------|----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.sessions'`                         |\n    | Stable | `Plug 'nvim-mini/mini.sessions', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.sessions').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Whether to read default session if Neovim opened without file arguments\n  autoread = false,\n\n  -- Whether to write currently read session before leaving it\n  autowrite = true,\n\n  -- Directory where global sessions are stored (use `''` to disable)\n  directory = --<\"session\" subdir of user data directory from |stdpath()|>,\n\n  -- File for local session (use `''` to disable)\n  file = 'Session.vim',\n\n  -- Whether to force possibly harmful actions (meaning depends on function)\n  force = { read = false, write = true, delete = false },\n\n  -- Hook functions for actions. Default `nil` means 'do nothing'.\n  hooks = {\n    -- Before successful action\n    pre = { read = nil, write = nil, delete = nil },\n    -- After successful action\n    post = { read = nil, write = nil, delete = nil },\n  },\n\n  -- Whether to print session path after action\n  verbose = { read = false, write = true, delete = true },\n}\n```\n\n## Similar plugins\n\n- [mhinz/vim-startify](https://github.com/mhinz/vim-startify)\n- [Shatur/neovim-session-manager](https://github.com/Shatur/neovim-session-manager)\n"
  },
  {
    "path": "readmes/mini-snippets.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-snippets_readme.png?raw=true\" alt=\"mini.snippets\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Manage and expand snippets\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-snippets.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-snippets) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-snippets.mp4 -->\nhttps://github.com/user-attachments/assets/2cb38960-a26c-48ae-83cd-5fbcaa57d1cf\n\n## Features\n\n- Manage snippet collection by adding it explicitly or with a flexible set of performant built-in loaders. See `:h MiniSnippets.gen_loader`.\n\n- Configured snippets are efficiently resolved before every expand based on current local context. This, for example, allows using different snippets in different local tree-sitter languages (like in markdown code blocks). See `:h MiniSnippets.default_prepare()`.\n\n- Match which snippet to insert based on the currently typed text. Supports both exact and fuzzy matching. See `:h MiniSnippets.default_match()`.\n\n- Select from several matched snippets via `vim.ui.select()`. See `:h MiniSnippets.default_select()`.\n\n- Start specialized in-process LSP server to show loaded snippets inside (auto)completion engines (like [mini.completion](https://nvim-mini.org/mini.nvim/readmes/mini-completion)). See `:h MiniSnippets.start_lsp_server()`.\n\n- Insert, jump, and edit during snippet session in a configurable manner:\n    - Configurable mappings for jumping and stopping.\n    - Jumping wraps around the tabstops for easier navigation.\n    - Easy to reason rules for when session automatically stops.\n    - Text synchronization of linked tabstops preserving relative indent.\n    - Dynamic tabstop state visualization (current/visited/unvisited, etc.)\n    - Inline visualization of empty tabstops (requires Neovim>=0.10).\n    - Works inside comments by preserving comment leader on new lines.\n    - Supports nested sessions (expand snippet while there is an active one).\n\n    See `:h MiniSnippets.default_insert()`.\n\n- Exported function to parse snippet body into easy-to-reason data structure. See `:h MiniSnippets.parse()`.\n\nNotes:\n\n- It does not set up any snippet collection by default. Explicitly populate `config.snippets` to have snippets to match from.\n- It does not come with a built-in snippet collection. It is expected from users to add their own snippets, manually or with dedicated plugin(s).\n- It does not support variable/tabstop transformations in default snippet session. This requires ECMAScript Regular Expression parser which can not be implemented concisely.\n\nSources with more details:\n\n- [Overview](#overview)\n- `:h MiniSnippets-glossary`\n- `:h MiniSnippets-examples`\n- `:h MiniSnippets-in-other-plugins` (for plugin authors)\n\n## Dependencies\n\nThis module doesn't come with snippet collection. Either create it manually or install a dedicated plugin. For example, [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets).\n\n## Quickstart\n\n- Use the following setup:\n\n    ```lua\n    local gen_loader = require('mini.snippets').gen_loader\n    require('mini.snippets').setup({\n      snippets = {\n        -- Load custom file with global snippets first (adjust for Windows)\n        gen_loader.from_file('~/.config/nvim/snippets/global.json'),\n\n        -- Load snippets based on current language by reading files from\n        -- \"snippets/\" subdirectories from 'runtimepath' directories.\n        gen_loader.from_lang(),\n      },\n    })\n    ```\n\n    This setup allows having single file with custom \"global\" snippets (will be present in every buffer) and snippets which will be loaded based on the local language (see `:h MiniSnippets.gen_loader.from_lang()`).\n\n    Create language snippets manually (like by creating and populating '`$XDG_CONFIG_HOME`/nvim/snippets/lua.json' file) or by installing dedicated snippet collection plugin (like [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets)).\n\n\n    **Note**: all built-in loaders cache their output by default. It means that after a file is first read, changing it won't have effect during current Neovim session. See `:h MiniSnippets.gen_loader` about how to reset cache if necessary.\n\n- Open Neovim in a file with dedicated language (like 'init.lua' from your config) and press `<C-j>`.\n\nThe best way to grasp the design of snippet management and expansion is to\ntry them out yourself. Here are extra steps for a basic demo:\n\n- Create 'snippets/global.json' file in the config directory with the content:\n\n    ```json\n    {\n      \"Basic\":        { \"prefix\": \"ba\", \"body\": \"T1=$1 T2=$2 T0=$0\"         },\n      \"Placeholders\": { \"prefix\": \"pl\", \"body\": \"T1=${1:aa}\\nT2=${2:<$1>}\"  },\n      \"Choices\":      { \"prefix\": \"ch\", \"body\": \"T1=${1|a,b|} T2=${2|c,d|}\" },\n      \"Linked\":       { \"prefix\": \"li\", \"body\": \"T1=$1\\n\\tT1=$1\"            },\n      \"Variables\":    { \"prefix\": \"va\", \"body\": \"Runtime: $VIMRUNTIME\\n\"    },\n      \"Complex\":      {\n        \"prefix\": \"co\",\n        \"body\": [ \"T1=${1:$RANDOM}\", \"T3=${3:$1_${2:$1}}\", \"T2=$2\" ]\n      }\n    }\n    ```\n- Open Neovim. Type each snippet prefix and press `<C-j>` (even if there is still active session). Explore from there.\n\n## Overview\n\nSnippet is a template for a frequently used text. Typical workflow is to type snippet's (configurable) prefix and expand it into a snippet session: add some pre-defined text and allow user to interactively change/add at certain places.\n\nThis overview assumes default config for mappings and expand. See `:h MiniSnippets.config` and `:h MiniSnippets-examples` for more details.\n\n### Snippet structure\n\nSnippet consists from three parts:\n\n- `Prefix` - identifier used to match against current text.\n- `Body` - actually inserted content with appropriate syntax.\n- `Desc` - description in human readable form.\n\nExample: `{ prefix = 'tis', body = 'This is snippet', desc = 'Snip' }`\nTyping `tis` and pressing \"expand\" mapping (`<C-j>` by default) will remove \"tis\", add \"This is snippet\", and place cursor at the end in Insert mode.\n\n### Syntax\n\nInserting just text after typing smaller prefix is already powerful enough. For more flexibility, snippet body can be formatted in a special way to provide extra features. This module implements support for syntax defined in [LSP specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#snippet_syntax) (with small deviations).\n\nA quick overview of basic syntax features:\n\n- Tabstops are snippet parts meant for interactive editing at their location. They are denoted as `$1`, `$2`, etc.\n\n  Navigating between them is called \"jumping\" and is done in numerical order of tabstop identifiers by pressing special keys: `<C-l>` and `<C-h>` to jump to next and previous tabstop respectively.\n\n  Special tabstop `$0` is called \"final tabstop\": it is used to decide when snippet session is automatically stopped and is visited last during jumping.\n\n  Example: `T1=$1 T2=$2 T0=$0` is expanded as `T1= T2= T0=` with three tabstops.\n\n- Tabstop can have placeholder: a text used if tabstop is not yet edited. Text is preserved if no editing is done. It follows this same syntax, which means it can itself contain tabstops with placeholders (i.e. be nested). Tabstop with placeholder is denoted as `${1:placeholder}` (`$1` is `${1:}`).\n\n  Example: `T1=${1:text} T2=${2:<$1>}` is expanded as `T1=text T2=<text>`; typing `x` at first placeholder results in `T1=x T2=<x>`; jumping once and typing `y` results in `T1=x T2=y`.\n\n- There can be several tabstops with same identifier. They are linked and updated in sync during text editing. Can also have different placeholders; they are forced to be the same as in the first (from left to right) tabstop.\n\n  Example: `T1=${1:text} T1=$1` is expanded as `T1=text T1=text`; typing `x` at first placeholder results in `T1=x T1=x`.\n\n- Tabstop can also have choices: suggestions about tabstop text. It is denoted as `${1|a,b,c|}`. Choices are shown (with `:h ins-completion` like interface) after jumping to tabstop. First choice is used as placeholder.\n\n  Example: `T1=${1|left,right|}` is expanded as `T1=left`.\n\n- Variables can be used to automatically insert text without user interaction. As tabstops, each one can have a placeholder which is used if variable is not defined. There is a special set of variables describing editor state.\n\n  Example: `V1=$TM_FILENAME V2=${NOTDEFINED:placeholder}` is expanded as `V1=current-file-basename V2=placeholder`.\n\nThere are several differences LSP specification: not supporting variable transformations, wider set of supported special variables, and couple more. For more details see `:h MiniSnippets-syntax-specification`.\n\nThere is a `:h MiniSnippets.parse()` function for programmatically parsing snippet body into a comprehensible data structure.\n\n### Expand\n\nUsing snippets is done via what is called \"expanding\". It goes like this:\n\n- Type snippet prefix or its recognizable part.\n- Press `<C-j>` to expand. It will perform the following steps:\n    - Prepare available snippets in current context (buffer + local language). This allows snippet setup to have general function loaders which return different snippets in different contexts.\n    - Match text to the left of cursor with available prefixes. It first tries to do exact match and falls back to fuzzy matching.\n    - If there are several matches, use `vim.ui.select()` to choose one.\n    - Insert single matching snippet. If snippet contains tabstops, start snippet session.\n\nFor more information see these parts of help:\n\n- `:h MiniSnippets.default_prepare()`\n- `:h MiniSnippets.default_match()`\n- `:h MiniSnippets.default_select()`\n- `:h MiniSnippets.default_insert()`\n\nSnippet session allows interactive editing at tabstop locations:\n\n- All tabstop locations are visualized depending on tabstop \"state\" (whether it is current/visited/unvisited/final and whether it was already edited).\n\n  Empty tabstops are visualized with inline virtual text (`•` / `∎` for regular/final tabstops). It is removed after session is stopped.\n\n- Start session at first tabstop. Type text to replace placeholder. When finished with current tabstop, jump to next with `<C-l>`. Repeat. If changed mind about some previous tabstop, jump back with `<C-h>`. Jumping also wraps around the edge (first tabstop is next after final).\n\n- If tabstop has choices, use `<C-n>` / `<C-p>` to select next / previous item.\n\n- Starting another snippet session while there is an active one is allowed. This creates nested sessions: suspend current, start the new one. After newly created is stopped, resume the suspended one.\n\n- Stop session manually by pressing `<C-c>` or make it stop automatically: if final tabstop is current either make a text edit or exit to Normal mode. If snippet doesn't explicitly define final tabstop, it is added at the end of the snippet.\n\nFor more information about snippet session see `:h MiniSnippets-session`.\n\nTo select and insert snippets via completion engine (that supports LSP completion; like [mini.completion](https://nvim-mini.org/mini.nvim/readmes/mini-completion) or `:h vim.lsp.completion`), call `:h MiniSnippets.start_lsp_server()` after `require('mini.snippets').setup()`. This sets up an LSP server that matches and provides snippets loaded with 'mini.snippets'. To match with completion engine, use `start_lsp_server({ match = false })`.\n\n### Management\n\n**Important**: Out of the box 'mini.snippets' doesn't load any snippets, it should be done explicitly inside `:h MiniSnippets.setup()` following `:h MiniSnippets.config`.\n\nThe suggested approach to snippet management is to create dedicated files with snippet data and load them through function loaders in `config.snippets`. See [Quickstart](#quickstart) for basic (yet capable) snippet management config.\n\nGeneral idea of supported files is to have at least out of the box experience with common snippet collections. Namely [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets).\n\nThe following files are supported:\n\n- Extensions:\n    - Read/decoded as JSON object: `*.json`, `*.code-snippets`\n    - Executed as Lua file and uses returned value: `*.lua`\n\n- Content:\n    - Dict-like: object in JSON; returned table in Lua; no order guarantees.\n    - Array-like: array in JSON; returned array table in Lua; preserves order.\n\nExample of file content with a single snippet:\n\n- Lua dict-like:   `return { name = { prefix = 't', body = 'Text' } }`\n- Lua array-like:  `return { { prefix = 't', body = 'Text', desc = 'name' } }`\n- JSON dict-like:  `{ \"name\": { \"prefix\": \"t\", \"body\": \"Text\" } }`\n- JSON array-like: `[ { \"prefix\": \"t\", \"body\": \"Text\", \"desc\": \"name\" } ]`\n\nGeneral advice:\n\n- Put files in \"snippets\" subdirectory of any path in 'runtimepath' (like '`$XDG_CONFIG_HOME`/nvim/snippets/global.json'). This is compatible with `:h MiniSnippets.gen_loader.from_runtime()` and [Quickstart](#quickstart).\n- Prefer `*.json` files with dict-like content if you want more cross platform setup. Otherwise use `*.lua` files with array-like content.\n\nNotes:\n\n- There is no built-in support for VSCode-like \"package.json\" files. Define structure manually in `:h MiniSnippets.setup()` via built-in or custom loaders.\n- There is no built-in support for `scope` field of snippet data. Snippets are expected to be manually separated into smaller files and loaded on demand.\n\nFor supported snippet syntax see `:h MiniSnippets-syntax-specification` or [Syntax](#syntax).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                       |\n    |--------|--------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.snippets')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.snippets', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                      |\n    |--------|---------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.snippets', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.snippets', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                             |\n    |--------|----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.snippets'`                         |\n    | Stable | `Plug 'nvim-mini/mini.snippets', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.snippets').setup()` with non-empty `snippets` to have snippets to match from.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Array of snippets and loaders (see |MiniSnippets.config| for details).\n  -- Nothing is defined by default. Add manually to have snippets to match.\n  snippets = {},\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    -- Expand snippet at cursor position. Created globally in Insert mode.\n    expand = '<C-j>',\n\n    -- Interact with default `expand.insert` session.\n    -- Created for the duration of active session(s)\n    jump_next = '<C-l>',\n    jump_prev = '<C-h>',\n    stop = '<C-c>',\n  },\n\n  -- Functions describing snippet expansion. If `nil`, default values\n  -- are `MiniSnippets.default_<field>()`.\n  expand = {\n    -- Resolve raw config snippets at context\n    prepare = nil,\n    -- Match resolved snippets at cursor position\n    match = nil,\n    -- Possibly choose among matched snippets\n    select = nil,\n    -- Insert selected snippet\n    insert = nil,\n  },\n}\n```\n\n## Similar plugins\n\n- [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip)\n- Built-in snippet expansion in Neovim>=0.10, see `:h vim.snippet` (doesn't provide snippet management, only snippet expansion).\n- [rafamadriz/friendly-snippets](https://github.com/rafamadriz/friendly-snippets) (a curated collection of snippet files)\n- [abeldekat/cmp-mini-snippets](https://github.com/abeldekat/cmp-mini-snippets) (a source for [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) that integrates 'mini.snippets')\n"
  },
  {
    "path": "readmes/mini-splitjoin.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-splitjoin_readme.png?raw=true\" alt=\"mini.splitjoin\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Split and join arguments\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-splitjoin.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-splitjoin) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-splitjoin.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/223969793-e0e461ff-5a98-444f-9bc3-7b490ebfe59e.mp4\n\n## Features\n\n- Mappings and Lua functions that modify arguments (regions inside brackets between allowed separators) under cursor.\n\n  Supported actions:\n    - Toggle - split if arguments are on single line, join otherwise. Main supported function of the module. See `MiniSplitjoin.toggle()` in help file.\n    - Split - make every argument separator be on end of separate line. See `MiniSplitjoin.split()` in help file.\n    - Join - make all arguments be on single line. See `MiniSplitjoin.join()` in help file.\n\n- Mappings are dot-repeatable in Normal mode and work in Visual mode.\n\n- Customizable argument detection (see `MiniSplitjoin.config.detect` in help file):\n    - Which brackets can contain arguments.\n    - Which strings can separate arguments.\n    - Which regions exclude when looking for separators (like inside nested brackets or quotes).\n\n- Customizable pre and post hooks for both split and join. See `split` and `join` of `MiniSplitjoin.config` in help file.\n\n- Works inside comments by using modified notion of indent. See `MiniSplitjoin.get_indent_part()` in help file.\n\n- Provides low-level Lua functions for split and join at positions. See `MiniSplitjoin.split_at()` and `MiniSplitjoin.join_at()` in help file.\n\nNotes:\n\n- Search for arguments is done using Lua patterns (regex-like approach). Certain amount of false positives is to be expected.\n\n- This module is mostly designed around `MiniSplitjoin.toggle()`. If initial split positions are on different lines, join first and then split.\n\n- Actions can be done on Visual mode selection, which mostly present as a safety route in case of incorrect detection of initial region. It uses `MiniSplitjoin.get_visual_region()` which treats selection as full brackets (use `va)` and not `vi)`).\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                        |\n    |--------|---------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.splitjoin')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.splitjoin', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                       |\n    |--------|----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.splitjoin', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.splitjoin', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                              |\n    |--------|-----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.splitjoin'`                         |\n    | Stable | `Plug 'nvim-mini/mini.splitjoin', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.splitjoin').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Module mappings. Use `''` (empty string) to disable one.\n  -- Created for both Normal and Visual modes.\n  mappings = {\n    toggle = 'gS',\n    split = '',\n    join = '',\n  },\n\n  -- Detection options: where split/join should be done\n  detect = {\n    -- Array of Lua patterns to detect region with arguments.\n    -- Default: { '%b()', '%b[]', '%b{}' }\n    brackets = nil,\n\n    -- String Lua pattern defining argument separator\n    separator = ',',\n\n    -- Array of Lua patterns for sub-regions to exclude separators from.\n    -- Enables correct detection in presence of nested brackets and quotes.\n    -- Default: { '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" }\n    exclude_regions = nil,\n  },\n\n  -- Split options\n  split = {\n    hooks_pre = {},\n    hooks_post = {},\n  },\n\n  -- Join options\n  join = {\n    hooks_pre = {},\n    hooks_post = {},\n  },\n}\n```\n\n## Similar plugins\n\n- [FooSoft/vim-argwrap](https://github.com/FooSoft/vim-argwrap)\n- [AndrewRadev/splitjoin.vim](https://github.com/AndrewRadev/splitjoin.vim)\n- [Wansmer/treesj](https://github.com/Wansmer/treesj)\n"
  },
  {
    "path": "readmes/mini-starter.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-starter_readme.png?raw=true\" alt=\"mini.starter\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Fast and flexible start screen\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-starter.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-starter) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-starter.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173045153-19087983-0211-4ab9-8278-909616b53c7e.mp4\n\n## Features\n\n- All available actions are defined inside items. There are pre-configured whole sections in `MiniStarter.sections`.\n- Configure what items are displayed by supplying an array which can be normalized to an array of items. Read about how supplied items are normalized in `MiniStarter.refresh()`.\n- Modify the final look by supplying content hooks. There are pre-configured content hook generators in `MiniStarter.gen_hook`.\n- Choosing an item can be done in two ways:\n    - Type prefix query to filter item by matching its name (ignoring case). Displayed information is updated after every typed character. For every item its unique prefix is highlighted.\n    - Use Down/Up arrows (or `<C-n>`/`<C-p>`, or `<M-j>`/`<M-k>`) and hit Enter.\n- Allow multiple simultaneously open Starter buffers.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                      |\n    |--------|-------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.starter')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.starter', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                     |\n    |--------|--------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.starter', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.starter', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                            |\n    |--------|---------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.starter'`                         |\n    | Stable | `Plug 'nvim-mini/mini.starter', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.starter').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Whether to open starter buffer on VimEnter. Not opened if Neovim was\n  -- started with intent to show something else.\n  autoopen = true,\n\n  -- Whether to evaluate action of single active item\n  evaluate_single = false,\n\n  -- Items to be displayed. Should be an array with the following elements:\n  -- - Item: table with <action>, <name>, and <section> keys.\n  -- - Function: should return one of these three categories.\n  -- - Array: elements of these three types (i.e. item, array, function).\n  -- If `nil` (default), default items will be used (see |mini.starter|).\n  items = nil,\n\n  -- Header to be displayed before items. Converted to single string via\n  -- `tostring` (use `\\n` to display several lines). If function, it is\n  -- evaluated first. If `nil` (default), polite greeting will be used.\n  header = nil,\n\n  -- Footer to be displayed after items. Converted to single string via\n  -- `tostring` (use `\\n` to display several lines). If function, it is\n  -- evaluated first. If `nil` (default), default usage help will be shown.\n  footer = nil,\n\n  -- Array  of functions to be applied consecutively to initial content.\n  -- Each function should take and return content for 'Starter' buffer (see\n  -- |mini.starter| and |MiniStarter.content| for more details).\n  content_hooks = nil,\n\n  -- Characters to update query. Each character will have special buffer\n  -- mapping overriding your global ones. Be careful to not add `:` as it\n  -- allows you to go into command mode.\n  query_updaters = 'abcdefghijklmnopqrstuvwxyz0123456789_-.',\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [mhinz/vim-startify](https://github.com/mhinz/vim-startify)\n- [glepnir/dashboard-nvim](https://github.com/glepnir/dashboard-nvim)\n- [goolord/alpha-nvim](https://github.com/goolord/alpha-nvim)\n"
  },
  {
    "path": "readmes/mini-statusline.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-statusline_readme.png?raw=true\" alt=\"mini.statusline\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Minimal and fast statusline module with opinionated default look\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-statusline.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-statusline) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-statusline.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173045208-42463c8f-a2ac-488d-9d30-216891f4bb51.mp4\n\n## Features\n\n- Define own custom statusline structure for active and inactive windows. This is done with a function which should return string appropriate for |statusline|. Its code should be similar to default one with structure:\n    - Compute string data for every section you want to be displayed.\n    - Combine them in groups with `MiniStatusline.combine_groups()`.\n- Built-in active mode indicator with colors.\n- Sections can hide information when window is too narrow (specific window width is configurable per section).\n\n## Dependencies\n\nFor full experience needs (still works without any of suggestions):\n\n- [Nerd font](https://www.nerdfonts.com/) and enabled ['mini.icons'](https://nvim-mini.org/mini.nvim/readmes/mini-icons) module to show filetype icons. Can fall back to using [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) plugin.\n\n- Enabled ['mini.git'](https://nvim-mini.org/mini.nvim/readmes/mini-git) and ['mini.diff'](https://nvim-mini.org/mini.nvim/readmes/mini-diff) modules to show Git and diff related information. Can fall back to using [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim) plugin.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                         |\n    |--------|----------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.statusline')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.statusline', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.statusline', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.statusline', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                               |\n    |--------|------------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.statusline'`                         |\n    | Stable | `Plug 'nvim-mini/mini.statusline', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.statusline').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Content of statusline as functions which return statusline string. See\n  -- `:h statusline` and code of default contents (used instead of `nil`).\n  content = {\n    -- Content for active window\n    active = nil,\n    -- Content for inactive window(s)\n    inactive = nil,\n  },\n\n  -- Whether to use icons by default\n  use_icons = true,\n}\n```\n\n## Similar plugins\n\n- [nvim-lualine/lualine.nvim](https://github.com/nvim-lualine/lualine.nvim)\n"
  },
  {
    "path": "readmes/mini-surround.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-surround_readme.png?raw=true\" alt=\"mini.surround\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Fast and feature-rich surround actions\n\n- Add, delete, replace, find, highlight surrounding (like pair of parenthesis, quotes, etc.).\n- Supports dot-repeat for text edits, `v:count`, different search methods, \"last\"/\"next\" extended mappings, customization via Lua patterns or functions, and more.\n- Has builtins for brackets, function call, tag, user prompt, and any alphanumeric/punctuation/whitespace character.\n- Has maintained configuration of setup similar to 'tpope/vim-surround'.\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-surround.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-surround) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-surround.mp4 -->\nhttps://github.com/user-attachments/assets/e91b6e16-7a9c-44aa-afb4-7e07efc3e811\n\n## Features\n\n- Actions (text editing actions are dot-repeatable out of the box and respect `[count]`) with configurable mappings:\n    - Add surrounding with `sa` (in visual mode or on motion).\n    - Delete surrounding with `sd`.\n    - Replace surrounding with `sr`.\n    - Find surrounding with `sf` or `sF` (move cursor right or left).\n    - Highlight surrounding with `sh`.\n- Surrounding is identified by a single character as both \"input\" (in `delete` and `replace` start, `find`, and `highlight`) and \"output\" (in `add` and `replace` end):\n    - 'f' - function call (string of alphanumeric symbols or '_' or '.' followed by balanced '()'). In \"input\" finds function call, in \"output\" prompts user to enter function name.\n    - 't' - tag. In \"input\" finds tag with same identifier, in \"output\" prompts user to enter tag name.\n    - All symbols in brackets '()', '[]', '{}', '<>\". In \"input' represents balanced brackets (open - with whitespace pad, close - without), in \"output\" - left and right parts of brackets.\n    - '?' - interactive. Prompts user to enter left and right parts.\n    - All other single character identifiers (supported by `getcharstr()`) represent surrounding with identical left and right parts.\n- Configurable search methods to find not only covering but possibly next, previous, or nearest surrounding. See more in help for `MiniSurround.config`.\n- All actions involving finding surrounding (delete, replace, find, highlight) can be used with suffix that changes search method to find previous/last. See more in help for `MiniSurround.config`.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                       |\n    |--------|--------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.surround')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.surround', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                      |\n    |--------|---------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.surround', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.surround', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                             |\n    |--------|----------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.surround'`                         |\n    | Stable | `Plug 'nvim-mini/mini.surround', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.surround').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Add custom surroundings to be used on top of builtin ones. For more\n  -- information with examples, see `:h MiniSurround.config`.\n  custom_surroundings = nil,\n\n  -- Duration (in ms) of highlight when calling `MiniSurround.highlight()`\n  highlight_duration = 500,\n\n  -- Module mappings. Use `''` (empty string) to disable one.\n  mappings = {\n    add = 'sa', -- Add surrounding in Normal and Visual modes\n    delete = 'sd', -- Delete surrounding\n    find = 'sf', -- Find surrounding (to the right)\n    find_left = 'sF', -- Find surrounding (to the left)\n    highlight = 'sh', -- Highlight surrounding\n    replace = 'sr', -- Replace surrounding\n\n    suffix_last = 'l', -- Suffix to search with \"prev\" method\n    suffix_next = 'n', -- Suffix to search with \"next\" method\n  },\n\n  -- Number of lines within which surrounding is searched\n  n_lines = 20,\n\n  -- Whether to respect selection type:\n  -- - Place surroundings on separate lines in linewise mode.\n  -- - Place surroundings on each line in blockwise mode.\n  respect_selection_type = false,\n\n  -- How to search for surrounding (first inside current line, then inside\n  -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev',\n  -- 'cover_or_nearest', 'next', 'prev', 'nearest'. For more details,\n  -- see `:h MiniSurround.config`.\n  search_method = 'cover',\n\n  -- Whether to disable showing non-error feedback\n  -- This also affects (purely informational) helper messages shown after\n  -- idle time if user input is required.\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [tpope/vim-surround](https://github.com/tpope/vim-surround)\n- [kylechui/nvim-surround](https://github.com/kylechui/nvim-surround)\n- [machakann/vim-sandwich](https://github.com/machakann/vim-sandwich)\n"
  },
  {
    "path": "readmes/mini-tabline.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-tabline_readme.png?raw=true\" alt=\"mini.tabline\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Minimal and fast tabline showing listed buffers\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-tabline.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-tabline) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-tabline.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173045373-f5bdea82-fe3e-4488-8c9a-ebba062a373c.mp4\n\n## Features\n\n- Buffers are listed in the order of their identifier.\n- Different highlight groups for \"states\" of buffer affecting 'buffer tabs'.\n- Buffer names are made unique by extending paths to files or appending unique identifier to buffers without name.\n- Current buffer is displayed \"optimally centered\" (in center of screen while maximizing the total number of buffers shown) when there are many buffers open.\n- 'Buffer tabs' are clickable if Neovim allows it.\n- Extra information section in case of multiple Neovim tabpages.\n- Truncation symbols which show if there are tabs to the left and/or right. Exact characters are taken from 'listchars' option (`precedes` and `extends` fields) and are shown only if 'list' option is enabled.\n\n## Dependencies\n\nFor full experience needs (still works without any of suggestions):\n\n- Enabled ['mini.icons'](https://nvim-mini.org/mini.nvim/readmes/mini-icons) module to show icons near file names. Can fall back to using [nvim-tree/nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) plugin.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                      |\n    |--------|-------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.tabline')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.tabline', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                     |\n    |--------|--------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.tabline', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.tabline', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                            |\n    |--------|---------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.tabline'`                         |\n    | Stable | `Plug 'nvim-mini/mini.tabline', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.tabline').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Whether to show file icons (requires 'mini.icons')\n  show_icons = true,\n\n  -- Function which formats the tab label\n  -- By default surrounds with space and possibly prepends with icon\n  format = nil,\n\n  -- Where to show tabpage section in case of multiple vim tabpages.\n  -- One of 'left', 'right', 'none'.\n  tabpage_section = 'left',\n}\n```\n\n## Similar plugins\n\n- [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim)\n- [romgrk/barbar.nvim](https://github.com/romgrk/barbar.nvim)\n- [ap/vim-buftabline](https://github.com/ap/vim-buftabline)\n"
  },
  {
    "path": "readmes/mini-test.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-test_readme.png?raw=true\" alt=\"mini.test\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Write and use extensive Neovim plugin tests\n\n- Supports hierarchical tests, hooks, parametrization, filtering (like from current file or cursor position), screen tests, \"busted-style\" emulation, customizable reporters, and more.\n- Designed to be used with provided wrapper for managing child Neovim processes.\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-test.txt). For more hands-on introduction based on examples, see [TESTING.md](https://nvim-mini.org/mini.nvim/TESTING). For more in-depth usage see ['mini.nvim' tests](https://github.com/nvim-mini/mini.nvim/tree/main/tests).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-test) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-test.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/175773105-f33cd3bb-6f62-4a61-95b1-b175e11905bb.mp4\n\n## Features\n\n- Test action is defined as a named callable entry of a table.\n- Helper for creating child Neovim process which is designed to be used in tests (including taking and verifying screenshots). See help for `MiniTest.new_child_neovim()` and `MiniTest.expect.reference_screenshot()`.\n- Hierarchical organization of tests with custom hooks, parametrization, and user data. See help for `MiniTest.new_set()`.\n- Emulation of [Olivine-Labs/busted](https://github.com/Olivine-Labs/busted) interface (`describe`, `it`, etc.).\n- Predefined small yet usable set of expectations (`assert`-like functions). See help for `MiniTest.expect`.\n- Customizable definition of what files should be tested.\n- Test case filtering. There are predefined wrappers for testing a file (`MiniTest.run_file()`) and case at a location like current cursor position (`MiniTest.run_at_location()`).\n- Customizable reporter of output results. There are two predefined ones:\n    - `MiniTest.gen_reporter.buffer()` for interactive usage.\n    - `MiniTest.gen_reporter.stdout()` for headless Neovim.\n- Customizable project specific testing script.\n- Works on Unix (Linux, MacOS, etc.) and Windows.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                   |\n    |--------|----------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.test')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.test', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.test', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.test', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.test'`                         |\n    | Stable | `Plug 'nvim-mini/mini.test', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.test').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Options for collection of test cases. See `:h MiniTest.collect()`.\n  collect = {\n    -- Temporarily emulate functions from 'busted' testing framework\n    -- (`describe`, `it`, `before_each`, `after_each`, and more)\n    emulate_busted = true,\n\n    -- Function returning array of file paths to be collected.\n    -- Default: all Lua files in 'tests' directory starting with 'test_'.\n    find_files = function()\n      return vim.fn.globpath('tests', '**/test_*.lua', true, true)\n    end,\n\n    -- Predicate function indicating if test case should be executed\n    filter_cases = function(case) return true end,\n  },\n\n  -- Options for execution of test cases. See `:h MiniTest.execute()`.\n  execute = {\n    -- Table with callable fields `start()`, `update()`, and `finish()`\n    reporter = nil,\n\n    -- Whether to stop execution after first error\n    stop_on_error = false,\n  },\n\n  -- Path (relative to current directory) to script which handles project\n  -- specific test running\n  script_path = 'scripts/minitest.lua',\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n}\n```\n\n## Similar plugins\n\n- [nvim-lua/plenary.nvim](https://github.com/nvim-lua/plenary.nvim) ('test_harness', 'busted', 'luassert' modules)\n"
  },
  {
    "path": "readmes/mini-trailspace.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-trailspace_readme.png?raw=true\" alt=\"mini.trailspace\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Work with trailing whitespace\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-trailspace.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-trailspace) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-trailspace.mp4 -->\nhttps://user-images.githubusercontent.com/24854248/173045420-7aaf21b6-1d2e-4333-8a23-dea7e49c3a01.mp4\n\n## Features\n\n- Highlighting is done only in modifiable buffer by default, only in Normal mode, and stops in Insert mode and when leaving window.\n- Trim all trailing whitespace with `MiniTrailspace.trim()`.\n- Trim all trailing empty lines with `MiniTrailspace.trim_last_lines()`.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                         |\n    |--------|----------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.trailspace')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.trailspace', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                        |\n    |--------|-----------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.trailspace', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.trailspace', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                               |\n    |--------|------------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.trailspace'`                         |\n    | Stable | `Plug 'nvim-mini/mini.trailspace', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.trailspace').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- Highlight only in normal buffers (ones with empty 'buftype'). This is\n  -- useful to not show trailing whitespace where it usually doesn't matter.\n  only_in_normal_buffers = true,\n}\n```\n\n## Similar plugins\n\n- [ntpeters/vim-better-whitespace](https://github.com/ntpeters/vim-better-whitespace)\n"
  },
  {
    "path": "readmes/mini-visits.md",
    "content": "<p align=\"center\"> <img src=\"https://github.com/nvim-mini/assets/blob/main/logo-2/logo-visits_readme.png?raw=true\" alt=\"mini.visits\" style=\"max-width:100%;border:solid 2px\"/> </p>\n\n### Track and reuse file system visits\n\nSee more details in [Features](#features) and [Documentation](../doc/mini-visits.txt).\n\n---\n\n> [!NOTE]\n> This was previously hosted at a personal `echasnovski` GitHub account. It was transferred to a dedicated organization to improve long term project stability. See more details [here](https://github.com/nvim-mini/mini.nvim/discussions/1970).\n\n⦿ This is a part of [mini.nvim](https://nvim-mini.org/mini.nvim) library. Please use [this link](https://nvim-mini.org/mini.nvim/readmes/mini-visits) if you want to mention this module.\n\n⦿ All contributions (issues, pull requests, discussions, etc.) are done inside of 'mini.nvim'.\n\n⦿ See [whole library documentation](https://nvim-mini.org/mini.nvim/doc/mini-nvim) to learn about general design principles, disable/configuration recipes, and more.\n\n⦿ See [MiniMax](https://nvim-mini.org/MiniMax) for a full config example that uses this module.\n\n---\n\nIf you want to help this project grow but don't know where to start, check out [contributing guides of 'mini.nvim'](https://nvim-mini.org/mini.nvim/CONTRIBUTING) or leave a Github star for 'mini.nvim' project and/or any its standalone Git repositories.\n\n## Demo\n\n<!-- Demo source: https://github.com/nvim-mini/assets/blob/main/demo/demo-visits.mp4 -->\nhttps://github.com/nvim-mini/mini.nvim/assets/24854248/ad8ff054-9b95-4e9c-84b1-b39ddba9d7d3\n\n**Note**: This demo uses custom `vim.ui.select()` from [mini.pick](https://nvim-mini.org/mini.nvim/readmes/mini-pick).\n\n## Features\n\n- Persistently track file system visits (both files and directories) per project directory. Store visit index is human readable and editable.\n\n- Visit index is normalized on every write to contain relevant information. Exact details can be customized. See `:h MiniVisits.normalize()`.\n\n- Built-in ability to persistently use label paths for later use. See `:h MiniVisits.add_label()` and `:h MiniVisits.remove_label()`.\n\n- Exported functions to reuse visit data:\n    - List visited paths/labels with custom filter and sort (uses \"robust frecency\" by default). Can be used as source for pickers.\n\n      See `:h MiniVisits.list_paths()` and `:h MiniVisits.list_labels()`. See `:h MiniVisits.gen_filter` and `:h MiniVisits.gen_sort`.\n\n    - Select visited paths/labels using `vim.ui.select()`.\n\n      See `:h MiniVisits.select_path()` and `:h MiniVisits.select_label()`.\n\n    - Iterate through visit paths in target direction (\"forward\", \"backward\", \"first\", \"last\"). See `:h MiniVisits.iterate_paths()`.\n\n- Exported functions to manually update visit index allowing persistent track of any user information. See `*_index()` functions.\n\nNotes:\n\n- All data is stored _only_ in in-session Lua variable (for quick operation) and at `config.store.path` on disk (for persistent usage).\n\n- It doesn't account for paths being renamed or moved (because there is no general way to detect that). Usually a manual intervention to the visit index is required after the change but _before_ the next writing to disk (usually before closing current session) because it will treat previous path as deleted and remove it from index.\n\n    There is a `MiniVisits.rename_in_index()` helper for that.\n    If rename/move is done with ['mini.files'](https://nvim-mini.org/mini.nvim/readmes/mini-files), index is autoupdated.\n\nFor more information see these parts of help:\n\n- `:h MiniVisits-overview`\n- `:h MiniVisits-index-specification`\n- `:h MiniVisits-examples`\n\n## Overview\n\n### Tracking visits\n\nFile system visits (both directory and files) tracking is done in two steps:\n\n- On every dedicated event timer is (re)started to actually register visit after certain amount of time.\n\n- When delay time passes without any dedicated events being triggered (meaning user is \"settled\" on certain buffer), visit is registered if all of the following conditions are met:\n    - Module is not disabled.\n    - Buffer is normal with non-empty name (used as visit path).\n    - Visit path does not equal to the latest tracked one.\n\nVisit is autoregistered for current directory and leads to increase of count\nand latest time of visit. See `:h MiniVisits-index-specification` for more details.\n\nNotes:\n\n- All data is stored _only_ in in-session Lua variable (for quick operation) and in one place on disk (for persistent usage). It is automatically written to disk before every Neovim exit.\n\n- Tracking can be disabled by supplying empty string as `track.event`. Then it is up to the user to properly call `MiniVisits.register_visit()`.\n\n### Reusing visits\n\nVisit data can be reused in at least these ways:\n\n- Get a list of visited paths and use it to visualize/pick/navigate visit history.\n\n- Select one of the visited paths to open it.\n\n- Move along visit history.\n\n- Utilize labels. Any visit can be added one or more labels (like \"core\", \"tmp\", etc.). They are bound to the visit and are stored persistently.\n\n    Labels can be used to manually create groups of files and/or directories that have particular interest to the user.\n\n    There is no one right way to use them, though. See `:h MiniVisits-examples` for some inspiration.\n\n- Utilizing custom data. Visit index can be manipulated manually using\n  `_index()` set of functions. All \"storable\" user data inside index is then stored on disk, so it can be used to create any kind of workflow user wants.\n\nSee `:h MiniVisits-examples` for some actual configuration and workflow examples.\n\n## Installation\n\nThis plugin can be installed as part of 'mini.nvim' library (**recommended**) or as a standalone Git repository.\n\nThere are two branches to install from:\n\n- `main` (default, **recommended**) will have latest development version of plugin. All changes since last stable release should be perceived as being in beta testing phase (meaning they already passed alpha-testing and are moderately settled).\n- `stable` will be updated only upon releases with code tested during public beta-testing phase in `main` branch.\n\nHere are code snippets for some common installation methods (use only one):\n\n<details>\n<summary>With <a href=\"https://nvim-mini.org/mini.nvim/readmes/mini-deps\">mini.deps</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | *Follow recommended 'mini.deps' installation* |\n    | Stable | *Follow recommended 'mini.deps' installation* |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                                     |\n    |--------|------------------------------------------------------------------|\n    | Main   | `add('nvim-mini/mini.visits')`                                   |\n    | Stable | `add({ source = 'nvim-mini/mini.visits', checkout = 'stable' })` |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/folke/lazy.nvim\">folke/lazy.nvim</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                  |\n    |--------|-----------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.nvim', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.nvim', version = '*' },`   |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                    |\n    |--------|-------------------------------------------------|\n    | Main   | `{ 'nvim-mini/mini.visits', version = false },` |\n    | Stable | `{ 'nvim-mini/mini.visits', version = '*' },`   |\n\n</details>\n\n<details>\n<summary>With <a href=\"https://github.com/junegunn/vim-plug\">junegunn/vim-plug</a></summary>\n\n- 'mini.nvim' library:\n\n    | Branch | Code snippet                                         |\n    |--------|------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.nvim'`                         |\n    | Stable | `Plug 'nvim-mini/mini.nvim', { 'branch': 'stable' }` |\n\n- Standalone plugin:\n\n    | Branch | Code snippet                                           |\n    |--------|--------------------------------------------------------|\n    | Main   | `Plug 'nvim-mini/mini.visits'`                         |\n    | Stable | `Plug 'nvim-mini/mini.visits', { 'branch': 'stable' }` |\n\n</details>\n\n**Important**: don't forget to call `require('mini.visits').setup()` to enable its functionality.\n\n**Note**: if you are on Windows, there might be problems with too long file paths (like `error: unable to create file <some file name>: Filename too long`). Try doing one of the following:\n\n- Enable corresponding git global config value: `git config --system core.longpaths true`. Then try to reinstall.\n- Install plugin in other place with shorter path.\n\n## Default config\n\n```lua\n-- No need to copy this inside `setup()`. Will be used automatically.\n{\n  -- How visit index is converted to list of paths\n  list = {\n    -- Predicate for which paths to include (all by default)\n    filter = nil,\n\n    -- Sort paths based on the visit data (robust frecency by default)\n    sort = nil,\n  },\n\n  -- Whether to disable showing non-error feedback\n  silent = false,\n\n  -- How visit index is stored\n  store = {\n    -- Whether to write all visits before Neovim is closed\n    autowrite = true,\n\n    -- Function to ensure that written index is relevant\n    normalize = nil,\n\n    -- Path to store visit index\n    path = vim.fn.stdpath('data') .. '/mini-visits-index',\n  },\n\n  -- How visit tracking is done\n  track = {\n    -- Start visit register timer at this event\n    -- Supply empty string (`''`) to not do this automatically\n    event = 'BufEnter',\n\n    -- Debounce delay after event to register a visit\n    delay = 1000,\n  },\n}\n```\n\n## Similar plugins\n\n- [nvim-telescope/telescope-frecency.nvim](https://github.com/nvim-telescope/telescope-frecency.nvim)\n- [ThePrimeagen/harpoon](https://github.com/ThePrimeagen/harpoon)\n"
  },
  {
    "path": "scripts/dual_log.sh",
    "content": "# Check standalone repos result\nlocal_repos=\"$( ls -d dual/repos/*/ )\"\n\nfor repo in $local_repos; do\n  cd $repo > /dev/null\n  # Show only logs with actual changes (saves screen lines)\n  if [ $( git rev-parse main ) != $( git rev-parse origin/main ) ]\n  then\n    printf \"\\n\\033[1m$( basename $repo )\\033[0m\\n\"\n    git log origin/main..main --abbrev-commit --format=oneline\n  fi\n  cd - > /dev/null\ndone\n"
  },
  {
    "path": "scripts/dual_push.sh",
    "content": "# Push standalone repos result\nlocal_repos=\"$( ls -d dual/repos/*/ )\"\n\nfor repo in $local_repos; do\n  cd $repo > /dev/null\n  # Push only if there is something to push (saves time)\n  if [ $( git rev-parse main ) != $( git rev-parse origin/main ) ]\n  then\n    printf \"\\n\\033[1mPushing $( basename $repo )\\033[0m\\n\"\n    git push origin main\n  fi\n  cd - > /dev/null\ndone\n\necho ''\n"
  },
  {
    "path": "scripts/dual_release.sh",
    "content": "# Make release from current commits\n# **IMPORTANT**: sync repos (`make dual_sync` and `make dual_push`) before this\n\n# Register tag name and message as script arguments\nif [ -z \"$1\" ] || [ -z \"$2\" ]\nthen\n  printf \"Supply tag name and message as script arguments\\n\"\n  exit 2\nfi\ntag_name=$1\ntag_message=$2\n\nrepos_dir=dual/repos\nmkdir -p $repos_dir\n\nrelease_module () {\n  # First argument is a string with module name\n  module=$1\n  shift\n\n  repo=\"$( realpath $repos_dir/mini.$module )\"\n  printf \"\\n\\033[1mReleasing $( basename $repo )\\033[0m\\n\"\n\n  # Possibly pull whole repository\n  if [[ ! -d $repo ]]\n  then\n    printf \"\\033[4mPulling missing repository\\033[0m\\n\"\n    # Handle 'mini.git' differently because GitHub repo is named 'mini-git'\n    # (\".git\" suffix is not allowed as repo name on GitHub)\n    if [ $module = \"git\" ]; then github_repo=\"mini-git\"; else github_repo=\"mini.$module\"; fi\n    git clone --filter=blob:none https://github.com/nvim-mini/$github_repo.git $repo\n  fi\n\n  cd $repo > /dev/null\n\n  # Ensure `stable` branch points to latest `main`\n  printf \"\\033[4mMaking \\`stable\\` point to latest \\`main\\`\\033[0m\\n\"\n  git checkout main\n  git pull --unshallow\n  git checkout -B stable\n  git checkout main\n  echo ''\n\n  # Create tag\n  printf \"\\033[4mCreating tag\\033[0m\\n\"\n  git tag -a \"$tag_name\" -m \"$tag_message\"\n  echo ''\n\n  # Push\n  printf \"\\033[4mPushing\\033[0m\\n\"\n  git push origin $tag_name\n  git push origin stable\n  echo ''\n\n  cd - > /dev/null\n}\n\nrelease_module \"ai\"\nrelease_module \"align\"\nrelease_module \"animate\"\nrelease_module \"base16\"\nrelease_module \"basics\"\nrelease_module \"bracketed\"\nrelease_module \"bufremove\"\nrelease_module \"clue\"\nrelease_module \"cmdline\"\nrelease_module \"colors\"\nrelease_module \"comment\"\nrelease_module \"completion\"\nrelease_module \"cursorword\"\nrelease_module \"deps\"\nrelease_module \"diff\"\nrelease_module \"doc\"\nrelease_module \"extra\"\nrelease_module \"files\"\nrelease_module \"fuzzy\"\nrelease_module \"git\"\nrelease_module \"hipatterns\"\nrelease_module \"hues\"\nrelease_module \"icons\"\nrelease_module \"indentscope\"\nrelease_module \"jump\"\nrelease_module \"jump2d\"\nrelease_module \"keymap\"\nrelease_module \"map\"\nrelease_module \"misc\"\nrelease_module \"move\"\nrelease_module \"notify\"\nrelease_module \"operators\"\nrelease_module \"pairs\"\nrelease_module \"pick\"\nrelease_module \"sessions\"\nrelease_module \"snippets\"\nrelease_module \"splitjoin\"\nrelease_module \"starter\"\nrelease_module \"statusline\"\nrelease_module \"surround\"\nrelease_module \"tabline\"\nrelease_module \"test\"\nrelease_module \"trailspace\"\nrelease_module \"visits\"\n"
  },
  {
    "path": "scripts/dual_sync.sh",
    "content": "# Perform local sync of standalone repositories, but only if on `main` branch\nbranch=\"$( git symbolic-ref --short HEAD )\"\nif [[ $branch != \"main\" ]]\nthen\n  printf \"\\nDo sync only for 'main' branch, not '$branch'\\n\\n\"\n  exit 2\nfi\n\nrepos_dir=dual/repos\npatches_dir=dual/patches\n\nmkdir -p $repos_dir\nmkdir -p $patches_dir\n\nsync_module () {\n  # First argument is a string with module name. Others - extra paths to track\n  # for module.\n  module=$1\n  shift\n\n  repo=\"$( realpath $repos_dir/mini.$module )\"\n  patch=\"$( realpath $patches_dir/mini.$module.patch )\"\n\n  # Make patch with commits from 'sync' branch to current HEAD which affect\n  # files related to the module\n  git format-patch sync..HEAD --output $patch -- \\\n    lua/mini/$module.lua \\\n    doc/mini-$module.txt \\\n    readmes/mini-$module.md \\\n    LICENSE \\\n    $@\n\n  # Do nothing if patch is empty\n  if [[ ! -s $patch ]]\n  then\n    rm $patch\n    # Return early to skip unnecessary repo pull (saves time)\n    return\n  fi\n\n  printf \"\\n\\033[1mmini.$module\\033[0m\\n\"\n\n  # Tweak patch:\n  # - Move 'readmes/mini-xxx.md' to 'README.md'. This should modify only patch\n  #   metadata, and not text (assuming it uses 'readmes/mini-xxx.md' on\n  #   purpose; as in \"use [this link](https://.../readmes/mini-xxx.md)\").\n  sed -i \"s/readmes\\/mini-$module\\.md\\([^)]\\)/README.md\\\\1/\" $patch\n  sed -i \"s/readmes\\/mini-$module\\.md$/README.md/\" $patch\n  # - Move all known relative links one step higher (and hope that it doesn't\n  #   occur anywhere else in patch). NOTE: There can be other relative links\n  #   which should be corrected manually\n  sed -i \"s/\\[Documentation\\](\\.\\.\\/doc/[Documentation](doc/\" $patch\n\n  # Possibly pull repository\n  if [[ ! -d $repo ]]\n  then\n    printf \"Pulling\\n\"\n    # Handle 'mini.git' differently because GitHub repo is named 'mini-git'\n    # (\".git\" suffix is not allowed as repo name on GitHub)\n    if [ $module = \"git\" ]; then github_repo=\"mini-git\"; else github_repo=\"mini.$module\"; fi\n    git clone --filter=blob:none https://github.com/nvim-mini/$github_repo.git $repo >/dev/null 2>&1\n  fi\n\n  # Apply patch\n  printf \"Applying patch\\n\"\n  cd $repo > /dev/null\n  git am $patch\n  cd - > /dev/null\n}\n\nsync_module \"ai\"\nsync_module \"align\"\nsync_module \"animate\"\nsync_module \"base16\" colors/minischeme.lua colors/minicyan.lua\nsync_module \"basics\"\nsync_module \"bracketed\"\nsync_module \"bufremove\"\nsync_module \"clue\"\nsync_module \"cmdline\"\nsync_module \"colors\"\nsync_module \"comment\"\nsync_module \"completion\"\nsync_module \"cursorword\"\nsync_module \"deps\" scripts/init-deps-example.lua\nsync_module \"diff\"\nsync_module \"doc\"\nsync_module \"extra\"\nsync_module \"files\"\nsync_module \"fuzzy\"\nsync_module \"git\"\nsync_module \"hipatterns\"\nsync_module \"hues\" colors/miniwinter.lua colors/minispring.lua colors/minisummer.lua colors/miniautumn.lua colors/randomhue.lua\nsync_module \"icons\"\nsync_module \"indentscope\"\nsync_module \"jump\"\nsync_module \"jump2d\"\nsync_module \"keymap\"\nsync_module \"map\"\nsync_module \"misc\"\nsync_module \"move\"\nsync_module \"notify\"\nsync_module \"operators\"\nsync_module \"pairs\"\nsync_module \"pick\"\nsync_module \"sessions\"\nsync_module \"snippets\"\nsync_module \"splitjoin\"\nsync_module \"starter\"\nsync_module \"statusline\"\nsync_module \"surround\"\nsync_module \"tabline\"\nsync_module \"test\"\nsync_module \"trailspace\"\nsync_module \"visits\"\n"
  },
  {
    "path": "scripts/init-deps-example.lua",
    "content": "-- Clone 'mini.nvim' manually in a way that it gets managed by 'mini.deps'\nlocal path_package = vim.fn.stdpath('data') .. '/site/'\nlocal mini_path = path_package .. 'pack/deps/start/mini.nvim'\nif not vim.loop.fs_stat(mini_path) then\n  vim.cmd('echo \"Installing `mini.nvim`\" | redraw')\n  local clone_cmd = { 'git', 'clone', '--filter=blob:none', 'https://github.com/nvim-mini/mini.nvim', mini_path }\n  vim.fn.system(clone_cmd)\n  vim.cmd('packadd mini.nvim | helptags ALL')\n  vim.cmd('echo \"Installed `mini.nvim`\" | redraw')\nend\n\n-- Set up 'mini.deps' (customize to your liking)\nrequire('mini.deps').setup({ path = { package = path_package } })\n\n-- Use 'mini.deps'. `now()` and `later()` are helpers for a safe two-stage\n-- startup and are optional.\nlocal add, now, later = MiniDeps.add, MiniDeps.now, MiniDeps.later\n\n-- Safely execute immediately\nnow(function()\n  vim.o.termguicolors = true\n  vim.cmd('colorscheme miniwinter')\nend)\nnow(function() require('mini.notify').setup() end)\nnow(function() require('mini.icons').setup() end)\nnow(function() require('mini.tabline').setup() end)\nnow(function() require('mini.statusline').setup() end)\n\n-- Safely execute later\nlater(function() require('mini.ai').setup() end)\nlater(function() require('mini.comment').setup() end)\nlater(function() require('mini.pick').setup() end)\nlater(function() require('mini.surround').setup() end)\n\nnow(function()\n  -- Use other plugins with `add()`. It ensures plugin is available in current\n  -- session (installs if absent)\n  add({\n    source = 'neovim/nvim-lspconfig',\n    -- Supply dependencies near target plugin\n    depends = { 'williamboman/mason.nvim' },\n  })\nend)\n\nlater(function()\n  add({\n    source = 'nvim-treesitter/nvim-treesitter',\n    -- Use 'master' while monitoring updates in 'main'\n    checkout = 'master',\n    monitor = 'main',\n    -- Perform action after every checkout\n    hooks = { post_checkout = function() vim.cmd('TSUpdate') end },\n  })\n  -- Possible to immediately execute code which depends on the added plugin\n  require('nvim-treesitter.configs').setup({\n    ensure_installed = { 'lua', 'vimdoc' },\n    highlight = { enable = true },\n  })\nend)\n"
  },
  {
    "path": "scripts/lint-filename-length.sh",
    "content": "#!/usr/bin/env bash\n\n# Exact value of maximum length is chosen as a \"reasonably high but not bigger\n# than 143 (maximum filename length on eCryptfs systmes) number\".\n# Having low-ish value also helps with restirctions on full path length.\nmax_filename_length=125\n\nexit_code=0\nfor filename in $(find . -not -path './.git/**' -not -path './dual/**' -printf %f\\\\n); do\n  if [ \"${#filename}\" -gt $max_filename_length ]; then\n    echo \"Too long file name: $filename\"\n    exit_code=1\n  fi\ndone\n\nexit $exit_code\n"
  },
  {
    "path": "scripts/lintcommit-ci.sh",
    "content": "#!/usr/bin/env bash\n\nmsg_file_dir='lintcommit-msg-files/'\nmkdir -p $msg_file_dir\nfunction cleanup {\n  rm -rf $msg_file_dir\n}\ntrap cleanup EXIT\n\nrange=\"${1:-origin/sync..HEAD}\"\nmsg_files=()\nfor commit in $( git rev-list --reverse $range -- ); do \\\n  file=\"$msg_file_dir$commit\" ; \\\n  git log -1 --pretty=format:%B $commit > $file ; \\\n  msg_files+=($file) ; \\\ndone\n\nnvim --headless --noplugin -u ./scripts/lintcommit.lua -- ${msg_files[*]}\n"
  },
  {
    "path": "scripts/lintcommit.lua",
    "content": "-- Validate commit message. Designed to be run as pre-commit hook and in CI.\n--\n-- Each Neovim's argument for when it is opened is assumed to be a path to\n-- a file containing commit message to validate\n-- Example usage:\n-- ```\n-- nvim --headless --noplugin -u scripts/lintcommit.lua -- .git/COMMIT_EDITMSG\n-- ```\n\n-- Validator functions\nlocal allowed_commit_types = { 'ci', 'docs', 'feat', 'fix', 'refactor', 'style', 'test' }\n\nlocal allowed_scopes = { 'ALL' }\nfor _, module in ipairs(vim.fn.readdir('lua/mini')) do\n  if module ~= 'init.lua' then table.insert(allowed_scopes, module:match('^(.+)%.lua$')) end\nend\n\nlocal validate_subject = function(line)\n  -- Possibly allow starting with 'fixup' to disable commit linting\n  if vim.startswith(line, 'fixup') then\n    local is_strict = vim.loop.os_getenv('LINTCOMMIT_STRICT') ~= nil\n    local msg = is_strict and 'No \"fixup\" commits are allowed.' or ''\n    return not is_strict, msg\n  end\n\n  -- Should match overall conventional commit spec\n  local commit_type, scope, desc = string.match(line, '^([^(]+)(%b())!?: (.+)$')\n  if commit_type == nil then\n    commit_type, desc = string.match(line, '^([^!:]+)!?: (.+)$')\n  end\n  if commit_type == nil or desc == nil then\n    return false,\n      'First line does not match conventional commit specification of `<type>[optional scope][!]: <description>`: '\n        .. vim.inspect(line)\n  end\n\n  -- Commit type should be present and be from one of allowed\n  if not vim.tbl_contains(allowed_commit_types, commit_type) then\n    local one_of = table.concat(vim.tbl_map(vim.inspect, allowed_commit_types), ', ')\n    return false, 'Commit type ' .. vim.inspect(commit_type) .. ' is not allowed. Use one of ' .. one_of .. '.'\n  end\n\n  -- Scope, if present, should be from one of allowed\n  if scope ~= nil then\n    scope = scope:sub(2, -2)\n    if not vim.tbl_contains(allowed_scopes, scope) then\n      local one_of = table.concat(vim.tbl_map(vim.inspect, allowed_scopes), ', ')\n      return false, 'Scope ' .. vim.inspect(scope) .. ' is not allowed. Use one of ' .. one_of .. '.'\n    end\n  end\n\n  -- Description should be present and properly formatted\n  if string.find(desc, '^%w') == nil then\n    return false, 'Description should start with alphanumeric character: ' .. vim.inspect(desc)\n  end\n\n  if string.find(desc, '^%u%l') ~= nil then\n    return false, 'Description should not start with capitalized word: ' .. vim.inspect(desc)\n  end\n\n  if string.find(desc, '[.,?!;]$') ~= nil then\n    return false, 'Description should not end with any of `.,?!;`: ' .. vim.inspect(desc)\n  end\n\n  -- Subject should not be too long\n  if vim.fn.strdisplaywidth(line) > 72 then\n    return false, 'First line is longer than 72 characters: ' .. vim.inspect(desc)\n  end\n\n  return true, nil\nend\n\nlocal validate_body = function(parts)\n  if #parts == 1 then return true, nil end\n\n  if parts[2] ~= '' then return false, 'Second line should be empty' end\n  if parts[3] == nil then return false, 'If first line is not enough, body should be present' end\n  if string.find(parts[3], '^%S') == nil then return false, 'First body line should not start with whitespace.' end\n\n  for i = 3, #parts do\n    if vim.fn.strdisplaywidth(parts[i]) > 80 and not vim.startswith(parts[i], 'Co-authored-by:') then\n      return false, 'Body line is longer than 80 characters: ' .. vim.inspect(parts[i])\n    end\n  end\n\n  if string.find(parts[#parts], '^%s*$') ~= nil then return false, 'Body should not end with blank line.' end\n\n  return true, nil\nend\n\nlocal validate_bad_wording = function(msg)\n  local has_fix = msg:find('[Ff]ix #') or msg:find('[Ff]ixes #') or msg:find('[Ff]ixed #')\n  local has_bad_close = msg:find('[Cc]lose[sd]? #') ~= nil\n  local has_bad_resolve = msg:find('[Rr]esolve[sd] #') ~= nil\n  if has_fix or has_bad_close or has_bad_resolve then\n    return false,\n      'Use \"Resolve #\" GitHub keyword to resolve issue/PR '\n        .. '(not \"Fix(/es/ed)\", not \"Close(/s/d)\", not \"Resolve(s/d)\").'\n  end\n  return true, nil\nend\n\nlocal remove_cleanup_lines = function(lines)\n  -- Remove lines which are assumed to be later cleaned up by Git itself\n  -- See `git help commit` for option `--cleanup` (assumes default value)\n  local res = {}\n  for _, l in ipairs(lines) do\n    -- Ignore anything past and including scissors line\n    if l == '# ------------------------ >8 ------------------------' then break end\n    -- Ignore comments\n    if l:find('^%s*#') == nil then table.insert(res, l) end\n  end\n\n  -- Ignore trailing blank lines\n  for i = #res, 1, -1 do\n    if res[i]:find('%S') ~= nil then break end\n    res[i] = nil\n  end\n\n  return res\nend\n\nlocal validate_commit_msg = function(lines)\n  local is_valid, err_msg\n\n  -- If not in strict context, ignore lines which will be later cleaned up\n  local is_strict = vim.loop.os_getenv('LINTCOMMIT_STRICT') ~= nil\n  if not is_strict then lines = remove_cleanup_lines(lines) end\n\n  -- Allow all lines to be empty to abort committing\n  local all_empty = true\n  for _, l in ipairs(lines) do\n    if l ~= '' then all_empty = false end\n  end\n  if all_empty then return true, nil end\n\n  -- Validate subject (first line)\n  is_valid, err_msg = validate_subject(lines[1])\n  if not is_valid then return is_valid, err_msg end\n\n  -- Validate body\n  is_valid, err_msg = validate_body(lines)\n  if not is_valid then return is_valid, err_msg end\n\n  -- No validation for footer\n\n  -- Should not contain bad wording\n  for _, l in ipairs(lines) do\n    is_valid, err_msg = validate_bad_wording(l)\n    if not is_valid then return is_valid, err_msg end\n  end\n\n  return true, nil\nend\n\nlocal validate_commit_msg_from_file = function(path)\n  local ok, lines = pcall(vim.fn.readfile, path)\n  if not ok then return false, 'Could not read file ' .. path end\n  return validate_commit_msg(lines)\nend\n\n-- Actual validation\nlocal exit_code = 0\nfor i = 0, vim.fn.argc(-1) - 1 do\n  local path = vim.fn.argv(i, -1)\n  io.write('Commit message of ' .. vim.fn.fnamemodify(path, ':t') .. ':\\n')\n  local is_valid, err_msg = validate_commit_msg_from_file(path)\n  io.write((is_valid and 'OK' or err_msg) .. '\\n\\n')\n  if not is_valid then exit_code = 1 end\nend\n\nos.exit(exit_code)\n\n-- Tests to be run interactively: `_G.test_cases_failed` should be empty.\n-- NOTE: Comment out previous `os.exit()` call\nlocal test_cases = {\n  -- Subject\n  ['fixup'] = true,\n  ['fixup: commit message'] = true,\n  ['fixup! commit message'] = true,\n\n  ['ci: normal message'] = true,\n  ['docs: normal message'] = true,\n  ['feat: normal message'] = true,\n  ['fix: normal message'] = true,\n  ['refactor: normal message'] = true,\n  ['style: normal message'] = true,\n  ['test: normal message'] = true,\n\n  ['feat(ai): message with scope'] = true,\n  ['feat!: message with breaking change'] = true,\n  ['feat(ai)!: message with scope and breaking change'] = true,\n  ['style(ALL): style all modules'] = true,\n\n  ['unknown: unknown type'] = false,\n  ['feat(unknown): unknown scope'] = false,\n  ['refactor(): empty scope'] = false,\n  ['ci( ): whitespace as scope'] = false,\n\n  ['ci no colon after type'] = false,\n  [': no type before colon 1'] = false,\n  [' : no type before colon 2'] = false,\n  ['  : no type before colon 3'] = false,\n  ['ci:'] = false,\n  ['ci: '] = false,\n  ['ci:  '] = false,\n\n  ['feat: message with : in it'] = true,\n  ['feat(ai): message with : in it'] = true,\n\n  ['test:  extra space after colon'] = false,\n  ['ci:\ttab after colon'] = false,\n  ['ci:no space after colon'] = false,\n  ['ci : extra space before colon'] = false,\n\n  ['ci: bad punctuation at end of sentence.'] = false,\n  ['ci: bad punctuation at end of sentence,'] = false,\n  ['ci: bad punctuation at end of sentence?'] = false,\n  ['ci: bad punctuation at end of sentence!'] = false,\n  ['ci: bad punctuation at end of sentence;'] = false,\n  ['ci: good punctuation at end of sentence:'] = true,\n  ['ci: good punctuation at end of sentence\"'] = true,\n  [\"ci: good punctuation at end of sentence'\"] = true,\n  ['ci: good punctuation at end of sentence)'] = true,\n  ['ci: good punctuation at end of sentence]'] = true,\n\n  ['ci: Capitalized first word'] = false,\n  ['ci: UPPER_CASE First Word'] = true,\n  ['ci: very very very very very very very very very very very looong subject'] = false,\n\n  -- Body\n  ['ci: desc\\n\\nBody'] = true,\n  ['ci: desc\\n\\nBody\\n\\nwith\\n   \\nempty and blank lines'] = true,\n\n  ['ci: desc\\nSecond line is not empty'] = false,\n  ['ci: desc\\n\\n First body line starts with whitespace'] = false,\n\n  -- Line width should be checked only in not cleaned up lines\n  ['ci: desc\\n\\nBody\\nwith\\nVery very very very very very very very very very very very very looong body line'] = false,\n  ['ci: desc\\n\\nBody\\nwith\\n# Comment with very very very very very very very very very very looong body line'] = true,\n  ['ci: desc\\n\\nBody\\nwith\\n# ------------------------ >8 ------------------------\\nVery very very very very very very very very very very very very looong body line'] = true,\n\n  -- Trailing blank lines are allowed in not strict context\n  ['ci: only two lines\\n\\n'] = true,\n  ['ci: desc\\n\\nLast line is empty\\n\\n'] = true,\n  ['ci: desc\\n\\nLast line is blank\\n  '] = true,\n\n  -- Footer\n  -- No validation for footer\n\n  -- Bad wordings\n  ['ci: this has Fixed #1'] = false,\n  ['ci: this has fixed #1'] = false,\n  ['ci: this Fixes #1'] = false,\n  ['ci: this fixes #1'] = false,\n  ['ci: this will Fix #1'] = false,\n  ['ci: this will fix #1'] = false,\n  ['ci: this has Closed #1'] = false,\n  ['ci: this has closed #1'] = false,\n  ['ci: this Closes #1'] = false,\n  ['ci: this closes #1'] = false,\n  ['ci: this will Close #1'] = false,\n  ['ci: this will close #1'] = false,\n  ['ci: this has Resolved #1'] = false,\n  ['ci: this has resolved #1'] = false,\n  ['ci: this Resolves #1'] = false,\n  ['ci: this resolves #1'] = false,\n\n  ['ci: desc\\n\\nthis has Fixed #1'] = false,\n  ['ci: desc\\n\\nthis has fixed #1'] = false,\n  ['ci: desc\\n\\nthis Fixes #1'] = false,\n  ['ci: desc\\n\\nthis fixes #1'] = false,\n  ['ci: desc\\n\\nthis will Fix #1'] = false,\n  ['ci: desc\\n\\nthis will fix #1'] = false,\n  ['ci: desc\\n\\nthis has Closed #1'] = false,\n  ['ci: desc\\n\\nthis has closed #1'] = false,\n  ['ci: desc\\n\\nthis Closes #1'] = false,\n  ['ci: desc\\n\\nthis closes #1'] = false,\n  ['ci: desc\\n\\nthis will Close #1'] = false,\n  ['ci: desc\\n\\nthis will close #1'] = false,\n  ['ci: desc\\n\\nthis has Resolved #1'] = false,\n  ['ci: desc\\n\\nthis has resolved #1'] = false,\n  ['ci: desc\\n\\nthis Resolves #1'] = false,\n  ['ci: desc\\n\\nthis resolves #1'] = false,\n\n  -- Comments are allowed in not strict context\n  ['# Comment\\nci: desc'] = true,\n  [' # Comment\\nci: desc'] = true,\n  ['ci: desc\\n# Comment\\n\\nBody'] = true,\n\n  -- Allow all empty lines\n  [''] = true,\n  ['\\n'] = true,\n  ['\\n# Comment'] = true,\n}\n\n_G.test_cases_failed = {}\n\nvim.loop.os_unsetenv('LINTCOMMIT_STRICT')\nfor message, expected in pairs(test_cases) do\n  local lines = vim.split(message, '\\n')\n  local is_valid = validate_commit_msg(lines)\n  if is_valid ~= expected then\n    table.insert(_G.test_cases_failed, { msg = message, expected = expected, actual = is_valid })\n  end\nend\n\nvim.loop.os_setenv('LINTCOMMIT_STRICT', 'true')\nlocal strict_test_cases = {\n  -- Fixup commit type is not allowed\n  ['fixup'] = false,\n  ['fixup: should fail'] = false,\n  ['fixup! should fail'] = false,\n\n  -- - Should only matter in subject\n  ['ci: desc\\n\\nfixup'] = true,\n\n  -- Do not allow comments outside of commit body\n  ['# Comment\\nci: desc'] = false,\n  [' # Comment\\nci: desc'] = false,\n  ['ci: desc\\n# Comment\\n\\nBody'] = false,\n\n  ['ci: desc\\n\\nBody\\n# Comment in body'] = true,\n\n  -- Check line width even in previously ignored contexts\n  ['ci: desc\\n\\nBody\\nwith\\n# Comment with very very very very very very very very very very looong body line'] = false,\n  ['ci: desc\\n\\nBody\\nwith\\n# ------------------------ >8 ------------------------\\nVery very very very very very very very very very very very very looong body line'] = false,\n\n  -- Trailing blank lines are not allowed in strict context\n  ['ci: only two lines\\n\\n'] = false,\n  ['ci: desc\\n\\nLast line is empty\\n\\n'] = false,\n  ['ci: desc\\n\\nLast line is blank\\n  '] = false,\n}\nfor message, expected in pairs(strict_test_cases) do\n  local lines = vim.split(message, '\\n')\n  local is_valid = validate_commit_msg(lines)\n  if is_valid ~= expected then\n    table.insert(_G.test_cases_failed, { msg = message, expected = expected, actual = is_valid })\n  end\nend\n\n-- Cleanup\nvim.loop.os_unsetenv('LINTCOMMIT_STRICT')\n"
  },
  {
    "path": "scripts/minidoc.lua",
    "content": "local minidoc = require('mini.doc')\n\nif _G.MiniDoc == nil then minidoc.setup() end\n\nlocal modules = {\n  'ai',\n  'align',\n  'animate',\n  'base16',\n  'basics',\n  'bracketed',\n  'bufremove',\n  'clue',\n  'cmdline',\n  'colors',\n  'comment',\n  'completion',\n  'cursorword',\n  'deps',\n  'diff',\n  'doc',\n  'extra',\n  'files',\n  'fuzzy',\n  'git',\n  'hipatterns',\n  'hues',\n  'icons',\n  'indentscope',\n  'jump',\n  'jump2d',\n  'keymap',\n  'map',\n  'misc',\n  'move',\n  'notify',\n  'operators',\n  'pairs',\n  'pick',\n  'sessions',\n  'snippets',\n  'splitjoin',\n  'starter',\n  'statusline',\n  'surround',\n  'tabline',\n  'test',\n  'trailspace',\n  'visits',\n}\n\nMiniDoc.generate({ 'lua/mini/init.lua' }, 'doc/mini-nvim.txt')\n\nfor _, m in ipairs(modules) do\n  MiniDoc.generate({ 'lua/mini/' .. m .. '.lua' }, 'doc/mini-' .. m .. '.txt')\nend\n"
  },
  {
    "path": "scripts/minimal_init.lua",
    "content": "-- Add project root as full path to runtime path (in order to be able to\n-- `require()`) modules from this module\nvim.cmd([[let &rtp.=','.getcwd()]])\n\n-- Ensure persistent color scheme (matters after new default in Neovim 0.10)\nvim.o.background = 'dark'\nrequire('mini.hues').setup({ background = '#11262d', foreground = '#c0c8cc', autoadjust = false })\nvim.g.colors_name = 'minitest-scheme'\n\n-- - Make screenshot tests more robust across Neovim versions\nvim.o.statusline = '%<%f %l,%c%V'\n\nif vim.fn.has('nvim-0.11') == 1 then\n  vim.api.nvim_set_hl(0, 'PmenuMatch', { link = 'Pmenu' })\n  vim.api.nvim_set_hl(0, 'PmenuMatchSel', { link = 'PmenuSel' })\nend\n\n-- Ensure no custom fold method in Lua files (it interfers with many tests)\nvim.cmd('au FileType lua set foldmethod=manual')\n\n-- - Ensure that child process is tested with termguicolors, since 'mini.hues'\n--   only works with it. This might matter with screenshot testing.\n--   One example is how https://github.com/neovim/neovim/pull/35026 adjusts\n--   the behavior based on the presence of `rgb`.\n--   NOTE: similar effect can be achieved by adding the following to\n--   `child.setup` in 'helpers.lua':\n--   `child.api.nvim_ui_attach(child.o.columns, child.o.lines, { rgb=true })`\nvim.o.termguicolors = true\n"
  },
  {
    "path": "scripts/minitest.lua",
    "content": "local minitest = require('mini.test')\n\nif _G.MiniTest == nil then minitest.setup() end\nminitest.run()\n"
  },
  {
    "path": "tests/dir-ai/mock-nvim-treesitter/lua/nvim-treesitter/init.lua",
    "content": ""
  },
  {
    "path": "tests/dir-ai/mock-nvim-treesitter/lua/nvim-treesitter/query.lua",
    "content": "local new_match = function(range, metadata_range)\n  return {\n    -- Allow emulating tree-sitter directives that can compute range in query.\n    -- For example, like this 'after/query/lua/textobjects.scm':\n    -- ```\n    -- ; extends\n    -- ((table_constructor) @table.outer @table.inner (#offset! @table.inner 0 1 0 -1))\n    -- ```\n    metadata = metadata_range ~= nil and { range = metadata_range } or nil,\n    node = {\n      -- `node:range()` should return 0-based numbers (row1, col1, row2, col2)\n      -- for end-exclusive region\n      range = function(include_bytes)\n        if not include_bytes then return unpack(range) end\n        -- If `include_bytes` is `true`, then the output is\n        -- `row1-col1-byte1-row2-col2-byte2`\n        local start_byte = vim.fn.line2byte(range[1] + 1) + range[2]\n        local end_byte = vim.fn.line2byte(range[3] + 1) + range[4] - 1\n        return range[1], range[2], start_byte, range[3], range[4], end_byte\n      end,\n    },\n  }\nend\n\n-- Imitate matches from reference file 'tests/dir-ai/lua-file.lua'\n-- The 'function.outer' and 'function.inner' matches are \"real\"\n--stylua: ignore\nlocal matches = {\n  ['@function.outer'] = {\n     new_match({ 2, 0, 4,  3  }),\n     new_match({ 3, 9, 3,  38 }),\n     new_match({ 6, 6, 10, 3  }),\n  },\n  ['@function.inner'] = {\n     new_match({ 3, 2,  3, 38 }),\n     new_match({ 3, 20, 3, 33 }),\n     new_match({ 6, 6, 10, 3  }, { 7, 2,  9, 13 }),\n  },\n  ['@plugin_return'] = {\n     new_match({ 3,  2, 3,  38 }),\n     new_match({ 9,  2, 9,  13 }),\n     new_match({ 12, 0, 12, 8  }),\n  },\n}\n\nlocal get_capture_matches_recursively = function(_, captures, _)\n  local res = {}\n  captures = type(captures) == 'string' and { captures } or captures\n  for _, cap in ipairs(captures) do\n    vim.list_extend(res, matches[cap])\n  end\n  return res\nend\n\nreturn { get_capture_matches_recursively = get_capture_matches_recursively }\n"
  },
  {
    "path": "tests/dir-bracketed/dir-a/file-aa",
    "content": "Placeholder to test file-related functions of 'mini.bracketed'\n"
  },
  {
    "path": "tests/dir-bracketed/file-a",
    "content": "Placeholder to test file-related functions of 'mini.bracketed'\n"
  },
  {
    "path": "tests/dir-bracketed/file-b",
    "content": "Placeholder to test file-related functions of 'mini.bracketed'\n"
  },
  {
    "path": "tests/dir-bracketed/file-c",
    "content": "Placeholder to test file-related functions of 'mini.bracketed'\n"
  },
  {
    "path": "tests/dir-bracketed/file-d",
    "content": "Placeholder to test file-related functions of 'mini.bracketed'\n"
  },
  {
    "path": "tests/dir-bracketed/file-e",
    "content": "Placeholder to test file-related functions of 'mini.bracketed'\n"
  },
  {
    "path": "tests/dir-bracketed/mock/diagnostic.lua",
    "content": "local lines = {\n  'Error Warning Info Hint',\n  '  Error  ',\n  '  Warning  ',\n  '  Info  ',\n  '  Hint  ',\n  'Hint Info Warning Error',\n}\n\nlocal severity = vim.diagnostic.severity\n\n--stylua: ignore\nlocal diagnostic_arr = {\n  { lnum = 0, end_lnum = 0, col = 0,  end_col = 5,  message = 'Error 1',   severity = severity.ERROR },\n  { lnum = 0, end_lnum = 0, col = 6,  end_col = 13, message = 'Warning 1', severity = severity.WARN  },\n  { lnum = 0, end_lnum = 0, col = 14, end_col = 18, message = 'Info 1',    severity = severity.INFO  },\n  { lnum = 0, end_lnum = 0, col = 19, end_col = 23, message = 'Hint 1',    severity = severity.HINT  },\n  { lnum = 1, end_lnum = 1, col = 2,  end_col = 7,  message = 'Error 2',   severity = severity.ERROR },\n  { lnum = 2, end_lnum = 2, col = 2,  end_col = 9,  message = 'Warning 2', severity = severity.WARN  },\n  { lnum = 3, end_lnum = 3, col = 2,  end_col = 6,  message = 'Info 2',    severity = severity.INFO  },\n  { lnum = 4, end_lnum = 4, col = 2,  end_col = 6,  message = 'Hint 2',    severity = severity.HINT  },\n  { lnum = 5, end_lnum = 5, col = 0,  end_col = 4,  message = 'Hint 3',    severity = severity.HINT  },\n  { lnum = 5, end_lnum = 5, col = 5,  end_col = 9,  message = 'Info 3',    severity = severity.INFO  },\n  { lnum = 5, end_lnum = 5, col = 10, end_col = 17, message = 'Warning 3', severity = severity.WARN  },\n  { lnum = 5, end_lnum = 5, col = 18, end_col = 23, message = 'Error 3',   severity = severity.ERROR },\n}\n\nlocal filter = function(severity_level)\n  return vim.tbl_filter(function(x) return x.severity == severity[severity_level] end, diagnostic_arr)\nend\n\nlocal convert_to_cursor_positions = function(arr)\n  return vim.tbl_map(function(x) return { x.lnum + 1, x.col } end, arr)\nend\n\nlocal cursor_positions = {\n  all = convert_to_cursor_positions(diagnostic_arr),\n  error = convert_to_cursor_positions(filter('ERROR')),\n  warning = convert_to_cursor_positions(filter('WARN')),\n  info = convert_to_cursor_positions(filter('INFO')),\n  hint = convert_to_cursor_positions(filter('HINT')),\n  error_warning = convert_to_cursor_positions(\n    vim.tbl_filter(function(x) return x.severity == severity.ERROR or x.severity == severity.WARN end, diagnostic_arr)\n  ),\n}\n\nreturn { diagnostic_arr = diagnostic_arr, lines = lines, cursor_positions = cursor_positions }\n"
  },
  {
    "path": "tests/dir-bracketed/mock/treesitter.lua",
    "content": "-- Mock tree-sitter as if node is a region inside balanced `{}`\n\n-- Find enclosing balanced `{}`. If `accept_at_cursor`, return balanced `{}`\n-- when on it.\nlocal find_enclosing_brackets = function(row, col, accept_at_cursor)\n  local searchpairpos = function(flags)\n    flags = flags or ''\n\n    local cache_cursor = vim.api.nvim_win_get_cursor(0)\n    vim.api.nvim_win_set_cursor(0, { row, col - 1 })\n    local res = vim.fn.searchpairpos('{', '', '}', 'nWz' .. flags)\n    vim.api.nvim_win_set_cursor(0, cache_cursor)\n\n    return res\n  end\n\n  if accept_at_cursor == nil then accept_at_cursor = true end\n\n  local char_at_cursor = vim.fn.getline(row):sub(col, col)\n\n  if char_at_cursor == '{' and accept_at_cursor then return { row, col }, searchpairpos() end\n  if char_at_cursor == '{' and not accept_at_cursor then return searchpairpos('b'), searchpairpos('c') end\n\n  if char_at_cursor == '}' and accept_at_cursor then return searchpairpos('b'), { row, col } end\n  if char_at_cursor == '}' and not accept_at_cursor then return searchpairpos('bc'), searchpairpos() end\n\n  return searchpairpos('b'), searchpairpos()\nend\n\n--@param row number Row number starting from 1.\n--@param col number Column number starting from 1.\nlocal new_node\nnew_node = function(row, col, accept_at_cursor)\n  if row == nil or col == nil then return nil end\n\n  -- Start and end of this node\n  local node_start, node_end = find_enclosing_brackets(row, col, accept_at_cursor)\n\n  -- - No node under cursor if no `{}` found\n  local no_node_found = (node_start[1] == 0 and node_start[2] == 0) or (node_end[1] == 0 and node_end[2] == 0)\n  if no_node_found then return nil end\n\n  -- Row and column for parent node\n  local node = {}\n\n  -- Start - inclusive, end - row-inclusive, col-exclusive. All zero-indexed.\n  node.start = function(_) return node_start[1] - 1, node_start[2] - 1 end\n  node.end_ = function(_) return node_end[1] - 1, node_end[2] end\n  node.range = function(_) return node_start[1] - 1, node_start[2] - 1, node_end[1] - 1, node_end[2] - 1 end\n\n  -- NOTE: this recursively searches for all parents for initial node\n  local parent_node = new_node(node_start[1], node_start[2], false)\n  node.parent = function(_) return parent_node end\n\n  return node\nend\n\n-- `row` and `col` are both zero-indexed here\nvim.treesitter.get_node = function(opts) return new_node(opts.pos[1] + 1, opts.pos[2] + 1) end\n"
  },
  {
    "path": "tests/dir-cmdline/compiler/testcompiler.vim",
    "content": ""
  },
  {
    "path": "tests/dir-cmdline/fileA",
    "content": ""
  },
  {
    "path": "tests/dir-cmdline/fileB",
    "content": ""
  },
  {
    "path": "tests/dir-cmdline/keymap/testkeymap.vim",
    "content": ""
  },
  {
    "path": "tests/dir-cmdline/pack/test/opt/testplugin/plugin/testplugin.vim",
    "content": ""
  },
  {
    "path": "tests/dir-colors/mock_cs/colors/mock_cs.lua",
    "content": "vim.cmd('highlight clear')\nvim.g.colors_name = 'mock_cs'\n\n--stylua: ignore start\nvim.api.nvim_set_hl(0, 'Normal',          { fg = '#5f87af', bg = '#080808' })\nvim.api.nvim_set_hl(0, 'TestNormalCterm', { ctermfg = 67,   ctermbg = 232 })\nvim.api.nvim_set_hl(0, 'TestComment',     { fg = '#5f87af', bg = '#080808' })\nvim.api.nvim_set_hl(0, 'TestSpecial',     { sp = '#00ff00', underline = true })\nvim.api.nvim_set_hl(0, 'TestBlend',       { bg = '#121212', blend = 0 })\n--stylua: ignore end\n\nvim.g.terminal_color_0 = '#010101'\nvim.g.terminal_color_7 = '#fefefe'\n"
  },
  {
    "path": "tests/dir-deps/mocks/spawn.lua",
    "content": "_G.process_log = {}\n\nlocal process_id = 1\nlocal new_process = function(pid)\n  local is_active, is_closing = true, false\n  return {\n    pid = pid,\n    close = function(_)\n      table.insert(_G.process_log, 'Process ' .. pid .. ' was closed.')\n      is_active, is_closing = false, true\n    end,\n    is_closing = function(_) return is_closing end,\n    is_active = function(_) return is_active end,\n  }\nend\n\n-- Define object containing the queue with mocking stdio data.\n-- Each element is a table with `out` and `err` fields, both can be `nil`,\n-- `string`, or `string[]`. **Heavy** assumptions about how `new_pipe` is used:\n-- - It is called twice before each `vim.loop.spawn`.\n-- - It is first called for `stdout`, then for `stderr`.\n_G.stdio_queue = {}\nlocal io_field = 'out'\nvim.loop.new_pipe = function()\n  local cur_process_id, cur_io_field = process_id, io_field\n  local cur_feed = (_G.stdio_queue[cur_process_id] or {})[cur_io_field]\n  if type(cur_feed) ~= 'table' then cur_feed = { cur_feed } end\n  io_field = io_field == 'out' and 'err' or 'out'\n\n  return {\n    read_start = function(_, callback)\n      for _, x in ipairs(cur_feed) do\n        if type(x) == 'table' then callback(x.err, nil) end\n        if type(x) == 'string' then callback(nil, x) end\n      end\n      callback(nil, nil)\n    end,\n    close = function()\n      table.insert(_G.process_log, string.format('Stream %s for process %s was closed.', cur_io_field, cur_process_id))\n    end,\n  }\nend\n\n-- Array of data to mock the process. Each element can be either `nil` or\n-- a table with the following fields:\n-- - <action> `(function|nil)` - callable to simulate job's side-effects.\n-- - <duration> `(number|nil)` - how long a process should take. Default: 0.\n-- - <exit_code> `(number|nil)` - exit code. Default: 0.\n_G.process_mock_data = {}\n_G.spawn_log = {}\nvim.loop.spawn = function(path, options, on_exit)\n  local options_without_callables = vim.deepcopy(options) or {}\n  options_without_callables.stdio = nil\n  table.insert(_G.spawn_log, { executable = path, options = options_without_callables })\n\n  local pid = process_id\n  process_id = process_id + 1\n\n  local mock_data = _G.process_mock_data[pid] or {}\n  if vim.is_callable(mock_data.action) then mock_data.action() end\n  vim.defer_fn(function() on_exit(mock_data.exit_code or 0) end, mock_data.duration or 0)\n\n  return new_process(pid), pid\nend\n\nvim.loop.process_kill = function(process) table.insert(_G.process_log, 'Process ' .. process.pid .. ' was killed.') end\n\n_G.n_cpu_info = 4\nvim.loop.cpu_info = function()\n  local res = {}\n  for i = 1, _G.n_cpu_info do\n    res[i] = { model = 'A Very High End CPU' }\n  end\n  return res\nend\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plu-gin_0.nvim/lua/plug_0.lua",
    "content": "return { 'plu-gin_0.nvim/lua/plug_0.lua' }\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/after/plugin/plug_1.lua",
    "content": "_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'after/plugin/plug_1.lua')\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/after/plugin/plug_1.nonlua",
    "content": "error()\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/after/plugin/plug_1.vim",
    "content": "lua <<EOF\n_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'after/plugin/plug_1.vim')\nEOF\n\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/after/plugin/subdir/plug_1_sub.lua",
    "content": "_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'after/plugin/subdir/plug_1_sub.lua')\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/doc/help_1.txt",
    "content": "  *depstest_plugin_1_tag*\nThis is help for plugin_1.\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/lua/plug_1.lua",
    "content": "return { 'plugin_1/lua/plug_1.lua' }\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/plugin/plug_1.lua",
    "content": "_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'plugin/plug_1.lua')\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/plugin/plug_1.vim",
    "content": "lua <<EOF\n_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'plugin/plug_1.vim')\nEOF\n\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_1/plugin/subdir/plug_1_sub.lua",
    "content": "_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'plugin/subdir/plug_1_sub.lua')\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_2/after/plugin/plug_2.lua",
    "content": "_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'after/plugin/plug_2.lua')\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_2/doc/help_2.txt",
    "content": "  *depstest_plugin_2_tag*\nThis is help for plugin_2.\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_2/lua/plug_2.lua",
    "content": "return { 'plugin_2/lua/plug_2.lua' }\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_2/plugin/plug_2.lua",
    "content": "_G.plugin_log = _G.plugin_log or {}\ntable.insert(_G.plugin_log, 'plugin/plug_2.lua')\n"
  },
  {
    "path": "tests/dir-deps/pack/deps/opt/plugin_3/lua/plug_3.lua",
    "content": "return { 'plugin_3/lua/plug_3.lua' }\n"
  },
  {
    "path": "tests/dir-deps/snapshots/not-proper-1",
    "content": "Not proper Lua\n"
  },
  {
    "path": "tests/dir-deps/snapshots/not-proper-2",
    "content": "return \"Proper Lua but not proper return\"\n"
  },
  {
    "path": "tests/dir-deps/snapshots/snap",
    "content": "return {\n  plugin_1 = 'sha1head',\n  plugin_2 = 'sha2head'\n}\n"
  },
  {
    "path": "tests/dir-deps/test-log",
    "content": "========== Update 2024-01-02 03:04:05 ==========\n+++ plugin_1 +++\nPath:         MOCKDIR/pack/deps/opt/plugin_1\nSource:       https://github.com/user/plugin_1\nState before: sha1head\nState after:  new1head (main)\n\nPending updates from `main`:\n> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim\n  Added commit in checkout.\n\n"
  },
  {
    "path": "tests/dir-diff/file",
    "content": "aaa\nuuu\n"
  },
  {
    "path": "tests/dir-diff/file-bom",
    "content": "﻿bbb\nvvv\n"
  },
  {
    "path": "tests/dir-diff/git-repo/.git-dir/index",
    "content": ""
  },
  {
    "path": "tests/dir-diff/git-repo/dir-in-git/file-in-git",
    "content": "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n"
  },
  {
    "path": "tests/dir-diff/mocks/spawn.lua",
    "content": "_G.process_log = {}\n\nlocal process_id = 1\nlocal new_process = function(pid)\n  local close = function(_) table.insert(_G.process_log, 'Process ' .. pid .. ' was closed.') end\n  return { pid = pid, close = close }\nend\n\n-- Define object containing the queue with mocking stdio data.\n-- Each element is an array of tables with the format:\n-- - Element 1 is stdio type. One of \"in\", \"out\", \"err\".\n-- - Element 2 is the feed of the pipe. Can be `nil`, `string`, `string[]`.\n_G.stdio_queue = {}\nlocal process_pipe_indexes = {}\nvim.loop.new_pipe = function()\n  local cur_process_id = process_id\n  local process_pipe_data = _G.stdio_queue[cur_process_id] or {}\n\n  process_pipe_indexes[cur_process_id] = (process_pipe_indexes[cur_process_id] or 0) + 1\n  local cur_pipe_data = process_pipe_data[process_pipe_indexes[cur_process_id]] or {}\n  local cur_io_field, cur_feed = cur_pipe_data[1], cur_pipe_data[2]\n\n  if type(cur_feed) ~= 'table' then cur_feed = { cur_feed } end\n\n  return {\n    read_start = function(_, callback)\n      for _, x in ipairs(cur_feed) do\n        if type(x) == 'table' then callback(x.err, nil) end\n        if type(x) == 'string' then callback(nil, x) end\n      end\n      callback(nil, nil)\n    end,\n    write = function(_, chars)\n      local msg = string.format('Stream %s for process %s wrote: %s', cur_io_field, cur_process_id, chars)\n      table.insert(_G.process_log, msg)\n    end,\n    shutdown = function()\n      local msg = string.format('Stream %s for process %s was shut down.', cur_io_field, cur_process_id)\n      table.insert(_G.process_log, msg)\n    end,\n    close = function()\n      table.insert(_G.process_log, string.format('Stream %s for process %s was closed.', cur_io_field, cur_process_id))\n    end,\n  }\nend\n\n-- Array of data to mock the process. Each element can be either `nil` or\n-- a table with the following fields:\n-- - <action> `(function|nil)` - callable to simulate job's side-effects.\n-- - <duration> `(number|nil)` - how long a process should take. Default: 0.\n-- - <exit_code> `(number|nil)` - exit code. Default: 0.\n_G.process_mock_data = {}\n_G.spawn_log = {}\nvim.loop.spawn = function(path, options, on_exit)\n  local options_without_callables = vim.deepcopy(options) or {}\n  options_without_callables.stdio = nil\n  table.insert(_G.spawn_log, { executable = path, options = options_without_callables })\n\n  local pid = process_id\n  process_id = process_id + 1\n\n  local mock_data = _G.process_mock_data[pid] or {}\n  if vim.is_callable(mock_data.action) then mock_data.action() end\n  vim.defer_fn(function() on_exit(mock_data.exit_code or 0) end, mock_data.duration or 0)\n\n  return new_process(pid), pid\nend\n"
  },
  {
    "path": "tests/dir-doc/.gitignore",
    "content": "*-output.txt\ndoc/\n"
  },
  {
    "path": "tests/dir-doc/.styluaignore",
    "content": "*\n"
  },
  {
    "path": "tests/dir-doc/arguments/file.lua",
    "content": "-- This file should be used to generate output help file.\n-- It also should respect `--` as annotation prefix (as test for respecting\n-- `config` argument).\n"
  },
  {
    "path": "tests/dir-doc/arguments/file_ignore.lua",
    "content": "-- This file should be ignored\n"
  },
  {
    "path": "tests/dir-doc/arguments/output_reference.txt",
    "content": "This file should be used to generate output help file.\nIt also should respect `--` as annotation prefix (as test for respecting\n`config` argument).\nThis line should be added in `section_post` hook.\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:\n"
  },
  {
    "path": "tests/dir-doc/buffer-local_script.lua",
    "content": "_G.is_inside_buffer_local_script = true\n\n-- Buffer variable should be later restored\nvim.b.minidoc_config = { script_path = 'aaa' }\n"
  },
  {
    "path": "tests/dir-doc/custom-script/gendoc/gendoc-script.lua",
    "content": "-- Global config should be later restored\nMiniDoc.config.aaa = true\n\nreturn require('mini.doc').generate(nil, 'output.txt', {})\n"
  },
  {
    "path": "tests/dir-doc/custom-script/init.lua",
    "content": "--- File inside test for usage of custom script\n"
  },
  {
    "path": "tests/dir-doc/custom-script/output_reference.txt",
    "content": "File inside test for usage of custom script\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "tests/dir-doc/default-collation/after/file01.lua",
    "content": "--- File 'default-collation/after/file01.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/after/file02.lua",
    "content": "--- File 'default-collation/after/file02.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/after/init.lua",
    "content": "--- File 'default-collation/after/init.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/colors/file01.lua",
    "content": "--- File 'default-collation/colors/file01.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/colors/file02.lua",
    "content": "--- File 'default-collation/colors/file02.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/colors/init.lua",
    "content": "--- File 'default-collation/colors/init.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/default-collation_reference.txt",
    "content": "File 'default-collation/init.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/file01.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/file02.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/lua/init.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/lua/file01.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/lua/file02.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/lua/aaa/init.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/after/init.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/after/file01.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/after/file02.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/colors/init.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/colors/file01.lua'\n\n\n==============================================================================\n------------------------------------------------------------------------------\nFile 'default-collation/colors/file02.lua'\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:\n"
  },
  {
    "path": "tests/dir-doc/default-collation/file01.lua",
    "content": "--- File 'default-collation/file01.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/file02.lua",
    "content": "--- File 'default-collation/file02.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/init.lua",
    "content": "--- File 'default-collation/init.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/lua/aaa/init.lua",
    "content": "--- File 'default-collation/lua/aaa/init.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/lua/file01.lua",
    "content": "--- File 'default-collation/lua/file01.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/lua/file02.lua",
    "content": "--- File 'default-collation/lua/file02.lua'\n"
  },
  {
    "path": "tests/dir-doc/default-collation/lua/init.lua",
    "content": "--- File 'default-collation/lua/init.lua'\n"
  },
  {
    "path": "tests/dir-doc/helpers.lua",
    "content": "H = {}\n\n--- Remove (possibly not empty) directory\n_G.remove_dir = function(path)\n  local fs = vim.loop.fs_scandir(path)\n  if not fs then\n    vim.notify([[Couldn't open directory ]] .. path)\n    return\n  end\n\n  local path_sep = package.config:sub(1, 1)\n  while true do\n    local f_name, _ = vim.loop.fs_scandir_next(fs)\n    if f_name == nil then break end\n    local p = ('%s%s%s'):format(path, path_sep, f_name)\n    vim.loop.fs_unlink(p)\n  end\n\n  vim.loop.fs_rmdir(path)\nend\n\n_G.validate_doc_structure = function(x)\n  H.validate_structure(x, 'doc', nil)\n\n  for _, file in ipairs(x) do\n    H.validate_structure(file, 'file', x)\n\n    for _, block in ipairs(file) do\n      H.validate_structure(block, 'block', file)\n\n      for _, section in ipairs(block) do\n        H.validate_structure(section, 'section', block)\n\n        for _, line in ipairs(section) do\n          if type(line) ~= 'string' then error('Section element is not a line.') end\n        end\n      end\n    end\n  end\nend\n\n-- Helper methods =============================================================\nH.validate_structure = function(x, struct_type, parent)\n  local type_string = vim.inspect(struct_type)\n\n  if not H.is_structure(x, struct_type) then error(('Element is not %s structure.'):format(type_string)) end\n\n  if parent == nil then return end\n\n  if tostring(x.parent) ~= tostring(parent) then\n    error(('%s structure has not correct `info.parent`.'):format(type_string))\n  end\n\n  if tostring(parent[x.parent_index]) ~= tostring(x) then\n    error(('%s structure has not correct `info.parent_index`.'):format(type_string))\n  end\nend\n\nH.info_fields = {\n  section = { id = 'string', line_begin = 'number', line_end = 'number' },\n  block = { afterlines = 'table', line_begin = 'number', line_end = 'number' },\n  file = { path = 'string' },\n  doc = { input = 'table', output = 'string', config = 'table' },\n}\n\nH.is_structure = function(x, struct_type)\n  if not H.struct_has_elements(x) then return false end\n  if not x.type == struct_type then return false end\n\n  for info_name, info_type in pairs(H.info_fields[struct_type]) do\n    if type(x.info[info_name]) ~= info_type then return false end\n  end\n\n  return true\nend\n\nH.struct_has_elements = function(x)\n  -- Fields\n  if not (type(x.info) == 'table' and type(x.type) == 'string') then return false end\n\n  if x.parent ~= nil and not (type(x.parent) == 'table' and type(x.parent_index) == 'number') then return false end\n\n  -- Methods\n  for _, name in ipairs({ 'insert', 'remove', 'has_descendant', 'has_lines', 'clear_lines' }) do\n    if type(x[name]) ~= 'function' then return false end\n  end\n\n  return true\nend\n"
  },
  {
    "path": "tests/dir-doc/inference/inference_reference.txt",
    "content": "Tests for inferring from afterline\n\n------------------------------------------------------------------------------\n                                                                         *M.a()*\n                                `M.a`({x}, {y})\nThis function definition should be inferred\n\n------------------------------------------------------------------------------\nThis function definition should not be inferred (not from first column)\n\n------------------------------------------------------------------------------\n                                                                           *b()*\n                                 `b`({x}, {y})\nThis function definition should be inferred\n\n------------------------------------------------------------------------------\nThis function definition should not be inferred (not from first column)\n\n------------------------------------------------------------------------------\n                                                                         *M.c()*\n                                `M.c`({x}, {y})\nThis function definition should be inferred\n\n------------------------------------------------------------------------------\n                                                                       *M.c_1()*\n                                   `M.c_1`()\nThis function definition should be inferred\n\n------------------------------------------------------------------------------\nThis function definition should not be inferred (not from first column)\n\n------------------------------------------------------------------------------\n                                                                           *d()*\n                                 `d`({x}, {y})\nThis function definition should be inferred\n\n------------------------------------------------------------------------------\n                                                                         *d_1()*\n                                    `d_1`()\nThis function definition should be inferred\n\n------------------------------------------------------------------------------\nThis function definition should not be inferred (not from first column)\n\n------------------------------------------------------------------------------\n                                                                           *M.A*\n                                     `M.A`\nThis assignment should be inferred\n\n------------------------------------------------------------------------------\n                                                                         *M.A_1*\n                                    `M.A_1`\nThis assignment should be inferred\n\n------------------------------------------------------------------------------\nThis assignment should not be inferred (not from first column)\n\n------------------------------------------------------------------------------\n                                                                             *B*\n                                      `B`\nThis assignment should be inferred\n\n------------------------------------------------------------------------------\n                                                                           *B_1*\n                                     `B_1`\nThis assignment should be inferred\n\n------------------------------------------------------------------------------\nThis assignment should not be inferred (not from first column)\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:"
  },
  {
    "path": "tests/dir-doc/inference/init.lua",
    "content": "--stylua: ignore start\n--- Tests for inferring from afterline\n\nlocal M = {}\n\n-- Functions\n\n--- This function definition should be inferred\nM.a = function(x, y)\n  print('M.a')\nend\n\n--- This function definition should not be inferred (not from first column)\n  M.a_no = function() end\n\n--- This function definition should be inferred\nlocal function b(x, y)\n  print('b')\nend\n\n--- This function definition should not be inferred (not from first column)\n  local function b_no() end\n\n--- This function definition should be inferred\nM.c = function(x, y)\n  print('M.c')\nend\n\n--- This function definition should be inferred\nM.c_1=function() end\n\n--- This function definition should not be inferred (not from first column)\n  M.c_no = function() end\n\n--- This function definition should be inferred\nlocal d = function(x, y)\n  print('d')\nend\n\n--- This function definition should be inferred\nlocal d_1=function() end\n\n--- This function definition should not be inferred (not from first column)\n  local d_no = function() end\n\n\n-- Assignments\n\n--- This assignment should be inferred\nM.A = 1\n\n--- This assignment should be inferred\nM.A_1=1\n\n--- This assignment should not be inferred (not from first column)\n  M.A_no = 1\n\n--- This assignment should be inferred\nlocal B = 1\n\n--- This assignment should be inferred\nlocal B_1=1\n\n--- This assignment should not be inferred (not from first column)\n  local B_no = 1\n\nreturn M\n--stylua: ignore end\n"
  },
  {
    "path": "tests/dir-doc/sections/.styluaignore",
    "content": "init.lua\n"
  },
  {
    "path": "tests/dir-doc/sections/alias.lua",
    "content": "--- Test `@alias` section\n\n---@alias   var_one   fun(type: string, data: any)\n---@alias var_two table<string,number> Another data structure.\n---   Its description spans over multiple lines.\n---@alias %bad_name* This alias has bad name and should still work.\n\n---@param x var_one\n---@param y var_two\n---@param z var_three Should be enclosed as custom classes are allowed.\n---@alias var_three This alias shouldn't be applied to previous line as it is defined after it.\n\n--- Aliases also expand inside text: var_one\n\n--- Test of `MiniDoc.current.aliases`\n---\n---@eval return vim.inspect(MiniDoc.current.aliases)\n\n---@alias aaa number\n---@alias _bbb1 string\n---@alias ccc_ table\n---@alias union number|nil\n---@alias unionOther string | table\n\n--- Aliases should not be replaced when they are obviously not meant to\n---\n---@param a1 aaaClass Should not be replaced\n---@param a2 aaa_bbb1 Should not be replaced\n---@param a3 ccc_bbb1 Should not be replaced\n---\n---@text None of these should be replaced: aaaA _bbb1_ other.ccc_\n---\n---@return aaaClass\n---@return aaa_bbb1\n---@return ccc_bbb1\n---\n---@text All next ones should be replaced as they are inside allowed syntax\n---\n---@param b1 aaa?\n---@param b2 _bbb1?\n---@param b3 ccc_?\n---\n---@param c1 aaa|_bbb1|ccc_\n---@param c2 aaa[]\n---@param c3 [aaa,_bbb1,ccc_]\n---@param c4 {[aaa]:_bbb1}\n---@param c5 table<aaa,_bbb1>\n---@param c6 {key1:aaa,key2:_bbb1}\n---@param c7 fun(arg1:aaa,arg2:_bbb1):ccc_\n---\n---@text Union types should try to \"smartly\" add parenthesis\n---\n---@param d1  union\n---@param D1  unionOther\n---@param d2  union?\n---@param D2  unionOther?\n---@param d3  union[]\n---@param D3  unionOther[]\n---@param d4  [union,unionOther]\n---@param D4  [unionOther,union]\n---@param d5  [union, unionOther]\n---@param D5  [unionOther, union]\n---@param d6  [ union, unionOther ]\n---@param D6  [ unionOther, union ]\n---@param d7  [ union , unionOther ]\n---@param d8  {[union]:unionOther}\n---@param D8  {[unionOther]:union}\n---@param d9  { [union]: unionOther }\n---@param D9  { [unionOther]: union }\n---@param d10 table<union,unionOther>\n---@param D10 table<unionOther,union>\n---@param d11 table<union, unionOther>\n---@param D11 table<unionOther, union>\n---@param d12 {key1:union,key2:unionOther}\n---@param D12 {key1:unionOther,key2:union}\n---@param d13 { key1:union, key2:unionOther }\n---@param D13 { key1:unionOther, key2:union }\n---@param d14 { key1: union, key2: unionOther }\n---@param d15 fun(arg1:union,arg2:unionOther):union\n---@param D15 fun(arg1:unionOther,arg2:union):unionOther\n---@param d16 fun(arg1: union, arg2: unionOther): union\n---@param D16 fun(arg1: unionOther, arg2: union): unionOther\n\n--- There should not be replacements in some special cases\n---\n---@param aaa aaa Parameter name should not be replaced.\n---\n---@class aaa Class name should not be replaced\n---@field aaa aaa Field name should not be replaced.\n---\n---@tag aaa\n---@toc_entry aaa (no alias replacement)\n"
  },
  {
    "path": "tests/dir-doc/sections/eval.lua",
    "content": "local M = {}\n\n--- Tests of `@eval` section\n---\n--- Generic case\n---\n---@eval local i = 1\n--- return ('This string is ' .. 'evaluated using local variable. '\n---   .. i .. ' + ' .. i .. ' = ' .. (i + i))\n\n--- Usage of `MiniDoc.afterlines_to_code()` and `MiniDoc.current.eval_section`\n---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)\nM.tab = {\n  -- Some functional setting\n  --minidoc_replace_start     a = <function; should be padded>,\n  a = function() return 1 + 1 end,\n  --minidoc_replace_end\n  -- A very important setting\n  b = 2,\n  c = {\n    d = 3,\n    e = 4,\n  },\n  --minidoc_replace_start\n  f = 'This line should be completely removed',\n  --minidoc_replace_end\n}\n--minidoc_afterlines_end\n\nM.entry = [[Shouldn't be included in afterlines]]\n"
  },
  {
    "path": "tests/dir-doc/sections/init.lua",
    "content": "local M = {}\n\n--- Test for `@class`, `@field`, and `@type`\n---\n---@class User\n---\n---@field login string User login.\n---@field password string User password.\n---@field address? string User address (should expand to optional).\n---\n---@type table\nM.User = {}\n\n--- Test `@diagnostic` (should be ignored in output) and `@overload`\n---\n---@param x string Variable.\n---\n---@overload fun(x: string)\n---@diagnostic disable\nlocal f = function(x, y) return x + 1 end\n---@diagnostic enable\n\n--- Test for `@private`\n---\n--- Private method that shouldn't be present in output\n---@private\n---\n---@param x number Should not error if there are sections after `@private`.\n---@return number Should not error if there are sections after `@private`.\nM._private_method = function(x) return x + 2 end\n\n--- Test for `@seealso` and `@usage`\n---\n---@usage `M.fun(1, 2)`\n---\n---@seealso |test-f| |f-test-different-line|\nM.fun = function(a, b) return true end\n\n--- Test for `@signature` and `@tag`\n---\n--- `@signature` should override default title inference where it is placed.\n--- `@tag` should enclose non-whitespace group separately.\n---\n---@signature fun(x, y)\n---@tag test-f f-test\n--- f-test-different-line\nlocal f = function() end\n\n\n--- Test for smart empty line append\n--- Some text\n---   \n\n--- Test for smart empty line before tag\n--- >lua\n---   -- This is code block\n--- <\n---@tag important-tag\n\n--- Test for `@text`\n---\n---@param a string\n---@text\n--- This illustrates some code:\n--- >\n---   require('mini.doc').setup()\n--- <\n"
  },
  {
    "path": "tests/dir-doc/sections/param.lua",
    "content": "--- Tests for `@param` section\n\n--- Test for general cases\n---\n---@param b number Number.\n---@param a string Some string. Multiline description:\n---   - Item 1.\n---   - Item 2.\n---@param c table\n---@param d\n---@param x %%%bad_name!! Actual formatting is not defined\n\n--- Test for expanding `?` to `(optional)`\n---\n---@param x? string This should add `(optional)`\n---@param y string? This should not add `(optional)` as `?` is not after first word.\n---@param abc string Having ? inside comment shouldn't trigger `(optional)`.\n\n--- Test for enclosing type\n---\n---@param a number Should work.\n---@param b number[] Should work.\n---@param B number[]? Should work.\n---@param c number|nil Should work.\n---@param C number | nil Should work.\n---@param d number | number[] Should work.\n---@param e (number | nil) Should not be doubly enclosed in ().\n---@param f [number, string] Should work.\n---@param F [number, string[]] Should work.\n---@param g {[string]:number} Should work.\n---@param G { [string]: number } Should work.\n---@param h {key1:string,key2:number} Should work.\n---@param H { key1: string, key2: number } Should work.\n---@param i table<string, number> Should work.\n---@param j fun(a: string, b:number) Should work.\n---@param k fun(a: string, b:number): table Should work.\n---@param K fun(a: string, b:number):table Should work.\n---@param l fun(a: string): string | nil Should work.\n---@param L fun(a: string):string | nil Should work.\n---@param m fun(a: string): (string | nil) Should work.\n---@param M fun(a: string):(string | nil) Should work.\n---@param n fun(a: string): [number, string] Should work.\n---@param N fun(a: string):[number, string] Should work.\n---@param o fun(a: string): { key1: string } Should work.\n---@param O fun(a: string):{ key1: string } Should work.\n---@param p fun(a: string): table<string, number> Should work.\n---@param P fun(a: string):table<string, number> Should work.\n---@param q fun(a: string): NUMBER | OTHER Should work.\n---@param Q fun(a: string):NUMBER | OTHER Should work.\n---@param r NUMBER Should still work as custom classes are allowed.\n---@param R My_Class.child Should still work as custom classes are allowed.\n---@param s NUMBER|nil Should still work as custom classes are allowed.\n---@param S My_Class.child|nil Should still work as custom classes are allowed.\n---@param t NUMBER | nil Should still work as custom classes are allowed.\n---@param T My_Class.child | nil Should still work as custom classes are allowed.\n---@param u (NUMBER | nil) Should not be doubly enclosed in ().\n---@param v number[] | (string | nil) | [number, string] Should work.\n---@param w number | string Should ignore |later| special[] characters?\n---@param x (number) | (string) Should still enclose in parenthesis.\n---@param a_function function Should enclose second `function`.\n---@param function_a function Should enclose second `function`.\n---@param a_function_a function Should enclose second `function`.\n---@param afunction function Should enclose second `function`.\n"
  },
  {
    "path": "tests/dir-doc/sections/return.lua",
    "content": "--- Tests for `@return` section\n\n--- Test for general cases\n---\n---@return number Some number.\n\n--- Test for expanding `?` to `(optional)`\n---\n---@return number?\n---@return boolean? Second ? shouldn't trigger anything.\n\n--- Test for enclosing type\n---\n---@return number Should work.\n---@return number[] Should work.\n---@return number[]? Should work.\n---@return number|nil Should work.\n---@return number | nil Should work.\n---@return number | number[] Should work.\n---@return (number | nil) Should not be doubly enclosed in ().\n---@return [number, string] Should work.\n---@return [number, string[]] Should work.\n---@return {[string]:number} Should work.\n---@return { [string]: number } Should work.\n---@return {key1:string,key2:number} Should work.\n---@return { key1: string, key2: number } Should work.\n---@return table<string, number> Should work.\n---@return fun(a: string, b:number) Should work.\n---@return fun(a: string, b:number): table Should work.\n---@return fun(a: string, b:number):table Should work.\n---@return fun(a: string): string | nil Should work.\n---@return fun(a: string):string | nil Should work.\n---@return fun(a: string): (string | nil) Should work.\n---@return fun(a: string):(string | nil) Should work.\n---@return fun(a: string): [number, string] Should work.\n---@return fun(a: string):[number, string] Should work.\n---@return fun(a: string): { key1: string } Should work.\n---@return fun(a: string):{ key1: string } Should work.\n---@return fun(a: string): table<string, number> Should work.\n---@return fun(a: string):table<string, number> Should work.\n---@return fun(a: string): NUMBER | OTHER Should work.\n---@return fun(a: string):NUMBER | OTHER Should work.\n---@return NUMBER Should still work as custom classes are allowed.\n---@return My_Class.child Should still work as custom classes are allowed.\n---@return NUMBER|nil Should still work as custom classes are allowed.\n---@return My_Class.child|nil Should still work as custom classes are allowed.\n---@return NUMBER | nil Should still work as custom classes are allowed.\n---@return My_Class.child | nil Should still work as custom classes are allowed.\n---@return (NUMBER | nil) Should not be doubly enclosed in ().\n---@return number[] | (string | nil) | [number, string] Should work.\n---@return number | string Should ignore |later| special[] characters?\n---@return (number) | (string) Should still enclose in parenthesis.\n---@return ... Should work.\n"
  },
  {
    "path": "tests/dir-doc/sections/sections_reference.txt",
    "content": "                                                                        *M.User*\n                                    `M.User`\nTest for `@class`, `@field`, and `@type`\n\nClass ~\n{User}\n\nFields ~\n{login} `(string)` User login.\n{password} `(string)` User password.\n{address} `(optional)` `(string)` User address (should expand to optional).\n\nType ~\n`(table)`\n\n------------------------------------------------------------------------------\n                                                                           *f()*\n                                 `f`({x}, {y})\nTest `@diagnostic` (should be ignored in output) and `@overload`\n\nParameters ~\n{x} `(string)` Variable.\n\nOverload ~\n`fun(x: string)`\n\n------------------------------------------------------------------------------\n                                                                       *M.fun()*\n                               `M.fun`({a}, {b})\nTest for `@seealso` and `@usage`\n\nUsage ~\n`M.fun(1, 2)`\n\nSee also ~\n|test-f| |f-test-different-line|\n\n------------------------------------------------------------------------------\n                                                                 *test-f* *f-test*\n                                                         *f-test-different-line*\nTest for `@signature` and `@tag`\n\n`@signature` should override default title inference where it is placed.\n`@tag` should enclose non-whitespace group separately.\n\n                                `fun`({x}, {y})\n\n------------------------------------------------------------------------------\nTest for smart empty line append\nSome text\n  \n------------------------------------------------------------------------------\n                                                                 *important-tag*\nTest for smart empty line before tag\n>lua\n  -- This is code block\n<\n------------------------------------------------------------------------------\nTest for `@text`\n\nParameters ~\n{a} `(string)`\n\nThis illustrates some code:\n>\n  require('mini.doc').setup()\n<\n\n==============================================================================\n------------------------------------------------------------------------------\nTest `@alias` section\n\n------------------------------------------------------------------------------\nParameters ~\n{x}   `(fun(type: string, data: any))`\n{y} `(table<string,number>)` Another data structure.\n  Its description spans over multiple lines.\n{z} `(var_three)` Should be enclosed as custom classes are allowed.\n\n------------------------------------------------------------------------------\nAliases also expand inside text:   fun(type: string, data: any)\n\n------------------------------------------------------------------------------\nTest of `MiniDoc.current.aliases`\n\n{\n  [\"%bad_name*\"] = \"This alias has bad name and should still work.\",\n  var_one = \"  fun(type: string, data: any)\",\n  var_three = \"This alias shouldn't be applied to previous line as it is defined after it.\",\n  var_two = \"table<string,number> Another data structure.\\n  Its description spans over multiple lines.\"\n}\n\n------------------------------------------------------------------------------\nAliases should not be replaced when they are obviously not meant to\n\nParameters ~\n{a1} `(aaaClass)` Should not be replaced\n{a2} `(aaa_bbb1)` Should not be replaced\n{a3} `(ccc_bbb1)` Should not be replaced\n\nNone of these should be replaced: aaaA _bbb1_ other.ccc_\n\nReturn ~\n`(aaaClass)`\nReturn ~\n`(aaa_bbb1)`\nReturn ~\n`(ccc_bbb1)`\n\nAll next ones should be replaced as they are inside allowed syntax\n\n{b1} `(number?)`\n{b2} `(string?)`\n{b3} `(table?)`\n\n{c1} `(number|string|table)`\n{c2} `(number[])`\n{c3} `([number,string,table])`\n{c4} `({[number]:string})`\n{c5} `(table<number,string>)`\n{c6} `({key1:number,key2:string})`\n{c7} `(fun(arg1:number,arg2:string):table)`\n\nUnion types should try to \"smartly\" add parenthesis\n\n{d1}  `(number|nil)`\n{D1}  `(string | table)`\n{d2}  `((number|nil)?)`\n{D2}  `((string | table)?)`\n{d3}  `((number|nil)[])`\n{D3}  `((string | table)[])`\n{d4}  `([(number|nil),(string | table)])`\n{D4}  `([(string | table),(number|nil)])`\n{d5}  `([(number|nil), (string | table)])`\n{D5}  `([(string | table), (number|nil)])`\n{d6}  `([ (number|nil), string | table ])`\n{D6}  `([ (string | table), number|nil ])`\n{d7}  `([ number|nil , string | table ])`\n{d8}  `({[(number|nil)]:(string | table)})`\n{D8}  `({[(string | table)]:(number|nil)})`\n{d9}  `({ [(number|nil)]: string | table })`\n{D9}  `({ [(string | table)]: number|nil })`\n{d10} `(table<(number|nil),(string | table)>)`\n{D10} `(table<(string | table),(number|nil)>)`\n{d11} `(table<(number|nil), (string | table)>)`\n{D11} `(table<(string | table), (number|nil)>)`\n{d12} `({key1:(number|nil),key2:(string | table)})`\n{D12} `({key1:(string | table),key2:(number|nil)})`\n{d13} `({ key1:(number|nil), key2:(string | table) })`\n{D13} `({ key1:(string | table), key2:(number|nil) })`\n{d14} `({ key1: (number|nil), key2: string | table })`\n{d15} `(fun(arg1:(number|nil),arg2:(string | table)):(number|nil))`\n{D15} `(fun(arg1:(string | table),arg2:(number|nil)):(string | table))`\n{d16} `(fun(arg1: (number|nil), arg2: (string | table)): number|nil)`\n{D16} `(fun(arg1: (string | table), arg2: (number|nil)): string | table)`\n\n------------------------------------------------------------------------------\n                                                                           *aaa*\nThere should not be replacements in some special cases\n\nParameters ~\n{aaa} `(aaa)` Parameter name should not be replaced.\n\nClass ~\n{aaa} Class name should not be replaced\nFields ~\n{aaa} `(aaa)` Field name should not be replaced.\n\n\n\n==============================================================================\n------------------------------------------------------------------------------\nTests of `@eval` section\n\nGeneric case\n\nThis string is evaluated using local variable. 1 + 1 = 2\n\n------------------------------------------------------------------------------\n                                                                         *M.tab*\n                                    `M.tab`\nUsage of `MiniDoc.afterlines_to_code()` and `MiniDoc.current.eval_section`\n>lua\n  M.tab = {\n    -- Some functional setting\n        a = <function; should be padded>,\n    -- A very important setting\n    b = 2,\n    c = {\n      d = 3,\n      e = 4,\n    },\n    \n  }\n<\n\n==============================================================================\n------------------------------------------------------------------------------\nTests for `@param` section\n\n------------------------------------------------------------------------------\nTest for general cases\n\nParameters ~\n{b} `(number)` Number.\n{a} `(string)` Some string. Multiline description:\n  - Item 1.\n  - Item 2.\n{c} `(table)`\n{d}\n{x} %%%`(bad_name)`!! Actual formatting is not defined\n\n------------------------------------------------------------------------------\nTest for expanding `?` to `(optional)`\n\nParameters ~\n{x} `(optional)` `(string)` This should add `(optional)`\n{y} `(string?)` This should not add `(optional)` as `?` is not after first word.\n{abc} `(string)` Having ? inside comment shouldn't trigger `(optional)`.\n\n------------------------------------------------------------------------------\nTest for enclosing type\n\nParameters ~\n{a} `(number)` Should work.\n{b} `(number[])` Should work.\n{B} `(number[]?)` Should work.\n{c} `(number|nil)` Should work.\n{C} `(number | nil)` Should work.\n{d} `(number | number[])` Should work.\n{e} `(number | nil)` Should not be doubly enclosed in ().\n{f} `([number, string])` Should work.\n{F} `([number, string[]])` Should work.\n{g} `({[string]:number})` Should work.\n{G} `({ [string]: number })` Should work.\n{h} `({key1:string,key2:number})` Should work.\n{H} `({ key1: string, key2: number })` Should work.\n{i} `(table<string, number>)` Should work.\n{j} `(fun(a: string, b:number))` Should work.\n{k} `(fun(a: string, b:number): table)` Should work.\n{K} `(fun(a: string, b:number):table)` Should work.\n{l} `(fun(a: string): string | nil)` Should work.\n{L} `(fun(a: string):string | nil)` Should work.\n{m} `(fun(a: string): (string | nil))` Should work.\n{M} `(fun(a: string):(string | nil))` Should work.\n{n} `(fun(a: string): [number, string])` Should work.\n{N} `(fun(a: string):[number, string])` Should work.\n{o} `(fun(a: string): { key1: string })` Should work.\n{O} `(fun(a: string):{ key1: string })` Should work.\n{p} `(fun(a: string): table<string, number>)` Should work.\n{P} `(fun(a: string):table<string, number>)` Should work.\n{q} `(fun(a: string): NUMBER | OTHER)` Should work.\n{Q} `(fun(a: string):NUMBER | OTHER)` Should work.\n{r} `(NUMBER)` Should still work as custom classes are allowed.\n{R} `(My_Class.child)` Should still work as custom classes are allowed.\n{s} `(NUMBER|nil)` Should still work as custom classes are allowed.\n{S} `(My_Class.child|nil)` Should still work as custom classes are allowed.\n{t} `(NUMBER | nil)` Should still work as custom classes are allowed.\n{T} `(My_Class.child | nil)` Should still work as custom classes are allowed.\n{u} `(NUMBER | nil)` Should not be doubly enclosed in ().\n{v} `(number[] | (string | nil) | [number, string])` Should work.\n{w} `(number | string)` Should ignore |later| special[] characters?\n{x} `((number) | (string))` Should still enclose in parenthesis.\n{a_function} `(function)` Should enclose second `function`.\n{function_a} `(function)` Should enclose second `function`.\n{a_function_a} `(function)` Should enclose second `function`.\n{afunction} `(function)` Should enclose second `function`.\n\n\n==============================================================================\n------------------------------------------------------------------------------\nTests for `@return` section\n\n------------------------------------------------------------------------------\nTest for general cases\n\nReturn ~\n`(number)` Some number.\n\n------------------------------------------------------------------------------\nTest for expanding `?` to `(optional)`\n\nReturn ~\n`(number)` `(optional)`\nReturn ~\n`(boolean)` `(optional)` Second ? shouldn't trigger anything.\n\n------------------------------------------------------------------------------\nTest for enclosing type\n\nReturn ~\n`(number)` Should work.\nReturn ~\n`(number[])` Should work.\nReturn ~\n`(number[])` `(optional)` Should work.\nReturn ~\n`(number|nil)` Should work.\nReturn ~\n`(number | nil)` Should work.\nReturn ~\n`(number | number[])` Should work.\nReturn ~\n`(number | nil)` Should not be doubly enclosed in ().\nReturn ~\n`([number, string])` Should work.\nReturn ~\n`([number, string[]])` Should work.\nReturn ~\n`({[string]:number})` Should work.\nReturn ~\n`({ [string]: number })` Should work.\nReturn ~\n`({key1:string,key2:number})` Should work.\nReturn ~\n`({ key1: string, key2: number })` Should work.\nReturn ~\n`(table<string, number>)` Should work.\nReturn ~\n`(fun(a: string, b:number))` Should work.\nReturn ~\n`(fun(a: string, b:number): table)` Should work.\nReturn ~\n`(fun(a: string, b:number):table)` Should work.\nReturn ~\n`(fun(a: string): string | nil)` Should work.\nReturn ~\n`(fun(a: string):string | nil)` Should work.\nReturn ~\n`(fun(a: string): (string | nil))` Should work.\nReturn ~\n`(fun(a: string):(string | nil))` Should work.\nReturn ~\n`(fun(a: string): [number, string])` Should work.\nReturn ~\n`(fun(a: string):[number, string])` Should work.\nReturn ~\n`(fun(a: string): { key1: string })` Should work.\nReturn ~\n`(fun(a: string):{ key1: string })` Should work.\nReturn ~\n`(fun(a: string): table<string, number>)` Should work.\nReturn ~\n`(fun(a: string):table<string, number>)` Should work.\nReturn ~\n`(fun(a: string): NUMBER | OTHER)` Should work.\nReturn ~\n`(fun(a: string):NUMBER | OTHER)` Should work.\nReturn ~\n`(NUMBER)` Should still work as custom classes are allowed.\nReturn ~\n`(My_Class.child)` Should still work as custom classes are allowed.\nReturn ~\n`(NUMBER|nil)` Should still work as custom classes are allowed.\nReturn ~\n`(My_Class.child|nil)` Should still work as custom classes are allowed.\nReturn ~\n`(NUMBER | nil)` Should still work as custom classes are allowed.\nReturn ~\n`(My_Class.child | nil)` Should still work as custom classes are allowed.\nReturn ~\n`(NUMBER | nil)` Should not be doubly enclosed in ().\nReturn ~\n`(number[] | (string | nil) | [number, string])` Should work.\nReturn ~\n`(number | string)` Should ignore |later| special[] characters?\nReturn ~\n`((number) | (string))` Should still enclose in parenthesis.\nReturn ~\n`(...)` Should work.\n\n\n==============================================================================\n------------------------------------------------------------------------------\nTest `@toc` and `@toc_entry` sections\n\nTable of contents:\n  aaa (no alias replacement) ........................................... |aaa|\n      Entry #1 .............................................................\n  Entry #2: ................................................................\n  This time it is\n  multiline\n  Entry #3 .................................................. |toc-entry-with|\n                                                               |multiline-tag|\n  Entry #4: .......................................... |toc-second-entry-with|\n  Multiline with                                             |multiline-tag-2|\n  three lines\n  ............................................ |toc-entry-without-description|\n  Entry #6 (without tag) ...................................................\n  Entry #7: A very-very-very-very-very-very-very-very-very-very long description ...\n\n------------------------------------------------------------------------------\nTOC entry with leading spaces\n\n------------------------------------------------------------------------------\nMultiline TOC entry\n\n------------------------------------------------------------------------------\n                                                                *toc-entry-with*\n                                                                 *multiline-tag*\nTOC entry with multiline tag\n\n------------------------------------------------------------------------------\n                                                         *toc-second-entry-with*\n                                                               *multiline-tag-2*\nTOC entry with multiline tag and entry\n\n------------------------------------------------------------------------------\n                                                 *toc-entry-without-description*\nTOC entry without description\n\n------------------------------------------------------------------------------\nTOC entry without tag\n\n------------------------------------------------------------------------------\nTOC entry with very long description\n\n------------------------------------------------------------------------------\nTest of `MiniDoc.current.toc`\n\nNumber of current TOC entries: 8\n\n\n vim:tw=78:ts=8:noet:ft=help:norl:\n"
  },
  {
    "path": "tests/dir-doc/sections/toc.lua",
    "content": "--- Test `@toc` and `@toc_entry` sections\n---\n--- Table of contents:\n---@toc\n\n--- TOC entry with leading spaces\n---@toc_entry     Entry #1\n\n--- Multiline TOC entry\n---@toc_entry Entry #2:\n--- This time it is\n--- multiline\n\n--- TOC entry with multiline tag\n---@tag toc-entry-with\n--- multiline-tag\n---@toc_entry Entry #3\n\n--- TOC entry with multiline tag and entry\n---@tag toc-second-entry-with\n--- multiline-tag-2\n---@toc_entry Entry #4:\n--- Multiline with\n--- three lines\n\n--- TOC entry without description\n---\n---@tag toc-entry-without-description\n---@toc_entry\n\n--- TOC entry without tag\n---@toc_entry Entry #6 (without tag)\n\n--- TOC entry with very long description\n---@toc_entry Entry #7: A very-very-very-very-very-very-very-very-very-very long description\n\n--- Test of `MiniDoc.current.toc`\n---\n---@eval return 'Number of current TOC entries: ' .. #MiniDoc.current.toc\n"
  },
  {
    "path": "tests/dir-doc/structure/file1.lua",
    "content": "---@text This is `@text` section.\n--- It has multiple lines.\n---@text This is another section in the same block.\n\n---@text This is another block with single `@text` section.\n"
  },
  {
    "path": "tests/dir-doc/structure/file2.lua",
    "content": "---@text This is another file.\n"
  },
  {
    "path": "tests/dir-extra/colorschemes/colors/miniforcebg.lua",
    "content": "vim.o.background = vim.o.background == 'dark' and 'light' or 'dark'\nvim.g.colors_name = 'miniforcebg'\n"
  },
  {
    "path": "tests/dir-extra/explorer/Dir2/file2-1",
    "content": ""
  },
  {
    "path": "tests/dir-extra/explorer/File2",
    "content": "File 2\n"
  },
  {
    "path": "tests/dir-extra/explorer/dir1/file1-1",
    "content": "File 1-1\n"
  },
  {
    "path": "tests/dir-extra/explorer/dir1/subdir/file1-1-1",
    "content": "File 1-1-1\n"
  },
  {
    "path": "tests/dir-extra/explorer/dir3/file3-1",
    "content": ""
  },
  {
    "path": "tests/dir-extra/explorer/file1",
    "content": "File 1\n"
  },
  {
    "path": "tests/dir-extra/explorer/file3",
    "content": "File 3\n"
  },
  {
    "path": "tests/dir-extra/git-files/git-file-1",
    "content": "Line 1-1\nLine 1-2\nLine 1-3\nLine 1-4\nLine 1-5\nLine 1-6\nLine 1-7\nLine 1-8\nLine 1-9\nLine 1-10\nLine 1-11\nLine 1-12\nLine 1-13\nLine 1-14\nLine 1-15\nLine 1-16\nLine 1-17\nLine 1-18\nLine 1-19\nLine 1-20\nLine 1-21\n"
  },
  {
    "path": "tests/dir-extra/git-files/git-file-2",
    "content": "Line 2-1\nLine 2-2\nLine 2-3\nLine 2-4\nLine 2-5\nLine 2-6\nLine 2-7\nLine 2-8\nLine 2-9\nLine 2-10\nLine 2-11\nLine 2-12\nLine 2-13\nLine 2-14\nLine 2-15\nLine 2-16\nLine 2-17\nLine 2-18\nLine 2-19\nLine 2-20\nLine 2-21\n"
  },
  {
    "path": "tests/dir-extra/lua/nvim-web-devicons.lua",
    "content": "vim.cmd('hi DevIconLicense guifg=#111111')\nvim.cmd('hi DevIconMakefile guifg=#222222')\nvim.cmd('hi DevIconGif guifg=#333333')\nvim.cmd('hi DevIconLua guifg=#444444')\nvim.cmd('hi DevIconTxt guifg=#555555')\nvim.cmd('hi DevIconDefault guifg=#666666')\n\nreturn {\n  get_icon = function(filename, _, options)\n    if filename == 'LICENSE' then return '', 'DevIconLicense' end\n    if filename == 'Makefile' then return '', 'DevIconMakefile' end\n    if vim.endswith(filename, 'gif') then return '', 'DevIconGif' end\n    if vim.endswith(filename, 'lua') then return '', 'DevIconLua' end\n    if vim.endswith(filename, 'txt') then return '', 'DevIconTxt' end\n    if (options or {}).default then return '', 'DevIconDefault' end\n  end,\n}\n"
  },
  {
    "path": "tests/dir-extra/mocks/diagnostic-file-1",
    "content": "Error Warning Info Hint\n  Error\n  Warning\n  Info\n  Hint\n"
  },
  {
    "path": "tests/dir-extra/mocks/diagnostic-file-2",
    "content": "Error\nWarning\nInfo\nHint\n"
  },
  {
    "path": "tests/dir-extra/mocks/diagnostic.lua",
    "content": "local severity = vim.diagnostic.severity\n_G.diag_ns = vim.api.nvim_create_namespace('mock-diagnostics')\n\n-- Open files\nvim.cmd('edit tests/dir-extra/mocks/diagnostic-file-1')\n_G.buf_id_1 = vim.api.nvim_get_current_buf()\nvim.cmd('edit tests/dir-extra/mocks/diagnostic-file-2')\n_G.buf_id_2 = vim.api.nvim_get_current_buf()\n\n-- Define diagnostic\n--stylua: ignore\n_G.diagnostic_arr = {\n  -- Several entries on one line\n  { bufnr = buf_id_1, lnum = 0, end_lnum = 0, col = 0,  end_col = 5,  message = 'Error 1',   severity = severity.ERROR },\n  { bufnr = buf_id_1, lnum = 0, end_lnum = 0, col = 6,  end_col = 13, message = 'Warning 1', severity = severity.WARN  },\n  { bufnr = buf_id_1, lnum = 0, end_lnum = 0, col = 14, end_col = 18, message = 'Info 1',    severity = severity.INFO  },\n  { bufnr = buf_id_1, lnum = 0, end_lnum = 0, col = 19, end_col = 23, message = 'Hint 1',    severity = severity.HINT  },\n\n  -- Entries on separate lines not at line start\n  { bufnr = buf_id_1, lnum = 1, end_lnum = 1, col = 2,  end_col = 7,  message = 'Error 2',   severity = severity.ERROR },\n  { bufnr = buf_id_1, lnum = 2, end_lnum = 2, col = 2,  end_col = 9,  message = 'Warning 2', severity = severity.WARN  },\n  { bufnr = buf_id_1, lnum = 3, end_lnum = 3, col = 2,  end_col = 6,  message = 'Info 2',    severity = severity.INFO  },\n  { bufnr = buf_id_1, lnum = 4, end_lnum = 4, col = 2,  end_col = 6,  message = 'Hint 2',    severity = severity.HINT  },\n\n  -- Another buffer\n  { bufnr = buf_id_2, lnum = 0, end_lnum = 0, col = 0,  end_col = 5,  message = 'Error 3',   severity = severity.ERROR },\n  { bufnr = buf_id_2, lnum = 1, end_lnum = 1, col = 0,  end_col = 7,  message = 'Warning 3', severity = severity.WARN  },\n  { bufnr = buf_id_2, lnum = 2, end_lnum = 2, col = 0,  end_col = 4,  message = 'Info 3',    severity = severity.INFO  },\n  { bufnr = buf_id_2, lnum = 3, end_lnum = 3, col = 0,  end_col = 4,  message = 'Hint 3',    severity = severity.HINT  },\n}\n\n-- Set diagnostic\nvim.diagnostic.set(diag_ns, buf_id_1, vim.tbl_filter(function(x) return x.bufnr == buf_id_1 end, _G.diagnostic_arr), {})\nvim.diagnostic.set(diag_ns, buf_id_2, vim.tbl_filter(function(x) return x.bufnr == buf_id_2 end, _G.diagnostic_arr), {})\n"
  },
  {
    "path": "tests/dir-extra/mocks/git-commit",
    "content": "commit 1111111111111111111111111111111111111111\nAuthor: Mini Nvim <mini.nvim@emailaddress.com>\nDate:   Thu Jan 1 11:11:11 1970 +0300\n\n    Initial commit.\n\ndiff --git a/git-files/git-file-1 b/git-files/git-file-1\nindex 1111111..0123456 100644\n--- a/git-files/git-file-1\n+++ b/git-files/git-file-1\n@@ -1,5 +1,5 @@\n Line 1-1\n-Line 1-2\n Line 1-3\n Line 1-4\n Line 1-5\n+Line 1-6\n\n"
  },
  {
    "path": "tests/dir-extra/mocks/git-diff",
    "content": "diff --git a/git-files/git-file-1 b/git-files/git-file-1\nindex c139d4e..234d24d 100644\n--- a/git-files/git-file-1\n+++ b/git-files/git-file-1\n@@ -1,4 +1,3 @@\n-Line 1-1\n Line 1-2\n Line 1-3\n Line 1-4\n@@ -9,6 +8,7 @@ Line 1-8\n Line 1-9\n Line 1-10\n Line 1-11\n+Line new\n Line 1-12\n Line 1-13\n Line 1-14\n@@ -18,4 +18,4 @@ Line 1-17\n Line 1-18\n Line 1-19\n Line 1-20\n-Line 1-21\n+Line changed\ndiff --git a/git-files/git-file-2 b/git-files/git-file-2\nindex e45e3de..bd830d0 100644\n--- a/git-files/git-file-2\n+++ b/git-files/git-file-2\n@@ -1,5 +1,4 @@\n Line 2-1\n-Line 2-2\n Line 2-3\n Line 2-4\n Line 2-5\n@@ -10,10 +9,11 @@ Line 2-9\n Line 2-10\n Line 2-11\n Line 2-12\n+Line new\n Line 2-13\n Line 2-14\n Line 2-15\n-Line 2-16\n+Line changed\n Line 2-17\n Line 2-18\n Line 2-19\n"
  },
  {
    "path": "tests/dir-extra/mocks/git-diff-edge-cases",
    "content": "diff --git i/git-files/git-file-1 w/git-files/git-file-1\nindex c139d4e..234d24d 100644\n--- i/git-files/git-file-1\n+++ w/git-files/git-file-1\n@@ -1,4 +1,3 @@\n-Line 1-1\n Line 1-2\n Line 1-3\n Line 1-4\ndiff --git i/git-files/git-file-2 w//git-files/git-file-2\ndeleted file mode 100644\nindex e45e3de1..00000000\n--- i/git-files/git-file-2\n+++ /dev/null\n@@ -1,21 +0,0 @@\n-Line 2-1\n-Line 2-2\n-Line 2-3\n-Line 2-4\n-Line 2-5\n-Line 2-6\n-Line 2-7\n-Line 2-8\n-Line 2-9\n-Line 2-10\n-Line 2-11\n-Line 2-12\n-Line 2-13\n-Line 2-14\n-Line 2-15\n-Line 2-16\n-Line 2-17\n-Line 2-18\n-Line 2-19\n-Line 2-20\n-Line 2-21\n"
  },
  {
    "path": "tests/dir-extra/mocks/git-diff-unified-0",
    "content": "diff --git a/git-files/git-file-1 b/git-files/git-file-1\nindex c139d4e..234d24d 100644\n--- a/git-files/git-file-1\n+++ b/git-files/git-file-1\n@@ -1 +0,0 @@\n-Line 1-1\n@@ -11,0 +11 @@ Line 1-11\n+Line new\n@@ -21 +21 @@ Line 1-20\n-Line 1-21\n+Line changed\ndiff --git a/git-files/git-file-2 b/git-files/git-file-2\nindex e45e3de..bd830d0 100644\n--- a/git-files/git-file-2\n+++ b/git-files/git-file-2\n@@ -2 +1,0 @@ Line 2-1\n-Line 2-2\n@@ -12,0 +12 @@ Line 2-12\n+Line new\n@@ -16 +16 @@ Line 2-15\n-Line 2-16\n+Line changed\n\n"
  },
  {
    "path": "tests/dir-extra/mocks/git-diff-unified-20",
    "content": "diff --git a/git-files/git-file-1 b/git-files/git-file-1\nindex c139d4e..234d24d 100644\n--- a/git-files/git-file-1\n+++ b/git-files/git-file-1\n@@ -1,21 +1,21 @@\n-Line 1-1\n Line 1-2\n Line 1-3\n Line 1-4\n Line 1-5\n Line 1-6\n Line 1-7\n Line 1-8\n Line 1-9\n Line 1-10\n Line 1-11\n+Line new\n Line 1-12\n Line 1-13\n Line 1-14\n Line 1-15\n Line 1-16\n Line 1-17\n Line 1-18\n Line 1-19\n Line 1-20\n-Line 1-21\n+Line changed\ndiff --git a/git-files/git-file-2 b/git-files/git-file-2\nindex e45e3de..bd830d0 100644\n--- a/git-files/git-file-2\n+++ b/git-files/git-file-2\n@@ -1,21 +1,21 @@\n Line 2-1\n-Line 2-2\n Line 2-3\n Line 2-4\n Line 2-5\n Line 2-6\n Line 2-7\n Line 2-8\n Line 2-9\n Line 2-10\n Line 2-11\n Line 2-12\n+Line new\n Line 2-13\n Line 2-14\n Line 2-15\n-Line 2-16\n+Line changed\n Line 2-17\n Line 2-18\n Line 2-19\n Line 2-20\n Line 2-21\n\n"
  },
  {
    "path": "tests/dir-extra/mocks/keymaps.lua",
    "content": "local tmp = 1\n\nlocal keymap_rhs = function()\n  -- Comment\n  _G.been_here = true\nend\n\n--stylua: ignore\nvim.api.nvim_set_keymap(\n  'n', 'ga', '',\n  { callback = keymap_rhs, desc = 'Keymap with callback' }\n)\n"
  },
  {
    "path": "tests/dir-extra/mocks/spawn.lua",
    "content": "_G.process_log = {}\n\nlocal n_pid = 0\nlocal new_process = function(pid)\n  return {\n    pid = pid,\n\n    _is_active_indicator = true,\n    is_active = function(process) return process._is_active_indicator end,\n    kill = function(process)\n      process._is_active_indicator = false\n      table.insert(_G.process_log, 'Process ' .. pid .. ' was killed.')\n    end,\n\n    _is_closing_indicator = false,\n    is_closing = function(process) return process._is_closing_indicator end,\n    close = function(process)\n      process._is_closing_indicator = true\n      table.insert(_G.process_log, 'Process ' .. pid .. ' was closed.')\n    end,\n  }\nend\n\n-- Mock streams by using global `_G.stdout_data_feed` and `_G.stderr_data_feed`\n-- arrays as source. Each feed's element should be either string (for usable\n-- data) or a table with `err` field (for error).\nlocal stream_counts = {}\nvim.loop.new_pipe = function()\n  -- NOTE: Use `_G.stream_type_queue` to determine which stream type to create\n  -- (for log purposes). This is to account for `vim.loop.spawn` creating\n  -- different sets of streams. Assume 'stdout' by default.\n  if _G.stream_type_queue == nil or #_G.stream_type_queue == 0 then _G.stream_type_queue = { 'stdout' } end\n  local stream_type = _G.stream_type_queue[1]\n  table.remove(_G.stream_type_queue, 1)\n\n  local new_count = (stream_counts[stream_type] or 0) + 1\n  stream_counts[stream_type] = new_count\n  local cur_stream_id = stream_type .. '_' .. new_count\n\n  return {\n    _is_active_indicator = true,\n    is_active = function(stream) return stream._is_active_indicator end,\n    read_start = function(stream, callback)\n      -- It is not possible in Neovim<0.10 to execute `vim.fn` functions during\n      -- `pipe:read_start()`\n      local vim_fn_orig = vim.deepcopy(vim.fn)\n      vim.fn = setmetatable({}, { __index = function() error('Can not use `vim.fn` during `read_start`.') end })\n\n      -- A stream/pipe is active if it is actually reading data at the moment\n      stream._is_active_indicator = true\n      local data_feed = stream_type == 'stdout' and _G.stdout_data_feed or _G.stderr_data_feed\n      for _, x in ipairs(data_feed or {}) do\n        if type(x) == 'table' then callback(x.err, nil) end\n        if type(x) == 'string' then callback(nil, x) end\n      end\n\n      table.insert(_G.process_log, cur_stream_id .. ' finished reading.')\n      stream._is_active_indicator = false\n      callback(nil, nil)\n\n      vim.fn = vim_fn_orig\n    end,\n    read_stop = function(stream)\n      stream._is_active_indicator = false\n      table.insert(_G.process_log, cur_stream_id .. ' was stopped.')\n    end,\n\n    _is_closing_indicator = false,\n    is_closing = function(stream) return stream._is_closing_indicator end,\n    close = function() table.insert(_G.process_log, cur_stream_id .. ' was closed.') end,\n  }\nend\n\n_G.spawn_log = {}\nvim.loop.spawn = function(path, options, on_exit)\n  local options_without_callables = vim.deepcopy(options)\n  options_without_callables.stdio = nil\n  table.insert(_G.spawn_log, { executable = path, options = options_without_callables })\n\n  vim.schedule(function() on_exit() end)\n\n  n_pid = n_pid + 1\n  local pid = 'Pid_' .. n_pid\n  return new_process(pid), pid\nend\n"
  },
  {
    "path": "tests/dir-extra/real-files/LICENSE",
    "content": "MIT (c)\n"
  },
  {
    "path": "tests/dir-extra/real-files/Makefile",
    "content": "VAR ?= 1\n\nall: test\n"
  },
  {
    "path": "tests/dir-extra/real-files/a.lua",
    "content": "local a = 1\nlocal t = {\n  x = math.max(a, 2),\n  y = math.min(a, 2),\n}\n"
  },
  {
    "path": "tests/dir-extra/real-files/b.txt",
    "content": "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10\nLine 11\nLine 12\nLine 13\nLine 14\nLine 15\nLine 16\nLine 17\nLine 18\nLine 19\nLine 20\nLine 21\nLine 22\nLine 23\nLine 24\nLine 25\nLine 26\n"
  },
  {
    "path": "tests/dir-files/common/.a-dir/aa-file",
    "content": ""
  },
  {
    "path": "tests/dir-files/common/.a-dir/ab-file",
    "content": ""
  },
  {
    "path": "tests/dir-files/common/.a-file",
    "content": ".a-file\n"
  },
  {
    "path": "tests/dir-files/common/A-file-2",
    "content": "A-file-2\n"
  },
  {
    "path": "tests/dir-files/common/a-dir/aa-dir/aaa-file",
    "content": ""
  },
  {
    "path": "tests/dir-files/common/a-dir/aa-file",
    "content": ""
  },
  {
    "path": "tests/dir-files/common/a-dir/ab-file",
    "content": ""
  },
  {
    "path": "tests/dir-files/common/a-file",
    "content": "a-file\n"
  },
  {
    "path": "tests/dir-files/common/b-dir/ba-file",
    "content": ""
  },
  {
    "path": "tests/dir-files/common/b-file",
    "content": "b-file\nAnother line\n"
  },
  {
    "path": "tests/dir-files/init-default-explorer.lua",
    "content": "dofile('scripts/minimal_init.lua')\n\n-- Make test more portable\nvim.cmd('source tests/dir-files/mock-win-functions.lua')\nvim.o.laststatus = 0\n\n-- Ensure instance size\nvim.o.lines = 15\nvim.o.columns = 80\n\n-- Set up module\nlocal use_as_default_explorer = os.getenv('USE_AS_DEFAULT_EXPLORER') == 'true'\nrequire('mini.files').setup({ options = { use_as_default_explorer = use_as_default_explorer } })\n"
  },
  {
    "path": "tests/dir-files/lua/nvim-web-devicons.lua",
    "content": "return {\n  get_icon = function(filename, _, options)\n    if filename == 'LICENSE' then return '', 'DevIconLicense' end\n    if filename == 'Makefile' then return '', 'DevIconMakefile' end\n    if vim.endswith(filename, 'gif') then return '', 'DevIconGif' end\n    if vim.endswith(filename, 'lua') then return '', 'DevIconLua' end\n    if vim.endswith(filename, 'txt') then return '', 'DevIconTxt' end\n    if (options or {}).default then return '', 'DevIconDefault' end\n  end,\n}\n"
  },
  {
    "path": "tests/dir-files/mock-win-functions.lua",
    "content": "local mock_title = function(x)\n  if type(x) ~= 'string' then return x end\n  -- Make sure that full path title is the same on any machine\n  return x:gsub('^(.+)/tests/dir%-files', function(m)\n    -- Account for possible title truncation.\n    -- NOTE: This will also remove the intentional truncation with '…' prefix.\n    -- There should be dedicated tests for this truncation that are not\n    -- affected by this mock.\n    local mocked_root = string.sub('MOCK_ROOT', -vim.fn.strdisplaywidth(m))\n    return mocked_root .. '/tests/dir-files'\n  end)\nend\n\n_G.nvim_open_win_orig = vim.api.nvim_open_win\n\nvim.api.nvim_open_win = function(buf_id, enter, config)\n  config.title = mock_title(config.title)\n  return nvim_open_win_orig(buf_id, enter, config)\nend\n\n_G.nvim_win_set_config_orig = vim.api.nvim_win_set_config\n\nvim.api.nvim_win_set_config = function(win_id, config)\n  config.title = mock_title(config.title)\n  return nvim_win_set_config_orig(win_id, config)\nend\n"
  },
  {
    "path": "tests/dir-files/nested/dir-1/dir-11/dir-111/dir-1111/dir-11111/file-111111",
    "content": ""
  },
  {
    "path": "tests/dir-files/nested/dir-1/dir-12/file-121",
    "content": ""
  },
  {
    "path": "tests/dir-files/real/LICENSE",
    "content": ""
  },
  {
    "path": "tests/dir-files/real/Makefile",
    "content": "VAR ?= 1\n\nall: test\n"
  },
  {
    "path": "tests/dir-files/real/a.lua",
    "content": "local a = 1\nlocal t = {\n  x = math.max(1, 2),\n  y = math.min(1, 2),\n}\n"
  },
  {
    "path": "tests/dir-files/real/b.txt",
    "content": "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10\nLine 11\nLine 12\nLine 13\nLine 14\nLine 15\nLine 16\nLine 17\nLine 18\nLine 19\nLine 20\nLine 21\nLine 22\nLine 23\nLine 24\nLine 25\nLine 26\n"
  },
  {
    "path": "tests/dir-files/real/top-secret",
    "content": ""
  },
  {
    "path": "tests/dir-git/File2",
    "content": ""
  },
  {
    "path": "tests/dir-git/deps-confirm",
    "content": "This is a confirmation report before an update.\n\nOther very useful info\n\n!!! plugin_a !!!\n\nSome error\n\n+++ plugin_b +++\nPath:         /home/user/.local/share/nvim/site/pack/deps/opt/plugin_b\nSource:       https://github.com/cool-plugins/plugin_b\nState before: aa339f6ab611da07183a7fe44daa482605392502\nState after:  093b29f2b409278e2ed69a90462fee54714b5a84 (master)\n\nPending updates from `master`:\n> 093b29f2 | 2024-09-06 06:42:29 +0000 | Neo McVim\n  feat: very important feature\n\n> bfe74a48 | 2024-09-05 13:25:50 +0000 | Neo McVim\n  fix: very important fix\n\n< 3826d0c4 | 2024-09-04 09:08:06 +0200 | Neo McVim\n  chore: not very important chore\n\n+++ plugin_c +++\nPath:         /home/user/.local/share/nvim/site/pack/deps/opt/plugin_c\nSource:       https://github.com/cool-plugins/plugin_c\nState before: 3a3c6244553f13fdd92d312c82722b57ce6c4bec\nState after:  fe3deb7f67ce0cc4ebfe2ea6c1c7ae1c7a939d73 (main)\n\nPending updates from `main`:\n> fe3deb7 | 2024-09-04 03:40:17 -0500 | Caleb White\n  fix: even more important fix\n\n--- plugin_d ---\nPath:   /home/user/.local/share/nvim/site/pack/deps/opt/plugin_d\nSource: https://github.com/cool-plugins/plugin_d\nState:  d231729b13da28fd1625c3d85f2315886ddeb05d (HEAD)\n"
  },
  {
    "path": "tests/dir-git/diff-output",
    "content": "diff --git a/dir/file1 b/dir/file1\nindex dd2b945..b81ef66 100644\n--- a/dir/file1\n+++ b/dir/file1\n@@ -247,3 +247,3 @@ Hunk header 1\n       Line 1\n-      Previous line 2\n+      Current line 2\n     Line 3\n@@ -317,4 +317,4 @@\n Line 11\n+Added line 12\n+Added line 13\n \ndiff --git a/file b/file\nindex a0a225b..9f8c05f 100644\n--- a/file\n+++ b/file\n@@ -283,4 +283,4 @@\n +++\n-+++ Deleted line 112\n---- Deleted line 113\n ---\n"
  },
  {
    "path": "tests/dir-git/file",
    "content": "aaa\nuuu\n\nxxx\n"
  },
  {
    "path": "tests/dir-git/file1",
    "content": ""
  },
  {
    "path": "tests/dir-git/file3",
    "content": ""
  },
  {
    "path": "tests/dir-git/git-repo/.git-dir/COMMIT_EDITMSG",
    "content": "\n# This is a mock of Git template for its `GIT_EDITOR`\n"
  },
  {
    "path": "tests/dir-git/git-repo/.git-dir/HEAD",
    "content": "ref: refs/heads/tmp\n"
  },
  {
    "path": "tests/dir-git/git-repo/.git-dir/index",
    "content": ""
  },
  {
    "path": "tests/dir-git/git-repo/.git-dir/refs/heads/tmp",
    "content": "\n"
  },
  {
    "path": "tests/dir-git/git-repo/dir-in-git/file-in-dir-in-git",
    "content": "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n"
  },
  {
    "path": "tests/dir-git/git-repo/file-in-git",
    "content": "\n"
  },
  {
    "path": "tests/dir-git/git-repo/file-in-git_symlink-source",
    "content": ""
  },
  {
    "path": "tests/dir-git/help-output",
    "content": "\nGIT-PUSH(1)                        Git Manual                       GIT-PUSH(1)\n\nNAME\n       git-push - Update remote refs along with associated objects\n\nSYNOPSIS\n       git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]\n                  [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose]\n                  [-u | --set-upstream] [-o <string> | --push-option=<string>]\n                  [--[no-]signed|--signed=(true|false|if-asked)]\n                  [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]]\n                  [--no-verify] [<repository> [<refspec>...]]\n\nDESCRIPTION\n       A truncated output of `git help push` for testing purposes\n\nOPTIONS\n       <repository>\n           The \"remote\" repository. Should be parsed as option.\n\n       <refspec>...\n           Specify what destination ref to update with what source object.\n           Some other very important information.\n\n       --all, --branches\n           Push all branches (i.e. refs under refs/heads/); cannot be used with\n           other <refspec>.\n\n       --prune\n           Remove remote branches that don’t have a local counterpart.\n\n           This line contains --do-not-parse flag which should not be parsed.\n\n           --another-no-parse\n\n       -n, --dry-run\n           Do everything except actually send the updates.\n\n       -vv\n           A single dash flag but with two letters afterwards.\n\n       --[no-]signed, --signed=(true|false|if-asked)\n           This is some hard to parse options.\n           Should prefer '--signed' over '--signed='.\n\n       --receive-pack=<git-receive-pack>, --exec=<git-receive-pack>\n           Another hard to parse.\n\n       --[no-]force-with-lease, --force-with-lease=<refname>,\n       --force-with-lease=<refname>:<expect>\n           An entry which documents same flag several times.\n\n       -4, --ipv4\n           Use IPv4 addresses only, ignoring IPv6 addresses.\n\n       -6, --ipv6\n           Use IPv6 addresses only, ignoring IPv4 addresses.\n\nNEW SECTION\n       --not-an-option\n           Although formatted as an option, it is not in an appropriate section.\n"
  },
  {
    "path": "tests/dir-git/log-output",
    "content": "commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2\nAuthor: Neo McVim <neo.mcvim@gmail.com>\nDate:   Sat May 4 16:24:15 2024 +0300\n\n    Commit 1\n    \n    Important details about commit.\n    Even more details about commit.\n\ndiff --git a/dir/file-before b/dir/file-after\nindex dd2b945..b81ef66 100644\n--- a/dir/file-before\n+++ b/dir/file-after\n@@ -1,3 +1,3 @@ Hunk header 1\n       Line 1\n-      Previous line 2\n+      Current line 2\n     Line 3\n@@ -317,4 +317,4 @@\n Line 11\n+Added line 12\n+Added line 13\n \ndiff --git a/file b/file\nindex a0a225b..9f8c05f 100644\n--- a/file\n+++ b/file\n@@ -283,4 +283,4 @@\n +++\n-+++ Deleted line 112\n---- Deleted line 113\n ---\n\ncommit 7264474d3bda16d0098a7f89a4143fe4db3d82cf\nAuthor: Neo McVim <neo.mcvim@gmail.com>\nDate:   Sat May 4 16:20:29 2024 +0300\n\n    Commit 2\n\ndiff --git i/dir/file1 w/dir/file1\nindex dd2b945..b81ef66 100644\n--- i/dir/file1\n+++ w/dir/file1\n@@ -247 +247 @@ Hunk header 1\n-      Previous line 02\n+      Current line 02\n@@ -317,4 +317,4 @@\n Line 011\n+Added line 012\n+Added line 013\n \ndiff --git a/file.lua b/file.lua\nindex a0a225b..9f8c05f 100644\n--- a/file.lua\n+++ b/file.lua\n@@ -1,4 +1,4 @@\n +++\n-+++ local a = 'deleted'\n---- local b = 'lines'\n ---\n"
  },
  {
    "path": "tests/dir-git/mocks/spawn.lua",
    "content": "_G.process_log = {}\nlocal process_id = 1\nlocal new_process = function(pid)\n  local is_active, is_closing = true, false\n  return {\n    pid = pid,\n    close = function(_)\n      table.insert(_G.process_log, 'Process ' .. pid .. ' was closed.')\n      is_active, is_closing = false, true\n    end,\n    is_closing = function(_) return is_closing end,\n    is_active = function(_) return is_active end,\n  }\nend\n\n-- Define object containing the queue with mocking stdio data.\n-- Each element is an array of tables with the format:\n-- - Element 1 is stdio type. One of \"in\", \"out\", \"err\".\n-- - Element 2 is the feed of the pipe. Can be `nil`, `string`, `string[]`.\n_G.stdio_queue = {}\nlocal process_pipe_indexes = {}\nvim.loop.new_pipe = function()\n  local cur_process_id = process_id\n  local process_pipe_data = _G.stdio_queue[cur_process_id] or {}\n\n  process_pipe_indexes[cur_process_id] = (process_pipe_indexes[cur_process_id] or 0) + 1\n  local cur_pipe_data = process_pipe_data[process_pipe_indexes[cur_process_id]] or {}\n  local cur_io_field, cur_feed = cur_pipe_data[1], cur_pipe_data[2]\n\n  if type(cur_feed) ~= 'table' then cur_feed = { cur_feed } end\n\n  return {\n    read_start = function(_, callback)\n      for _, x in ipairs(cur_feed) do\n        if type(x) == 'table' then callback(x.err, nil) end\n        if type(x) == 'string' then callback(nil, x) end\n      end\n      callback(nil, nil)\n    end,\n    write = function(_, chars)\n      local msg = string.format('Stream %s for process %s wrote: %s', cur_io_field, cur_process_id, chars)\n      table.insert(_G.process_log, msg)\n    end,\n    shutdown = function()\n      local msg = string.format('Stream %s for process %s was shut down.', cur_io_field, cur_process_id)\n      table.insert(_G.process_log, msg)\n    end,\n    close = function()\n      table.insert(_G.process_log, string.format('Stream %s for process %s was closed.', cur_io_field, cur_process_id))\n    end,\n  }\nend\n\n-- Array of data to mock the process. Each element can be either `nil` or\n-- a table with the following fields:\n-- - <action> `(function|nil)` - callable to simulate job's side-effects.\n-- - <duration> `(number|nil)` - how long a process should take. Default: 0.\n-- - <exit_code> `(number|nil)` - exit code. Default: 0.\n_G.process_mock_data = {}\n_G.spawn_log = {}\nvim.loop.spawn = function(path, options, on_exit)\n  local options_without_callables = vim.deepcopy(options) or {}\n  options_without_callables.stdio = nil\n  table.insert(_G.spawn_log, { executable = path, options = options_without_callables })\n\n  local pid = process_id\n  process_id = process_id + 1\n\n  local mock_data = _G.process_mock_data[pid] or {}\n  if vim.is_callable(mock_data.action) then mock_data.action(path, options) end\n  vim.defer_fn(function() on_exit(mock_data.exit_code or 0) end, mock_data.duration or 0)\n\n  return new_process(pid), pid\nend\n"
  },
  {
    "path": "tests/dir-keymap/mock-plugins/blink.cmp/lua/blink/cmp/init.lua",
    "content": "return {\n  is_menu_visible = function()\n    table.insert(_G.log, 'blink.is_menu_visible')\n    return _G.blink_is_menu_visible_res\n  end,\n\n  get_selected_item = function()\n    table.insert(_G.log, 'blink.get_selected_item')\n    return _G.blink_get_selected_item_res\n  end,\n\n  select_next = function() table.insert(_G.log, 'blink.select_next') end,\n  select_prev = function() table.insert(_G.log, 'blink.select_prev') end,\n  accept = function() table.insert(_G.log, 'blink.accept') end,\n}\n"
  },
  {
    "path": "tests/dir-keymap/mock-plugins/luasnip/lua/luasnip/init.lua",
    "content": "return {\n  jumpable = function()\n    table.insert(_G.log, 'luasnip.jumpable')\n    return _G.luasnip_jumpable_res\n  end,\n\n  expandable = function()\n    table.insert(_G.log, 'luasnip.expandable')\n    return _G.luasnip_expandable_res\n  end,\n\n  jump = function(dir) table.insert(_G.log, 'luasnip.jump ' .. dir) end,\n  expand = function() table.insert(_G.log, 'luasnip.expand') end,\n}\n"
  },
  {
    "path": "tests/dir-keymap/mock-plugins/nvim-autopairs/lua/nvim-autopairs/init.lua",
    "content": "return {\n  autopairs_cr = function()\n    table.insert(_G.log, 'nvimautopairs.autopairs_cr')\n    -- Mock exactly how 'nvim-autopairs' works here\n    local res = '<C-G>u<CR><Cmd>normal!<Space>====<CR><Up><End><CR>'\n    return vim.api.nvim_replace_termcodes(res, true, true, true)\n  end,\n\n  autopairs_bs = function()\n    table.insert(_G.log, 'nvimautopairs.autopairs_bs')\n    -- Mock exactly how 'nvim-autopairs' works here\n    local res = '<C-G>U<BS><Del>'\n    return vim.api.nvim_replace_termcodes(res, true, true, true)\n  end,\n}\n"
  },
  {
    "path": "tests/dir-keymap/mock-plugins/nvim-cmp/lua/cmp/init.lua",
    "content": "return {\n  visible = function()\n    table.insert(_G.log, 'cmp.visible')\n    return _G.cmp_visible_res\n  end,\n\n  get_selected_entry = function()\n    table.insert(_G.log, 'cmp.get_selected_entry')\n    return _G.cmp_get_selected_entry_res\n  end,\n\n  select_next_item = function() table.insert(_G.log, 'cmp.select_next_item') end,\n  select_prev_item = function() table.insert(_G.log, 'cmp.select_prev_item') end,\n  confirm = function() table.insert(_G.log, 'cmp.confirm') end,\n}\n"
  },
  {
    "path": "tests/dir-keymap/tree-sitter-tests.lua",
    "content": "function f(aa, b)\n  return {\n    aa,\n    bb,\n  }\nend\n\nreturn { f = f }\n"
  },
  {
    "path": "tests/dir-map/lua/gitsigns.lua",
    "content": "local get_hunks = function()\n  local res = {}\n  local add = function(added, removed) table.insert(res, { added = added, removed = removed }) end\n\n  -- Typical use cases\n  -- First two lines should be \"add\"\n  add({ start = 1, count = 2 }, { start = 0, count = 0 })\n  -- Single line 4 should be \"delete\"\n  add({ start = 4, count = 0 }, { start = 5, count = 6 })\n  -- First two lines (7-8) should be \"change\", rest (9-12) - \"add\"\n  add({ start = 7, count = 6 }, { start = 7, count = 2 })\n\n  -- Out of bounds data\n  add({ start = 0, count = 0 }, { start = 1, count = 2 })\n  add({ start = 1000, count = 1 }, { start = 0, count = 0 })\n\n  return res\nend\n\nvim.cmd('hi GitSignsAdd guibg=green')\nvim.cmd('hi GitSignsChange guibg=gray')\nvim.cmd('hi GitSignsDelete guibg=red')\n\nreturn { get_hunks = get_hunks }\n"
  },
  {
    "path": "tests/dir-map/mock-diagnostic.lua",
    "content": "local severity = vim.diagnostic.severity\n\nvim.diagnostic.get = function()\n  local cur_buf_id = vim.api.nvim_get_current_buf()\n  local res = {}\n  local add = function(severity_level_name, lnum, end_lnum, col, end_col)\n    table.insert(res, {\n      bufnr = cur_buf_id,\n      lnum = lnum - 1,\n      end_lnum = end_lnum - 1,\n      col = col - 1,\n      end_col = end_col - 1,\n      severity = severity[severity_level_name],\n    })\n  end\n\n  -- Multiple entries on single line\n  add('HINT', 1, 1, 1, 4)\n  add('INFO', 1, 1, 2, 5)\n  add('WARN', 1, 1, 3, 6)\n  add('ERROR', 1, 1, 4, 7)\n\n  -- One per line entry\n  add('HINT', 4, 4, 1, 1)\n  add('INFO', 7, 7, 1, 1)\n  add('WARN', 10, 10, 1, 1)\n  add('ERROR', 13, 13, 1, 1)\n\n  -- Multiline entry\n  add('ERROR', 1, 5, 1, 1)\n\n  -- Out of bounds data\n  add('ERROR', 0, 0, 1, 1)\n  add('ERROR', 1000, 1000, 1, 1)\n\n  return res\nend\n"
  },
  {
    "path": "tests/dir-map/resolution_1x2",
    "content": "  a  aaa\n"
  },
  {
    "path": "tests/dir-map/resolution_2x1",
    "content": " a a\n  aa\n"
  },
  {
    "path": "tests/dir-map/resolution_2x2",
    "content": "  a  aaa  a  aaa  a  aaa  a  aaa\n        a a a a  a a a aaaaaaaaa\n"
  },
  {
    "path": "tests/dir-map/resolution_3x2",
    "content": "  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa\n        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa\n                                a a a a a a a a a a a a a a a a  a a a a a a a a a a a a a a a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
  },
  {
    "path": "tests/dir-map/resolution_4x2",
    "content": "  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa  a  aaa\n        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa        a a a a  a a a aaaaaaaaa\n                                a a a a a a a a a a a a a a a a  a a a a a a a a a a a a a a a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                                a a a a a a a a a a a a a a a a  a a a a a a a a a a a a a a a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                                a a a a a a a a a a a a a a a a  a a a a a a a a a a a a a a a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                                a a a a a a a a a a a a a a a a  a a a a a a a a a a a a a a a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n                                                                                                                                a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a  a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
  },
  {
    "path": "tests/dir-map/src-test-integration.lua",
    "content": "_G.n_test_integration_calls = 0\n\n_G.test_integration = function()\n  _G.n_test_integration_calls = _G.n_test_integration_calls + 1\n\n  -- Match lines which start with at least three whitespaces\n  local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true)\n  local res = {}\n  for i, l in ipairs(lines) do\n    if l:find('^%s%s%s') ~= nil then table.insert(res, { line = i, hl_group = 'Operator' }) end\n  end\n  return res\nend\n"
  },
  {
    "path": "tests/dir-misc/Makefile",
    "content": "# Dummy Makefile to test `MiniMisc.find_root()`\n"
  },
  {
    "path": "tests/dir-misc/aaa.lua",
    "content": "-- Dummy file to open inside `MiniMisc.find_root()` tests\n"
  },
  {
    "path": "tests/dir-misc/dir/lang.aaa",
    "content": ""
  },
  {
    "path": "tests/dir-misc/dir/subdir/lang.aaa",
    "content": ""
  },
  {
    "path": "tests/dir-misc/dir/subdir-2/lang.aaa",
    "content": ""
  },
  {
    "path": "tests/dir-misc/init-restore-cursor.lua",
    "content": "dofile('scripts/minimal_init.lua')\n\n-- Enable reading correct shada file\nvim.o.shadafile = 'tests/dir-misc/restore-cursor.shada'\n\n-- Set testable size\nvim.o.lines = 10\nvim.o.columns = 20\n\n-- Set up tested functionality based on test type\nlocal test_type = vim.env.RESTORE_CURSOR_TEST_TYPE\n\nif test_type == 'set-not-normal-buftype' then vim.cmd('au BufReadPost * set buftype=help') end\nif test_type == 'set-position' then vim.cmd('au BufReadPost * call cursor(4, 0)') end\nif test_type == 'make-folds' then vim.cmd('au BufReadPost * 2,3 fold | 9,10 fold') end\n\nlocal opts = {}\nif test_type == 'not-center' then opts = { center = false } end\nif test_type == 'ignore-lua' then opts = { ignore_filetype = { 'lua' } } end\n\nrequire('mini.misc').setup_restore_cursor(opts)\n"
  },
  {
    "path": "tests/dir-misc/lang.aaa",
    "content": ""
  },
  {
    "path": "tests/dir-misc/mocked-git-repo/bbb.lua",
    "content": "-- Dummy file to open inside `MiniMisc.find_root()` tests\n"
  },
  {
    "path": "tests/dir-misc/pack/bundle/opt/mocked-lang-plugin/ftdetect/aaa.lua",
    "content": "_G.lang_plugin_ftdetect = _G.lang_plugin_ftdetect or {}\ntable.insert(_G.lang_plugin_ftdetect, 'ftdetect/aaa.lua')\n\n-- Set filetype 'aaa.lang' for file named 'lang.aaa'\nvim.filetype.add({ filename = { ['lang.aaa'] = 'lang-aaa' } })\n"
  },
  {
    "path": "tests/dir-misc/pack/bundle/opt/mocked-lang-plugin/ftplugin/aaa.lua",
    "content": "_G.lang_plugin_ftplugin = _G.lang_plugin_ftplugin or {}\n_G.lang_plugin_ftplugin[tostring(vim.api.nvim_get_current_buf())] = true\n_G.lang_plugin_ftplugin['ftplugin/aaa.lua'] = (_G.lang_plugin_ftplugin['ftplugin/aaa.lua'] or 0) + 1\n"
  },
  {
    "path": "tests/dir-misc/pack/bundle/opt/mocked-lang-plugin/ftplugin/lang-aaa.lua",
    "content": "_G.lang_plugin_ftplugin = _G.lang_plugin_ftplugin or {}\n_G.lang_plugin_ftplugin[tostring(vim.api.nvim_get_current_buf())] = true\n_G.lang_plugin_ftplugin['ftplugin/lang-aaa.lua'] = (_G.lang_plugin_ftplugin['ftplugin/lang-aaa.lua'] or 0) + 1\n"
  },
  {
    "path": "tests/dir-misc/restore-cursor.lua",
    "content": "-- aaa\n-- aaa\n-- aaa\n-- aaa\n-- aaa\n-- aaa\n-- aaa\n-- aaa\n-- aaa\n-- aaa\n"
  },
  {
    "path": "tests/dir-pick/builtin-tests/dir1/file1-1",
    "content": "dir1/file1-1\n\naaa\nbbb\nccc\n"
  },
  {
    "path": "tests/dir-pick/builtin-tests/dir1/file1-2",
    "content": "dir1/file1-2\n\naaa\nbbb\nccc\n"
  },
  {
    "path": "tests/dir-pick/builtin-tests/dir2/file2-1",
    "content": "dir2/file2-1\n\naaa\nbbb\nccc\n"
  },
  {
    "path": "tests/dir-pick/builtin-tests/file",
    "content": "file\n\naaa\nbbb\nccc\n"
  },
  {
    "path": "tests/dir-pick/file",
    "content": "dir-pick/file\n"
  },
  {
    "path": "tests/dir-pick/lua/nvim-web-devicons.lua",
    "content": "vim.cmd('hi DevIconLicense guifg=#111111')\nvim.cmd('hi DevIconMakefile guifg=#222222')\nvim.cmd('hi DevIconGif guifg=#333333')\nvim.cmd('hi DevIconLua guifg=#444444')\nvim.cmd('hi DevIconTxt guifg=#555555')\nvim.cmd('hi DevIconDefault guifg=#666666')\n\nreturn {\n  get_icon = function(filename, _, options)\n    if filename == 'LICENSE' then return '', 'DevIconLicense' end\n    if filename == 'Makefile' then return '', 'DevIconMakefile' end\n    if vim.endswith(filename, 'gif') then return '', 'DevIconGif' end\n    if vim.endswith(filename, 'lua') then return '', 'DevIconLua' end\n    if vim.endswith(filename, 'txt') then return '', 'DevIconTxt' end\n    if (options or {}).default then return '', 'DevIconDefault' end\n  end,\n}\n"
  },
  {
    "path": "tests/dir-pick/mocks/spawn.lua",
    "content": "_G.process_log = {}\n\nlocal n_pid, n_stdout = 0, 0\nlocal new_process = function(pid)\n  return {\n    pid = pid,\n\n    _is_active_indicator = true,\n    is_active = function(process) return process._is_active_indicator end,\n    kill = function(process)\n      process._is_active_indicator = false\n      table.insert(_G.process_log, 'Process ' .. pid .. ' was killed.')\n    end,\n\n    _is_closing_indicator = false,\n    is_closing = function(process) return process._is_closing_indicator end,\n    close = function(process)\n      process._is_closing_indicator = true\n      table.insert(_G.process_log, 'Process ' .. pid .. ' was closed.')\n    end,\n  }\nend\n\n-- Mock `stdout` by using global `_G.stdout_data_feed` array as source.\n-- Each feed's element should be either string (for usable data) or a table\n-- with `err` field (for error).\nvim.loop.new_pipe = function()\n  n_stdout = n_stdout + 1\n  local cur_stdout_id = 'Stdout_' .. n_stdout\n\n  return {\n    _is_active_indicator = true,\n    is_active = function(stream) return stream._is_active_indicator end,\n    read_start = function(stream, callback)\n      -- It is not possible in Neovim<0.10 to execute `vim.fn` functions during\n      -- `pipe:read_start()`\n      local vim_fn_orig = vim.deepcopy(vim.fn)\n      vim.fn = setmetatable({}, { __index = function() error('Can not use `vim.fn` during `read_start`.') end })\n\n      -- A stream/pipe is active if it is actually reading data at the moment\n      stream._is_active_indicator = true\n      for _, x in ipairs(_G.stdout_data_feed or {}) do\n        if type(x) == 'table' then callback(x.err, nil) end\n        if type(x) == 'string' then callback(nil, x) end\n      end\n\n      table.insert(_G.process_log, 'Stdout ' .. cur_stdout_id .. ' finished reading.')\n      stream._is_active_indicator = false\n      callback(nil, nil)\n\n      vim.fn = vim_fn_orig\n    end,\n    read_stop = function(stream)\n      stream._is_active_indicator = false\n      table.insert(_G.process_log, 'Stdout ' .. cur_stdout_id .. ' was stopped.')\n    end,\n\n    _is_closing_indicator = false,\n    is_closing = function(stream) return stream._is_closing_indicator end,\n    close = function(stream)\n      stream._is_closing_indicator = true\n      table.insert(_G.process_log, 'Stdout ' .. cur_stdout_id .. ' was closed.')\n    end,\n  }\nend\n\n_G.spawn_log = {}\nvim.loop.spawn = function(path, options, on_exit)\n  local options_without_callables = vim.deepcopy(options)\n  options_without_callables.stdio = nil\n  table.insert(_G.spawn_log, { executable = path, options = options_without_callables })\n\n  vim.schedule(function() on_exit() end)\n\n  n_pid = n_pid + 1\n  local pid = 'Pid_' .. n_pid\n  return new_process(pid), pid\nend\n"
  },
  {
    "path": "tests/dir-pick/real-files/LICENSE",
    "content": "MIT (c)\n"
  },
  {
    "path": "tests/dir-pick/real-files/Makefile",
    "content": "VAR ?= 1\n\nall: test\n"
  },
  {
    "path": "tests/dir-pick/real-files/a.lua",
    "content": "local a = 1\nlocal t = {\n  x = math.max(1, 2),\n  y = math.min(1, 2),\n}\n"
  },
  {
    "path": "tests/dir-pick/real-files/b.txt",
    "content": "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10\nLine 11\nLine 12\nLine 13\nLine 14\nLine 15\nLine 16\nLine 17\nLine 18\nLine 19\nLine 20\nLine 21\nLine 22\nLine 23\nLine 24\nLine 25\nLine 26\n"
  },
  {
    "path": "tests/dir-sessions/global/.session",
    "content": ""
  },
  {
    "path": "tests/dir-sessions/global/session1",
    "content": "lua _G.session_file = 'tests/dir-sessions/global/session1'\n"
  },
  {
    "path": "tests/dir-sessions/global/session2.vim",
    "content": "lua _G.session_file = 'tests/dir-sessions/global/session2.vim'\n"
  },
  {
    "path": "tests/dir-sessions/global/session3.lua",
    "content": "-- This will be sourced as Lua code (read `:h -S` and `:h source`)\n_G.session_file = 'tests/dir-sessions/global/session3.lua'\n"
  },
  {
    "path": "tests/dir-sessions/global/session_cd_global",
    "content": "lua _G.session_file = 'tests/dir-sessions/global/session_cd_global'\nlua vim.fn.chdir('../global') \n"
  },
  {
    "path": "tests/dir-sessions/global/session_cd_local",
    "content": "lua _G.session_file = 'tests/dir-sessions/global/session_cd_local'\nlua vim.fn.chdir('../local') \n"
  },
  {
    "path": "tests/dir-sessions/global/session_cd_local_2",
    "content": "lua _G.session_file = 'tests/dir-sessions/global/session_cd_local_2'\nlua vim.fn.chdir('../local-2') \n"
  },
  {
    "path": "tests/dir-sessions/init-files/autoread.lua",
    "content": "-- Avoid hit-enter-prompt\nvim.o.cmdheight = 10\n-- Avoid storing unnecessary data (also sometimes avoid hit-enter-prompt)\nvim.o.swapfile = false\n\nvim.cmd('set rtp+=.')\nrequire('mini.sessions').setup({ autoread = true, autowrite = false, directory = 'tests/dir-sessions/local' })\n"
  },
  {
    "path": "tests/dir-sessions/init-files/autowrite.lua",
    "content": "-- Avoid storing unnecessary data (also sometimes avoid hit-enter-prompt)\nvim.o.swapfile = false\n\nvim.cmd('set rtp+=.')\nrequire('mini.sessions').setup({ autowrite = true })\n"
  },
  {
    "path": "tests/dir-sessions/local/alternative-local-session",
    "content": "lua _G.session_file = 'tests/dir-sessions/local/alternative-local-session'\n"
  },
  {
    "path": "tests/dir-snippets/.styluaignore",
    "content": "bad-file-cant-execute.lua\n"
  },
  {
    "path": "tests/dir-snippets/bad-file-cant-decode.json",
    "content": "{ \"name\" = 1 \n"
  },
  {
    "path": "tests/dir-snippets/bad-file-cant-execute.lua",
    "content": "return {\n"
  },
  {
    "path": "tests/dir-snippets/bad-file-not-dict-object.json",
    "content": "1\n"
  },
  {
    "path": "tests/dir-snippets/bad-file-not-table-return.lua",
    "content": "return 1\n"
  },
  {
    "path": "tests/dir-snippets/file-array.code-snippets",
    "content": "[\n  {\n    \"prefix\": \"lua_a\",\n    \"body\": \"LUA_A=$1\",\n    \"desc\": \"Desc LUA_A\"\n  },\n  {\n    \"prefix\": \"lua_b\",\n    \"body\": \"LUA_B=$1\",\n    \"description\": \"Desc LUA_B\"\n  },\n  {\n    \"body\": \"LUA_C=$1\"\n  },\n  {\n    \"prefix\": \"d\",\n    \"body\": \"D1=$1\"\n  },\n  {\n    \"prefix\": \"d\",\n    \"desc\": \"Dupl2\"\n  },\n\n  {\n    \"prefix\": 1,\n    \"desc\": \"Not snippet data #1\"\n  },\n  2\n]\n"
  },
  {
    "path": "tests/dir-snippets/file-array.json",
    "content": "[\n  {\n    \"prefix\": \"lua_a\",\n    \"body\": \"LUA_A=$1\",\n    \"desc\": \"Desc LUA_A\"\n  },\n  {\n    \"prefix\": \"lua_b\",\n    \"body\": \"LUA_B=$1\",\n    \"description\": \"Desc LUA_B\"\n  },\n  {\n    \"body\": \"LUA_C=$1\"\n  },\n  {\n    \"prefix\": \"d\",\n    \"body\": \"D1=$1\"\n  },\n  {\n    \"prefix\": \"d\",\n    \"desc\": \"Dupl2\"\n  },\n\n  {\n    \"prefix\": 1,\n    \"desc\": \"Not snippet data #1\"\n  },\n  2\n]\n"
  },
  {
    "path": "tests/dir-snippets/file-array.lua",
    "content": "return {\n  { prefix = 'lua_a', body = 'LUA_A=$1', desc = 'Desc LUA_A' },\n  { prefix = 'lua_b', body = 'LUA_B=$1', description = 'Desc LUA_B' },\n\n  { prefix = 1, desc = 'Not snippet data #1' },\n\n  { prefix = nil, body = 'LUA_C=$1' },\n  { prefix = 'd', body = 'D1=$1' },\n  { prefix = 'd', body = nil, desc = 'Dupl2' },\n\n  2,\n}\n"
  },
  {
    "path": "tests/dir-snippets/file-dict.code-snippets",
    "content": "{\n  \"name_a\": {\n    \"prefix\": \"lua_a\",\n    \"body\": \"LUA_A=$1\",\n    \"desc\": \"Desc LUA_A\"\n  },\n  \"name_b\": {\n    \"prefix\": \"lua_b\",\n    \"body\": \"LUA_B=$1\",\n    \"description\": \"Desc LUA_B\"\n  },\n  \"name_c\": {\n    \"body\": \"LUA_C=$1\"\n  },\n  \"dupl1\": {\n    \"prefix\": \"d\",\n    \"body\": \"D1=$1\"\n  },\n  \"dupl2\": {\n    \"prefix\": \"d\",\n    \"desc\": \"Dupl2\"\n  },\n\n  \"problem_1\": {\n    \"prefix\": 1,\n    \"desc\": \"Not snippet data #1\"\n  },\n  \"problem_2\": 2\n}\n"
  },
  {
    "path": "tests/dir-snippets/file-dict.json",
    "content": "{\n  \"name_a\": {\n    \"prefix\": \"lua_a\",\n    \"body\": \"LUA_A=$1\",\n    \"desc\": \"Desc LUA_A\"\n  },\n  \"name_b\": {\n    \"prefix\": \"lua_b\",\n    \"body\": \"LUA_B=$1\",\n    \"description\": \"Desc LUA_B\"\n  },\n  \"name_c\": {\n    \"body\": \"LUA_C=$1\"\n  },\n  \"dupl1\": {\n    \"prefix\": \"d\",\n    \"body\": \"D1=$1\"\n  },\n  \"dupl2\": {\n    \"prefix\": \"d\",\n    \"desc\": \"Dupl2\"\n  },\n\n  \"problem_1\": {\n    \"prefix\": 1,\n    \"desc\": \"Not snippet data #1\"\n  },\n  \"problem_2\": 2\n}\n"
  },
  {
    "path": "tests/dir-snippets/file-dict.lua",
    "content": "return {\n  name_a = { prefix = 'lua_a', body = 'LUA_A=$1', desc = 'Desc LUA_A' },\n  name_b = { prefix = 'lua_b', body = 'LUA_B=$1', description = 'Desc LUA_B' },\n  name_c = { prefix = nil, body = 'LUA_C=$1', desc = nil },\n  dupl1 = { prefix = 'd', body = 'D1=$1', desc = nil },\n  dupl2 = { prefix = 'd', body = nil, desc = 'Dupl2' },\n\n  problem_a = { prefix = 1, desc = 'Not snippet data #1' },\n  problem_b = 2,\n}\n"
  },
  {
    "path": "tests/dir-snippets/file-dynamic-snippets.lua",
    "content": "return {\n  function(context) return { prefix = 'dyn', body = 'Buf: ' .. context.buf_id, desc = 'Dynamic' } end,\n  -- Should also work with function returning (maybe nested) function\n  function(_)\n    return {\n      function(con) return { prefix = 'dynest', body = 'Buf (from nested): ' .. con.buf_id, desc = 'Dynamic nested' } end,\n    }\n  end,\n}\n"
  },
  {
    "path": "tests/dir-snippets/file.many.dots.lua",
    "content": "return { { prefix = 'a', body = 'A=$1' } }\n"
  },
  {
    "path": "tests/dir-snippets/file.notsupported",
    "content": "{\n  \"name\": {\n    \"prefix\": \"a\",\n    \"body\": \"A=$1\",\n  }\n}\n"
  },
  {
    "path": "tests/dir-snippets/snippets/lua.json",
    "content": "{ \"snippets/lua.json\": { \"prefix\": \"a\", \"body\": \"A=$1\" } }\n"
  },
  {
    "path": "tests/dir-snippets/snippets/lua.lua",
    "content": "return { ['snippets/lua.lua'] = { prefix = 'b', body = 'B=$1' } }\n"
  },
  {
    "path": "tests/dir-snippets/snippets/nested/lua.json",
    "content": "{ \"snippets/nested/lua.json\": { \"prefix\": \"g\", \"body\": \"G=$1\" } }\n"
  },
  {
    "path": "tests/dir-snippets/snippets/nested/lua.lua",
    "content": "return { ['snippets/nested/lua.lua'] = { prefix = 'h', body = 'H=$1' } }\n"
  },
  {
    "path": "tests/dir-snippets/subdir/snippets/lua/deeper/another.json",
    "content": "{ \"subdir/snippets/lua/deeper/another.json\": { \"prefix\": \"f\", \"body\": \"F=$1\" } }\n"
  },
  {
    "path": "tests/dir-snippets/subdir/snippets/lua/file.json",
    "content": "{ \"subdir/snippets/lua/file.json\": { \"prefix\": \"e\", \"body\": \"E=$1\" } }\n"
  },
  {
    "path": "tests/dir-snippets/subdir/snippets/lua/snips.lua",
    "content": "return { ['subdir/snippets/lua/snips.lua'] = { prefix = 'd', body = 'D=$1' } }\n"
  },
  {
    "path": "tests/dir-snippets/subdir/snippets/lua.code-snippets",
    "content": "{ \"subdir/snippets/lua.code-snippets\": { \"prefix\": \"e\", \"body\": \"E=$1\" } }\n"
  },
  {
    "path": "tests/dir-snippets/subdir/snippets/lua.json",
    "content": "{ \"subdir/snippets/lua.json\": { \"prefix\": \"c\", \"body\": \"C=$1\" } }\n"
  },
  {
    "path": "tests/dir-starter/dir/file1",
    "content": ""
  },
  {
    "path": "tests/dir-starter/dir/file3",
    "content": ""
  },
  {
    "path": "tests/dir-starter/dir/subdir/file2",
    "content": ""
  },
  {
    "path": "tests/dir-starter/directory/file",
    "content": ""
  },
  {
    "path": "tests/dir-starter/init-files/test-init.lua",
    "content": "-- Avoid hit-enter-prompt\nvim.o.cmdheight = 2\n-- Avoid storing unnecessary data (also sometimes avoid hit-enter-prompt)\nvim.o.swapfile = false\n\nvim.cmd('set rtp+=.')\n_G.n_event = 0\nvim.cmd('autocmd User MiniStarterOpened lua _G.n_event = _G.n_event + 1')\nrequire('mini.starter').setup({ autoopen = true })\n"
  },
  {
    "path": "tests/dir-starter/sessions/session_global.lua",
    "content": ""
  },
  {
    "path": "tests/dir-statusline/lua/nvim-web-devicons.lua",
    "content": "return {\n  get_icon = function(filename, extension, options)\n    if filename == 'LICENSE' then return '', 'DevIconLicense' end\n    if vim.endswith(filename, 'lua') then return '', 'DevIconLua' end\n    if vim.endswith(filename, 'txt') then return '', 'DevIconTxt' end\n    if (options or {}).default then return '', 'DevIconDefault' end\n  end,\n}\n"
  },
  {
    "path": "tests/dir-statusline/mock-diagnostics.lua",
    "content": "vim.diagnostic.get = function(_, _)\n  local s = vim.diagnostic.severity\n  return {\n    { severity = s.ERROR },\n    { severity = s.WARN },\n    { severity = s.INFO },\n    { severity = s.HINT },\n    { severity = s.ERROR },\n    { severity = s.WARN },\n    { severity = s.INFO },\n    { severity = s.ERROR },\n    { severity = s.WARN },\n    { severity = s.ERROR },\n  }\nend\n\nif vim.fn.has('nvim-0.10') == 1 then\n  vim.diagnostic.count = function(_, _)\n    local s = vim.diagnostic.severity\n    return { [s.ERROR] = 4, [s.WARN] = 3, [s.INFO] = 2, [s.HINT] = 1 }\n  end\nend\n"
  },
  {
    "path": "tests/dir-surround/mock-nvim-treesitter/lua/nvim-treesitter/init.lua",
    "content": ""
  },
  {
    "path": "tests/dir-surround/mock-nvim-treesitter/lua/nvim-treesitter/parsers.lua",
    "content": "local parser = {\n  for_each_tree = function(_, f)\n    local tree = { root = function(_) return {} end }\n    local lang_tree = { lang = function(_) return 'lua' end }\n    f(tree, lang_tree)\n  end,\n}\n\nlocal get_parser = function(_) return parser end\n\nreturn { get_parser = get_parser }\n"
  },
  {
    "path": "tests/dir-surround/mock-nvim-treesitter/lua/nvim-treesitter/query.lua",
    "content": "local new_match = function(range, id, metadata_range)\n  return {\n    -- Allow emulating tree-sitter directives that can compute range in query.\n    -- For example, like this 'after/query/lua/textobjects.scm':\n    -- ```\n    -- ; extends\n    -- ((table_constructor) @table.outer @table.inner (#offset! @table.inner 0 1 0 -1))\n    -- ```\n    metadata = metadata_range ~= nil and { range = metadata_range } or nil,\n    node = {\n      -- Track `id` for mocking query within node\n      _id = id,\n\n      -- Mock that it is a \"real\" TSNode\n      tree = function() end,\n\n      -- `node:range()` should return 0-based numbers (row1, col1, row2, col2)\n      -- for end-exclusive region\n      range = function(include_bytes)\n        if not include_bytes then return unpack(range) end\n        -- If `include_bytes` is `true`, then the output is\n        -- `row1-col1-byte1-row2-col2-byte2`\n        local start_byte = vim.fn.line2byte(range[1] + 1) + range[2]\n        local end_byte = vim.fn.line2byte(range[3] + 1) + range[4] - 1\n        return range[1], range[2], start_byte, range[3], range[4], end_byte\n      end,\n    },\n  }\nend\n\n-- Imitate matches from reference file 'tests/dir-ai/lua-file.lua'\n-- The 'function.outer' and 'function.inner' matches are \"real\"\n--stylua: ignore\nlocal matches = {\n  ['@function.outer'] = {\n     new_match({ 2, 0, 4,  3  }, 1),\n     new_match({ 3, 9, 3,  37 }, 2),\n     new_match({ 6, 6, 10, 3  }, 3),\n  },\n  ['@function.inner'] = {\n     new_match({ 3, 2,  3, 37 }, 4),\n     new_match({ 3, 20, 3, 33 }, 5),\n     new_match({ 6, 6, 10, 3  }, 6, { 7, 2,  9, 13 }),\n  },\n  ['@plugin_other.outer'] = {\n     new_match({ 0,  0, 0,  12 }, 7),\n     new_match({ 9,  2, 9,  8  }, 8),\n     new_match({ 12, 0, 12, 8  }, 9),\n  },\n  ['@plugin_other.inner'] = {\n     new_match({ 0,  6, 0,  12 }, 10),\n     new_match({ 12, 7, 12, 8  }, 11),\n  },\n}\n\nlocal node_match_ids = {\n  [1] = { 4, 5 },\n  [2] = { 5 },\n  [3] = { 6 },\n  [4] = {},\n  [5] = {},\n  [6] = {},\n  [7] = { 10 },\n  [8] = {},\n  [9] = { 11 },\n  [10] = {},\n  [11] = {},\n}\n\nlocal get_capture_matches_recursively = function(_, captures, _)\n  local res = {}\n  captures = type(captures) == 'string' and { captures } or captures\n  for _, cap in ipairs(captures) do\n    vim.list_extend(res, matches[cap])\n  end\n  return res\nend\n\nlocal get_capture_matches = function(_, capture, _, node, _)\n  local all_matches = matches[capture]\n  local valid_ids = node._id ~= nil and node_match_ids[node._id] or vim.tbl_keys(node_match_ids)\n  return vim.tbl_filter(function(m) return vim.tbl_contains(valid_ids, m.node._id) end, all_matches)\nend\n\nreturn { get_capture_matches_recursively = get_capture_matches_recursively, get_capture_matches = get_capture_matches }\n"
  },
  {
    "path": "tests/dir-tabline/bad%new.dir/aaa.lua",
    "content": ""
  },
  {
    "path": "tests/dir-tabline/dir1/aaa",
    "content": ""
  },
  {
    "path": "tests/dir-tabline/dir1/bad%new.file.lua",
    "content": ""
  },
  {
    "path": "tests/dir-tabline/dir1/dir_nested/aaa",
    "content": ""
  },
  {
    "path": "tests/dir-tabline/dir2/aaa",
    "content": ""
  },
  {
    "path": "tests/dir-tabline/dir2/dir_nested/aaa",
    "content": ""
  },
  {
    "path": "tests/dir-tabline/lua/nvim-web-devicons.lua",
    "content": "return {\n  get_icon = function(filename, extension, options)\n    _G.devicons_args = { filename = filename, extension = extension, options = options }\n\n    if filename == 'LICENSE' then return '', 'DevIconLicense' end\n    if vim.endswith(filename, 'lua') then return '', 'DevIconLua' end\n    if vim.endswith(filename, 'txt') then return '', 'DevIconTxt' end\n    if (options or {}).default then return '', 'DevIconDefault' end\n  end,\n}\n"
  },
  {
    "path": "tests/dir-test/init_stdout-reporter_works.lua",
    "content": "vim.cmd('set rtp+=.')\n\nrequire('mini.test').setup()\n\nlocal group_depth = tonumber(vim.env.TEST_GROUP_DEPTH)\n\nlocal quit_on_finish\nif vim.env.TEST_QUIT_ON_FINISH ~= nil then quit_on_finish = vim.env.TEST_QUIT_ON_FINISH == 'true' end\n\nlocal reporter = MiniTest.gen_reporter.stdout({\n  group_depth = group_depth,\n  quit_on_finish = quit_on_finish,\n})\n\nMiniTest.run_file('tests/dir-test/testref_reporters.lua', { execute = { reporter = reporter } })\n"
  },
  {
    "path": "tests/dir-test/intermediate-screenshot",
    "content": "-|---------|---------|\n1|This is a call to `r\n2|eference_screenshot(\n3|)` with manual path \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00000000000000000000\n2|00000000000000000000\n3|00000000000000000000\n4|11111111111111111111\n5|22222222222222222222\n"
  },
  {
    "path": "tests/dir-test/reference-screenshot",
    "content": "-|---------|--\n1|aaa         \n2|~           \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/dir-test/testref_case-helpers.lua",
    "content": "local T = MiniTest.new_set()\n\nlocal finally_with_error, finally_no_error = false, false\n\nT['finally() with error'] = function()\n  MiniTest.finally(function() finally_with_error = true end)\n  error()\nend\n\nT['finally() with error; check'] = function() MiniTest.expect.equality(finally_with_error, true) end\n\nT['finally() no error'] = function()\n  MiniTest.finally(function() finally_no_error = true end)\n  local res = true\n  return res\nend\n\nT['finally() no error; check'] = function() MiniTest.expect.equality(finally_no_error, true) end\n\n_G.finally_log = {}\nT['finally() can be called several times in same function'] = function()\n  MiniTest.finally(function() table.insert(_G.finally_log, 'one') end)\n  MiniTest.finally(function() table.insert(_G.finally_log, 'two') end)\nend\n\nT['skip(); no message'] = function()\n  MiniTest.skip()\n  error('This error should not take effect')\nend\n\nT['skip(); with message'] = function()\n  MiniTest.skip('This is a custom skip message')\n  error('This error should not take effect')\nend\n\nlocal skip_helper = function() MiniTest.skip('Skip from helper') end\nT['skip() can be called from helper'] = function() skip_helper() end\n\nT['skip() can be called in `pre_case` hooks'] = MiniTest.new_set({\n  hooks = { pre_case = function() MiniTest.skip('Should skip case') end },\n})\n\nT['skip() can be called in `pre_case` hooks']['skip one'] = function() error() end\nT['skip() can be called in `pre_case` hooks']['skip two'] = function() error() end\n\nT['skip() has no effect in not `pre_case` hooks'] = MiniTest.new_set({\n  hooks = {\n    pre_once = function() MiniTest.skip('pre_once') end,\n    post_csae = function() MiniTest.skip('post_csae') end,\n    post_once = function() MiniTest.skip('post_once') end,\n  },\n}, { ['skip() in other hooks'] = function() error() end })\n\nT['add_note()'] = MiniTest.new_set({\n  hooks = {\n    pre_once = function() MiniTest.add_note('pre_once') end,\n    pre_case = function() MiniTest.add_note('pre_case') end,\n    post_case = function() MiniTest.add_note('post_case') end,\n    post_once = function() MiniTest.add_note('post_once') end,\n  },\n}, { ['add_note() case'] = function() MiniTest.add_note('test case') end })\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_collect-busted.lua",
    "content": "local eq = MiniTest.expect.equality\n\ndescribe('describe()/it()', function()\n  describe('nested', function()\n    it('Case 1', function() end)\n    it('Case 2', function() end)\n  end)\n\n  it('Case 3', function() end)\nend)\n\ndescribe('setup()/teardown()', function()\n  local n = 0\n\n  describe('nested', function()\n    setup(function() n = n + 1 end)\n    it('setup() works', function() eq(n, 1) end)\n    teardown(function() n = n + 1 end)\n  end)\n\n  it('teardown() works', function() eq(n, 2) end)\nend)\n\ndescribe('before_each()/after_each()', function()\n  local n, m = 0, 0\n\n  before_each(function() n = n + 1 end)\n  after_each(function() m = m + 1 end)\n\n  describe('nested', function()\n    describe('nested 2', function()\n      it('work', function() eq({ n, m }, { 1, 0 }) end)\n    end)\n    it('work 2', function() eq({ n, m }, { 2, 1 }) end)\n    it('work 3', function() eq({ n, m }, { 3, 2 }) end)\n  end)\n\n  it('work 4', function() eq({ n, m }, { 4, 3 }) end)\nend)\n\ndescribe('MiniTest.skip()', function()\n  it('works', function() MiniTest.skip() end)\nend)\n\ndescribe('MiniTest.finally()', function()\n  local n = 0\n\n  it('no error', function()\n    MiniTest.finally(function() n = n + 1 end)\n    eq(n, 0)\n  end)\n\n  it('works with no error', function() eq(n, 1) end)\n\n  it('with error', function()\n    MiniTest.finally(function() n = n + 1 end)\n    error('Some error')\n  end)\n\n  it('works with error', function() eq(n, 2) end)\nend)\n"
  },
  {
    "path": "tests/dir-test/testref_custom-script.lua",
    "content": "_G.custom_script_result = 'This actually ran'\n\n-- Dummy call to `run()` to ensure there is no infinite loop\nMiniTest.run({\n  collect = {\n    find_files = function() return {} end,\n  },\n})\n\n-- Buffer local and global configs should be later restored\nMiniTest.config.aaa = true\nvim.b.minitest_config = { aaa = true }\n"
  },
  {
    "path": "tests/dir-test/testref_general.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal f = function() end\nlocal T = new_set({ hooks = { pre_once = f, pre_case = f, post_case = f, post_once = f } })\n\nT['case 1'] = function() error('Some error') end\nT['case 2'] = function() end\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_new-set.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal T = new_set()\n\n-- Collection order -----------------------------------------------------------\nT['order'] = new_set(nil, { ['From initial call'] = function() return 1 end })\n\nT['order']['zzz First added'] = function() end\nT['order']['aaa Second added'] = function() end\n\n-- Implicit additions should be also collected\ntable.insert(T['order'], function() end)\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_reporters.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal T = new_set()\n\n--stylua: ignore start\nT['first group'] = new_set()\nT['first group']['pass'] = function() end\nT['first group']['pass with notes'] = function() MiniTest.add_note('Passed note') end\nT['first group']['fail'] = function() error('Custom error', 0) end\nT['first group']['fail with notes'] = function()\n  MiniTest.add_note('Failed note')\n  error('Custom error after note', 0)\nend\n\nT['second group'] = new_set()\nT['second group']['pass'] = function() end\nT['second group']['pass with notes'] = function() MiniTest.add_note('Passed note #2') end\nT['second group']['fail'] = function() error('Custom error #2', 0) end\nT['second group']['fail with notes'] = function()\n  MiniTest.add_note('Failed note #2')\n  error('Custom error after note #2', 0)\nend\n\nT['third group with \\n in name'] = new_set()\nT['third group with \\n in name']['case with \\n in name'] = function() MiniTest.add_note('Passed note #3') end\n--stylua: ignore end\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run-data.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal T = new_set()\n\nT['data'] = new_set({ data = { a = 1, b = 2 } })\n\nT['data']['first level'] = function() end\n\nT['data']['nested'] = new_set({ data = { a = 10, c = 30 } })\n\nT['data']['nested']['should override'] = function() end\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run-hooks.lua",
    "content": "local new_set = MiniTest.new_set\n\n_G.log = {}\nlocal logging = function(msg)\n  return function() table.insert(_G.log, msg) end\nend\n\nlocal T = new_set()\n\n-- Track order of hook execution via adding to `_G.log`\nT['order'] = new_set({\n  hooks = {\n    pre_once = logging('pre_once_1'),\n    pre_case = logging('pre_case_1'),\n    post_case = logging('post_case_1'),\n    post_once = logging('post_once_1'),\n  },\n})\n\nT['order']['first level'] = logging('First level test')\n\nT['order']['nested'] = new_set({\n  hooks = {\n    pre_once = logging('pre_once_2'),\n    pre_case = logging('pre_case_2'),\n    post_case = logging('post_case_2'),\n    post_once = logging('post_once_2'),\n  },\n})\n\nT['order']['nested']['first'] = logging('Nested #1')\nT['order']['nested']['second'] = logging('Nested #2')\n\n-- Test that non-post-hooks are not executed if there is an error in pre hook\nlocal erroring = function(x)\n  return function() error(x, 0) end\nend\n\nT['skip_case_on_hook_error #1'] = new_set({\n  hooks = {\n    pre_once = erroring('pre_once_3'),\n    pre_case = logging('pre_case_3'),\n    post_case = logging('post_case_3'),\n    post_once = logging('post_once_3'),\n  },\n})\n\nT['skip_case_on_hook_error #1']['case'] = logging('Skipped Case #1')\n\nT['skip_case_on_hook_error #2'] = new_set({\n  hooks = {\n    pre_once = logging('pre_once_4'),\n    pre_case = erroring('pre_case_4'),\n    post_case = logging('post_case_4'),\n    post_once = logging('post_once_4'),\n  },\n})\n\nT['skip_case_on_hook_error #2']['case'] = logging('Skipped Case #2')\n\n-- Ensure that this will be called even if represented by the same function.\n-- Use this in several `_once` hooks and see that they all got executed.\nlocal f = logging('Same function')\nT['same `*_once` hooks'] = new_set({ hooks = { pre_once = f, post_once = f } })\nT['same `*_once` hooks']['nested'] = new_set({ hooks = { pre_once = f, post_once = f } })\nT['same `*_once` hooks']['nested']['test'] = logging('Same hook test')\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run-n_retry-stop_on_error.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal T = new_set()\n\n_G.log = {}\nlocal log = function(msg) table.insert(_G.log, msg) end\n\nlocal n1 = 0\nT['retries until first success'] = new_set({ n_retry = 10 }, {\n  test = function()\n    n1 = n1 + 1\n    log('try #' .. n1)\n    if n1 < 3 then error() end\n  end,\n})\n\nT['continues even if first tries were errors'] = function()\n  log('continue')\n  error()\nend\n\nT['should not reach here'] = function() log('not reach') end\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run-n_retry.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal T = new_set()\n\n_G.log = {}\nlocal log = function(msg) table.insert(_G.log, msg) end\nlocal logging = function(msg)\n  return function() log(msg) end\nend\nlocal erroring = function(msg)\n  return function()\n    log(msg)\n    error('Error: ' .. msg, 0)\n  end\nend\n\nT['n_retry defaults to 1'] = erroring('default')\n\nT['should override'] = new_set({ n_retry = 2 })\n\nT['should override']['case'] = erroring('should override')\n\nT['should override']['nested'] = new_set({ n_retry = 3 })\n\nT['should override']['nested']['case'] = erroring('more override')\n\nlocal n1 = 0\nT['retries until first success'] = new_set({ n_retry = 10 }, {\n  test = function()\n    n1 = n1 + 1\n    log('first success #' .. n1)\n    if n1 < 3 then error() end\n  end,\n})\n\nlocal n2 = 0\nT['reports latest error'] = new_set({ n_retry = 3 }, {\n  test = function()\n    n2 = n2 + 1\n    log('latest error #' .. n2)\n    error('Error #' .. n2, 0)\n  end,\n})\n\nT['does not retry hooks'] = new_set({\n  hooks = {\n    pre_once = erroring('no retry pre_once'),\n    pre_case = erroring('no retry pre_case'),\n    post_case = erroring('no retry post_case'),\n    post_once = erroring('no retry post_once'),\n  },\n  n_retry = 2,\n}, { test = logging('Should not be present because there were hook errors') })\n\nT['calls all `pre_case` and `post_case` hooks on case retry'] = new_set({\n  hooks = {\n    pre_once = logging('outer pre_once'),\n    pre_case = logging('outer pre_case'),\n    post_case = logging('outer post_case'),\n    post_once = logging('outer post_once'),\n  },\n  -- Should ignore this `n_retry` when executing hooks on retry of cases from\n  -- inner set with its own `n_retry`\n  n_retry = 10,\n})\n\nT['calls all `pre_case` and `post_case` hooks on case retry']['inner'] = new_set({\n  hooks = {\n    pre_once = logging('inner pre_once'),\n    pre_case = logging('inner pre_case'),\n    post_case = logging('inner post_case'),\n    post_once = logging('inner post_once'),\n  },\n  n_retry = 2,\n})\n\nT['calls all `pre_case` and `post_case` hooks on case retry']['inner']['case'] = erroring('hook exec case')\n\nT['screenshot number'] = new_set({ n_retry = 2 }, {\n  test = function()\n    -- Should compute default path with proper screeshot suffix\n    -- Basically a test that cached number of screenshots is reset before\n    -- *every* try and not only before first try\n    local child = MiniTest.new_child_neovim()\n    child.start()\n    child.o.lines, child.o.columns = 10, 15\n\n    log('screenshot')\n    MiniTest.expect.reference_screenshot(child.get_screenshot())\n    error('Expected error')\n  end,\n})\n\nT['does not retry skipping'] = new_set({ n_retry = 2 }, {\n  test = function()\n    log('skip')\n    MiniTest.skip()\n  end,\n})\n\nT['works for every parametrize entry'] = new_set({\n  parametrize = { { 1 }, { 2 } },\n  n_retry = 2,\n}, {\n  test = function(arg)\n    log('parameter ' .. arg)\n    error()\n  end,\n})\n\nT['updates state on every retry'] = new_set({\n  hooks = {\n    pre_once = function() end,\n    pre_case = function() end,\n    post_case = function() end,\n    post_once = function() end,\n  },\n  n_retry = 2,\n}, { test = function() error() end })\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run-parametrize-error.lua",
    "content": "local T = MiniTest.new_set()\nT['parametrize'] = MiniTest.new_set({ parametrize = { 'a' } }, { test = function() end })\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run-parametrize.lua",
    "content": "local new_set = MiniTest.new_set\n\nlocal T = new_set()\n\nlocal error_vararg = function(...)\n  local args = vim.tbl_map(vim.inspect, { ... })\n  error('Passed arguments: ' .. table.concat(args, ', '))\nend\n\nT['parametrize'] = new_set({ parametrize = { { 'a' }, { 'b' } } })\n\n-- Should be parametrized with 'a' and 'b'\nT['parametrize']['first level'] = error_vararg\n\nT['parametrize']['nested'] = new_set({ parametrize = { { 1 }, { 2 } } })\n\n-- Should be parametrized with cartesian product of {'a', 'b'} and {1, 2}\nT['parametrize']['nested']['test'] = error_vararg\n\nT['multiple args'] = new_set({ parametrize = { { 'a', 'a' }, { 'b', 'b' } } })\n\nT['multiple args']['nested'] = new_set({ parametrize = { { 1, 1 }, { 2, 2 } } })\n\n-- Should be parametrized with cartesian product and each have 4 arguments\nT['multiple args']['nested']['test'] = error_vararg\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/testref_run.lua",
    "content": "local T = MiniTest.new_set()\n\nT['run_at_location()'] = function()\n  -- Should be the only one collected with `run_at_location()`\nend\n\nT['extra case'] = function() end\n\nreturn T\n"
  },
  {
    "path": "tests/dir-test/tests-test_test.lua---expect---reference_screenshot()---respects-`opts.directory`",
    "content": "-|---------|--\n1|opts.directo\n2|ry          \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/dir-test/tests-test_test.lua---expect---reference_screenshot()---respects-`opts.directory`-002",
    "content": "-|---------|--\n1|opts.directo\n2|ry          \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/dir-trailspace/file",
    "content": "aa  \n"
  },
  {
    "path": "tests/dir-visits/dir_1/file_1-1",
    "content": "File 1-1\n"
  },
  {
    "path": "tests/dir-visits/dir_1/file_1-2",
    "content": "File 1-2\n"
  },
  {
    "path": "tests/dir-visits/dir_1/file_1-3",
    "content": "File 1-3\n"
  },
  {
    "path": "tests/dir-visits/dir_1/subdir/file_1-1-1",
    "content": "File 1-1-1\n"
  },
  {
    "path": "tests/dir-visits/dir_2/file_2-1",
    "content": "File 2-1\n"
  },
  {
    "path": "tests/dir-visits/file",
    "content": "File\n"
  },
  {
    "path": "tests/helpers.lua",
    "content": "local Helpers = {}\n\n-- Add extra expectations\nHelpers.expect = vim.deepcopy(MiniTest.expect)\n\nHelpers.expect.match = MiniTest.new_expectation(\n  'string matching',\n  function(str, pattern) return str:find(pattern) ~= nil end,\n  function(str, pattern) return string.format('Pattern: %s\\nObserved string: %s', vim.inspect(pattern), str) end\n)\n\nHelpers.expect.no_match = MiniTest.new_expectation(\n  'no string matching',\n  function(str, pattern) return str:find(pattern) == nil end,\n  function(str, pattern) return string.format('Pattern: %s\\nObserved string: %s', vim.inspect(pattern), str) end\n)\n\nHelpers.expect.equality_approx = MiniTest.new_expectation(\n  'approximate equality',\n  function(x, y, tol)\n    if type(x) ~= type(y) then return false end\n    if type(x) == 'number' then return math.abs(x - y) <= tol end\n    if type(x) ~= 'table' then return vim.deep_equal(x, y) end\n\n    local x_keys, y_keys = vim.tbl_keys(x), vim.tbl_keys(y)\n    table.sort(x_keys)\n    table.sort(y_keys)\n    if not vim.deep_equal(x_keys, y_keys) then return false end\n    for _, key in ipairs(x_keys) do\n      if math.abs(x[key] - y[key]) > tol then return false end\n    end\n\n    return true\n  end,\n  function(x, y, tol) return string.format('Left: %s\\nRight: %s\\nTolerance: %s', vim.inspect(x), vim.inspect(y), tol) end\n)\n\nHelpers.make_partial_tbl = function(tbl, ref)\n  local res = {}\n  for k, v in pairs(ref) do\n    res[k] = (type(tbl[k]) == 'table' and type(v) == 'table') and Helpers.make_partial_tbl(tbl[k], v) or tbl[k]\n  end\n  for i = 1, #tbl do\n    if ref[i] == nil then res[i] = tbl[i] end\n  end\n  return res\nend\n\nHelpers.expect.equality_partial_tbl = MiniTest.new_expectation(\n  'equality of tables only in reference fields',\n  function(x, y)\n    if type(x) == 'table' and type(y) == 'table' then x = Helpers.make_partial_tbl(x, y, {}) end\n    return vim.deep_equal(x, y)\n  end,\n  function(x, y)\n    return string.format('Left: %s\\nRight: %s', vim.inspect(Helpers.make_partial_tbl(x, y, {})), vim.inspect(y))\n  end\n)\n\n-- Monkey-patch `MiniTest.new_child_neovim` with helpful wrappers\nHelpers.new_child_neovim = function()\n  local child = MiniTest.new_child_neovim()\n\n  local prevent_hanging = function(method)\n    if not child.is_blocked() then return end\n\n    local msg = string.format('Can not use `child.%s` because child process is blocked.', method)\n    error(msg)\n  end\n\n  child.setup = function()\n    child.restart({ '-u', 'scripts/minimal_init.lua' })\n\n    -- Change initial buffer to be readonly. This not only increases execution\n    -- speed, but more closely resembles manually opened Neovim.\n    child.bo.readonly = false\n  end\n\n  child.set_lines = function(arr, start, finish)\n    prevent_hanging('set_lines')\n\n    if type(arr) == 'string' then arr = vim.split(arr, '\\n') end\n\n    child.api.nvim_buf_set_lines(0, start or 0, finish or -1, false, arr)\n  end\n\n  child.get_lines = function(start, finish)\n    prevent_hanging('get_lines')\n\n    return child.api.nvim_buf_get_lines(0, start or 0, finish or -1, false)\n  end\n\n  child.set_cursor = function(line, column, win_id)\n    prevent_hanging('set_cursor')\n\n    child.api.nvim_win_set_cursor(win_id or 0, { line, column })\n  end\n\n  child.get_cursor = function(win_id)\n    prevent_hanging('get_cursor')\n\n    return child.api.nvim_win_get_cursor(win_id or 0)\n  end\n\n  child.set_size = function(lines, columns)\n    prevent_hanging('set_size')\n\n    if type(lines) == 'number' then child.o.lines = lines end\n\n    if type(columns) == 'number' then child.o.columns = columns end\n  end\n\n  child.get_size = function()\n    prevent_hanging('get_size')\n\n    return { child.o.lines, child.o.columns }\n  end\n\n  --- Assert visual marks\n  ---\n  --- Useful to validate visual selection\n  ---\n  ---@param first number|table Table with start position or number to check linewise.\n  ---@param last number|table Table with finish position or number to check linewise.\n  ---@private\n  child.expect_visual_marks = function(first, last)\n    child.ensure_normal_mode()\n\n    first = type(first) == 'number' and { first, 0 } or first\n    last = type(last) == 'number' and { last, 2147483647 } or last\n\n    MiniTest.expect.equality(child.api.nvim_buf_get_mark(0, '<'), first)\n    MiniTest.expect.equality(child.api.nvim_buf_get_mark(0, '>'), last)\n  end\n\n  -- Work with 'mini.nvim':\n  -- - `mini_load` - load with \"normal\" table config\n  -- - `mini_load_strconfig` - load with \"string\" config, which is still a\n  --   table but with string values. Final loading is done by constructing\n  --   final string table. Needed to be used if one of the config entries is a\n  --   function (as currently there is no way to communicate a function object\n  --   through RPC).\n  -- - `mini_unload` - unload module and revert common side effects.\n  child.mini_load = function(name, config)\n    local lua_cmd = ([[require('mini.%s').setup(...)]]):format(name)\n    child.lua(lua_cmd, { config })\n  end\n\n  child.mini_load_strconfig = function(name, strconfig)\n    local t = {}\n    for key, val in pairs(strconfig) do\n      table.insert(t, key .. ' = ' .. val)\n    end\n    local str = string.format('{ %s }', table.concat(t, ', '))\n\n    local command = ([[require('mini.%s').setup(%s)]]):format(name, str)\n    child.lua(command)\n  end\n\n  child.mini_unload = function(name)\n    local module_name = 'mini.' .. name\n    local tbl_name = 'Mini' .. name:sub(1, 1):upper() .. name:sub(2)\n\n    -- Unload Lua module\n    child.lua(([[package.loaded['%s'] = nil]]):format(module_name))\n\n    -- Remove global table\n    child.lua(('_G[\"%s\"] = nil'):format(tbl_name))\n\n    -- Remove autocmd group\n    if child.fn.exists('#' .. tbl_name) == 1 then child.api.nvim_del_augroup_by_name(tbl_name) end\n  end\n\n  child.expect_screenshot = function(opts, path)\n    opts = opts or {}\n    local screenshot_opts = { redraw = opts.redraw }\n    opts.redraw = nil\n    MiniTest.expect.reference_screenshot(child.get_screenshot(screenshot_opts), path, opts)\n  end\n\n  -- Poke child's event loop to make it up to date\n  child.poke_eventloop = function() child.api.nvim_eval('1') end\n\n  return child\nend\n\n-- Detect CI\nHelpers.is_ci = function() return os.getenv('CI') ~= nil end\nHelpers.skip_in_ci = function(msg)\n  if Helpers.is_ci() then MiniTest.skip(msg or 'Does not test properly in CI') end\nend\n\n-- Detect OS\nHelpers.is_windows = function() return vim.fn.has('win32') == 1 end\nHelpers.skip_on_windows = function(msg)\n  if Helpers.is_windows() then MiniTest.skip(msg or 'Does not test properly on Windows') end\nend\n\nHelpers.is_macos = function() return vim.fn.has('mac') == 1 end\nHelpers.skip_on_macos = function(msg)\n  if Helpers.is_macos() then MiniTest.skip(msg or 'Does not test properly on MacOS') end\nend\n\nHelpers.is_linux = function() return vim.fn.has('linux') == 1 end\nHelpers.skip_on_linux = function(msg)\n  if Helpers.is_linux() then MiniTest.skip(msg or 'Does not test properly on Linux') end\nend\n\n-- Standardized way of dealing with time\nHelpers.is_slow = function() return Helpers.is_ci() and (Helpers.is_windows() or Helpers.is_macos()) end\nHelpers.skip_if_slow = function(msg)\n  if Helpers.is_slow() then MiniTest.skip(msg or 'Does not test properly in slow context') end\nend\n\nHelpers.get_time_const = function(delay)\n  local coef = 1\n  if Helpers.is_ci() then\n    if Helpers.is_linux() then coef = 2 end\n    if Helpers.is_windows() then coef = 5 end\n    if Helpers.is_macos() then coef = 15 end\n  end\n  return coef * delay\nend\n\nHelpers.sleep = function(ms, child, skip_slow)\n  if skip_slow then\n    Helpers.skip_if_slow('Skip because state checks after sleep are hard to make robust in slow context')\n  end\n  vim.loop.sleep(math.max(ms, 1))\n  if child ~= nil then child.poke_eventloop() end\nend\n\n-- Standardized way of setting number of retries\nHelpers.get_n_retry = function(n)\n  local coef = 1\n  if Helpers.is_ci() then\n    if Helpers.is_linux() then coef = 2 end\n    if Helpers.is_windows() then coef = 3 end\n    if Helpers.is_macos() then coef = 4 end\n  end\n  return coef * n\nend\n\nreturn Helpers\n"
  },
  {
    "path": "tests/mock-lsp/extra.lua",
    "content": "_G.lsp_requests = {}\n\nlocal capabilities = {\n  declarationProvider = true,\n  definitionProvider = true,\n  documentSymbolProvider = true,\n  implementationProvider = true,\n  referencesProvider = true,\n  typeDefinitionProvider = true,\n  workspaceSymbolProvider = true,\n}\n\nlocal new_location = function(uri, from_line, from_col, to_line, to_col)\n  return {\n    uri = uri,\n    range = { start = { line = from_line, character = from_col }, ['end'] = { line = to_line, character = to_col } },\n  }\nend\n\nlocal make_location_request = function(method)\n  return function(params)\n    table.insert(_G.lsp_requests, method)\n    return { new_location(params.textDocument.uri, 2, 15, 2, 16) }\n  end\nend\n\nlocal make_symbol_request = function(method)\n  return function(params)\n    table.insert(_G.lsp_requests, method)\n    _G.params = params\n    local symbol_kind = vim.lsp.protocol.SymbolKind\n    return {\n      {\n        name = 'a',\n        kind = symbol_kind.Number,\n        range = { start = { line = 0, character = 6 }, ['end'] = { line = 0, character = 11 } },\n        selectionRange = { start = { line = 0, character = 6 }, ['end'] = { line = 0, character = 7 } },\n      },\n      {\n        name = 't',\n        kind = symbol_kind.Object,\n        range = { start = { line = 1, character = 6 }, ['end'] = { line = 4, character = 1 } },\n        selectionRange = { start = { line = 1, character = 6 }, ['end'] = { line = 1, character = 7 } },\n        children = {\n          {\n            name = 'x',\n            kind = symbol_kind.Variable,\n            range = { start = { line = 2, character = 2 }, ['end'] = { line = 2, character = 20 } },\n            selectionRange = { start = { line = 2, character = 2 }, ['end'] = { line = 2, character = 3 } },\n          },\n          {\n            name = 'y',\n            kind = symbol_kind.Variable,\n            range = { start = { line = 3, character = 2 }, ['end'] = { line = 3, character = 20 } },\n            selectionRange = { start = { line = 3, character = 2 }, ['end'] = { line = 3, character = 3 } },\n          },\n        },\n      },\n    }\n  end\nend\n\nlocal requests = {\n  initialize = function(_) return { capabilities = capabilities } end,\n  shutdown = function(_) return nil end,\n\n  -- Location methods\n  ['textDocument/declaration'] = make_location_request('textDocument/declaration'),\n  ['textDocument/definition'] = make_location_request('textDocument/definition'),\n  ['textDocument/implementation'] = make_location_request('textDocument/implementation'),\n  ['textDocument/typeDefinition'] = make_location_request('textDocument/typeDefinition'),\n  ['textDocument/references'] = function(params)\n    table.insert(_G.lsp_requests, 'textDocument/references')\n    return {\n      new_location(params.textDocument.uri, 0, 6, 0, 7),\n      new_location(params.textDocument.uri, 2, 15, 2, 16),\n      new_location(params.textDocument.uri, 3, 15, 3, 16),\n    }\n  end,\n\n  -- Symbols methods\n  ['textDocument/documentSymbol'] = make_symbol_request('textDocument/documentSymbol'),\n  ['workspace/symbol'] = make_symbol_request('workspace/symbol'),\n}\n\nlocal cmd = function(dispatchers)\n  -- Adaptation of `MiniSnippets.start_lsp_server()` implementation\n  local is_closing, request_id = false, 0\n\n  return {\n    request = function(method, params, callback)\n      local method_impl = requests[method]\n      if method_impl ~= nil then callback(nil, method_impl(params)) end\n      request_id = request_id + 1\n      return true, request_id\n    end,\n    notify = function(method, params) return false end,\n    is_closing = function() return is_closing end,\n    terminate = function() is_closing = true end,\n  }\nend\n\n-- Start server and attach to current buffer\nreturn vim.lsp.start({ name = 'extra-lsp', cmd = cmd, root_dir = vim.fn.getcwd() })\n"
  },
  {
    "path": "tests/mock-lsp/fruits.lua",
    "content": "local resolve_provider = true\nif _G.mock_no_resolve then resolve_provider = false end\nlocal capabilities = { completionProvider = { resolveProvider = resolve_provider } }\n\nlocal requests = {\n  initialize = function(_) return { capabilities = capabilities } end,\n  shutdown = function(_) return nil end,\n\n  ['textDocument/completion'] = function(_)\n    return {\n      { label = 'Apple', insertText = 'Fruit Apple', documentation = 'Apple fruit' },\n      { label = 'Jackfruit', insertText = 'Fruit Jack' },\n    }\n  end,\n\n  ['completionItem/resolve'] = function(params)\n    _G.n_completionitem_resolve = (_G.n_completionitem_resolve or 0) + 1\n    params.documentation = { kind = 'markdown', value = params.label .. ' is a fruit' }\n    return params\n  end,\n}\n\nlocal cmd = function(dispatchers)\n  -- Adaptation of `MiniSnippets.start_lsp_server()` implementation\n  local is_closing, request_id = false, 0\n\n  return {\n    request = function(method, params, callback)\n      local method_impl = requests[method]\n      if method_impl ~= nil then callback(nil, method_impl(params)) end\n      request_id = request_id + 1\n      return true, request_id\n    end,\n    notify = function(method, params) return false end,\n    is_closing = function() return is_closing end,\n    terminate = function() is_closing = true end,\n  }\nend\n\n-- Start server and attach to current buffer\n_G.fruits_lsp_client_id = vim.lsp.start({ name = 'fruits-lsp', cmd = cmd, root_dir = vim.fn.getcwd() })\n"
  },
  {
    "path": "tests/mock-lsp/months.lua",
    "content": "_G.Months = {}\n\n--stylua: ignore start\nMonths.items = {\n  { name = 'January',   kind = 1 },\n  { name = 'February',  kind = 1 },\n  { name = 'March',     kind = 2 },\n  { name = 'April',     kind = 2 },\n  { name = 'May',       kind = 2 },\n  { name = 'June',      kind = 3 },\n  { name = 'July',      kind = 3 },\n  { name = 'August',    kind = 3 },\n  { name = 'September', kind = 4 },\n  { name = 'October',   kind = 4 },\n  { name = 'November',  kind = 4 },\n  { name = 'December',  kind = 1 },\n}\n\nlocal markdown_info = {\n  -- Should remove all blank lines from the top\n  '',\n  '  ',\n  '# Month #07',\n  -- Should collapse multiple blank lines into one\n  '',\n  ' ',\n  '\\t',\n  -- Should replace section separator with continuous one spanning window width\n  '---',\n  '',\n  -- Should conceal special characters and highlight\n  'This *is* __markdown__ text',\n  '',\n  ' ',\n  -- Should conceal code block characters *and* remove all blank lines before\n  -- and after code block (as those will be displayed as empty themselves)\n  '```lua',\n  'local a = 1',\n  '```',\n  -- Should remove all blank lines from the bottom\n  ' ',\n  '',\n  '\\t',\n  ' ',\n  '',\n}\n\nMonths.data = {\n  January   = { documentation = 'Month #01' },\n  February  = { documentation = 'a\\nb\\nc\\nd\\ne\\nf\\ng\\nh' },\n  March     = { documentation = 'Month #03' },\n  April     = { documentation = 'Month #04', detail = '\\n  local a = \"New info\"  \\n  \\n' },\n  May       = { documentation = nil },\n  June      = { documentation = 'Month #06' },\n  July      = { documentation = table.concat(markdown_info, '\\n') },\n  August    = { documentation = 'Month #08', detail = 'Month' },\n  September = { documentation = nil,         detail = 'Sep' },\n  October   = { documentation = 'Month #10' },\n  November  = { documentation = 'Month #11' },\n  December  = { documentation = string.rep('a ', 1000) },\n}\n--stylua: ignore end\n\nMonths.client = {\n  name = 'months-lsp',\n  offset_encoding = 'utf-16',\n  server_capabilities = {\n    completionProvider = { resolveProvider = true, triggerCharacters = { '.' } },\n    signatureHelpProvider = { triggerCharacters = { '(', ',' } },\n  },\n}\n\nlocal construct_additionTextEdits = function(id, name)\n  return {\n    {\n      newText = ('from months.%s import %s\\n'):format(id, name),\n      range = {\n        start = { line = 0, character = 0 },\n        ['end'] = { line = 0, character = 0 },\n      },\n    },\n  }\nend\n\nlocal construct_textEdit = function(name, kind)\n  if _G.mock_textEdit == nil then return end\n  local new_text, pos = _G.mock_textEdit.new_text, _G.mock_textEdit.pos\n  local is_insertreplaceedit = kind == 'InsertReplaceEdit'\n  local range = {\n    start = { line = pos[1] - 1, character = pos[2] - 1 },\n    ['end'] = { line = pos[1] - 1, character = pos[2] },\n  }\n  return {\n    newText = new_text(name),\n    [is_insertreplaceedit and 'insert' or 'range'] = range,\n    replace = is_insertreplaceedit and range or nil,\n  }\nend\n\nlocal construct_filterText = function(name)\n  if _G.mock_filterText == nil then return end\n  return _G.mock_filterText(name)\nend\n\n-- Log actual table params for testing proper requests\n_G.params_log = {}\n\nlocal requests = {\n  initialize = function(_) return { capabilities = Months.client.server_capabilities } end,\n  shutdown = function(_) return nil end,\n\n  ['textDocument/completion'] = function(params)\n    -- Count actual requests for easier \"force completion\" tests\n    _G.n_textdocument_completion = (_G.n_textdocument_completion or 0) + 1\n\n    params = type(params) == 'function' and params(Months.client, vim.api.nvim_get_current_buf()) or params\n    table.insert(_G.params_log, { method = 'textDocument/completion', params = vim.deepcopy(params) })\n\n    -- Imitate returning nothing in comments\n    local line = vim.fn.getline(params.position.line + 1)\n    if line:find('^%s*#') ~= nil then return { items = {} } end\n\n    local items = {}\n    for i, item in ipairs(Months.items) do\n      local res = { label = item.name, kind = item.kind, sortText = ('%03d'):format(i) }\n      -- Mock `additionalTextEdits` as in `pyright`\n      if item.name == 'September' or item.name == 'November' then\n        res.additionalTextEdits = construct_additionTextEdits('completion', item.name)\n      end\n\n      if item.name == 'April' then\n        res.textEdit = construct_textEdit(item.name, 'InsertReplaceEdit')\n        res.textEditText = _G.mock_itemdefaults ~= nil and 'New April' or nil\n        res.filterText = construct_filterText(item.name)\n      end\n      if item.name == 'August' then\n        res.textEdit = construct_textEdit(item.name, 'textEdit')\n        res.textEditText = _G.mock_itemdefaults ~= nil and 'New August' or nil\n        res.filterText = construct_filterText(item.name)\n      end\n\n      table.insert(items, res)\n    end\n\n    -- Mock incomplete computation\n    if _G.mock_isincomplete then items = vim.list_slice(items, 1, 6) end\n\n    return { items = items, isIncomplete = _G.mock_isincomplete, itemDefaults = _G.mock_itemdefaults }\n  end,\n\n  ['completionItem/resolve'] = function(params)\n    table.insert(_G.params_log, { method = 'completionItem/resolve', params = vim.deepcopy(params) })\n\n    -- Count actual requests for easier tests\n    _G.n_completionitem_resolve = (_G.n_completionitem_resolve or 0) + 1\n\n    local data = Months.data[params.label]\n    if data == nil then return params end\n\n    local doc = data.documentation\n    if doc ~= nil then params.documentation = { kind = 'markdown', value = doc } end\n    params.detail = data.detail\n\n    -- Mock additionalTextEdits as in `typescript-language-server`\n    if params.label == 'October' or params.label == 'November' then\n      params.additionalTextEdits = construct_additionTextEdits('resolve', params.label)\n    end\n\n    -- Mock resolving text to be inserted (which should usually not happen, but\n    -- it still might)\n    if params.label == 'May' then params.insertText = 'Resolved $1 May' end\n\n    return params\n  end,\n\n  ['textDocument/signatureHelp'] = function(params)\n    params = type(params) == 'function' and params(Months.client, vim.api.nvim_get_current_buf()) or params\n    table.insert(_G.params_log, { method = 'textDocument/completion', params = vim.deepcopy(params) })\n\n    local n_line, n_col = params.position.line, params.position.character\n    local line = vim.api.nvim_buf_get_lines(0, n_line, n_line + 1, false)[1]\n    line = line:sub(1, n_col)\n\n    local after_open_paren = line:match('%(.*$') or line\n    local after_close_paren = line:match('%).*$') or line\n\n    -- Stop showing signature help after closing bracket\n    if after_close_paren:len() < after_open_paren:len() then return { signatures = {} } end\n\n    -- Compute active parameter id by counting number of ',' from latest '('\n    local _, active_param_id = after_open_paren:gsub('%,', '%,')\n\n    -- Compute what is displayed in signature help: text and parameter info\n    -- (for highlighting) based on latest function call\n    local word = line:match('(%S+%()[^%(]*$')\n    local label, parameters\n    if word == 'long(' then\n      label = string.rep('a ', 1000)\n    elseif word == 'string.format(' then\n      label = 'function string.format(s:string|number, ...any)'\n    elseif word == 'multiline(' then\n      label = 'multiline(\\narg1,\\narg2)'\n      parameters = { { label = 'arg1' }, { label = 'arg2' } }\n    elseif word == 'bad_signature(' then\n      label = 'bad_signature(param1)'\n      parameters = { { label = 'not-substring' } }\n    elseif word == 'scroll(' then\n      label = 'aaa bbb ccc ddd eee fff ggg hhh'\n    elseif word == 'short(' then\n      label = line:match('^short%(aa,') and 'bbbbbbbbbbb' or 'aa'\n    else\n      label = 'abc(param1, param2)'\n      parameters = { { label = { 4, 10 } }, { label = { 12, 18 } } }\n    end\n\n    -- Construct output\n    local signature = { activeParameter = active_param_id, label = label, parameters = parameters }\n    return { signatures = { signature } }\n  end,\n}\n\n-- Start an actual LSP server -------------------------------------------------\n_G.lines_at_request = {}\n\nlocal cmd = function(dispatchers)\n  -- Adaptation of `MiniSnippets.start_lsp_server()` implementation\n  local is_closing, request_id = false, 0\n\n  return {\n    request = function(method, params, callback)\n      table.insert(_G.lines_at_request, vim.api.nvim_get_current_line())\n\n      -- Mock relevant methods with possible error\n      local err = (_G.mock_error or {})[method]\n      local method_impl = err ~= nil and function() return nil end or requests[method]\n      if method_impl and _G.mock_request_delay == nil then callback(err, method_impl(params)) end\n      if method_impl and _G.mock_request_delay ~= nil then\n        vim.defer_fn(function() callback(err, method_impl(params)) end, _G.mock_request_delay)\n      end\n\n      request_id = request_id + 1\n      return true, request_id\n    end,\n    notify = function(method, params)\n      if method == 'exit' then dispatchers.on_exit(0, 15) end\n      return false\n    end,\n    is_closing = function() return is_closing end,\n    terminate = function() is_closing = true end,\n  }\nend\n\n-- NOTE: set `root_dir` for a working `reuse_client` on Neovim<0.11\n_G.months_lsp_client_id = vim.lsp.start({ name = Months.client.name, cmd = cmd, root_dir = vim.fn.getcwd() })\n\nlocal gr = vim.api.nvim_create_augroup('months-lsp-auto-attach', { clear = true })\nlocal auto_attach = function(ev)\n  if not vim.api.nvim_buf_is_valid(ev.buf) then return end\n  vim.lsp.buf_attach_client(ev.buf, _G.months_lsp_client_id)\nend\nvim.api.nvim_create_autocmd('BufEnter', { group = gr, callback = auto_attach })\n"
  },
  {
    "path": "tests/mock-system/vim-system.lua",
    "content": "-- Queue of what `vim.system` should return as its `SystemObjCompleted`.\n-- Each call takes first entry and uses it. Entries can be:\n-- - Partial `SystemObjCompleted`, others inferred with custom defaults.\n--   Both `stdout` and `stderr` can be array of lines (instead of 'aa\\nbb').\n-- - `{ delay: integer, sys_out: SystemObjCompleted }` - more elaborate way\n--   to control the delay of each one.\n_G.system_queue = {}\n\n-- - `:h SystemObjCompleted`\n_G.sys_out_default = { code = 0, signal = 0, stdout = '', stderr = '' }\n_G.sys_out_terminated = { code = 0, signal = 0, stdout = '', stderr = '' }\n_G.delay_default = 0\n\n-- Log of how `vim.system()` is used\n_G.system_log = {}\n\nvim.system = function(cmd, opts, on_exit)\n  local data = _G.system_queue[1]\n  if data == nil then error('Can not mock `vim.system`: `_G.system_output_queue[1]` is nil') end\n  table.remove(_G.system_queue, 1)\n\n  table.insert(_G.system_log, { 'vim.system', { cmd = cmd, opts = opts } })\n\n  -- Prepare output object\n  if data.sys_out == nil then data = { sys_out = data } end\n  data = vim.tbl_deep_extend('force', { delay = _G.delay_default, sys_out = _G.sys_out_default }, data)\n  local stdout = data.sys_out.stdout\n  data.sys_out.stdout = type(stdout) == 'table' and table.concat(stdout, '\\n') or stdout\n\n  -- Schedule CLI exit\n  local has_exited = false\n  vim.defer_fn(function()\n    has_exited = true\n    if vim.is_callable(on_exit) then on_exit(data.sys_out) end\n  end, data.delay)\n\n  -- `:h SystemObj`\n  local res = {}\n  res.is_closing = function(_)\n    table.insert(_G.system_log, { 'is_closing' })\n    return has_exited\n  end\n  res.kill = function(_, ...) table.insert(_G.system_log, { 'kill', { ... } }) end\n  res.wait = function(_, timeout)\n    table.insert(_G.system_log, { 'wait', { timeout } })\n\n    vim.wait(timeout or 10000000, function() return has_exited end)\n    if has_exited then return data.sys_out end\n    res:kill(9)\n    return { code = 124, signal = 9, stdout = '', stderr = '' }\n  end\n  res.write = function(_, ...) table.insert(_G.system_log, { 'write', { ... } }) end\n\n  return res\nend\n"
  },
  {
    "path": "tests/mock-treesitter/lua-file.lua",
    "content": "local M = {}\n\nfunction M.a(u, vv, www)\n  return function() print(u .. vv) end\nend\n\nM.b = function()\n  local x = 1 + 1\n  print('1 + 1 = ' .. x)\n  return true\nend\n\nreturn M\n"
  },
  {
    "path": "tests/mock-treesitter/queries/lua/textobjects.scm",
    "content": "; Source: https://github.com/nvim-treesitter/nvim-treesitter-textobjects\n[ (function_declaration) (function_definition) ] @function.outer\n\n(function_declaration body: (_) @function.inner)\n(function_definition body: (_) @function.inner)\n\n; - Quantified captures (several captured nodes). Result range should cover\n;   from left most node start to right most node end.\n(parameters\n  .\n  (_) @parameter.inner @parameter.outer\n  .\n  \",\"? @parameter.outer)\n\n(parameters\n  \",\" @parameter.outer\n  .\n  (_) @parameter.inner @parameter.outer)\n\n; Custom\n[ (return_statement) ] @return.outer\n\n(return_statement (expression_list (_) @return.inner))\n\n(string) @string\n\n((string) @string_offset (#offset! @string_offset 0 1 0 -2))\n\n((chunk) @chunk.inner @chunk.outer (#offset! @chunk.inner 1 0 -1 0))\n"
  },
  {
    "path": "tests/screenshots/tests-dir-test-testref_run-n_retry.lua---screenshot-number---test",
    "content": "--|---------|-----\n01|               \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|< Name] 0,0-1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Builtin---User-prompt---colors-its-prompts",
    "content": "-|---------|---------|---------|---------|\n1|_aaa!                                   \n2|~                                       \n3|~                                       \n4|[No Name] 1,3                           \n5|(mini.ai) Left edge: _                  \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222\n5|3333333333333333333334444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Builtin---User-prompt---colors-its-prompts-002",
    "content": "-|---------|---------|---------|---------|\n1|_aaa!                                   \n2|~                                       \n3|~                                       \n4|[No Name] 1,3                           \n5|(mini.ai) Right edge: !                 \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222\n5|3333333333333333333333444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Builtin---User-prompt---colors-its-prompts-003",
    "content": "-|---------|---------|---------|---------|\n1|_aaa!                                   \n2|~                                       \n3|~                                       \n4|[No Name] 1,5                           \n5|                             5          \n\n-|---------|---------|---------|---------|\n1|0000111111111111111111111111111111111111\n2|2222222222222222222222222222222222222222\n3|2222222222222222222222222222222222222222\n4|3333333333333333333333333333333333333333\n5|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Textobject---respects-`config.silent`",
    "content": "-|---------|---------|---------|---------|\n1|(aaa)                                   \n2|~                                       \n3|~                                       \n4|[No Name] 1,2                           \n5|-- VISUAL --                            \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222\n5|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Textobject---shows-reminder-after-one-idle-second---test-+-args-{-'a'-}",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,2                                                         \n5|(mini.ai) Reminder to press `a` textobject id                         \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Textobject---shows-reminder-after-one-idle-second---test-+-args-{-'a'-}-002",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,5                                                         \n5|-- VISUAL --                                               5          \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0111022222222222222222222222222222222222222222222222222222222222222222\n2|3333333333333333333333333333333333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333333333333333333333333333333333\n4|4444444444444444444444444444444444444444444444444444444444444444444444\n5|5555555555556666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Textobject---shows-reminder-after-one-idle-second---test-+-args-{-'i'-}",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,2                                                         \n5|(mini.ai) Reminder to press `i` textobject id                         \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_ai.lua---Textobject---shows-reminder-after-one-idle-second---test-+-args-{-'i'-}-002",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,4                                                         \n5|-- VISUAL --                                               3          \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0110000000000000000000000000000000000000000000000000000000000000000000\n2|2222222222222222222222222222222222222222222222222222222222222222222222\n3|2222222222222222222222222222222222222222222222222222222222222222222222\n4|3333333333333333333333333333333333333333333333333333333333333333333333\n5|4444444444445555555555555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---cleans-command-line-only-if-state-was-shown",
    "content": "--|---------|---------|\n01|a _b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|[No Name] 1,1       \n12|My echo             \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|11111111111111111111\n11|22222222222222222222\n12|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---respects-`config.silent`",
    "content": "--|---------|---------|\n01|a_b                 \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|[No Name] 2,1       \n12|-- VISUAL2          \n\n--|---------|---------|\n01|00011111111111111111\n02|10001111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|22222222222222222222\n11|33333333333333333333\n12|44444444455555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---showing-state-does-not-cause-hit-enter-prompt",
    "content": "-|---------|---------|\n1|a_b                 \n2|aa_b                \n3|~                   \n4|[No Name] 1,1       \n5|(mini.align) Split: \n6|\"\" | Jus            \n\n-|---------|---------|\n1|00000000000000000000\n2|00000000000000000000\n3|11111111111111111111\n4|22222222222222222222\n5|33333333333334444444\n6|55666444555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Normal'-}",
    "content": "--|---------|---------|\n01|a_b                 \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 1,1       \n08|                    \n09|                    \n10|                    \n11|                    \n12|         g@Vip      \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|00000000000000000000\n09|00000000000000000000\n10|00000000000000000000\n11|00000000000000000000\n12|00000000033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Normal'-}-002",
    "content": "--|---------|---------|\n01|a_b                 \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 1,1       \n08|(mini.align) Select \n09|justify: left, cente\n10|r, right, none      \n11|                    \n12|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|33333333333334444444\n09|44444444456666656666\n10|66656666665666666666\n11|66666666666666666666\n12|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Normal'-}-003",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 1,1       \n08|(mini.align) Select \n09|justify: left, cente\n10|r, right, none      \n11|                    \n12|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|33333333333334444444\n09|44444444456666656666\n10|66656666665666666666\n11|66666666666666666666\n12|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Normal'-}-004",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 1,1       \n08|(mini.align) Split: \n09|\"\" | Justify: \"right\n10|\" | Merge: \"\" | Pres\n11|s modifier          \n12|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|33333333333334444444\n09|55666444444444555555\n10|56664444444556655555\n11|55555555555555555555\n12|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Normal'-}-005",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 1,1       \n08|(mini.align) Split: \n09|\"\" | Justify: \"cente\n10|r\" | Merge: \"\" | Pre\n11|ss modifier         \n12|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|33333333333334444444\n09|55666444444444555555\n10|55666444444455665555\n11|55555555555555555555\n12|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Normal'-}-006",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 1,1       \n08|                    \n09|                    \n10|                    \n11|                    \n12|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|33333333333333333333\n09|33333333333333333333\n10|33333333333333333333\n11|33333333333333333333\n12|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Visual'-}",
    "content": "--|---------|---------|\n01|a_b                 \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|                    \n09|                    \n10|                    \n11|                    \n12|-- VISUAL2          \n\n--|---------|---------|\n01|00011111111111111111\n02|10001111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|33333333333333333333\n08|11111111111111111111\n09|11111111111111111111\n10|11111111111111111111\n11|11111111111111111111\n12|44444444455555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Visual'-}-002",
    "content": "--|---------|---------|\n01|a_b                 \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|(mini.align) Select \n09|justify: left, cente\n10|r, right, none      \n11|                    \n12|                    \n\n--|---------|---------|\n01|00011111111111111111\n02|10001111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|33333333333333333333\n08|44444444444445555555\n09|55555555567777767777\n10|77767777776777777777\n11|77777777777777777777\n12|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Visual'-}-003",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|(mini.align) Select \n09|justify: left, cente\n10|r, right, none      \n11|                    \n12|-- VISUAL2          \n\n--|---------|---------|\n01|00001111111111111111\n02|10001111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|33333333333333333333\n08|44444444444445555555\n09|55555555567777767777\n10|77767777776777777777\n11|77777777777777777777\n12|55555555577777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Visual'-}-004",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|(mini.align) Split: \n09|\"\" | Justify: \"right\n10|\" | Merge: \"\" | Pres\n11|s modifier          \n12|                    \n\n--|---------|---------|\n01|00001111111111111111\n02|10001111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|33333333333333333333\n08|44444444444445555555\n09|66777555555555666666\n10|67775555555667766666\n11|66666666666666666666\n12|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Visual'-}-005",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|(mini.align) Split: \n09|\"\" | Justify: \"cente\n10|r\" | Merge: \"\" | Pre\n11|ss modifier         \n12|                    \n\n--|---------|---------|\n01|00001111111111111111\n02|10001111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|33333333333333333333\n08|44444444444445555555\n09|66777555555555666666\n10|66777555555566776666\n11|66666666666666666666\n12|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align---shows-state-after-one-idle-second---test-+-args-{-'Visual'-}-006",
    "content": "--|---------|---------|\n01| a_b                \n02|aa_b                \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|                    \n09|                    \n10|                    \n11|                    \n12|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22222222222222222222\n08|33333333333333333333\n09|33333333333333333333\n10|33333333333333333333\n11|33333333333333333333\n12|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-restores-visual-selection---test-+-args-{-'Visual-block'-}",
    "content": "--|---------|---------|---------|\n01|a  _b_c                       \n02|aaa_bbb_ccc                   \n03|                              \n04|previous selection            \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL BLOCK -- 2x5        \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555555666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-restores-visual-selection---test-+-args-{-'Visual-block'-}-002",
    "content": "--|---------|---------|---------|\n01|  a_b_c                       \n02|aaa_bbb_ccc                   \n03|                              \n04|previous selection            \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL BLOCK -- 2x5        \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555555666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-restores-visual-selection---test-+-args-{-'Visual-char'-}",
    "content": "--|---------|---------|---------|\n01|a  _b_c                       \n02|aaa_bbb_ccc                   \n03|                              \n04|previous selection            \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL --       2          \n\n--|---------|---------|---------|\n01|000000011111111111111111111111\n02|000011111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-restores-visual-selection---test-+-args-{-'Visual-char'-}-002",
    "content": "--|---------|---------|---------|\n01|  a_b_c                       \n02|aaa_bbb_ccc                   \n03|                              \n04|previous selection            \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL --       2          \n\n--|---------|---------|---------|\n01|000000011111111111111111111111\n02|000011111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-restores-visual-selection---test-+-args-{-'Visual-line'-}",
    "content": "--|---------|---------|---------|\n01|a  _b  _c                     \n02|aaa_bbb_ccc                   \n03|                              \n04|previous selection            \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000111111111111111111111\n02|100000000001111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-restores-visual-selection---test-+-args-{-'Visual-line'-}-002",
    "content": "--|---------|---------|---------|\n01|  a_  b_  c                   \n02|aaa_bbb_ccc                   \n03|                              \n04|previous selection            \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000001111111111111111111\n02|100000000001111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---correctly-shows-all-steps-in-status",
    "content": "--|---------|---------|---------|\n01|a _b                          \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: (sss1, sss\n09|2) \"_\" | Justify: (jjj1, jjj2)\n10| \"left\" | Merge: (mmm1, mmm2) \n11|\"\" | Press modifier           \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445555555555\n09|555555666444444444555555555555\n10|555555566644444445555555555555\n11|556655555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---respects-`config.silent`",
    "content": "--|---------|---------|\n01|a_b_c               \n02|aaa_bbb_ccc         \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|[No Name] 2,1       \n08|                    \n09|                    \n10|                    \n11|                    \n12|-- VISUAL2          \n\n--|---------|---------|\n01|00000111111111111111\n02|10000000000111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|33333333333333333333\n08|44444444444444444444\n09|44444444444444444444\n10|44444444444444444444\n11|44444444444444444444\n12|55555555544444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---uses-option-names-for-main-steps",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445566644444\n09|444455555566644444445566555555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-block'-}",
    "content": "--|---------|---------|---------|\n01|a_b_c                         \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445566644444\n09|444455555566644444445566555555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-block'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555556664444444556655555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-block'-}-003",
    "content": "--|---------|---------|---------|\n01|  a_b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555666444444455665555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-block'-}-004",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_c                    \n02|aaa-_bbb_ccc                  \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"-\" | Pr\n10|ess modifier                  \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555666444444455566555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-block'-}-005",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_c                    \n02|aaa-_bbb_ccc                  \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,2                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|444444444444333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-char'-}",
    "content": "--|---------|---------|---------|\n01|a_b_c                         \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445566644444\n09|444455555566644444445566555555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-char'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555556664444444556655555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-char'-}-003",
    "content": "--|---------|---------|---------|\n01|  a_b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555666444444455665555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-char'-}-004",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_-c                   \n02|aaa-_-bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"-\" | Pr\n10|ess modifier                  \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555666444444455566555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-char'-}-005",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_-c                   \n02|aaa-_-bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,2                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|444444444444333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-line'-}",
    "content": "--|---------|---------|---------|\n01|a_b_c                         \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445566644444\n09|444455555566644444445566555555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-line'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b  _c                     \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555556664444444556655555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-line'-}-003",
    "content": "--|---------|---------|---------|\n01|  a_  b_  c                   \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555666444444455665555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-line'-}-004",
    "content": "--|---------|---------|---------|\n01|  a-_-  b-_-  c               \n02|aaa-_-bbb-_-ccc               \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"-\" | Pr\n10|ess modifier                  \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555666444444455566555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Normal-line'-}-005",
    "content": "--|---------|---------|---------|\n01|  a-_-  b-_-  c               \n02|aaa-_-bbb-_-ccc               \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,2                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|444444444444333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-block'-}",
    "content": "--|---------|---------|---------|\n01|a_b_c                         \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL BLOCK -- 2x5        \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555555666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-block'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL BLOCK -- 2x5        \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555555666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-block'-}-003",
    "content": "--|---------|---------|---------|\n01|  a_b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL BLOCK -- 2x5        \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555555666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-block'-}-004",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_-c                   \n02|aaa-_-bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"-\" | Pr\n10|ess modifier                  \n11|                              \n12|-- VISUAL BLOCK -- 2x5        \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566677666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555555666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-block'-}-005",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_-c                   \n02|aaa-_-bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,6                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|444444444444333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-char'-}",
    "content": "--|---------|---------|---------|\n01|a_b_c                         \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL --       2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-char'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL --       2          \n\n--|---------|---------|---------|\n01|000000011111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-char'-}-003",
    "content": "--|---------|---------|---------|\n01|  a_b_c                       \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL --       2          \n\n--|---------|---------|---------|\n01|000000011111111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-char'-}-004",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_-c                   \n02|aaa-_-bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,5                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"-\" | Pr\n10|ess modifier                  \n11|                              \n12|-- VISUAL --       2          \n\n--|---------|---------|---------|\n01|000000000001111111111111111111\n02|000011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566677666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-char'-}-005",
    "content": "--|---------|---------|---------|\n01|  a-_-b-_-c                   \n02|aaa-_-bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,6                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|444444444444333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-line'-}",
    "content": "--|---------|---------|---------|\n01|a_b_c                         \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100000000001111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-line'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b  _c                     \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000111111111111111111111\n02|100000000001111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-line'-}-003",
    "content": "--|---------|---------|---------|\n01|  a_  b_  c                   \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000001111111111111111111\n02|100000000001111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-line'-}-004",
    "content": "--|---------|---------|---------|\n01|  a-_-  b-_-  c               \n02|aaa-_-bbb-_-ccc               \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"-\" | Pr\n10|ess modifier                  \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000000000111111111111111\n02|100000000000000111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566677666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Align-with-preview---works---test-+-args-{-'Visual-line'-}-005",
    "content": "--|---------|---------|---------|\n01|  a-_-  b-_-  c               \n02|aaa-_-bbb-_-ccc               \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,2                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|444444444444333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----does-nothing-if-no-pre-steps",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----does-nothing-if-no-pre-steps-002",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----prompts-to-choose-if-ambiguous",
    "content": "--|---------|---------|---------|\n01|a _b                          \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: (sss) \"_\" \n09|| Justify: (jjj) \"left\" | Merg\n10|e: (mmm) \"\" | Press modifier  \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445555555556\n09|664444444445555555555556664444\n10|444555555556655555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----prompts-to-choose-if-ambiguous-002",
    "content": "--|---------|---------|---------|\n01|a _b                          \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Select pre-step t\n09|o remove: split, justify, merg\n10|e                             \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444444444444444\n09|444444444456666665666666665666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----prompts-to-choose-if-ambiguous-003",
    "content": "--|---------|---------|---------|\n01|a _b                          \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: (jjj) \"left\" | Merge: (mm\n10|m) \"\" | Press modifier        \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555555555556664444444555\n10|555556655555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----prompts-to-choose-if-ambiguous-004",
    "content": "--|---------|---------|---------|\n01|a _b                          \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Select pre-step t\n09|o remove: split, justify, merg\n10|e                             \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444444444444444\n09|444444444456666665666666665666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----prompts-to-choose-if-ambiguous-005",
    "content": "--|---------|---------|---------|\n01|a _b                          \n02|aa_b                          \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: (mmm) \"\" \n10|| Press modifier              \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333344444445556664444\n09|444445555556664444444555555556\n10|655555555555555555555555555555\n11|555555555555555555555555555555\n12|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----works---test-+-args-{-'pre_justify'-}",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: (aaa) \"left\" | Merge: \"\" |\n10| Press modifier               \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666666666677755555556677\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----works---test-+-args-{-'pre_justify'-}-002",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----works---test-+-args-{-'pre_merge'-}",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: (aaa) \"\" |\n10| Press modifier               \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556666666677\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----works---test-+-args-{-'pre_merge'-}-002",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----works---test-+-args-{-'pre_split'-}",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: (aaa) \"\" |\n09| Justify: \"left\" | Merge: \"\" |\n10| Press modifier               \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556666666677\n09|755555555566666677755555556677\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----BS----works---test-+-args-{-'pre_split'-}-002",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----bar-",
    "content": "--|---------|---------|---------|\n01||a|b|                         \n02||aaa|bbb|                     \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100000000111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----bar--002",
    "content": "--|---------|---------|---------|\n01|| a   | b   |                 \n02|| aaa | bbb |                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"|\" | Just\n09|ify: (trim) \"left\" | Merge: \" \n10|\" | Press modifier            \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000000011111111111111111\n02|100000000000011111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666666666777555555566\n10|677666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----comma-",
    "content": "--|---------|---------|---------|\n01|a,b                           \n02|aaa,bbb                       \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100000011111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----comma--002",
    "content": "--|---------|---------|---------|\n01|a,   b                        \n02|aaa, bbb                      \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \",\" | Just\n09|ify: (trim, pair) \"left\" | Mer\n10|ge: \" \" | Press modifier      \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000111111111111111111111111\n02|100000001111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666666666666666777555\n10|555566677666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----equal-sign-",
    "content": "--|---------|---------|---------|\n01|a=b                           \n02|aaa=bbb                       \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100000011111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----equal-sign--002",
    "content": "--|---------|---------|---------|\n01|a   = b                       \n02|aaa = bbb                     \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"%p*=+[<>~\n09|]*\" | Justify: (trim) \"left\" |\n10| Merge: \" \" | Press modifier  \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000011111111111111111111111\n02|100000000111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556666666666\n09|666777555555555666666666666677\n10|755555556667766666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----space-bar-",
    "content": "--|---------|---------|---------|\n01|  a  b                        \n02|    aaa    bbb                \n03|a b                           \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 3,1                 \n08|(mini.align) Split: \"\" | Justi\n09|fy: \"left\" | Merge: \"\" | Press\n10| modifier                     \n11|                              \n12|-- VISUAL LINE --  3          \n\n--|---------|---------|---------|\n01|000000111111111111111111111111\n02|000000000000001111111111111111\n03|100111111111111111111111111111\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556677755555\n09|555566666677755555556677666666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers----space-bar--002",
    "content": "--|---------|---------|---------|\n01|     a   b                    \n02|     aaa bbb                  \n03|a    b                        \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 3,1                 \n08|(mini.align) Split: (squash) \"\n09|%s+\" | Justify: \"left\" | Merge\n10|: \"\" | Press modifier         \n11|                              \n12|-- VISUAL LINE --  3          \n\n--|---------|---------|---------|\n01|000000000011111111111111111111\n02|000000000000111111111111111111\n03|100000111111111111111111111111\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556666666666\n09|666677755555555566666677755555\n10|556677666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---f---allows-empty-input",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: (filter) \"left\" | Merge: \n10|\"\" | Press modifier           \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666666666667775555555\n10|667766666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---f---works",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aa_b                          \n03|aaa_b                         \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Enter filter expr\n09|ession:                       \n10|                              \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|000000000000000000000000000000\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333334444444444444444444444\n10|444444444444444444444444444444\n11|444444444444444444444444444444\n12|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---i---works",
    "content": "--|---------|---------|---------|\n01|# aaaaa=b                     \n02|\"aaaaa =b\"                    \n03|a      =b                     \n04|aa     =b                     \n05|~                             \n06|~                             \n07|[No Name] 4,1                 \n08|(mini.align) Split: \"=\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL LINE --  4          \n\n--|---------|---------|---------|\n01|000000000111111111111111111111\n02|000000000011111111111111111111\n03|000000000111111111111111111111\n04|100000000111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---i---works-002",
    "content": "--|---------|---------|---------|\n01|# aaaaa=b                     \n02|\"aaaaa=b\"                     \n03|a =b                          \n04|aa=b                          \n05|~                             \n06|~                             \n07|[No Name] 4,1                 \n08|(mini.align) Split: (ignore) \"\n09|=\" | Justify: \"left\" | Merge: \n10|\"\" | Press modifier           \n11|                              \n12|-- VISUAL LINE --  4          \n\n--|---------|---------|---------|\n01|000000000111111111111111111111\n02|000000000111111111111111111111\n03|000011111111111111111111111111\n04|100011111111111111111111111111\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556666666666\n09|667775555555556666667775555555\n10|667766666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'c'-}",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Select justify: l\n09|eft, center, right, none      \n10|                              \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555555555555556\n09|777776777777767777776777777777\n10|777777777777777777777777777777\n11|777777777777777777777777777777\n12|555555555555555557777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'c'-}-002",
    "content": "--|---------|---------|---------|\n01| a _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"center\" | Merge: \"\" | Pr\n10|ess modifier                  \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666677755555556677666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'l'-}",
    "content": "--|---------|---------|---------|\n01|  a_b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Select justify: l\n09|eft, center, right, none      \n10|                              \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555555555555556\n09|777776777777767777776777777777\n10|777777777777777777777777777777\n11|777777777777777777777777777777\n12|555555555555555557777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'l'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'n'-}",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Select justify: l\n09|eft, center, right, none      \n10|                              \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555555555555556\n09|777776777777767777776777777777\n10|777777777777777777777777777777\n11|777777777777777777777777777777\n12|555555555555555557777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'n'-}-002",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"none\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'r'-}",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Select justify: l\n09|eft, center, right, none      \n10|                              \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555555555555556\n09|777776777777767777776777777777\n10|777777777777777777777777777777\n11|777777777777777777777777777777\n12|555555555555555557777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'r'-}-002",
    "content": "--|---------|---------|---------|\n01|  a_b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"right\" | Merge: \"\" | Pre\n10|ss modifier                   \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666777555555566776666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'u'-}",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Select justify: l\n09|eft, center, right, none      \n10|                              \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555555555555556\n09|777776777777767777776777777777\n10|777777777777777777777777777777\n11|777777777777777777777777777777\n12|555555555555555557777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---j---works---test-+-args-{-'u'-}-002",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: \"left\" | Merge: \"\" | Pres\n10|s modifier                    \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000001111111111111111111111111\n02|100001111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666667775555555667766666\n10|666666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---m---works",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Enter merge delim\n09|iter:                         \n10|                              \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333444444444444444444444444\n10|444444444444444444444444444444\n11|444444444444444444444444444444\n12|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---m---works-002",
    "content": "--|---------|---------|---------|\n01|a  --_--b                     \n02|aaa--_--b                     \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---p---works",
    "content": "--|---------|---------|---------|\n01|a_  b_  c                     \n02|aaa_bbb_ccc                   \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: (pair) \"left\" | Merge: \"\"\n10| | Press modifier             \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000111111111111111111111\n02|100000000001111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666666666777555555566\n10|776666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---s---works",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|(mini.align) Enter split Lua p\n09|attern:                       \n10|                              \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333334444444444444444444444\n10|444444444444444444444444444444\n11|444444444444444444444444444444\n12|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---s---works-002",
    "content": "--|---------|---------|---------|\n01|a  _b                         \n02|aaa_b                         \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 1,1                 \n08|                              \n09|                              \n10|                              \n11|                              \n12|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|222222222222222222222222222222\n08|333333333333333333333333333333\n09|333333333333333333333333333333\n10|333333333333333333333333333333\n11|333333333333333333333333333333\n12|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_align.lua---Modifiers---t---works",
    "content": "--|---------|---------|---------|\n01| a   _b  _c                   \n02|  aaa_bbb_ccc                 \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|[No Name] 2,1                 \n08|(mini.align) Split: \"_\" | Just\n09|ify: (trim) \"left\" | Merge: \"\"\n10| | Press modifier             \n11|                              \n12|-- VISUAL LINE --  2          \n\n--|---------|---------|---------|\n01|000000000001111111111111111111\n02|100000000000011111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|222222222222222222222222222222\n06|222222222222222222222222222222\n07|333333333333333333333333333333\n08|444444444444455555556667775555\n09|555556666666666666777555555566\n10|776666666666666666666666666666\n11|666666666666666666666666666666\n12|555555555555555556666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---can-have-only-one-animation-active",
    "content": "-|---------|--\n1| aaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---can-have-only-one-animation-active-002",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2| aa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|100000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---can-have-only-one-animation-active-003",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5| aaaaaaaaa  \n6|~           \n7|< Name] 1,10\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|100000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---can-have-only-one-animation-active-004",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|a aaaaaaaa  \n6|~           \n7|< Name] 1,10\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|010000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---does-not-stop-if-mark-should-be-placed-outside-of-range",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5| aaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|100000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---does-not-stop-if-mark-should-be-placed-outside-of-range-002",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---does-not-stop-if-mark-should-be-placed-outside-of-range-003",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5| aaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|100000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---does-not-stop-if-mark-should-be-placed-outside-of-range-004",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---does-not-stop-if-mark-should-be-placed-outside-of-range-005",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5| aaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|100000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---does-not-stop-if-mark-should-be-placed-outside-of-range-006",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---is-not-animated-if-`path`-output-is-empty-or-`nil`",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---is-not-animated-if-`path`-output-is-empty-or-`nil`-002",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---respects-`enable`-config-setting",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'b'-}",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'b'-}-002",
    "content": "-|---------|--\n1| aaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'g'-}",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'g'-}-002",
    "content": "-|---------|--\n1| aaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---respects-buffer-local-config",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---stops-on-buffer-change",
    "content": "--|---------|---------|----\n01| aaaaaaaaa │            \n02|aaa        │~           \n03|           │~           \n04|aaa        │~           \n05|aaaaaaaaaa │~           \n06|~          │~           \n07|~          │~           \n08|~          │~           \n09|~          │~           \n10|~          │~           \n11|< Name] 5,1 <Name] 0,0-1\n12|                        \n\n--|---------|---------|----\n01|011111111112333333333333\n02|111111111112444444444444\n03|111111111112444444444444\n04|111111111112444444444444\n05|111111111112444444444444\n06|555555555552444444444444\n07|555555555552444444444444\n08|555555555552444444444444\n09|555555555552444444444444\n10|555555555552444444444444\n11|666666666666777777777777\n12|333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---stops-on-buffer-change-002",
    "content": "--|---------|---------|----\n01|aaaaaaaaaa │            \n02| aa        │~           \n03|           │~           \n04|aaa        │~           \n05|aaaaaaaaaa │~           \n06|~          │~           \n07|~          │~           \n08|~          │~           \n09|~          │~           \n10|~          │~           \n11|< Name] 5,1 <Name] 0,0-1\n12|                        \n\n--|---------|---------|----\n01|000000000001222222222222\n02|300000000001444444444444\n03|000000000001444444444444\n04|000000000001444444444444\n05|000000000001444444444444\n06|555555555551444444444444\n07|555555555551444444444444\n08|555555555551444444444444\n09|555555555551444444444444\n10|555555555551444444444444\n11|666666666666777777777777\n12|222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---stops-on-buffer-change-003",
    "content": "--|---------|---------|----\n01|aaaaaaaaaa │            \n02|aaa        │~           \n03|           │~           \n04|aaa        │~           \n05|aaaaaaaaaa │~           \n06|~          │~           \n07|~          │~           \n08|~          │~           \n09|~          │~           \n10|~          │~           \n11|< Name] 5,1 <Name] 0,0-1\n12|                        \n\n--|---------|---------|----\n01|000000000001222222222222\n02|000000000001333333333333\n03|400000000001333333333333\n04|000000000001333333333333\n05|000000000001333333333333\n06|555555555551333333333333\n07|555555555551333333333333\n08|555555555551333333333333\n09|555555555551333333333333\n10|555555555551333333333333\n11|666666666666777777777777\n12|222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---stops-on-buffer-change-004",
    "content": "--|---------|---------|----\n01|aaaaaaaaaa │            \n02|aaa        │~           \n03|           │~           \n04|aaa        │~           \n05|aaaaaaaaaa │~           \n06|~          │~           \n07|~          │~           \n08|~          │~           \n09|~          │~           \n10|~          │~           \n11|< Name] 5,1 <Name] 0,0-1\n12|                        \n\n--|---------|---------|----\n01|000000000001222222222222\n02|000000000001333333333333\n03|400000000001333333333333\n04|000000000001333333333333\n05|000000000001333333333333\n06|555555555551333333333333\n07|555555555551333333333333\n08|555555555551333333333333\n09|555555555551333333333333\n10|555555555551333333333333\n11|666666666666777777777777\n12|000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---stops-on-buffer-change-005",
    "content": "--|---------|---------|----\n01|aaaaaaaaaa │            \n02|aaa        │~           \n03|           │~           \n04|aaa        │~           \n05|aaaaaaaaaa │~           \n06|~          │~           \n07|~          │~           \n08|~          │~           \n09|~          │~           \n10|~          │~           \n11|< Name] 5,1 <Name] 0,0-1\n12|                        \n\n--|---------|---------|----\n01|000000000001222222222222\n02|000000000001333333333333\n03|000000000001333333333333\n04|000000000001333333333333\n05|000000000001333333333333\n06|444444444441333333333333\n07|444444444441333333333333\n08|444444444441333333333333\n09|444444444441333333333333\n10|444444444441333333333333\n11|555555555555666666666666\n12|000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works",
    "content": "-|---------|--\n1| aaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-002",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2| aa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|100000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-003",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|100000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-004",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4| aa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|100000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-005",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line",
    "content": "-|---------|--\n1| aaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-002",
    "content": "-|---------|--\n1|a aaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|010000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-003",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aa          \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|001000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-004",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|000100000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-005",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000010000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-006",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000001000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-007",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000100000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-008",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000010000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-cursor-and-or-marks-are-outside-of-line-009",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<Name] 4,4-9\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-movement-is-triggered-by-outside-command",
    "content": "-|---------|--\n1| aaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-movement-is-triggered-by-outside-command-002",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2| aa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|100000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-movement-is-triggered-by-outside-command-003",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|100000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-movement-is-triggered-by-outside-command-004",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4| aa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|100000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-when-movement-is-triggered-by-outside-command-005",
    "content": "-|---------|--\n1|aaaaaaaaaa  \n2|aaa         \n3|            \n4|aaa         \n5|aaaaaaaaaa  \n6|~           \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-horizontally-scrolled-window-view",
    "content": "-|---------|--\n1| aaaaaaa    \n2|a           \n3|            \n4|a           \n5|aaaaaaaa    \n6|~           \n7|<o Name] 5,6\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-horizontally-scrolled-window-view-002",
    "content": "-|---------|--\n1|aaaaaaaa    \n2|a           \n3|            \n4|a           \n5|aaaaaaaa    \n6|~           \n7|<o Name] 5,6\n8|            \n\n-|---------|--\n1|000000000000\n2|010000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-horizontally-scrolled-window-view-003",
    "content": "-|---------|--\n1|aaaaaaaa    \n2|a           \n3|            \n4|a           \n5|aaaaaaaa    \n6|~           \n7|<o Name] 5,6\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|001000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-horizontally-scrolled-window-view-004",
    "content": "-|---------|--\n1|aaaaaaaa    \n2|a           \n3|            \n4|a           \n5|aaaaaaaa    \n6|~           \n7|<o Name] 5,6\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|001000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-horizontally-scrolled-window-view-005",
    "content": "-|---------|--\n1|aaaaaaaa    \n2|a           \n3|            \n4|a           \n5|aaaaaaaa    \n6|~           \n7|<o Name] 5,6\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters",
    "content": "-|---------|--\n1| ыы         \n2|🬗🬗🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|011111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-002",
    "content": "-|---------|--\n1|ыыы         \n2|🬗 🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|010000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-003",
    "content": "-|---------|--\n1|ыыы         \n2|🬗🬗          \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|001000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-004",
    "content": "-|---------|--\n1|ыыы         \n2|🬗🬗🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000100000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-005",
    "content": "-|---------|--\n1|ыыы         \n2|🬗🬗🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000010000000\n4|000000000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-006",
    "content": "-|---------|--\n1|ыыы         \n2|🬗🬗🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000001000000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-007",
    "content": "-|---------|--\n1|ыыы         \n2|🬗🬗🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000100000\n5|000000000000\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-multibyte-characters-008",
    "content": "-|---------|--\n1|ыыы         \n2|🬗🬗🬗         \n3|            \n4|ы           \n5|ыыыыыыыы    \n6|~           \n7|<ame] 5,15-8\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-tabs",
    "content": "-|---------|--\n1|    a       \n2|    bb      \n3|cc          \n4|~           \n5|~           \n6|~           \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000001000000\n2|000000000000\n3|000000000000\n4|222222222222\n5|222222222222\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-tabs-002",
    "content": "-|---------|--\n1|     a      \n2|    bb      \n3|cc          \n4|~           \n5|~           \n6|~           \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000010000000\n2|000000000000\n3|000000000000\n4|222222222222\n5|222222222222\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-tabs-003",
    "content": "-|---------|--\n1|    aa      \n2|    bb      \n3|cc          \n4|~           \n5|~           \n6|~           \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000100000000\n3|000000000000\n4|222222222222\n5|222222222222\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-tabs-004",
    "content": "-|---------|--\n1|    aa      \n2|    bb      \n3|cc          \n4|~           \n5|~           \n6|~           \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|001000000000\n3|000000000000\n4|222222222222\n5|222222222222\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-tabs-005",
    "content": "-|---------|--\n1|    aa      \n2|    bb      \n3|c           \n4|~           \n5|~           \n6|~           \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|010000000000\n4|222222222222\n5|222222222222\n6|222222222222\n7|333333333333\n8|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Cursor---works-with-tabs-006",
    "content": "-|---------|--\n1|    aa      \n2|    bb      \n3|cc          \n4|~           \n5|~           \n6|~           \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|111111111111\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|< 1,1 <] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|333333444444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-002",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|<] 1,1 < 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|333333344444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-003",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|<] 1,1 < 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|333333344444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-004",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|< 1,1 <] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|333333444444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-005",
    "content": "-|---------|--\n1|aaaa│AAAA   \n2|bbbb│BBBB   \n3|<1,1 <e] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000012222222\n2|000012222222\n3|333334444444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-006",
    "content": "-|---------|--\n1|aaa│AAAA    \n2|bbb│BBBB    \n3|<,1 <me] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000122222222\n2|000122222222\n3|333344444444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-007",
    "content": "-|---------|--\n1|aa│AAAA     \n2|bb│BBBB     \n3|<1 <ame] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|001222222222\n2|001222222222\n3|333444444444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-008",
    "content": "-|---------|--\n1|a│AAAA      \n2|b│BBBB      \n3|< <Name] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|012222222222\n2|012222222222\n3|334444444444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---allows-immediate-another-resize-animation-009",
    "content": "-|---------|--\n1|a│AAAA      \n2|b│BBBB      \n3|< <Name] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|012222222222\n2|012222222222\n3|334444444444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---animates-only-for-equal-layouts",
    "content": "-|---------|--\n1|AAAA        \n2|BBBB        \n3|<o Name] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|222222222222\n6|222222222222\n7|333333333333\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---animates-only-for-equal-layouts-002",
    "content": "-|---------|--\n1|AAAA  │AAAA \n2|BBBB  │BBBB \n3|<] 1,1 < 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|333333344444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column",
    "content": "-|---------|--\n1|a│AAAA      \n2|~│BBBB      \n3|< <Name] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|012222222222\n2|312222222222\n3|445555555555\n4|000000000000\n5|000000000000\n6|000000000000\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-002",
    "content": "-|---------|--\n1|aa│AAAA     \n2|~ │BBBB     \n3|<0 <ame] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|001222222222\n2|331222222222\n3|444555555555\n4|000000000000\n5|000000000000\n6|000000000000\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-003",
    "content": "-|---------|--\n1|aaa│AAAA    \n2|~  │BBBB    \n3|~  │CCCC    \n4|<10 <me] 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000122222222\n2|333122222222\n3|333122222222\n4|444455555555\n5|000000000000\n6|000000000000\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-004",
    "content": "-|---------|--\n1|aaa │AAAA   \n2|~   │BBBB   \n3|~   │CCCC   \n4|<,10 <e] 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000012222222\n2|333312222222\n3|333312222222\n4|444445555555\n5|000000000000\n6|000000000000\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-005",
    "content": "-|---------|--\n1|aaa  │AAAA  \n2|~    │BBBB  \n3|~    │CCCC  \n4|<1,12 <] 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|333331222222\n3|333331222222\n4|444444555555\n5|000000000000\n6|000000000000\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-006",
    "content": "-|---------|--\n1|aaa  │AAAA  \n2|~    │BBBB  \n3|~    │CCCC  \n4|<1,12 <] 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|333331222222\n3|333331222222\n4|444444555555\n5|000000000000\n6|000000000000\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window",
    "content": "-|---------|--\n1|a│AAAA      \n2|~│BBBB      \n3|< <Name] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|012222222222\n2|312222222222\n3|445555555555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-002",
    "content": "-|---------|--\n1|aa│AAAA     \n2|~ │BBBB     \n3|<0 <ame] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|001222222222\n2|331222222222\n3|444555555555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-003",
    "content": "-|---------|--\n1|aaa│AAAA    \n2|~  │BBBB    \n3|<10 <me] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000122222222\n2|333122222222\n3|444455555555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-004",
    "content": "-|---------|--\n1|aaa │AAAA   \n2|~   │BBBB   \n3|<,10 <e] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000012222222\n2|333312222222\n3|444445555555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-005",
    "content": "-|---------|--\n1|aaa  │AAAA  \n2|~    │BBBB  \n3|<1,10 <] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|333331222222\n3|444444555555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-006",
    "content": "-|---------|--\n1|aaa   │AAAA \n2|~     │BBBB \n3|< 1,10 < 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|333333122222\n3|444444455555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-007",
    "content": "-|---------|--\n1|aaa    │AAAA\n2|~      │BBBB\n3|<] 1,10 <1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|333333312222\n3|444444445555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-008",
    "content": "-|---------|--\n1|aaa     │AAA\n2|~       │BBB\n3|<e] 1,10 <,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001222\n2|333333331222\n3|444444444555\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-009",
    "content": "-|---------|--\n1|aaa      │AA\n2|~        │BB\n3|<me] 1,10 <1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000122\n2|333333333122\n3|444444444455\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-010",
    "content": "-|---------|--\n1|aaa       │A\n2|~         │B\n3|<ame] 1,12 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|333333333312\n3|444444444445\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---does-not-flicker-due-to-high-cursor-column-in-current-window-011",
    "content": "-|---------|--\n1|aaa       │A\n2|~         │B\n3|<ame] 1,12 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|333333333312\n3|444444444445\n4|222222222222\n5|222222222222\n6|222222222222\n7|555555555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---is-not-animated-if-`subresize`-output-is-empty-or-`nil`",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---is-not-animated-if-`subresize`-output-is-empty-or-`nil`-002",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|<] 1,1 < 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|333333344444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`enable`-config-setting",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'b'-}",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'b'-}-002",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|<] 1,1 < 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|333333344444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'b'-}-003",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|cccc   │CCCC\n4|<e] 1,1 <1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|000000012222\n4|333333334444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'g'-}",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'g'-}-002",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|<] 1,1 < 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|333333344444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-`vim.{g,b}.minianimate_disable`---test-+-args-{-'g'-}-003",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|cccc   │CCCC\n4|<e] 1,1 <1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|000000012222\n4|333333334444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---respects-buffer-local-config",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|< 1,1 <] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|333333444444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-002",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|<] 1,1 < 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|333333344444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-003",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|<e] 1,1 <1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|333333334444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-004",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|<me] 1,1 <,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001222\n2|000000001222\n3|333333333444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-005",
    "content": "-|---------|--\n1|aaaa     │AA\n2|bbbb     │BB\n3|<ame] 1,1 <1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000122\n2|000000000122\n3|333333333344\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-006",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-007",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-008",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|<Name] 1,1 <\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|333333333334\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-009",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|cccc      │C\n4|<Name] 1,1 <\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|000000000012\n4|333333333334\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-010",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|cccc      │C\n4|dddd      │D\n5|<Name] 1,1 <\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|000000000012\n4|000000000012\n5|333333333334\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-011",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|cccc      │C\n4|dddd      │D\n5|<Name] 1,1 <\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|000000000012\n4|000000000012\n5|333333333334\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-012",
    "content": "-|---------|--\n1|aaaa      │A\n2|bbbb      │B\n3|cccc      │C\n4|dddd      │D\n5|<Name] 1,1 <\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000012\n2|000000000012\n3|000000000012\n4|000000000012\n5|333333333334\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-013",
    "content": "-|---------|--\n1|aaaa     │AA\n2|bbbb     │BB\n3|cccc     │CC\n4|dddd     │DD\n5|<ame] 1,1 <1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000122\n2|000000000122\n3|000000000122\n4|000000000122\n5|333333333344\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-014",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|cccc    │CCC\n4|dddd    │DDD\n5|<me] 1,1 <,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001222\n2|000000001222\n3|000000001222\n4|000000001222\n5|333333333444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-015",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|cccc   │CCCC\n4|<e] 1,1 <1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|000000012222\n4|333333334444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-016",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|<] 1,1 < 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|333333344444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-017",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|<] 1,1 < 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|333333344444\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-when-resize-is-triggered-by-outside-command",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|< 1,1 <] 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|333333444444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-when-resize-is-triggered-by-outside-command-002",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|<] 1,1 < 1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|333333344444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-when-resize-is-triggered-by-outside-command-003",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|<e] 1,1 <1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|333333334444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-when-resize-is-triggered-by-outside-command-004",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|<e] 1,1 <1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|333333334444\n4|222222222222\n5|222222222222\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|<me] 1,1 <,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001222\n2|000000001222\n3|333333333444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-002",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|<e] 1,1 <1,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|333333334444\n4|000000000000\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-003",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|<] 1,1 < 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|333333344444\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-004",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|cccc │CCCC  \n4|< 1,1 <] 1,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|333333444444\n5|000000000000\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-005",
    "content": "-|---------|--\n1|aaaa│AAAA   \n2|bbbb│BBBB   \n3|cccc│CCCC   \n4|dddd│DDDD   \n5|<1,1 <e] 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000012222222\n2|000012222222\n3|000012222222\n4|000012222222\n5|333334444444\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-006",
    "content": "-|---------|--\n1|aaa│AAAA    \n2|bbb│BBBB    \n3|ccc│CCCC    \n4|ddd│DDDD    \n5|<,1 <me] 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000122222222\n2|000122222222\n3|000122222222\n4|000122222222\n5|333344444444\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-007",
    "content": "-|---------|--\n1|aaa│AAAA    \n2|bbb│BBBB    \n3|ccc│CCCC    \n4|ddd│DDDD    \n5|<,1 <me] 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000122222222\n2|000122222222\n3|000122222222\n4|000122222222\n5|333344444444\n6|000000000000\n7|333333333333\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-008",
    "content": "-|---------|--\n1|aaa│AAAA    \n2|bbb│BBBB    \n3|ccc│CCCC    \n4|ddd│DDDD    \n5|<,1 <me] 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000122222222\n2|000122222222\n3|000122222222\n4|000122222222\n5|333344444444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-009",
    "content": "-|---------|--\n1|aaaa│AAAA   \n2|bbbb│BBBB   \n3|cccc│CCCC   \n4|dddd│DDDD   \n5|<1,1 <e] 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000012222222\n2|000012222222\n3|000012222222\n4|000012222222\n5|333334444444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-010",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|cccc │CCCC  \n4|dddd │DDDD  \n5|< 1,1 <] 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|333333444444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-011",
    "content": "-|---------|--\n1|aaaa  │AAAA \n2|bbbb  │BBBB \n3|cccc  │CCCC \n4|dddd  │DDDD \n5|<] 1,1 < 1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000122222\n2|000000122222\n3|000000122222\n4|000000122222\n5|333333344444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-012",
    "content": "-|---------|--\n1|aaaa   │AAAA\n2|bbbb   │BBBB\n3|cccc   │CCCC\n4|dddd   │DDDD\n5|<e] 1,1 <1,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000012222\n2|000000012222\n3|000000012222\n4|000000012222\n5|333333334444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-013",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|cccc    │CCC\n4|dddd    │DDD\n5|<me] 1,1 <,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001222\n2|000000001222\n3|000000001222\n4|000000001222\n5|333333333444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-014",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|cccc    │CCC\n4|dddd    │DDD\n5|<me] 1,1 <,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001222\n2|000000001222\n3|000000001222\n4|000000001222\n5|333333333444\n6|222222222222\n7|444444444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-015",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|cccc    │CCC\n4|dddd    │DDD\n5|<me] 1,1 <,1\n6|1111        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001000\n2|000000001000\n3|000000001000\n4|000000001000\n5|222222222222\n6|333333333333\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-016",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|cccc    │CCC\n4|<me] 1,1 <,1\n5|1111        \n6|2222        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001000\n2|000000001000\n3|000000001000\n4|222222222222\n5|333333333333\n6|333333333333\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-017",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|bbbb    │BBB\n3|<me] 1,1 <,1\n4|1111        \n5|2222        \n6|3333        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001000\n2|000000001000\n3|222222222222\n4|333333333333\n5|333333333333\n6|333333333333\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-018",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|<me] 1,1 <,1\n3|1111        \n4|2222        \n5|3333        \n6|4444        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001000\n2|222222222222\n3|333333333333\n4|333333333333\n5|333333333333\n6|333333333333\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Resize---works-with-`winheight`-`winwidth`-019",
    "content": "-|---------|--\n1|aaaa    │AAA\n2|<me] 1,1 <,1\n3|1111        \n4|2222        \n5|3333        \n6|4444        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000001000\n2|222222222222\n3|333333333333\n4|333333333333\n5|333333333333\n6|333333333333\n7|444444444444\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---allows-immediate-another-scroll-animation",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---allows-immediate-another-scroll-animation-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 2,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---allows-immediate-another-scroll-animation-003",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---allows-immediate-another-scroll-animation-004",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---allows-immediate-another-scroll-animation-005",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---allows-immediate-another-scroll-animation-006",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-animate-in-Select-mode",
    "content": "-|---------|-----\n1|cccc           \n2|dddd           \n3|eeee           \n4|[No Name] 4,1  \n5|-- S1          \n\n-|---------|-----\n1|000000000000000\n2|000000000000000\n3|000000000000000\n4|111111111111111\n5|222233333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-automatically-animate-after-buffer-change",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-automatically-animate-after-buffer-change-002",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-automatically-animate-result-of-'incsearch'",
    "content": "--|---------|---------|-----\n01|hhhh                     \n02|iiii                     \n03|jjjj                     \n04|kkkk                     \n05|llll                     \n06|mmmm                     \n07|nnnn                     \n08|oooo                     \n09|[No Name] 15,1           \n10|/oo  ...[1/2]            \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|0000000000000000000000000\n03|0000000000000000000000000\n04|0000000000000000000000000\n05|0000000000000000000000000\n06|0000000000000000000000000\n07|0000000000000000000000000\n08|1122000000000000000000000\n09|3333333333333333333333333\n10|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-automatically-animate-result-of-'incsearch'-002",
    "content": "--|---------|---------|-----\n01|hhhh                     \n02|iiii                     \n03|jjjj                     \n04|kkkk                     \n05|llll                     \n06|mmmm                     \n07|nnnn                     \n08|oooo                     \n09|[No Name] 15,1           \n10|/oo  ...[1/2]            \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|0000000000000000000000000\n03|0000000000000000000000000\n04|0000000000000000000000000\n05|0000000000000000000000000\n06|0000000000000000000000000\n07|0000000000000000000000000\n08|1122000000000000000000000\n09|3333333333333333333333333\n10|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-automatically-animate-result-of-'incsearch'-003",
    "content": "--|---------|---------|-----\n01|aaaa                     \n02|bbbb                     \n03|cccc                     \n04|dddd                     \n05|eeee                     \n06|ffff                     \n07|gggg                     \n08|hhhh                     \n09|[No Name] 1,3            \n10|?aa  ...[2/2]            \n\n--|---------|---------|-----\n01|0011222222222222222222222\n02|2222222222222222222222222\n03|2222222222222222222222222\n04|2222222222222222222222222\n05|2222222222222222222222222\n06|2222222222222222222222222\n07|2222222222222222222222222\n08|2222222222222222222222222\n09|3333333333333333333333333\n10|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---does-not-automatically-animate-result-of-'incsearch'-004",
    "content": "--|---------|---------|-----\n01|aaaa                     \n02|bbbb                     \n03|cccc                     \n04|dddd                     \n05|eeee                     \n06|ffff                     \n07|gggg                     \n08|hhhh                     \n09|[No Name] 1,3            \n10|?aa  ...[2/2]            \n\n--|---------|---------|-----\n01|0011222222222222222222222\n02|2222222222222222222222222\n03|2222222222222222222222222\n04|2222222222222222222222222\n05|2222222222222222222222222\n06|2222222222222222222222222\n07|2222222222222222222222222\n08|2222222222222222222222222\n09|3333333333333333333333333\n10|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---handles-mappings-with--Cmd--CR-",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---handles-mappings-with--Cmd--CR--002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-'scrolloff'-in-presence-of-folds",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|+--  6 lines\n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-'scrolloff'-in-presence-of-folds-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|+--  6 lines\n6|llll        \n7|<o Name] 8,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|111111111111\n6|000000000000\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-'scrolloff'-in-presence-of-folds-003",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|+--  6 lines\n5|llll        \n6|mmmm        \n7|< Name] 10,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|000000000000\n6|000000000000\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-'scrolloff'-in-presence-of-folds-004",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|+--  6 lines\n4|llll        \n5|mmmm        \n6|nnnn        \n7|< Name] 13,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|000000000000\n5|000000000000\n6|000000000000\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-'scrolloff'-in-presence-of-folds-005",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|+--  6 lines\n4|llll        \n5|mmmm        \n6|nnnn        \n7|< Name] 13,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|000000000000\n5|000000000000\n6|000000000000\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-folds",
    "content": "-|---------|--\n1|aaaa        \n2|+--  6 lines\n3|hhhh        \n4|iiii        \n5|jjjj        \n6|kkkk        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-folds-002",
    "content": "-|---------|--\n1|+--  6 lines\n2|hhhh        \n3|iiii        \n4|jjjj        \n5|kkkk        \n6|llll        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|111111111111\n5|111111111111\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-folds-003",
    "content": "-|---------|--\n1|hhhh        \n2|iiii        \n3|jjjj        \n4|kkkk        \n5|llll        \n6|mmmm        \n7|<o Name] 8,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-folds-004",
    "content": "-|---------|--\n1|iiii        \n2|jjjj        \n3|kkkk        \n4|llll        \n5|mmmm        \n6|nnnn        \n7|<o Name] 9,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-folds-005",
    "content": "-|---------|--\n1|iiii        \n2|jjjj        \n3|kkkk        \n4|llll        \n5|mmmm        \n6|nnnn        \n7|<o Name] 9,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-global-'scrolloff'",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-global-'scrolloff'-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 6,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-global-'scrolloff'-003",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 7,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-global-'scrolloff'-004",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 8,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-global-'scrolloff'-005",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 8,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-window-local-'scrolloff'",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 5,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-window-local-'scrolloff'-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 6,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-window-local-'scrolloff'-003",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 7,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-window-local-'scrolloff'-004",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 8,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---respects-window-local-'scrolloff'-005",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 8,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-buffer-change",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-buffer-change-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 2,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-buffer-change-003",
    "content": "-|---------|--\n1|AAAA        \n2|BBBB        \n3|CCCC        \n4|DDDD        \n5|~           \n6|~           \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|111111111111\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-buffer-change-004",
    "content": "-|---------|--\n1|AAAA        \n2|BBBB        \n3|CCCC        \n4|DDDD        \n5|~           \n6|~           \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|111111111111\n6|111111111111\n7|222222222222\n8|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-window-change",
    "content": "-|---------|--\n1|aaaa │AAAA  \n2|bbbb │BBBB  \n3|cccc │CCCC  \n4|dddd │DDDD  \n5|eeee │~     \n6|ffff │~     \n7|< 1,1 <] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|000001333333\n6|000001333333\n7|444444555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-window-change-002",
    "content": "-|---------|--\n1|bbbb │AAAA  \n2|cccc │BBBB  \n3|dddd │CCCC  \n4|eeee │DDDD  \n5|ffff │~     \n6|gggg │~     \n7|< 2,1 <] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|000001333333\n6|000001333333\n7|444444555555\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-window-change-003",
    "content": "-|---------|--\n1|bbbb │AAAA  \n2|cccc │BBBB  \n3|dddd │CCCC  \n4|eeee │DDDD  \n5|ffff │~     \n6|gggg │~     \n7|< 2,1 <] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|000001333333\n6|000001333333\n7|444444555555\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---stops-on-window-change-004",
    "content": "-|---------|--\n1|bbbb │AAAA  \n2|cccc │BBBB  \n3|dddd │CCCC  \n4|eeee │DDDD  \n5|ffff │~     \n6|gggg │~     \n7|< 2,1 <] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|000001333333\n6|000001333333\n7|444444555555\n8|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 2,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-003",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 3,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-004",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-005",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-006",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-007",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-008",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-009",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-010",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 4,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-properly-just-after-buffer-change",
    "content": "-|---------|--\n1|AAAA        \n2|BBBB        \n3|CCCC        \n4|DDDD        \n5|EEEE        \n6|FFFF        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-properly-just-after-buffer-change-002",
    "content": "-|---------|--\n1|BBBB        \n2|CCCC        \n3|DDDD        \n4|EEEE        \n5|FFFF        \n6|GGGG        \n7|<o Name] 2,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-properly-just-after-window-change",
    "content": "-|---------|--\n1|aaaa │aaaa  \n2|bbbb │bbbb  \n3|cccc │cccc  \n4|dddd │dddd  \n5|eeee │eeee  \n6|ffff │ffff  \n7|< 1,1 <] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|000001222222\n6|000001222222\n7|333333444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-properly-just-after-window-change-002",
    "content": "-|---------|--\n1|bbbb │aaaa  \n2|cccc │bbbb  \n3|dddd │cccc  \n4|eeee │dddd  \n5|ffff │eeee  \n6|gggg │ffff  \n7|< 2,1 <] 1,1\n8|            \n\n-|---------|--\n1|000001222222\n2|000001222222\n3|000001222222\n4|000001222222\n5|000001222222\n6|000001222222\n7|333333444444\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-when-movement-is-triggered-by-outside-command",
    "content": "-|---------|--\n1|aaaa        \n2|bbbb        \n3|cccc        \n4|dddd        \n5|eeee        \n6|ffff        \n7|<o Name] 1,1\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-when-movement-is-triggered-by-outside-command-002",
    "content": "-|---------|--\n1|bbbb        \n2|cccc        \n3|dddd        \n4|eeee        \n5|ffff        \n6|gggg        \n7|<o Name] 4,2\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-when-movement-is-triggered-by-outside-command-003",
    "content": "-|---------|--\n1|cccc        \n2|dddd        \n3|eeee        \n4|ffff        \n5|gggg        \n6|hhhh        \n7|<o Name] 6,3\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-when-movement-is-triggered-by-outside-command-004",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 9,4\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_animate.lua---Scroll---works-when-movement-is-triggered-by-outside-command-005",
    "content": "-|---------|--\n1|dddd        \n2|eeee        \n3|ffff        \n4|gggg        \n5|hhhh        \n6|iiii        \n7|<o Name] 9,4\n8|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|000000000000\n5|000000000000\n6|000000000000\n7|111111111111\n8|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_basics.lua---Mappings---Toggle-options---respects-`config.silent`",
    "content": "--|---------|---------|\n01|    1               \n02|                    \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|[No Name] 0,0-1     \n10|                    \n\n--|---------|---------|\n01|00111122222222222222\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|33333333333333333333\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_basics.lua---Mappings---Toggle-options---shows-feedback-about-new-value",
    "content": "--|---------|---------|\n01|    1               \n02|                    \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|[No Name] 0,0-1     \n10|  spell             \n\n--|---------|---------|\n01|00111122222222222222\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|33333333333333333333\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---'mini.nvim'-compatibility---mini.align",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aa_b                          \n03|~                             \n04|~                             \n05|[No Name] 2,1                 \n06|(mini.align) Split: \"\" | Justi\n07|fy: \"left\" | Merge: \"\" | Press\n08| modifier                     \n09|                              \n10|                              \n\n--|---------|---------|---------|\n01|000111111111111111111111111111\n02|100011111111111111111111111111\n03|222222222222222222222222222222\n04|222222222222222222222222222222\n05|333333333333333333333333333333\n06|444444444444455555556677755555\n07|555566666677755555556677666666\n08|666666666666666666666666666666\n09|666666666666666666666666666666\n10|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---'mini.nvim'-compatibility---mini.align-002",
    "content": "--|---------|---------|---------|\n01|a_b                           \n02|aa_b                          \n03|~                             \n04|~                             \n05|[No Name] 1,1                 \n06|(mini.align) Split: \"\" | Justi\n07|fy: \"left\" | Merge: \"\" | Press\n08| modifier                     \n09|                              \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|222222222222222222222222222222\n06|333333333333344444445566644444\n07|444455555566644444445566555555\n08|555555555555555555555555555555\n09|555555555555555555555555555555\n10|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---are-properly-sorted",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~       ┌ <Space> ─────────────────────┐\n03|~       │ 0     │ LHS: \" 0\"            │\n04|~       │ 9     │ LHS: \" 9\"            │\n05|~       │ A     │ LHS: \" A\"            │\n06|~       │ a     │ LHS: \" a\"            │\n07|~       │ X     │ LHS: \" X\"            │\n08|~       │ x     │ LHS: \" x\"            │\n09|~       │ <C-A> │ LHS: \" \\1\"           │\n10|~       │ <C-X> │ LHS: \" \\24\"          │\n11|~       │ /     │ LHS: \" /\"            │\n12|~       │ :     │ LHS: \" :\"            │\n13|~       └──────────────────────────────┘\n14|[No Name] 0,0-1                         \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111123333333332222222222222222222222\n03|1111111124444444566666666666666666666662\n04|1111111124444444566666666666666666666662\n05|1111111124444444566666666666666666666662\n06|1111111124444444566666666666666666666662\n07|1111111124444444566666666666666666666662\n08|1111111124444444566666666666666666666662\n09|1111111124444444566666666666666666666662\n10|1111111124444444566666666666666666666662\n11|1111111124444444566666666666666666666662\n12|1111111124444444566666666666666666666662\n13|1111111122222222222222222222222222222222\n14|7777777777777777777777777777777777777777\n15|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-be-configured-after-load",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-be-overridden-in-later-entries",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ a │ Second <Space>a          │\n07|~       │ b │ First <Space>b           │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111127775666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-have-callable-description",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ From callable desc       │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-have-callables",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-have-callables-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-have-callables-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ b │ From <Space>b callable   │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-have-callables-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ c │                          │\n07|~       │ d │ From <Space>d callable   │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---can-have-nested-subarrays",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       ┌ <Space> ─────────────────────┐\n05|~       │ a │                          │\n06|~       │ b │                          │\n07|~       │ c │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111123333333332222222222222222222222\n05|1111111124445666666666666666666666666662\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---handles-an-array-of-modes",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ Clue <Space>a            │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---handles-an-array-of-modes-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ Clue <Space>a            │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|-- VISUAL --                 1          \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---handles-no-description",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       ┌ <Space> ─────────────────────┐\n05|~       │ a │                          │\n06|~       │ b │                          │\n07|~       │ c │ +2 choices               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111123333333332222222222222222222222\n05|1111111124445666666666666666666666666662\n06|1111111124445666666666666666666666666662\n07|1111111124445777777777777777777777777772\n08|1111111122222222222222222222222222222222\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---handles-showing-group-clues-after-executing-key-with-postkeys",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ f │ LHS: \" f\"                │\n07|~       │ g │ Group                    │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111127775888888888888888888888888882\n08|1111111122222222222222222222222222222222\n09|9999999999999999999999999999999999999999\n10|::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---handles-showing-group-clues-after-executing-key-with-postkeys-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ Group ───────────────────────┐\n06|~       │ a │ LHS: \" ga\"               │\n07|~       │ b │ LHS: \" gb\"               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333222222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---has-proper-precedence",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~       ┌ <Space> ─────────────────────┐\n03|~       │ a │ Buffer-local <Space>a    │\n04|~       │ b │                          │\n05|~       │ c │ Global <Space>c          │\n06|~       │ d │                          │\n07|~       │ e │ Clue <Space>e            │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111123333333332222222222222222222222\n03|1111111124445666666666666666666666666662\n04|1111111124445666666666666666666666666662\n05|1111111124445666666666666666666666666662\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---respects-`vim.b.miniclue_config`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       ┌ <Space> ─────────────────────┐\n05|~       │ a │ From buffer-local config │\n06|~       │ b │                          │\n07|~       │ c │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111123333333332222222222222222222222\n05|1111111124445666666666666666666666666662\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---shows-as-group-a-single-non-exact-clue",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ +1 choice                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---shows-as-group-a-single-non-exact-clue-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space>a ────────────────────┐\n07|~       │ a │ +1 choice                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333333222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---shows-as-group-a-single-non-exact-clue-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space>aa ───────────────────┐\n07|~       │ a │ Clue <Space>a            │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333333322222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---silently-ignores-non-valid-clues",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Clues---uses-human-readable-names-for-special-keys",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~       ┌ <Space> ─────────────────────┐\n03|~       │ <C-J>     │                  │\n04|~       │ <C-M-J>   │                  │\n05|~       │ <C-Right> │                  │\n06|~       │ <C-S-J>   │                  │\n07|~       │ <C-X>     │                  │\n08|~       │ <End>     │                  │\n09|~       │ <F1>      │                  │\n10|~       │ <kRight>  │                  │\n11|~       │ <PageUp>  │                  │\n12|~       │ <Right>   │                  │\n13|~       │ <S-F1>    │                  │\n14|~       │ <S-Right> │                  │\n15|~       │ <Space>   │                  │\n16|~       │ <Tab>     │                  │\n17|~       │ <         │                  │\n18|~       └──────────────────────────────┘\n19|[No Name] 0,0-1                         \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111123333333332222222222222222222222\n03|1111111124444444444456666666666666666662\n04|1111111124444444444456666666666666666662\n05|1111111124444444444456666666666666666662\n06|1111111124444444444456666666666666666662\n07|1111111124444444444456666666666666666662\n08|1111111124444444444456666666666666666662\n09|1111111124444444444456666666666666666662\n10|1111111124444444444456666666666666666662\n11|1111111124444444444456666666666666666662\n12|1111111124444444444456666666666666666662\n13|1111111124444444444456666666666666666662\n14|1111111124444444444456666666666666666662\n15|1111111124444444444456666666666666666662\n16|1111111124444444444456666666666666666662\n17|1111111124444444444456666666666666666662\n18|1111111122222222222222222222222222222222\n19|7777777777777777777777777777777777777777\n20|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---closes-window-if-postkeys-do-not-end-up-key-querying",
    "content": "--|---------|---------|---------|---------|\n01|G                                       \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,2                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---persists-window-if-action-changes-tabpage",
    "content": "--|---------|---------|---------|---------|\n01|                    │                   \n02|~                   │~                  \n03|~                   │~                  \n04|~       ┌ <C-W> ───────────────────────┐\n05|~       │ d     │ Show diagnostics und…│\n06|~       │ T     │ Move to new tabpage  │\n07|~       │ <C-D> │ Show diagnostics und…│\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1      [No Name] 0,0-1    \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000012222222222222222222\n02|3333333333333333333314444444444444444444\n03|3333333333333333333314444444444444444444\n04|3333333356666666555555555555555555555555\n05|33333333577777778999999999999999999999:5\n06|333333335;;;;;;;899999999999999999999995\n07|33333333577777778999999999999999999999:5\n08|3333333355555555555555555555555555555555\n09|<<<<<<<<<<<<<<<<<<<<<===================\n10|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---persists-window-if-action-changes-tabpage-002",
    "content": "--|---------|---------|---------|---------|\n01| [No Name]  [No Name]                  X\n02|                                        \n03|~                                       \n04|~       ┌ <C-W> ───────────────────────┐\n05|~       │ d     │ Show diagnostics und…│\n06|~       │ T     │ Move to new tabpage  │\n07|~       │ <C-D> │ Show diagnostics und…│\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000011111111111000000000000000000\n02|2222222222222222222222222222222222222222\n03|3333333333333333333333333333333333333333\n04|3333333314444444111111111111111111111111\n05|3333333315555555677777777777777777777781\n06|3333333319999999677777777777777777777771\n07|3333333315555555677777777777777777777781\n08|3333333311111111111111111111111111111111\n09|::::::::::::::::::::::::::::::::::::::::\n10|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---shows-window-immediately",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ f │ LHS: \" f\"                │\n07|~       │ x │ LHS: \" x\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ f │ LHS: \" f\"                │\n07|~       │ x │ LHS: \" x\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ f │ LHS: \" f\"                │\n07|~       │ x │ LHS: \" x\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---works-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ f │ LHS: \" f\"                │\n07|~       │ x │ LHS: \" x\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---works-in-edge-cases",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ LHS: \" a\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---works-in-edge-cases-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ _ ───────────────────────────┐\n07|~       │ b │ LHS: \"_b\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123332222222222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Postkeys---works-in-edge-cases-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ LHS: \" a\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Querying-keys---does-not-entirely-block-redraws",
    "content": "--|---------|---------|---------|---------|\n01|aaaa                                    \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ f │ Add hl                   │\n08|~       └──────────────────────────────┘\n09|[No Name] 1,1                           \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0111111111111111111111111111111111111111\n02|2222222222222222222222222222222222222222\n03|2222222222222222222222222222222222222222\n04|2222222222222222222222222222222222222222\n05|2222222222222222222222222222222222222222\n06|2222222234444444443333333333333333333333\n07|2222222235556777777777777777777777777773\n08|2222222233333333333333333333333333333333\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Querying-keys---does-not-entirely-block-redraws-002",
    "content": "--|---------|---------|---------|---------|\n01|aaaa                                    \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ f │ Add hl                   │\n08|~       └──────────────────────────────┘\n09|[No Name] 1,1                           \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0011111111111111111111111111111111111111\n02|2222222222222222222222222222222222222222\n03|2222222222222222222222222222222222222222\n04|2222222222222222222222222222222222222222\n05|2222222222222222222222222222222222222222\n06|2222222234444444443333333333333333333333\n07|2222222235556777777777777777777777777773\n08|2222222233333333333333333333333333333333\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Querying-keys---takes-into-account-user-supplied-clues",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ My space a               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Querying-keys---takes-into-account-user-supplied-clues-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,1                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---allows-zero-delay",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ LHS: \" a\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-have-'auto'-for-`row`-and-`col`-in-window-config",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ LHS: \" a\"                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-have-'auto'-for-`row`-and-`col`-in-window-config-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|┌ <Space> ─────────────────────┐        \n07|│ a │ LHS: \" a\"                │        \n08|└──────────────────────────────┘        \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|2333333333222222222222222222222211111111\n07|2444566666666666666666666666666211111111\n08|2222222222222222222222222222222211111111\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-have-'auto'-for-`row`-and-`col`-in-window-config-003",
    "content": "--|---------|---------|---------|---------|\n01|┌ <Space> ─────────────────────┐        \n02|│ a │ LHS: \" a\"                │        \n03|└──────────────────────────────┘        \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0111111111000000000000000000000022222222\n02|0333455555555555555555555555555066666666\n03|0000000000000000000000000000000066666666\n04|6666666666666666666666666666666666666666\n05|6666666666666666666666666666666666666666\n06|6666666666666666666666666666666666666666\n07|6666666666666666666666666666666666666666\n08|6666666666666666666666666666666666666666\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-have-'auto'-for-`row`-and-`col`-in-window-config-004",
    "content": "--|---------|---------|---------|---------|\n01|        ┌ <Space> ─────────────────────┐\n02|~       │ a │ LHS: \" a\"                │\n03|~       └──────────────────────────────┘\n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000012222222221111111111111111111111\n02|3333333314445666666666666666666666666661\n03|3333333311111111111111111111111111111111\n04|3333333333333333333333333333333333333333\n05|3333333333333333333333333333333333333333\n06|3333333333333333333333333333333333333333\n07|3333333333333333333333333333333333333333\n08|3333333333333333333333333333333333333333\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-have-`config.window.config.width='auto'`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                      ┌ <Space> ──────┐\n07|~                      │ a │ LHS: \" a\" │\n08|~                      └───────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111123333333332222222\n07|1111111111111111111111124445666666666662\n08|1111111111111111111111122222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-have-callable-`config.window.config`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                      ┌ <Space> ──────┐\n04|~                      │ a │ LHS: \" a\" │\n05|~                      │ b │ LHS: \" b\" │\n06|~                      │               │\n07|~                      │               │\n08|~                      └───────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111123333333332222222\n04|1111111111111111111111124445666666666662\n05|1111111111111111111111124445666666666662\n06|1111111111111111111111127777777777777772\n07|1111111111111111111111127777777777777772\n08|1111111111111111111111122222222222222222\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---can-work-with-small-instance-dimensions",
    "content": "-|---------|--\n1|┌ <Space> ─┐\n2|│ a │      │\n3|└──────────┘\n4|<Name] 0,0-1\n5|            \n\n-|---------|--\n1|011111111100\n2|022234444440\n3|000000000000\n4|555555555555\n5|666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---does-not-trigger-unnecessary-events",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │ +1 choice                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---highlights-group-descriptions-differently",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       ┌ <Space> ─────────────────────┐\n05|~       │ a │ Single #1                │\n06|~       │ b │ +Group                   │\n07|~       │ c │ Single #2                │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111123333333332222222222222222222222\n05|1111111124445666666666666666666666666662\n06|1111111124445777777777777777777777777772\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---highlights-next-key-with-postkeys-differently",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       ┌ <Space> ─────────────────────┐\n05|~       │ a │ Without postkeys #1      │\n06|~       │ b │ With postkey             │\n07|~       │ c │ Without postkeys #2      │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111123333333332222222222222222222222\n05|1111111124445666666666666666666666666662\n06|1111111127775666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---indicates-that-description-is-truncated",
    "content": "-|---------|---------|\n1|   ┌ <Space> ──────┐\n2|~  │ a │ A very lo…│\n3|~  └───────────────┘\n4|[No Name] 0,0-1     \n5|                    \n\n-|---------|---------|\n1|00012222222221111111\n2|33314445666666666671\n3|33311111111111111111\n4|88888888888888888888\n5|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---properly-translates-special-keys",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ <Space> │ +2 choices         │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124444444445666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---properly-translates-special-keys-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space><Space> ──────────────┐\n07|~       │ < │ +2 choices               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333333333333222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---properly-translates-special-keys-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space><Space>< ─────────────┐\n07|~       │ < │ +2 choices               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333333333333322222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---properly-translates-special-keys-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space><Space><< ────────────┐\n06|~       │ f │ LHS: \"  <<f\"             │\n07|~       │ g │ LHS: \"  <<g\"             │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333333333333332222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---reacts-to-`VimResized`",
    "content": "-|---------|---------|\n1|┌ <Space> ─────────┐\n2|│ a │              │\n3|│ b │              │\n4|│ c │              │\n5|└──────────────────┘\n6|[No Name] 0,0-1     \n7|                    \n\n-|---------|---------|\n1|01111111110000000000\n2|02223444444444444440\n3|02223444444444444440\n4|02223444444444444440\n5|00000000000000000000\n6|55555555555555555555\n7|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---reacts-to-`VimResized`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~       ┌ <Space> ─────────────────────┐\n04|~       │ a │                          │\n05|~       │ b │                          │\n06|~       │ c │                          │\n07|~       │ d │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111123333333332222222222222222222222\n04|1111111124445666666666666666666666666662\n05|1111111124445666666666666666666666666662\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-'winborder'-option",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ╭ <Space> ─────────────────────╮\n07|~       │ a │ LHS: \" a\"                │\n08|~       ╰──────────────────────────────╯\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-'winborder'-option-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ╔ <Space> ═════════════════════╗\n07|~       ║ a │ LHS: \" a\"                ║\n08|~       ╚══════════════════════════════╝\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-'winborder'-option-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       + <Space> ---------------------+\n07|~       | a │ LHS: \" a\"                |\n08|~       +------------------------------+\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`config.window.config`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ╔…tom title to check truncation╗\n07|~       ║ a │ LHS: \" a\"                ║\n08|~       ╚══════════════════════════════╝\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333333333333333333333333332\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`config.window.config`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|┌…opqrstuvwxyzabcdefgijklmnopqrstuvwxyz┐\n07|│ a │ LHS: \" a\"                        │\n08|└──────────────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|2333333333333333333333333333333333333332\n07|2444566666666666666666666666666666666662\n08|2222222222222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`config.window.delay`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`config.window.delay`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`config.window.delay`-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space>a ────────────────────┐\n06|~       │ a │ LHS: \" aa\"               │\n07|~       │ b │ LHS: \" ab\"               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333333222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       │ d │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-002",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ c │                          │\n3|~       │ d │                          │\n4|~       │ e │                          │\n5|~       │ f │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-003",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ d │                          │\n3|~       │ e │                          │\n4|~       │ f │                          │\n5|~       │ g │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-004",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ b │                          │\n3|~       │ c │                          │\n4|~       │ d │                          │\n5|~       │ e │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-005",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       │ d │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-006",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       │ d │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-007",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ c │                          │\n3|~       │ d │                          │\n4|~       │ e │                          │\n5|~       │ f │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-008",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       │ d │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n8|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-009",
    "content": "-|---------|---------|---------|---------|\n1|                                        \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n7|2222222222222222222222222222222222222222\n8|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`scroll_down`-and-`scroll_up`-in-`config.window`-010",
    "content": "-|---------|---------|---------|---------|\n1|                                        \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 0,0-1                         \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n7|2222222222222222222222222222222222222222\n8|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-`vim.b.miniclue_config`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                 ┌ <Space> ───────────┐\n07|~                 │ a │ LHS: \" a\"      │\n08|~                 └────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111112333333333222222222222\n07|1111111111111111112444566666666666666662\n08|1111111111111111112222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-tabline,-statusline,-cmdheight",
    "content": "-|---------|---------|---------|---------|\n1| [No Name]                              \n2|        ┌ <Space> ─────────────────────┐\n3|~       │ a │                          │\n4|~       │ b │                          │\n5|~       └──────────────────────────────┘\n6|[No Name] 0,0-1                         \n7|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000011111111111111111111111111111\n2|2222222203333333330000000000000000000000\n3|4444444405556777777777777777777777777770\n4|4444444405556777777777777777777777777770\n5|4444444400000000000000000000000000000000\n6|8888888888888888888888888888888888888888\n7|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-tabline,-statusline,-cmdheight-002",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       │ d │                          │\n6|~       └──────────────────────────────┘\n7|                      0,0-1         All \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-tabline,-statusline,-cmdheight-003",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       └──────────────────────────────┘\n5|[No Name] 0,0-1                         \n6|                                        \n7|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333311111111111111111111111111111111\n5|7777777777777777777777777777777777777777\n6|0000000000000000000000000000000000000000\n7|0000000000000000000000888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---respects-tabline,-statusline,-cmdheight-004",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       │ d │                          │\n6|~       └──────────────────────────────┘\n7|[No Name] 0,0-1                         \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333314445666666666666666666666666661\n6|3333333311111111111111111111111111111111\n7|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---scroll-is-not-persistent",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|~       │ e │                          │\n3|~       │ f │                          │\n4|~       │ g │ +6 choices               │\n5|~       └──────────────────────────────┘\n6|[No Name] 0,0-1                         \n7|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445777777777777777777777777771\n5|3333333311111111111111111111111111111111\n6|8888888888888888888888888888888888888888\n7|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---scroll-is-not-persistent-002",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space>g ────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       └──────────────────────────────┘\n6|[No Name] 0,0-1                         \n7|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012222222222111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333311111111111111111111111111111111\n6|7777777777777777777777777777777777777777\n7|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---scroll-is-not-persistent-003",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ _ ───────────────────────────┐\n2|~       │ a │                          │\n3|~       │ b │                          │\n4|~       │ c │                          │\n5|~       └──────────────────────────────┘\n6|[No Name] 0,0-1                         \n7|                                        \n\n-|---------|---------|---------|---------|\n1|0000000012221111111111111111111111111111\n2|3333333314445666666666666666666666666661\n3|3333333314445666666666666666666666666661\n4|3333333314445666666666666666666666666661\n5|3333333311111111111111111111111111111111\n6|7777777777777777777777777777777777777777\n7|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~       ┌ <Space> ───────────┐\n05|~       │ a │ Group a        │\n06|~       │ b │ +3 choices     │\n07|~       │ c │ +1 choice      │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111112333333333222222222222\n05|111111112444566666666666666662\n06|111111112444566666666666666662\n07|111111112444577777777777777772\n08|111111112222222222222222222222\n09|888888888888888888888888888888\n10|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-002",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~       ┌ Group a ───────────┐\n07|~       │ a │ Subgroup aa    │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112333333333222222222222\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-003",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~       ┌ Subgroup aa ───────┐\n06|~       │ a │ Do aaa         │\n07|~       │ b │ Do aab         │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111112333333333333322222222\n06|111111112444566666666666666662\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-004",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~       ┌ Group a ───────────┐\n07|~       │ a │ Subgroup aa    │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112333333333222222222222\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-005",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~       ┌ <Space>b ──────────┐\n07|~       │ a │ Subgroup ba    │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112333333333322222222222\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-006",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~       ┌ Subgroup ba ───────┐\n06|~       │ a │ Do baa         │\n07|~       │ b │ Do bab         │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111112333333333333322222222\n06|111111112444566666666666666662\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-007",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~       ┌ <Space>c ──────────┐\n07|~       │ a │ +1 choice      │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112333333333322222222222\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---uses-query-clue-as-title-008",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~       ┌ <Space>ca ─────────┐\n07|~       │ a │ Do caa         │\n08|~       └────────────────────┘\n09|[No Name] 0,0-1               \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112333333333332222222222\n07|111111112444566666666666666662\n08|111111112222222222222222222222\n09|777777777777777777777777777777\n10|888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space>a ────────────────────┐\n06|~       │ a │ LHS: \" aa\"               │\n07|~       │ b │ LHS: \" ab\"               │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333333222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-in-Command-line-window",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|[No Name] 0,0-1                         \n03|:                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ f │ LHS: \" f\"                │\n08|~       └──────────────────────────────┘\n09|[Command Line] 1,0-1                    \n10|:                                       \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2333333333333333333333333333333333333333\n04|2222222222222222222222222222222222222222\n05|2222222222222222222222222222222222222222\n06|2222222245555555554444444444444444444444\n07|2222222246667888888888888888888888888884\n08|2222222244444444444444444444444444444444\n09|9999999999999999999999999999999999999999\n10|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-in-Command-line-window-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|[No Name] 0,0-1                         \n03|:                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[Command Line] 1,0-1                    \n10|:                                       \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2333333333333333333333333333333333333333\n04|2222222222222222222222222222222222222222\n05|2222222222222222222222222222222222222222\n06|2222222222222222222222222222222222222222\n07|2222222222222222222222222222222222222222\n08|2222222222222222222222222222222222222222\n09|4444444444444444444444444444444444444444\n10|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-with-multibyte-characters",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~        ┌ <Space> ────────────────────┐\n03|~        │ f │ Single-byte #1          │\n04|~        │ y │ Single-byte #2          │\n05|~        │ ф │ Не англомовний опис     │\n06|~        │ ы │ Тест на коректну ширину │\n07|~        │ э │ Многобайтовая группа    │\n08|~        └─────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111112333333333222222222222222222222\n03|1111111112444566666666666666666666666662\n04|1111111112444566666666666666666666666662\n05|1111111112444566666666666666666666666662\n06|1111111112444566666666666666666666666662\n07|1111111112444577777777777777777777777772\n08|1111111112222222222222222222222222222222\n09|8888888888888888888888888888888888888888\n10|9999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-with-multibyte-characters-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                         ┌…вая группа ┐\n06|~                         │ ю │ фыва   │\n07|~                         │ я │ йцукен │\n08|~                         └────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111123333333333332\n06|1111111111111111111111111124445666666662\n07|1111111111111111111111111124445666666662\n08|1111111111111111111111111122222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---Showing-keys---works-with-small-available-dimensions",
    "content": "-|---------|---------|---------|---------|\n1|        ┌ <Space> ─────────────────────┐\n2|        │ a │                          │\n3|        └──────────────────────────────┘\n4|                                        \n5|                      0,0-1         All \n\n-|---------|---------|---------|---------|\n1|0000000012222222221111111111111111111111\n2|0000000013334555555555555555555555555551\n3|0000000011111111111111111111111111111111\n4|0000000000000000000000000000000000000000\n5|0000000000000000000000666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---ensure_all_triggers()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ a │ LHS: \" a\"                │\n07|~       │ b │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---ensure_all_triggers()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ a │ LHS: \" a\"                │\n07|~       │ c │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---ensure_buf_triggers()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~       ┌ <Space> ─────────────────────┐\n06|~       │ a │ LHS: \" a\"                │\n07|~       │ b │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111123333333332222222222222222222222\n06|1111111124445666666666666666666666666662\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---builtin_completion()---works",
    "content": "--|---------|---------|---------|---------|-----\n01|                                             \n02|~                                            \n03|~  ┌ <C-X> ─────────────────────────────────┐\n04|~  │ s     │ Spelling suggestions           │\n05|~  │ <C-]> │ Tags                           │\n06|~  │ <C-D> │ Defined identifiers            │\n07|~  │ <C-E> │ Scroll up                      │\n08|~  │ <C-F> │ File names                     │\n09|~  │ <C-K> │ Identifiers from dictionary    │\n10|~  │ <C-L> │ Whole lines                    │\n11|~  │ <C-N> │ Next completion                │\n12|~  │ <C-O> │ Omni completion                │\n13|~  │ <C-P> │ Previous completion            │\n14|~  │ <C-S> │ Spelling suggestions           │\n15|~  │ <C-T> │ Identifiers from thesaurus     │\n16|~  │ <C-U> │ With 'completefunc'            │\n17|~  │ <C-V> │ Like in command line           │\n18|~  │ <C-Y> │ Scroll down                    │\n19|~  │ <C-Z> │ Stop completion                │\n20|~  │ <Tab> │ Identifiers                    │\n21|~  └────────────────────────────────────────┘\n22|[No Name] 0,1                                \n23|-- INSERT --                                 \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111\n03|111233333332222222222222222222222222222222222\n04|111244444445666666666666666666666666666666662\n05|111244444445666666666666666666666666666666662\n06|111244444445666666666666666666666666666666662\n07|111244444445666666666666666666666666666666662\n08|111244444445666666666666666666666666666666662\n09|111244444445666666666666666666666666666666662\n10|111244444445666666666666666666666666666666662\n11|111244444445666666666666666666666666666666662\n12|111244444445666666666666666666666666666666662\n13|111244444445666666666666666666666666666666662\n14|111244444445666666666666666666666666666666662\n15|111244444445666666666666666666666666666666662\n16|111244444445666666666666666666666666666666662\n17|111244444445666666666666666666666666666666662\n18|111244444445666666666666666666666666666666662\n19|111244444445666666666666666666666666666666662\n20|111244444445666666666666666666666666666666662\n21|111222222222222222222222222222222222222222222\n22|777777777777777777777777777777777777777777777\n23|888888888888999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---g()---works",
    "content": "--|---------|---------|---------|---------|---------|-----\n01|                                                       \n02|~  ┌ g ───────────────────────────────────────────────┐\n03|~  │ 0     │ Go to leftmost visible column            │\n04|~  │ 8     │ Print hex value of char under cursor     │\n05|~  │ a     │ Print ascii value                        │\n06|~  │ c     │ Toggle comment                           │\n07|~  │ D     │ Go to definition in file                 │\n08|~  │ d     │ Go to definition in function             │\n09|~  │ E     │ Go backwards to end of previous WORD     │\n10|~  │ e     │ Go backwards to end of previous word     │\n11|~  │ F     │ Edit file under cursor + jump line       │\n12|~  │ f     │ Edit file under cursor                   │\n13|~  │ g     │ Go to line (def: first)                  │\n14|~  │ H     │ Start Select line mode                   │\n15|~  │ h     │ Start Select mode                        │\n16|~  │ I     │ Start Insert at column 1                 │\n17|~  │ i     │ Start Insert where it stopped            │\n18|~  │ J     │ Join lines without extra spaces          │\n19|~  │ j     │ Go down by screen lines                  │\n20|~  │ k     │ Go up by screen lines                    │\n21|~  │ M     │ Go to middle of text line                │\n22|~  │ m     │ Go to middle of screen line              │\n23|~  │ N     │ Select previous search match             │\n24|~  │ n     │ Select next search match                 │\n25|~  │ O     │ vim.lsp.buf.document_symbol()            │\n26|~  │ o     │ Go to byte                               │\n27|~  │ P     │ Put text before cursor + stay after it   │\n28|~  │ p     │ Put text after cursor + stay after it    │\n29|~  │ Q     │ Switch to \"Ex\" mode                      │\n30|~  │ q     │ Format text (operator)                   │\n31|~  │ R     │ Enter Virtual Replace mode               │\n32|~  │ r     │ +LSP                                     │\n33|~  │ s     │ Sleep                                    │\n34|~  │ T     │ Go to previous tabpage                   │\n35|~  │ t     │ Go to next tabpage                       │\n36|~  │ U     │ Make uppercase (operator)                │\n37|~  │ u     │ Make lowercase (operator)                │\n38|~  │ V     │ Avoid reselect                           │\n39|~  │ v     │ Reselect previous Visual area            │\n40|~  │ w     │ Format text + keep cursor (operator)     │\n41|~  │ x     │ Opens filepath or URI under cursor with …│\n42|~  │ <C-]> │ `:tjump` to tag under cursor             │\n43|~  │ <C-A> │ Dump a memory profile                    │\n44|~  │ <C-G> │ Show information about cursor            │\n45|~  │ <C-H> │ Start Select block mode                  │\n46|~  │ <Tab> │ Go to last accessed tabpage              │\n47|~  │ #     │ Search backwards word under cursor       │\n48|~  │ $     │ Go to rightmost visible column           │\n49|~  │ %     │ Cycle through matching groups            │\n50|~  │ &     │ Repeat last `:s` on all lines            │\n51|~  │ '     │ Jump to mark (don't affect jumplist)     │\n52|~  │ *     │ Search word under cursor                 │\n53|~  │ +     │ Go to newer text state                   │\n54|~  │ ,     │ Go to newer position in change list      │\n55|~  │ -     │ Go to older text state                   │\n56|~  │ ;     │ Go to older position in change list      │\n57|~  │ <     │ Display previous command output          │\n58|~  │ ?     │ Rot13 encode (operator)                  │\n59|~  │ @     │ Call 'operatorfunc' (operator)           │\n60|~  │ ]     │ `:tselect` tag under cursor              │\n61|~  │ ^     │ Go to leftmost visible non-whitespace    │\n62|~  │ _     │ Go to lower line                         │\n63|~  │ `     │ Jump to mark (don't affect jumplist)     │\n64|~  │ ~     │ Swap case (operator)                     │\n65|~  └──────────────────────────────────────────────────┘\n66|[No Name] 0,0-1                                        \n67|                                                       \n\n--|---------|---------|---------|---------|---------|-----\n01|0000000000000000000000000000000000000000000000000000000\n02|1112333222222222222222222222222222222222222222222222222\n03|1112444444456666666666666666666666666666666666666666662\n04|1112444444456666666666666666666666666666666666666666662\n05|1112444444456666666666666666666666666666666666666666662\n06|1112444444457777777777777777777777777777777777777777772\n07|1112444444456666666666666666666666666666666666666666662\n08|1112444444456666666666666666666666666666666666666666662\n09|1112444444456666666666666666666666666666666666666666662\n10|1112444444456666666666666666666666666666666666666666662\n11|1112444444456666666666666666666666666666666666666666662\n12|1112444444456666666666666666666666666666666666666666662\n13|1112444444456666666666666666666666666666666666666666662\n14|1112444444456666666666666666666666666666666666666666662\n15|1112444444456666666666666666666666666666666666666666662\n16|1112444444456666666666666666666666666666666666666666662\n17|1112444444456666666666666666666666666666666666666666662\n18|1112444444456666666666666666666666666666666666666666662\n19|1112444444456666666666666666666666666666666666666666662\n20|1112444444456666666666666666666666666666666666666666662\n21|1112444444456666666666666666666666666666666666666666662\n22|1112444444456666666666666666666666666666666666666666662\n23|1112444444456666666666666666666666666666666666666666662\n24|1112444444456666666666666666666666666666666666666666662\n25|1112444444456666666666666666666666666666666666666666662\n26|1112444444456666666666666666666666666666666666666666662\n27|1112444444456666666666666666666666666666666666666666662\n28|1112444444456666666666666666666666666666666666666666662\n29|1112444444456666666666666666666666666666666666666666662\n30|1112444444456666666666666666666666666666666666666666662\n31|1112444444456666666666666666666666666666666666666666662\n32|1112444444457777777777777777777777777777777777777777772\n33|1112444444456666666666666666666666666666666666666666662\n34|1112444444456666666666666666666666666666666666666666662\n35|1112444444456666666666666666666666666666666666666666662\n36|1112444444456666666666666666666666666666666666666666662\n37|1112444444456666666666666666666666666666666666666666662\n38|1112444444456666666666666666666666666666666666666666662\n39|1112444444456666666666666666666666666666666666666666662\n40|1112444444456666666666666666666666666666666666666666662\n41|1112444444456666666666666666666666666666666666666666682\n42|1112444444456666666666666666666666666666666666666666662\n43|1112444444456666666666666666666666666666666666666666662\n44|1112444444456666666666666666666666666666666666666666662\n45|1112444444456666666666666666666666666666666666666666662\n46|1112444444456666666666666666666666666666666666666666662\n47|1112444444456666666666666666666666666666666666666666662\n48|1112444444456666666666666666666666666666666666666666662\n49|1112444444456666666666666666666666666666666666666666662\n50|1112444444456666666666666666666666666666666666666666662\n51|1112444444456666666666666666666666666666666666666666662\n52|1112444444456666666666666666666666666666666666666666662\n53|1112444444456666666666666666666666666666666666666666662\n54|1112444444456666666666666666666666666666666666666666662\n55|1112444444456666666666666666666666666666666666666666662\n56|1112444444456666666666666666666666666666666666666666662\n57|1112444444456666666666666666666666666666666666666666662\n58|1112444444456666666666666666666666666666666666666666662\n59|1112444444456666666666666666666666666666666666666666662\n60|1112444444456666666666666666666666666666666666666666662\n61|1112444444456666666666666666666666666666666666666666662\n62|1112444444456666666666666666666666666666666666666666662\n63|1112444444456666666666666666666666666666666666666666662\n64|1112444444456666666666666666666666666666666666666666662\n65|1112222222222222222222222222222222222222222222222222222\n66|9999999999999999999999999999999999999999999999999999999\n67|:::::::::::::::::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---g()---works-002",
    "content": "--|---------|---------|---------|---------|---------|-----\n01|                                                       \n02|~  ┌ g ───────────────────────────────────────────────┐\n03|~  │ c     │ Toggle comment                           │\n04|~  │ f     │ Edit selected file                       │\n05|~  │ J     │ Join selected lines without extra spaces │\n06|~  │ q     │ Format selection                         │\n07|~  │ r     │ +LSP                                     │\n08|~  │ V     │ Avoid reselect                           │\n09|~  │ w     │ Format selection + keep cursor           │\n10|~  │ x     │ Opens filepath or URI under cursor with …│\n11|~  │ <C-]> │ `:tjump` to selected tag                 │\n12|~  │ <C-A> │ Increment with compound                  │\n13|~  │ <C-G> │ Show information about selection         │\n14|~  │ <C-X> │ Decrement with compound                  │\n15|~  │ ?     │ Rot13 encode selection                   │\n16|~  │ ]     │ `:tselect` selected tag                  │\n17|~  └──────────────────────────────────────────────────┘\n18|[No Name] 0,0-1                                        \n19|-- VISUAL --                                1          \n\n--|---------|---------|---------|---------|---------|-----\n01|0000000000000000000000000000000000000000000000000000000\n02|1112333222222222222222222222222222222222222222222222222\n03|1112444444456666666666666666666666666666666666666666662\n04|1112444444456666666666666666666666666666666666666666662\n05|1112444444456666666666666666666666666666666666666666662\n06|1112444444456666666666666666666666666666666666666666662\n07|1112444444457777777777777777777777777777777777777777772\n08|1112444444456666666666666666666666666666666666666666662\n09|1112444444456666666666666666666666666666666666666666662\n10|1112444444456666666666666666666666666666666666666666682\n11|1112444444456666666666666666666666666666666666666666662\n12|1112444444456666666666666666666666666666666666666666662\n13|1112444444456666666666666666666666666666666666666666662\n14|1112444444456666666666666666666666666666666666666666662\n15|1112444444456666666666666666666666666666666666666666662\n16|1112444444456666666666666666666666666666666666666666662\n17|1112222222222222222222222222222222222222222222222222222\n18|9999999999999999999999999999999999999999999999999999999\n19|::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ ' ──────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123332222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-002",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ g' ─────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123333222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-003",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ ` ──────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123332222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-004",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ g` ─────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123333222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-005",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ ' ──────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|-- VISUAL --                         1          \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123332222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-006",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ g' ─────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|-- VISUAL --                         1          \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123333222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-007",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ ` ──────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|-- VISUAL --                         1          \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123332222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---marks()---works-008",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ g` ─────────────────────────────────────────┐\n05|~│ \" │ Latest exited position                  │\n06|~│ ' │ Line before jump                        │\n07|~│ ( │ Start of sentence                       │\n08|~│ ) │ End of sentence                         │\n09|~│ . │ Latest change                           │\n10|~│ < │ Start of latest visual selection        │\n11|~│ > │ End of latest visual selection          │\n12|~│ [ │ Start of latest changed or yanked text  │\n13|~│ ] │ End of latest changed or yanked text    │\n14|~│ ^ │ Latest insert position                  │\n15|~│ ` │ Position before jump                    │\n16|~│ { │ Start of paragraph                      │\n17|~│ } │ End of paragraph                        │\n18|~└─────────────────────────────────────────────┘\n19|[No Name] 0,0-1                                 \n20|-- VISUAL --                         1          \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123333222222222222222222222222222222222222222222\n05|124445666666666666666666666666666666666666666662\n06|124445666666666666666666666666666666666666666662\n07|124445666666666666666666666666666666666666666662\n08|124445666666666666666666666666666666666666666662\n09|124445666666666666666666666666666666666666666662\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|122222222222222222222222222222222222222222222222\n19|777777777777777777777777777777777777777777777777\n20|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---respects-`opts.show_contents`",
    "content": "--|---------|---------|---------|-----\n01|                                   \n02|bbb                                \n03|~  ┌ \" ───────────────────────────┐\n04|~  │ 0 │ \"bbb\"                    │\n05|~  │ 1 │                          │\n06|~  │ 2 │                          │\n07|~  │ 3 │                          │\n08|~  │ 4 │                          │\n09|~  │ 5 │                          │\n10|~  │ 6 │                          │\n11|~  │ 7 │                          │\n12|~  │ 8 │                          │\n13|~  │ 9 │                          │\n14|~  │ a │ \"aaa\"                    │\n15|~  │ b │                          │\n16|~  │ c │                          │\n17|~  │ d │                          │\n18|~  │ e │                          │\n19|~  │ f │                          │\n20|~  │ g │                          │\n21|~  │ h │                          │\n22|~  │ i │                          │\n23|~  │ j │                          │\n24|~  │ k │                          │\n25|~  │ l │                          │\n26|~  │ m │                          │\n27|~  │ n │                          │\n28|~  │ o │                          │\n29|~  │ p │                          │\n30|~  │ q │                          │\n31|~  │ r │                          │\n32|~  │ s │                          │\n33|~  │ t │                          │\n34|~  │ u │                          │\n35|~  │ v │                          │\n36|~  │ w │                          │\n37|~  │ x │ \"aaa\\nbbb\\n\"             │\n38|~  │ y │                          │\n39|~  │ z │                          │\n40|~  │ \" │ \"aaa\"                    │\n41|~  │ # │                          │\n42|~  │ % │                          │\n43|~  │ * │                          │\n44|~  │ + │                          │\n45|~  │ - │ \"aaa\"                    │\n46|~  │ . │                          │\n47|~  │ / │                          │\n48|~  │ : │                          │\n49|~  │ = │ Result of expression     │\n50|~  └──────────────────────────────┘\n51|[No Name] 1,0-1                    \n52|                                   \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|00000000000000000000000000000000000\n03|11123332222222222222222222222222222\n04|11124445666666666666666666666666662\n05|11124445666666666666666666666666662\n06|11124445666666666666666666666666662\n07|11124445666666666666666666666666662\n08|11124445666666666666666666666666662\n09|11124445666666666666666666666666662\n10|11124445666666666666666666666666662\n11|11124445666666666666666666666666662\n12|11124445666666666666666666666666662\n13|11124445666666666666666666666666662\n14|11124445666666666666666666666666662\n15|11124445666666666666666666666666662\n16|11124445666666666666666666666666662\n17|11124445666666666666666666666666662\n18|11124445666666666666666666666666662\n19|11124445666666666666666666666666662\n20|11124445666666666666666666666666662\n21|11124445666666666666666666666666662\n22|11124445666666666666666666666666662\n23|11124445666666666666666666666666662\n24|11124445666666666666666666666666662\n25|11124445666666666666666666666666662\n26|11124445666666666666666666666666662\n27|11124445666666666666666666666666662\n28|11124445666666666666666666666666662\n29|11124445666666666666666666666666662\n30|11124445666666666666666666666666662\n31|11124445666666666666666666666666662\n32|11124445666666666666666666666666662\n33|11124445666666666666666666666666662\n34|11124445666666666666666666666666662\n35|11124445666666666666666666666666662\n36|11124445666666666666666666666666662\n37|11124445666666666666666666666666662\n38|11124445666666666666666666666666662\n39|11124445666666666666666666666666662\n40|11124445666666666666666666666666662\n41|11124445666666666666666666666666662\n42|11124445666666666666666666666666662\n43|11124445666666666666666666666666662\n44|11124445666666666666666666666666662\n45|11124445666666666666666666666666662\n46|11124445666666666666666666666666662\n47|11124445666666666666666666666666662\n48|11124445666666666666666666666666662\n49|11124445666666666666666666666666662\n50|11122222222222222222222222222222222\n51|77777777777777777777777777777777777\n52|88888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ \" ──────────────────────────────────────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,0-1                                 \n25|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123332222222222222222222222222222222222222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-002",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ \" ──────────────────────────────────────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,0-1                                 \n25|-- VISUAL --                         1          \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123332222222222222222222222222222222222222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-003",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~┌ <C-R> ──────────────────────────────────────┐\n07|~│ 0     │ Latest yank                         │\n08|~│ 1     │ Latest big delete                   │\n09|~│ <C-O> │ +Insert literally + not auto-indent │\n10|~│ <C-P> │ +Insert + fix indent                │\n11|~│ <C-R> │ +Insert literally                   │\n12|~│ \"     │ Default register                    │\n13|~│ #     │ Alternate buffer                    │\n14|~│ %     │ Name of the current file            │\n15|~│ *     │ Selection clipboard                 │\n16|~│ +     │ System clipboard                    │\n17|~│ -     │ Latest small delete                 │\n18|~│ .     │ Latest inserted text                │\n19|~│ /     │ Latest search pattern               │\n20|~│ :     │ Latest executed command             │\n21|~│ =     │ Result of expression                │\n22|~│ _     │ Black hole                          │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,1                                   \n25|-- INSERT --                                    \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|123333333222222222222222222222222222222222222222\n07|124444444566666666666666666666666666666666666662\n08|124444444566666666666666666666666666666666666662\n09|124444444577777777777777777777777777777777777772\n10|124444444577777777777777777777777777777777777772\n11|124444444577777777777777777777777777777777777772\n12|124444444566666666666666666666666666666666666662\n13|124444444566666666666666666666666666666666666662\n14|124444444566666666666666666666666666666666666662\n15|124444444566666666666666666666666666666666666662\n16|124444444566666666666666666666666666666666666662\n17|124444444566666666666666666666666666666666666662\n18|124444444566666666666666666666666666666666666662\n19|124444444566666666666666666666666666666666666662\n20|124444444566666666666666666666666666666666666662\n21|124444444566666666666666666666666666666666666662\n22|124444444566666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|888888888888888888888888888888888888888888888888\n25|999999999999::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-004",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ +Insert literally + not auto-indent ────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,1                                   \n25|-- INSERT --                                    \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123333333333333333333333333333333333333222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-005",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ +Insert + fix indent ───────────────────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,1                                   \n25|-- INSERT --                                    \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123333333333333333333333222222222222222222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-006",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ +Insert literally ──────────────────────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,1                                   \n25|-- INSERT --                                    \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123333333333333333333222222222222222222222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-007",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~┌ <C-R> ──────────────────────────────────────┐\n08|~│ 0     │ Latest yank                         │\n09|~│ 1     │ Latest big delete                   │\n10|~│ <C-O> │ +Insert literally                   │\n11|~│ <C-R> │ +Insert literally                   │\n12|~│ \"     │ Default register                    │\n13|~│ #     │ Alternate buffer                    │\n14|~│ %     │ Name of the current file            │\n15|~│ *     │ Selection clipboard                 │\n16|~│ +     │ System clipboard                    │\n17|~│ -     │ Latest small delete                 │\n18|~│ .     │ Latest inserted text                │\n19|~│ /     │ Latest search pattern               │\n20|~│ :     │ Latest executed command             │\n21|~│ =     │ Result of expression                │\n22|~│ _     │ Black hole                          │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,0-1                                 \n25|:                                               \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|123333333222222222222222222222222222222222222222\n08|124444444566666666666666666666666666666666666662\n09|124444444566666666666666666666666666666666666662\n10|124444444577777777777777777777777777777777777772\n11|124444444577777777777777777777777777777777777772\n12|124444444566666666666666666666666666666666666662\n13|124444444566666666666666666666666666666666666662\n14|124444444566666666666666666666666666666666666662\n15|124444444566666666666666666666666666666666666662\n16|124444444566666666666666666666666666666666666662\n17|124444444566666666666666666666666666666666666662\n18|124444444566666666666666666666666666666666666662\n19|124444444566666666666666666666666666666666666662\n20|124444444566666666666666666666666666666666666662\n21|124444444566666666666666666666666666666666666662\n22|124444444566666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|888888888888888888888888888888888888888888888888\n25|999999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-008",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ +Insert literally ──────────────────────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,0-1                                 \n25|:                                               \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123333333333333333333222222222222222222222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---registers()---works-009",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~                                               \n05|~                                               \n06|~                                               \n07|~                                               \n08|~                                               \n09|~┌ +Insert literally ──────────────────────────┐\n10|~│ 0 │ Latest yank                             │\n11|~│ 1 │ Latest big delete                       │\n12|~│ \" │ Default register                        │\n13|~│ # │ Alternate buffer                        │\n14|~│ % │ Name of the current file                │\n15|~│ * │ Selection clipboard                     │\n16|~│ + │ System clipboard                        │\n17|~│ - │ Latest small delete                     │\n18|~│ . │ Latest inserted text                    │\n19|~│ / │ Latest search pattern                   │\n20|~│ : │ Latest executed command                 │\n21|~│ = │ Result of expression                    │\n22|~│ _ │ Black hole                              │\n23|~└─────────────────────────────────────────────┘\n24|[No Name] 0,0-1                                 \n25|:                                               \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111\n09|123333333333333333333222222222222222222222222222\n10|124445666666666666666666666666666666666666666662\n11|124445666666666666666666666666666666666666666662\n12|124445666666666666666666666666666666666666666662\n13|124445666666666666666666666666666666666666666662\n14|124445666666666666666666666666666666666666666662\n15|124445666666666666666666666666666666666666666662\n16|124445666666666666666666666666666666666666666662\n17|124445666666666666666666666666666666666666666662\n18|124445666666666666666666666666666666666666666662\n19|124445666666666666666666666666666666666666666662\n20|124445666666666666666666666666666666666666666662\n21|124445666666666666666666666666666666666666666662\n22|124445666666666666666666666666666666666666666662\n23|122222222222222222222222222222222222222222222222\n24|777777777777777777777777777777777777777777777777\n25|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---square_brackets()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|------\n01|                                                                  \n02|┌ [ ─────────────────────────────────────────────────────────────┐\n03|│ A       │ :rewind                                              │\n04|│ a       │ :previous                                            │\n05|│ B       │ :brewind                                             │\n06|│ b       │ :bprevious                                           │\n07|│ c       │ Go to previous change                                │\n08|│ D       │ Jump to the first diagnostic in the current buffer   │\n09|│ d       │ Jump to the previous diagnostic in the current buffer│\n10|│ f       │ Edit file under cursor                               │\n11|│ I       │ Show lines with cursor word                          │\n12|│ i       │ Show first line with cursor word                     │\n13|│ L       │ :lrewind                                             │\n14|│ l       │ :lprevious                                           │\n15|│ M       │ Go to previous method end                            │\n16|│ m       │ Go to previous method start                          │\n17|│ P       │ Paste with current indent                            │\n18|│ p       │ Paste with current indent                            │\n19|│ Q       │ :crewind                                             │\n20|│ q       │ :cprevious                                           │\n21|│ s       │ Go to previous misspelled word                       │\n22|│ T       │ :trewind                                             │\n23|│ t       │ :tprevious                                           │\n24|│ z       │ Go to current open fold start                        │\n25|│ <C-D>   │ Go to first macro def with cursor word               │\n26|│ <C-L>   │ :lpfile                                              │\n27|│ <C-Q>   │ :cpfile                                              │\n28|│ <C-T>   │ :ptprevious                                          │\n29|│ <Space> │ Add empty line above cursor                          │\n30|│ <Tab>   │ Go to first match with cursor word                   │\n31|│ #       │ Go to previous unmatched #if/#else/#ifdef            │\n32|│ %       │                                                      │\n33|│ '       │ Go to previous mark, first non-blank                 │\n34|│ (       │ Go to previous unmatched '('                         │\n35|│ *       │ Go to previous C comment start                       │\n36|│ /       │ Go to previous C comment start                       │\n37|│ [       │ Go to previous section                               │\n38|│ ]       │ Go to previous SECTION                               │\n39|│ `       │ Go to previous mark                                  │\n40|│ {       │ Go to previous unmatched '{'                         │\n41|└────────────────────────────────────────────────────────────────┘\n42|[No Name] 0,0-1                                                   \n43|                                                                  \n\n--|---------|---------|---------|---------|---------|---------|------\n01|000000000000000000000000000000000000000000000000000000000000000000\n02|122211111111111111111111111111111111111111111111111111111111111111\n03|133333333345555555555555555555555555555555555555555555555555555551\n04|133333333345555555555555555555555555555555555555555555555555555551\n05|133333333345555555555555555555555555555555555555555555555555555551\n06|133333333345555555555555555555555555555555555555555555555555555551\n07|133333333345555555555555555555555555555555555555555555555555555551\n08|133333333345555555555555555555555555555555555555555555555555555551\n09|133333333345555555555555555555555555555555555555555555555555555551\n10|133333333345555555555555555555555555555555555555555555555555555551\n11|133333333345555555555555555555555555555555555555555555555555555551\n12|133333333345555555555555555555555555555555555555555555555555555551\n13|133333333345555555555555555555555555555555555555555555555555555551\n14|133333333345555555555555555555555555555555555555555555555555555551\n15|133333333345555555555555555555555555555555555555555555555555555551\n16|133333333345555555555555555555555555555555555555555555555555555551\n17|133333333345555555555555555555555555555555555555555555555555555551\n18|133333333345555555555555555555555555555555555555555555555555555551\n19|133333333345555555555555555555555555555555555555555555555555555551\n20|133333333345555555555555555555555555555555555555555555555555555551\n21|133333333345555555555555555555555555555555555555555555555555555551\n22|133333333345555555555555555555555555555555555555555555555555555551\n23|133333333345555555555555555555555555555555555555555555555555555551\n24|133333333345555555555555555555555555555555555555555555555555555551\n25|133333333345555555555555555555555555555555555555555555555555555551\n26|133333333345555555555555555555555555555555555555555555555555555551\n27|133333333345555555555555555555555555555555555555555555555555555551\n28|133333333345555555555555555555555555555555555555555555555555555551\n29|133333333345555555555555555555555555555555555555555555555555555551\n30|133333333345555555555555555555555555555555555555555555555555555551\n31|133333333345555555555555555555555555555555555555555555555555555551\n32|133333333345555555555555555555555555555555555555555555555555555551\n33|133333333345555555555555555555555555555555555555555555555555555551\n34|133333333345555555555555555555555555555555555555555555555555555551\n35|133333333345555555555555555555555555555555555555555555555555555551\n36|133333333345555555555555555555555555555555555555555555555555555551\n37|133333333345555555555555555555555555555555555555555555555555555551\n38|133333333345555555555555555555555555555555555555555555555555555551\n39|133333333345555555555555555555555555555555555555555555555555555551\n40|133333333345555555555555555555555555555555555555555555555555555551\n41|111111111111111111111111111111111111111111111111111111111111111111\n42|666666666666666666666666666666666666666666666666666666666666666666\n43|777777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---square_brackets()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|------\n01|                                                                  \n02|┌ ] ─────────────────────────────────────────────────────────────┐\n03|│ A       │ :last                                                │\n04|│ a       │ :next                                                │\n05|│ B       │ :blast                                               │\n06|│ b       │ :bnext                                               │\n07|│ c       │ Go to next change                                    │\n08|│ D       │ Jump to the last diagnostic in the current buffer    │\n09|│ d       │ Jump to the next diagnostic in the current buffer    │\n10|│ f       │ Edit file under cursor                               │\n11|│ I       │ Show below lines with cursor word                    │\n12|│ i       │ Show next line with cursor word                      │\n13|│ L       │ :llast                                               │\n14|│ l       │ :lnext                                               │\n15|│ M       │ Go to next method end                                │\n16|│ m       │ Go to next method start                              │\n17|│ P       │ Paste with current indent                            │\n18|│ p       │ Paste with current indent                            │\n19|│ Q       │ :clast                                               │\n20|│ q       │ :cnext                                               │\n21|│ s       │ Go to next misspelled word                           │\n22|│ T       │ :tlast                                               │\n23|│ t       │ :tnext                                               │\n24|│ z       │ Go to current open fold end                          │\n25|│ <C-D>   │ Go to next macro def with cursor word                │\n26|│ <C-L>   │ :lnfile                                              │\n27|│ <C-Q>   │ :cnfile                                              │\n28|│ <C-T>   │ :ptnext                                              │\n29|│ <Space> │ Add empty line below cursor                          │\n30|│ <Tab>   │ Go to next match with cursor word                    │\n31|│ #       │ Go to next unmatched #if/#else/#ifdef                │\n32|│ %       │                                                      │\n33|│ '       │ Go to next mark, first non-blank                     │\n34|│ )       │ Go to next unmatched ')'                             │\n35|│ *       │ Go to next C comment end                             │\n36|│ /       │ Go to next C comment end                             │\n37|│ [       │ Go to next SECTION                                   │\n38|│ ]       │ Go to next section                                   │\n39|│ `       │ Go to next mark                                      │\n40|│ }       │ Go to next unmatched '}'                             │\n41|└────────────────────────────────────────────────────────────────┘\n42|[No Name] 0,0-1                                                   \n43|                                                                  \n\n--|---------|---------|---------|---------|---------|---------|------\n01|000000000000000000000000000000000000000000000000000000000000000000\n02|122211111111111111111111111111111111111111111111111111111111111111\n03|133333333345555555555555555555555555555555555555555555555555555551\n04|133333333345555555555555555555555555555555555555555555555555555551\n05|133333333345555555555555555555555555555555555555555555555555555551\n06|133333333345555555555555555555555555555555555555555555555555555551\n07|133333333345555555555555555555555555555555555555555555555555555551\n08|133333333345555555555555555555555555555555555555555555555555555551\n09|133333333345555555555555555555555555555555555555555555555555555551\n10|133333333345555555555555555555555555555555555555555555555555555551\n11|133333333345555555555555555555555555555555555555555555555555555551\n12|133333333345555555555555555555555555555555555555555555555555555551\n13|133333333345555555555555555555555555555555555555555555555555555551\n14|133333333345555555555555555555555555555555555555555555555555555551\n15|133333333345555555555555555555555555555555555555555555555555555551\n16|133333333345555555555555555555555555555555555555555555555555555551\n17|133333333345555555555555555555555555555555555555555555555555555551\n18|133333333345555555555555555555555555555555555555555555555555555551\n19|133333333345555555555555555555555555555555555555555555555555555551\n20|133333333345555555555555555555555555555555555555555555555555555551\n21|133333333345555555555555555555555555555555555555555555555555555551\n22|133333333345555555555555555555555555555555555555555555555555555551\n23|133333333345555555555555555555555555555555555555555555555555555551\n24|133333333345555555555555555555555555555555555555555555555555555551\n25|133333333345555555555555555555555555555555555555555555555555555551\n26|133333333345555555555555555555555555555555555555555555555555555551\n27|133333333345555555555555555555555555555555555555555555555555555551\n28|133333333345555555555555555555555555555555555555555555555555555551\n29|133333333345555555555555555555555555555555555555555555555555555551\n30|133333333345555555555555555555555555555555555555555555555555555551\n31|133333333345555555555555555555555555555555555555555555555555555551\n32|133333333345555555555555555555555555555555555555555555555555555551\n33|133333333345555555555555555555555555555555555555555555555555555551\n34|133333333345555555555555555555555555555555555555555555555555555551\n35|133333333345555555555555555555555555555555555555555555555555555551\n36|133333333345555555555555555555555555555555555555555555555555555551\n37|133333333345555555555555555555555555555555555555555555555555555551\n38|133333333345555555555555555555555555555555555555555555555555555551\n39|133333333345555555555555555555555555555555555555555555555555555551\n40|133333333345555555555555555555555555555555555555555555555555555551\n41|111111111111111111111111111111111111111111111111111111111111111111\n42|666666666666666666666666666666666666666666666666666666666666666666\n43|777777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---windows()---works",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~┌ <C-W> ──────────────────────────────────────┐\n04|~│ b     │ Focus bottom                        │\n05|~│ c     │ Close                               │\n06|~│ d     │ Show diagnostics under the cursor   │\n07|~│ F     │ Split + edit file name + jump       │\n08|~│ f     │ Split + edit file name              │\n09|~│ g     │ +Extra actions                      │\n10|~│ H     │ Move to very left                   │\n11|~│ h     │ Focus left                          │\n12|~│ i     │ Split + jump to declaration         │\n13|~│ J     │ Move to very bottom                 │\n14|~│ j     │ Focus down                          │\n15|~│ K     │ Move to very top                    │\n16|~│ k     │ Focus up                            │\n17|~│ L     │ Move to very right                  │\n18|~│ l     │ Focus right                         │\n19|~│ n     │ Open new                            │\n20|~│ o     │ Close all but current               │\n21|~│ P     │ Focus preview                       │\n22|~│ p     │ Focus last accessed                 │\n23|~│ q     │ Quit current                        │\n24|~│ R     │ Rotate up/left                      │\n25|~│ r     │ Rotate down/right                   │\n26|~│ s     │ Split horizontally                  │\n27|~│ T     │ Create new tabpage + move           │\n28|~│ t     │ Focus top                           │\n29|~│ v     │ Split vertically                    │\n30|~│ W     │ Focus previous                      │\n31|~│ w     │ Focus next                          │\n32|~│ x     │ Exchange windows                    │\n33|~│ z     │ Close preview                       │\n34|~│ <C-D> │ Show diagnostics under the cursor   │\n35|~│ +     │ Increase height                     │\n36|~│ -     │ Decrease height                     │\n37|~│ <     │ Decrease width                      │\n38|~│ =     │ Make windows same dimensions        │\n39|~│ >     │ Increase width                      │\n40|~│ ]     │ Split + jump to tag                 │\n41|~│ ^     │ Split + edit alternate file         │\n42|~│ _     │ Set height (def: very high)         │\n43|~│ |     │ Set width (def: very wide)          │\n44|~│ }     │ Show tag in preview                 │\n45|~└─────────────────────────────────────────────┘\n46|[No Name] 0,0-1                                 \n47|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|123333333222222222222222222222222222222222222222\n04|124444444566666666666666666666666666666666666662\n05|124444444566666666666666666666666666666666666662\n06|124444444566666666666666666666666666666666666662\n07|124444444566666666666666666666666666666666666662\n08|124444444566666666666666666666666666666666666662\n09|124444444577777777777777777777777777777777777772\n10|124444444566666666666666666666666666666666666662\n11|124444444566666666666666666666666666666666666662\n12|124444444566666666666666666666666666666666666662\n13|124444444566666666666666666666666666666666666662\n14|124444444566666666666666666666666666666666666662\n15|124444444566666666666666666666666666666666666662\n16|124444444566666666666666666666666666666666666662\n17|124444444566666666666666666666666666666666666662\n18|124444444566666666666666666666666666666666666662\n19|124444444566666666666666666666666666666666666662\n20|124444444566666666666666666666666666666666666662\n21|124444444566666666666666666666666666666666666662\n22|124444444566666666666666666666666666666666666662\n23|124444444566666666666666666666666666666666666662\n24|124444444566666666666666666666666666666666666662\n25|124444444566666666666666666666666666666666666662\n26|124444444566666666666666666666666666666666666662\n27|124444444566666666666666666666666666666666666662\n28|124444444566666666666666666666666666666666666662\n29|124444444566666666666666666666666666666666666662\n30|124444444566666666666666666666666666666666666662\n31|124444444566666666666666666666666666666666666662\n32|124444444566666666666666666666666666666666666662\n33|124444444566666666666666666666666666666666666662\n34|124444444566666666666666666666666666666666666662\n35|124444444566666666666666666666666666666666666662\n36|124444444566666666666666666666666666666666666662\n37|124444444566666666666666666666666666666666666662\n38|124444444566666666666666666666666666666666666662\n39|124444444566666666666666666666666666666666666662\n40|124444444566666666666666666666666666666666666662\n41|124444444566666666666666666666666666666666666662\n42|124444444566666666666666666666666666666666666662\n43|124444444566666666666666666666666666666666666662\n44|124444444566666666666666666666666666666666666662\n45|122222222222222222222222222222222222222222222222\n46|888888888888888888888888888888888888888888888888\n47|999999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---windows()---works-002",
    "content": "--|---------|---------|---------|---------|--------\n01|                                                \n02|~                                               \n03|~                                               \n04|~┌ +Extra actions ─────────────────────────────┐\n05|~│ F     │ New tabpage + edit file name + jump │\n06|~│ f     │ New tabpage + edit file name        │\n07|~│ T     │ Focus previous tabpage              │\n08|~│ t     │ Focus next tabpage                  │\n09|~│ <C-]> │ Split + jump to tag with `:tjump`   │\n10|~│ <Tab> │ Focus last accessed tab             │\n11|~│ ]     │ Split + list tags                   │\n12|~│ }     │ Do `:ptjump`                        │\n13|~└─────────────────────────────────────────────┘\n14|[No Name] 0,0-1                                 \n15|                                                \n\n--|---------|---------|---------|---------|--------\n01|000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111\n04|123333333333333333222222222222222222222222222222\n05|124444444566666666666666666666666666666666666662\n06|124444444566666666666666666666666666666666666662\n07|124444444566666666666666666666666666666666666662\n08|124444444566666666666666666666666666666666666662\n09|124444444566666666666666666666666666666666666662\n10|124444444566666666666666666666666666666666666662\n11|124444444566666666666666666666666666666666666662\n12|124444444566666666666666666666666666666666666662\n13|122222222222222222222222222222222222222222222222\n14|777777777777777777777777777777777777777777777777\n15|888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---z()---works",
    "content": "--|---------|---------|---------|---------|---------|-----\n01|                                                       \n02|~                                                      \n03|~┌ z ─────────────────────────────────────────────────┐\n04|~│ A │ Toggle folds recursively                       │\n05|~│ a │ Toggle fold                                    │\n06|~│ b │ Redraw at bottom                               │\n07|~│ C │ Close folds recursively                        │\n08|~│ c │ Close fold                                     │\n09|~│ D │ Delete folds recursively                       │\n10|~│ d │ Delete fold                                    │\n11|~│ E │ Eliminate all folds                            │\n12|~│ e │ Scroll to cursor on right screen side          │\n13|~│ F │ Create fold                                    │\n14|~│ f │ Create fold (operator)                         │\n15|~│ G │ Temporarily mark as correctly spelled          │\n16|~│ g │ Permanently mark as correctly spelled          │\n17|~│ H │ Scroll left half screen                        │\n18|~│ h │ Scroll left                                    │\n19|~│ i │ Toggle 'foldenable'                            │\n20|~│ j │ Move to start of next fold                     │\n21|~│ k │ Move to end of previous fold                   │\n22|~│ L │ Scroll right half screen                       │\n23|~│ l │ Scroll right                                   │\n24|~│ M │ Close all folds                                │\n25|~│ m │ Fold more                                      │\n26|~│ N │ Set 'foldenable'                               │\n27|~│ n │ Reset 'foldenable'                             │\n28|~│ O │ Open folds recursively                         │\n29|~│ o │ Open fold                                      │\n30|~│ P │ Paste without trailspace                       │\n31|~│ p │ Paste without trailspace                       │\n32|~│ R │ Open all folds                                 │\n33|~│ r │ Fold less                                      │\n34|~│ s │ Scroll to cursor on left screen side           │\n35|~│ t │ Redraw at top                                  │\n36|~│ u │ +Undo spelling commands                        │\n37|~│ v │ Open enough folds                              │\n38|~│ W │ Temporarily mark as incorrectly spelled        │\n39|~│ w │ Permanently mark as incorrectly spelled        │\n40|~│ X │ Update folds                                   │\n41|~│ x │ Update folds + open enough folds               │\n42|~│ y │ Yank without trailing spaces (operator)        │\n43|~│ z │ Redraw at center                               │\n44|~│ + │ Redraw under bottom at top                     │\n45|~│ - │ Redraw at bottom + cursor on first non-blank   │\n46|~│ . │ Redraw at center + cursor on first non-blank   │\n47|~│ = │ Show spelling suggestions                      │\n48|~│ ^ │ Redraw above top at bottom                     │\n49|~└────────────────────────────────────────────────────┘\n50|[No Name] 0,0-1                                        \n51|                                                       \n\n--|---------|---------|---------|---------|---------|-----\n01|0000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111\n03|1233322222222222222222222222222222222222222222222222222\n04|1244456666666666666666666666666666666666666666666666662\n05|1244456666666666666666666666666666666666666666666666662\n06|1244456666666666666666666666666666666666666666666666662\n07|1244456666666666666666666666666666666666666666666666662\n08|1244456666666666666666666666666666666666666666666666662\n09|1244456666666666666666666666666666666666666666666666662\n10|1244456666666666666666666666666666666666666666666666662\n11|1244456666666666666666666666666666666666666666666666662\n12|1244456666666666666666666666666666666666666666666666662\n13|1244456666666666666666666666666666666666666666666666662\n14|1244456666666666666666666666666666666666666666666666662\n15|1244456666666666666666666666666666666666666666666666662\n16|1244456666666666666666666666666666666666666666666666662\n17|1244456666666666666666666666666666666666666666666666662\n18|1244456666666666666666666666666666666666666666666666662\n19|1244456666666666666666666666666666666666666666666666662\n20|1244456666666666666666666666666666666666666666666666662\n21|1244456666666666666666666666666666666666666666666666662\n22|1244456666666666666666666666666666666666666666666666662\n23|1244456666666666666666666666666666666666666666666666662\n24|1244456666666666666666666666666666666666666666666666662\n25|1244456666666666666666666666666666666666666666666666662\n26|1244456666666666666666666666666666666666666666666666662\n27|1244456666666666666666666666666666666666666666666666662\n28|1244456666666666666666666666666666666666666666666666662\n29|1244456666666666666666666666666666666666666666666666662\n30|1244456666666666666666666666666666666666666666666666662\n31|1244456666666666666666666666666666666666666666666666662\n32|1244456666666666666666666666666666666666666666666666662\n33|1244456666666666666666666666666666666666666666666666662\n34|1244456666666666666666666666666666666666666666666666662\n35|1244456666666666666666666666666666666666666666666666662\n36|1244457777777777777777777777777777777777777777777777772\n37|1244456666666666666666666666666666666666666666666666662\n38|1244456666666666666666666666666666666666666666666666662\n39|1244456666666666666666666666666666666666666666666666662\n40|1244456666666666666666666666666666666666666666666666662\n41|1244456666666666666666666666666666666666666666666666662\n42|1244456666666666666666666666666666666666666666666666662\n43|1244456666666666666666666666666666666666666666666666662\n44|1244456666666666666666666666666666666666666666666666662\n45|1244456666666666666666666666666666666666666666666666662\n46|1244456666666666666666666666666666666666666666666666662\n47|1244456666666666666666666666666666666666666666666666662\n48|1244456666666666666666666666666666666666666666666666662\n49|1222222222222222222222222222222222222222222222222222222\n50|8888888888888888888888888888888888888888888888888888888\n51|9999999999999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---gen_clues---z()---works-002",
    "content": "--|---------|---------|---------|---------|---------|-----\n01|                                                       \n02|~                                                      \n03|~                                                      \n04|~                                                      \n05|~                                                      \n06|~┌ z ─────────────────────────────────────────────────┐\n07|~│ f │ Create fold from selection                     │\n08|~└────────────────────────────────────────────────────┘\n09|[No Name] 0,0-1                                        \n10|-- VISUAL --                                1          \n\n--|---------|---------|---------|---------|---------|-----\n01|0000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111\n06|1233322222222222222222222222222222222222222222222222222\n07|1244456666666666666666666666666666666666666666666666662\n08|1222222222222222222222222222222222222222222222222222222\n09|7777777777777777777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_clue.lua---setup()---ensures-valid-triggers-on-`LspAttach`-event",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~       ┌ <Space> ─────────────────────┐\n07|~       │ a │                          │\n08|~       └──────────────────────────────┘\n09|[No Name] 0,0-1                         \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111123333333332222222222222222222222\n07|1111111124445666666666666666666666666662\n08|1111111122222222222222222222222222222222\n09|7777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---is-not-triggered-when-wildmenu-is-visible",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05| ball               \n06| badd               \n07| balt               \n08| bNext              \n09| blast              \n10|:ball               \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|22222222222222222311\n06|44444444444444444411\n07|44444444444444444411\n08|44444444444444444411\n09|44444444444444444411\n10|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|:                   \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-002",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05| ball               \n06| badd               \n07| balt               \n08| bNext              \n09| blast              \n10|:b                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|22222222222222222311\n06|22222222222222222211\n07|22222222222222222211\n08|22222222222222222211\n09|22222222222222222211\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-003",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05| bfirst             \n06| sbfirst            \n07| tabfind            \n08| tabfirst           \n09| bufdo              \n10|:bf                 \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|22222222222222222311\n06|22222222222222222211\n07|22222222222222222211\n08|22222222222222222211\n09|22222222222222222211\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-004",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05| ball               \n06| badd               \n07| balt               \n08| bNext              \n09| blast              \n10|:b                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|22222222222222222311\n06|22222222222222222211\n07|22222222222222222211\n08|22222222222222222211\n09|22222222222222222211\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-005",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|:                   \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-different-command-types",
    "content": "--|---------|---------|\n01|aa                  \n02|aaa                 \n03|aaaa                \n04|~                   \n05|~                   \n06| a                  \n07| aaa                \n08| aa                 \n09| aaaa               \n10|/a                  \n\n--|---------|---------|\n01|01222222222222222222\n02|00022222222222222222\n03|00002222222222222222\n04|33333333333333333333\n05|33333333333333333333\n06|44444444444444444333\n07|44444444444444444333\n08|44444444444444444333\n09|44444444444444444333\n10|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-different-command-types-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aaa                 \n03|aaaa                \n04|~                   \n05|~                   \n06| a                  \n07| aa                 \n08| aaa                \n09| aaaa               \n10|?a                  \n\n--|---------|---------|\n01|00111111111111111111\n02|00011111111111111111\n03|00021111111111111111\n04|33333333333333333333\n05|33333333333333333333\n06|44444444444444444333\n07|44444444444444444333\n08|44444444444444444333\n09|44444444444444444333\n10|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-different-command-types-003",
    "content": "--|---------|---------|\n01|\"a                  \n02|aaa                 \n03|aaaa                \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|=a                  \n\n--|---------|---------|\n01|01222222222222222222\n02|11122222222222222222\n03|11112222222222222222\n04|33333333333333333333\n05|33333333333333333333\n06|33333333333333333333\n07|33333333333333333333\n08|33333333333333333333\n09|33333333333333333333\n10|45444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-different-command-types-004",
    "content": "--|---------|---------|\n01|aa                  \n02|aaa                 \n03|aaaa                \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|a                   \n\n--|---------|---------|\n01|01222222222222222222\n02|11122222222222222222\n03|11112222222222222222\n04|33333333333333333333\n05|33333333333333333333\n06|33333333333333333333\n07|33333333333333333333\n08|33333333333333333333\n09|33333333333333333333\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-edge-cases",
    "content": "--|---------|---------|\n01|Line 1              \n02|Line 2              \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~  Line             \n10|:s/L                \n\n--|---------|---------|\n01|01111111111111111111\n02|11111111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22333333333333333332\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-edge-cases-002",
    "content": "--|---------|---------|\n01|Line 1              \n02|Line 2              \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~  Line             \n10|:g/L                \n\n--|---------|---------|\n01|01111111111111111111\n02|21111111111111111111\n03|33333333333333333333\n04|33333333333333333333\n05|33333333333333333333\n06|33333333333333333333\n07|33333333333333333333\n08|33333333333333333333\n09|33444444444444444443\n10|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-in-edge-cases-003",
    "content": "--|---------|---------|\n01|Line 1              \n02|Line 2              \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~  Line             \n10|:v/L                \n\n--|---------|---------|\n01|01111111111111111111\n02|21111111111111111111\n03|33333333333333333333\n04|33333333333333333333\n05|33333333333333333333\n06|33333333333333333333\n07|33333333333333333333\n08|33333333333333333333\n09|33444444444444444443\n10|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-with-different-completion-types",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|~    ignorecase               \n10|:set ig                       \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|111122222222222222222111111111\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-with-different-completion-types-002",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~     fileA                   \n09|~     fileB                   \n10|:edit f                       \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111112222222222222222211111111\n09|111112222222222222222211111111\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autocomplete---works-with-different-completion-types-003",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~     fileA                   \n09|~     fileB                   \n10|:grep f                       \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111112222222222222222211111111\n09|111112222222222222222211111111\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│┌  1│Line 1       │\n06|│┊   │Line 2       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:1,101              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24555677777777777772\n06|24555677777777777772\n07|24555688888888888882\n08|24555677777777777772\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│    │Line 1       │\n05|│┌  2│Line 2       │\n06|│┊   │Line 3       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:2,101              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24444566666666666662\n05|27444566666666666662\n06|27444566666666666662\n07|27444588888888888882\n08|27444566666666666662\n09|27444566666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│┌  1│Line 1       │\n05|│┊   │Line 2       │\n06|│┊   │·············│\n07|│┊   │Line 99      │\n08|│└100│Line 100     │\n09|│    │Line 101     │\n10|└──────────────────┘\n11|:1,100              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24555677777777777772\n05|24555677777777777772\n06|24555688888888888882\n07|24555677777777777772\n08|24555677777777777772\n09|25555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│    │Line 1       │\n04|│┌  2│Line 2       │\n05|│┊   │Line 3       │\n06|│┊   │·············│\n07|│┊   │Line 99      │\n08|│└100│Line 100     │\n09|│    │Line 101     │\n10|└──────────────────┘\n11|:2,100              \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13333455555555555551\n04|16333455555555555551\n05|16333455555555555551\n06|16333477777777777771\n07|16333455555555555551\n08|16333455555555555551\n09|13333455555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 2        │\n04|│┌ 3│Line 3        │\n05|│┊  │Line 4        │\n06|│┊  │··············│\n07|│┊  │Line 98       │\n08|│└99│Line 99       │\n09|│   │Line 100      │\n10|└──────────────────┘\n11|:3,99               \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│  │Line 2         │\n04|│┌3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│┊ │Line 6         │\n08|│└7│Line 7         │\n09|│  │Line 8         │\n10|└──────────────────┘\n11|:3,7                \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13345555555555555551\n04|16345555555555555551\n05|16345555555555555551\n06|16345555555555555551\n07|16345555555555555551\n08|16345555555555555551\n09|13345555555555555551\n10|11111111111111111111\n11|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-007",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│  │Line 2         │\n05|│┌3│Line 3         │\n06|│┊ │Line 4         │\n07|│┊ │Line 5         │\n08|│└6│Line 6         │\n09|│  │Line 7         │\n10|└──────────────────┘\n11|:3,6                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24456666666666666662\n05|27456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-008",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│  │Line 2         │\n06|│┌3│Line 3         │\n07|│┊ │Line 4         │\n08|│└5│Line 5         │\n09|│  │Line 6         │\n10|└──────────────────┘\n11|:3,5                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-009",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 2         │\n07|│┌3│Line 3         │\n08|│└4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:3,4                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-computes-lines-to-show-010",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 2         │\n08|│🭬3│Line 3         │\n09|│  │Line 4         │\n10|└──────────────────┘\n11|:3,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-shows-window-without-border",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌  1│Line 1         \n06|┊   │Line 2         \n07|┊   │···············\n08|┊   │Line 100       \n09|└101│Line 101       \n10|:1,101              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23334555555555555555\n06|23334555555555555555\n07|23334666666666666666\n08|23334555555555555555\n09|23334555555555555555\n10|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-shows-window-without-border-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|    │Line 1         \n04|┌  2│Line 2         \n05|┊   │Line 3         \n06|┊   │···············\n07|┊   │Line 99        \n08|└100│Line 100       \n09|    │Line 101       \n10|:2,100              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22223444444444444444\n04|52223444444444444444\n05|52223444444444444444\n06|52223666666666666666\n07|52223444444444444444\n08|52223444444444444444\n09|22223444444444444444\n10|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-shows-window-without-border-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|  │Line 1           \n05|┌2│Line 2           \n06|┊ │Line 3           \n07|┊ │Line 4           \n08|└5│Line 5           \n09|  │Line 6           \n10|:2,5                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|22344444444444444444\n05|52344444444444444444\n06|52344444444444444444\n07|52344444444444444444\n08|52344444444444444444\n09|22344444444444444444\n10|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-shows-window-without-border-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|  │Line 1           \n08|🭬2│Line 2           \n09|  │Line 3           \n10|:2,2                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|22344444444444444444\n08|52344444444444444444\n09|22344444444444444444\n10|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-shows-window-without-border-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|┌  2│Line 2         \n08|┊   │···············\n09|└101│Line 101       \n10|:2,101              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|23334555555555555555\n08|23334666666666666666\n09|23334555555555555555\n10|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---correctly-shows-window-without-border-006",
    "content": "-|---------|---------|\n1|┌2│Line 2           \n2|┊ │Line 3           \n3|└4│Line 4           \n4|:2,4                \n\n-|---------|---------|\n1|01233333333333333333\n2|01233333333333333333\n3|01233333333333333333\n4|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│   │Line 1        │\n03|│   │Line 2        │\n04|│┌ 3│Line 3        │\n05|│┊  │Line 4        │\n06|│┊  │Line 5        │\n07|│┊  │··············│\n08|│┊  │Line 8        │\n09|│┊  │Line 9        │\n10|│└10│Line 10       │\n11|│   │Line 11       │\n12|│   │Line 12       │\n13|└──────────────────┘\n14|:3,10               \n\n--|---------|---------|\n01|01111110000000000000\n02|02223444444444444440\n03|02223444444444444440\n04|05223444444444444440\n05|05223444444444444440\n06|05223444444444444440\n07|05223666666666666660\n08|05223444444444444440\n09|05223444444444444440\n10|05223444444444444440\n11|02223444444444444440\n12|02223444444444444440\n13|00000000000000000000\n14|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-002",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│   │Line 1        │\n03|│   │Line 2        │\n04|│┌ 3│Line 3        │\n05|│┊  │Line 4        │\n06|│┊  │Line 5        │\n07|│┊  │··············│\n08|│┊  │Line 8        │\n09|│┊  │Line 9        │\n10|│└10│Line 10       │\n11|│   │Line 11       │\n12|└──────────────────┘\n13|:3,10               \n\n--|---------|---------|\n01|01111110000000000000\n02|02223444444444444440\n03|02223444444444444440\n04|05223444444444444440\n05|05223444444444444440\n06|05223444444444444440\n07|05223666666666666660\n08|05223444444444444440\n09|05223444444444444440\n10|05223444444444444440\n11|02223444444444444440\n12|00000000000000000000\n13|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-003",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│   │Line 2        │\n03|│┌ 3│Line 3        │\n04|│┊  │Line 4        │\n05|│┊  │Line 5        │\n06|│┊  │··············│\n07|│┊  │Line 8        │\n08|│┊  │Line 9        │\n09|│└10│Line 10       │\n10|│   │Line 11       │\n11|└──────────────────┘\n12|:3,10               \n\n--|---------|---------|\n01|01111110000000000000\n02|02223444444444444440\n03|05223444444444444440\n04|05223444444444444440\n05|05223444444444444440\n06|05223666666666666660\n07|05223444444444444440\n08|05223444444444444440\n09|05223444444444444440\n10|02223444444444444440\n11|00000000000000000000\n12|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-004",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│   │Line 2        │\n03|│┌ 3│Line 3        │\n04|│┊  │Line 4        │\n05|│┊  │Line 5        │\n06|│┊  │··············│\n07|│┊  │Line 8        │\n08|│┊  │Line 9        │\n09|│└10│Line 10       │\n10|└──────────────────┘\n11|:3,10               \n\n--|---------|---------|\n01|01111110000000000000\n02|02223444444444444440\n03|05223444444444444440\n04|05223444444444444440\n05|05223444444444444440\n06|05223666666666666660\n07|05223444444444444440\n08|05223444444444444440\n09|05223444444444444440\n10|00000000000000000000\n11|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-005",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│┌ 3│Line 3        │\n03|│┊  │Line 4        │\n04|│┊  │Line 5        │\n05|│┊  │··············│\n06|│┊  │Line 8        │\n07|│┊  │Line 9        │\n08|│└10│Line 10       │\n09|└──────────────────┘\n10|:3,10               \n\n--|---------|---------|\n01|01111110000000000000\n02|02334555555555555550\n03|02334555555555555550\n04|02334555555555555550\n05|02334666666666666660\n06|02334555555555555550\n07|02334555555555555550\n08|02334555555555555550\n09|00000000000000000000\n10|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-006",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌ 3│Line 3        │\n3|│┊  │Line 4        │\n4|│┊  │··············│\n5|│┊  │Line 8        │\n6|│┊  │Line 9        │\n7|│└10│Line 10       │\n8|└──────────────────┘\n9|:3,10               \n\n-|---------|---------|\n1|01111110000000000000\n2|02334555555555555550\n3|02334555555555555550\n4|02334666666666666660\n5|02334555555555555550\n6|02334555555555555550\n7|02334555555555555550\n8|00000000000000000000\n9|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-007",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌ 3│Line 3        │\n3|│┊  │Line 4        │\n4|│┊  │··············│\n5|│┊  │Line 9        │\n6|│└10│Line 10       │\n7|└──────────────────┘\n8|:3,10               \n\n-|---------|---------|\n1|01111110000000000000\n2|02334555555555555550\n3|02334555555555555550\n4|02334666666666666660\n5|02334555555555555550\n6|02334555555555555550\n7|00000000000000000000\n8|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-008",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌ 3│Line 3        │\n3|│┊  │··············│\n4|│┊  │Line 9        │\n5|│└10│Line 10       │\n6|└──────────────────┘\n7|:3,10               \n\n-|---------|---------|\n1|01111110000000000000\n2|02334555555555555550\n3|02334666666666666660\n4|02334555555555555550\n5|02334555555555555550\n6|00000000000000000000\n7|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-009",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌ 3│Line 3        │\n3|│┊  │··············│\n4|│└10│Line 10       │\n5|└──────────────────┘\n6|:3,10               \n\n-|---------|---------|\n1|01111110000000000000\n2|02334555555555555550\n3|02334666666666666660\n4|02334555555555555550\n5|00000000000000000000\n6|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-010",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │···············│\n4|└──────────────────┘\n5|:3,10               \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|00000000000000000000\n5|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-011",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|└──────────────────┘\n4|:3,10               \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|00000000000000000000\n4|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-012",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 1         │\n03|│  │Line 2         │\n04|│┌3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│┊ │Line 6         │\n08|│┊ │Line 7         │\n09|│└8│Line 8         │\n10|│  │Line 9         │\n11|│  │Line 10        │\n12|└──────────────────┘\n13|:3,8                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|02234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|05234444444444444440\n09|05234444444444444440\n10|02234444444444444440\n11|02234444444444444440\n12|00000000000000000000\n13|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-013",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 1         │\n03|│  │Line 2         │\n04|│┌3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│┊ │Line 6         │\n08|│┊ │Line 7         │\n09|│└8│Line 8         │\n10|│  │Line 9         │\n11|└──────────────────┘\n12|:3,8                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|02234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|05234444444444444440\n09|05234444444444444440\n10|02234444444444444440\n11|00000000000000000000\n12|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-014",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 2         │\n03|│┌3│Line 3         │\n04|│┊ │Line 4         │\n05|│┊ │Line 5         │\n06|│┊ │Line 6         │\n07|│┊ │Line 7         │\n08|│└8│Line 8         │\n09|│  │Line 9         │\n10|└──────────────────┘\n11|:3,8                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|05234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|05234444444444444440\n09|02234444444444444440\n10|00000000000000000000\n11|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-015",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 2         │\n03|│┌3│Line 3         │\n04|│┊ │Line 4         │\n05|│┊ │Line 5         │\n06|│┊ │Line 6         │\n07|│┊ │Line 7         │\n08|│└8│Line 8         │\n09|└──────────────────┘\n10|:3,8                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|05234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|05234444444444444440\n09|00000000000000000000\n10|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-016",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │Line 4         │\n4|│┊ │Line 5         │\n5|│┊ │Line 6         │\n6|│┊ │Line 7         │\n7|│└8│Line 8         │\n8|└──────────────────┘\n9|:3,8                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02345555555555555550\n4|02345555555555555550\n5|02345555555555555550\n6|02345555555555555550\n7|02345555555555555550\n8|00000000000000000000\n9|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-017",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │Line 4         │\n4|│┊ │···············│\n5|│┊ │Line 7         │\n6|│└8│Line 8         │\n7|└──────────────────┘\n8|:3,8                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02345555555555555550\n4|02346666666666666660\n5|02345555555555555550\n6|02345555555555555550\n7|00000000000000000000\n8|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-018",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │···············│\n4|│┊ │Line 7         │\n5|│└8│Line 8         │\n6|└──────────────────┘\n7|:3,8                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|02345555555555555550\n5|02345555555555555550\n6|00000000000000000000\n7|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-019",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │···············│\n4|│└8│Line 8         │\n5|└──────────────────┘\n6|:3,8                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|02345555555555555550\n5|00000000000000000000\n6|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-020",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │···············│\n4|└──────────────────┘\n5|:3,8                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|00000000000000000000\n5|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-021",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 1         │\n03|│  │Line 2         │\n04|│┌3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│└6│Line 6         │\n08|│  │Line 7         │\n09|│  │Line 8         │\n10|└──────────────────┘\n11|:3,6                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|02234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|02234444444444444440\n09|02234444444444444440\n10|00000000000000000000\n11|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-022",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 1         │\n03|│  │Line 2         │\n04|│┌3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│└6│Line 6         │\n08|│  │Line 7         │\n09|└──────────────────┘\n10|:3,6                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|02234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|02234444444444444440\n09|00000000000000000000\n10|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-023",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 2         │\n3|│┌3│Line 3         │\n4|│┊ │Line 4         │\n5|│┊ │Line 5         │\n6|│└6│Line 6         │\n7|│  │Line 7         │\n8|└──────────────────┘\n9|:3,6                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|05234444444444444440\n4|05234444444444444440\n5|05234444444444444440\n6|05234444444444444440\n7|02234444444444444440\n8|00000000000000000000\n9|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-024",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 2         │\n3|│┌3│Line 3         │\n4|│┊ │Line 4         │\n5|│┊ │Line 5         │\n6|│└6│Line 6         │\n7|└──────────────────┘\n8|:3,6                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|05234444444444444440\n4|05234444444444444440\n5|05234444444444444440\n6|05234444444444444440\n7|00000000000000000000\n8|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-025",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │Line 4         │\n4|│┊ │Line 5         │\n5|│└6│Line 6         │\n6|└──────────────────┘\n7|:3,6                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02345555555555555550\n4|02345555555555555550\n5|02345555555555555550\n6|00000000000000000000\n7|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-026",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │···············│\n4|│└6│Line 6         │\n5|└──────────────────┘\n6|:3,6                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|02345555555555555550\n5|00000000000000000000\n6|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-027",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│┊ │···············│\n4|└──────────────────┘\n5|:3,6                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|00000000000000000000\n5|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-028",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 1         │\n3|│  │Line 2         │\n4|│┌3│Line 3         │\n5|│└4│Line 4         │\n6|│  │Line 5         │\n7|│  │Line 6         │\n8|└──────────────────┘\n9|:3,4                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|02234444444444444440\n4|05234444444444444440\n5|05234444444444444440\n6|02234444444444444440\n7|02234444444444444440\n8|00000000000000000000\n9|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-029",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 1         │\n3|│  │Line 2         │\n4|│┌3│Line 3         │\n5|│└4│Line 4         │\n6|│  │Line 5         │\n7|└──────────────────┘\n8|:3,4                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|02234444444444444440\n4|05234444444444444440\n5|05234444444444444440\n6|02234444444444444440\n7|00000000000000000000\n8|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-030",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 2         │\n3|│┌3│Line 3         │\n4|│└4│Line 4         │\n5|│  │Line 5         │\n6|└──────────────────┘\n7|:3,4                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|05234444444444444440\n4|05234444444444444440\n5|02234444444444444440\n6|00000000000000000000\n7|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-031",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 2         │\n3|│┌3│Line 3         │\n4|│└4│Line 4         │\n5|└──────────────────┘\n6|:3,4                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|05234444444444444440\n4|05234444444444444440\n5|00000000000000000000\n6|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-032",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌3│Line 3         │\n3|│└4│Line 4         │\n4|└──────────────────┘\n5|:3,4                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02345555555555555550\n4|00000000000000000000\n5|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-033",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│   │Line 2        │\n03|│└ 3│Line 3        │\n04|│┊  │Line 4        │\n05|│┊  │Line 5        │\n06|│┊  │··············│\n07|│┊  │Line 8        │\n08|│┊  │Line 9        │\n09|│┌10│Line 10       │\n10|│   │Line 11       │\n11|└──────────────────┘\n12|:10,3               \n\n--|---------|---------|\n01|01111110000000000000\n02|02223444444444444440\n03|05223444444444444440\n04|05223444444444444440\n05|05223444444444444440\n06|05223666666666666660\n07|05223444444444444440\n08|05223444444444444440\n09|05223444444444444440\n10|02223444444444444440\n11|00000000000000000000\n12|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-034",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│└ 3│Line 3        │\n3|│┊  │Line 4        │\n4|│┊  │··············│\n5|│┊  │Line 8        │\n6|│┊  │Line 9        │\n7|│┌10│Line 10       │\n8|└──────────────────┘\n9|:10,3               \n\n-|---------|---------|\n1|01111110000000000000\n2|02334555555555555550\n3|02334555555555555550\n4|02334666666666666660\n5|02334555555555555550\n6|02334555555555555550\n7|02334555555555555550\n8|00000000000000000000\n9|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-035",
    "content": "--|---------|---------|\n01|┌ Peek ────────────┐\n02|│  │Line 1         │\n03|│  │Line 2         │\n04|│└3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│┊ │Line 6         │\n08|│┊ │Line 7         │\n09|│┌8│Line 8         │\n10|│  │Line 9         │\n11|└──────────────────┘\n12|:8,3                \n\n--|---------|---------|\n01|01111110000000000000\n02|02234444444444444440\n03|02234444444444444440\n04|05234444444444444440\n05|05234444444444444440\n06|05234444444444444440\n07|05234444444444444440\n08|05234444444444444440\n09|05234444444444444440\n10|02234444444444444440\n11|00000000000000000000\n12|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-036",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│└3│Line 3         │\n3|│┊ │Line 4         │\n4|│┊ │···············│\n5|│┊ │Line 7         │\n6|│┌8│Line 8         │\n7|└──────────────────┘\n8|:8,3                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02345555555555555550\n4|02346666666666666660\n5|02345555555555555550\n6|02345555555555555550\n7|00000000000000000000\n8|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-037",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│  │Line 1         │\n3|│  │Line 2         │\n4|│└3│Line 3         │\n5|│┌4│Line 4         │\n6|│  │Line 5         │\n7|└──────────────────┘\n8|:4,3                \n\n-|---------|---------|\n1|01111110000000000000\n2|02234444444444444440\n3|02234444444444444440\n4|05234444444444444440\n5|05234444444444444440\n6|02234444444444444440\n7|00000000000000000000\n8|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---fits-into-available-height-038",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│└3│Line 3         │\n3|│┌4│Line 4         │\n4|└──────────────────┘\n5|:4,3                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02345555555555555550\n4|00000000000000000000\n5|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---hides-visual-selection",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|┌ Peek ────────────┐\n09|│  │Line 1         │\n10|│┌2│Line 2         │\n11|│┊ │Line 3         │\n12|│└4│Line 4         │\n13|│  │Line 5         │\n14|└──────────────────┘\n15|:'<,'>              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|23333332222222222222\n09|24456666666666666662\n10|27456666666666666662\n11|27456666666666666662\n12|27456666666666666662\n13|24456666666666666662\n14|22222222222222222222\n15|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---hides-visual-selection-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|Line 7              \n09|Line 8              \n10|Line 9              \n11|Line 10             \n12|Line 11             \n13|Line 12             \n14|My statusline       \n15|:'<,'>              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|12222211111111111111\n04|22222211111111111111\n05|21111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|11111111111111111111\n11|11111111111111111111\n12|11111111111111111111\n13|11111111111111111111\n14|33333333333333333333\n15|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---ignores-'wrap'",
    "content": "--|---------|---------|\n01|My tabline          \n02|Very big line number\n03| one                \n04|                    \n05|                    \n06|┌ Peek ────────────┐\n07|│  │Very big line n│\n08|│🭬2│               │\n09|│  │               │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---ignores-'wrap'-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Very big line number\n03| one                \n04|                    \n05|┌ Peek ────────────┐\n06|│  │Very big line n│\n07|│┌2│               │\n08|│└3│               │\n09|│  │Very big line n│\n10|└──────────────────┘\n11|:2,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---ignores-'wrap'-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Very big line number\n03| one                \n04|                    \n05|┌ Peek ────────────┐\n06|│┌1│Very big line n│\n07|│┊ │               │\n08|│┊ │               │\n09|│└4│Very big line n│\n10|└──────────────────┘\n11|:1,4                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24567777777777777772\n07|24567777777777777772\n08|24567777777777777772\n09|24567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---ignores-'wrap'-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Very big line number\n03| one                \n04|                    \n05|┌ Peek ────────────┐\n06|│  │Very big line >│\n07|│┌2│               │\n08|│└3│               │\n09|│  │Very big line >│\n10|└──────────────────┘\n11|:2,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666672\n07|28456666666666666662\n08|28456666666666666662\n09|24456666666666666672\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---is-shown-below-pmenu-and--C-d--output",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Lin sort            \n04|Lin source          \n05|Lin snoremap        \n06|┌ P snoremenu      ┐\n07|│┌1 history        │\n08|│└2 chistory       │\n09|│   lhistory       │\n10|└── stopinsert     ┘\n11|:1,2sort            \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11122222222222222221\n04|11133333333333333331\n05|11133333333333333331\n06|45533333333333333334\n07|46733333333333333334\n08|46733333333333333334\n09|47733333333333333334\n10|44433333333333333334\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---persists-for-the-entirety-of-command-typing",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---persists-for-the-entirety-of-command-typing-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2delete            \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---persists-for-the-entirety-of-command-typing-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│  │Line 1         │\n06|│┌2│Line 2         │\n07|│┊ │Line 3         │\n08|│└4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:2delete _ 3        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-`VimResized`",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│  │Line 1         │\n04|│┌2│Line 2         │\n05|│┊ │Line 3         │\n06|│┊ │Line 4         │\n07|│└5│Line 5         │\n08|│  │Line 6         │\n09|└──────────────────┘\n10|:2,5                \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13345555555555555551\n04|16345555555555555551\n05|16345555555555555551\n06|16345555555555555551\n07|16345555555555555551\n08|13345555555555555551\n09|11111111111111111111\n10|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-`VimResized`-002",
    "content": "--|---------|---------|-----\n01|My tabline               \n02|┌ Peek ─────────────────┐\n03|│  │Line 1              │\n04|│┌2│Line 2              │\n05|│┊ │Line 3              │\n06|│┊ │Line 4              │\n07|│└5│Line 5              │\n08|│  │Line 6              │\n09|└───────────────────────┘\n10|:2,5                     \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1222222111111111111111111\n03|1334555555555555555555551\n04|1634555555555555555555551\n05|1634555555555555555555551\n06|1634555555555555555555551\n07|1634555555555555555555551\n08|1334555555555555555555551\n09|1111111111111111111111111\n10|7777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-`VimResized`-003",
    "content": "--|---------|-----\n01|My tabline     \n02|Line 1         \n03|Line 2         \n04|Line 3         \n05|Line 4         \n06|Line 5         \n07|┌ Peek ───────┐\n08|│  │Line 1    │\n09|│┌2│Line 2    │\n10|│┊ │Line 3    │\n11|│┊ │Line 4    │\n12|│└5│Line 5    │\n13|│  │Line 6    │\n14|└─────────────┘\n15|:2,5           \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|233333322222222\n08|244566666666662\n09|274566666666662\n10|274566666666662\n11|274566666666662\n12|274566666666662\n13|244566666666662\n14|222222222222222\n15|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-`VimResized`-004",
    "content": "-|---------|---------|\n1|┌ Peek ────────────┐\n2|│┌2│Line 2         │\n3|│┊ │···············│\n4|│└5│Line 5         │\n5|└──────────────────┘\n6|:2,5                \n\n-|---------|---------|\n1|01111110000000000000\n2|02345555555555555550\n3|02346666666666666660\n4|02345555555555555550\n5|00000000000000000000\n6|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-command-line-height-change-during-typing",
    "content": "--|---------|-----\n01|┌ Peek ───────┐\n02|│  │Line 1    │\n03|│┌2│Line 2    │\n04|│┊ │Line 3    │\n05|│┊ │Line 4    │\n06|│└5│Line 5    │\n07|│  │Line 6    │\n08|└─────────────┘\n09|:2,5aaaaaaaaaaa\n10|aaaaa          \n\n--|---------|-----\n01|011111100000000\n02|022344444444440\n03|052344444444440\n04|052344444444440\n05|052344444444440\n06|052344444444440\n07|022344444444440\n08|000000000000000\n09|666666666666666\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-command-line-height-change-during-typing-002",
    "content": "--|---------|-----\n01|┌ Peek ───────┐\n02|│  │Line 1    │\n03|│┌2│Line 2    │\n04|│┊ │Line 3    │\n05|│┊ │Line 4    │\n06|│└5│Line 5    │\n07|└─────────────┘\n08|:2,5aaaaaaaaaaa\n09|aaaaaaaaaaaaaaa\n10|aaaaaa         \n\n--|---------|-----\n01|011111100000000\n02|022344444444440\n03|052344444444440\n04|052344444444440\n05|052344444444440\n06|052344444444440\n07|000000000000000\n08|666666666666666\n09|666666666666666\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---reacts-to-command-line-height-change-during-typing-003",
    "content": "--|---------|-----\n01|┌ Peek ───────┐\n02|│┌2│Line 2    │\n03|│┊ │Line 3    │\n04|│┊ │Line 4    │\n05|│└5│Line 5    │\n06|└─────────────┘\n07|:2,5aaaaaaaaaaa\n08|aaaaaaaaaaaaaaa\n09|aaaaaaaaaaaaaaa\n10|aaaaaaa        \n\n--|---------|-----\n01|011111100000000\n02|023455555555550\n03|023455555555550\n04|023455555555550\n05|023455555555550\n06|000000000000000\n07|666666666666666\n08|666666666666666\n09|666666666666666\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-'winborder'",
    "content": "--|---------|---------|\n01|My tabline          \n02|╭ Peek ────────────╮\n03|│    │Line 1       │\n04|│┌  2│Line 2       │\n05|│┊   │Line 3       │\n06|│┊   │·············│\n07|│┊   │Line 99      │\n08|│└100│Line 100     │\n09|│    │Line 101     │\n10|╰──────────────────╯\n11|::2,100             \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13333455555555555551\n04|16333455555555555551\n05|16333455555555555551\n06|16333477777777777771\n07|16333455555555555551\n08|16333455555555555551\n09|13333455555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-'winborder'-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|╔ Peek ════════════╗\n03|║    │Line 1       ║\n04|║┌  2│Line 2       ║\n05|║┊   │Line 3       ║\n06|║┊   │·············║\n07|║┊   │Line 99      ║\n08|║└100│Line 100     ║\n09|║    │Line 101     ║\n10|╚══════════════════╝\n11|::2,100             \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13333455555555555551\n04|16333455555555555551\n05|16333455555555555551\n06|16333477777777777771\n07|16333455555555555551\n08|16333455555555555551\n09|13333455555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-'winborder'-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|+ Peek ------------+\n03||    │Line 1       |\n04||┌  2│Line 2       |\n05||┊   │Line 3       |\n06||┊   │·············|\n07||┊   │Line 99      |\n08||└100│Line 100     |\n09||    │Line 101     |\n10|+------------------+\n11|::2,100             \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13333455555555555551\n04|16333455555555555551\n05|16333455555555555551\n06|16333477777777777771\n07|16333455555555555551\n08|16333455555555555551\n09|13333455555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│┌  1│Line 1       │\n08|│┊   │·············│\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:1,101              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24555677777777777772\n08|24555688888888888882\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│┌  2│Line 2       │\n08|│┊   │·············│\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:2,101              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24555677777777777772\n08|24555688888888888882\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│┌  1│Line 1       │\n08|│┊   │·············│\n09|│└100│Line 100     │\n10|└──────────────────┘\n11|:1,100              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24555677777777777772\n08|24555688888888888882\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│┌  2│Line 2       │\n08|│┊   │·············│\n09|│└100│Line 100     │\n10|└──────────────────┘\n11|:2,100              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24555677777777777772\n08|24555688888888888882\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│┌2│Line 2         │\n08|│┊ │Line 3         │\n09|│└4│Line 4         │\n10|└──────────────────┘\n11|:2,4                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24567777777777777772\n08|24567777777777777772\n09|24567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|┌ Peek ────────────┐\n08|│┌2│Line 2         │\n09|│└3│Line 3         │\n10|└──────────────────┘\n11|:2,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|23333332222222222222\n08|24567777777777777772\n09|24567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.n_context`-007",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|┌ Peek ────────────┐\n09|│🭬2│Line 2         │\n10|└──────────────────┘\n11|:2,2                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|23333332222222222222\n09|24567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.window.config`",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|  │Line 1           \n09|🭬2│Line 2           \n10|  │Line 3           \n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|22344444444444411111\n09|52344444444444411111\n10|22344444444444466666\n11|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.window.config`-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|╔…tion╗             \n05|║  │Li║             \n06|║🭬2│Li║             \n07|║  │Li║             \n08|║  │Li║             \n09|║  │Li║             \n10|╚═════╝usline       \n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333321111111111111\n05|24456621111111111111\n06|27456621111111111111\n07|24456621111111111111\n08|24456621111111111111\n09|24456621111111111111\n10|22222228888888888888\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.window.config`-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌…jklmnopqrstuvwxyz┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333333333333333332\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-`config.autopeek.window.statuscolumn`",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│!1  Line 1        │\n08|│!2  Line 2        │\n09|│!3  Line 3        │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24444555555555555552\n08|24444555555555555552\n09|24444555555555555552\n10|22222222222222222222\n11|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---respects-mappings",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 2         │\n07|│┌3│Line 3         │\n08|│└4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:3,4                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---updates-when-navigating-through-history",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│   │Line 9        │\n08|│🭬10│Line 10       │\n09|│   │Line 11       │\n10|└──────────────────┘\n11|:10                 \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24445666666666666662\n08|27445666666666666662\n09|24445666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---updates-when-navigating-through-history-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|Line 7              \n09|Line 8              \n10|My statusline       \n11|:echo               \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n11|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---updates-when-navigating-through-history-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│  │Line 1         │\n05|│┌2│Line 2         │\n06|│┊ │Line 3         │\n07|│┊ │Line 4         │\n08|│└5│Line 5         │\n09|│  │Line 6         │\n10|└──────────────────┘\n11|:2,5sort            \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24456666666666666662\n05|27456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---updates-when-navigating-through-history-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|Line 7              \n09|Line 8              \n10|My statusline       \n11|:echo               \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n11|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│└1│Line 1         │\n08|│┌2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2,                 \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24567777777777777772\n08|24567777777777777772\n09|25567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2,2                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 1        │\n04|│┌ 2│Line 2        │\n05|│┊  │Line 3        │\n06|│┊  │··············│\n07|│┊  │Line 19       │\n08|│└20│Line 20       │\n09|│   │Line 21       │\n10|└──────────────────┘\n11|:2,20               \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│    │Line 1       │\n05|│┌  2│Line 2       │\n06|│┊   │Line 3       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:2,200              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24444566666666666662\n05|27444566666666666662\n06|27444566666666666662\n07|27444588888888888882\n08|27444566666666666662\n09|27444566666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 1        │\n04|│┌ 2│Line 2        │\n05|│┊  │Line 3        │\n06|│┊  │··············│\n07|│┊  │Line 19       │\n08|│└20│Line 20       │\n09|│   │Line 21       │\n10|└──────────────────┘\n11|:2,20               \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-007",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│└1│Line 1         │\n08|│┌2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2,                 \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24567777777777777772\n08|24567777777777777772\n09|25567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-008",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|Line 7              \n09|Line 8              \n10|My statusline       \n11|:                   \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n11|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-009",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|Line 7              \n09|Line 8              \n10|My statusline       \n11|:                   \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n11|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-if-range-is-present-immediately",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 1         │\n07|│┌2│Line 2         │\n08|│└3│Line 3         │\n09|│  │Line 4         │\n10|└──────────────────┘\n11|:2,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|┌ Peek ────────────┐\n05|│┌  1│Line 1       │\n06|│┊   │Line 2       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:%                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24555677777777777772\n06|24555677777777777772\n07|24555688888888888882\n08|24555677777777777772\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|Line 5              \n05|Line 6              \n06|┌ Peek ────────────┐\n07|│    │Line 99      │\n08|│🭬100│Line 100     │\n09|│    │Line 101     │\n10|└──────────────────┘\n11|:/                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24444566666666666662\n08|27444566666666666662\n09|24444566666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|Line 5              \n05|Line 6              \n06|┌ Peek ────────────┐\n07|│   │Line 10       │\n08|│🭬11│Line 11       │\n09|│   │Line 12       │\n10|└──────────────────┘\n11|:/Li                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24445666666666666662\n08|27445666666666666662\n09|24445666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|Line 5              \n05|Line 6              \n06|┌ Peek ────────────┐\n07|│   │Line 39       │\n08|│🭬40│Line 40       │\n09|│   │Line 41       │\n10|└──────────────────┘\n11|:/Line 4            \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24445666666666666662\n08|27445666666666666662\n09|24445666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 9        │\n04|│└10│Line 10       │\n05|│┊  │Line 11       │\n06|│┊  │··············│\n07|│┊  │Line 39       │\n08|│┌40│Line 40       │\n09|│   │Line 41       │\n10|└──────────────────┘\n11|:/Line 4/,          \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 39       │\n04|│┌40│Line 40       │\n05|│┊  │Line 41       │\n06|│┊  │··············│\n07|│┊  │Line 59       │\n08|│└60│Line 60       │\n09|│   │Line 61       │\n10|└──────────────────┘\n11|:/Line 4/,/Line 6   \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-007",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|Line 5              \n05|Line 6              \n06|Line 7              \n07|┌ Peek ────────────┐\n08|│🭬1│Line 1         │\n09|│  │Line 2         │\n10|└──────────────────┘\n11|:1xxx               \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|23333332222222222222\n08|24567777777777777772\n09|25567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-008",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|Line 5              \n05|Line 6              \n06|┌ Peek ────────────┐\n07|│┌1│Line 1         │\n08|│└2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:1,2xxx             \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24567777777777777772\n08|24567777777777777772\n09|25567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-regular-command-line-parsing-fails-009",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 3              \n03|Line 4              \n04|┌ Peek ────────────┐\n05|│┌  1│Line 1       │\n06|│┊   │Line 2       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:%xxx               \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24555677777777777772\n06|24555677777777777772\n07|24555688888888888882\n08|24555677777777777772\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-using-command-line-expression-register",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 1        │\n04|│┌ 2│Line 2        │\n05|│┊  │Line 3        │\n06|│┊  │··············│\n07|│┊  │Line 19       │\n08|│└20│Line 20       │\n09|│   │Line 21       │\n10|└──────────────────┘\n11|:2,20               \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-when-using-command-line-expression-register-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 1        │\n04|│┌ 2│Line 2        │\n05|│┊  │Line 3        │\n06|│┊  │··············│\n07|│┊  │Line 20       │\n08|│└21│Line 21       │\n09|│   │Line 22       │\n10|└──────────────────┘\n11|:2,20+              \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-'inccommand'",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2s                 \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-'inccommand'-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2s/                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-'inccommand'-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2s/Li              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|34444443333333333333\n07|35567777777777777773\n08|38562277777777777773\n09|35567777777777777773\n10|33333333333333333333\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-'inccommand'-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|ne 2                \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│ne 2           │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2s/Li/             \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-'inccommand'-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|XXne 2              \n04|Line 3              \n05|Line 4              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│XXne 2         │\n09|│  │Line 3         │\n10|└──────────────────┘\n11|:2s/Li/XX           \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|34444443333333333333\n07|35567777777777777773\n08|38562277777777777773\n09|35567777777777777773\n10|33333333333333333333\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-'inccommand'-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|XXne 2              \n04|Line 3              \n05|Line 4              \n06|Line 5              \n07|Line 6              \n08|Line 7              \n09|Line 8              \n10|My statusline       \n11|:2s/Li/XX/          \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n11|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-different-'cmdheight'",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│  │Line 1         │\n05|│┌2│Line 2         │\n06|│┊ │Line 3         │\n07|│┊ │Line 4         │\n08|│└5│Line 5         │\n09|│  │Line 6         │\n10|└──────────────────┘\n11|:2,5                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24456666666666666662\n05|27456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-different-'cmdheight'-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│  │Line 1         │\n04|│┌2│Line 2         │\n05|│┊ │Line 3         │\n06|│┊ │Line 4         │\n07|│└5│Line 5         │\n08|│  │Line 6         │\n09|└──────────────────┘\n10|:2,5                \n11|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13345555555555555551\n04|16345555555555555551\n05|16345555555555555551\n06|16345555555555555551\n07|16345555555555555551\n08|13345555555555555551\n09|11111111111111111111\n10|77777777777777777777\n11|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│    │Line 1       │\n05|│┌  2│Line 2       │\n06|│┊   │Line 3       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:.,$                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24444566666666666662\n05|27444566666666666662\n06|27444566666666666662\n07|27444588888888888882\n08|27444566666666666662\n09|27444566666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│┌  1│Line 1       │\n06|│┊   │Line 2       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│└101│Line 101     │\n10|└──────────────────┘\n11|:%                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24555677777777777772\n06|24555677777777777772\n07|24555688888888888882\n08|24555677777777777772\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 2         │\n07|│┌3│Line 3         │\n08|│└4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:*                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 2         │\n07|│┌3│Line 3         │\n08|│└4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:'<,'>              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│   │Line 9        │\n06|│┌10│Line 10       │\n07|│┊  │Line 11       │\n08|│└12│Line 12       │\n09|│   │Line 13       │\n10|└──────────────────┘\n11|:'a,'b              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24445666666666666662\n06|27445666666666666662\n07|27445666666666666662\n08|27445666666666666662\n09|24445666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│   │Line 9        │\n06|│└10│Line 10       │\n07|│┊  │Line 11       │\n08|│┌12│Line 12       │\n09|│   │Line 13       │\n10|└──────────────────┘\n11|:'b,'a              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24445666666666666662\n06|27445666666666666662\n07|27445666666666666662\n08|27445666666666666662\n09|24445666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-007",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 3         │\n07|│└4│Line 4         │\n08|│┌5│Line 5         │\n09|│  │Line 6         │\n10|└──────────────────┘\n11|:/Line 5/,/Line 4/  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-008",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 4        │\n04|│┌ 5│Line 5        │\n05|│┊  │Line 6        │\n06|│┊  │··············│\n07|│┊  │Line 39       │\n08|│└40│Line 40       │\n09|│   │Line 41       │\n10|└──────────────────┘\n11|:/Line 5/;/Line 4/  \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-009",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 58       │\n04|│┌59│Line 59       │\n05|│┊  │Line 60       │\n06|│┊  │··············│\n07|│┊  │Line 68       │\n08|│└69│Line 69       │\n09|│   │Line 70       │\n10|└──────────────────┘\n11|:?Line 5?,?Line 6?  \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-010",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 5        │\n04|│└ 6│Line 6        │\n05|│┊  │Line 7        │\n06|│┊  │··············│\n07|│┊  │Line 58       │\n08|│┌59│Line 59       │\n09|│   │Line 60       │\n10|└──────────────────┘\n11|:?Line 5?;?Line 6?  \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-011",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│└1│Line 1         │\n06|│┊ │Line 2         │\n07|│┊ │Line 3         │\n08|│┌4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:++,-               \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24567777777777777772\n06|24567777777777777772\n07|24567777777777777772\n08|24567777777777777772\n09|25567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-012",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│  │Line 4         │\n05|│┌5│Line 5         │\n06|│┊ │Line 6         │\n07|│┊ │Line 7         │\n08|│└8│Line 8         │\n09|│  │Line 9         │\n10|└──────────────────┘\n11|:'<+2,'a--          \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24456666666666666662\n05|27456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-every-kind-of-line-range-013",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│└  1│Line 1       │\n06|│┊   │Line 2       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│┌101│Line 101     │\n10|└──────────────────┘\n11|:/5/+100,/4/-100    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24555677777777777772\n06|24555677777777777772\n07|24555688888888888882\n08|24555677777777777772\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│└  1│Line 1       │\n06|│┊   │Line 2       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│┌101│Line 101     │\n10|└──────────────────┘\n11|:101,1              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24555677777777777772\n06|24555677777777777772\n07|24555688888888888882\n08|24555677777777777772\n09|24555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│    │Line 1       │\n05|│└  2│Line 2       │\n06|│┊   │Line 3       │\n07|│┊   │·············│\n08|│┊   │Line 100     │\n09|│┌101│Line 101     │\n10|└──────────────────┘\n11|:101,2              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24444566666666666662\n05|27444566666666666662\n06|27444566666666666662\n07|27444588888888888882\n08|27444566666666666662\n09|27444566666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│└  1│Line 1       │\n05|│┊   │Line 2       │\n06|│┊   │·············│\n07|│┊   │Line 99      │\n08|│┌100│Line 100     │\n09|│    │Line 101     │\n10|└──────────────────┘\n11|:100,1              \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24555677777777777772\n05|24555677777777777772\n06|24555688888888888882\n07|24555677777777777772\n08|24555677777777777772\n09|25555677777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│    │Line 1       │\n04|│└  2│Line 2       │\n05|│┊   │Line 3       │\n06|│┊   │·············│\n07|│┊   │Line 99      │\n08|│┌100│Line 100     │\n09|│    │Line 101     │\n10|└──────────────────┘\n11|:100,2              \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13333455555555555551\n04|16333455555555555551\n05|16333455555555555551\n06|16333477777777777771\n07|16333455555555555551\n08|16333455555555555551\n09|13333455555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│   │Line 2        │\n04|│└ 3│Line 3        │\n05|│┊  │Line 4        │\n06|│┊  │··············│\n07|│┊  │Line 98       │\n08|│┌99│Line 99       │\n09|│   │Line 100      │\n10|└──────────────────┘\n11|:99,3               \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13334555555555555551\n04|16334555555555555551\n05|16334555555555555551\n06|16334777777777777771\n07|16334555555555555551\n08|16334555555555555551\n09|13334555555555555551\n10|11111111111111111111\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|┌ Peek ────────────┐\n03|│  │Line 2         │\n04|│└3│Line 3         │\n05|│┊ │Line 4         │\n06|│┊ │Line 5         │\n07|│┊ │Line 6         │\n08|│┌7│Line 7         │\n09|│  │Line 8         │\n10|└──────────────────┘\n11|:7,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|12222221111111111111\n03|13345555555555555551\n04|16345555555555555551\n05|16345555555555555551\n06|16345555555555555551\n07|16345555555555555551\n08|16345555555555555551\n09|13345555555555555551\n10|11111111111111111111\n11|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-007",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|┌ Peek ────────────┐\n04|│  │Line 2         │\n05|│└3│Line 3         │\n06|│┊ │Line 4         │\n07|│┊ │Line 5         │\n08|│┌6│Line 6         │\n09|│  │Line 7         │\n10|└──────────────────┘\n11|:6,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23333332222222222222\n04|24456666666666666662\n05|27456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-008",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│  │Line 2         │\n06|│└3│Line 3         │\n07|│┊ │Line 4         │\n08|│┌5│Line 5         │\n09|│  │Line 6         │\n10|└──────────────────┘\n11|:5,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24456666666666666662\n06|27456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-inverted-range-009",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Line 3              \n05|┌ Peek ────────────┐\n06|│  │Line 2         │\n07|│└3│Line 3         │\n08|│┌4│Line 4         │\n09|│  │Line 5         │\n10|└──────────────────┘\n11|:4,3                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23333332222222222222\n06|24456666666666666662\n07|27456666666666666662\n08|27456666666666666662\n09|24456666666666666662\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-virtual-lines",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Virt                \n05|Line 3              \n06|┌ Peek ────────────┐\n07|│  │Line 1         │\n08|│🭬2│Line 2         │\n09|│• │Virt           │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27456666666666666662\n09|28856666666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-virtual-lines-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Virt                \n05|Line 3              \n06|┌ Peek ────────────┐\n07|│  │Line 3         │\n08|│• │Virt above     │\n09|│🭬4│Line 4         │\n10|└──────────────────┘\n11|:4                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24456666666666666662\n08|27756666666666666662\n09|28456666666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-virtual-lines-003",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|┌ Peek ────────────┐\n05|│  │Line 1         │\n06|│┌2│Line 2         │\n07|│• │Virt           │\n08|│┊ │Line 3         │\n09|│• │Virt above     │\n10|└──────────────────┘\n11|:2,4                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|23333332222222222222\n05|24456666666666666662\n06|27456666666666666662\n07|28856666666666666662\n08|27456666666666666662\n09|28856666666666666662\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-virtual-lines-004",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Virt                \n05|Line 3              \n06|Virt above          \n07|Line 4              \n08|┌ Peek ────────────┐\n09|│🭬2│Line 2         │\n10|└──────────────────┘\n11|:2                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|23333332222222222222\n09|24567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-virtual-lines-005",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Virt                \n05|Line 3              \n06|Virt above          \n07|Line 4              \n08|┌ Peek ────────────┐\n09|│🭬4│Line 4         │\n10|└──────────────────┘\n11|:4                  \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|23333332222222222222\n09|24567777777777777772\n10|22222222222222222222\n11|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---Autopeek---works-with-virtual-lines-006",
    "content": "--|---------|---------|\n01|My tabline          \n02|Line 1              \n03|Line 2              \n04|Virt                \n05|Line 3              \n06|┌ Peek ────────────┐\n07|│┌2│Line 2         │\n08|│• │Virt           │\n09|│┊ │Line 3         │\n10|└──────────────────┘\n11|:2,4                \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|23333332222222222222\n07|24567777777777777772\n08|28867777777777777772\n09|24567777777777777772\n10|22222222222222222222\n11|99999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---respects-`opts`",
    "content": "-|---------|-----\n1|* #Line 1      \n2|<2#Line 2      \n3|- #Line 3      \n4|- #Line 4      \n5|>5#Line 5      \n6|* #Line 6      \n7|               \n\n-|---------|-----\n1|012333333333333\n2|012333333333333\n3|012333333333333\n4|012333333333333\n5|012333333333333\n6|012333333333333\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---respects-`opts`-002",
    "content": "-|---------|-----\n1|% %Line 1      \n2|%2%Line 2      \n3|% %Line 3      \n4|% %Line 4      \n5|%5%Line 5      \n6|% %Line 6      \n7|               \n\n-|---------|-----\n1|012333333333333\n2|012333333333333\n3|012333333333333\n4|012333333333333\n5|012333333333333\n6|012333333333333\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---respects-`opts`-003",
    "content": "-|---------|-----\n1|* #            \n2|=2#Very big lin\n3|! #e number one\n4|$ #Virt        \n5|* #Very big lin\n6|! #e number two\n7|               \n\n-|---------|-----\n1|012333333333333\n2|012333333333333\n3|442333333333333\n4|442333333333333\n5|012333333333333\n6|442333333333333\n7|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---respects-`opts`-004",
    "content": "-|---------|-----\n1|% %            \n2|%2%Very big lin\n3|% %e number one\n4|% %Virt        \n5|% %Very big lin\n6|% %e number two\n7|               \n\n-|---------|-----\n1|012333333333333\n2|012333333333333\n3|442333333333333\n4|442333333333333\n5|012333333333333\n6|442333333333333\n7|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works",
    "content": "-|---------|-----\n1|  │Line 1      \n2|┌2│Line 2      \n3|┊ │Line 3      \n4|┊ │Line 4      \n5|└5│Line 5      \n6|  │Line 6      \n7|               \n\n-|---------|-----\n1|001222222222222\n2|301222222222222\n3|301222222222222\n4|301222222222222\n5|301222222222222\n6|001222222222222\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works-002",
    "content": "-|---------|-----\n1|  │Line 1      \n2|  │Line 2      \n3|  │Line 3      \n4|┌4│Line 4      \n5|└5│Line 5      \n6|  │Line 6      \n7|               \n\n-|---------|-----\n1|001222222222222\n2|001222222222222\n3|001222222222222\n4|301222222222222\n5|301222222222222\n6|001222222222222\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works-003",
    "content": "-|---------|-----\n1|  │Line 1      \n2|  │Line 2      \n3|  │Line 3      \n4|🭬4│Line 4      \n5|  │Line 5      \n6|  │Line 6      \n7|               \n\n-|---------|-----\n1|001222222222222\n2|001222222222222\n3|001222222222222\n4|301222222222222\n5|001222222222222\n6|001222222222222\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works-004",
    "content": "-|---------|-----\n1|  │Line 1      \n2|  │Line 2      \n3|  │Line 3      \n4|└4│Line 4      \n5|┌5│Line 5      \n6|  │Line 6      \n7|               \n\n-|---------|-----\n1|001222222222222\n2|001222222222222\n3|001222222222222\n4|301222222222222\n5|301222222222222\n6|001222222222222\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works-005",
    "content": "-|---------|-----\n1|  │Line 1      \n2|└2│Line 2      \n3|┊ │Line 3      \n4|┊ │Line 4      \n5|┌5│Line 5      \n6|  │Line 6      \n7|               \n\n-|---------|-----\n1|001222222222222\n2|301222222222222\n3|301222222222222\n4|301222222222222\n5|301222222222222\n6|001222222222222\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works-006",
    "content": "-|---------|-----\n1|   │Line 7     \n2|┌ 8│Line 8     \n3|┊  │Line 9     \n4|└10│Line 10    \n5|   │Line 11    \n6|   │Line 12    \n7|               \n\n-|---------|-----\n1|000122222222222\n2|300122222222222\n3|300122222222222\n4|300122222222222\n5|000122222222222\n6|000122222222222\n7|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cmdline.lua---default_autopeek_statuscolumn()---works-with-wrapped-and-virtual-lines",
    "content": "--|---------|-----\n01|  │            \n02|┌2│Very big lin\n03|↳ │e number one\n04|• │Virt        \n05|└3│Very big lin\n06|↳ │e number two\n07|• │Virt above  \n08|  │            \n09|~              \n10|               \n\n--|---------|-----\n01|001222222222222\n02|301222222222222\n03|441222222222222\n04|441222222222222\n05|301222222222222\n06|441222222222222\n07|441222222222222\n08|001222222222222\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_colors.lua---interactive()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|-- Experiment with color scheme using 'mini.colors'         \n02|--                                                          \n03|-- Treat this as regular Lua file                           \n04|-- Methods of initial color scheme can be called directly   \n05|-- See more in `:h MiniColors.interactive()`                \n06|--                                                          \n07|-- Initial color scheme: test_interactive                   \n08|-- Buffer-local mappings (Normal mode):                     \n09|--   Apply: <M-a>                                           \n10|--   Reset: <M-r>                                           \n11|--   Quit:  <M-q>                                           \n12|--   Write: <M-w>                                           \n13|--                                                          \n14|-- Examples:                                                \n15|--                                                          \n16|-- Invert dark/light color scheme to be light/dark          \n17|-- chan_invert('lightness', { gamut_clip = 'cusp' })        \n18|--                                                          \n19|-- Make foreground text more saturated                      \n20|-- chan_add('saturation', 20,  { filter = 'fg' })           \n21|                                                            \n22|                                                            \n23|~                                                           \n24|~                                                           \n25|~                                                           \n26|~                                                           \n27|minicolors://2/interactive 22,0-1                           \n28|                                                            \n29|                                                            \n30|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000111111111\n02|001111111111111111111111111111111111111111111111111111111111\n03|000000000000000000000000000000000111111111111111111111111111\n04|000000000000000000000000000000000000000000000000000000000111\n05|000000000000000000000000000000000000000000001111111111111111\n06|001111111111111111111111111111111111111111111111111111111111\n07|000000000000000000000000000000000000000001111111111111111111\n08|000000000000000000000000000000000000000111111111111111111111\n09|000000000000000001111111111111111111111111111111111111111111\n10|000000000000000001111111111111111111111111111111111111111111\n11|000000000000000001111111111111111111111111111111111111111111\n12|000000000000000001111111111111111111111111111111111111111111\n13|001111111111111111111111111111111111111111111111111111111111\n14|000000000000111111111111111111111111111111111111111111111111\n15|001111111111111111111111111111111111111111111111111111111111\n16|000000000000000000000000000000000000000000000000001111111111\n17|000000000000000000000000000000000000000000000000000011111111\n18|001111111111111111111111111111111111111111111111111111111111\n19|000000000000000000000000000000000000001111111111111111111111\n20|000000000000000000000000000000000000000000000000011111111111\n21|111111111111111111111111111111111111111111111111111111111111\n22|111111111111111111111111111111111111111111111111111111111111\n23|222222222222222222222222222222222222222222222222222222222222\n24|222222222222222222222222222222222222222222222222222222222222\n25|222222222222222222222222222222222222222222222222222222222222\n26|222222222222222222222222222222222222222222222222222222222222\n27|333333333333333333333333333333333333333333333333333333333333\n28|111111111111111111111111111111111111111111111111111111111111\n29|111111111111111111111111111111111111111111111111111111111111\n30|111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_colors.lua---interactive()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|-- Experiment with color scheme using 'mini.colors'         \n02|--                                                          \n03|-- Treat this as regular Lua file                           \n04|-- Methods of initial color scheme can be called directly   \n05|-- See more in `:h MiniColors.interactive()`                \n06|--                                                          \n07|-- Initial color scheme: test_interactive                   \n08|-- Buffer-local mappings (Normal mode):                     \n09|--   Apply: <M-a>                                           \n10|--   Reset: <M-r>                                           \n11|--   Quit:  <M-q>                                           \n12|--   Write: <M-w>                                           \n13|--                                                          \n14|-- Examples:                                                \n15|--                                                          \n16|-- Invert dark/light color scheme to be light/dark          \n17|-- chan_invert('lightness', { gamut_clip = 'cusp' })        \n18|--                                                          \n19|-- Make foreground text more saturated                      \n20|-- chan_add('saturation', 20,  { filter = 'fg' })           \n21|                                                            \n22|chan_invert('lightness')                                    \n23|~                                                           \n24|~                                                           \n25|~                                                           \n26|~                                                           \n27|minicolors://2/interactive 22,24                            \n28|Write to 'colors/' of your config under this name: test_inte\n29|ractive                                                     \n30|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000111111111\n02|001111111111111111111111111111111111111111111111111111111111\n03|000000000000000000000000000000000111111111111111111111111111\n04|000000000000000000000000000000000000000000000000000000000111\n05|000000000000000000000000000000000000000000001111111111111111\n06|001111111111111111111111111111111111111111111111111111111111\n07|000000000000000000000000000000000000000001111111111111111111\n08|000000000000000000000000000000000000000111111111111111111111\n09|000000000000000001111111111111111111111111111111111111111111\n10|000000000000000001111111111111111111111111111111111111111111\n11|000000000000000001111111111111111111111111111111111111111111\n12|000000000000000001111111111111111111111111111111111111111111\n13|001111111111111111111111111111111111111111111111111111111111\n14|000000000000111111111111111111111111111111111111111111111111\n15|001111111111111111111111111111111111111111111111111111111111\n16|000000000000000000000000000000000000000000000000001111111111\n17|000000000000000000000000000000000000000000000000000011111111\n18|001111111111111111111111111111111111111111111111111111111111\n19|000000000000000000000000000000000000001111111111111111111111\n20|000000000000000000000000000000000000000000000000011111111111\n21|111111111111111111111111111111111111111111111111111111111111\n22|222222222223444444444443111111111111111111111111111111111111\n23|555555555555555555555555555555555555555555555555555555555555\n24|555555555555555555555555555555555555555555555555555555555555\n25|555555555555555555555555555555555555555555555555555555555555\n26|555555555555555555555555555555555555555555555555555555555555\n27|666666666666666666666666666666666666666666666666666666666666\n28|777777777777777777777777777777777777777777777777777777777777\n29|777777777777777777777777777777777777777777777777777777777777\n30|777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-at-LSP-trigger---test-+-args-{-'completefunc'-}",
    "content": "--|---------|---------|---------|\n01|May.                          \n02|~   January   Text            \n03|~   February  Text            \n04|~   March     Method          \n05|~   April     Method          \n06|~   May       Method          \n07|~   June      Function        \n08|~   July      Function        \n09|~   August    Function        \n10|~   September Constructor     \n11|~   October   Constructor     \n12|~   November  Constructor     \n13|~   December  Text            \n14|~                             \n15|[No Name] 1,5                 \n16|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111222222222222222222222221111\n03|111222222222222222222222221111\n04|111222222222222222222222221111\n05|111222222222222222222222221111\n06|111222222222222222222222221111\n07|111222222222222222222222221111\n08|111222222222222222222222221111\n09|111222222222222222222222221111\n10|111222222222222222222222221111\n11|111222222222222222222222221111\n12|111222222222222222222222221111\n13|111222222222222222222222221111\n14|111111111111111111111111111111\n15|333333333333333333333333333333\n16|444444444444555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-at-LSP-trigger---test-+-args-{-'completefunc'-}-002",
    "content": "--|---------|---------|---------|\n01|May.                          \n02|# .                           \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|~                             \n10|~                             \n11|~                             \n12|~                             \n13|~                             \n14|~                             \n15|[No Name] 2,4                 \n16|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|111111111111111111111111111111\n10|111111111111111111111111111111\n11|111111111111111111111111111111\n12|111111111111111111111111111111\n13|111111111111111111111111111111\n14|111111111111111111111111111111\n15|222222222222222222222222222222\n16|333333333333444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-at-LSP-trigger---test-+-args-{-'omnifunc'-}",
    "content": "--|---------|---------|---------|\n01|May.                          \n02|~   January   Text            \n03|~   February  Text            \n04|~   March     Method          \n05|~   April     Method          \n06|~   May       Method          \n07|~   June      Function        \n08|~   July      Function        \n09|~   August    Function        \n10|~   September Constructor     \n11|~   October   Constructor     \n12|~   November  Constructor     \n13|~   December  Text            \n14|~                             \n15|[No Name] 1,5                 \n16|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111222222222222222222222221111\n03|111222222222222222222222221111\n04|111222222222222222222222221111\n05|111222222222222222222222221111\n06|111222222222222222222222221111\n07|111222222222222222222222221111\n08|111222222222222222222222221111\n09|111222222222222222222222221111\n10|111222222222222222222222221111\n11|111222222222222222222222221111\n12|111222222222222222222222221111\n13|111222222222222222222222221111\n14|111111111111111111111111111111\n15|333333333333333333333333333333\n16|444444444444555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-at-LSP-trigger---test-+-args-{-'omnifunc'-}-002",
    "content": "--|---------|---------|---------|\n01|May.                          \n02|# .                           \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|~                             \n10|~                             \n11|~                             \n12|~                             \n13|~                             \n14|~                             \n15|[No Name] 2,4                 \n16|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|111111111111111111111111111111\n10|111111111111111111111111111111\n11|111111111111111111111111111111\n12|111111111111111111111111111111\n13|111111111111111111111111111111\n14|111111111111111111111111111111\n15|222222222222222222222222222222\n16|333333333333444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-for-`isIncomplete`-even-if-canceled",
    "content": "--|---------|---------|\n01|Jul                 \n02|July Function       \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,4       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111122222\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-in-case-of-`isIncomplete`",
    "content": "--|---------|---------|\n01|J                   \n02|January Text        \n03|June    Function    \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,2       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111222\n03|11111111111111111222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-in-case-of-`isIncomplete`-002",
    "content": "--|---------|---------|\n01|Ju                  \n02|June Function       \n03|July Function       \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,3       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111122222\n03|11111111111111122222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---forces-new-LSP-completion-in-case-of-`isIncomplete`-003",
    "content": "--|---------|---------|\n01|J                   \n02|January Text        \n03|June    Function    \n04|July    Function    \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,2       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111222\n03|11111111111111111222\n04|11111111111111111222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---respects-string-`config.fallback_action`",
    "content": "--|---------|---------|-----\n01|Line number 1            \n02|L                        \n03|Line number 1            \n04|~                        \n05|~                        \n06|~                        \n07|~                        \n08|~                        \n09|[No Name] 2,2            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|0000000000000000000000000\n03|1111111111111112222222222\n04|2222222222222222222222222\n05|2222222222222222222222222\n06|2222222222222222222222222\n07|2222222222222222222222222\n08|2222222222222222222222222\n09|3333333333333333333333333\n10|4444444444445555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---respects-string-`config.fallback_action`-002",
    "content": "--|---------|---------|-----\n01|Line number 1            \n02|L                        \n03|Line                     \n04|~                        \n05|~                        \n06|~                        \n07|~                        \n08|~                        \n09|[No Name] 2,2            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|0000000000000000000000000\n03|1111111111111112222222222\n04|2222222222222222222222222\n05|2222222222222222222222222\n06|2222222222222222222222222\n07|2222222222222222222222222\n08|2222222222222222222222222\n09|3333333333333333333333333\n10|4444444444445555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---works-with-LSP-client",
    "content": "--|---------|---------|\n01|Ju                  \n02|June Function       \n03|July Function       \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,3       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111122222\n03|11111111111111122222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---works-with-`-BS-`",
    "content": "--|---------|---------|\n01|Jun                 \n02|June Function       \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,4       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111122222\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---works-with-`-BS-`-002",
    "content": "--|---------|---------|\n01|Ju                  \n02|June Function       \n03|July Function       \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,3       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111122222\n03|11111111111111122222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---works-with-`-BS-`-003",
    "content": "--|---------|---------|\n01|J                   \n02|January Text        \n03|June    Function    \n04|July    Function    \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,2       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111222\n03|11111111111111111222\n04|11111111111111111222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Autocompletion---works-without-LSP-clients",
    "content": "--|---------|---------|---------|\n01|aab aac aba aa                \n02|~           aab               \n03|~           aac               \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|[No Name] 1,15                \n10|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111112222222222222222111\n03|111111111112222222222222222111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|333333333333333333333333333333\n10|444444444444555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---accounts-for-border-when-picking-side",
    "content": "--|---------|---------|---------|---------|\n01|aaaaaaaaaaaa January                    \n02|~┌ Info ───┐ January Text               \n03|~│Month #01│ June    Function           \n04|~└─────────┘ July    Function           \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,21                          \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1233333322224444444444444444441111111111\n03|1255555555526666666666666666661111111111\n04|1222222222226666666666666666661111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---adjusts-for-top-bottom-code-block-delimiters",
    "content": "--|---------|---------|---------|\n01|September                     \n02|September Constructor ┌…o ┐   \n03|~                     │Sep│   \n04|~                     └───┘   \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|[No Name] 1,10                \n10|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111123332444\n03|444444444444444444444425552444\n04|444444444444444444444422222444\n05|444444444444444444444444444444\n06|444444444444444444444444444444\n07|444444444444444444444444444444\n08|444444444444444444444444444444\n09|666666666666666666666666666666\n10|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---adjusts-for-top-bottom-code-block-delimiters-002",
    "content": "--|---------|---------|---------|\n01|September                     \n02|September Constructor ┌…o ┐   \n03|~                     │Sep│   \n04|~                     └───┘   \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|[No Name] [+]  1,10        All\n10|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111123332444\n03|444444444444444444444425552444\n04|444444444444444444444422222444\n05|444444444444444444444444444444\n06|444444444444444444444444444444\n07|444444444444444444444444444444\n08|444444444444444444444444444444\n09|666666666666666666666666666666\n10|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---adjusts-title",
    "content": "--|---------|---------|---------|-----\n01|February                           \n02|January   Text        ┌…┐          \n03|February  Text        │a│          \n04|March     Method      │b│          \n05|April     Method      │c│          \n06|May       Method      │d│          \n07|June      Function    │e│          \n08|July      Function    │f│          \n09|August    Function    │g│          \n10|September Constructor │h│          \n11|October   Constructor └─┘          \n12|November  Constructor              \n13|December  Text                     \n14|~                                  \n15|~                                  \n16|~                                  \n17|~                                  \n18|~                                  \n19|[No Name] 1,9                      \n20|-- INSERT --                       \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111111111112324444444444\n03|55555555555555555555552624444444444\n04|11111111111111111111112624444444444\n05|11111111111111111111112624444444444\n06|11111111111111111111112624444444444\n07|11111111111111111111112624444444444\n08|11111111111111111111112624444444444\n09|11111111111111111111112624444444444\n10|11111111111111111111112624444444444\n11|11111111111111111111112224444444444\n12|11111111111111111111114444444444444\n13|11111111111111111111114444444444444\n14|44444444444444444444444444444444444\n15|44444444444444444444444444444444444\n16|44444444444444444444444444444444444\n17|44444444444444444444444444444444444\n18|44444444444444444444444444444444444\n19|77777777777777777777777777777777777\n20|88888888888899999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---adjusts-title-002",
    "content": "--|---------|---------|---------|-----\n01|January                            \n02|January   Text        ┌ Info ───┐  \n03|February  Text        │Month #01│  \n04|March     Method      └─────────┘  \n05|April     Method                   \n06|May       Method                   \n07|June      Function                 \n08|July      Function                 \n09|August    Function                 \n10|September Constructor              \n11|October   Constructor              \n12|November  Constructor              \n13|December  Text                     \n14|~                                  \n15|~                                  \n16|~                                  \n17|~                                  \n18|~                                  \n19|[No Name] 1,8                      \n20|-- INSERT --                       \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111111111112333333222244\n03|55555555555555555555552666666666244\n04|55555555555555555555552222222222244\n05|55555555555555555555554444444444444\n06|55555555555555555555554444444444444\n07|55555555555555555555554444444444444\n08|55555555555555555555554444444444444\n09|55555555555555555555554444444444444\n10|55555555555555555555554444444444444\n11|55555555555555555555554444444444444\n12|55555555555555555555554444444444444\n13|55555555555555555555554444444444444\n14|44444444444444444444444444444444444\n15|44444444444444444444444444444444444\n16|44444444444444444444444444444444444\n17|44444444444444444444444444444444444\n18|44444444444444444444444444444444444\n19|77777777777777777777777777777777777\n20|88888888888899999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---adjusts-window-width",
    "content": "--|---------|---------|-------\n01|January                    \n02|January Text     ┌ Info ┐  \n03|June    Function │Month │  \n04|July    Function │#01   │  \n05|~                └──────┘  \n06|~                          \n07|~                          \n08|~                          \n09|[No Name] 1,8              \n10|-- INSERT --               \n\n--|---------|---------|-------\n01|000000000000000000000000000\n02|111111111111111112333333244\n03|555555555555555552666666244\n04|555555555555555552666666244\n05|444444444444444442222222244\n06|444444444444444444444444444\n07|444444444444444444444444444\n08|444444444444444444444444444\n09|777777777777777777777777777\n10|888888888888999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---can-be-adjusted-in-event",
    "content": "--|---------|---------|---------|---------|\n01|June                                    \n02|January Text     ┌───Custom┐            \n03|June    Function │Month #06│            \n04|July    Function └─────────┘            \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,5                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111122223333332444444444444\n03|5555555555555555526666666662444444444444\n04|1111111111111111122222222222444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---has-minimal-dimensions-for-small-text",
    "content": "--|---------|---------|---------|---------|\n01|January                                 \n02|January Text     ┌ Info ───┐            \n03|June    Function │Month #01│            \n04|July    Function └─────────┘            \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,8                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111123333332222444444444444\n03|5555555555555555526666666662444444444444\n04|5555555555555555522222222222444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---ignores-data-from-first-response-if-server-can-resolve-completion-item",
    "content": "--|---------|---------|---------|---------|-----\n01|April                                        \n02|April Method   ┌ Info ──────────────┐        \n03|~              │local a = \"New info\"│        \n04|~              │                    │        \n05|~              │Month #04           │        \n06|~              └────────────────────┘        \n07|~                                            \n08|~                                            \n09|[No Name] 1,6                                \n10|-- INSERT --                                 \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000000000000\n02|111111111111111233333322222222222222244444444\n03|444444444444444255555555555555555555244444444\n04|444444444444444266666666666666666666244444444\n05|444444444444444266666666666666666666244444444\n06|444444444444444222222222222222222222244444444\n07|444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444\n09|777777777777777777777777777777777777777777777\n10|888888888888999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option",
    "content": "--|---------|---------|---------|---\n01|       January                   \n02|~     ┌──────────────────┐┌…nfo ┐\n03|~     │ January Text     ││Month│\n04|~     │ June    Function ││ #01 │\n05|~     │ July    Function │└─────┘\n06|~     └──────────────────┘       \n07|~                                \n08|~                                \n09|~                                \n10|~                                \n11|~                                \n12|~                                \n13|~                                \n14|[No Name] 1,15                   \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111222222222222222222223444443\n03|111111255555555555555555523666663\n04|111111222222222222222222223666663\n05|111111222222222222222222223333333\n06|111111222222222222222222221111111\n07|111111111111111111111111111111111\n08|111111111111111111111111111111111\n09|111111111111111111111111111111111\n10|111111111111111111111111111111111\n11|111111111111111111111111111111111\n12|111111111111111111111111111111111\n13|111111111111111111111111111111111\n14|777777777777777777777777777777777\n15|888888888888999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-002",
    "content": "--|---------|---------|---------|---\n01|        January                  \n02|┌…nfo ┐┌──────────────────┐      \n03|│Month││ January Text     │      \n04|│ #01 ││ June    Function │      \n05|└─────┘│ July    Function │      \n06|~      └──────────────────┘      \n07|~                                \n08|~                                \n09|~                                \n10|~                                \n11|~                                \n12|~                                \n13|~                                \n14|[No Name] 1,16                   \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|122222133333333333333333333444444\n03|155555136666666666666666663444444\n04|155555133333333333333333333444444\n05|111111133333333333333333333444444\n06|444444433333333333333333333444444\n07|444444444444444444444444444444444\n08|444444444444444444444444444444444\n09|444444444444444444444444444444444\n10|444444444444444444444444444444444\n11|444444444444444444444444444444444\n12|444444444444444444444444444444444\n13|444444444444444444444444444444444\n14|777777777777777777777777777777777\n15|888888888888999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-003",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|January Text     ┌ Info ───┐     \n03|June    Function │Month #01│     \n04|July    Function └─────────┘     \n05|~                                \n06|~                                \n07|~                                \n08|~                                \n09|~                                \n10|~                                \n11|~                                \n12|~                                \n13|~                                \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111112333333222244444\n03|555555555555555552666666666244444\n04|555555555555555552222222222244444\n05|444444444444444444444444444444444\n06|444444444444444444444444444444444\n07|444444444444444444444444444444444\n08|444444444444444444444444444444444\n09|444444444444444444444444444444444\n10|444444444444444444444444444444444\n11|444444444444444444444444444444444\n12|444444444444444444444444444444444\n13|444444444444444444444444444444444\n14|777777777777777777777777777777777\n15|888888888888999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-004",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|┌─────────────────┐Month #01     \n03|│January Text     │              \n04|│June    Function │              \n05|│July    Function │              \n06|└─────────────────┘              \n07|~                                \n08|~                                \n09|~                                \n10|~                                \n11|~                                \n12|~                                \n13|~                                \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111111122222222233333\n03|144444444444444444133333333333333\n04|111111111111111111133333333333333\n05|111111111111111111133333333333333\n06|111111111111111111133333333333333\n07|333333333333333333333333333333333\n08|333333333333333333333333333333333\n09|333333333333333333333333333333333\n10|333333333333333333333333333333333\n11|333333333333333333333333333333333\n12|333333333333333333333333333333333\n13|333333333333333333333333333333333\n14|555555555555555555555555555555555\n15|666666666666777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-005",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|January Text     Month #01       \n03|June    Function                 \n04|July    Function                 \n05|~                                \n06|~                                \n07|~                                \n08|~                                \n09|~                                \n10|~                                \n11|~                                \n12|~                                \n13|~                                \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111112222222223333333\n03|444444444444444443333333333333333\n04|444444444444444443333333333333333\n05|333333333333333333333333333333333\n06|333333333333333333333333333333333\n07|333333333333333333333333333333333\n08|333333333333333333333333333333333\n09|333333333333333333333333333333333\n10|333333333333333333333333333333333\n11|333333333333333333333333333333333\n12|333333333333333333333333333333333\n13|333333333333333333333333333333333\n14|555555555555555555555555555555555\n15|666666666666777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-006",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|┌──────────────────────┐┌ Info ┐ \n03|│January   Text         │Month │ \n04|│February  Text         │#01   │ \n05|│March     Method       └──────┘ \n06|│April     Method                \n07|│May       Method                \n08|│June      Function              \n09|│July      Function              \n10|│August    Function              \n11|│September Constructor │         \n12|│October   Constructor │         \n13|└──────────────────────┘         \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111111111111233333324\n03|155555555555555555555556277777724\n04|111111111111111111111116277777724\n05|111111111111111111111116222222224\n06|111111111111111111111116444444444\n07|111111111111111111111116444444444\n08|111111111111111111111116444444444\n09|111111111111111111111116444444444\n10|111111111111111111111116444444444\n11|111111111111111111111111444444444\n12|111111111111111111111111444444444\n13|111111111111111111111111444444444\n14|888888888888888888888888888888888\n15|999999999999:::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-007",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|January   Text        ┌ Info ───┐\n03|February  Text        │Month #01│\n04|March     Method      └─────────┘\n05|April     Method                 \n06|May       Method                 \n07|June      Function               \n08|July      Function               \n09|August    Function               \n10|September Constructor            \n11|October   Constructor            \n12|November  Constructor            \n13|December  Text                   \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111111111123333332222\n03|444444444444444444444425555555552\n04|444444444444444444444422222222222\n05|444444444444444444444466666666666\n06|444444444444444444444466666666666\n07|444444444444444444444466666666666\n08|444444444444444444444466666666666\n09|444444444444444444444466666666666\n10|444444444444444444444466666666666\n11|444444444444444444444466666666666\n12|444444444444444444444466666666666\n13|444444444444444444444466666666666\n14|777777777777777777777777777777777\n15|888888888888999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-008",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|┌──────────────────────┐Month #01\n03|│January   Text                  \n04|│February  Text                  \n05|│March     Method                \n06|│April     Method                \n07|│May       Method                \n08|│June      Function              \n09|│July      Function              \n10|│August    Function              \n11|│September Constructor │         \n12|│October   Constructor │         \n13|└──────────────────────┘         \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111111111111222222222\n03|133333333333333333333334555555555\n04|111111111111111111111114555555555\n05|111111111111111111111114555555555\n06|111111111111111111111114555555555\n07|111111111111111111111114555555555\n08|111111111111111111111114555555555\n09|111111111111111111111114555555555\n10|111111111111111111111114555555555\n11|111111111111111111111111555555555\n12|111111111111111111111111555555555\n13|111111111111111111111111555555555\n14|666666666666666666666666666666666\n15|777777777777888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-'pumborder'-option-009",
    "content": "--|---------|---------|---------|---\n01|January                          \n02|January   Text        Month #01  \n03|February  Text                   \n04|March     Method                 \n05|April     Method                 \n06|May       Method                 \n07|June      Function               \n08|July      Function               \n09|August    Function               \n10|September Constructor            \n11|October   Constructor            \n12|November  Constructor            \n13|December  Text                   \n14|[No Name] 1,8                    \n15|-- INSERT --                     \n\n--|---------|---------|---------|---\n01|000000000000000000000000000000000\n02|111111111111111111111122222222233\n03|444444444444444444444433333333333\n04|444444444444444444444433333333333\n05|444444444444444444444433333333333\n06|444444444444444444444433333333333\n07|444444444444444444444433333333333\n08|444444444444444444444433333333333\n09|444444444444444444444433333333333\n10|444444444444444444444433333333333\n11|444444444444444444444433333333333\n12|444444444444444444444433333333333\n13|444444444444444444444433333333333\n14|555555555555555555555555555555555\n15|666666666666777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-`config.window.info`",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|December                                                    \n02|December Text  ┌ Info ──────────────────────────────────┐   \n03|~              │a a a a a a a a a a a a a a a a a a a a │   \n04|~              │a a a a a a a a a a a a a a a a a a a a │   \n05|~              │a a a a a a a a a a a a a a a a a a a a │   \n06|~              │a a a a a a a a a a a a a a a a a a a a │   \n07|~              │a a a a a a a a a a a a a a a a a a a a │   \n08|~              │a a a a a a a a a a a a a a a a a a a a │   \n09|~              │a a a a a a a a a a a a a a a a a a a a │   \n10|~              │a a a a a a a a a a a a a a a a a a a a │   \n11|~              │a a a a a a a a a a a a a a a a a a a a │   \n12|~              │a a a a a a a a a a a a a a a a a a a a │   \n13|~              │a a a a a a a a a a a a a a a a a a a a │   \n14|~              │a a a a a a a a a a a a a a a a a a a a │   \n15|~              │a a a a a a a a a a a a a a a a a a a a │   \n16|~              │a a a a a a a a a a a a a a a a a a a a │   \n17|~              │a a a a a a a a a a a a a a a a a a a a │   \n18|~              │a a a a a a a a a a a a a a a a a a a a │   \n19|~              │a a a a a a a a a a a a a a a a a a a a │   \n20|~              │a a a a a a a a a a a a a a a a a a a a │   \n21|~              │a a a a a a a a a a a a a a a a a a a a │   \n22|~              │a a a a a a a a a a a a a a a a a a a a │   \n23|~              └────────────────────────────────────────┘   \n24|[No Name] 1,9                                               \n25|-- INSERT --                                                \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111233333322222222222222222222222222222222222444\n03|444444444444444255555555555555555555555555555555555555552444\n04|444444444444444255555555555555555555555555555555555555552444\n05|444444444444444255555555555555555555555555555555555555552444\n06|444444444444444255555555555555555555555555555555555555552444\n07|444444444444444255555555555555555555555555555555555555552444\n08|444444444444444255555555555555555555555555555555555555552444\n09|444444444444444255555555555555555555555555555555555555552444\n10|444444444444444255555555555555555555555555555555555555552444\n11|444444444444444255555555555555555555555555555555555555552444\n12|444444444444444255555555555555555555555555555555555555552444\n13|444444444444444255555555555555555555555555555555555555552444\n14|444444444444444255555555555555555555555555555555555555552444\n15|444444444444444255555555555555555555555555555555555555552444\n16|444444444444444255555555555555555555555555555555555555552444\n17|444444444444444255555555555555555555555555555555555555552444\n18|444444444444444255555555555555555555555555555555555555552444\n19|444444444444444255555555555555555555555555555555555555552444\n20|444444444444444255555555555555555555555555555555555555552444\n21|444444444444444255555555555555555555555555555555555555552444\n22|444444444444444255555555555555555555555555555555555555552444\n23|444444444444444222222222222222222222222222222222222222222444\n24|666666666666666666666666666666666666666666666666666666666666\n25|777777777777888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---respects-`config.window.info`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|December                                                    \n02|December Text  1 Info 222222222222223                       \n03|~              8a a a a a a a a a a 4                       \n04|~              8a a a a a a a a a a 4                       \n05|~              8a a a a a a a a a a 4                       \n06|~              8a a a a a a a a a a 4                       \n07|~              8a a a a a a a a a a 4                       \n08|~              8a a a a a a a a a a 4                       \n09|~              8a a a a a a a a a a 4                       \n10|~              8a a a a a a a a a a 4                       \n11|~              8a a a a a a a a a a 4                       \n12|~              8a a a a a a a a a a 4                       \n13|~              7666666666666666666665                       \n14|~                                                           \n15|~                                                           \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|~                                                           \n20|~                                                           \n21|~                                                           \n22|~                                                           \n23|~                                                           \n24|[No Name] 1,9                                               \n25|-- INSERT --                                                \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111233333322222222222222244444444444444444444444\n03|444444444444444255555555555555555555244444444444444444444444\n04|444444444444444255555555555555555555244444444444444444444444\n05|444444444444444255555555555555555555244444444444444444444444\n06|444444444444444255555555555555555555244444444444444444444444\n07|444444444444444255555555555555555555244444444444444444444444\n08|444444444444444255555555555555555555244444444444444444444444\n09|444444444444444255555555555555555555244444444444444444444444\n10|444444444444444255555555555555555555244444444444444444444444\n11|444444444444444255555555555555555555244444444444444444444444\n12|444444444444444255555555555555555555244444444444444444444444\n13|444444444444444222222222222222222222244444444444444444444444\n14|444444444444444444444444444444444444444444444444444444444444\n15|444444444444444444444444444444444444444444444444444444444444\n16|444444444444444444444444444444444444444444444444444444444444\n17|444444444444444444444444444444444444444444444444444444444444\n18|444444444444444444444444444444444444444444444444444444444444\n19|444444444444444444444444444444444444444444444444444444444444\n20|444444444444444444444444444444444444444444444444444444444444\n21|444444444444444444444444444444444444444444444444444444444444\n22|444444444444444444444444444444444444444444444444444444444444\n23|444444444444444444444444444444444444444444444444444444444444\n24|666666666666666666666666666666666666666666666666666666666666\n25|777777777777888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---stylizes-markdown-with-concealed-characters",
    "content": "--|---------|---------|---------|---------|-----\n01|July                                         \n02|July Function  ┌ Info ─────────────────────┐ \n03|~              │# Month #07                │ \n04|~              │                           │ \n05|~              │───────────────────────────│ \n06|~              │                           │ \n07|~              │This is markdown text      │ \n08|~              │                           │ \n09|~              │local a = 1                │ \n10|~              └───────────────────────────┘ \n11|~                                            \n12|~                                            \n13|~                                            \n14|[No Name] 1,5                                \n15|-- INSERT --                                 \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000000000000\n02|111111111111111233333322222222222222222222224\n03|444444444444444255555555555666666666666666624\n04|444444444444444266666666666666666666666666624\n05|444444444444444266666666666666666666666666624\n06|444444444444444266666666666666666666666666624\n07|444444444444444266666776888888886666666666624\n08|444444444444444266666666666666666666666666624\n09|44444444444444428888896969:666666666666666624\n10|444444444444444222222222222222222222222222224\n11|444444444444444444444444444444444444444444444\n12|444444444444444444444444444444444444444444444\n13|444444444444444444444444444444444444444444444\n14|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n15|<<<<<<<<<<<<=================================\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---uses-`detail`-to-construct-content",
    "content": "--|---------|---------|---------|---------|-----\n01|April                                        \n02|April  Method   ┌ Info ──────────────┐       \n03|August Function │local a = \"New info\"│       \n04|~               │                    │       \n05|~               │Month #04           │       \n06|~               └────────────────────┘       \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|~                                            \n13|~                                            \n14|[No Name] 1,6                                \n15|-- INSERT --                                 \n\n--|---------|---------|---------|---------|-----\n01|000001111111111111111111111111111111111111111\n02|222222222222222234444443333333333333335555555\n03|666666666666666637777789898::::::::::35555555\n04|555555555555555539999999999999999999935555555\n05|555555555555555539999999999999999999935555555\n06|555555555555555533333333333333333333335555555\n07|555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555\n10|555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555\n14|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n15|<<<<<<<<<<<<=================================\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---uses-`detail`-to-construct-content-002",
    "content": "--|---------|---------|---------|---------|-----\n01|August                                       \n02|April  Method   ┌ Info ───┐                  \n03|August Function │Month #08│                  \n04|~               └─────────┘                  \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|~                                            \n13|~                                            \n14|[No Name] 1,7                                \n15|-- INSERT --                                 \n\n--|---------|---------|---------|---------|-----\n01|000000111111111111111111111111111111111111111\n02|222222222222222234444443333555555555555555555\n03|666666666666666637777777773555555555555555555\n04|555555555555555533333333333555555555555555555\n05|555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555\n10|555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555\n14|888888888888888888888888888888888888888888888\n15|999999999999:::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---uses-`info`-field-from-not-LSP-source",
    "content": "--|---------|---------|---------|\n01|Fall                          \n02|Fall           ┌…fo ┐         \n03|~              │back│         \n04|~              └────┘         \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|[No Name] 1,5                 \n10|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111233332444444444\n03|444444444444444255552444444444\n04|444444444444444222222444444444\n05|444444444444444444444444444444\n06|444444444444444444444444444444\n07|444444444444444444444444444444\n08|444444444444444444444444444444\n09|666666666666666666666666666666\n10|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---works",
    "content": "--|---------|---------|---------|---------|\n01|January                                 \n02|January Text     ┌ Info ───┐            \n03|June    Function │Month #01│            \n04|July    Function └─────────┘            \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,8                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111123333332222444444444444\n03|5555555555555555526666666662444444444444\n04|5555555555555555522222222222444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---works-without-attached-LSP-server",
    "content": "--|---------|---------|---------|---------|\n01|aa                                      \n02|aa             ┌ Info ─┐                \n03|aaa            │Word aa│                \n04|~              └───────┘                \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,3                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111112333333224444444444444444\n03|5555555555555552666666624444444444444444\n04|4444444444444442222222224444444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Information-window---works-without-attached-LSP-server-002",
    "content": "--|---------|---------|---------|---------|\n01|aaa                                     \n02|aa             ┌ Info ──┐               \n03|aaa            │Word aaa│               \n04|~              └────────┘               \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,4                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111112333333222444444444444444\n03|5555555555555552666666662444444444444444\n04|4444444444444442222222222444444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|7777777777777777777777777777777777777777\n10|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Manual-completion---respects-`abbr_hlgroup`-as-item-field",
    "content": "--|---------|---------|---------|---------|\n01|J                                       \n02|January Text                            \n03|June    Function                        \n04|July    Function                        \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,2                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111222222222233333333333333333333333\n03|4444222222222222233333333333333333333333\n04|2222222222222222233333333333333333333333\n05|3333333333333333333333333333333333333333\n06|3333333333333333333333333333333333333333\n07|3333333333333333333333333333333333333333\n08|3333333333333333333333333333333333333333\n09|5555555555555555555555555555555555555555\n10|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Manual-completion---respects-`filterText`-during-built-in-filtering",
    "content": "--|---------|---------|\n01|                    \n02|ab    Unknown       \n03|cba   Unknown       \n04|dcba  Unknown S     \n05|edcba Unknown S     \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 0,1       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111112222\n03|11111111111111112222\n04|11111111111111112222\n05|11111111111111112222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Manual-completion---respects-`filterText`-during-built-in-filtering-002",
    "content": "--|---------|---------|\n01|a                   \n02|cba   Unknown       \n03|dcba  Unknown S     \n04|edcba Unknown S     \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,2       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111112222\n03|11111111111111112222\n04|11111111111111112222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444455555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Manual-completion---respects-`kind_hlgroup`-as-item-field",
    "content": "--|---------|---------|---------|---------|\n01|J                                       \n02|January Text                            \n03|June    Function                        \n04|July    Function                        \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|[No Name] 1,2                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111122221111133333333333333333333333\n03|1111111144444444133333333333333333333333\n04|1111111111111111133333333333333333333333\n05|3333333333333333333333333333333333333333\n06|3333333333333333333333333333333333333333\n07|3333333333333333333333333333333333333333\n08|3333333333333333333333333333333333333333\n09|5555555555555555555555555555555555555555\n10|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Manual-completion---respects-`labelDetails`-from-LSP-response",
    "content": "--|---------|---------|---------|--\n01|                                \n02|January   Text        jan       \n03|February  Text        FEB       \n04|March     Method      mar MAR   \n05|April     Method                \n06|May       Method                \n07|June      Function              \n08|July      Function              \n09|August    Function              \n10|September Constructor           \n11|October   Constructor           \n12|November  Constructor           \n13|December  Text                  \n14|~                               \n15|[No Name] 0,1                   \n16|-- INSERT --                    \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11111111111111111111111111111122\n03|11111111111111111111111111111122\n04|11111111111111111111111111111122\n05|11111111111111111111111111111122\n06|11111111111111111111111111111122\n07|11111111111111111111111111111122\n08|11111111111111111111111111111122\n09|11111111111111111111111111111122\n10|11111111111111111111111111111122\n11|11111111111111111111111111111122\n12|11111111111111111111111111111122\n13|11111111111111111111111111111122\n14|22222222222222222222222222222222\n15|33333333333333333333333333333333\n16|44444444444455555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Manual-completion---uses-`vim.lsp.protocol.CompletionItemKind`-in-LSP-step",
    "content": "--|---------|---------|---------|\n01|Jackpot                       \n02|                              \n03|January   Text                \n04|February  Text                \n05|March     Method              \n06|April     Method              \n07|May       Method              \n08|June      S Something         \n09|July      S Something         \n10|August    S Something         \n11|September Fallback            \n12|October   Fallback            \n13|November  Fallback            \n14|December  Text                \n15|~                             \n16|[No Name] 2,1                 \n17|-- INSERT --                  \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|000000000000000000000000000000\n03|111111111111111111111122222222\n04|111111111111111111111122222222\n05|111111111111111111111122222222\n06|111111111111111111111122222222\n07|111111111111111111111122222222\n08|111111111111111111111122222222\n09|111111111111111111111122222222\n10|111111111111111111111122222222\n11|111111111111111111111122222222\n12|111111111111111111111122222222\n13|111111111111111111111122222222\n14|111111111111111111111122222222\n15|222222222222222222222222222222\n16|333333333333333333333333333333\n17|444444444444555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-both-windows",
    "content": "--|---------|---------|-----\n01|scroll(February          \n02|~      February Text  ┌…┐\n03|~      │aaa │         │a│\n04|~      │bbb │         │b│\n05|~      │ccc │         │c│\n06|~      │ddd │         │d│\n07|~      └────┘         └─┘\n08|~                        \n09|[No Name] 1,16           \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111112222222222222222343\n03|1111111355553111111111353\n04|1111111355553111111111353\n05|1111111355553111111111353\n06|1111111355553111111111353\n07|1111111333333111111111333\n08|1111111111111111111111111\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-both-windows-002",
    "content": "--|---------|---------|-----\n01|scroll(February          \n02|~      February Text  ┌…┐\n03|~      │aaa │         │d│\n04|~      │bbb │         │e│\n05|~      │ccc │         │f│\n06|~      │ddd │         │g│\n07|~      └────┘         └─┘\n08|~                        \n09|[No Name] 1,16           \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111112222222222222222343\n03|1111111355553111111111353\n04|1111111355553111111111353\n05|1111111355553111111111353\n06|1111111355553111111111353\n07|1111111333333111111111333\n08|1111111111111111111111111\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-both-windows-003",
    "content": "--|---------|---------|-----\n01|scroll(February          \n02|~      February Text  ┌…┐\n03|~      │aaa │         │a│\n04|~      │bbb │         │b│\n05|~      │ccc │         │c│\n06|~      │ddd │         │d│\n07|~      └────┘         └─┘\n08|~                        \n09|[No Name] 1,16           \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111112222222222222222343\n03|1111111355553111111111353\n04|1111111355553111111111353\n05|1111111355553111111111353\n06|1111111355553111111111353\n07|1111111333333111111111333\n08|1111111111111111111111111\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-both-windows-004",
    "content": "--|---------|---------|-----\n01|scroll(F                 \n02|~      ┌…re ┐            \n03|~      │<<< │            \n04|~      │fff │            \n05|~      │ggg │            \n06|~      │hhh │            \n07|~      └────┘            \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111233332111111111111\n03|1111111244452111111111111\n04|1111111255552111111111111\n05|1111111255552111111111111\n06|1111111255552111111111111\n07|1111111222222111111111111\n08|1111111111111111111111111\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │a│       \n04|~              │b│       \n05|~              │c│       \n06|~              │d│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window-002",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │d│       \n04|~              │e│       \n05|~              │f│       \n06|~              │g│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window-003",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │g│       \n04|~              │h│       \n05|~              │ │       \n06|~              │ │       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442624444444\n06|4444444444444442624444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|7777777777777777777777777\n10|8888888888889999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window-004",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │h│       \n04|~              │ │       \n05|~              │ │       \n06|~              │ │       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442624444444\n05|4444444444444442624444444\n06|4444444444444442624444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|7777777777777777777777777\n10|8888888888889999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window-005",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │d│       \n04|~              │e│       \n05|~              │f│       \n06|~              │g│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window-006",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │a│       \n04|~              │b│       \n05|~              │c│       \n06|~              │d│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-info-window-007",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │a│       \n04|~              │b│       \n05|~              │c│       \n06|~              │d│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-signature-window",
    "content": "--|---------|---------|-----\n01|scroll(                  \n02|~      ┌…re ┐            \n03|~      │aaa │            \n04|~      │bbb │            \n05|~      │ccc │            \n06|~      │ddd │            \n07|~      └────┘            \n08|~                        \n09|[No Name] 1,8            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111233332111111111111\n03|1111111244442111111111111\n04|1111111244442111111111111\n05|1111111244442111111111111\n06|1111111244442111111111111\n07|1111111222222111111111111\n08|1111111111111111111111111\n09|5555555555555555555555555\n10|6666666666667777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-signature-window-002",
    "content": "--|---------|---------|-----\n01|scroll(                  \n02|~      ┌…re ┐            \n03|~      │<<< │            \n04|~      │fff │            \n05|~      │ggg │            \n06|~      │hhh │            \n07|~      └────┘            \n08|~                        \n09|[No Name] 1,8            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111233332111111111111\n03|1111111244452111111111111\n04|1111111255552111111111111\n05|1111111255552111111111111\n06|1111111255552111111111111\n07|1111111222222111111111111\n08|1111111111111111111111111\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-signature-window-003",
    "content": "--|---------|---------|-----\n01|scroll(                  \n02|~      ┌…re ┐            \n03|~      │<<< │            \n04|~      │    │            \n05|~      │    │            \n06|~      │    │            \n07|~      └────┘            \n08|~                        \n09|[No Name] 1,8            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111233332111111111111\n03|1111111244452111111111111\n04|1111111266662111111111111\n05|1111111266662111111111111\n06|1111111266662111111111111\n07|1111111222222111111111111\n08|1111111111111111111111111\n09|7777777777777777777777777\n10|8888888888889999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-signature-window-004",
    "content": "--|---------|---------|-----\n01|scroll(                  \n02|~      ┌…re ┐            \n03|~      │<<< │            \n04|~      │eee │            \n05|~      │fff │            \n06|~      │ggg │            \n07|~      └────┘            \n08|~                        \n09|[No Name] 1,8            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111233332111111111111\n03|1111111244452111111111111\n04|1111111255552111111111111\n05|1111111255552111111111111\n06|1111111255552111111111111\n07|1111111222222111111111111\n08|1111111111111111111111111\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---can-be-done-in-signature-window-005",
    "content": "--|---------|---------|-----\n01|scroll(                  \n02|~      ┌…re ┐            \n03|~      │aaa │            \n04|~      │bbb │            \n05|~      │ccc │            \n06|~      │ddd │            \n07|~      └────┘            \n08|~                        \n09|[No Name] 1,8            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111233332111111111111\n03|1111111244442111111111111\n04|1111111244442111111111111\n05|1111111244442111111111111\n06|1111111244442111111111111\n07|1111111222222111111111111\n08|1111111111111111111111111\n09|5555555555555555555555555\n10|6666666666667777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---respects-`config.mappings`",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │a│       \n04|~              │b│       \n05|~              │c│       \n06|~              │d│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---respects-`config.mappings`-002",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │d│       \n04|~              │e│       \n05|~              │f│       \n06|~              │g│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Scroll---respects-`config.mappings`-003",
    "content": "--|---------|---------|-----\n01|February                 \n02|February Text  ┌…┐       \n03|~              │a│       \n04|~              │b│       \n05|~              │c│       \n06|~              │d│       \n07|~              └─┘       \n08|~                        \n09|[No Name] 1,9            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112324444444\n03|4444444444444442524444444\n04|4444444444444442524444444\n05|4444444444444442524444444\n06|4444444444444442524444444\n07|4444444444444442224444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---accounts-for-border-when-picking-side",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|abc(                                    \n04|~   ┌ Signature ────────┐               \n05|~   │abc(param1, param2)│               \n06|~   └───────────────────┘               \n07|~                                       \n08|~                                       \n09|[No Name] 3,5                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|1111233333333333222222222111111111111111\n05|1111244445555554444444442111111111111111\n06|1111222222222222222222222111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|6666666666666666666666666666666666666666\n10|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---adjusts-title",
    "content": "--|---------|---------|-----\n01|short(                   \n02|~     ┌… ┐               \n03|~     │aa│               \n04|~     └──┘               \n05|~                        \n06|~                        \n07|~                        \n08|~                        \n09|[No Name] 1,7            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111112332111111111111111\n03|1111112442111111111111111\n04|1111112222111111111111111\n05|1111111111111111111111111\n06|1111111111111111111111111\n07|1111111111111111111111111\n08|1111111111111111111111111\n09|5555555555555555555555555\n10|6666666666667777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---adjusts-title-002",
    "content": "--|---------|---------|-----\n01|short(aa,                \n02|~        ┌ Signature ┐   \n03|~        │bbbbbbbbbbb│   \n04|~        └───────────┘   \n05|~                        \n06|~                        \n07|~                        \n08|~                        \n09|[No Name] 1,10           \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111112333333333332111\n03|1111111112444444444442111\n04|1111111112222222222222111\n05|1111111111111111111111111\n06|1111111111111111111111111\n07|1111111111111111111111111\n08|1111111111111111111111111\n09|5555555555555555555555555\n10|6666666666667777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---adjusts-window-height",
    "content": "--|---------|---------|-----\n01|long(                    \n02|~    ┌…ignature ┐        \n03|~    │a a a a a │        \n04|~    │a a a a a │        \n05|~    │a a a a a │        \n06|~    │a a a a a │        \n07|~    │a a a a a │        \n08|~    └──────────┘        \n09|[No Name] 1,6            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111123333333333211111111\n03|1111124444444444211111111\n04|1111124444444444211111111\n05|1111124444444444211111111\n06|1111124444444444211111111\n07|1111124444444444211111111\n08|1111122222222222211111111\n09|5555555555555555555555555\n10|6666666666667777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---can-be-adjusted-in-event",
    "content": "-|---------|---------|---------|\n1|abc(x,                        \n2|~   ┌─────────────Custom┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,7                 \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111122222222222222333333211111\n3|111124444444444445555554211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---handles-multiline-text",
    "content": "--|---------|---------|---------|-----\n01|multiline(                         \n02|~         ┌ Signature ───────────┐ \n03|~         │multiline( arg1, arg2)│ \n04|~         └──────────────────────┘ \n05|~                                  \n06|~                                  \n07|~                                  \n08|~                                  \n09|[No Name] 1,11                     \n10|-- INSERT --                       \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111112333333333332222222222221\n03|11111111112444444444445555444444421\n04|11111111112222222222222222222222221\n05|11111111111111111111111111111111111\n06|11111111111111111111111111111111111\n07|11111111111111111111111111111111111\n08|11111111111111111111111111111111111\n09|66666666666666666666666666666666666\n10|77777777777788888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---has-minimal-dimensions-for-small-text",
    "content": "-|---------|---------|---------|\n1|abc(                          \n2|~   ┌ Signature ────────┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,5                 \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111123333333333322222222211111\n3|111124444555555444444444211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---respects-`config.window.signature`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|long(                                                                           \n02|~    ┌ Signature ─────────────────────────────┐                                 \n03|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n04|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n05|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n06|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n07|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n08|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n09|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n10|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n11|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n12|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n13|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n14|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n15|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n16|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n17|~    │a a a a a a a a a a a a a a a a a a a a │                                 \n18|~    └────────────────────────────────────────┘                                 \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|[No Name] 1,6                                                                   \n24|-- INSERT --                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111233333333333222222222222222222222222222222111111111111111111111111111111111\n03|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n04|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n05|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n06|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n07|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n08|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n09|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n10|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n11|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n12|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n13|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n14|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n15|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n16|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n17|11111244444444444444444444444444444444444444442111111111111111111111111111111111\n18|11111222222222222222222222222222222222222222222111111111111111111111111111111111\n19|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n21|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n24|66666666666677777777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---respects-`config.window.signature`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|long(                                                                           \n02|~    1 Signature 2222222223                                                     \n03|~    8a a a a a a a a a a 4                                                     \n04|~    8a a a a a a a a a a 4                                                     \n05|~    8a a a a a a a a a a 4                                                     \n06|~    8a a a a a a a a a a 4                                                     \n07|~    8a a a a a a a a a a 4                                                     \n08|~    8a a a a a a a a a a 4                                                     \n09|~    8a a a a a a a a a a 4                                                     \n10|~    8a a a a a a a a a a 4                                                     \n11|~    8a a a a a a a a a a 4                                                     \n12|~    8a a a a a a a a a a 4                                                     \n13|~    7666666666666666666665                                                     \n14|~                                                                               \n15|~                                                                               \n16|~                                                                               \n17|~                                                                               \n18|~                                                                               \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|[No Name] 1,6                                                                   \n24|-- INSERT --                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111233333333333222222222211111111111111111111111111111111111111111111111111111\n03|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n04|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n05|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n06|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n07|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n08|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n09|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n10|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n11|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n12|11111244444444444444444444211111111111111111111111111111111111111111111111111111\n13|11111222222222222222222222211111111111111111111111111111111111111111111111111111\n14|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n15|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n16|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n18|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n19|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n21|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n24|66666666666677777777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---stylizes-markdown-with-concealed-characters",
    "content": "--|---------|---------|---------|---------|---------|---------|-----\n01|string.format(                                                   \n02|~             ┌ Signature ────────────────────────────────────┐  \n03|~             │function string.format(s:string|number, ...any)│  \n04|~             └───────────────────────────────────────────────┘  \n05|~                                                                \n06|~                                                                \n07|~                                                                \n08|~                                                                \n09|[No Name] 1,15                                                   \n10|-- INSERT --                                                     \n\n--|---------|---------|---------|---------|---------|---------|-----\n01|00000012222221333333333333333333333333333333333333333333333333333\n02|44444444444444566666666666555555555555555555555555555555555555544\n03|4444444444444457777777778888889::::::9798888887;;;;;;97888;;;9544\n04|44444444444444555555555555555555555555555555555555555555555555544\n05|44444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444\n09|<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-highlighting-of-active-parameter",
    "content": "-|---------|---------|---------|\n1|abc(                          \n2|~   ┌ Signature ────────┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,5                 \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111123333333333322222222211111\n3|111124444555555444444444211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-highlighting-of-active-parameter-002",
    "content": "-|---------|---------|---------|\n1|abc(1,                        \n2|~   ┌ Signature ────────┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,7                 \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111123333333333322222222211111\n3|111124444444444445555554211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-highlighting-of-active-parameter-003",
    "content": "-|---------|---------|---------|\n1|abc(1,222,                    \n2|~   ┌ Signature ────────┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,11                \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111123333333333322222222211111\n3|111124444444444444444444211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|555555555555555555555555555555\n7|666666666666777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-highlighting-of-active-parameter-004",
    "content": "-|---------|---------|---------|\n1|abc(1,222,                    \n2|~   ┌ Signature ────────┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,8                 \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111123333333333322222222211111\n3|111124444444444445555554211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-highlighting-of-active-parameter-005",
    "content": "-|---------|---------|---------|\n1|multiline(                    \n2|~     ┌ Signature ───────────┐\n3|~     │multiline( arg1, arg2)│\n4|~     └──────────────────────┘\n5|~                             \n6|[No Name] 1,11                \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111111233333333333222222222222\n3|111111244444444444555544444442\n4|111111222222222222222222222222\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-highlighting-of-active-parameter-006",
    "content": "-|---------|---------|---------|\n1|multiline(3,                  \n2|~     ┌ Signature ───────────┐\n3|~     │multiline( arg1, arg2)│\n4|~     └──────────────────────┘\n5|~                             \n6|[No Name] 1,13                \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111111233333333333222222222222\n3|111111244444444444444444555542\n4|111111222222222222222222222222\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-without-delay-with-different-window",
    "content": "-|---------|---------|---------|-----\n1|multiline(                         \n2|abc(111, 2┌ Signature ───────────┐ \n3|~         │multiline( arg1, arg2)│ \n4|~         └──────────────────────┘ \n5|~                                  \n6|~                                  \n7|[No Name] 1,11                     \n8|-- INSERT --                       \n\n-|---------|---------|---------|-----\n1|00000000000000000000000000000000000\n2|00000000001222222222221111111111110\n3|33333333331444444444445555444444413\n4|33333333331111111111111111111111113\n5|33333333333333333333333333333333333\n6|33333333333333333333333333333333333\n7|66666666666666666666666666666666666\n8|77777777777788888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---updates-without-delay-with-different-window-002",
    "content": "-|---------|---------|---------|-----\n1|multiline(                         \n2|abc(111, 222)                      \n3|~          ┌ Signature ────────┐   \n4|~          │abc(param1, param2)│   \n5|~          └───────────────────┘   \n6|~                                  \n7|[No Name] 2,12                     \n8|-- INSERT --                       \n\n-|---------|---------|---------|-----\n1|00000000000000000000000000000000000\n2|00000000000000000000000000000000000\n3|11111111111233333333333222222222111\n4|11111111111244444444444455555542111\n5|11111111111222222222222222222222111\n6|11111111111111111111111111111111111\n7|66666666666666666666666666666666666\n8|77777777777788888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Signature-help---works",
    "content": "-|---------|---------|---------|\n1|abc(                          \n2|~   ┌ Signature ────────┐     \n3|~   │abc(param1, param2)│     \n4|~   └───────────────────┘     \n5|~                             \n6|[No Name] 1,5                 \n7|-- INSERT --                  \n\n-|---------|---------|---------|\n1|000000000000000000000000000000\n2|111123333333333322222222211111\n3|111124444555555444444444211111\n4|111122222222222222222222211111\n5|111111111111111111111111111111\n6|666666666666666666666666666666\n7|777777777777888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---LSP-server-from-'mini.snippets'---works",
    "content": "--|---------|---------|---------|-----\n01|aa                                 \n02|aa    Snippet S ┌ Info ────────┐   \n03|bb cc Snippet S │Snippet $1 aa │   \n04|~               │              │   \n05|~               │The aa snippet│   \n06|~               └──────────────┘   \n07|~                                  \n08|~                                  \n09|[No Name] 1,3                      \n10|-- INSERT --                       \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111112333333222222222444\n03|55555555555555552666666666666672444\n04|44444444444444442777777777777772444\n05|44444444444444442777777777777772444\n06|44444444444444442222222222222222444\n07|44444444444444444444444444444444444\n08|44444444444444444444444444444444444\n09|88888888888888888888888888888888888\n10|999999999999:::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---LSP-server-from-'mini.snippets'---works-with-in-server-matching",
    "content": "--|---------|---------|---------|-----\n01|bb c                               \n02|bb cc Snippet S                    \n03|~                                  \n04|~                                  \n05|~                                  \n06|~                                  \n07|~                                  \n08|~                                  \n09|[No Name] 1,5                      \n10|-- INSERT --                       \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111112222222222222222222\n03|22222222222222222222222222222222222\n04|22222222222222222222222222222222222\n05|22222222222222222222222222222222222\n06|22222222222222222222222222222222222\n07|22222222222222222222222222222222222\n08|22222222222222222222222222222222222\n09|33333333333333333333333333333333333\n10|44444444444455555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---are-not-inserted-if-have-no-tabstops-or-variables",
    "content": "--|---------|---------|---------|---------|---------|--\n01|                                                    \n02|Just text                                Snippet    \n03|Text with \\$1 escaped dollar             Snippet    \n04|Text with \\$TM_FILENAME escaped dollar   Snippet    \n05|Text with \\${1} escaped dollar           Snippet    \n06|Text with \\${TM_FILENAME} escaped dollar Snippet    \n07|Has $TM_FILENAME variable                Snippet S  \n08|Has $var variable                        Snippet S  \n09|Has $1 tabstop                           Snippet S  \n10|$1 has tabstop                           Snippet S  \n11|Has ${1} tabstop                         Snippet S  \n12|${1} has tabstop                         Snippet S  \n13|Has ${1:aaa} tabstop                     Snippet S  \n14|Has $0 tabstop                           Snippet S  \n15|Has ${0} tabstop                         Snippet S  \n16|Has tabstop$0                            Snippet S  \n17|Has  tab                                 Snippet S  \n18|Has^@newline                             Snippet S  \n19|~                                                   \n20|[No Name] 0,1                                       \n21|-- INSERT --                                        \n\n--|---------|---------|---------|---------|---------|--\n01|0000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111112\n03|1111111111111111111111111111111111111111111111111112\n04|1111111111111111111111111111111111111111111111111112\n05|1111111111111111111111111111111111111111111111111112\n06|1111111111111111111111111111111111111111111111111112\n07|1111111111111111111111111111111111111111111111111112\n08|1111111111111111111111111111111111111111111111111112\n09|1111111111111111111111111111111111111111111111111112\n10|1111111111111111111111111111111111111111111111111112\n11|1111111111111111111111111111111111111111111111111112\n12|1111111111111111111111111111111111111111111111111112\n13|1111111111111111111111111111111111111111111111111112\n14|1111111111111111111111111111111111111111111111111112\n15|1111111111111111111111111111111111111111111111111112\n16|1111111111111111111111111111111111111111111111111112\n17|1111111111111111111111111111111111111111111111111112\n18|1111111111111111111111111111111111111111111111111112\n19|2222222222222222222222222222222222222222222222222222\n20|3333333333333333333333333333333333333333333333333333\n21|4444444444445555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---properly-show-special-symbol-in-popup",
    "content": "--|---------|---------|---------|-----\n01|                                   \n02|Snippet A1 $1 Snippet  S Det       \n03|Snippet A2 $1 Snippet  S Desc      \n04|Snippet A2 $1 Snippet  S Det Desc  \n05|OnlyText      Snippet              \n06|NotASnippet   Function             \n07|~                                  \n08|~                                  \n09|[No Name] 0,1                      \n10|-- INSERT --                       \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111111111111111111111112\n03|11111111111111111111111111111111112\n04|11111111111111111111111111111111112\n05|11111111111111111111111111111111112\n06|11111111111111111111111111111111112\n07|22222222222222222222222222222222222\n08|22222222222222222222222222222222222\n09|33333333333333333333333333333333333\n10|44444444444455555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---respect-'mini.snippets'-config",
    "content": "--|---------|---------|-----\n01|Snippet_!(∎) Hello       \n02|~                        \n03|~                        \n04|~                        \n05|~                        \n06|~                        \n07|~                        \n08|~                        \n09|[No Name] 1,9-10         \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000012320000000000000\n02|4444444444444444444444444\n03|4444444444444444444444444\n04|4444444444444444444444444\n05|4444444444444444444444444\n06|4444444444444444444444444\n07|4444444444444444444444444\n08|4444444444444444444444444\n09|5555555555555555555555555\n10|6666666666667777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---show-full-snippet-text-as-info",
    "content": "--|---------|---------|-----\n01|May                      \n02|May Function S ┌ Info ──┐\n03|~              │May the │\n04|~              │$1 be   │\n05|~              │with you│\n06|~              └────────┘\n07|~                        \n08|~                        \n09|[No Name] 1,4            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111112333333222\n03|4444444444444442555555552\n04|4444444444444442555555552\n05|4444444444444442555555552\n06|4444444444444442222222222\n07|4444444444444444444444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---show-full-snippet-text-as-info-002",
    "content": "--|---------|---------|-----\n01|January                  \n02|January Function S ┌…fo ┐\n03|~                  │Mont│\n04|~                  │h   │\n05|~                  │#01 │\n06|~                  └────┘\n07|~                        \n08|~                        \n09|[No Name] 1,8            \n10|-- INSERT --             \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111111111233332\n03|4444444444444444444255552\n04|4444444444444444444255552\n05|4444444444444444444255552\n06|4444444444444444444222222\n07|4444444444444444444444444\n08|4444444444444444444444444\n09|6666666666666666666666666\n10|7777777777778888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_completion.lua---Snippets---work",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|Snippet A $1              Snippet  S    \n03|Snippet B $1              Function S    \n04|Snip C                    Function S    \n05|Snip D                    Function S    \n06|Snip E                    Function S    \n07|Snippet F^@Multi^@Line $1 Snippet  S    \n08|Snip G                    Snippet  S    \n09|[No Name] 0,1                           \n10|-- INSERT --                            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111222\n03|1111111111111111111111111111111111111222\n04|1111111111111111111111111111111111111222\n05|1111111111111111111111111111111111111222\n06|1111111111111111111111111111111111111222\n07|1111111111111111111111111111111111111222\n08|1111111111111111111111111111111111111222\n09|3333333333333333333333333333333333333333\n10|4444444444445555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_cursorword.lua---Highlighting---can-stop",
    "content": "-|---------|-----\n1|a aa aaa       \n2|aa aaa a       \n3|aaa a aa       \n4|[No Name] 1,1  \n5|-- INSERT --   \n\n-|---------|-----\n1|000000000000000\n2|000000000000000\n3|000000000000000\n4|111111111111111\n5|222222222222333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cursorword.lua---Highlighting---respects-MiniCursorwordCurrent-highlight-group",
    "content": "-|---------|--\n1|a aa aaa    \n2|aa aaa a    \n3|aaa a aa    \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|111111121111\n3|111121111111\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_cursorword.lua---Highlighting---works",
    "content": "-|---------|--\n1|a aa aaa    \n2|aa aaa a    \n3|aaa a aa    \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|111111101111\n3|111101111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cursorword.lua---Highlighting---works-on-multibyte-character",
    "content": "-|---------|--\n1|ы ыы ыыы    \n2|ыы ыыы ы    \n3|ыыы ы ыы    \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|111111101111\n3|111101111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cursorword.lua---Highlighting---works-on-multibyte-character-002",
    "content": "-|---------|--\n1|      \n2|      \n3|      \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|111111101111\n3|111101111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_cursorword.lua---Highlighting---works-with-multiple-windows",
    "content": "-|---------|---------|---------|---------|\n1|a aa aaa            │a aa aaa           \n2|aa aaa a            │aa aaa a           \n3|aaa a aa            │aaa a aa           \n4|[No Name] 2,1        [No Name] 1,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0011000000000000000023444444444444444444\n2|1100000000000000000024444444344444444444\n3|0000001100000000000024444344444444444444\n4|5555555555555555555556666666666666666666\n5|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---Commands----DepsAdd-works",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~        plu-gin_0.nvim       \n07|~        plugin_1             \n08|~        plugin_2             \n09|~        plugin_3             \n10|:DepsAdd plu-gin_0.nvim       \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112222222222222222111111\n07|111111113333333333333333111111\n08|111111113333333333333333111111\n09|111111113333333333333333111111\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---Commands----DepsShowLog-works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|========== Update 2024-01-02 03:04:05 ==========            \n02|+++ plugin_1 +++                                            \n03|Path:         MOCKDIR/pack/deps/opt/plugin_1                \n04|Source:       https://github.com/user/plugin_1              \n05|State before: sha1head                                      \n06|State after:  new1head (main)                               \n07|                                                            \n08|Pending updates from `main`:                                \n09|> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim          \n10|  Added commit in checkout.                                 \n11|                                                            \n12|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000111111111111\n02|222222222222222211111111111111111111111111111111111111111111\n03|111111111111113333333333333333333333333333331111111111111111\n04|111111111111113333333333333333333333333333333311111111111111\n05|111111111111113333333311111111111111111111111111111111111111\n06|111111111111113333333314444441111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111\n09|555555555555555555555555555555555555555555555555551111111111\n10|111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111\n12|666666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---Commands----DepsUpdate-works",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~           plugin_1          \n09|~           plugin_2          \n10|:DepsUpdate plugin_1          \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111112222222222222222111\n09|111111111113333333333333333111\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---Commands----DepsUpdateOffline-works",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                  plugin_1   \n08|~                  plugin_2   \n09|~                             \n10|:DepsUpdateOffline plugin_1   \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111222222222221\n08|111111111111111111333333333331\n09|111111111111111111111111111111\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---clean()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before a clean.                                   \n02|                                                                                \n03|Lines `- <plugin>` show plugins to be deleted from disk.                        \n04|Remove line to not delete that plugin.                                          \n05|                                                                                \n06|To finish clean, write this buffer (for example, with `:write` command).        \n07|To cancel clean, close this window (for example, with `:close` command).        \n08|                                                                                \n09|- plugin_not_in_session_1                                                       \n10|- plugin_not_in_session_2                                                       \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000011111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000111111111111111111111111\n04|00000000000000000000000000000000000000111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|00000000000000000000000000000000000000000000000000000000000000000000000011111111\n07|00000000000000000000000000000000000000000000000000000000000000000000000011111111\n08|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n12|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n13|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n14|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---clean()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before a clean.                                   \n02|                                                                                \n03|Lines `- <plugin>` show plugins to be deleted from disk.                        \n04|Remove line to not delete that plugin.                                          \n05|                                                                                \n06|To finish clean, write this buffer (for example, with `:write` command).        \n07|To cancel clean, close this window (for example, with `:close` command).        \n08|                                                                                \n09|- plugin_not_in_session_1 (MOCKDIR/pack/deps/opt/plugin_not_in_session_1)       \n10|- plugin_not_in_session_2                                                       \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000011111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000111111111111111111111111\n04|00000000000000000000000000000000000000111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|00000000000000000000000000000000000000000000000000000000000000000000000011111111\n07|00000000000000000000000000000000000000000000000000000000000000000000000011111111\n08|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111112222222222222222222222222222222222222222222222221111111\n10|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n12|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n13|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n14|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n15|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---update()---can-fold-in-confirm-buffer",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before an update.                                 \n02|                                                                                \n03|Line `+++ <plugin_name> +++` means plugin will be updated.                      \n04|See update details below it.                                                    \n05|Changes starting with \">\"/\"<\" will be added/removed.                            \n06|Remove the line to not update that plugin.                                      \n07|                                                                                \n08|Line `--- <plugin_name> ---` means plugin has nothing to update.                \n09|                                                                                \n10|Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.    \n11|See error details below it.                                                     \n12|                                                                                \n13|Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.                \n14|To finish update, write this buffer (for example, with `:write` command).       \n15|To cancel update, close this window (for example, with `:close` command).       \n16|                                                                                \n17|!!! plugin_3 !!!                                                                \n18|  >> ···········································································\n19|                                                                                \n20|+++ plugin_2 +++                                                                \n21|  >> Path:         MOCKDIR/pack/deps/opt/plugin_2·······························\n22|                                                                                \n23|--- plugin_1 ---                                                                \n24|  >> Path:   MOCKDIR/pack/deps/opt/plugin_1·····································\n25|~                                                                               \n26|~                                                                               \n27|~                                                                               \n28|~                                                                               \n29|~                                                                               \n30|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000001111111111111111111111\n04|00000000000000000000000000001111111111111111111111111111111111111111111111111111\n05|00000000000000000000000000000000000000000000000000001111111111111111111111111111\n06|00000000000000000000000000000000000000000011111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000001111\n11|00000000000000000000000000011111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n14|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n16|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|22222222222222221111111111111111111111111111111111111111111111111111111111111111\n18|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n19|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|44444444444444441111111111111111111111111111111111111111111111111111111111111111\n21|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n22|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|55555555555555551111111111111111111111111111111111111111111111111111111111111111\n24|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n25|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n26|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n27|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n28|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n29|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n30|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---update()---can-highlight-breaking-changes",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before an update.                                 \n02|                                                                                \n03|Line `+++ <plugin_name> +++` means plugin will be updated.                      \n04|See update details below it.                                                    \n05|Changes starting with \">\"/\"<\" will be added/removed.                            \n06|Remove the line to not update that plugin.                                      \n07|                                                                                \n08|Line `--- <plugin_name> ---` means plugin has nothing to update.                \n09|                                                                                \n10|Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.    \n11|See error details below it.                                                     \n12|                                                                                \n13|Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.                \n14|To finish update, write this buffer (for example, with `:write` command).       \n15|To cancel update, close this window (for example, with `:close` command).       \n16|                                                                                \n17|+++ plugin_1 +++                                                                \n18|Path:         MOCKDIR/pack/deps/opt/plugin_1                                    \n19|Source:       https://github.com/user/plugin_1                                  \n20|State before: sha1head                                                          \n21|State after:  wow1head (main)                                                   \n22|                                                                                \n23|Pending updates from `main`:                                                    \n24|< sha2head | 2024-01-02 01:01:01 +0200 | Neo McVim                              \n25|  feat!: a breaking feature                                                     \n26|> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim                              \n27|  fix(deps)!: a breaking fix                                                    \n28|> wow2head | 2024-01-02 03:03:03 +0200 | Neo McVim                              \n29|  fix: not a fix!: breaking change                                              \n30|~                                                                               \n31|~                                                                               \n32|~                                                                               \n33|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000001111111111111111111111\n04|00000000000000000000000000001111111111111111111111111111111111111111111111111111\n05|00000000000000000000000000000000000000000000000000001111111111111111111111111111\n06|00000000000000000000000000000000000000000011111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000001111\n11|00000000000000000000000000011111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n14|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n16|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|22222222222222221111111111111111111111111111111111111111111111111111111111111111\n18|11111111111111333333333333333333333333333333111111111111111111111111111111111111\n19|11111111111111333333333333333333333333333333331111111111111111111111111111111111\n20|11111111111111333333331111111111111111111111111111111111111111111111111111111111\n21|11111111111111333333331000000111111111111111111111111111111111111111111111111111\n22|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n24|44444444444444444444444444444444444444444444444444111111111111111111111111111111\n25|55555555555555555555555555511111111111111111111111111111111111111111111111111111\n26|66666666666666666666666666666666666666666666666666111111111111111111111111111111\n27|55555555555555555555555555551111111111111111111111111111111111111111111111111111\n28|66666666666666666666666666666666666666666666666666111111111111111111111111111111\n29|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n30|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n31|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n32|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n33|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---update()---can-work-with-non-default-branches",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before an update.                                 \n02|                                                                                \n03|Line `+++ <plugin_name> +++` means plugin will be updated.                      \n04|See update details below it.                                                    \n05|Changes starting with \">\"/\"<\" will be added/removed.                            \n06|Remove the line to not update that plugin.                                      \n07|                                                                                \n08|Line `--- <plugin_name> ---` means plugin has nothing to update.                \n09|                                                                                \n10|Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.    \n11|See error details below it.                                                     \n12|                                                                                \n13|Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.                \n14|To finish update, write this buffer (for example, with `:write` command).       \n15|To cancel update, close this window (for example, with `:close` command).       \n16|                                                                                \n17|+++ plugin_1 +++                                                                \n18|Path:         MOCKDIR/pack/deps/opt/plugin_1                                    \n19|Source:       https://github.com/user/plugin_1                                  \n20|State before: sha1head                                                          \n21|State after:  new1head (hello)                                                  \n22|                                                                                \n23|Pending updates from `hello`:                                                   \n24|> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim                              \n25|  Added commit in checkout.                                                     \n26|                                                                                \n27|Monitor updates from `world`:                                                   \n28|> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim                              \n29|  Added commit in monitor.                                                      \n30|~                                                                               \n31|~                                                                               \n32|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000001111111111111111111111\n04|00000000000000000000000000001111111111111111111111111111111111111111111111111111\n05|00000000000000000000000000000000000000000000000000001111111111111111111111111111\n06|00000000000000000000000000000000000000000011111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000001111\n11|00000000000000000000000000011111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n14|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n16|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|22222222222222221111111111111111111111111111111111111111111111111111111111111111\n18|11111111111111333333333333333333333333333333111111111111111111111111111111111111\n19|11111111111111333333333333333333333333333333331111111111111111111111111111111111\n20|11111111111111333333331111111111111111111111111111111111111111111111111111111111\n21|11111111111111333333331000000011111111111111111111111111111111111111111111111111\n22|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n24|44444444444444444444444444444444444444444444444444111111111111111111111111111111\n25|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n26|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n27|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n28|44444444444444444444444444444444444444444444444444111111111111111111111111111111\n29|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n30|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n31|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n32|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---update()---shows-empty-monitor-log",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before an update.                                 \n02|                                                                                \n03|Line `+++ <plugin_name> +++` means plugin will be updated.                      \n04|See update details below it.                                                    \n05|Changes starting with \">\"/\"<\" will be added/removed.                            \n06|Remove the line to not update that plugin.                                      \n07|                                                                                \n08|Line `--- <plugin_name> ---` means plugin has nothing to update.                \n09|                                                                                \n10|Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.    \n11|See error details below it.                                                     \n12|                                                                                \n13|Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.                \n14|To finish update, write this buffer (for example, with `:write` command).       \n15|To cancel update, close this window (for example, with `:close` command).       \n16|                                                                                \n17|--- plugin_1 ---                                                                \n18|Path:   MOCKDIR/pack/deps/opt/plugin_1                                          \n19|Source: https://github.com/user/plugin_1                                        \n20|State:  sha1head (hello)                                                        \n21|                                                                                \n22|Monitor updates from `world`:                                                   \n23|<Nothing>                                                                       \n24|~                                                                               \n25|~                                                                               \n26|~                                                                               \n27|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000001111111111111111111111\n04|00000000000000000000000000001111111111111111111111111111111111111111111111111111\n05|00000000000000000000000000000000000000000000000000001111111111111111111111111111\n06|00000000000000000000000000000000000000000011111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000001111\n11|00000000000000000000000000011111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n14|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n16|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|22222222222222221111111111111111111111111111111111111111111111111111111111111111\n18|11111111333333333333333333333333333333111111111111111111111111111111111111111111\n19|11111111333333333333333333333333333333331111111111111111111111111111111111111111\n20|11111111333333331000000011111111111111111111111111111111111111111111111111111111\n21|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|44444444411111111111111111111111111111111111111111111111111111111111111111111111\n24|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n25|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n26|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n27|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_deps.lua---update()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|This is a confirmation report before an update.                                 \n02|                                                                                \n03|Line `+++ <plugin_name> +++` means plugin will be updated.                      \n04|See update details below it.                                                    \n05|Changes starting with \">\"/\"<\" will be added/removed.                            \n06|Remove the line to not update that plugin.                                      \n07|                                                                                \n08|Line `--- <plugin_name> ---` means plugin has nothing to update.                \n09|                                                                                \n10|Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.    \n11|See error details below it.                                                     \n12|                                                                                \n13|Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.                \n14|To finish update, write this buffer (for example, with `:write` command).       \n15|To cancel update, close this window (for example, with `:close` command).       \n16|                                                                                \n17|!!! plugin_3 !!!                                                                \n18|                                                                                \n19|ERROR CODE 1                                                                    \n20|Error computing origin                                                          \n21|                                                                                \n22|+++ plugin_2 +++                                                                \n23|Path:         MOCKDIR/pack/deps/opt/plugin_2                                    \n24|Source:       https://new_source/plugin_2                                       \n25|State before: sha2head                                                          \n26|State after:  new2head (master)                                                 \n27|                                                                                \n28|Pending updates from `master`:                                                  \n29|< sha2head | 2024-01-02 01:01:01 +0200 | Neo McVim                              \n30|  Removed commit in plugin_2.                                                   \n31|> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim                              \n32|  Added commit in plugin_2.                                                     \n33|                                                                                \n34|--- plugin_1 ---                                                                \n35|Path:   MOCKDIR/pack/deps/opt/plugin_1                                          \n36|Source: https://github.com/user/plugin_1                                        \n37|State:  sha1head (main)                                                         \n38|~                                                                               \n39|~                                                                               \n40|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|00000000000000000000000000000000000000000000000000000000001111111111111111111111\n04|00000000000000000000000000001111111111111111111111111111111111111111111111111111\n05|00000000000000000000000000000000000000000000000000001111111111111111111111111111\n06|00000000000000000000000000000000000000000011111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000001111\n11|00000000000000000000000000011111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|00000000000000000000000000000000000000000000000000000000000000001111111111111111\n14|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000001111111\n16|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|22222222222222221111111111111111111111111111111111111111111111111111111111111111\n18|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n19|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n21|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|33333333333333331111111111111111111111111111111111111111111111111111111111111111\n23|11111111111111444444444444444444444444444444111111111111111111111111111111111111\n24|11111111111111444444444444444444444444444111111111111111111111111111111111111111\n25|11111111111111444444441111111111111111111111111111111111111111111111111111111111\n26|11111111111111444444441000000001111111111111111111111111111111111111111111111111\n27|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n28|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n29|55555555555555555555555555555555555555555555555555111111111111111111111111111111\n30|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n31|66666666666666666666666666666666666666666666666666111111111111111111111111111111\n32|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n33|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n34|77777777777777771111111111111111111111111111111111111111111111111111111111111111\n35|11111111444444444444444444444444444444111111111111111111111111111111111111111111\n36|11111111444444444444444444444444444444441111111111111111111111111111111111111111\n37|11111111444444441000000111111111111111111111111111111111111111111111111111111111\n38|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n39|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n40|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Diff---`MiniDiffUpdated`-event-can-be-used-to-override-`minidiff_summary_string`-variable",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ uuu          \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|Hello          \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Diff---redraws-statusline-when-diff-is-updated",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ uuu          \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|#1 +1          \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Diff---redraws-statusline-when-diff-is-updated-002",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ uuu          \n03|▒ hello        \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|#1 +2          \n10|-- INSERT --   \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|221111111111111\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---always-highlights-whole-lines",
    "content": "--|---------|---------|-----\n01|  AAA                    \n02|▒ uuu                    \n03|  BBB                    \n04|  CCC                    \n05|▒ CcC                    \n06|▒ DDD                    \n07|  EEE                    \n08|  FFF                    \n09|[No Name] 1,1            \n10|                         \n\n--|---------|---------|-----\n01|0011111111111111111111111\n02|2233333333333333333333333\n03|0011111111111111111111111\n04|0045444444444444444444444\n05|6678777777777777777777777\n06|9911111111111111111111111\n07|00:::::::::::::::::::::::\n08|0011111111111111111111111\n09|;;;;;;;;;;;;;;;;;;;;;;;;;\n10|<<<<<<<<<<<<<<<<<<<<<<<<<\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---scrolls-along-with-buffer-lines",
    "content": "--|---------|-----\n01|▒ ghijklmnopqrs\n02|  ghijklmnopqrs\n03|  ghijklmnopqrs\n04|  ghijklmnopqrs\n05|▒ GHIJKLMNOPQRS\n06|  ghijklmnopqrs\n07|  ghijklmnopqrs\n08|~              \n09|[No Name] 1,8  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|221111111111111\n04|224444444444444\n05|556666666666666\n06|223333333333333\n07|221111111111111\n08|222222222222222\n09|777777777777777\n10|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---scrolls-along-with-buffer-lines-002",
    "content": "--|---------|-----\n01|▒ ghijklmnopqrs\n02|  ghijklmnopqrs\n03|  ghijklmnopqrs\n04|  ghijklmnopqrs\n05|  ghijklmnopqrs\n06|▒ GHIJKLMNOPQRS\n07|  ghijklmnopqrs\n08|~              \n09|[No Name] 1,8  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|221111111111111\n04|224444444444444\n05|224444444444444\n06|556666666666666\n07|221111111111111\n08|222222222222222\n09|777777777777777\n10|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---has-non-zero-interhunk-context",
    "content": "--|---------|-----\n01|  1234567890   \n02|▒ __34567890   \n03|  1234567890   \n04|▒ _2_4567890   \n05|  1234567890   \n06|▒ _23_567890   \n07|  1234567890   \n08|▒ _234_67890   \n09|  1234567890   \n10|▒ _2345_7890   \n11|  1234567890   \n12|▒ _23456_890   \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001122222222222\n02|334455555555555\n03|001112222222222\n04|334445555555555\n05|001111222222222\n06|334444555555555\n07|001111122222222\n08|334444455555555\n09|001111112222222\n10|334444445555555\n11|001222221222222\n12|334555554555555\n13|000000000000000\n14|666666666666666\n15|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works",
    "content": "--|---------|-----\n01|  AAA          \n02|  B_BBB_B      \n03|▒ b_BBB_b      \n04|  CCC          \n05|▒ CCcccC       \n06|  DDdddD       \n07|▒ DDD          \n08|  EEE          \n09|▒ xxx          \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|002333332333333\n03|445666665666666\n04|003333333333333\n05|446655566666666\n06|003322233333333\n07|446666666666666\n08|002223333333333\n09|445556666666666\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|777777777777777\n15|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-BOM-bytes",
    "content": "--|---------|-----\n01|  <feff>bbb    \n02|▒ bBb          \n03|  vvv          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|~              \n10|~              \n11|~              \n12|~              \n13|~              \n14|<f/file-bom 1,1\n15|               \n\n--|---------|-----\n01|001111111211111\n02|334544444444444\n03|006666666666666\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|777777777777777\n15|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters",
    "content": "--|---------|-----\n01|  ыыы          \n02|▒ фыы          \n03|  ыыы          \n04|▒ ыфы          \n05|  ыыы          \n06|▒ ыыф          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334555555555555\n03|002122222222222\n04|335455555555555\n05|002212222222222\n06|335545555555555\n07|000000000000000\n08|000000000000000\n09|666666666666666\n10|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-002",
    "content": "--|---------|-----\n01|  фыы          \n02|▒ ыыы          \n03|  ыфы          \n04|▒ ыыы          \n05|  ыыф          \n06|▒ ыыы          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334555555555555\n03|002122222222222\n04|335455555555555\n05|002212222222222\n06|335545555555555\n07|000000000000000\n08|000000000000000\n09|666666666666666\n10|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-003",
    "content": "--|---------|-----\n01|  ыы           \n02|▒ фыы          \n03|  ыы           \n04|▒ ыфы          \n05|  ыы           \n06|▒ ыыф          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223444444444444\n03|001111111111111\n04|224344444444444\n05|001111111111111\n06|224434444444444\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-004",
    "content": "--|---------|-----\n01|  фыы          \n02|▒ ыы           \n03|  ыфы          \n04|▒ ыы           \n05|  ыыф          \n06|▒ ыы           \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334444444444444\n03|002122222222222\n04|334444444444444\n05|002212222222222\n06|334444444444444\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-005",
    "content": "--|---------|-----\n01|  ▒▒▒          \n02|▒ ┃▒▒          \n03|  ▒▒▒          \n04|▒ ▒┃▒          \n05|  ▒▒▒          \n06|▒ ▒▒┃          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334555555555555\n03|002122222222222\n04|335455555555555\n05|002212222222222\n06|335545555555555\n07|000000000000000\n08|000000000000000\n09|666666666666666\n10|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-006",
    "content": "--|---------|-----\n01|  ┃▒▒          \n02|▒ ▒▒▒          \n03|  ▒┃▒          \n04|▒ ▒▒▒          \n05|  ▒▒┃          \n06|▒ ▒▒▒          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334555555555555\n03|002122222222222\n04|335455555555555\n05|002212222222222\n06|335545555555555\n07|000000000000000\n08|000000000000000\n09|666666666666666\n10|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-007",
    "content": "--|---------|-----\n01|  ▒▒           \n02|▒ ┃▒▒          \n03|  ▒▒           \n04|▒ ▒┃▒          \n05|  ▒▒           \n06|▒ ▒▒┃          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223444444444444\n03|001111111111111\n04|224344444444444\n05|001111111111111\n06|224434444444444\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-008",
    "content": "--|---------|-----\n01|  ┃▒▒          \n02|▒ ▒▒           \n03|  ▒┃▒          \n04|▒ ▒▒           \n05|  ▒▒┃          \n06|▒ ▒▒           \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334444444444444\n03|002122222222222\n04|334444444444444\n05|002212222222222\n06|334444444444444\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-009",
    "content": "--|---------|-----\n01|  xxx          \n02|▒ ыxx          \n03|  xxx          \n04|▒ xыx          \n05|  xxx          \n06|▒ xxы          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334555555555555\n03|002122222222222\n04|335455555555555\n05|002212222222222\n06|335545555555555\n07|000000000000000\n08|000000000000000\n09|666666666666666\n10|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-multibyte-characters-010",
    "content": "--|---------|-----\n01|  ыxx          \n02|▒ xxx          \n03|  xыx          \n04|▒ xxx          \n05|  xxы          \n06|▒ xxx          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001222222222222\n02|334555555555555\n03|002122222222222\n04|335455555555555\n05|002212222222222\n06|335545555555555\n07|000000000000000\n08|000000000000000\n09|666666666666666\n10|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-one-of-lines-being-empty",
    "content": "-|---------|-----\n1|  uuu          \n2|  AAA          \n3|▒              \n4|  vvv          \n5|~              \n6|[No Name] 1,1  \n7|               \n\n-|---------|-----\n1|001111111111111\n2|002223333333333\n3|445555555555555\n4|001111111111111\n5|000000000000000\n6|666666666666666\n7|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---word-diff---works-with-one-of-lines-being-empty-002",
    "content": "-|---------|-----\n1|  uuu          \n2|               \n3|▒ AAA          \n4|  vvv          \n5|~              \n6|[No Name] 1,1  \n7|               \n\n-|---------|-----\n1|001111111111111\n2|002222222222222\n3|334445555555555\n4|001111111111111\n5|000000000000000\n6|666666666666666\n7|777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|  CCC          \n05|▒ CcC          \n06|▒ DDD          \n07|  EEE          \n08|  FFF          \n09|~              \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|004544444444444\n05|667877777777777\n06|991111111111111\n07|00:::::::::::::\n08|001111111111111\n09|000000000000000\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|;;;;;;;;;;;;;;;\n15|<<<<<<<<<<<<<<<\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-002",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|  CCC          \n05|▒ CcC          \n06|▒ DDD          \n07|  EEE          \n08|  EeE          \n09|  FFF          \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 6,4  \n15|-- INSERT --   \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|004544444444444\n05|667877777777777\n06|991111111111111\n07|00:::::::::::::\n08|001111111111111\n09|001111111111111\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|;;;;;;;;;;;;;;;\n15|<<<<<<<<<<<<===\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-003",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|  CCC          \n05|▒ CcC          \n06|  DDD          \n07|  EEE          \n08|▒ EeE          \n09|  FFF          \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 6,4  \n15|-- INSERT --   \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|004544444444444\n05|667877777777777\n06|001111111111111\n07|004544444444444\n08|667877777777777\n09|001111111111111\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|999999999999999\n15|::::::::::::;;;\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-at-edge-lines",
    "content": "--|---------|-----\n01|▒ uuu          \n02|  aaa          \n03|▒ vvv          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-at-edge-lines-002",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ AaA          \n03|  BBB          \n04|  CCC          \n05|▒ CcC          \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001211111111111\n02|334544444444444\n03|006666666666666\n04|001211111111111\n05|334544444444444\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|777777777777777\n10|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-at-edge-lines-003",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ BBB          \n03|  DDD          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-when-'change'-overlaps-with-'delete'",
    "content": "--|---------|-----\n01|  AAA          \n02|  BBB          \n03|▒ BbB          \n04|  CCC          \n05|  DDD          \n06|~              \n07|~              \n08|~              \n09|~              \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|002322222222222\n03|445655555555555\n04|007777777777777\n05|001111111111111\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|888888888888888\n15|999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-with-'add'-hunks",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ uuu          \n03|▒ vvv          \n04|  bbb          \n05|▒ www          \n06|  ccc          \n07|~              \n08|~              \n09|~              \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|223333333333333\n04|001111111111111\n05|223333333333333\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|444444444444444\n15|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-with-'change'-hunks",
    "content": "--|---------|-----\n01|  AAA          \n02|  BBB          \n03|▒ BbB          \n04|  CCC          \n05|▒ CcC          \n06|  DDD          \n07|▒ DdD          \n08|  EEE          \n09|~              \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|002322222222222\n03|445655555555555\n04|002322222222222\n05|445655555555555\n06|002322222222222\n07|445655555555555\n08|001111111111111\n09|000000000000000\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|777777777777777\n15|888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-with-'change'-hunks-002",
    "content": "--|---------|-----\n01|  AAA          \n02|  BBB          \n03|  CCC          \n04|  DDD          \n05|▒ uuu          \n06|▒ BbB          \n07|▒ CcC          \n08|▒ DdD          \n09|  EEE          \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|002222222222222\n03|002222222222222\n04|002222222222222\n05|334444444444444\n06|334444444444444\n07|334444444444444\n08|334444444444444\n09|001111111111111\n10|000000000000000\n11|000000000000000\n12|000000000000000\n13|000000000000000\n14|555555555555555\n15|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Overlay---works-with-'delete'-hunks",
    "content": "--|---------|-----\n01|▒ aaa          \n02|  bbb          \n03|  ccc          \n04|▒ ddd          \n05|  eee          \n06|  fff          \n07|~              \n08|~              \n09|~              \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 1,1  \n15|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|223333333333333\n04|001111111111111\n05|223333333333333\n06|221111111111111\n07|222222222222222\n08|222222222222222\n09|222222222222222\n10|222222222222222\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|444444444444444\n15|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---can-be-visually-disabled",
    "content": "--|---------|-----\n01|AAA            \n02|uuu            \n03|BBB            \n04|CcC            \n05|DDD            \n06|FFF            \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---does-not-appear-if-there-is-no-gutter",
    "content": "--|---------|-----\n01|AAA            \n02|uuu            \n03|BBB            \n04|CcC            \n05|DDD            \n06|FFF            \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---forces-redraw-when-it-is-needed",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ aaa          \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 2,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---forces-redraw-when-it-is-needed-002",
    "content": "--|---------|-----\n01|aaa            \n02|aaa            \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 2,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---reacts-to-hunk-lines-delete-move",
    "content": "--|---------|-----\n01|  aaa          \n02|  uuu          \n03|  vvv          \n04|  bbb          \n05|  ccc          \n06|  ddd          \n07|~              \n08|~              \n09|[No Name] 2,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|001111111111111\n03|001111111111111\n04|001111111111111\n05|001111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---reacts-to-hunk-lines-delete-move-002",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ uuu          \n03|▒ vvv          \n04|  bbb          \n05|  ccc          \n06|  ddd          \n07|~              \n08|~              \n09|[No Name] 2,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|221111111111111\n04|001111111111111\n05|001111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---respects-`view.signs`",
    "content": "--|---------|-----\n01|  AAA          \n02|+ uuu          \n03|  BBB          \n04|~ CcC          \n05|- DDD          \n06|  FFF          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|331111111111111\n05|441111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---respects-`view.style`",
    "content": "--|---------|-----\n01|  1 AAA        \n02|  2 uuu        \n03|  3 BBB        \n04|  4 CcC        \n05|  5 DDD        \n06|  6 FFF        \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|222211111111111\n03|000011111111111\n04|333311111111111\n05|444411111111111\n06|000011111111111\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---respects-`view.style`-002",
    "content": "--|---------|-----\n01|AAA            \n02|uuu            \n03|BBB            \n04|CcC            \n05|DDD            \n06|FFF            \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---shows-signcolumn-even-if-hunks-are-outside-of-view",
    "content": "--|---------|-----\n01|  AAA          \n02|  BBB          \n03|  CCC          \n04|  DDD          \n05|  EEE          \n06|  FFF          \n07|  GGG          \n08|  HHH          \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|223333333333333\n04|223333333333333\n05|223333333333333\n06|223333333333333\n07|223333333333333\n08|223333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---shows-signcolumn-even-if-hunks-are-outside-of-view-002",
    "content": "--|---------|-----\n01|▒              \n02|▒              \n03|  AAA          \n04|  BBB          \n05|  CCC          \n06|  DDD          \n07|  EEE          \n08|  FFF          \n09|[No Name] 2,0-1\n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|441111111111111\n04|441111111111111\n05|441111111111111\n06|441111111111111\n07|441111111111111\n08|441111111111111\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|▒ CcC          \n05|▒ DDD          \n06|  FFF          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|331111111111111\n05|441111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'add'-hunks",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ uuu          \n03|▒ vvv          \n04|  bbb          \n05|▒ www          \n06|  ccc          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|221111111111111\n04|001111111111111\n05|221111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'add'-hunks-002",
    "content": "--|---------|-----\n01|▒ uuu          \n02|  aaa          \n03|▒ bbb          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'change'-hunks",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ BbB          \n03|▒              \n04|  DDD          \n05|▒ EeE          \n06|  FFF          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|221111111111111\n04|001111111111111\n05|221111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'change'-hunks-002",
    "content": "--|---------|-----\n01|▒ AaA          \n02|  BBB          \n03|▒ CcC          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'delete'-hunks",
    "content": "--|---------|-----\n01|▒ aaa          \n02|  ddd          \n03|▒ eee          \n04|  ggg          \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|221111111111111\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'delete'-hunks-002",
    "content": "--|---------|-----\n01|▒ bbb          \n02|▒ ccc          \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|001111111111111\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---Visualization---works-with-'delete'-hunks-003",
    "content": "--|---------|-----\n01|▒ bbb          \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---disable()---works",
    "content": "--|---------|-----\n01|aaa            \n02|bbb            \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---set_ref_text()---immediately-updates-diff-data-and-visualization",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ bbb          \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---set_ref_text()---removing-reference-text-removes-visualization",
    "content": "--|---------|-----\n01|  aaa          \n02|▒ bbb          \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---set_ref_text()---removing-reference-text-removes-visualization-002",
    "content": "--|---------|-----\n01|aaa            \n02|bbb            \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---toggle_overlay()---works",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|▒ CcC          \n05|▒ DDD          \n06|  FFF          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|331111111111111\n05|441111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---toggle_overlay()---works-002",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|  CCC          \n05|▒ CcC          \n06|▒ DDD          \n07|  EEE          \n08|  FFF          \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|004544444444444\n05|667877777777777\n06|991111111111111\n07|00:::::::::::::\n08|001111111111111\n09|;;;;;;;;;;;;;;;\n10|<<<<<<<<<<<<<<<\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---toggle_overlay()---works-003",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---toggle_overlay()---works-004",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|223333333333333\n03|001111111111111\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_diff.lua---toggle_overlay()---works-005",
    "content": "--|---------|-----\n01|  AAA          \n02|▒ uuu          \n03|  BBB          \n04|▒ CcC          \n05|▒ DDD          \n06|  FFF          \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|221111111111111\n03|001111111111111\n04|331111111111111\n05|441111111111111\n06|001111111111111\n07|000000000000000\n08|000000000000000\n09|555555555555555\n10|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---buf_lines()---can-not-show-icons",
    "content": "--|---------|---------|---------|---------|\n01|This is                                 \n02|  buffer 1                              \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│buffer-1│1│This is      │              \n07|│buffer-1│2│  buffer 1   │              \n08|││1│This is              │              \n09|││2│  buffer 2           │              \n10|││1│                     │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffer lines (all) ────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888888888882222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---buf_lines()---respects-`local_opts.scope`",
    "content": "--|---------|---------|---------|---------|\n01|This is                                 \n02|  buffer 1                              \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│1│This is               │              \n07|│2│  buffer 1            │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffer lines (current) ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888888888888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---buf_lines()---works",
    "content": "--|---------|---------|---------|---------|\n01|This is                                 \n02|  buffer 1                              \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│  buffer-1│1│This is    │              \n07|│  buffer-1│2│  buffer 1 │              \n08|│  │1│This is            │              \n09|│  │2│  buffer 2         │              \n10|│  │1│                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffer lines (all) ────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888888888882222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---colorschemes()---respects-`local_opts.preview_hl_groups`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ miniautumn ────────────┐              \n06|│Normal                  │              \n07|│MiniPickBorder          │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Colorschemes ── 1|6|34 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333222222222222211111111111111\n06|2000000444444444444444444211111111111111\n07|2222222222222224444444444211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333333332233333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---colorschemes()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ^mini▏────────────────┐              \n06|│miniautumn              │              \n07|│minicyan                │              \n08|│minischeme              │              \n09|│minispring              │              \n10|│minisummer              │              \n11|│miniwinter              │              \n12|│                        │              \n13|│                        │              \n14|└ Colorschemes ── 1|6|34 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334444452222222222222222211111111111111\n06|2666677777777777777777777211111111111111\n07|2888899999999999999999999211111111111111\n08|2888899999999999999999999211111111111111\n09|2888899999999999999999999211111111111111\n10|2888899999999999999999999211111111111111\n11|2888899999999999999999999211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;;;;;;22;;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---colorschemes()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ miniautumn ────────────┐              \n06|│@attribute              │              \n07|│@attribute.builtin      │              \n08|│@boolean                │              \n09|│@character              │              \n10|│@character.special      │              \n11|│@comment                │              \n12|│@comment.documentation  │              \n13|│@comment.error          │              \n14|└ Colorschemes ── 1|6|34 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333222222222222211111111111111\n06|2444444444455555555555555211111111111111\n07|2666666666666666666555555211111111111111\n08|2777777775555555555555555211111111111111\n09|2777777777755555555555555211111111111111\n10|2666666666666666666555555211111111111111\n11|2888888885555555555555555211111111111111\n12|2888888888888888888888855211111111111111\n13|2999999999999995555555555211111111111111\n14|2333333333333332233333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---colorschemes()---works-with-preview",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ miniautumn ────────────┐              \n06|│@attribute              │              \n07|│@attribute.builtin      │              \n08|│@boolean                │              \n09|│@character              │              \n10|│@character.special      │              \n11|│@comment                │              \n12|│@comment.documentation  │              \n13|│@comment.error          │              \n14|└ Colorschemes ── 1|6|34 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333222222222222211111111111111\n06|2444444444455555555555555211111111111111\n07|2666666666666666666555555211111111111111\n08|2777777775555555555555555211111111111111\n09|2777777777755555555555555211111111111111\n10|2666666666666666666555555211111111111111\n11|2888888885555555555555555211111111111111\n12|2888888888888888888888855211111111111111\n13|2999999999999995555555555211111111111111\n14|2333333333333332233333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---colorschemes()---works-with-preview-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ minicyan ──────────────┐              \n06|│@attribute              │              \n07|│@attribute.builtin      │              \n08|│@boolean                │              \n09|│@character              │              \n10|│@character.special      │              \n11|│@comment                │              \n12|│@comment.documentation  │              \n13|│@comment.error          │              \n14|└ Colorschemes ── 2|6|34 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333322222222222222211111111111111\n06|2444444444422222222222222211111111111111\n07|2555555555555555555222222211111111111111\n08|2666666662222222222222222211111111111111\n09|2444444444422222222222222211111111111111\n10|2777777777777777777222222211111111111111\n11|2888888882222222222222222211111111111111\n12|2888888888888888888888822211111111111111\n13|2444444444444442222222222211111111111111\n14|2333333333333332233333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---colorschemes()---works-with-preview-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ miniautumn ────────────┐              \n06|│@attribute              │              \n07|│@attribute.builtin      │              \n08|│@boolean                │              \n09|│@character              │              \n10|│@character.special      │              \n11|│@comment                │              \n12|│@comment.documentation  │              \n13|│@comment.error          │              \n14|└ Colorschemes ── 1|6|34 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333222222222222211111111111111\n06|2444444444455555555555555211111111111111\n07|2666666666666666666555555211111111111111\n08|2777777775555555555555555211111111111111\n09|2777777777755555555555555211111111111111\n10|2666666666666666666555555211111111111111\n11|2888888885555555555555555211111111111111\n12|2888888888888888888888855211111111111111\n13|2999999999999995555555555211111111111111\n14|2333333333333332233333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---commands()---respects-user-commands",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|-----\n01|                                                                           \n02|~                                                                          \n03|~                                                                          \n04|~                                                                          \n05|~                                                                          \n06|~                                                                          \n07|~                                                                          \n08|~                                                                          \n09|┌ MyCommand ───────────────────────────────────┐                           \n10|│{                                             │                           \n11|│  bang = false,                               │                           \n12|│  bar = false,                                │                           \n13|│  definition = \"lua _G.my_command = true\",    │                           \n14|│  keepscript = false,                         │                           \n15|│  name = \"MyCommand\",                         │                           \n16|│  nargs = \"0\",                                │                           \n17|│  register = false,                           │                           \n18|│  script_id = -10                             │                           \n19|│}                                             │                           \n20|│                                              │                           \n21|│                                              │                           \n22|│                                              │                           \n23|│                                              │                           \n24|└ Commands ─────────────────────────── 1|2|585 ┘                           \n25|                                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111\n09|233333333333222222222222222222222222222222222222111111111111111111111111111\n10|244444444444444444444444444444444444444444444442111111111111111111111111111\n11|244444444444444444444444444444444444444444444442111111111111111111111111111\n12|244444444444444444444444444444444444444444444442111111111111111111111111111\n13|244444444444444444444444444444444444444444444442111111111111111111111111111\n14|244444444444444444444444444444444444444444444442111111111111111111111111111\n15|244444444444444444444444444444444444444444444442111111111111111111111111111\n16|244444444444444444444444444444444444444444444442111111111111111111111111111\n17|244444444444444444444444444444444444444444444442111111111111111111111111111\n18|244444444444444444444444444444444444444444444442111111111111111111111111111\n19|244444444444444444444444444444444444444444444442111111111111111111111111111\n20|255555555555555555555555555555555555555555555552111111111111111111111111111\n21|255555555555555555555555555555555555555555555552111111111111111111111111111\n22|255555555555555555555555555555555555555555555552111111111111111111111111111\n23|255555555555555555555555555555555555555555555552111111111111111111111111111\n24|233333333332222222222222222222222222223333333332111111111111111111111111111\n25|000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---commands()---respects-user-commands-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|-----\n01|                                                                           \n02|~                                                                          \n03|~                                                                          \n04|~                                                                          \n05|~                                                                          \n06|~                                                                          \n07|~                                                                          \n08|~                                                                          \n09|┌ MyCommandBuf ────────────────────────────────┐                           \n10|│{                                             │                           \n11|│  bang = false,                               │                           \n12|│  bar = false,                                │                           \n13|│  definition = \"lua _G.my_command_buf = true\",│                           \n14|│  keepscript = false,                         │                           \n15|│  name = \"MyCommandBuf\",                      │                           \n16|│  nargs = \"*\",                                │                           \n17|│  register = false,                           │                           \n18|│  script_id = -10                             │                           \n19|│}                                             │                           \n20|│                                              │                           \n21|│                                              │                           \n22|│                                              │                           \n23|│                                              │                           \n24|└ Commands ─────────────────────────── 2|2|585 ┘                           \n25|                                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111\n09|233333333333333222222222222222222222222222222222111111111111111111111111111\n10|244444444444444444444444444444444444444444444442111111111111111111111111111\n11|244444444444444444444444444444444444444444444442111111111111111111111111111\n12|244444444444444444444444444444444444444444444442111111111111111111111111111\n13|244444444444444444444444444444444444444444444442111111111111111111111111111\n14|244444444444444444444444444444444444444444444442111111111111111111111111111\n15|244444444444444444444444444444444444444444444442111111111111111111111111111\n16|244444444444444444444444444444444444444444444442111111111111111111111111111\n17|244444444444444444444444444444444444444444444442111111111111111111111111111\n18|244444444444444444444444444444444444444444444442111111111111111111111111111\n19|244444444444444444444444444444444444444444444442111111111111111111111111111\n20|255555555555555555555555555555555555555555555552111111111111111111111111111\n21|255555555555555555555555555555555555555555555552111111111111111111111111111\n22|255555555555555555555555555555555555555555555552111111111111111111111111111\n23|255555555555555555555555555555555555555555555552111111111111111111111111111\n24|233333333332222222222222222222222222223333333332111111111111111111111111111\n25|000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---commands()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|┌> 'chdir▏────────────────────────────────────────┐                             \n04|│chdir                                            │                             \n05|│lchdir                                           │                             \n06|│tchdir                                           │                             \n07|│                                                 │                             \n08|│                                                 │                             \n09|└ Commands ────────────────────────────── 1|3|581 ┘                             \n10|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|23344444452222222222222222222222222222222222222222211111111111111111111111111111\n04|26666677777777777777777777777777777777777777777777211111111111111111111111111111\n05|28999998888888888888888888888888888888888888888888211111111111111111111111111111\n06|28999998888888888888888888888888888888888888888888211111111111111111111111111111\n07|2:::::::::::::::::::::::::::::::::::::::::::::::::211111111111111111111111111111\n08|2:::::::::::::::::::::::::::::::::::::::::::::::::211111111111111111111111111111\n09|2;;;;;;;;;;222222222222222222222222222222;;;;;;;;;211111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---commands()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|┌ chdir ──────────────────────────────────────────┐                             \n04|│No command data for `chdir` is yet available.    │                             \n05|│                                                 │                             \n06|│                                                 │                             \n07|│                                                 │                             \n08|│                                                 │                             \n09|└ Commands ────────────────────────────── 1|3|581 ┘                             \n10|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|23333333222222222222222222222222222222222222222222211111111111111111111111111111\n04|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n05|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n06|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n07|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n08|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n09|23333333333222222222222222222222222222222333333333211111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---diagnostic()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|┌> ▏──────────────────────────────────────────────────────────┐                                     \n10|│E │ tests/dir-extra/mocks/diagnostic-file-1 │ Error 1        │                                     \n11|│E │ tests/dir-extra/mocks/diagnostic-file-1 │ Error 2        │                                     \n12|│E │ tests/dir-extra/mocks/diagnostic-file-2 │ Error 3        │                                     \n13|│W │ tests/dir-extra/mocks/diagnostic-file-1 │ Warning 1      │                                     \n14|│W │ tests/dir-extra/mocks/diagnostic-file-1 │ Warning 2      │                                     \n15|│W │ tests/dir-extra/mocks/diagnostic-file-2 │ Warning 3      │                                     \n16|│I │ tests/dir-extra/mocks/diagnostic-file-1 │ Info 1         │                                     \n17|│I │ tests/dir-extra/mocks/diagnostic-file-1 │ Info 2         │                                     \n18|│I │ tests/dir-extra/mocks/diagnostic-file-2 │ Info 3         │                                     \n19|│H │ tests/dir-extra/mocks/diagnostic-file-1 │ Hint 1         │                                     \n20|│H │ tests/dir-extra/mocks/diagnostic-file-1 │ Hint 2         │                                     \n21|│H │ tests/dir-extra/mocks/diagnostic-file-2 │ Hint 3         │                                     \n22|│                                                             │                                     \n23|│                                                             │                                     \n24|└ Diagnostic (all) ────────────────────────────────── 1|12|12 ┘                                     \n25|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|2334222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111\n10|2555555555555555555555555555555555555555555555555555556666666621111111111111111111111111111111111111\n11|2777777777777777777777777777777777777777777777777777778888888821111111111111111111111111111111111111\n12|2777777777777777777777777777777777777777777777777777778888888821111111111111111111111111111111111111\n13|2999999999999999999999999999999999999999999999999999999988888821111111111111111111111111111111111111\n14|2999999999999999999999999999999999999999999999999999999988888821111111111111111111111111111111111111\n15|2999999999999999999999999999999999999999999999999999999988888821111111111111111111111111111111111111\n16|2::::::::::::::::::::::::::::::::::::::::::::::::::::88888888821111111111111111111111111111111111111\n17|2::::::::::::::::::::::::::::::::::::::::::::::::::::88888888821111111111111111111111111111111111111\n18|2::::::::::::::::::::::::::::::::::::::::::::::::::::88888888821111111111111111111111111111111111111\n19|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88888888821111111111111111111111111111111111111\n20|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88888888821111111111111111111111111111111111111\n21|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88888888821111111111111111111111111111111111111\n22|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<21111111111111111111111111111111111111\n23|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<21111111111111111111111111111111111111\n24|2==================2222222222222222222222222222222222=========21111111111111111111111111111111111111\n25|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---diagnostic()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|┌ E │ tests/dir-extra/mocks/diagnostic-file-1 │ Error 2 ──────┐                                     \n10|│  Error                                                      │                                     \n11|│  Warning                                                    │                                     \n12|│  Info                                                       │                                     \n13|│  Hint                                                       │                                     \n14|│                                                             │                                     \n15|│                                                             │                                     \n16|│                                                             │                                     \n17|│                                                             │                                     \n18|│                                                             │                                     \n19|│                                                             │                                     \n20|│                                                             │                                     \n21|│                                                             │                                     \n22|│                                                             │                                     \n23|│                                                             │                                     \n24|└ Diagnostic (all) ────────────────────────────────── 2|12|12 ┘                                     \n25|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|2333333333333333333333333333333333333333333333333333333322222221111111111111111111111111111111111111\n10|2445555544444444444444444444444444444444444444444444444444444421111111111111111111111111111111111111\n11|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n12|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n13|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n14|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n15|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n16|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n17|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n18|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n19|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n20|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n21|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n22|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n23|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n24|2333333333333333333222222222222222222222222222222222233333333321111111111111111111111111111111111111\n25|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---can-be-resumed",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ subdir/               │              \n08|│ file1-1               │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2666666666666666666666666211111111111111\n09|2999999999999999999999999211111111111111\n10|2999999999999999999999999211111111111111\n11|2999999999999999999999999211111111111111\n12|2999999999999999999999999211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---can-be-resumed-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ subdir/               │              \n08|│ file1-1               │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2666666666666666666666666211111111111111\n09|2999999999999999999999999211111111111111\n10|2999999999999999999999999211111111111111\n11|2999999999999999999999999211111111111111\n12|2999999999999999999999999211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---can-not-show-icons",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│..                      │              \n07|│dir1/                   │              \n08|│Dir2/                   │              \n09|│dir3/                   │              \n10|│file1                   │              \n11|│File2                   │              \n12|│file3                   │              \n13|│                        │              \n14|└ File explorer ── 1|7|7 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888888228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---can-not-show-icons-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│..                      │              \n07|│subdir/                 │              \n08|│file1-1                 │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888888228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---respects-`local_opts.filter`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ dir1/                 │              \n08|│ Dir2/                 │              \n09|│ dir3/                 │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 1|4|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2778888888888888888888888211111111111111\n09|2778888888888888888888888211111111111111\n10|2999999999999999999999999211111111111111\n11|2999999999999999999999999211111111111111\n12|2999999999999999999999999211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---respects-`local_opts.filter`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ subdir/               │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2999999999999999999999999211111111111111\n09|2999999999999999999999999211111111111111\n10|2999999999999999999999999211111111111111\n11|2999999999999999999999999211111111111111\n12|2999999999999999999999999211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---respects-`local_opts.sort`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ Dir2/                 │              \n08|│ File2                 │              \n09|│ dir1/                 │              \n10|│ dir3/                 │              \n11|│ file1                 │              \n12|│ file3                 │              \n13|│                        │              \n14|└ File explorer ── 1|7|7 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2888888888888888888888888211111111111111\n09|2778888888888888888888888211111111111111\n10|2778888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---respects-`local_opts.sort`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ file1-1               │              \n08|│ subdir/               │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2777777777777777777777777211111111111111\n08|2887777777777777777777777211111111111111\n09|2999999999999999999999999211111111111111\n10|2999999999999999999999999211111111111111\n11|2999999999999999999999999211111111111111\n12|2999999999999999999999999211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ dir1/                 │              \n08|│ Dir2/                 │              \n09|│ dir3/                 │              \n10|│ file1                 │              \n11|│ File2                 │              \n12|│ file3                 │              \n13|│                        │              \n14|└ File explorer ── 1|7|7 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2778888888888888888888888211111111111111\n09|2778888888888888888888888211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ subdir/               │              \n08|│ file1-1               │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2888888888888888888888888211111111111111\n09|2999999999999999999999999211111111111111\n10|2999999999999999999999999211111111111111\n11|2999999999999999999999999211111111111111\n12|2999999999999999999999999211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---works-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ .. ────────────────────┐              \n06|│Dir2/                   │              \n07|│File2                   │              \n08|│dir1/                   │              \n09|│dir3/                   │              \n10|│file1                   │              \n11|│file3                   │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333322222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333333333223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---works-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ subdir/ ───────────────┐              \n06|│file1-1-1               │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333333333223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---works-005",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ file1-1 ───────────────┐              \n06|│File 1-1                │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ File explorer ── 3|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333333333223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---explorer()---works-006",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ ..                    │              \n07|│ dir1/                 │              \n08|│ Dir2/                 │              \n09|│ dir3/                 │              \n10|│ file1                 │              \n11|│ File2                 │              \n12|│ file3                 │              \n13|│                        │              \n14|└ File explorer ── 1|7|7 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2556666666666666666666666211111111111111\n07|2778888888888888888888888211111111111111\n08|2778888888888888888888888211111111111111\n09|2778888888888888888888888211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2999999999999999999999999211111111111111\n14|2:::::::::::::::22:::::::211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_branches()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                          \n02|~                                                                                         \n03|┌> ▏────────────────────────────────────────────────────┐                                 \n04|│* main              0123456 Commit message.            │                                 \n05|│remotes/origin/HEAD -> origin/main                     │                                 \n06|│remotes/origin/main aaaaaaa Another commit message.    │                                 \n07|│                                                       │                                 \n08|│                                                       │                                 \n09|└ Git branches (all) ──────────────────────────── 1|3|3 ┘                                 \n10|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|233422222222222222222222222222222222222222222222222222222111111111111111111111111111111111\n04|255555555555555555555555555555555555555555555555555555552111111111111111111111111111111111\n05|266666666666666666666666666666666666666666666666666666662111111111111111111111111111111111\n06|266666666666666666666666666666666666666666666666666666662111111111111111111111111111111111\n07|277777777777777777777777777777777777777777777777777777772111111111111111111111111111111111\n08|277777777777777777777777777777777777777777777777777777772111111111111111111111111111111111\n09|288888888888888888888222222222222222222222222222288888882111111111111111111111111111111111\n10|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_branches()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                          \n02|~                                                                                         \n03|┌ * main              0123456 Commit message. ──────────┐                                 \n04|│0123456 Commit message.                                │                                 \n05|│aaaaaaa Another commit message.                        │                                 \n06|│                                                       │                                 \n07|│                                                       │                                 \n08|│                                                       │                                 \n09|└ Git branches (all) ──────────────────────────── 1|3|3 ┘                                 \n10|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|233333333333333333333333333333333333333333333322222222222111111111111111111111111111111111\n04|244444444444444444444444444444444444444444444444444444442111111111111111111111111111111111\n05|244444444444444444444444444444444444444444444444444444442111111111111111111111111111111111\n06|255555555555555555555555555555555555555555555555555555552111111111111111111111111111111111\n07|255555555555555555555555555555555555555555555555555555552111111111111111111111111111111111\n08|255555555555555555555555555555555555555555555555555555552111111111111111111111111111111111\n09|233333333333333333333222222222222222222222222222233333332111111111111111111111111111111111\n10|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_commits()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌> ▏──────────────────────────────────────────────────────────┐                                     \n13|│0123456 Commit message.                                      │                                     \n14|│aaaaaaa Another commit message.                              │                                     \n15|│1111111 Initial commit.                                      │                                     \n16|│                                                             │                                     \n17|│                                                             │                                     \n18|│                                                             │                                     \n19|│                                                             │                                     \n20|│                                                             │                                     \n21|│                                                             │                                     \n22|│                                                             │                                     \n23|│                                                             │                                     \n24|│                                                             │                                     \n25|│                                                             │                                     \n26|│                                                             │                                     \n27|│                                                             │                                     \n28|│                                                             │                                     \n29|│                                                             │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git commits (all) ─────────────────────────────────── 1|3|3 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2334222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111\n13|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n14|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n15|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n16|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n17|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n18|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n19|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n20|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n21|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n22|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n23|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n24|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n25|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n26|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n27|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n28|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n29|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n30|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n31|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n32|2888888888888888888822222222222222222222222222222222222888888821111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_commits()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌ 1111111 Initial commit. ────────────────────────────────────┐                                     \n13|│commit 1111111111111111111111111111111111111111              │                                     \n14|│Author: Mini Nvim <mini.nvim@emailaddress.com>               │                                     \n15|│Date:   Thu Jan 1 11:11:11 1970 +0300                        │                                     \n16|│                                                             │                                     \n17|│    Initial commit.                                          │                                     \n18|│                                                             │                                     \n19|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n20|│index 1111111..0123456 100644                                │                                     \n21|│--- a/git-files/git-file-1                                   │                                     \n22|│+++ b/git-files/git-file-1                                   │                                     \n23|│@@ -1,5 +1,5 @@                                              │                                     \n24|│ Line 1-1                                                    │                                     \n25|│-Line 1-2                                                    │                                     \n26|│ Line 1-3                                                    │                                     \n27|│ Line 1-4                                                    │                                     \n28|│ Line 1-5                                                    │                                     \n29|│+Line 1-6                                                    │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git commits (all) ─────────────────────────────────── 3|3|3 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2333333333333333333333333322222222222222222222222222222222222221111111111111111111111111111111111111\n13|2444444566666666666666666666666666666666666666665555555555555521111111111111111111111111111111111111\n14|2444444457777777777899999999999999999999999999855555555555555521111111111111111111111111111111111111\n15|244444555:::::::::::::::::::::::::::::55555555555555555555555521111111111111111111111111111111111111\n16|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n17|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n18|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n19|2666666666666666666666666666666666666666666666666666666665555521111111111111111111111111111111111111\n20|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5555555555555555555555555555555521111111111111111111111111111111111111\n21|2666666666666666666666666665555555555555555555555555555555555521111111111111111111111111111111111111\n22|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n23|2;;;;;;;;;;;;;;;555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n24|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n25|2<<<<<<<<<555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n26|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n27|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n28|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n29|2777777777555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n30|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n31|2=============================================================21111111111111111111111111111111111111\n32|2333333333333333333322222222222222222222222222222222222333333321111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_files()---can-not-show-icons",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|┌> ▏───────────────────────────┐                  \n04|│git-files/git-file-1          │                  \n05|│git-files/git-file-2          │                  \n06|│                              │                  \n07|│                              │                  \n08|│                              │                  \n09|└ Git files (tracked) ── 1|2|2 ┘                  \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|23342222222222222222222222222222111111111111111111\n04|25555555555555555555555555555552111111111111111111\n05|26666666666666666666666666666662111111111111111111\n06|27777777777777777777777777777772111111111111111111\n07|27777777777777777777777777777772111111111111111111\n08|27777777777777777777777777777772111111111111111111\n09|28888888888888888888882288888882111111111111111111\n10|00000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_files()---works",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|┌> ▏───────────────────────────┐                  \n04|│ git-files/git-file-1        │                  \n05|│ git-files/git-file-2        │                  \n06|│                              │                  \n07|│                              │                  \n08|│                              │                  \n09|└ Git files (tracked) ── 1|2|2 ┘                  \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|23342222222222222222222222222222111111111111111111\n04|25555555555555555555555555555552111111111111111111\n05|26666666666666666666666666666662111111111111111111\n06|27777777777777777777777777777772111111111111111111\n07|27777777777777777777777777777772111111111111111111\n08|27777777777777777777777777777772111111111111111111\n09|28888888888888888888882288888882111111111111111111\n10|00000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_files()---works-002",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|┌ git-files/git-file-1 ────────┐                  \n04|│Line 1-1                      │                  \n05|│Line 1-2                      │                  \n06|│Line 1-3                      │                  \n07|│Line 1-4                      │                  \n08|│Line 1-5                      │                  \n09|└ Git files (tracked) ── 1|2|2 ┘                  \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|23333333333333333333333222222222111111111111111111\n04|24444444444444444444444444444442111111111111111111\n05|24444444444444444444444444444442111111111111111111\n06|24444444444444444444444444444442111111111111111111\n07|24444444444444444444444444444442111111111111111111\n08|24444444444444444444444444444442111111111111111111\n09|23333333333333333333332233333332111111111111111111\n10|00000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---respects-`local_opts.n_context`---test-+-args-{-0-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|┌> ▏──────────────────────────────────────────────────────────┐                                     \n06|│ git-files/git-file-1 │ -1 +0,0   │                         │                                     \n07|│ git-files/git-file-1 │ -11,0 +11 │ Line 1-11               │                                     \n08|│ git-files/git-file-1 │ -21 +21   │ Line 1-20               │                                     \n09|│ git-files/git-file-2 │ -2 +1,0   │ Line 2-1                │                                     \n10|│ git-files/git-file-2 │ -12,0 +12 │ Line 2-12               │                                     \n11|│ git-files/git-file-2 │ -16 +16   │ Line 2-15               │                                     \n12|│                                                             │                                     \n13|│                                                             │                                     \n14|└ Git hunks (unstaged all) ──────────────────────────── 1|6|6 ┘                                     \n15|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|2334222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111\n06|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n07|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n08|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n09|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n10|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n11|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n12|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n13|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n14|2888888888888888888888888882222222222222222222222222222888888821111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---respects-`local_opts.n_context`---test-+-args-{-0-}-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|┌ git-files/git-file-1 │ -1 +0,0   │  ────────────────────────┐                                     \n06|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n07|│index c139d4e..234d24d 100644                                │                                     \n08|│--- a/git-files/git-file-1                                   │                                     \n09|│+++ b/git-files/git-file-1                                   │                                     \n10|│@@ -1 +0,0 @@                                                │                                     \n11|│-Line 1-1                                                    │                                     \n12|│                                                             │                                     \n13|│                                                             │                                     \n14|└ Git hunks (unstaged all) ──────────────────────────── 1|6|6 ┘                                     \n15|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|2333333333333333333333333333333333333322222222222222222222222221111111111111111111111111111111111111\n06|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n07|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n08|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n09|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n10|2666666666666655555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n11|2888888888555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n12|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n13|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n14|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---respects-`local_opts.n_context`---test-+-args-{-0-}-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|┌ git-files/git-file-1 │ -11,0 +11 │ Line 1-11 ───────────────┐                                     \n06|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n07|│index c139d4e..234d24d 100644                                │                                     \n08|│--- a/git-files/git-file-1                                   │                                     \n09|│+++ b/git-files/git-file-1                                   │                                     \n10|│@@ -11,0 +11 @@ Line 1-11                                    │                                     \n11|│+Line new                                                    │                                     \n12|│                                                             │                                     \n13|│                                                             │                                     \n14|└ Git hunks (unstaged all) ──────────────────────────── 2|6|6 ┘                                     \n15|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|2333333333333333333333333333333333333333333333322222222222222221111111111111111111111111111111111111\n06|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n07|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n08|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n09|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n10|2666666666666666666666666655555555555555555555555555555555555521111111111111111111111111111111111111\n11|2777777777555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n12|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n13|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n14|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---respects-`local_opts.n_context`---test-+-args-{-20-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|┌> ▏──────────────────────────────────────────────────────────┐                                     \n06|│ git-files/git-file-1 │ -1,21 +1,21 │                       │                                     \n07|│ git-files/git-file-2 │ -1,21 +1,21 │                       │                                     \n08|│                                                             │                                     \n09|│                                                             │                                     \n10|│                                                             │                                     \n11|│                                                             │                                     \n12|│                                                             │                                     \n13|│                                                             │                                     \n14|└ Git hunks (unstaged all) ──────────────────────────── 1|2|2 ┘                                     \n15|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|2334222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111\n06|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n07|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n08|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n09|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n10|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n11|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n12|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n13|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n14|2888888888888888888888888882222222222222222222222222222888888821111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---respects-`local_opts.n_context`---test-+-args-{-20-}-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|┌ git-files/git-file-1 │ -1,21 +1,21 │  ──────────────────────┐                                     \n06|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n07|│index c139d4e..234d24d 100644                                │                                     \n08|│--- a/git-files/git-file-1                                   │                                     \n09|│+++ b/git-files/git-file-1                                   │                                     \n10|│@@ -1,21 +1,21 @@                                            │                                     \n11|│-Line 1-1                                                    │                                     \n12|│ Line 1-2                                                    │                                     \n13|│ Line 1-3                                                    │                                     \n14|└ Git hunks (unstaged all) ──────────────────────────── 1|2|2 ┘                                     \n15|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|2333333333333333333333333333333333333333222222222222222222222221111111111111111111111111111111111111\n06|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n07|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n08|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n09|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n10|2666666666666666665555555555555555555555555555555555555555555521111111111111111111111111111111111111\n11|2888888888555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n12|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n13|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n14|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---respects-`local_opts.n_context`---test-+-args-{-20-}-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|┌ git-files/git-file-2 │ -1,21 +1,21 │  ──────────────────────┐                                     \n06|│diff --git a/git-files/git-file-2 b/git-files/git-file-2     │                                     \n07|│index e45e3de..bd830d0 100644                                │                                     \n08|│--- a/git-files/git-file-2                                   │                                     \n09|│+++ b/git-files/git-file-2                                   │                                     \n10|│@@ -1,21 +1,21 @@                                            │                                     \n11|│ Line 2-1                                                    │                                     \n12|│-Line 2-2                                                    │                                     \n13|│ Line 2-3                                                    │                                     \n14|└ Git hunks (unstaged all) ──────────────────────────── 2|2|2 ┘                                     \n15|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|2333333333333333333333333333333333333333222222222222222222222221111111111111111111111111111111111111\n06|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n07|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n08|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n09|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n10|2666666666666666665555555555555555555555555555555555555555555521111111111111111111111111111111111111\n11|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n12|2888888888555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n13|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n14|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌> ▏──────────────────────────────────────────────────────────┐                                     \n13|│ git-files/git-file-1 │ -1,4 +1,3    │                      │                                     \n14|│ git-files/git-file-1 │ -9,6 +8,7    │ Line 1-8             │                                     \n15|│ git-files/git-file-1 │ -18,4 +18,4  │ Line 1-17            │                                     \n16|│ git-files/git-file-2 │ -1,5 +1,4    │                      │                                     \n17|│ git-files/git-file-2 │ -10,10 +9,11 │ Line 2-9             │                                     \n18|│                                                             │                                     \n19|│                                                             │                                     \n20|│                                                             │                                     \n21|│                                                             │                                     \n22|│                                                             │                                     \n23|│                                                             │                                     \n24|│                                                             │                                     \n25|│                                                             │                                     \n26|│                                                             │                                     \n27|│                                                             │                                     \n28|│                                                             │                                     \n29|│                                                             │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git hunks (unstaged all) ──────────────────────────── 1|5|5 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2334222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111\n13|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n14|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n15|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n16|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n17|2666666666666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n18|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n19|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n20|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n21|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n22|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n23|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n24|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n25|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n26|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n27|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n28|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n29|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n30|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n31|2777777777777777777777777777777777777777777777777777777777777721111111111111111111111111111111111111\n32|2888888888888888888888888882222222222222222222222222222888888821111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌ git-files/git-file-1 │ -1,4 +1,3    │  ─────────────────────┐                                     \n13|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n14|│index c139d4e..234d24d 100644                                │                                     \n15|│--- a/git-files/git-file-1                                   │                                     \n16|│+++ b/git-files/git-file-1                                   │                                     \n17|│@@ -1,4 +1,3 @@                                              │                                     \n18|│-Line 1-1                                                    │                                     \n19|│ Line 1-2                                                    │                                     \n20|│ Line 1-3                                                    │                                     \n21|│ Line 1-4                                                    │                                     \n22|│                                                             │                                     \n23|│                                                             │                                     \n24|│                                                             │                                     \n25|│                                                             │                                     \n26|│                                                             │                                     \n27|│                                                             │                                     \n28|│                                                             │                                     \n29|│                                                             │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git hunks (unstaged all) ──────────────────────────── 1|5|5 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2333333333333333333333333333333333333333322222222222222222222221111111111111111111111111111111111111\n13|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n14|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n15|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n16|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n17|2666666666666666555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n18|2888888888555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n19|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n20|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n21|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n22|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n23|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n24|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n25|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n26|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n27|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n28|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n29|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n30|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n31|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n32|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌ git-files/git-file-1 │ -9,6 +8,7    │ Line 1-8 ─────────────┐                                     \n13|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n14|│index c139d4e..234d24d 100644                                │                                     \n15|│--- a/git-files/git-file-1                                   │                                     \n16|│+++ b/git-files/git-file-1                                   │                                     \n17|│@@ -9,6 +8,7 @@ Line 1-8                                     │                                     \n18|│ Line 1-9                                                    │                                     \n19|│ Line 1-10                                                   │                                     \n20|│ Line 1-11                                                   │                                     \n21|│+Line new                                                    │                                     \n22|│ Line 1-12                                                   │                                     \n23|│ Line 1-13                                                   │                                     \n24|│ Line 1-14                                                   │                                     \n25|│                                                             │                                     \n26|│                                                             │                                     \n27|│                                                             │                                     \n28|│                                                             │                                     \n29|│                                                             │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git hunks (unstaged all) ──────────────────────────── 2|5|5 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2333333333333333333333333333333333333333333333333222222222222221111111111111111111111111111111111111\n13|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n14|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n15|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n16|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n17|2666666666666666666666666555555555555555555555555555555555555521111111111111111111111111111111111111\n18|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n19|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n20|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n21|2777777777555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n22|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n23|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n24|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n25|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n26|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n27|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n28|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n29|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n30|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n31|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n32|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---works-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌ git-files/git-file-1 │ -18,4 +18,4  │ Line 1-17 ────────────┐                                     \n13|│diff --git a/git-files/git-file-1 b/git-files/git-file-1     │                                     \n14|│index c139d4e..234d24d 100644                                │                                     \n15|│--- a/git-files/git-file-1                                   │                                     \n16|│+++ b/git-files/git-file-1                                   │                                     \n17|│@@ -18,4 +18,4 @@ Line 1-17                                  │                                     \n18|│ Line 1-18                                                   │                                     \n19|│ Line 1-19                                                   │                                     \n20|│ Line 1-20                                                   │                                     \n21|│-Line 1-21                                                   │                                     \n22|│+Line changed                                                │                                     \n23|│                                                             │                                     \n24|│                                                             │                                     \n25|│                                                             │                                     \n26|│                                                             │                                     \n27|│                                                             │                                     \n28|│                                                             │                                     \n29|│                                                             │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git hunks (unstaged all) ──────────────────────────── 3|5|5 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2333333333333333333333333333333333333333333333333322222222222221111111111111111111111111111111111111\n13|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n14|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n15|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n16|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n17|2666666666666666666666666666555555555555555555555555555555555521111111111111111111111111111111111111\n18|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n19|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n20|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n21|2888888888855555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n22|2777777777777755555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n23|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n24|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n25|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n26|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n27|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n28|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n29|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n30|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n31|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n32|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---works-005",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌ git-files/git-file-2 │ -1,5 +1,4    │  ─────────────────────┐                                     \n13|│diff --git a/git-files/git-file-2 b/git-files/git-file-2     │                                     \n14|│index e45e3de..bd830d0 100644                                │                                     \n15|│--- a/git-files/git-file-2                                   │                                     \n16|│+++ b/git-files/git-file-2                                   │                                     \n17|│@@ -1,5 +1,4 @@                                              │                                     \n18|│ Line 2-1                                                    │                                     \n19|│-Line 2-2                                                    │                                     \n20|│ Line 2-3                                                    │                                     \n21|│ Line 2-4                                                    │                                     \n22|│ Line 2-5                                                    │                                     \n23|│                                                             │                                     \n24|│                                                             │                                     \n25|│                                                             │                                     \n26|│                                                             │                                     \n27|│                                                             │                                     \n28|│                                                             │                                     \n29|│                                                             │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git hunks (unstaged all) ──────────────────────────── 4|5|5 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2333333333333333333333333333333333333333322222222222222222222221111111111111111111111111111111111111\n13|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n14|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n15|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n16|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n17|2666666666666666555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n18|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n19|2888888888555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n20|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n21|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n22|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n23|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n24|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n25|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n26|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n27|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n28|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n29|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n30|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n31|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n32|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---git_hunks()---works-006",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|~                                                                                                   \n08|~                                                                                                   \n09|~                                                                                                   \n10|~                                                                                                   \n11|~                                                                                                   \n12|┌ git-files/git-file-2 │ -10,10 +9,11 │ Line 2-9 ─────────────┐                                     \n13|│diff --git a/git-files/git-file-2 b/git-files/git-file-2     │                                     \n14|│index e45e3de..bd830d0 100644                                │                                     \n15|│--- a/git-files/git-file-2                                   │                                     \n16|│+++ b/git-files/git-file-2                                   │                                     \n17|│@@ -10,10 +9,11 @@ Line 2-9                                  │                                     \n18|│ Line 2-10                                                   │                                     \n19|│ Line 2-11                                                   │                                     \n20|│ Line 2-12                                                   │                                     \n21|│+Line new                                                    │                                     \n22|│ Line 2-13                                                   │                                     \n23|│ Line 2-14                                                   │                                     \n24|│ Line 2-15                                                   │                                     \n25|│-Line 2-16                                                   │                                     \n26|│+Line changed                                                │                                     \n27|│ Line 2-17                                                   │                                     \n28|│ Line 2-18                                                   │                                     \n29|│ Line 2-19                                                   │                                     \n30|│                                                             │                                     \n31|│                                                             │                                     \n32|└ Git hunks (unstaged all) ──────────────────────────── 5|5|5 ┘                                     \n33|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|2333333333333333333333333333333333333333333333333222222222222221111111111111111111111111111111111111\n13|2444444444444444444444444444444444444444444444444444444445555521111111111111111111111111111111111111\n14|2666666666666666666666666666665555555555555555555555555555555521111111111111111111111111111111111111\n15|2444444444444444444444444445555555555555555555555555555555555521111111111111111111111111111111111111\n16|2777777777777777777777777775555555555555555555555555555555555521111111111111111111111111111111111111\n17|2666666666666666666666666666555555555555555555555555555555555521111111111111111111111111111111111111\n18|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n19|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n20|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n21|2777777777555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n22|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n23|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n24|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n25|2888888888855555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n26|2777777777777755555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n27|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n28|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n29|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n30|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n31|2999999999999999999999999999999999999999999999999999999999999921111111111111111111111111111111111111\n32|2333333333333333333333333332222222222222222222222222222333333321111111111111111111111111111111111111\n33|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hipatterns()---respects-`local_opts.highlighters`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|min                                                                                                                     \n03|max                                                                                                                     \n04|local                                                                                                                   \n05|┌> ▏───────────────────────────────────────────────────────────────────────┐                                            \n06|│minmax │ tests/dir-extra/real-files/a.lua│3│12│  x = math.max(a, 2),      │                                            \n07|│minmax │ tests/dir-extra/real-files/a.lua│4│12│  y = math.min(a, 2),      │                                            \n08|│minmax │ Buffer_3│2│1│min                                                 │                                            \n09|│minmax │ Buffer_3│3│1│max                                                 │                                            \n10|│                                                                          │                                            \n11|│                                                                          │                                            \n12|│                                                                          │                                            \n13|│                                                                          │                                            \n14|└ Mini.hipatterns matches (all) ──────────────────────────────────── 1|4|4 ┘                                            \n15|                                                                                                                        \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|222220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|344533333333333333333333333333333333333333333333333333333333333333333333333366666666666666666666666666666666666666666666\n06|377777777777777777777777777777777777777777777777777777777777777777777777777366666666666666666666666666666666666666666666\n07|311111188888888888888888888888888888888888888888888888888888888888888888888366666666666666666666666666666666666666666666\n08|311111188888888888888888888888888888888888888888888888888888888888888888888366666666666666666666666666666666666666666666\n09|311111188888888888888888888888888888888888888888888888888888888888888888888366666666666666666666666666666666666666666666\n10|399999999999999999999999999999999999999999999999999999999999999999999999999366666666666666666666666666666666666666666666\n11|399999999999999999999999999999999999999999999999999999999999999999999999999366666666666666666666666666666666666666666666\n12|399999999999999999999999999999999999999999999999999999999999999999999999999366666666666666666666666666666666666666666666\n13|399999999999999999999999999999999999999999999999999999999999999999999999999366666666666666666666666666666666666666666666\n14|3:::::::::::::::::::::::::::::::333333333333333333333333333333333333:::::::366666666666666666666666666666666666666666666\n15|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hipatterns()---respects-`local_opts.scope`",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|min                                               \n03|max                                               \n04|local                                             \n05|┌> ▏───────────────────────────┐                  \n06|│local  │ Buffer_3│4│1│local   │                  \n07|│minmax │ Buffer_3│2│1│min     │                  \n08|│minmax │ Buffer_3│3│1│max     │                  \n09|│                              │                  \n10|│                              │                  \n11|│                              │                  \n12|│                              │                  \n13|│                              │                  \n14|└…hipatterns matches (current) ┘                  \n15|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11100000000000000000000000000000000000000000000000\n03|11100000000000000000000000000000000000000000000000\n04|22222000000000000000000000000000000000000000000000\n05|34453333333333333333333333333333666666666666666666\n06|37777788888888888888888888888883666666666666666666\n07|31111119999999999999999999999993666666666666666666\n08|31111119999999999999999999999993666666666666666666\n09|3::::::::::::::::::::::::::::::3666666666666666666\n10|3::::::::::::::::::::::::::::::3666666666666666666\n11|3::::::::::::::::::::::::::::::3666666666666666666\n12|3::::::::::::::::::::::::::::::3666666666666666666\n13|3::::::::::::::::::::::::::::::3666666666666666666\n14|3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3666666666666666666\n15|00000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hipatterns()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|min                                                                                                                     \n03|max                                                                                                                     \n04|local                                                                                                                   \n05|┌> ▏───────────────────────────────────────────────────────────────────────┐                                            \n06|│local  │ tests/dir-extra/real-files/a.lua│1│1│local a = 1                 │                                            \n07|│local  │ tests/dir-extra/real-files/a.lua│2│1│local t = {                 │                                            \n08|│minmax │ tests/dir-extra/real-files/a.lua│3│12│  x = math.max(a, 2),      │                                            \n09|│minmax │ tests/dir-extra/real-files/a.lua│4│12│  y = math.min(a, 2),      │                                            \n10|│local  │ Buffer_3│4│1│local                                               │                                            \n11|│minmax │ Buffer_3│2│1│min                                                 │                                            \n12|│minmax │ Buffer_3│3│1│max                                                 │                                            \n13|│                                                                          │                                            \n14|└ Mini.hipatterns matches (all) ──────────────────────────────────── 1|7|7 ┘                                            \n15|                                                                                                                        \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|222220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|344533333333333333333333333333333333333333333333333333333333333333333333333366666666666666666666666666666666666666666666\n06|377777888888888888888888888888888888888888888888888888888888888888888888888366666666666666666666666666666666666666666666\n07|399999:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::366666666666666666666666666666666666666666666\n08|3111111::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::366666666666666666666666666666666666666666666\n09|3111111::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::366666666666666666666666666666666666666666666\n10|399999:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::366666666666666666666666666666666666666666666\n11|3111111::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::366666666666666666666666666666666666666666666\n12|3111111::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::366666666666666666666666666666666666666666666\n13|3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;366666666666666666666666666666666666666666666\n14|3<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<333333333333333333333333333333333333<<<<<<<366666666666666666666666666666666666666666666\n15|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hipatterns()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|min                                                                                                                     \n03|max                                                                                                                     \n04|local                                                                                                                   \n05|┌ minmax │ Buffer_3│3│1│max ───────────────────────────────────────────────┐                                            \n06|│max                                                                       │                                            \n07|│local                                                                     │                                            \n08|│                                                                          │                                            \n09|│                                                                          │                                            \n10|│                                                                          │                                            \n11|│                                                                          │                                            \n12|│                                                                          │                                            \n13|│                                                                          │                                            \n14|└ Mini.hipatterns matches (all) ──────────────────────────────────── 7|7|7 ┘                                            \n15|                                                                                                                        \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|222220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|344444444444444444444444444433333333333333333333333333333333333333333333333355555555555555555555555555555555555555555555\n06|366677777777777777777777777777777777777777777777777777777777777777777777777355555555555555555555555555555555555555555555\n07|388888888888888888888888888888888888888888888888888888888888888888888888888355555555555555555555555555555555555555555555\n08|399999999999999999999999999999999999999999999999999999999999999999999999999355555555555555555555555555555555555555555555\n09|399999999999999999999999999999999999999999999999999999999999999999999999999355555555555555555555555555555555555555555555\n10|399999999999999999999999999999999999999999999999999999999999999999999999999355555555555555555555555555555555555555555555\n11|399999999999999999999999999999999999999999999999999999999999999999999999999355555555555555555555555555555555555555555555\n12|399999999999999999999999999999999999999999999999999999999999999999999999999355555555555555555555555555555555555555555555\n13|399999999999999999999999999999999999999999999999999999999999999999999999999355555555555555555555555555555555555555555555\n14|344444444444444444444444444444443333333333333333333333333333333333334444444355555555555555555555555555555555555555555555\n15|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---history()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│: lua _G.n = _G.n + 2                      │                         \n09|│: lua _G.n = _G.n + 1                      │                         \n10|│/ bbb                                      │                         \n11|│/ aaa                                      │                         \n12|│= 2+2                                      │                         \n13|│= 1+1                                      │                         \n14|│@ input 2                                  │                         \n15|│@ input 1                                  │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ History (all) ───────────────────── 1|8|8 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2334222222222222222222222222222222222222222221111111111111111111111111\n08|2555555555555555555555555555555555555555555521111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2667776666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2666666666666666666666666666666666666666666621111111111111111111111111\n13|2666666666666666666666666666666666666666666621111111111111111111111111\n14|2666666666666666666666666666666666666666666621111111111111111111111111\n15|2666666666666666666666666666666666666666666621111111111111111111111111\n16|2888888888888888888888888888888888888888888821111111111111111111111111\n17|2888888888888888888888888888888888888888888821111111111111111111111111\n18|2888888888888888888888888888888888888888888821111111111111111111111111\n19|2999999999999999222222222222222222222999999921111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---history()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌ : lua _G.n = _G.n + 2 ────────────────────┐                         \n08|│No preview available for `history` picker  │                         \n09|│                                           │                         \n10|│                                           │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ History (all) ───────────────────── 1|8|8 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333332222222222222222222221111111111111111111111111\n08|2444444444444444444444444444444444444444444421111111111111111111111111\n09|2555555555555555555555555555555555555555555521111111111111111111111111\n10|2555555555555555555555555555555555555555555521111111111111111111111111\n11|2555555555555555555555555555555555555555555521111111111111111111111111\n12|2555555555555555555555555555555555555555555521111111111111111111111111\n13|2555555555555555555555555555555555555555555521111111111111111111111111\n14|2555555555555555555555555555555555555555555521111111111111111111111111\n15|2555555555555555555555555555555555555555555521111111111111111111111111\n16|2555555555555555555555555555555555555555555521111111111111111111111111\n17|2555555555555555555555555555555555555555555521111111111111111111111111\n18|2555555555555555555555555555555555555555555521111111111111111111111111\n19|2333333333333333222222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hl_groups()---respects-non-default-linked-highlight-groups",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌> ^AAA▏─────────────────┐              \n04|│AAAA                    │              \n05|│AAAB                    │              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|└ Highlight groups ──────┘              \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2334444522222222222222222211111111111111\n04|2666677777777777777777777211111111111111\n05|2888899999999999999999999211111111111111\n06|2::::::::::::::::::::::::211111111111111\n07|2::::::::::::::::::::::::211111111111111\n08|2::::::::::::::::::::::::211111111111111\n09|2;;;;;;;;;;;;;;;;;;222222211111111111111\n10|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hl_groups()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|┌> ^Spell▏────────────────────────────────────────┐                             \n04|│SpellBad                                         │                             \n05|│SpellCap                                         │                             \n06|│SpellRare                                        │                             \n07|│SpellLocal                                       │                             \n08|│                                                 │                             \n09|└ Highlight groups ────────────────────── 1|4|957 ┘                             \n10|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|23344444452222222222222222222222222222222222222222211111111111111111111111111111\n04|26666666677777777777777777777777777777777777777777211111111111111111111111111111\n05|28888888899999999999999999999999999999999999999999211111111111111111111111111111\n06|2:::::::::9999999999999999999999999999999999999999211111111111111111111111111111\n07|2;;;;;;;;;;999999999999999999999999999999999999999211111111111111111111111111111\n08|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<211111111111111111111111111111\n09|2==================2222222222222222222222=========211111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---hl_groups()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|┌ SpellBad ───────────────────────────────────────┐                             \n04|│SpellBad       xxx cterm=undercurl gui=undercurl │                             \n05|│                                                 │                             \n06|│                                                 │                             \n07|│                                                 │                             \n08|│                                                 │                             \n09|└ Highlight groups ────────────────────── 1|4|957 ┘                             \n10|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|23333333333222222222222222222222222222222222222222211111111111111111111111111111\n04|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n05|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n06|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n07|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n08|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n09|23333333333333333332222222222222222222222333333333211111111111111111111111111111\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---keymaps()---shows-source-of-Lua-callback-in-preview",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|┌> 'ga ▏──────────────────────────────────────────────────────┐                                     \n08|│n   │ ga         │ \"Keymap with callback\"                    │                                     \n09|│                                                             │                                     \n10|│                                                             │                                     \n11|│                                                             │                                     \n12|│                                                             │                                     \n13|│                                                             │                                     \n14|│                                                             │                                     \n15|│                                                             │                                     \n16|│                                                             │                                     \n17|│                                                             │                                     \n18|│                                                             │                                     \n19|└ Keymaps (all) ────────────────────────────────────── 1|1|12 ┘                                     \n20|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|2334444522222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111\n08|2666666777666666666666666666666666666666666666666666666666666621111111111111111111111111111111111111\n09|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n10|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n11|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n12|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n13|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n14|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n15|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n16|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n17|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n18|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n19|2999999999999999222222222222222222222222222222222222229999999921111111111111111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---keymaps()---shows-source-of-Lua-callback-in-preview-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|┌ n   │ ga         │ \"Keymap with callback\" ──────────────────┐                                     \n08|│local keymap_rhs = function()                                │                                     \n09|│  -- Comment                                                 │                                     \n10|│  _G.been_here = true                                        │                                     \n11|│end                                                          │                                     \n12|│                                                             │                                     \n13|│--stylua: ignore                                             │                                     \n14|│vim.api.nvim_set_keymap(                                     │                                     \n15|│  'n', 'ga', '',                                             │                                     \n16|│  { callback = keymap_rhs, desc = 'Keymap with callback' }   │                                     \n17|│)                                                            │                                     \n18|│                                                             │                                     \n19|└ Keymaps (all) ────────────────────────────────────── 1|1|12 ┘                                     \n20|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333333333333333333333333322222222222222222221111111111111111111111111111111111111\n08|2444445666666666655544444444775555555555555555555555555555555521111111111111111111111111111111111111\n09|2889999999999888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n10|288::;<<<<<<<<<888====888888888888888888888888888888888888888821111111111111111111111111111111111111\n11|2>>>888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n12|2888888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n13|2999999999999999988888888888888888888888888888888888888888888821111111111111111111111111111111111111\n14|2888;<<<;???????????????;888888888888888888888888888888888888821111111111111111111111111111111111111\n15|288@@@;8@@@@;8@@;88888888888888888888888888888888888888888888821111111111111111111111111111111111111\n16|288:8<<<<<<<<8888888888888;8<<<<888@@@@@@@@@@@@@@@@@@@@@@8:88821111111111111111111111111111111111111\n17|2;88888888888888888888888888888888888888888888888888888888888821111111111111111111111111111111111111\n18|2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA21111111111111111111111111111111111111\n19|2333333333333333222222222222222222222222222222222222223333333321111111111111111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---keymaps()---shows-source-of-Lua-callback-in-preview-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                    \n02|~                                                                                                   \n03|~                                                                                                   \n04|~                                                                                                   \n05|~                                                                                                   \n06|~                                                                                                   \n07|┌ n   │ ga         │ \"Keymap with callback\" ──────────────────┐                                     \n08|│local tmp = 1                                                │                                     \n09|│                                                             │                                     \n10|│local keymap_rhs = function()                                │                                     \n11|│  -- Comment                                                 │                                     \n12|│  _G.been_here = true                                        │                                     \n13|│end                                                          │                                     \n14|│                                                             │                                     \n15|│--stylua: ignore                                             │                                     \n16|│vim.api.nvim_set_keymap(                                     │                                     \n17|│  'n', 'ga', '',                                             │                                     \n18|│  { callback = keymap_rhs, desc = 'Keymap with callback' }   │                                     \n19|└ Keymaps (all) ────────────────────────────────────── 1|1|12 ┘                                     \n20|                                                                                                    \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333333333333333333333333322222222222222222221111111111111111111111111111111111111\n08|2444445555555655555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n09|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n10|2777778999999999988877777777::8888888888888888888888888888888821111111111111111111111111111111111111\n11|255;;;;;;;;;;555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n12|255<<=>>>>>>>>>5556666555555555555555555555555555555555555555521111111111111111111111111111111111111\n13|2444555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n14|2555555555555555555555555555555555555555555555555555555555555521111111111111111111111111111111111111\n15|2;;;;;;;;;;;;;;;;55555555555555555555555555555555555555555555521111111111111111111111111111111111111\n16|2555=>>>=???????????????=555555555555555555555555555555555555521111111111111111111111111111111111111\n17|255@@@=5@@@@=5@@=55555555555555555555555555555555555555555555521111111111111111111111111111111111111\n18|255<5>>>>>>>>5555555555555=5>>>>555@@@@@@@@@@@@@@@@@@@@@@5<55521111111111111111111111111111111111111\n19|2333333333333333222222222222222222222222222222222222223333333321111111111111111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---keymaps()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|~                                                                               \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|┌> ▏──────────────────────────────────────────────┐                             \n12|│n @ │ <Space>b   │ <Cmd>lua _G.res = \"buf\"<CR>   │                             \n13|│n   │ <Space>nnn │ <Cmd>lua _G.res = \"long\"<CR>  │                             \n14|│n   │ <Space>d   │ \"Description\"                 │                             \n15|│n   │ <Space>n   │ <Cmd>lua _G.res = \"n\"<CR>     │                             \n16|│x   │ <Space>x   │ <Cmd>lua _G.res = \"x\"<CR>     │                             \n17|│s   │ <Space>s   │ <Cmd>lua _G.res = \"s\"<CR>     │                             \n18|│o   │ <Space>o   │ <Cmd>lua _G.res = \"o\"<CR>     │                             \n19|│i   │ <Space>i   │ <Cmd>lua _G.res = \"i\"<CR>     │                             \n20|│l   │ <Space>l   │ <Cmd>lua _G.res = \"l\"<CR>     │                             \n21|│c   │ <Space>c   │ <Cmd>lua _G.res = \"c\"<CR>     │                             \n22|│t   │ <Space>t   │ <Cmd>lua _G.res = \"t\"<CR>     │                             \n23|│                                                 │                             \n24|│                                                 │                             \n25|│                                                 │                             \n26|│                                                 │                             \n27|│                                                 │                             \n28|│                                                 │                             \n29|│                                                 │                             \n30|└ Keymaps (all) ───────────────────────── 1|11|11 ┘                             \n31|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|23342222222222222222222222222222222222222222222222211111111111111111111111111111\n12|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n13|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n14|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n15|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n16|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n17|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n18|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n19|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n20|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n21|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n22|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n23|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n24|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n25|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n26|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n27|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n28|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n29|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n30|28888888888888882222222222222222222222222888888888211111111111111111111111111111\n31|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---keymaps()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|~                                                                               \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|┌ n @ │ <Space>b   │ <Cmd>lua _G.res = \"buf\"<CR> ─┐                             \n12|│{                                                │                             \n13|│  abbr = 0,                                      │                             \n14|│  buffer = 1,                                    │                             \n15|│  expr = 0,                                      │                             \n16|│  lhs = \" b\",                                    │                             \n17|│  lhsraw = \" b\",                                 │                             \n18|│  lnum = 0,                                      │                             \n19|│  mode = \"n\",                                    │                             \n20|│  mode_bits = 1,                                 │                             \n21|│  noremap = 0,                                   │                             \n22|│  nowait = 0,                                    │                             \n23|│  replace_keycodes = 0,                          │                             \n24|│  rhs = '<Cmd>lua _G.res = \"buf\"<CR>',           │                             \n25|│  script = 0,                                    │                             \n26|│  scriptversion = 1,                             │                             \n27|│  sid = -9,                                      │                             \n28|│  silent = 0                                     │                             \n29|│}                                                │                             \n30|└ Keymaps (all) ───────────────────────── 1|11|11 ┘                             \n31|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|23333333333333333333333333333333333333333333333332211111111111111111111111111111\n12|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n13|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n14|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n15|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n16|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n17|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n18|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n19|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n20|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n21|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n22|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n23|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n24|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n25|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n26|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n27|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n28|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n29|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n30|23333333333333332222222222222222222222222333333333211111111111111111111111111111\n31|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`change`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|l Change 1 ocal a = 1                                                 \n02|local t = {                                                           \n03|  x Change 2  = math.max(a, 2),                                       \n04|  y = math.min(a, 2),                                                 \n05|}                                                                     \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│ tests/dir-extra/real-files/a.lua│1│11    │                         \n09|│ tests/dir-extra/real-files/a.lua│3│13    │                         \n10|│                                           │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (change) ───────────────────── 1|2|2 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000001000000000010000000000000000000000000000000000000000000000000\n02|2222200000300000000000000000000000000000000000000000000000000000000000\n03|0040000000010000333356665050155000000000000000000000000000000000000000\n04|0040003333566650501550000000000000000000000000000000000000000000000000\n05|3000000000000000000000000000000000000000000000000000000000000000000000\n06|7777777777777777777777777777777777777777777777777777777777777777777777\n07|899:888888888888888888888888888888888888888887777777777777777777777777\n08|8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87777777777777777777777777\n09|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n10|8===========================================87777777777777777777777777\n11|8===========================================87777777777777777777777777\n12|8===========================================87777777777777777777777777\n13|8===========================================87777777777777777777777777\n14|8===========================================87777777777777777777777777\n15|8===========================================87777777777777777777777777\n16|8===========================================87777777777777777777777777\n17|8===========================================87777777777777777777777777\n18|8===========================================87777777777777777777777777\n19|8>>>>>>>>>>>>>>>888888888888888888888>>>>>>>87777777777777777777777777\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`change`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|l Change 1 ocal a = 1                                                 \n02|local t = {                                                           \n03|  x Change 2  = math.max(a, 2),                                       \n04|  y = math.min(a, 2),                                                 \n05|}                                                                     \n06|~                                                                     \n07|┌ tests/dir-extra/real-files/a.lua│1│11 ────┐                         \n08|│l Change 1 ocal a = 1                      │                         \n09|│local t = {                                │                         \n10|│  x Change 2  = math.max(a, 2),            │                         \n11|│  y = math.min(a, 2),                      │                         \n12|│}                                          │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (change) ───────────────────── 1|2|2 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000001000000000010000000000000000000000000000000000000000000000000\n02|2222200000300000000000000000000000000000000000000000000000000000000000\n03|0040000000010000333356665050155000000000000000000000000000000000000000\n04|0040003333566650501550000000000000000000000000000000000000000000000000\n05|3000000000000000000000000000000000000000000000000000000000000000000000\n06|7777777777777777777777777777777777777777777777777777777777777777777777\n07|8999999999999999999999999999999999999999888887777777777777777777777777\n08|8:::::::::;<:::::::::;::::::::::::::::::::::87777777777777777777777777\n09|8=====>>>>>?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n10|8>>@>>>>>>>>A>>>>????BCCCB>B>ABB>>>>>>>>>>>>87777777777777777777777777\n11|8>>@>>>????BCCCB>B>ABB>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n12|8?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n13|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n14|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n15|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n16|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n17|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n18|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n19|8999999999999999888888888888888888888999999987777777777777777777777777\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`jump`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│  Buffer_2│2│1                             │                         \n09|│  Buffer_2│1│1                             │                         \n10|│ tests/dir-extra/real-files/a.lua│5│1     │                         \n11|│ tests/dir-extra/real-files/a.lua│1│1     │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (jump) ─────────────────────── 1|4|4 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2334222222222222222222222222222222222222222221111111111111111111111111\n08|2555555555555555555555555555555555555555555521111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2777777777777777777777777777777777777777777721111111111111111111111111\n13|2777777777777777777777777777777777777777777721111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2888888888888822222222222222222222222888888821111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`jump`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌ Buffer_2│2│1 ─────────────────────────────┐                         \n08|│bbbbb                                      │                         \n09|│                                           │                         \n10|│                                           │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (jump) ─────────────────────── 1|4|4 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333332222222222222222222222222222221111111111111111111111111\n08|2455555555555555555555555555555555555555555521111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2666666666666666666666666666666666666666666621111111111111111111111111\n13|2666666666666666666666666666666666666666666621111111111111111111111111\n14|2666666666666666666666666666666666666666666621111111111111111111111111\n15|2666666666666666666666666666666666666666666621111111111111111111111111\n16|2666666666666666666666666666666666666666666621111111111111111111111111\n17|2666666666666666666666666666666666666666666621111111111111111111111111\n18|2666666666666666666666666666666666666666666621111111111111111111111111\n19|2333333333333322222222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`location`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│ tests/dir-extra/real-files/a.lua│1│7│ Fi…│                         \n09|│  Buffer_2│2│2│ Buffer                     │                         \n10|│  Buffer_2│3│3                             │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (location) ─────────────────── 1|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2334222222222222222222222222222222222222222221111111111111111111111111\n08|2555555555555555555555555555555555555555555621111111111111111111111111\n09|2777777777777777777777777777777777777777777721111111111111111111111111\n10|2777777777777777777777777777777777777777777721111111111111111111111111\n11|2888888888888888888888888888888888888888888821111111111111111111111111\n12|2888888888888888888888888888888888888888888821111111111111111111111111\n13|2888888888888888888888888888888888888888888821111111111111111111111111\n14|2888888888888888888888888888888888888888888821111111111111111111111111\n15|2888888888888888888888888888888888888888888821111111111111111111111111\n16|2888888888888888888888888888888888888888888821111111111111111111111111\n17|2888888888888888888888888888888888888888888821111111111111111111111111\n18|2888888888888888888888888888888888888888888821111111111111111111111111\n19|2999999999999999992222222222222222222999999921111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`location`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌…ests/dir-extra/real-files/a.lua│1│7│ File ┐                         \n08|│local a = 1                                │                         \n09|│local t = {                                │                         \n10|│  x = math.max(a, 2),                      │                         \n11|│  y = math.min(a, 2),                      │                         \n12|│}                                          │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (location) ─────────────────── 1|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333333333333333333333333321111111111111111111111111\n08|2444445655575555555555555555555555555555555521111111111111111111111111\n09|28888899999:9999999999999999999999999999999921111111111111111111111111\n10|299;999::::<===<9<9><<999999999999999999999921111111111111111111111111\n11|299;999::::<===<9<9><<999999999999999999999921111111111111111111111111\n12|2:99999999999999999999999999999999999999999921111111111111111111111111\n13|2???????????????????????????????????????????21111111111111111111111111\n14|2???????????????????????????????????????????21111111111111111111111111\n15|2???????????????????????????????????????????21111111111111111111111111\n16|2???????????????????????????????????????????21111111111111111111111111\n17|2???????????????????????????????????????????21111111111111111111111111\n18|2???????????????????????????????????????????21111111111111111111111111\n19|2333333333333333332222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`location`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌ Buffer_2│2│2│ Buffer ─────────────────────┐                         \n08|│bbbbb                                      │                         \n09|│ccccc                                      │                         \n10|│ddddd                                      │                         \n11|│eeeee                                      │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (location) ─────────────────── 2|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333322222222222222222222221111111111111111111111111\n08|2454444444444444444444444444444444444444444421111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2777777777777777777777777777777777777777777721111111111111111111111111\n13|2777777777777777777777777777777777777777777721111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2333333333333333332222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`location`-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌ Buffer_2│3│3 ─────────────────────────────┐                         \n08|│ccccc                                      │                         \n09|│ddddd                                      │                         \n10|│eeeee                                      │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (location) ─────────────────── 3|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333332222222222222222222222222222221111111111111111111111111\n08|2445554444444444444444444444444444444444444421111111111111111111111111\n09|2555666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2777777777777777777777777777777777777777777721111111111111111111111111\n12|2777777777777777777777777777777777777777777721111111111111111111111111\n13|2777777777777777777777777777777777777777777721111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2333333333333333332222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`quickfix`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│ tests/dir-extra/real-files/a.lua│1│7│ Fi…│                         \n09|│  Buffer_2│2│2│ Buffer                     │                         \n10|│  Buffer_2│3│3                             │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (quickfix) ─────────────────── 1|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2334222222222222222222222222222222222222222221111111111111111111111111\n08|2555555555555555555555555555555555555555555621111111111111111111111111\n09|2777777777777777777777777777777777777777777721111111111111111111111111\n10|2777777777777777777777777777777777777777777721111111111111111111111111\n11|2888888888888888888888888888888888888888888821111111111111111111111111\n12|2888888888888888888888888888888888888888888821111111111111111111111111\n13|2888888888888888888888888888888888888888888821111111111111111111111111\n14|2888888888888888888888888888888888888888888821111111111111111111111111\n15|2888888888888888888888888888888888888888888821111111111111111111111111\n16|2888888888888888888888888888888888888888888821111111111111111111111111\n17|2888888888888888888888888888888888888888888821111111111111111111111111\n18|2888888888888888888888888888888888888888888821111111111111111111111111\n19|2999999999999999992222222222222222222999999921111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`quickfix`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌…ests/dir-extra/real-files/a.lua│1│7│ File ┐                         \n08|│local a = 1                                │                         \n09|│local t = {                                │                         \n10|│  x = math.max(a, 2),                      │                         \n11|│  y = math.min(a, 2),                      │                         \n12|│}                                          │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (quickfix) ─────────────────── 1|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333333333333333333333333321111111111111111111111111\n08|2444445655575555555555555555555555555555555521111111111111111111111111\n09|28888899999:9999999999999999999999999999999921111111111111111111111111\n10|299;999::::<===<9<9><<999999999999999999999921111111111111111111111111\n11|299;999::::<===<9<9><<999999999999999999999921111111111111111111111111\n12|2:99999999999999999999999999999999999999999921111111111111111111111111\n13|2???????????????????????????????????????????21111111111111111111111111\n14|2???????????????????????????????????????????21111111111111111111111111\n15|2???????????????????????????????????????????21111111111111111111111111\n16|2???????????????????????????????????????????21111111111111111111111111\n17|2???????????????????????????????????????????21111111111111111111111111\n18|2???????????????????????????????????????????21111111111111111111111111\n19|2333333333333333332222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`quickfix`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌ Buffer_2│2│2│ Buffer ─────────────────────┐                         \n08|│bbbbb                                      │                         \n09|│ccccc                                      │                         \n10|│ddddd                                      │                         \n11|│eeeee                                      │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (quickfix) ─────────────────── 2|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333322222222222222222222221111111111111111111111111\n08|2454444444444444444444444444444444444444444421111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2777777777777777777777777777777777777777777721111111111111111111111111\n13|2777777777777777777777777777777777777777777721111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2333333333333333332222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---list()---works-for-`quickfix`-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|aaaaa                                                                 \n02|bbbbb                                                                 \n03|ccccc                                                                 \n04|ddddd                                                                 \n05|eeeee                                                                 \n06|~                                                                     \n07|┌ Buffer_2│3│3 ─────────────────────────────┐                         \n08|│ccccc                                      │                         \n09|│ddddd                                      │                         \n10|│eeeee                                      │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ List (quickfix) ─────────────────── 3|3|3 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000000000000000000000000000000000\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333332222222222222222222222222222221111111111111111111111111\n08|2445554444444444444444444444444444444444444421111111111111111111111111\n09|2555666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2777777777777777777777777777777777777777777721111111111111111111111111\n12|2777777777777777777777777777777777777777777721111111111111111111111111\n13|2777777777777777777777777777777777777777777721111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2333333333333333332222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`declaration`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ tests/dir-extra/real-files/a.lua│3│16│   x = math.ma…│                                 \n07|│                                                       │                                 \n08|│                                                       │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (declaration) ───────────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::::::;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7>>>>>>>>>>>>>>>>>>>77777777777777777777777777777>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`declaration`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌…ir-extra/real-files/a.lua│3│16│   x = math.max(a, 2), ┐                                 \n06|│  x = math.max(a, 2),                                  │                                 \n07|│  y = math.min(a, 2),                                  │                                 \n08|│}                                                      │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (declaration) ───────────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888888887111111111111111111111111111111111\n06|799:999;;;;<===<><9?<<99999999999999999999999999999999997@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n07|7AABAAACCCCDEEEDADAFDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n08|7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n09|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n10|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n11|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n12|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n13|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n14|788888888888888888887777777777777777777777777777788888887@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`definition`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ tests/dir-extra/real-files/a.lua│3│16│   x = math.ma…│                                 \n07|│                                                       │                                 \n08|│                                                       │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (definition) ────────────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::::::;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7>>>>>>>>>>>>>>>>>>777777777777777777777777777777>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`definition`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌…ir-extra/real-files/a.lua│3│16│   x = math.max(a, 2), ┐                                 \n06|│  x = math.max(a, 2),                                  │                                 \n07|│  y = math.min(a, 2),                                  │                                 \n08|│}                                                      │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (definition) ────────────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888888887111111111111111111111111111111111\n06|799:999;;;;<===<><9?<<99999999999999999999999999999999997@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n07|7AABAAACCCCDEEEDADAFDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n08|7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n09|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n10|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n11|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n12|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n13|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n14|788888888888888888877777777777777777777777777777788888887@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│[Number] a                                             │                                 \n07|│[Object] t                                             │                                 \n08|│[Variable] x                                           │                                 \n09|│[Variable] y                                           │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7???????????????????????7777777777777777777777777???????7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌ [Number] a ───────────────────────────────────────────┐                                 \n06|│local a = 1                                            │                                 \n07|│local t = {                                            │                                 \n08|│  x = math.max(a, 2),                                  │                                 \n09|│  y = math.min(a, 2),                                  │                                 \n10|│}                                                      │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888877777777777777777777777777777777777777777777111111111111111111111111111111111\n06|799999:;:::<::::::::::::::::::::::::::::::::::::::::::::7=================================\n07|7>>>>>?????@????????????????????????????????????????????7=================================\n08|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n09|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n10|7@??????????????????????????????????????????????????????7=================================\n11|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n12|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n13|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n14|788888888888888888888888777777777777777777777777788888887=================================\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`-after-`MiniIcons.tweak_lsp_kind()`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│[ Number] a                                           │                                 \n07|│[ Object] t                                           │                                 \n08|│[ Variable] x                                         │                                 \n09|│[ Variable] y                                         │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7??????????????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7??????????????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAA7777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`-after-`MiniIcons.tweak_lsp_kind()`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│[Number ] a                                           │                                 \n07|│[Object ] t                                           │                                 \n08|│[Variable ] x                                         │                                 \n09|│[Variable ] y                                         │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7??????????????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7??????????????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAA7777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`-after-`MiniIcons.tweak_lsp_kind()`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│[] a                                                  │                                 \n07|│[] t                                                  │                                 \n08|│[] x                                                  │                                 \n09|│[] y                                                  │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7:::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=====>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7?????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7?????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAA7777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`-with-'mini.icons'-set-up",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ [Number] a                                           │                                 \n07|│ [Object] t                                           │                                 \n08|│ [Variable] x                                         │                                 \n09|│ [Variable] y                                         │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7============>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7??????????????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7??????????????>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAA7777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`document_symbol`-with-'mini.icons'-set-up-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌  [Number] a ─────────────────────────────────────────┐                                 \n06|│local a = 1                                            │                                 \n07|│local t = {                                            │                                 \n08|│  x = math.max(a, 2),                                  │                                 \n09|│  y = math.min(a, 2),                                  │                                 \n10|│}                                                      │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (document_symbol) ───────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888777777777777777777777777777777777777777777111111111111111111111111111111111\n06|799999:;:::<::::::::::::::::::::::::::::::::::::::::::::7=================================\n07|7>>>>>?????@????????????????????????????????????????????7=================================\n08|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n09|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n10|7@??????????????????????????????????????????????????????7=================================\n11|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n12|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n13|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n14|788888888888888888888888777777777777777777777777788888887=================================\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`implementation`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ tests/dir-extra/real-files/a.lua│3│16│   x = math.ma…│                                 \n07|│                                                       │                                 \n08|│                                                       │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (implementation) ────────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::::::;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7>>>>>>>>>>>>>>>>>>>>>>77777777777777777777777777>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`implementation`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌…ir-extra/real-files/a.lua│3│16│   x = math.max(a, 2), ┐                                 \n06|│  x = math.max(a, 2),                                  │                                 \n07|│  y = math.min(a, 2),                                  │                                 \n08|│}                                                      │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (implementation) ────────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888888887111111111111111111111111111111111\n06|799:999;;;;<===<><9?<<99999999999999999999999999999999997@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n07|7AABAAACCCCDEEEDADAFDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n08|7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n09|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n10|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n11|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n12|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n13|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n14|788888888888888888888887777777777777777777777777788888887@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`references`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ tests/dir-extra/real-files/a.lua│1│7│ local a = 1    │                                 \n07|│ tests/dir-extra/real-files/a.lua│3│16│   x = math.ma…│                                 \n08|│ tests/dir-extra/real-files/a.lua│4│16│   y = math.mi…│                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (references) ────────────────────────────── 1|3|3 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7:::::::::::::::::::::::::::::::::::::::::::::::::::::::7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n07|7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n08|7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n09|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n10|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n11|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n12|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n13|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n14|7??????????????????777777777777777777777777777777???????7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`references`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌…ir-extra/real-files/a.lua│3│16│   x = math.max(a, 2), ┐                                 \n06|│  x = math.max(a, 2),                                  │                                 \n07|│  y = math.min(a, 2),                                  │                                 \n08|│}                                                      │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (references) ────────────────────────────── 2|3|3 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888888887111111111111111111111111111111111\n06|799:999;;;;<===<><9?<<99999999999999999999999999999999997@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n07|7AABAAACCCCDEEEDADAFDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n08|7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n09|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n10|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n11|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n12|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n13|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n14|788888888888888888877777777777777777777777777777788888887@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`type_definition`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ tests/dir-extra/real-files/a.lua│3│16│   x = math.ma…│                                 \n07|│                                                       │                                 \n08|│                                                       │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (type_definition) ───────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::::::;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7>>>>>>>>>>>>>>>>>>>>>>>7777777777777777777777777>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`type_definition`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌…ir-extra/real-files/a.lua│3│16│   x = math.max(a, 2), ┐                                 \n06|│  x = math.max(a, 2),                                  │                                 \n07|│  y = math.min(a, 2),                                  │                                 \n08|│}                                                      │                                 \n09|│                                                       │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (type_definition) ───────────────────────── 1|1|1 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888888887111111111111111111111111111111111\n06|799:999;;;;<===<><9?<<99999999999999999999999999999999997@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n07|7AABAAACCCCDEEEDADAFDDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n08|7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n09|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n10|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n11|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n12|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n13|7GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n14|788888888888888888888888777777777777777777777777788888887@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│tests/dir-extra/real-files/a.lua│1│7│ [Number] a       │                                 \n07|│tests/dir-extra/real-files/a.lua│2│7│ [Object] t       │                                 \n08|│tests/dir-extra/real-files/a.lua│3│3│ [Variable] x     │                                 \n09|│tests/dir-extra/real-files/a.lua│4│3│ [Variable] y     │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7=======================================================7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7????????????????????????777777777777777777777777???????7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌ tests/dir-extra/real-files/a.lua│1│7│ [Number] a ─────┐                                 \n06|│local a = 1                                            │                                 \n07|│local t = {                                            │                                 \n08|│  x = math.max(a, 2),                                  │                                 \n09|│  y = math.min(a, 2),                                  │                                 \n10|│}                                                      │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888777777111111111111111111111111111111111\n06|799999:;:::<::::::::::::::::::::::::::::::::::::::::::::7=================================\n07|7>>>>>?????@????????????????????????????????????????????7=================================\n08|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n09|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n10|7@??????????????????????????????????????????????????????7=================================\n11|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n12|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n13|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n14|788888888888888888888888877777777777777777777777788888887=================================\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`-after-`MiniIcons.tweak_lsp_kind()`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│tests/dir-extra/real-files/a.lua│1│7│ [ Number] a     │                                 \n07|│tests/dir-extra/real-files/a.lua│2│7│ [ Object] t     │                                 \n08|│tests/dir-extra/real-files/a.lua│3│3│ [ Variable] x   │                                 \n09|│tests/dir-extra/real-files/a.lua│4│3│ [ Variable] y   │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7==================================================>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7????????????????????????????????????????????????????>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7????????????????????????????????????????????????????>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAAA777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`-after-`MiniIcons.tweak_lsp_kind()`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│tests/dir-extra/real-files/a.lua│1│7│ [Number ] a     │                                 \n07|│tests/dir-extra/real-files/a.lua│2│7│ [Object ] t     │                                 \n08|│tests/dir-extra/real-files/a.lua│3│3│ [Variable ] x   │                                 \n09|│tests/dir-extra/real-files/a.lua│4│3│ [Variable ] y   │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7==================================================>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7????????????????????????????????????????????????????>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7????????????????????????????????????????????????????>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAAA777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`-after-`MiniIcons.tweak_lsp_kind()`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│tests/dir-extra/real-files/a.lua│1│7│ [] a            │                                 \n07|│tests/dir-extra/real-files/a.lua│2│7│ [] t            │                                 \n08|│tests/dir-extra/real-files/a.lua│3│3│ [] x            │                                 \n09|│tests/dir-extra/real-files/a.lua│4│3│ [] y            │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7:::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7===========================================>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7???????????????????????????????????????????>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7???????????????????????????????????????????>>>>>>>>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAAA777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`-with-'mini.icons'-set-up",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌> ▏────────────────────────────────────────────────────┐                                 \n06|│ tests/dir-extra/real-files/a.lua│1│7│ [Number] a     │                                 \n07|│ tests/dir-extra/real-files/a.lua│2│7│ [Object] t     │                                 \n08|│ tests/dir-extra/real-files/a.lua│3│3│ [Variable] x   │                                 \n09|│ tests/dir-extra/real-files/a.lua│4│3│ [Variable] y   │                                 \n10|│                                                       │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788977777777777777777777777777777777777777777777777777777111111111111111111111111111111111\n06|7::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n07|7==================================================>>>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n08|7????????????????????????????????????????????????????>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n09|7????????????????????????????????????????????????????>>>7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n10|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n11|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n12|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n13|7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n14|7AAAAAAAAAAAAAAAAAAAAAAAA777777777777777777777777AAAAAAA7<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---lsp()---works-for-`workspace_symbol`-with-'mini.icons'-set-up-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                                               \n02|local t = {                                                                               \n03|  x = math.max(a, 2),                                                                     \n04|  y = math.min(a, 2),                                                                     \n05|┌  tests/dir-extra/real-files/a.lua│1│7│ [Number] a ───┐                                 \n06|│local a = 1                                            │                                 \n07|│local t = {                                            │                                 \n08|│  x = math.max(a, 2),                                  │                                 \n09|│  y = math.min(a, 2),                                  │                                 \n10|│}                                                      │                                 \n11|│                                                       │                                 \n12|│                                                       │                                 \n13|│                                                       │                                 \n14|└ LSP (workspace_symbol) ──────────────────────── 1|4|4 ┘                                 \n15|                                                                                          \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000001111121111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000001111131111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n04|114111333356665151255111111111111111111111111111111111111111111111111111111111111111111111\n05|788888888888888888888888888888888888888888888888888887777111111111111111111111111111111111\n06|799999:;:::<::::::::::::::::::::::::::::::::::::::::::::7=================================\n07|7>>>>>?????@????????????????????????????????????????????7=================================\n08|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n09|7??A???@@@@BCCCB?B?DBB??????????????????????????????????7=================================\n10|7@??????????????????????????????????????????????????????7=================================\n11|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n12|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n13|7EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE7=================================\n14|788888888888888888888888877777777777777777777777788888887=================================\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---manpages()---can-choose-in-split",
    "content": "--|---------|---------|---------|---------|\n01|st (1) - Manual Page│                   \n02|~                   │~                  \n03|~                   │~                  \n04|~                   │~                  \n05|~                   │~                  \n06|~                   │~                  \n07|~                   │~                  \n08|~                   │~                  \n09|~                   │~                  \n10|~                   │~                  \n11|~                   │~                  \n12|~                   │~                  \n13|~                   │~                  \n14|~                   │~                  \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000012222222222222222222\n02|3333333333333333333314444444444444444444\n03|3333333333333333333314444444444444444444\n04|3333333333333333333314444444444444444444\n05|3333333333333333333314444444444444444444\n06|3333333333333333333314444444444444444444\n07|3333333333333333333314444444444444444444\n08|3333333333333333333314444444444444444444\n09|3333333333333333333314444444444444444444\n10|3333333333333333333314444444444444444444\n11|3333333333333333333314444444444444444444\n12|3333333333333333333314444444444444444444\n13|3333333333333333333314444444444444444444\n14|3333333333333333333314444444444444444444\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---manpages()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│st (1)               - simple terminal     │                         \n09|│IO::Socket::IP (3perl) - Family-neutral IP…│                         \n10|│alacritty, Alacritty (1) - A fast, cross-p…│                         \n11|│afterstep_faq (1, 2)                       │                         \n12|│alacritty-msg(1) - Send messages to Alacri…│                         \n13|│amd64_iopl(2/amd64)                        │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ Manpages ────────────────────────── 1|6|6 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2334222222222222222222222222222222222222222221111111111111111111111111\n08|2555555555555555555555555555555555555555555521111111111111111111111111\n09|2666666666666666666666666666666666666666666721111111111111111111111111\n10|2666666666666666666666666666666666666666666721111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2666666666666666666666666666666666666666666721111111111111111111111111\n13|2666666666666666666666666666666666666666666621111111111111111111111111\n14|2888888888888888888888888888888888888888888821111111111111111111111111\n15|2888888888888888888888888888888888888888888821111111111111111111111111\n16|2888888888888888888888888888888888888888888821111111111111111111111111\n17|2888888888888888888888888888888888888888888821111111111111111111111111\n18|2888888888888888888888888888888888888888888821111111111111111111111111\n19|2999999999922222222222222222222222222999999921111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---manpages()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌ st (1)               - simple terminal ───┐                         \n08|│st (1) - Manual Page                       │                         \n09|│                                           │                         \n10|│                                           │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ Manpages ────────────────────────── 1|6|6 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333333333333333333333322221111111111111111111111111\n08|2444444444444444444444444444444444444444444421111111111111111111111111\n09|2555555555555555555555555555555555555555555521111111111111111111111111\n10|2555555555555555555555555555555555555555555521111111111111111111111111\n11|2555555555555555555555555555555555555555555521111111111111111111111111\n12|2555555555555555555555555555555555555555555521111111111111111111111111\n13|2555555555555555555555555555555555555555555521111111111111111111111111\n14|2555555555555555555555555555555555555555555521111111111111111111111111\n15|2555555555555555555555555555555555555555555521111111111111111111111111\n16|2555555555555555555555555555555555555555555521111111111111111111111111\n17|2555555555555555555555555555555555555555555521111111111111111111111111\n18|2555555555555555555555555555555555555555555521111111111111111111111111\n19|2333333333322222222222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---manpages()---works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|amd64_iopl (2) - Manual Page                                          \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|~                                                                     \n11|~                                                                     \n12|~                                                                     \n13|~                                                                     \n14|~                                                                     \n15|~                                                                     \n16|~                                                                     \n17|~                                                                     \n18|~                                                                     \n19|~                                                                     \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111111111111111111111111111111111\n15|1111111111111111111111111111111111111111111111111111111111111111111111\n16|1111111111111111111111111111111111111111111111111111111111111111111111\n17|1111111111111111111111111111111111111111111111111111111111111111111111\n18|1111111111111111111111111111111111111111111111111111111111111111111111\n19|1111111111111111111111111111111111111111111111111111111111111111111111\n20|2222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---respects-`local_opts.scope`",
    "content": "--|---------|---------|---------|---------|\n01|Line 1-1                                \n02|Line 1-2                                \n03|Line 1-3                                \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│A │ tests/dir-extra/rea…│              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Marks (global) ─ 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555556211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888888828888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---respects-`local_opts.scope`-002",
    "content": "--|---------|---------|---------|---------|\n01|Line 1-1                                \n02|Line 1-2                                \n03|Line 1-3                                \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a │ 1│4                 │              \n07|│b │ 3│6                 │              \n08|│' │ 1│1                 │              \n09|│\" │ 1│1                 │              \n10|│. │ 1│1                 │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Marks (buf) ──── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888822228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---respects-`local_opts.scope`-003",
    "content": "--|---------|---------|---------|---------|\n01|Line 2-1                                \n02|Line 2-2                                \n03|line 2-3                                \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a │ 2│3                 │              \n07|│' │ 1│1                 │              \n08|│\" │ 1│1                 │              \n09|│. │ 1│1                 │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Marks (buf) ──── 1|4|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888888822228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|Line 1-1                                                              \n02|Line 1-2                                                              \n03|Line 1-3                                                              \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌> ▏────────────────────────────────────────┐                         \n08|│a │ 1│4                                    │                         \n09|│b │ 3│6                                    │                         \n10|│' │ 1│1                                    │                         \n11|│\" │ 1│1                                    │                         \n12|│. │ 1│1                                    │                         \n13|│A │ tests/dir-extra/real-files/a.lua│1│6   │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ Marks (all) ─────────────────────── 1|6|6 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2334222222222222222222222222222222222222222221111111111111111111111111\n08|2555555555555555555555555555555555555555555521111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2666666666666666666666666666666666666666666621111111111111111111111111\n13|2666666666666666666666666666666666666666666621111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2888888888888822222222222222222222222888888821111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|Line 1-1                                                              \n02|Line 1-2                                                              \n03|Line 1-3                                                              \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌ a │ 1│4 ──────────────────────────────────┐                         \n08|│Line 1-1                                   │                         \n09|│Line 1-2                                   │                         \n10|│Line 1-3                                   │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ Marks (all) ─────────────────────── 1|6|6 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333222222222222222222222222222222222221111111111111111111111111\n08|2444544444444444444444444444444444444444444421111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2777777777777777777777777777777777777777777721111111111111111111111111\n12|2777777777777777777777777777777777777777777721111111111111111111111111\n13|2777777777777777777777777777777777777777777721111111111111111111111111\n14|2777777777777777777777777777777777777777777721111111111111111111111111\n15|2777777777777777777777777777777777777777777721111111111111111111111111\n16|2777777777777777777777777777777777777777777721111111111111111111111111\n17|2777777777777777777777777777777777777777777721111111111111111111111111\n18|2777777777777777777777777777777777777777777721111111111111111111111111\n19|2333333333333322222222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|Line 1-1                                                              \n02|Line 1-2                                                              \n03|Line 1-3                                                              \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌ b │ 3│6 ──────────────────────────────────┐                         \n08|│Line 1-3                                   │                         \n09|│                                           │                         \n10|│                                           │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ Marks (all) ─────────────────────── 2|6|6 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333222222222222222222222222222222222221111111111111111111111111\n08|2444445444444444444444444444444444444444444421111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2666666666666666666666666666666666666666666621111111111111111111111111\n13|2666666666666666666666666666666666666666666621111111111111111111111111\n14|2666666666666666666666666666666666666666666621111111111111111111111111\n15|2666666666666666666666666666666666666666666621111111111111111111111111\n16|2666666666666666666666666666666666666666666621111111111111111111111111\n17|2666666666666666666666666666666666666666666621111111111111111111111111\n18|2666666666666666666666666666666666666666666621111111111111111111111111\n19|2333333333333322222222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---marks()---works-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|Line 1-1                                                              \n02|Line 1-2                                                              \n03|Line 1-3                                                              \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|┌ A │ tests/dir-extra/real-files/a.lua│1│6 ─┐                         \n08|│local a = 1                                │                         \n09|│local t = {                                │                         \n10|│  x = math.max(a, 2),                      │                         \n11|│  y = math.min(a, 2),                      │                         \n12|│}                                          │                         \n13|│                                           │                         \n14|│                                           │                         \n15|│                                           │                         \n16|│                                           │                         \n17|│                                           │                         \n18|│                                           │                         \n19|└ Marks (all) ─────────────────────── 6|6|6 ┘                         \n20|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000000000000000000000000000000000\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|2333333333333333333333333333333333333333333221111111111111111111111111\n08|2444445666676666666666666666666666666666666621111111111111111111111111\n09|28888899999:9999999999999999999999999999999921111111111111111111111111\n10|299;999::::<===<9<9><<999999999999999999999921111111111111111111111111\n11|299;999::::<===<9<9><<999999999999999999999921111111111111111111111111\n12|2:99999999999999999999999999999999999999999921111111111111111111111111\n13|2???????????????????????????????????????????21111111111111111111111111\n14|2???????????????????????????????????????????21111111111111111111111111\n15|2???????????????????????????????????????????21111111111111111111111111\n16|2???????????????????????????????????????????21111111111111111111111111\n17|2???????????????????????????????????????????21111111111111111111111111\n18|2???????????????????????????????????????????21111111111111111111111111\n19|2333333333333322222222222222222222222333333321111111111111111111111111\n20|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---oldfiles()---can-not-show-icons",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│tests/dir-extra/real-files/LICENSE         │                         \n05|│tests/dir-extra/mocks/diagnostic.lua       │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Old files ───────────────────────── 1|2|2 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2777777777777777777777777777777777777777777721111111111111111111111111\n07|2777777777777777777777777777777777777777777721111111111111111111111111\n08|2777777777777777777777777777777777777777777721111111111111111111111111\n09|2888888888882222222222222222222222222888888821111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---oldfiles()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│ tests/dir-extra/real-files/LICENSE       │                         \n05|│ tests/dir-extra/mocks/diagnostic.lua     │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Old files ───────────────────────── 1|2|2 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2777777777777777777777777777777777777777777721111111111111111111111111\n07|2777777777777777777777777777777777777777777721111111111111111111111111\n08|2777777777777777777777777777777777777777777721111111111111111111111111\n09|2888888888882222222222222222222222222888888821111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---options()---correctly-previews-deprecated-options",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|-----\n01|                                                                                                                   \n02|~                                                                                                                  \n03|┌ aleph ────────────────────────────────────────────────────────────────┐                                          \n04|│Value:                                                                 │                                          \n05|│\"<Option is deprecated (will be removed in later Neovim versions)>\"    │                                          \n06|│                                                                       │                                          \n07|│Info:                                                                  │                                          \n08|│{                                                                      │                                          \n09|└ Options (all) ─────────────────────────────────────────────── 1|1|357 ┘                                          \n10|                                                                                                                   \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|-----\n01|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|2333333322222222222222222222222222222222222222222222222222222222222222222111111111111111111111111111111111111111111\n04|2444444555555555555555555555555555555555555555555555555555555555555555552111111111111111111111111111111111111111111\n05|2555555555555555555555555555555555555555555555555555555555555555555555552111111111111111111111111111111111111111111\n06|2555555555555555555555555555555555555555555555555555555555555555555555552111111111111111111111111111111111111111111\n07|2444445555555555555555555555555555555555555555555555555555555555555555552111111111111111111111111111111111111111111\n08|2555555555555555555555555555555555555555555555555555555555555555555555552111111111111111111111111111111111111111111\n09|2333333333333333222222222222222222222222222222222222222222222223333333332111111111111111111111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---options()---respects-set-options",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌> ^cursor▏──────────────┐              \n04|│cursorbind              │              \n05|│cursorcolumn            │              \n06|│cursorline              │              \n07|│cursorlineopt           │              \n08|│                        │              \n09|└ Options (all) ─────────┘              \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2334444444522222222222222211111111111111\n04|2666666777700000000000000211111111111111\n05|2888888999999999999999999211111111111111\n06|2888888999999999999999999211111111111111\n07|2888888:::::::99999999999211111111111111\n08|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n09|2<<<<<<<<<<<<<<<222222222211111111111111\n10|========================================\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---options()---respects-set-options-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌ cursorcolumn ──────────┐              \n04|│Value:                  │              \n05|│true                    │              \n06|│                        │              \n07|│Info:                   │              \n08|│{                       │              \n09|└ Options (all) ─────────┘              \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2333333333333332222222222211111111111111\n04|2444444555555555555555555211111111111111\n05|2555555555555555555555555211111111111111\n06|2555555555555555555555555211111111111111\n07|2444445555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2333333333333333222222222211111111111111\n10|6666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---options()---respects-set-options-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌ commentstring ─────────┐              \n04|│Value:                  │              \n05|│\"### %s\"                │              \n06|│                        │              \n07|│Info:                   │              \n08|│{                       │              \n09|└ Options (all) ─────────┘              \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2333333333333333222222222211111111111111\n04|2444444555555555555555555211111111111111\n05|2555555555555555555555555211111111111111\n06|2555555555555555555555555211111111111111\n07|2444445555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2333333333333333222222222211111111111111\n10|6666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---options()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|┌> ^cursor▏───────────────────────────┐                     \n13|│cursorbind                           │                     \n14|│cursorcolumn                         │                     \n15|│cursorline                           │                     \n16|│cursorlineopt                        │                     \n17|│                                     │                     \n18|│                                     │                     \n19|│                                     │                     \n20|│                                     │                     \n21|│                                     │                     \n22|│                                     │                     \n23|│                                     │                     \n24|│                                     │                     \n25|│                                     │                     \n26|│                                     │                     \n27|│                                     │                     \n28|│                                     │                     \n29|│                                     │                     \n30|│                                     │                     \n31|│                                     │                     \n32|│                                     │                     \n33|│                                     │                     \n34|└ Options (all) ───────────── 1|4|363 ┘                     \n35|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111\n12|233444444452222222222222222222222222222111111111111111111111\n13|266666677778888888888888888888888888882111111111111111111111\n14|2999999::::::;;;;;;;;;;;;;;;;;;;;;;;;;2111111111111111111111\n15|2999999::::;;;;;;;;;;;;;;;;;;;;;;;;;;;2111111111111111111111\n16|2999999:::::::;;;;;;;;;;;;;;;;;;;;;;;;2111111111111111111111\n17|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n18|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n19|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n20|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n21|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n22|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n23|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n24|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n25|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n26|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n27|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n28|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n29|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n30|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n31|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n32|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n33|2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<2111111111111111111111\n34|2===============2222222222222=========2111111111111111111111\n35|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---options()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|┌ cursorbind ─────────────────────────┐                     \n13|│Value:                               │                     \n14|│false                                │                     \n15|│                                     │                     \n16|│Info:                                │                     \n17|│{                                    │                     \n18|│  allows_duplicates = true,          │                     \n19|│  commalist = false,                 │                     \n20|│  default = false,                   │                     \n21|│  flaglist = false,                  │                     \n22|│  global_local = false,              │                     \n23|│  last_set_chan = 0,                 │                     \n24|│  last_set_linenr = 0,               │                     \n25|│  last_set_sid = 0,                  │                     \n26|│  name = \"cursorbind\",               │                     \n27|│  scope = \"win\",                     │                     \n28|│  shortname = \"crb\",                 │                     \n29|│  type = \"boolean\",                  │                     \n30|│  was_set = false                    │                     \n31|│}                                    │                     \n32|│                                     │                     \n33|│                                     │                     \n34|└ Options (all) ───────────── 1|4|363 ┘                     \n35|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111\n12|233333333333322222222222222222222222222111111111111111111111\n13|244444455555555555555555555555555555552111111111111111111111\n14|255555555555555555555555555555555555552111111111111111111111\n15|255555555555555555555555555555555555552111111111111111111111\n16|244444555555555555555555555555555555552111111111111111111111\n17|255555555555555555555555555555555555552111111111111111111111\n18|255555555555555555555555555555555555552111111111111111111111\n19|255555555555555555555555555555555555552111111111111111111111\n20|255555555555555555555555555555555555552111111111111111111111\n21|255555555555555555555555555555555555552111111111111111111111\n22|255555555555555555555555555555555555552111111111111111111111\n23|255555555555555555555555555555555555552111111111111111111111\n24|255555555555555555555555555555555555552111111111111111111111\n25|255555555555555555555555555555555555552111111111111111111111\n26|255555555555555555555555555555555555552111111111111111111111\n27|255555555555555555555555555555555555552111111111111111111111\n28|255555555555555555555555555555555555552111111111111111111111\n29|255555555555555555555555555555555555552111111111111111111111\n30|255555555555555555555555555555555555552111111111111111111111\n31|255555555555555555555555555555555555552111111111111111111111\n32|266666666666666666666666666666666666662111111111111111111111\n33|266666666666666666666666666666666666662111111111111111111111\n34|233333333333333322222222222223333333332111111111111111111111\n35|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---registers()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|~                                       \n16|~                                       \n17|~                                       \n18|~                                       \n19|~                                       \n20|~                                       \n21|~                                       \n22|~                                       \n23|~                                       \n24|~                                       \n25|~                                       \n26|~                                       \n27|~                                       \n28|~                                       \n29|~                                       \n30|┌> ▏─────────────────────┐              \n31|│\" │ Yank register Conta…│              \n32|│* │                     │              \n33|│+ │                     │              \n34|│: │                     │              \n35|│. │                     │              \n36|│% │                     │              \n37|│/ │                     │              \n38|│# │                     │              \n39|│= │ 1 + 1               │              \n40|│- │                     │              \n41|│0 │ Yank register Conta…│              \n42|│1 │                     │              \n43|│2 │                     │              \n44|│3 │                     │              \n45|│4 │                     │              \n46|│5 │                     │              \n47|│6 │                     │              \n48|│7 │                     │              \n49|│8 │                     │              \n50|│9 │                     │              \n51|│a │ Register a          │              \n52|│b │                     │              \n53|│c │                     │              \n54|│d │                     │              \n55|│e │                     │              \n56|│f │                     │              \n57|│g │                     │              \n58|│h │                     │              \n59|│i │                     │              \n60|│j │                     │              \n61|│k │                     │              \n62|│l │                     │              \n63|│m │                     │              \n64|│n │                     │              \n65|│o │                     │              \n66|│p │                     │              \n67|│q │                     │              \n68|│r │                     │              \n69|│s │                     │              \n70|│t │                     │              \n71|│u │                     │              \n72|│v │                     │              \n73|│w │                     │              \n74|│x │                     │              \n75|│y │                     │              \n76|│z │                     │              \n77|│                        │              \n78|│                        │              \n79|└ Registers ──── 1|46|46 ┘              \n80|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|1111111111111111111111111111111111111111\n16|1111111111111111111111111111111111111111\n17|1111111111111111111111111111111111111111\n18|1111111111111111111111111111111111111111\n19|1111111111111111111111111111111111111111\n20|1111111111111111111111111111111111111111\n21|1111111111111111111111111111111111111111\n22|1111111111111111111111111111111111111111\n23|1111111111111111111111111111111111111111\n24|1111111111111111111111111111111111111111\n25|1111111111111111111111111111111111111111\n26|1111111111111111111111111111111111111111\n27|1111111111111111111111111111111111111111\n28|1111111111111111111111111111111111111111\n29|1111111111111111111111111111111111111111\n30|2334222222222222222222222211111111111111\n31|2555555555555555555555556211111111111111\n32|2777777777777777777777777211111111111111\n33|2777777777777777777777777211111111111111\n34|2777777777777777777777777211111111111111\n35|2777777777777777777777777211111111111111\n36|2777777777777777777777777211111111111111\n37|2777777777777777777777777211111111111111\n38|2777777777777777777777777211111111111111\n39|2777777777777777777777777211111111111111\n40|2777777777777777777777777211111111111111\n41|2777777777777777777777776211111111111111\n42|2777777777777777777777777211111111111111\n43|2777777777777777777777777211111111111111\n44|2777777777777777777777777211111111111111\n45|2777777777777777777777777211111111111111\n46|2777777777777777777777777211111111111111\n47|2777777777777777777777777211111111111111\n48|2777777777777777777777777211111111111111\n49|2777777777777777777777777211111111111111\n50|2777777777777777777777777211111111111111\n51|2777777777777777777777777211111111111111\n52|2777777777777777777777777211111111111111\n53|2777777777777777777777777211111111111111\n54|2777777777777777777777777211111111111111\n55|2777777777777777777777777211111111111111\n56|2777777777777777777777777211111111111111\n57|2777777777777777777777777211111111111111\n58|2777777777777777777777777211111111111111\n59|2777777777777777777777777211111111111111\n60|2777777777777777777777777211111111111111\n61|2777777777777777777777777211111111111111\n62|2777777777777777777777777211111111111111\n63|2777777777777777777777777211111111111111\n64|2777777777777777777777777211111111111111\n65|2777777777777777777777777211111111111111\n66|2777777777777777777777777211111111111111\n67|2777777777777777777777777211111111111111\n68|2777777777777777777777777211111111111111\n69|2777777777777777777777777211111111111111\n70|2777777777777777777777777211111111111111\n71|2777777777777777777777777211111111111111\n72|2777777777777777777777777211111111111111\n73|2777777777777777777777777211111111111111\n74|2777777777777777777777777211111111111111\n75|2777777777777777777777777211111111111111\n76|2777777777777777777777777211111111111111\n77|2888888888888888888888888211111111111111\n78|2888888888888888888888888211111111111111\n79|2999999999992222999999999211111111111111\n80|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---registers()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|~                                       \n16|~                                       \n17|~                                       \n18|~                                       \n19|~                                       \n20|~                                       \n21|~                                       \n22|~                                       \n23|~                                       \n24|~                                       \n25|~                                       \n26|~                                       \n27|~                                       \n28|~                                       \n29|~                                       \n30|┌…ntains multiline text  ┐              \n31|│Yank register           │              \n32|│Contains multiline text │              \n33|│                        │              \n34|│                        │              \n35|│                        │              \n36|│                        │              \n37|│                        │              \n38|│                        │              \n39|│                        │              \n40|│                        │              \n41|│                        │              \n42|│                        │              \n43|│                        │              \n44|│                        │              \n45|│                        │              \n46|│                        │              \n47|│                        │              \n48|│                        │              \n49|│                        │              \n50|│                        │              \n51|│                        │              \n52|│                        │              \n53|│                        │              \n54|│                        │              \n55|│                        │              \n56|│                        │              \n57|│                        │              \n58|│                        │              \n59|│                        │              \n60|│                        │              \n61|│                        │              \n62|│                        │              \n63|│                        │              \n64|│                        │              \n65|│                        │              \n66|│                        │              \n67|│                        │              \n68|│                        │              \n69|│                        │              \n70|│                        │              \n71|│                        │              \n72|│                        │              \n73|│                        │              \n74|│                        │              \n75|│                        │              \n76|│                        │              \n77|│                        │              \n78|│                        │              \n79|└ Registers ──── 1|46|46 ┘              \n80|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|1111111111111111111111111111111111111111\n16|1111111111111111111111111111111111111111\n17|1111111111111111111111111111111111111111\n18|1111111111111111111111111111111111111111\n19|1111111111111111111111111111111111111111\n20|1111111111111111111111111111111111111111\n21|1111111111111111111111111111111111111111\n22|1111111111111111111111111111111111111111\n23|1111111111111111111111111111111111111111\n24|1111111111111111111111111111111111111111\n25|1111111111111111111111111111111111111111\n26|1111111111111111111111111111111111111111\n27|1111111111111111111111111111111111111111\n28|1111111111111111111111111111111111111111\n29|1111111111111111111111111111111111111111\n30|2333333333333333333333333211111111111111\n31|2444444444444444444444444211111111111111\n32|2444444444444444444444444211111111111111\n33|2444444444444444444444444211111111111111\n34|2555555555555555555555555211111111111111\n35|2555555555555555555555555211111111111111\n36|2555555555555555555555555211111111111111\n37|2555555555555555555555555211111111111111\n38|2555555555555555555555555211111111111111\n39|2555555555555555555555555211111111111111\n40|2555555555555555555555555211111111111111\n41|2555555555555555555555555211111111111111\n42|2555555555555555555555555211111111111111\n43|2555555555555555555555555211111111111111\n44|2555555555555555555555555211111111111111\n45|2555555555555555555555555211111111111111\n46|2555555555555555555555555211111111111111\n47|2555555555555555555555555211111111111111\n48|2555555555555555555555555211111111111111\n49|2555555555555555555555555211111111111111\n50|2555555555555555555555555211111111111111\n51|2555555555555555555555555211111111111111\n52|2555555555555555555555555211111111111111\n53|2555555555555555555555555211111111111111\n54|2555555555555555555555555211111111111111\n55|2555555555555555555555555211111111111111\n56|2555555555555555555555555211111111111111\n57|2555555555555555555555555211111111111111\n58|2555555555555555555555555211111111111111\n59|2555555555555555555555555211111111111111\n60|2555555555555555555555555211111111111111\n61|2555555555555555555555555211111111111111\n62|2555555555555555555555555211111111111111\n63|2555555555555555555555555211111111111111\n64|2555555555555555555555555211111111111111\n65|2555555555555555555555555211111111111111\n66|2555555555555555555555555211111111111111\n67|2555555555555555555555555211111111111111\n68|2555555555555555555555555211111111111111\n69|2555555555555555555555555211111111111111\n70|2555555555555555555555555211111111111111\n71|2555555555555555555555555211111111111111\n72|2555555555555555555555555211111111111111\n73|2555555555555555555555555211111111111111\n74|2555555555555555555555555211111111111111\n75|2555555555555555555555555211111111111111\n76|2555555555555555555555555211111111111111\n77|2555555555555555555555555211111111111111\n78|2555555555555555555555555211111111111111\n79|2333333333332222333333333211111111111111\n80|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---spellsuggest()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|hello wold                                                            \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|┌> ▏────────────────────────────────────────┐                         \n06|│world                                      │                         \n07|│would                                      │                         \n08|│Wold                                       │                         \n09|│old                                        │                         \n10|│word                                       │                         \n11|│weld                                       │                         \n12|│wild                                       │                         \n13|│bold                                       │                         \n14|└ Spell suggestions for \"wold\" ──── 1|25|25 ┘                         \n15|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|2334222222222222222222222222222222222222222221111111111111111111111111\n06|2555555555555555555555555555555555555555555521111111111111111111111111\n07|2666666666666666666666666666666666666666666621111111111111111111111111\n08|2666666666666666666666666666666666666666666621111111111111111111111111\n09|2666666666666666666666666666666666666666666621111111111111111111111111\n10|2666666666666666666666666666666666666666666621111111111111111111111111\n11|2666666666666666666666666666666666666666666621111111111111111111111111\n12|2666666666666666666666666666666666666666666621111111111111111111111111\n13|2666666666666666666666666666666666666666666621111111111111111111111111\n14|2777777777777777777777777777777222277777777721111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---spellsuggest()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|hello wold                                                            \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|┌ world ────────────────────────────────────┐                         \n06|│No preview available for `spellsuggest` pic│                         \n07|│                                           │                         \n08|│                                           │                         \n09|│                                           │                         \n10|│                                           │                         \n11|│                                           │                         \n12|│                                           │                         \n13|│                                           │                         \n14|└ Spell suggestions for \"wold\" ──── 1|25|25 ┘                         \n15|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|2333333322222222222222222222222222222222222221111111111111111111111111\n06|2444444444444444444444444444444444444444444421111111111111111111111111\n07|2555555555555555555555555555555555555555555521111111111111111111111111\n08|2555555555555555555555555555555555555555555521111111111111111111111111\n09|2555555555555555555555555555555555555555555521111111111111111111111111\n10|2555555555555555555555555555555555555555555521111111111111111111111111\n11|2555555555555555555555555555555555555555555521111111111111111111111111\n12|2555555555555555555555555555555555555555555521111111111111111111111111\n13|2555555555555555555555555555555555555555555521111111111111111111111111\n14|2333333333333333333333333333333222233333333321111111111111111111111111\n15|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---treesitter()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                           \n02|local t = {                                                           \n03|  x = math.max(a, 2),                                                 \n04|  y = math.min(a, 2),                                                 \n05|}                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|~                                                                     \n11|~                                                                     \n12|~                                                                     \n13|~                                                                     \n14|~                                                                     \n15|~                                                                     \n16|~                                                                     \n17|~                                                                     \n18|~                                                                     \n19|┌> ▏────────────────────────────────────────┐                         \n20|│variable_declaration (1│1 - 1│12)          │                         \n21|│ assignment_statement (1│7 - 1│12)         │                         \n22|│  variable_list (1│7 - 1│8)                │                         \n23|│   identifier (1│7 - 1│8)                  │                         \n24|│  expression_list (1│11 - 1│12)            │                         \n25|│   number (1│11 - 1│12)                    │                         \n26|│variable_declaration (2│1 - 5│2)           │                         \n27|│ assignment_statement (2│7 - 5│2)          │                         \n28|│  variable_list (2│7 - 2│8)                │                         \n29|│   identifier (2│7 - 2│8)                  │                         \n30|│  expression_list (2│11 - 5│2)             │                         \n31|│   table_constructor (2│11 - 5│2)          │                         \n32|│    field (3│3 - 3│21)                     │                         \n33|│     identifier (3│3 - 3│4)                │                         \n34|│     function_call (3│7 - 3│21)            │                         \n35|│      dot_index_expression (3│7 - 3│15)    │                         \n36|│       identifier (3│7 - 3│11)             │                         \n37|│       identifier (3│12 - 3│15)            │                         \n38|│      arguments (3│15 - 3│21)              │                         \n39|│       identifier (3│16 - 3│17)            │                         \n40|│       number (3│19 - 3│20)                │                         \n41|│    field (4│3 - 4│21)                     │                         \n42|│     identifier (4│3 - 4│4)                │                         \n43|│     function_call (4│7 - 4│21)            │                         \n44|│      dot_index_expression (4│7 - 4│15)    │                         \n45|│       identifier (4│7 - 4│11)             │                         \n46|│       identifier (4│12 - 4│15)            │                         \n47|│      arguments (4│15 - 4│21)              │                         \n48|│       identifier (4│16 - 4│17)            │                         \n49|│       number (4│19 - 4│20)                │                         \n50|│                                           │                         \n51|└ Tree-sitter nodes ─────────────── 1|30|30 ┘                         \n52|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000011111211111111111111111111111111111111111111111111111111111111111\n02|0000011111311111111111111111111111111111111111111111111111111111111111\n03|1141113333566651512551111111111111111111111111111111111111111111111111\n04|1141113333566651512551111111111111111111111111111111111111111111111111\n05|3111111111111111111111111111111111111111111111111111111111111111111111\n06|7777777777777777777777777777777777777777777777777777777777777777777777\n07|7777777777777777777777777777777777777777777777777777777777777777777777\n08|7777777777777777777777777777777777777777777777777777777777777777777777\n09|7777777777777777777777777777777777777777777777777777777777777777777777\n10|7777777777777777777777777777777777777777777777777777777777777777777777\n11|7777777777777777777777777777777777777777777777777777777777777777777777\n12|7777777777777777777777777777777777777777777777777777777777777777777777\n13|7777777777777777777777777777777777777777777777777777777777777777777777\n14|7777777777777777777777777777777777777777777777777777777777777777777777\n15|7777777777777777777777777777777777777777777777777777777777777777777777\n16|7777777777777777777777777777777777777777777777777777777777777777777777\n17|7777777777777777777777777777777777777777777777777777777777777777777777\n18|7777777777777777777777777777777777777777777777777777777777777777777777\n19|899:888888888888888888888888888888888888888887777777777777777777777777\n20|8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87777777777777777777777777\n21|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n22|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n23|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n24|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n25|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n26|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n27|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n28|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n29|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n30|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n31|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n32|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n33|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n34|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n35|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n36|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n37|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n38|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n39|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n40|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n41|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n42|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n43|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n44|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n45|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n46|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n47|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n48|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n49|8<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n50|8===========================================87777777777777777777777777\n51|8>>>>>>>>>>>>>>>>>>>888888888888888>>>>>>>>>87777777777777777777777777\n52|1111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---treesitter()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                           \n02|local t = {                                                           \n03|  x = math.max(a, 2),                                                 \n04|  y = math.min(a, 2),                                                 \n05|}                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|~                                                                     \n11|~                                                                     \n12|~                                                                     \n13|~                                                                     \n14|~                                                                     \n15|~                                                                     \n16|~                                                                     \n17|~                                                                     \n18|~                                                                     \n19|┌ variable_declaration (1│1 - 1│12) ────────┐                         \n20|│local a = 1                                │                         \n21|│local t = {                                │                         \n22|│  x = math.max(a, 2),                      │                         \n23|│  y = math.min(a, 2),                      │                         \n24|│}                                          │                         \n25|│                                           │                         \n26|│                                           │                         \n27|│                                           │                         \n28|│                                           │                         \n29|│                                           │                         \n30|│                                           │                         \n31|│                                           │                         \n32|│                                           │                         \n33|│                                           │                         \n34|│                                           │                         \n35|│                                           │                         \n36|│                                           │                         \n37|│                                           │                         \n38|│                                           │                         \n39|│                                           │                         \n40|│                                           │                         \n41|│                                           │                         \n42|│                                           │                         \n43|│                                           │                         \n44|│                                           │                         \n45|│                                           │                         \n46|│                                           │                         \n47|│                                           │                         \n48|│                                           │                         \n49|│                                           │                         \n50|│                                           │                         \n51|└ Tree-sitter nodes ─────────────── 1|30|30 ┘                         \n52|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000011111211111111111111111111111111111111111111111111111111111111111\n02|0000011111311111111111111111111111111111111111111111111111111111111111\n03|1141113333566651512551111111111111111111111111111111111111111111111111\n04|1141113333566651512551111111111111111111111111111111111111111111111111\n05|3111111111111111111111111111111111111111111111111111111111111111111111\n06|7777777777777777777777777777777777777777777777777777777777777777777777\n07|7777777777777777777777777777777777777777777777777777777777777777777777\n08|7777777777777777777777777777777777777777777777777777777777777777777777\n09|7777777777777777777777777777777777777777777777777777777777777777777777\n10|7777777777777777777777777777777777777777777777777777777777777777777777\n11|7777777777777777777777777777777777777777777777777777777777777777777777\n12|7777777777777777777777777777777777777777777777777777777777777777777777\n13|7777777777777777777777777777777777777777777777777777777777777777777777\n14|7777777777777777777777777777777777777777777777777777777777777777777777\n15|7777777777777777777777777777777777777777777777777777777777777777777777\n16|7777777777777777777777777777777777777777777777777777777777777777777777\n17|7777777777777777777777777777777777777777777777777777777777777777777777\n18|7777777777777777777777777777777777777777777777777777777777777777777777\n19|8999999999999999999999999999999999998888888887777777777777777777777777\n20|8:::::;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<87777777777777777777777777\n21|8=====>>>>>?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n22|8>>@>>>????ABBBA>A>CAA>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n23|8>>@>>>????ABBBA>A>CAA>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n24|8?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n25|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n26|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n27|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n28|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n29|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n30|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n31|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n32|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n33|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n34|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n35|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n36|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n37|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n38|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n39|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n40|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n41|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n42|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n43|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n44|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n45|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n46|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n47|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n48|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n49|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n50|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n51|8999999999999999999988888888888888899999999987777777777777777777777777\n52|1111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---treesitter()---works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|local a = 1                                                           \n02|local t = {                                                           \n03|  x = math.max(a, 2),                                                 \n04|  y = math.min(a, 2),                                                 \n05|}                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|~                                                                     \n11|~                                                                     \n12|~                                                                     \n13|~                                                                     \n14|~                                                                     \n15|~                                                                     \n16|~                                                                     \n17|~                                                                     \n18|~                                                                     \n19|┌  assignment_statement (1│7 - 1│12) ───────┐                         \n20|│local a = 1                                │                         \n21|│local t = {                                │                         \n22|│  x = math.max(a, 2),                      │                         \n23|│  y = math.min(a, 2),                      │                         \n24|│}                                          │                         \n25|│                                           │                         \n26|│                                           │                         \n27|│                                           │                         \n28|│                                           │                         \n29|│                                           │                         \n30|│                                           │                         \n31|│                                           │                         \n32|│                                           │                         \n33|│                                           │                         \n34|│                                           │                         \n35|│                                           │                         \n36|│                                           │                         \n37|│                                           │                         \n38|│                                           │                         \n39|│                                           │                         \n40|│                                           │                         \n41|│                                           │                         \n42|│                                           │                         \n43|│                                           │                         \n44|│                                           │                         \n45|│                                           │                         \n46|│                                           │                         \n47|│                                           │                         \n48|│                                           │                         \n49|│                                           │                         \n50|│                                           │                         \n51|└ Tree-sitter nodes ─────────────── 2|30|30 ┘                         \n52|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000011111211111111111111111111111111111111111111111111111111111111111\n02|0000011111311111111111111111111111111111111111111111111111111111111111\n03|1141113333566651512551111111111111111111111111111111111111111111111111\n04|1141113333566651512551111111111111111111111111111111111111111111111111\n05|3111111111111111111111111111111111111111111111111111111111111111111111\n06|7777777777777777777777777777777777777777777777777777777777777777777777\n07|7777777777777777777777777777777777777777777777777777777777777777777777\n08|7777777777777777777777777777777777777777777777777777777777777777777777\n09|7777777777777777777777777777777777777777777777777777777777777777777777\n10|7777777777777777777777777777777777777777777777777777777777777777777777\n11|7777777777777777777777777777777777777777777777777777777777777777777777\n12|7777777777777777777777777777777777777777777777777777777777777777777777\n13|7777777777777777777777777777777777777777777777777777777777777777777777\n14|7777777777777777777777777777777777777777777777777777777777777777777777\n15|7777777777777777777777777777777777777777777777777777777777777777777777\n16|7777777777777777777777777777777777777777777777777777777777777777777777\n17|7777777777777777777777777777777777777777777777777777777777777777777777\n18|7777777777777777777777777777777777777777777777777777777777777777777777\n19|8999999999999999999999999999999999999888888887777777777777777777777777\n20|8:::::;<<<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87777777777777777777777777\n21|8=====>>>>>?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n22|8>>@>>>????ABBBA>A>CAA>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n23|8>>@>>>????ABBBA>A>CAA>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n24|8?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>87777777777777777777777777\n25|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n26|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n27|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n28|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n29|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n30|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n31|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n32|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n33|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n34|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n35|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n36|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n37|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n38|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n39|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n40|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n41|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n42|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n43|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n44|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n45|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n46|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n47|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n48|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n49|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n50|8DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD87777777777777777777777777\n51|8999999999999999999988888888888888899999999987777777777777777777777777\n52|1111111111111111111111111111111111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_labels()---can-not-show-icons-after-choosing",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌> ▏──────────────────────────────────┐                     \n06|│file-xx                              │                     \n07|│file-xyx                             │                     \n08|│                                     │                     \n09|│                                     │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Paths for \"xxx\" label ─────── 1|2|2 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233422222222222222222222222222222222222111111111111111111111\n06|255555555555555555555555555555555555552111111111111111111111\n07|266666666666666666666666666666666666662111111111111111111111\n08|277777777777777777777777777777777777772111111111111111111111\n09|277777777777777777777777777777777777772111111111111111111111\n10|277777777777777777777777777777777777772111111111111111111111\n11|277777777777777777777777777777777777772111111111111111111111\n12|277777777777777777777777777777777777772111111111111111111111\n13|277777777777777777777777777777777777772111111111111111111111\n14|288888888888888888888888222222288888882111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_labels()---respects-`local_opts.sort`",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌ xxx ────────────────────────────────┐                     \n06|│aaa                                  │                     \n07|│                                     │                     \n08|│                                     │                     \n09|│                                     │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Visit labels (cwd) ────────── 1|3|3 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233333222222222222222222222222222222222111111111111111111111\n06|244444444444444444444444444444444444442111111111111111111111\n07|255555555555555555555555555555555555552111111111111111111111\n08|255555555555555555555555555555555555552111111111111111111111\n09|255555555555555555555555555555555555552111111111111111111111\n10|255555555555555555555555555555555555552111111111111111111111\n11|255555555555555555555555555555555555552111111111111111111111\n12|255555555555555555555555555555555555552111111111111111111111\n13|255555555555555555555555555555555555552111111111111111111111\n14|233333333333333333333222222222233333332111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_labels()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌> ▏──────────────────────────────────┐                     \n06|│xxx                                  │                     \n07|│uuu                                  │                     \n08|│yyy                                  │                     \n09|│                                     │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Visit labels (cwd) ────────── 1|3|3 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233422222222222222222222222222222222222111111111111111111111\n06|255555555555555555555555555555555555552111111111111111111111\n07|266666666666666666666666666666666666662111111111111111111111\n08|266666666666666666666666666666666666662111111111111111111111\n09|277777777777777777777777777777777777772111111111111111111111\n10|277777777777777777777777777777777777772111111111111111111111\n11|277777777777777777777777777777777777772111111111111111111111\n12|277777777777777777777777777777777777772111111111111111111111\n13|277777777777777777777777777777777777772111111111111111111111\n14|288888888888888888888222222222288888882111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_labels()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌ xxx ────────────────────────────────┐                     \n06|│file-xx                              │                     \n07|│file-xyx                             │                     \n08|│                                     │                     \n09|│                                     │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Visit labels (cwd) ────────── 1|3|3 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233333222222222222222222222222222222222111111111111111111111\n06|244444444444444444444444444444444444442111111111111111111111\n07|244444444444444444444444444444444444442111111111111111111111\n08|255555555555555555555555555555555555552111111111111111111111\n09|255555555555555555555555555555555555552111111111111111111111\n10|255555555555555555555555555555555555552111111111111111111111\n11|255555555555555555555555555555555555552111111111111111111111\n12|255555555555555555555555555555555555552111111111111111111111\n13|255555555555555555555555555555555555552111111111111111111111\n14|233333333333333333333222222222233333332111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_labels()---works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌> ▏──────────────────────────────────┐                     \n06|│ real-files/a.lua                   │                     \n07|│                                     │                     \n08|│                                     │                     \n09|│                                     │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Paths for \"yyy\" label ─────── 1|1|1 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233422222222222222222222222222222222222111111111111111111111\n06|255555555555555555555555555555555555552111111111111111111111\n07|266666666666666666666666666666666666662111111111111111111111\n08|266666666666666666666666666666666666662111111111111111111111\n09|266666666666666666666666666666666666662111111111111111111111\n10|266666666666666666666666666666666666662111111111111111111111\n11|266666666666666666666666666666666666662111111111111111111111\n12|266666666666666666666666666666666666662111111111111111111111\n13|266666666666666666666666666666666666662111111111111111111111\n14|277777777777777777777777222222277777772111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_paths()---can-not-show-icons",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌> ▏──────────────────────────────────┐                     \n06|│file-xyyx                            │                     \n07|│file-xx                              │                     \n08|│file-xyx                             │                     \n09|│real-files/a.lua                     │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Visit paths (cwd) ─────────── 1|4|4 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233422222222222222222222222222222222222111111111111111111111\n06|255555555555555555555555555555555555552111111111111111111111\n07|266666666666666666666666666666666666662111111111111111111111\n08|266666666666666666666666666666666666662111111111111111111111\n09|266666666666666666666666666666666666662111111111111111111111\n10|277777777777777777777777777777777777772111111111111111111111\n11|277777777777777777777777777777777777772111111111111111111111\n12|277777777777777777777777777777777777772111111111111111111111\n13|277777777777777777777777777777777777772111111111111111111111\n14|288888888888888888882222222222288888882111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_paths()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌> ▏──────────────────────────────────┐                     \n06|│  file-xyyx                          │                     \n07|│  file-xx                            │                     \n08|│  file-xyx                           │                     \n09|│ real-files/a.lua                   │                     \n10|│                                     │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Visit paths (cwd) ─────────── 1|4|4 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233422222222222222222222222222222222222111111111111111111111\n06|255555555555555555555555555555555555552111111111111111111111\n07|266666666666666666666666666666666666662111111111111111111111\n08|266666666666666666666666666666666666662111111111111111111111\n09|266666666666666666666666666666666666662111111111111111111111\n10|277777777777777777777777777777777777772111111111111111111111\n11|277777777777777777777777777777777777772111111111111111111111\n12|277777777777777777777777777777777777772111111111111111111111\n13|277777777777777777777777777777777777772111111111111111111111\n14|288888888888888888882222222222288888882111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_extra.lua---pickers---visit_paths()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|┌ real-files/a.lua ───────────────────┐                     \n06|│local a = 1                          │                     \n07|│local t = {                          │                     \n08|│  x = math.max(a, 2),                │                     \n09|│  y = math.min(a, 2),                │                     \n10|│}                                    │                     \n11|│                                     │                     \n12|│                                     │                     \n13|│                                     │                     \n14|└ Visit paths (cwd) ─────────── 4|4|4 ┘                     \n15|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|233333333333333333322222222222222222222111111111111111111111\n06|244444555556555555555555555555555555552111111111111111111111\n07|244444555557555555555555555555555555552111111111111111111111\n08|255855577779:::959569955555555555555552111111111111111111111\n09|255855577779:::959569955555555555555552111111111111111111111\n10|275555555555555555555555555555555555552111111111111111111111\n11|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2111111111111111111111\n12|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2111111111111111111111\n13|2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2111111111111111111111\n14|233333333333333333332222222222233333332111111111111111111111\n15|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Cursors---handle-`content.prefix`-returning-different-lengths",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│.a-dir                                            │                            \n03|│+a-dir                                            │                            \n04|│++b-dir                                           │                            \n05|│+++.a-file                                        │                            \n06|│++++a-file                                        │                            \n07|│+++++A-file-2                                     │                            \n08|│++++++b-file                                      │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,5           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333334444444444444444444444444444444444444444444405555555555555555555555555555\n03|06777778888888888888888888888888888888888888888888805555555555555555555555555555\n04|06677777888888888888888888888888888888888888888888805555555555555555555555555555\n05|06668888888888888888888888888888888888888888888888805555555555555555555555555555\n06|06666888888888888888888888888888888888888888888888805555555555555555555555555555\n07|06666688888888888888888888888888888888888888888888805555555555555555555555555555\n08|06666668888888888888888888888888888888888888888888805555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Cursors---shows-whole-line-after-horizontal-scroll",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│a-dir                                             │        \n03|│-dir                                              │        \n04|│-dir                                              │        \n05|│a-file                                            │        \n06|│-file                                             │        \n07|│-file-2                                           │        \n08|│-file                                             │        \n09|└──────────────────────────────────────────────────┘        \n10|                                          1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066667777777777777777777777777777777777777777777777055555555\n04|066667777777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Cursors---shows-whole-line-after-horizontal-scroll-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ .a-dir                                          │        \n03|│ a-dir                                           │        \n04|│ b-dir                                           │        \n05|│ .a-file                                         │        \n06|│ a-file                                          │        \n07|│ A-file-2                                        │        \n08|│ b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Default-explorer---works-in-`-edit-.`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Default-explorer---works-in-`-tabfind-.`",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ .a-dir                                          │        \n03|│ a-dir                                           │        \n04|│ b-dir                                           │        \n05|│ .a-file                                         │        \n06|│ a-file                                          │        \n07|│ A-file-2                                        │        \n08|│ b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Default-explorer---works-in-`-tabfind-.`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|b-file                                                      \n02|Another line                                                \n03|~                                                           \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|000000000000000000000000000000000000000000000000000000000000\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111111111111111111111111111111111111111111\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Default-explorer---works-in-`-vsplit-.`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                       │~                                      \n11|~                                       │~                                      \n12|~                                       │~                                      \n13|~                                       │~                                      \n14|~                                       │~                                      \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555558555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555558555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555558555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555558555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555558555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Default-explorer---works-in-`-vsplit-.`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|b-file                                  │                                       \n02|Another line                            │~                                      \n03|~                                       │~                                      \n04|~                                       │~                                      \n05|~                                       │~                                      \n06|~                                       │~                                      \n07|~                                       │~                                      \n08|~                                       │~                                      \n09|~                                       │~                                      \n10|~                                       │~                                      \n11|~                                       │~                                      \n12|~                                       │~                                      \n13|~                                       │~                                      \n14|~                                       │~                                      \n15|                                                              1,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000001222222222222222222222222222222222222222\n02|00000000000000000000000000000000000000001333333333333333333333333333333333333333\n03|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n04|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n05|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n06|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n07|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n08|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n09|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n10|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n11|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n12|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n13|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n14|44444444444444444444444444444444444444441333333333333333333333333333333333333333\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Default-explorer---works-on-startup",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowOpen`-can-be-used-to-tweak-window-config",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|╔═════════════════MOCK_ROOT/tests/dir-files/common ╗                            \n02|║ .a-dir                                          ║                            \n03|║ a-dir                                           ║                            \n04|║ b-dir                                           ║                            \n05|║ .a-file                                         ║                            \n06|║ a-file                                          ║                            \n07|║ A-file-2                                        ║                            \n08|║ b-file                                          ║                            \n09|╚══════════════════════════════════════════════════╝                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000011111111111111111111111111111111102222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowOpen`-can-be-used-to-tweak-window-config-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|╔…-files/common ╗╔══════════════════════════════════════════ .a-dir ╗           \n02|║ .a-dir       ║║ aa-file                                         ║           \n03|║ a-dir        ║║ ab-file                                         ║           \n04|║ b-dir        ║╚══════════════════════════════════════════════════╝           \n05|║ .a-file      ║                                                               \n06|║ a-file       ║                                                               \n07|║ A-file-2     ║                                                               \n08|║ b-file       ║                                                               \n09|╚═══════════════╝                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110000000000000000000000000000000000000000000022222222033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowOpen`-can-be-used-to-tweak-window-config-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|╔…-files/common ╗╔══════════════════════════════════════════ .a-dir ╗           \n02|║ .a-dir       ║║ aa-file                                         ║           \n03|║ a-dir        ║║ ab-file                                         ║           \n04|║ b-dir        ║╚══════════════════════════════════════════════════╝           \n05|║ .a-file      ║                                                               \n06|║ a-file       ║                                                               \n07|║ A-file-2     ║                                                               \n08|║ b-file       ║                                                               \n09|╚═══════════════╝                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110000000000000000000000000000000000000000000022222222033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowUpdate`-can-customize-internally-set-window-config-parts",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/common─┐┌.a-dir──────────────────────────────────┐┌aa-file─────────────┐    \n02|│ .a-dir  ││ aa-file                               ││                    │    \n03|│ a-dir   ││ ab-file                               ││                    │    \n04|│ b-dir   ││                                        ││                    │    \n05|│ .a-file ││                                        ││                    │    \n06|│ a-file  ││                                        ││                    │    \n07|└──────────┘└────────────────────────────────────────┘└────────────────────┘    \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111110002222220000000000000000000000000000000000001111111000000000000003333\n02|04444444455005555555555555555555555555555555555555555006666666666666666666607777\n03|08888888666006666666666666666666666666666666666666666009999999999999999999907777\n04|08888888666009999999999999999999999999999999999999999009999999999999999999907777\n05|06666666666009999999999999999999999999999999999999999009999999999999999999907777\n06|06666666666009999999999999999999999999999999999999999009999999999999999999907777\n07|00000000000000000000000000000000000000000000000000000000000000000000000000007777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowUpdate`-can-customize-internally-set-window-config-parts-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/common─┐┌.a-dir──────────────────────────────────┐┌abc─────────────────┐    \n02|│ .a-dir  ││ aa-file                               ││-No-fs-entry--------│    \n03|│ a-dir   ││abc                                     ││                    │    \n04|│ b-dir   ││ ab-file                               ││                    │    \n05|│ .a-file ││                                        ││                    │    \n06|│ a-file  ││                                        ││                    │    \n07|└──────────┘└────────────────────────────────────────┘└────────────────────┘    \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- INSERT --                                                  2,4           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111110023333332222222222222222222222222222222222201110000000000000000004444\n02|05555555566027777777777777777777777777777777777777777207777777777777777777708888\n03|0999999977702666666666666666666666666666666666666666620::::::::::::::::::::08888\n04|0999999977702777777777777777777777777777777777777777720::::::::::::::::::::08888\n05|0777777777702::::::::::::::::::::::::::::::::::::::::20::::::::::::::::::::08888\n06|0777777777702::::::::::::::::::::::::::::::::::::::::20::::::::::::::::::::08888\n07|00000000000022222222222222222222222222222222222222222200000000000000000000008888\n08|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n09|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|;;;;;;;;;;;;44444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowUpdate`-can-customize-internally-set-window-config-parts-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common────────┐┌def─────────────────┐                \n02|│ .a-dir                                ││-No-fs-entry--------│                \n03|│def                                     ││                    │                \n04|│ a-dir                                 ││                    │                \n05|│ b-dir                                 ││                    │                \n06|│ .a-file                               ││                    │                \n07|└────────────────────────────────────────┘└────────────────────┘                \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- INSERT --                                                  2,4           Top \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111100000000023332222222222222222224444444444444444\n02|05555555566666666666666666666666666666666026666666666666666666627777777777777777\n03|08888888888888888888888888888888888888888029999999999999999999927777777777777777\n04|05555555666666666666666666666666666666666029999999999999999999927777777777777777\n05|05555555666666666666666666666666666666666029999999999999999999927777777777777777\n06|06666666666666666666666666666666666666666029999999999999999999927777777777777777\n07|00000000000000000000000000000000000000000022222222222222222222227777777777777777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|::::::::::::44444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowUpdate`-can-customize-internally-set-window-config-parts-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common────────┐┌a───────────────────┐                \n02|│def                                     ││-No-fs-entry--------│                \n03|│ a-dir                                 ││                    │                \n04|│ b-dir                                 ││                    │                \n05|│ .a-file                               ││                    │                \n06|│a                                       ││                    │                \n07|└────────────────────────────────────────┘└────────────────────┘                \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- INSERT --                                                  6,2           25% \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111100000000023222222222222222222224444444444444444\n02|05555555555555555555555555555555555555555025555555555555555555526666666666666666\n03|07777777555555555555555555555555555555555028888888888888888888826666666666666666\n04|07777777555555555555555555555555555555555028888888888888888888826666666666666666\n05|05555555555555555555555555555555555555555028888888888888888888826666666666666666\n06|09999999999999999999999999999999999999999028888888888888888888826666666666666666\n07|00000000000000000000000000000000000000000022222222222222222222226666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|::::::::::::44444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Events---`MiniFilesWindowUpdate`-can-customize-internally-set-window-config-parts-005",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common────────┐┌a-file──────────────┐                \n02|│def                                     ││-No-fs-entry--------│                \n03|│ a-dir                                 ││                    │                \n04|│ b-dir                                 ││                    │                \n05|│ .a-file                               ││                    │                \n06|│a-file                                  ││                    │                \n07| a-file         ─────────────────────────┘└────────────────────┘                \n08| a-dir                                                                          \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- Keyword completion (^N^P) match 1 of 2                                       \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111100000000023333332222222222222224444444444444444\n02|05555555555555555555555555555555555555555025555555555555555555526666666666666666\n03|07777777555555555555555555555555555555555028888888888888888888826666666666666666\n04|07777777555555555555555555555555555555555028888888888888888888826666666666666666\n05|05555555555555555555555555555555555555555028888888888888888888826666666666666666\n06|09999999999999999999999999999999999999999028888888888888888888826666666666666666\n07|::::::::::::::::0000000000000000000000000022222222222222222222226666666666666666\n08|99999999999999996666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<<<<<<<<<444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-be-not-confirmed",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│new-file                                          │                            \n04|│ a-dir                                           │                            \n05|│ b-dir                                           │                            \n06|│ .a-file                                         │                            \n07|│ a-file                                          │                            \n08|│ A-file-2                                        │                            \n09|│ b-file                                          │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,8           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n10|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-be-not-confirmed-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-be-not-confirmed-with-preview",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ new-file ───────────────┐ \n02|│ .a-dir                                          ││-No-fs-entry-------------│ \n03|│new-file                                          │└─────────────────────────┘ \n04|│ a-dir                                           │                            \n05|│ b-dir                                           │                            \n06|│ .a-file                                         │                            \n07|│ a-file                                          │                            \n08|│ A-file-2                                        │                            \n09|│ b-file                                          │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,8           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002333333333322222222222222224\n02|05555555566666666666666666666666666666666666666666602666666666666666666666666627\n03|08888888888888888888888888888888888888888888888888802222222222222222222222222227\n04|05555555666666666666666666666666666666666666666666607777777777777777777777777777\n05|05555555666666666666666666666666666666666666666666607777777777777777777777777777\n06|06666666666666666666666666666666666666666666666666607777777777777777777777777777\n07|06666666666666666666666666666666666666666666666666607777777777777777777777777777\n08|06666666666666666666666666666666666666666666666666607777777777777777777777777777\n09|06666666666666666666666666666666666666666666666666607777777777777777777777777777\n10|00000000000000000000000000000000000000000000000000007777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-be-not-confirmed-with-preview-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ .a-dir ─────────────────┐ \n02|│ .a-dir                                          ││ aa-file                │ \n03|│ a-dir                                           ││ ab-file                │ \n04|│ b-dir                                           │└─────────────────────────┘ \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222220000000000000000003\n02|04444444455555555555555555555555555555555555555555500555555555555555555555555506\n03|07777777888888888888888888888888888888888888888888800888888888888888888888888806\n04|07777777888888888888888888888888888888888888888888800000000000000000000000000006\n05|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n06|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n07|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n08|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-convert-file-into-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir/                                            │                            \n03|│ file/                                           │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,13-11       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333334444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-convert-file-into-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ file                                            │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666667777777777777777777777777777777777777777777705555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ dir-target                                      │                            \n04|│ dir-copy                                        │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,16-14       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333333334444444444444444444444444444444444444405555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ dir-copy                                        │                            \n04|│ dir-target                                      │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666777777777777777777777777777777777777777705555555555555555555555555555\n04|03333333333334444444444444444444444444444444444444405555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-directory-inside-itself",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ nested                                          │           \n03|└───────────────┘│ dir                                             │           \n04|~                │ file                                            │           \n05|~                └──────────────────────────────────────────────────┘           \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110233333222222222222222222222222222222222222222222222244444444444\n02|05555566666666660277777777888888888888888888888888888888888888888888299999999999\n03|00000000000000000266666666666666666666666666666666666666666666666666299999999999\n04|99999999999999999288888888888888888888888888888888888888888888888888299999999999\n05|99999999999999999222222222222222222222222222222222222222222222222222299999999999\n06|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n07|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n08|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n09|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n10|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n11|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n12|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n13|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n14|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n15|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-directory-inside-itself-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ dir                                             │           \n03|└───────────────┘│ nested                                          │           \n04|~                │ file                                            │           \n05|~                └──────────────────────────────────────────────────┘           \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222000000000000000000000000000000000000000000000033333333333\n02|04444455555555550044444555555555555555555555555555555555555555555555066666666666\n03|00000000000000000077777777888888888888888888888888888888888888888888066666666666\n04|66666666666666666088888888888888888888888888888888888888888888888888066666666666\n05|66666666666666666000000000000000000000000000000000000000000000000000066666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-directory-inside-new-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ new-dir/new-subdir/dir                          │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,27-25       All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066666666666666666666666666666666666666666666666666055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-directory-inside-new-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ new-dir                                         │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066666666677777777777777777777777777777777777777777055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-file",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ file-copy                                       │                            \n04|│ file                                            │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,17-15       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-file-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ file                                            │                            \n04|│ file-copy                                       │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-file-inside-new-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ file                                            │        \n03|│ new-dir/new-subdir/file                         │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,27-25       All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-copy-file-inside-new-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ new-dir                                         │        \n03|│ file                                            │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333344444444444444444444444444444444444444444055555555\n03|066666666666666666666666666666666666666666666666666055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-create",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│new-file                                          │        \n03|│new-dir/                                          │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-create-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ new-dir                                         │        \n03|│ new-file                                        │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333344444444444444444444444444444444444444444055555555\n03|066666666666666666666666666666666666666666666666666055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-delete",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│                                                  │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-delete-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│                                                  │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir-target ──────────────────────────────────────┐           \n02|│ dir-target   ││ dir                                             │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222222200000000000000000000000000000000000000033333333333\n02|04444444444445550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir-target ──────────────────────────────────────┐           \n02|│ dir-target   ││ dir                                             │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222222200000000000000000000000000000000000000033333333333\n02|04444444444445550044444555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-file",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ file                                            │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222000000000000000000000000000000000000000000000033333333333\n02|04444455555555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-file-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ file                                            │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222000000000000000000000000000000000000000000000033333333333\n02|04444455555555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-inside-new-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ new-dir/new-subdir/file                         │        \n03|└──────────────────────────────────────────────────┘        \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,27-25       All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|000000000000000000000000000000000000000000000000000044444444\n04|444444444444444444444444444444444444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-inside-new-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ new-dir                                         │        \n03|└──────────────────────────────────────────────────┘        \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333344444444444444444444444444444444444444444055555555\n03|000000000000000000000000000000000000000000000000000055555555\n04|555555555555555555555555555555555555555555555555555555555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-while-changing-basename",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ new-file                                        │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,16-14       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222000000000000000000000000000000000000000000000033333333333\n02|04444455555555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-move-while-changing-basename-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ new-file                                        │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222000000000000000000000000000000000000000000000033333333333\n02|04444455555555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-rename",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ new-dir                                         │                            \n03|│ file-new                                        │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,16-14       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333334444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---can-rename-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ new-dir                                         │                            \n03|│ file-new                                        │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333334444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---copy-does-not-override-existing-entry",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ target-dir                                      │                            \n04|│ file                                            │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666667777777777777777777777777777777777777705555555555555555555555555555\n04|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---copy-does-not-override-existing-entry-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ target-dir ──────────────────────────────────────┐           \n02|│ dir          ││ dir                                             │           \n03|│ target-dir   ││ dir                                             │           \n04|│ file         ││ file                                            │           \n05|└───────────────┘│ file                                            │           \n06|~                └──────────────────────────────────────────────────┘           \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              3,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110233333333333322222222222222222222222222222222222222244444444444\n02|05555566666666660255555666666666666666666666666666666666666666666666277777777777\n03|08888888888889990266666666666666666666666666666666666666666666666666277777777777\n04|06666666666666660299999999999999999999999999999999999999999999999999277777777777\n05|00000000000000000266666666666666666666666666666666666666666666666666277777777777\n06|77777777777777777222222222222222222222222222222222222222222222222222277777777777\n07|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---copy-does-not-override-existing-entry-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ target-dir ──────────────────────────────────────┐           \n02|│ dir          ││ dir                                             │           \n03|│ target-dir   ││ file                                            │           \n04|│ file         │└──────────────────────────────────────────────────┘           \n05|└───────────────┘                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222222200000000000000000000000000000000000000033333333333\n02|04444455555555550044444555555555555555555555555555555555555555555555066666666666\n03|07777777777778880088888888888888888888888888888888888888888888888888066666666666\n04|05555555555555550000000000000000000000000000000000000000000000000000066666666666\n05|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---create-does-not-override-existing-entry",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│file                                              │        \n04|│dir/                                              │        \n05|│ file                                            │        \n06|└──────────────────────────────────────────────────┘        \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          3,4           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|044444444444444444444444444444444444444444444444444055555555\n04|066666666666666666666666666666666666666666666666666055555555\n05|044444444444444444444444444444444444444444444444444055555555\n06|000000000000000000000000000000000000000000000000000055555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---create-does-not-override-existing-entry-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ file                                            │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066666666666666666666666666666666666666666666666666055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---creates-files-in-nested-directories",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│dir/nested-file                                   │        \n04|│dir-1/nested-file-1                               │        \n05|│dir-1/nested-file-2                               │        \n06|└──────────────────────────────────────────────────┘        \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|055555555555555555555555555555555555555555555555555044444444\n05|055555555555555555555555555555555555555555555555555044444444\n06|000000000000000000000000000000000000000000000000000044444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---creates-files-in-nested-directories-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ dir-1                                           │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---creates-nested-directories",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│dir/nested-dir/                                   │        \n04|│dir-1/nested-dir-1/                               │        \n05|│dir-1/nested-dir-2/                               │        \n06|└──────────────────────────────────────────────────┘        \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|055555555555555555555555555555555555555555555555555044444444\n05|055555555555555555555555555555555555555555555555555044444444\n06|000000000000000000000000000000000000000000000000000044444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---creates-nested-directories-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ dir-1                                           │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|000000000000000000000000000000000000000000000000000055555555\n05|555555555555555555555555555555555555555555555555555555555555\n06|555555555555555555555555555555555555555555555555555555555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---handles-backslash-on-Unix",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ new-hello                                       │                            \n03|│bad\\file                                          │                            \n04|│ wo\\rld                                          │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,8           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n05|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---handles-backslash-on-Unix-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ bad\\file                                        │                            \n03|│ new-hello                                       │                            \n04|│ wo\\rld                                          │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n05|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---handles-move-directory-inside-itself",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│                                                  │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|--No lines in buffer--                                        0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---handles-move-directory-inside-itself-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|--No lines in buffer--                                        1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n04|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---ignores-blank-lines",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│                                                  │                            \n04|│                                                  │                            \n05|│ a-dir                                           │                            \n06|│ b-dir                                           │                            \n07|│ .a-file                                         │                            \n08|│ a-file                                          │                            \n09|│ A-file-2                                        │                            \n10|│ b-file                                          │                            \n11|└──────────────────────────────────────────────────┘                            \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n06|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n10|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n11|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---ignores-blank-lines-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---ignores-identical-user-copied-entries",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ .a-dir                                          │                            \n04|│ a-dir                                           │                            \n05|│ a-dir                                           │                            \n06|│ b-dir                                           │                            \n07|│ .a-file                                         │                            \n08|│ a-file                                          │                            \n09|│ A-file-2                                        │                            \n10|│ b-file                                          │                            \n11|└──────────────────────────────────────────────────┘                            \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n05|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n06|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n10|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n11|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---ignores-identical-user-copied-entries-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---move-does-not-override-existing-entry",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ target-dir                                      │                            \n04|│ file                                            │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666667777777777777777777777777777777777777705555555555555555555555555555\n04|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---move-does-not-override-existing-entry-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ target-dir ──────────────────────────────────────┐           \n02|│ target-dir   ││ dir                                             │           \n03|└───────────────┘│ dir                                             │           \n04|~                │ file                                            │           \n05|~                │ file                                            │           \n06|~                └──────────────────────────────────────────────────┘           \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              3,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222222200000000000000000000000000000000000000033333333333\n02|04444444444445550066666777777777777777777777777777777777777777777777088888888888\n03|00000000000000000077777777777777777777777777777777777777777777777777088888888888\n04|88888888888888888055555555555555555555555555555555555555555555555555088888888888\n05|88888888888888888077777777777777777777777777777777777777777777777777088888888888\n06|88888888888888888000000000000000000000000000000000000000000000000000088888888888\n07|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n08|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n09|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---move-does-not-override-existing-entry-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ target-dir ──────────────────────────────────────┐           \n02|│ dir          ││ dir                                             │           \n03|│ target-dir   ││ file                                            │           \n04|│ file         │└──────────────────────────────────────────────────┘           \n05|└───────────────┘                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222222200000000000000000000000000000000000000033333333333\n02|04444455555555550044444555555555555555555555555555555555555555555555066666666666\n03|07777777777778880088888888888888888888888888888888888888888888888888066666666666\n04|05555555555555550000000000000000000000000000000000000000000000000000066666666666\n05|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---move-works-again-after-undo",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir ─────────────────────────────────────────────┐           \n02|│ dir          ││ file                                            │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222000000000000000000000000000000000000000000000033333333333\n02|04444455555555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---move-works-again-after-undo-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ file                                            │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---rename-does-not-override-existing-entry",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ dir-2                                           │        \n04|│ file                                            │        \n05|│ file-2                                          │        \n06|└──────────────────────────────────────────────────┘        \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|077777777777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|000000000000000000000000000000000000000000000000000055555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---rename-does-not-override-existing-entry-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir-2                                           │        \n03|│ dir-2                                           │        \n04|│ file-2                                          │        \n05|│ file-2                                          │        \n06|└──────────────────────────────────────────────────┘        \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          3,14-12       All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333334444444444444444444444444444444444444444444055555555\n03|033333334444444444444444444444444444444444444444444055555555\n04|066666666666666666666666666666666666666666666666666055555555\n05|044444444444444444444444444444444444444444444444444055555555\n06|000000000000000000000000000000000000000000000000000055555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---rename-does-not-override-existing-entry-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ dir                                             │        \n03|│ dir-2                                           │        \n04|│ file                                            │        \n05|│ file-2                                          │        \n06|└──────────────────────────────────────────────────┘        \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          4,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333444444444444444444444444444444444444444444444055555555\n03|033333334444444444444444444444444444444444444444444055555555\n04|044444444444444444444444444444444444444444444444444055555555\n05|066666666666666666666666666666666666666666666666666055555555\n06|000000000000000000000000000000000000000000000000000055555555\n07|555555555555555555555555555555555555555555555555555555555555\n08|555555555555555555555555555555555555555555555555555555555555\n09|555555555555555555555555555555555555555555555555555555555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---rename-works-again-after-undo",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ file-new                                        │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,16-14       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---rename-works-again-after-undo-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ file                                            │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|1 change; before #1  0 seconds ago                            1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---respects-modified-hidden-buffers",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ dir                                             │                            \n03|│ file                                            │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---works-with-problematic-names",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ c file                                          │                            \n03|│d file                                            │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,6           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---File-manipulation---works-with-problematic-names-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ c file                                          │                            \n03|│ d file                                          │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in_plus`-supports--count-",
    "content": "--|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ───┐┌ dir-11 ────────────┐    \n02|│ dir-1   ││ dir-11  ││ dir-111           │    \n03|└──────────┘│ dir-12  │└────────────────────┘    \n04|~           └──────────┘                          \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|                                1,9-7         All \n\n--|---------|---------|---------|---------|---------|\n01|01111111111001111111000002222222200000000000003333\n02|04444444555004444444455004444444445555555555506666\n03|00000000000007777777788000000000000000000000006666\n04|66666666666600000000000066666666666666666666666666\n05|66666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in_plus`-supports--count--002",
    "content": "--|---------|---------|---------|---------|---------|\n01|Temp file                                         \n02|~                                                 \n03|~                                                 \n04|~                                                 \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|22222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in_plus`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in`-supports--count-",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ───┐┌ dir-11 ────────────┐              \n02|│ dir-1   ││ dir-11  ││ dir-111           │              \n03|└──────────┘│ dir-12  │└────────────────────┘              \n04|~           └──────────┘                                    \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111110011111110000022222222000000000000033333333333333\n02|044444445550044444444550044444444455555555555066666666666666\n03|000000000000077777777880000000000000000000000066666666666666\n04|666666666666000000000000666666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in`-supports--count--002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌…s/common ┐┌ .a-dir ────────────┐                          \n02|│ .a-dir  ││ aa-file           │                          \n03|│ a-dir   ││ ab-file           │                          \n04|│ b-dir   │└────────────────────┘                          \n05|│ .a-file │                                                \n06|│ a-file  │                                                \n07|│ A-file-2│                                                \n08|│ b-file  │                                                \n09|└──────────┘                                                \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111110022222222000000000000033333333333333333333333333\n02|044444444550055555555555555555555066666666666666666666666666\n03|077777778880088888888888888888888066666666666666666666666666\n04|077777778880000000000000000000000066666666666666666666666666\n05|088888888880666666666666666666666666666666666666666666666666\n06|088888888880666666666666666666666666666666666666666666666666\n07|088888888880666666666666666666666666666666666666666666666666\n08|088888888880666666666666666666666666666666666666666666666666\n09|000000000000666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in`-works-in-linewise-Visual-mode",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- VISUAL LINE --                                   2         2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06636666444444444444444444444444444444444444444444405555555555555555555555555555\n04|06666666444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|77777777777777777222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in`-works-in-linewise-Visual-mode-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ b-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ ba-file                                         │           \n03|│ a-dir        │└──────────────────────────────────────────────────┘           \n04|│ b-dir        │                                                               \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550066666666666666666666666666666666666666666666666666077777777777\n03|04444444555555550000000000000000000000000000000000000000000000000000077777777777\n04|08888888666666660777777777777777777777777777777777777777777777777777777777777777\n05|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n06|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n07|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n08|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n09|00000000000000000777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_in`-works-in-linewise-Visual-mode-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ b-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ ba-file                                         │           \n03|│ a-dir        │└──────────────────────────────────────────────────┘           \n04|│ b-dir        │                                                               \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550066666666666666666666666666666666666666666666666666077777777777\n03|04444444555555550000000000000000000000000000000000000000000000000000077777777777\n04|08888888666666660777777777777777777777777777777777777777777777777777777777777777\n05|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n06|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n07|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n08|05555555555555550777777777777777777777777777777777777777777777777777777777777777\n09|00000000000000000777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out_plus`-supports--count-",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|┌…1/dir-11 ┐┌ dir-111 ─┐┌ dir-1111 ──────────┐                        \n02|│ dir-111 ││ dir-1111││ dir-11111         │                        \n03|└──────────┘└──────────┘└────────────────────┘                        \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|                                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0111111111100111111111000222222222200000000000333333333333333333333333\n02|0444444444500444444444400444444444445555555550666666666666666666666666\n03|0000000000000000000000000000000000000000000000666666666666666666666666\n04|6666666666666666666666666666666666666666666666666666666666666666666666\n05|6666666666666666666666666666666666666666666666666666666666666666666666\n06|6666666666666666666666666666666666666666666666666666666666666666666666\n07|6666666666666666666666666666666666666666666666666666666666666666666666\n08|6666666666666666666666666666666666666666666666666666666666666666666666\n09|6666666666666666666666666666666666666666666666666666666666666666666666\n10|3333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out_plus`-supports--count--002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ested/dir-1/dir-11 ┐                                                \n02|│ dir-111           │                                                \n03|└────────────────────┘                                                \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|                                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0111111111111111111110222222222222222222222222222222222222222222222222\n02|0333333333444444444440555555555555555555555555555555555555555555555555\n03|0000000000000000000000555555555555555555555555555555555555555555555555\n04|5555555555555555555555555555555555555555555555555555555555555555555555\n05|5555555555555555555555555555555555555555555555555555555555555555555555\n06|5555555555555555555555555555555555555555555555555555555555555555555555\n07|5555555555555555555555555555555555555555555555555555555555555555555555\n08|5555555555555555555555555555555555555555555555555555555555555555555555\n09|5555555555555555555555555555555555555555555555555555555555555555555555\n10|2222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out_plus`-supports--count--003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐                                                \n02|│ dir-1             │                                                \n03|└────────────────────┘                                                \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|                                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0111111111111111111110222222222222222222222222222222222222222222222222\n02|0333333344444444444440555555555555555555555555555555555555555555555555\n03|0000000000000000000000555555555555555555555555555555555555555555555555\n04|5555555555555555555555555555555555555555555555555555555555555555555555\n05|5555555555555555555555555555555555555555555555555555555555555555555555\n06|5555555555555555555555555555555555555555555555555555555555555555555555\n07|5555555555555555555555555555555555555555555555555555555555555555555555\n08|5555555555555555555555555555555555555555555555555555555555555555555555\n09|5555555555555555555555555555555555555555555555555555555555555555555555\n10|2222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out_plus`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out_plus`-works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out_plus`-works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/a-dir ───────────┐                            \n02|│ aa-dir                                          │                            \n03|│ aa-file                                         │                            \n04|│ ab-file                                         │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111110000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out`-supports--count-",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|┌…1/dir-11 ┐┌ dir-111 ─┐┌ dir-1111 ──────────┐                        \n02|│ dir-111 ││ dir-1111││ dir-11111         │                        \n03|└──────────┘└──────────┘└────────────────────┘                        \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|                                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0111111111100111111111000222222222200000000000333333333333333333333333\n02|0444444444500444444444400444444444445555555550666666666666666666666666\n03|0000000000000000000000000000000000000000000000666666666666666666666666\n04|6666666666666666666666666666666666666666666666666666666666666666666666\n05|6666666666666666666666666666666666666666666666666666666666666666666666\n06|6666666666666666666666666666666666666666666666666666666666666666666666\n07|6666666666666666666666666666666666666666666666666666666666666666666666\n08|6666666666666666666666666666666666666666666666666666666666666666666666\n09|6666666666666666666666666666666666666666666666666666666666666666666666\n10|3333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out`-supports--count--002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ested/dir-1/dir-11 ┐┌ dir-111 ─┐┌ dir-1111 ┐                        \n02|│ dir-111           ││ dir-1111││ dir-1111│                        \n03|└────────────────────┘└──────────┘└──────────┘                        \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|                                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0111111111111111111110022222222200022222222220333333333333333333333333\n02|0444444444555555555550044444444440044444444440666666666666666666666666\n03|0000000000000000000000000000000000000000000000666666666666666666666666\n04|6666666666666666666666666666666666666666666666666666666666666666666666\n05|6666666666666666666666666666666666666666666666666666666666666666666666\n06|6666666666666666666666666666666666666666666666666666666666666666666666\n07|6666666666666666666666666666666666666666666666666666666666666666666666\n08|6666666666666666666666666666666666666666666666666666666666666666666666\n09|6666666666666666666666666666666666666666666666666666666666666666666666\n10|3333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out`-supports--count--003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐┌ dir-1 ───┐┌ dir-11 ──┐┌ dir-111 ─┐┌ dir-1111 ┐\n02|│ dir-1             ││ dir-11  ││ dir-111 ││ dir-1111││ dir-1111│\n03|└────────────────────┘│ dir-12  │└──────────┘└──────────┘└──────────┘\n04|~                     └──────────┘                                    \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|                                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0111111111111111111110022222220000022222222000022222222200022222222220\n02|0333333344444444444440033333333440033333333340033333333330033333333330\n03|0000000000000000000000055555555660000000000000000000000000000000000000\n04|7777777777777777777777000000000000777777777777777777777777777777777777\n05|7777777777777777777777777777777777777777777777777777777777777777777777\n06|7777777777777777777777777777777777777777777777777777777777777777777777\n07|7777777777777777777777777777777777777777777777777777777777777777777777\n08|7777777777777777777777777777777777777777777777777777777777777777777777\n09|7777777777777777777777777777777777777777777777777777777777777777777777\n10|8888888888888888888888888888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`go_out`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ a-dir ────────┐           \n02|│ .a-dir                                          ││ aa-dir       │           \n03|│ a-dir                                           ││ aa-file      │           \n04|│ b-dir                                           ││ ab-file      │           \n05|│ .a-file                                         │└───────────────┘           \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222200000000033333333333\n02|04444444455555555555555555555555555555555555555555500666666667777777088888888888\n03|06666666777777777777777777777777777777777777777777700555555555555555088888888888\n04|04444444555555555555555555555555555555555555555555500555555555555555088888888888\n05|05555555555555555555555555555555555555555555555555500000000000000000088888888888\n06|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n07|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n08|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n09|00000000000000000000000000000000000000000000000000008888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`reset`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`reset`-works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`reset`-works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-dir                                          │           \n03|│ a-dir        ││ aa-file                                         │           \n04|│ b-dir        ││ ab-file                                         │           \n05|│ .a-file      │└──────────────────────────────────────────────────┘           \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550066666666777777777777777777777777777777777777777777088888888888\n03|06666666777777770055555555555555555555555555555555555555555555555555088888888888\n04|04444444555555550055555555555555555555555555555555555555555555555555088888888888\n05|05555555555555550000000000000000000000000000000000000000000000000000088888888888\n06|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n07|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n08|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n09|00000000000000000888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`reveal_cwd`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ────────┐┌ dir-11 ────────────┐                        \n02|│ dir-1        ││ dir-11       ││ dir-111           │                        \n03|└───────────────┘│ dir-12       │└────────────────────┘                        \n04|~                └───────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110011111110000000000222222220000000000000333333333333333333333333\n02|04444444555555550044444444555555500444444444555555555550666666666666666666666666\n03|00000000000000000077777777888888800000000000000000000000666666666666666666666666\n04|66666666666666666000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`reveal_cwd`-works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ────────┐┌ dir-11 ────────────┐                        \n02|│ dir-1        ││ dir-11       ││ dir-111           │                        \n03|└───────────────┘│ dir-12       │└────────────────────┘                        \n04|~                └───────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110011111110000000000222222220000000000000333333333333333333333333\n02|04444444555555550044444444555555500444444444555555555550666666666666666666666666\n03|00000000000000000077777777888888800000000000000000000000666666666666666666666666\n04|66666666666666666000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`reveal_cwd`-works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ested/dir-1/dir-11 ┐                                                          \n02|│ dir-111           │                                                          \n03|└────────────────────┘                                                          \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333334444444444405555555555555555555555555555555555555555555555555555555555\n03|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n04|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`show_help`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ────────────┐                 │        \n03|││Buffer mappings:               │                 │        \n04|││                               │                 │        \n05|││Close                    │ q   │                 │        \n06|││Go in entry              │ l   │                 │        \n07|││Go in entry plus         │ L   │                 │        \n08|││Go out of directory      │ h   │                 │        \n09|└│Go out of directory plus │ H   │─────────────────┘        \n10|~│Go to bookmark           │ '   │                          \n11|~│Reset                    │ <BS>│                          \n12|~│Reveal cwd               │ @   │                          \n13|~│Set bookmark             │ m   │                          \n14|~│Show Help                │ g?  │                          \n15|~│Synchronize              │ =   │                          \n16|~│Trim branch left         │ <   │                          \n17|~│Trim branch right        │ >   │                          \n18|~│                               │                          \n19|~│(Press `q` to close)           │                          \n20|~└───────────────────────────────┘                          \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000044444444444444444055555555\n03|004444444444444444444444444444444066666666666666666055555555\n04|006666666666666666666666666666666066666666666666666055555555\n05|006666666666666666666666666666666066666666666666666055555555\n06|006666666666666666666666666666666066666666666666666055555555\n07|006666666666666666666666666666666066666666666666666055555555\n08|006666666666666666666666666666666066666666666666666055555555\n09|006666666666666666666666666666666000000000000000000055555555\n10|506666666666666666666666666666666055555555555555555555555555\n11|506666666666666666666666666666666055555555555555555555555555\n12|506666666666666666666666666666666055555555555555555555555555\n13|506666666666666666666666666666666055555555555555555555555555\n14|506666666666666666666666666666666055555555555555555555555555\n15|506666666666666666666666666666666055555555555555555555555555\n16|506666666666666666666666666666666055555555555555555555555555\n17|506666666666666666666666666666666055555555555555555555555555\n18|506666666666666666666666666666666055555555555555555555555555\n19|506666666666666666666666666666666055555555555555555555555555\n20|500000000000000000000000000000000055555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`show_help`-works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ────────────┐                 │        \n03|││Buffer mappings:               │                 │        \n04|││                               │                 │        \n05|││Close                    │ q   │                 │        \n06|││Go in entry              │ l   │                 │        \n07|││Go in entry plus         │ L   │                 │        \n08|││Go out of directory      │ h   │                 │        \n09|└│Go out of directory plus │ H   │─────────────────┘        \n10|~│Go to bookmark           │ '   │                          \n11|~│Reset                    │ <BS>│                          \n12|~│Reveal cwd               │ @   │                          \n13|~│Set bookmark             │ m   │                          \n14|~│Show Help                │ Q   │                          \n15|~│Synchronize              │ =   │                          \n16|~│Trim branch left         │ <   │                          \n17|~│Trim branch right        │ >   │                          \n18|~│                               │                          \n19|~│(Press `q` to close)           │                          \n20|~└───────────────────────────────┘                          \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000044444444444444444055555555\n03|004444444444444444444444444444444066666666666666666055555555\n04|006666666666666666666666666666666066666666666666666055555555\n05|006666666666666666666666666666666066666666666666666055555555\n06|006666666666666666666666666666666066666666666666666055555555\n07|006666666666666666666666666666666066666666666666666055555555\n08|006666666666666666666666666666666066666666666666666055555555\n09|006666666666666666666666666666666000000000000000000055555555\n10|506666666666666666666666666666666055555555555555555555555555\n11|506666666666666666666666666666666055555555555555555555555555\n12|506666666666666666666666666666666055555555555555555555555555\n13|506666666666666666666666666666666055555555555555555555555555\n14|506666666666666666666666666666666055555555555555555555555555\n15|506666666666666666666666666666666055555555555555555555555555\n16|506666666666666666666666666666666055555555555555555555555555\n17|506666666666666666666666666666666055555555555555555555555555\n18|506666666666666666666666666666666055555555555555555555555555\n19|506666666666666666666666666666666055555555555555555555555555\n20|500000000000000000000000000000000055555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`show_help`-works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ .a-dir                                          │        \n03|│ a-dir                                           │        \n04|│ b-dir                                           │        \n05|│ .a-file                                         │        \n06|│ a-file                                          │        \n07|│ A-file-2                                        │        \n08|│ b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|~                                                           \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|~                                                           \n20|~                                                           \n21|~                                                           \n22|                                g?        1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|555555555555555555555555555555555555555555555555555555555555\n16|555555555555555555555555555555555555555555555555555555555555\n17|555555555555555555555555555555555555555555555555555555555555\n18|555555555555555555555555555555555555555555555555555555555555\n19|555555555555555555555555555555555555555555555555555555555555\n20|555555555555555555555555555555555555555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`synchronize`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│                                                  │        \n03|└──────────────────────────────────────────────────┘        \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|000000000000000000000000000000000000000000000000000044444444\n04|444444444444444444444444444444444444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`synchronize`-works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ file-1                                          │        \n03|└──────────────────────────────────────────────────┘        \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|000000000000000000000000000000000000000000000000000044444444\n04|444444444444444444444444444444444444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`synchronize`-works-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ file-1                                          │        \n03|└──────────────────────────────────────────────────┘        \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|000000000000000000000000000000000000000000000000000044444444\n04|444444444444444444444444444444444444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`synchronize`-works-004",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ file-1                                          │        \n03|│ file-2                                          │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`synchronize`-works-005",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ file-1                                          │        \n03|│ file-2                                          │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`synchronize`-works-006",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ file-1                                          │        \n03|│ file-2                                          │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                =         1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`trim_left`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/.a-dir ──────────┐                            \n02|│ aa-file                                         │                            \n03|│ ab-file                                         │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111111000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Mappings---`trim_right`-works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---always-updates-with-cursor",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|------\n01|┌MOCK_ROOT/tests/dir-files/common/.a-dir ──────────┐┌ ab-file ────────────────┐       \n02|│ aa-file                                         ││                         │       \n03|│ ab-file                                         │└─────────────────────────┘       \n04|└──────────────────────────────────────────────────┘                                  \n05|~                                                                                     \n06|~                                                                                     \n07|~                                                                                     \n08|~                                                                                     \n09|~                                                                                     \n10|                                                                    2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|------\n01|01111111111111111111111111111111111111111000000000000222222222000000000000000003333333\n02|04444444444444444444444444444444444444444444444444400444444444444444444444444405555555\n03|06666666666666666666666666666666666666666666666666600000000000000000000000000005555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---can-work-after-renaming-with-small-overall-width",
    "content": "--|---------|---------|---------|---------|---------|----\n01|┌…r/nested ┐┌ nested-2 ──────────┐┌ file ─────────┐   \n02|│ nested-2││ new-file          ││               │   \n03|└──────────┘└────────────────────┘└───────────────┘   \n04|~                                                     \n05|~                                                     \n06|~                                                     \n07|~                                                     \n08|~                                                     \n09|~                                                     \n10|                                    1,16-14       All \n\n--|---------|---------|---------|---------|---------|----\n01|011111111110233333333332222222222201111110000000000444\n02|055555555550266666666666666666666207777777777777770888\n03|000000000000222222222222222222222200000000000000000888\n04|888888888888888888888888888888888888888888888888888888\n05|888888888888888888888888888888888888888888888888888888\n06|888888888888888888888888888888888888888888888888888888\n07|888888888888888888888888888888888888888888888888888888\n08|888888888888888888888888888888888888888888888888888888\n09|888888888888888888888888888888888888888888888888888888\n10|444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---can-work-after-renaming-with-small-overall-width-002",
    "content": "--|---------|---------|---------|---------|---------|----\n01|┌…r/nested ┐┌ nested-2 ──────────┐┌ new-file ─────┐   \n02|│ nested-2││ new-file          ││               │   \n03|└──────────┘└────────────────────┘└───────────────┘   \n04|~                                                     \n05|~                                                     \n06|~                                                     \n07|~                                                     \n08|~                                                     \n09|~                                                     \n10|                                    1,9-7         All \n\n--|---------|---------|---------|---------|---------|----\n01|011111111110022222222220000000000001111111111000000333\n02|044444444440055555555555555555555006666666666666660777\n03|000000000000000000000000000000000000000000000000000777\n04|777777777777777777777777777777777777777777777777777777\n05|777777777777777777777777777777777777777777777777777777\n06|777777777777777777777777777777777777777777777777777777\n07|777777777777777777777777777777777777777777777777777777\n08|777777777777777777777777777777777777777777777777777777\n09|777777777777777777777777777777777777777777777777777777\n10|333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---does-not-highlight-big-files",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OCK_ROOT/tests/dir-files ┐┌ big.lua ────────────────┐                          \n02|│ common                 ││local a = \"aaaaaaaaaaaaaa│                          \n03|│ lua                    │└─────────────────────────┘                          \n04|│ nested                 │                                                     \n05|│ real                   │                                                     \n06|│ big.lua                │                                                     \n07|│ init-default-explorer.l│                                                     \n08|│ mock-win-functions.lua │                                                     \n09|└─────────────────────────┘                                                     \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              5,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222220000000000000000033333333333333333333333333\n02|04444444455555555555555555005555555555555555555555555066666666666666666666666666\n03|04444455555555555555555555000000000000000000000000000066666666666666666666666666\n04|04444444455555555555555555066666666666666666666666666666666666666666666666666666\n05|04444445555555555555555555066666666666666666666666666666666666666666666666666666\n06|07777777777777777777777777066666666666666666666666666666666666666666666666666666\n07|05555555555555555555555555066666666666666666666666666666666666666666666666666666\n08|05555555555555555555555555066666666666666666666666666666666666666666666666666666\n09|00000000000000000000000000066666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---is-not-removed-when-going-out",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ────────┐┌ aa-dir ───────┐                             \n02|│ .a-dir       ││ aa-dir       ││ aaa-file     │                             \n03|│ a-dir        ││ aa-file      │└───────────────┘                             \n04|│ b-dir        ││ ab-file      │                                              \n05|│ .a-file      │└───────────────┘                                              \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000222222220000000033333333333333333333333333333\n02|04444444455555550066666666777777700777777777777777088888888888888888888888888888\n03|06666666777777770055555555555555500000000000000000088888888888888888888888888888\n04|04444444555555550055555555555555508888888888888888888888888888888888888888888888\n05|05555555555555550000000000000000008888888888888888888888888888888888888888888888\n06|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n07|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n08|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n09|00000000000000000888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---is-not-removed-when-going-out-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ────────┐┌ aa-dir ───────┐┌ aaa-file ─────┐            \n02|│ .a-dir       ││ aa-dir       ││ aaa-file     ││               │            \n03|│ a-dir        ││ aa-file      │└───────────────┘└───────────────┘            \n04|│ b-dir        ││ ab-file      │                                              \n05|│ .a-file      │└───────────────┘                                              \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000222222220000000002222222222000000333333333333\n02|04444444455555550066666666777777700777777777777777005555555555555550888888888888\n03|06666666777777770055555555555555500000000000000000000000000000000000888888888888\n04|04444444555555550055555555555555508888888888888888888888888888888888888888888888\n05|05555555555555550000000000000000008888888888888888888888888888888888888888888888\n06|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n07|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n08|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n09|00000000000000000888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---is-not-shown-if-not-enough-space",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ .a-dir                                          │        \n03|│ a-dir                                           │        \n04|│ b-dir                                           │        \n05|│ .a-file                                         │        \n06|│ a-file                                          │        \n07|│ A-file-2                                        │        \n08|│ b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---previews-only-one-level-deep",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌T/tests/dir-files/nested ┐┌ dir-1 ──────────────────┐                          \n02|│ dir-1                  ││ dir-11                 │                          \n03|└─────────────────────────┘│ dir-12                 │                          \n04|~                          └─────────────────────────┘                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222000000000000000000033333333333333333333333333\n02|04444444555555555555555555004444444455555555555555555066666666666666666666666666\n03|00000000000000000000000000007777777788888888888888888066666666666666666666666666\n04|66666666666666666666666666600000000000000000000000000066666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…les/temp ┐┌…y-name ┐                                                          \n02|│ long-di>││ subfi>│                                                          \n03|│ file    │└────────┘                                                          \n04|└──────────┘                                                                    \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222203333333333333333333333333333333333333333333333333333333333\n02|04444444445006666666507777777777777777777777777777777777777777777777777777777777\n03|08888888888000000000007777777777777777777777777777777777777777777777777777777777\n04|00000000000077777777777777777777777777777777777777777777777777777777777777777777\n05|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n06|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n07|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…les/temp ┐┌ file ──┐                                                          \n02|│ long-di>││+   Tabs│                                                          \n03|│ file    ││    Spa>│                                                          \n04|└──────────┘└────────┘                                                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222220003333333333333333333333333333333333333333333333333333333333\n02|04444444445005555666607777777777777777777777777777777777777777777777777777777777\n03|08888888888006666666507777777777777777777777777777777777777777777777777777777777\n04|00000000000000000000007777777777777777777777777777777777777777777777777777777777\n05|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n06|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n07|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…les/temp ┐┌ file ──┐                                                          \n02|│ long-dir││    Tabs│                                                          \n03|│ file    ││    Spac│                                                          \n04|└──────────┘└────────┘                                                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222220003333333333333333333333333333333333333333333333333333333333\n02|04444444444005555555506666666666666666666666666666666666666666666666666666666666\n03|07777777777005555555506666666666666666666666666666666666666666666666666666666666\n04|00000000000000000000006666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…les/temp ┐┌ file ──┐                                                          \n02|│ long-dir││    Tabs│                                                          \n03|│ file    ││    Spac│                                                          \n04|└──────────┘└────────┘                                                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222220003333333333333333333333333333333333333333333333333333333333\n02|04444444444005555555506666666666666666666666666666666666666666666666666666666666\n03|07777777777005555555506666666666666666666666666666666666666666666666666666666666\n04|00000000000000000000006666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-after-`trim_left()`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…/dir-files/nested/dir-1 ┐┌ dir-12 ─────────────────┐                          \n02|│ dir-11                 ││ file-121               │                          \n03|│ dir-12                 │└─────────────────────────┘                          \n04|└─────────────────────────┘                                                     \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222200000000000000000033333333333333333333333333\n02|04444444455555555555555555006666666666666666666666666077777777777777777777777777\n03|08888888866666666666666666000000000000000000000000000077777777777777777777777777\n04|00000000000000000000000000077777777777777777777777777777777777777777777777777777\n05|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n06|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n07|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-directories",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌T/tests/dir-files/common ┐┌ .a-dir ─────────────────┐                          \n02|│ .a-dir                 ││ aa-file                │                          \n03|│ a-dir                  ││ ab-file                │                          \n04|│ b-dir                  │└─────────────────────────┘                          \n05|│ .a-file                │                                                     \n06|│ a-file                 │                                                     \n07|│ A-file-2               │                                                     \n08|│ b-file                 │                                                     \n09|└─────────────────────────┘                                                     \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222200000000000000000033333333333333333333333333\n02|04444444455555555555555555005555555555555555555555555066666666666666666666666666\n03|07777777888888888888888888008888888888888888888888888066666666666666666666666666\n04|07777777888888888888888888000000000000000000000000000066666666666666666666666666\n05|08888888888888888888888888066666666666666666666666666666666666666666666666666666\n06|08888888888888888888888888066666666666666666666666666666666666666666666666666666\n07|08888888888888888888888888066666666666666666666666666666666666666666666666666666\n08|08888888888888888888888888066666666666666666666666666666666666666666666666666666\n09|00000000000000000000000000066666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-directories-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌T/tests/dir-files/common ┐┌ a-dir ──────────────────┐                          \n02|│ .a-dir                 ││ aa-dir                 │                          \n03|│ a-dir                  ││ aa-file                │                          \n04|│ b-dir                  ││ ab-file                │                          \n05|│ .a-file                │└─────────────────────────┘                          \n06|│ a-file                 │                                                     \n07|│ A-file-2               │                                                     \n08|│ b-file                 │                                                     \n09|└─────────────────────────┘                                                     \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222000000000000000000033333333333333333333333333\n02|04444444455555555555555555006666666677777777777777777088888888888888888888888888\n03|06666666777777777777777777005555555555555555555555555088888888888888888888888888\n04|04444444555555555555555555005555555555555555555555555088888888888888888888888888\n05|05555555555555555555555555000000000000000000000000000088888888888888888888888888\n06|05555555555555555555555555088888888888888888888888888888888888888888888888888888\n07|05555555555555555555555555088888888888888888888888888888888888888888888888888888\n08|05555555555555555555555555088888888888888888888888888888888888888888888888888888\n09|00000000000000000000000000088888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-directories-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ──────────────────┐┌ aa-dir ─────────────────┐         \n02|│ .a-dir       ││ aa-dir                 ││ aaa-file               │         \n03|│ a-dir        ││ aa-file                │└─────────────────────────┘         \n04|│ b-dir        ││ ab-file                │                                    \n05|│ .a-file      │└─────────────────────────┘                                    \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000011111111000000000000000000333333333\n02|04444444455555550066666666777777777777777770077777777777777777777777770888888888\n03|06666666777777770055555555555555555555555550000000000000000000000000000888888888\n04|04444444555555550055555555555555555555555550888888888888888888888888888888888888\n05|05555555555555550000000000000000000000000000888888888888888888888888888888888888\n06|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n07|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n08|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n09|00000000000000000888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-files",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/real ┐┌ a.lua ──────────────────┐                          \n02|│ a.lua                  ││local a = 1              │                          \n03|│ b.txt                  ││local t = {              │                          \n04|│ c.gif                  ││  x = math.max(1, 2),    │                          \n05|│ LICENSE                ││  y = math.min(1, 2),    │                          \n06|│ Makefile               ││}                        │                          \n07|│ top-secret             │└─────────────────────────┘                          \n08|└─────────────────────────┘                                                     \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222000000000000000000033333333333333333333333333\n02|04444444444444444444444444001111155555655555555555555077777777777777777777777777\n03|05555555555555555555555555001111155555855555555555555077777777777777777777777777\n04|05555555555555555555555555005595558888:;;;:6:56::5555077777777777777777777777777\n05|05555555555555555555555555005595558888:;;;:6:56::5555077777777777777777777777777\n06|05555555555555555555555555008555555555555555555555555077777777777777777777777777\n07|05555555555555555555555555000000000000000000000000000077777777777777777777777777\n08|00000000000000000000000000077777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-files-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/real ┐┌ b.txt ──────────────────┐                          \n02|│ a.lua                  ││Line 1                   │                          \n03|│ b.txt                  ││Line 2                   │                          \n04|│ c.gif                  ││Line 3                   │                          \n05|│ LICENSE                ││Line 4                   │                          \n06|│ Makefile               ││Line 5                   │                          \n07|│ top-secret             ││Line 6                   │                          \n08|└─────────────────────────┘│Line 7                   │                          \n09|~                          │Line 8                   │                          \n10|~                          │Line 9                   │                          \n11|~                          │Line 10                  │                          \n12|~                          │Line 11                  │                          \n13|~                          │Line 12                  │                          \n14|~                          └─────────────────────────┘                          \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222000000000000000000033333333333333333333333333\n02|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n03|06666666666666666666666666004444444444444444444444444055555555555555555555555555\n04|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n05|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n06|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n07|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n08|00000000000000000000000000004444444444444444444444444055555555555555555555555555\n09|55555555555555555555555555504444444444444444444444444055555555555555555555555555\n10|55555555555555555555555555504444444444444444444444444055555555555555555555555555\n11|55555555555555555555555555504444444444444444444444444055555555555555555555555555\n12|55555555555555555555555555504444444444444444444444444055555555555555555555555555\n13|55555555555555555555555555504444444444444444444444444055555555555555555555555555\n14|55555555555555555555555555500000000000000000000000000055555555555555555555555555\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-files-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/real ┐┌ c.gif ──────────────────┐                          \n02|│ a.lua                  ││-Non-text-file-----------│                          \n03|│ b.txt                  │└─────────────────────────┘                          \n04|│ c.gif                  │                                                     \n05|│ LICENSE                │                                                     \n06|│ Makefile               │                                                     \n07|│ top-secret             │                                                     \n08|└─────────────────────────┘                                                     \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222000000000000000000033333333333333333333333333\n02|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n03|04444444444444444444444444000000000000000000000000000055555555555555555555555555\n04|06666666666666666666666666055555555555555555555555555555555555555555555555555555\n05|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n06|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n07|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n08|00000000000000000000000000055555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-files-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/real ┐┌ LICENSE ────────────────┐                          \n02|│ a.lua                  ││                         │                          \n03|│ b.txt                  │└─────────────────────────┘                          \n04|│ c.gif                  │                                                     \n05|│ LICENSE                │                                                     \n06|│ Makefile               │                                                     \n07|│ top-secret             │                                                     \n08|└─────────────────────────┘                                                     \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              4,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222220000000000000000033333333333333333333333333\n02|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n03|04444444444444444444444444000000000000000000000000000055555555555555555555555555\n04|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n05|06666666666666666666666666055555555555555555555555555555555555555555555555555555\n06|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n07|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n08|00000000000000000000000000055555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-files-005",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/real ┐┌ Makefile ───────────────┐                          \n02|│ a.lua                  ││VAR ?= 1                 │                          \n03|│ b.txt                  ││                         │                          \n04|│ c.gif                  ││all: test                │                          \n05|│ LICENSE                │└─────────────────────────┘                          \n06|│ Makefile               │                                                     \n07|│ top-secret             │                                                     \n08|└─────────────────────────┘                                                     \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              5,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222222000000000000000033333333333333333333333333\n02|04444444444444444444444444005555444444444444444444444066666666666666666666666666\n03|04444444444444444444444444004444444444444444444444444066666666666666666666666666\n04|04444444444444444444444444007777444444444444444444444066666666666666666666666666\n05|04444444444444444444444444000000000000000000000000000066666666666666666666666666\n06|08888888888888888888888888066666666666666666666666666666666666666666666666666666\n07|04444444444444444444444444066666666666666666666666666666666666666666666666666666\n08|00000000000000000000000000066666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-for-files-006",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/real ┐┌ top-secret ─────────────┐                          \n02|│ a.lua                  ││-No-access---------------│                          \n03|│ b.txt                  │└─────────────────────────┘                          \n04|│ c.gif                  │                                                     \n05|│ LICENSE                │                                                     \n06|│ Makefile               │                                                     \n07|│ top-secret             │                                                     \n08|└─────────────────────────┘                                                     \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              6,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111002222222222220000000000000033333333333333333333333333\n02|04444444444444444444444444004444444444444444444444444055555555555555555555555555\n03|04444444444444444444444444000000000000000000000000000055555555555555555555555555\n04|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n05|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n06|04444444444444444444444444055555555555555555555555555555555555555555555555555555\n07|06666666666666666666666666055555555555555555555555555555555555555555555555555555\n08|00000000000000000000000000055555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌  ───────────────────────┐      \n02|│                         ││-No-fs-entry-------------│      \n03|└─────────────────────────┘└─────────────────────────┘      \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110022000000000000000000000000333333\n02|044444444444444444444444440055555555555555555555555550666666\n03|000000000000000000000000000000000000000000000000000000666666\n04|666666666666666666666666666666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌  ───────────────────────┐      \n02|│                         ││-No-fs-entry-------------│      \n03|│                         │└─────────────────────────┘      \n04|└─────────────────────────┘                                 \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|-- INSERT --                              2,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110233222222222222222222222222444444\n02|055555555555555555555555550255555555555555555555555552666666\n03|077777777777777777777777770222222222222222222222222222666666\n04|000000000000000000000000000666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|888888888888444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌ n ──────────────────────┐      \n02|│                         ││-No-fs-entry-------------│      \n03|│n                        │└─────────────────────────┘      \n04|└─────────────────────────┘                                 \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|-- INSERT --                              2,2           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110233322222222222222222222222444444\n02|055555555555555555555555550255555555555555555555555552666666\n03|077777777777777777777777770222222222222222222222222222666666\n04|000000000000000000000000000666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|888888888888444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-004",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌ ne ─────────────────────┐      \n02|│                         ││-No-fs-entry-------------│      \n03|│ne                       │└─────────────────────────┘      \n04|└─────────────────────────┘                                 \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|-- INSERT --                              2,3           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110233332222222222222222222222444444\n02|055555555555555555555555550255555555555555555555555552666666\n03|077777777777777777777777770222222222222222222222222222666666\n04|000000000000000000000000000666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|888888888888444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-005",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌ ne ─────────────────────┐      \n02|│                         ││-No-fs-entry-------------│      \n03|│new/                     │└─────────────────────────┘      \n04|│ne                       │                                 \n05| new            ──────────┘                                 \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|-- Keyword completion (^N^P) Back at original               \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110233332222222222222222222222444444\n02|055555555555555555555555550255555555555555555555555552666666\n03|055555555555555555555555550222222222222222222222222222666666\n04|077777777777777777777777770666666666666666666666666666666666\n05|777777777777777700000000000666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|888888888888888888888888888889999999999999999444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-006",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌   ──────────────────────┐      \n02|│                         ││-No-fs-entry-------------│      \n03|│new/                     │└─────────────────────────┘      \n04|│ne                       │                                 \n05|│                         │                                 \n06|└─────────────────────────┘                                 \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|-- INSERT --                              4,2           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110233322222222222222222222222444444\n02|055555555555555555555555550255555555555555555555555552666666\n03|055555555555555555555555550222222222222222222222222222666666\n04|055555555555555555555555550666666666666666666666666666666666\n05|077777777777777777777777770666666666666666666666666666666666\n06|000000000000000000000000000666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|888888888888444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-007",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌ new ────────────────────┐      \n02|│ new                    ││                         │      \n03|│ ne                     │└─────────────────────────┘      \n04|└─────────────────────────┘                                 \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110022222000000000000000000000333333\n02|044444555555555555555555550055555555555555555555555550666666\n03|077777777777777777777777770000000000000000000000000000666666\n04|000000000000000000000000000666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Preview---works-with-imaginary-paths-008",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OOT/tests/dir-files/temp ┐┌ ne ─────────────────────┐      \n02|│ new                    ││                         │      \n03|│ ne                     │└─────────────────────────┘      \n04|└─────────────────────────┘                                 \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111110022220000000000000000000000333333\n02|044444555555555555555555550055555555555555555555555550666666\n03|077777777777777777777777770000000000000000000000000000666666\n04|000000000000000000000000000666666666666666666666666666666666\n05|666666666666666666666666666666666666666666666666666666666666\n06|666666666666666666666666666666666666666666666666666666666666\n07|666666666666666666666666666666666666666666666666666666666666\n08|666666666666666666666666666666666666666666666666666666666666\n09|666666666666666666666666666666666666666666666666666666666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---always-show-cursor-line-in-directories",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ .a-dir ─────────────────┐ \n02|│ .a-dir                                          ││ aa-file                │ \n03|│ a-dir                                           ││ ab-file                │ \n04|│ b-dir                                           │└─────────────────────────┘ \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222220000000000000000003\n02|04444444455555555555555555555555555555555555555555500555555555555555555555555506\n03|07777777888888888888888888888888888888888888888888800888888888888888888888888806\n04|07777777888888888888888888888888888888888888888888800000000000000000000000000006\n05|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n06|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n07|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n08|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---always-show-cursor-line-in-directories-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ b-file ─────────────────┐ \n02|│ .a-dir                                          ││b-file                   │ \n03|│ a-dir                                           ││Another line             │ \n04|│ b-dir                                           │└─────────────────────────┘ \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              7,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222220000000000000000003\n02|04444444455555555555555555555555555555555555555555500555555555555555555555555506\n03|04444444555555555555555555555555555555555555555555500555555555555555555555555506\n04|04444444555555555555555555555555555555555555555555500000000000000000000000000006\n05|05555555555555555555555555555555555555555555555555506666666666666666666666666666\n06|05555555555555555555555555555555555555555555555555506666666666666666666666666666\n07|05555555555555555555555555555555555555555555555555506666666666666666666666666666\n08|07777777777777777777777777777777777777777777777777706666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ed/dir-1 ┐┌ dir-11 ──┐┌ dir-111 ─┐┌ dir-1111 ┐┌ dir-11111 ─────────┐          \n02|│ dir-11  ││ dir-111 ││ dir-1111││ dir-1111││ file-111111       │          \n03|│ dir-12  │└──────────┘└──────────┘└──────────┘└────────────────────┘          \n04|└──────────┘                                                                    \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111001111111100001111111110001111111111002222222222200000000003333333333\n02|04444444455004444444445004444444444004444444444005555555555555555555506666666666\n03|07777777788000000000000000000000000000000000000000000000000000000000006666666666\n04|00000000000066666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ed/dir-1 ┐┌ dir-11 ──┐┌ dir-111 ─┐┌ dir-1111 ──────────┐┌…ir-11111 ┐          \n02|│ dir-11  ││ dir-111 ││ dir-1111││ dir-11111         ││ file-111│          \n03|│ dir-12  │└──────────┘└──────────┘└────────────────────┘└──────────┘          \n04|└──────────┘                                                                    \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111001111111100001111111110002222222222000000000000111111111103333333333\n02|04444444455004444444445004444444444004444444444455555555500555555555506666666666\n03|07777777788000000000000000000000000000000000000000000000000000000000006666666666\n04|00000000000066666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ed/dir-1 ┐┌ dir-11 ──┐┌ dir-111 ───────────┐┌ dir-1111 ┐┌…ir-11111 ┐          \n02|│ dir-11  ││ dir-111 ││ dir-1111          ││ dir-1111││ file-111│          \n03|│ dir-12  │└──────────┘└────────────────────┘└──────────┘└──────────┘          \n04|└──────────┘                                                                    \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111001111111100002222222220000000000000111111111100111111111103333333333\n02|04444444455004444444445004444444444555555555500444444444400555555555506666666666\n03|07777777788000000000000000000000000000000000000000000000000000000000006666666666\n04|00000000000066666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ───┐┌ dir-11 ────────────┐┌ dir-111 ─┐┌ dir-1111 ┐          \n02|│ dir-1   ││ dir-11  ││ dir-111           ││ dir-1111││ dir-1111│          \n03|└──────────┘│ dir-12  │└────────────────────┘└──────────┘└──────────┘          \n04|~           └──────────┘                                                        \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111001111111000002222222200000000000000111111111000111111111103333333333\n02|04444444555004444444455004444444445555555555500444444444400444444444406666666666\n03|00000000000007777777788000000000000000000000000000000000000000000000006666666666\n04|66666666666600000000000066666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show-005",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ─────────────┐┌ dir-11 ──┐┌ dir-111 ─┐┌ dir-1111 ┐          \n02|│ dir-1   ││ dir-11            ││ dir-111 ││ dir-1111││ dir-1111│          \n03|└──────────┘│ dir-12            │└──────────┘└──────────┘└──────────┘          \n04|~           └────────────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222000000000000000111111110000111111111000111111111103333333333\n02|04444444555004444444455555555555500444444444500444444444400444444444406666666666\n03|00000000000007777777788888888888800000000000000000000000000000000000006666666666\n04|66666666666600000000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show-006",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐┌ dir-1 ───┐┌ dir-11 ──┐┌ dir-111 ─┐┌ dir-1111 ┐          \n02|│ dir-1             ││ dir-11  ││ dir-111 ││ dir-1111││ dir-1111│          \n03|└────────────────────┘│ dir-12  │└──────────┘└──────────┘└──────────┘          \n04|~                     └──────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222200000222222220000222222222000222222222203333333333\n02|04444444555555555555500444444445500444444444500444444444400444444444406666666666\n03|00000000000000000000000777777778800000000000000000000000000000000000006666666666\n04|66666666666666666666660000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-computes-part-of-branch-to-show-with-preview",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/.a-dir ──────────┐┌ aa-file ───────────┐      \n02|│ aa-file                                         ││                    │      \n03|│ ab-file                                         │└────────────────────┘      \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111111000000000000222222222000000000000333333\n02|04444444444444444444444444444444444444444444444444400555555555555555555550666666\n03|05555555555555555555555555555555555555555555555555500000000000000000000000666666\n04|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---correctly-highlight-content-during-editing",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ new-dir                                         │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              7,14-12       All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333334444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---does-not-wrap-content",
    "content": "--|---------|---------|\n01|┌…les/temp ┐        \n02|│ a a a a │        \n03|│ file    │        \n04|└──────────┘        \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|          1,9-7 All \n\n--|---------|---------|\n01|01111111111022222222\n02|03333333333044444444\n03|05555555555044444444\n04|00000000000044444444\n05|44444444444444444444\n06|44444444444444444444\n07|44444444444444444444\n08|44444444444444444444\n09|44444444444444444444\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---is-in-sync-with-cursor",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ───┐┌ dir-11 ────────────┐┌ dir-111 ─┐                      \n02|│ dir-1   ││ dir-11  ││ dir-111           ││ dir-1111│                      \n03|└──────────┘│ dir-12  │└────────────────────┘└──────────┘                      \n04|~           └──────────┘                                                        \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111001111111000002222222200000000000000111111111003333333333333333333333\n02|04444444555004444444455004444444445555555555500444444444406666666666666666666666\n03|00000000000007777777788000000000000000000000000000000000006666666666666666666666\n04|66666666666600000000000066666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---is-in-sync-with-cursor-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ─────────────┐┌ dir-11 ──┐┌ dir-111 ─┐                      \n02|│ dir-1   ││ dir-11            ││ dir-111 ││ dir-1111│                      \n03|└──────────┘│ dir-12            │└──────────┘└──────────┘                      \n04|~           └────────────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222000000000000000111111110000111111111003333333333333333333333\n02|04444444555004444444455555555555500444444444500444444444406666666666666666666666\n03|00000000000007777777788888888888800000000000000000000000006666666666666666666666\n04|66666666666600000000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---is-in-sync-with-cursor-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ─────────────┐                                              \n02|│ dir-1   ││ dir-11            │                                              \n03|└──────────┘│ dir-12            │                                              \n04|~           └────────────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222000000000000003333333333333333333333333333333333333333333333\n02|04444444555006666666677777777777708888888888888888888888888888888888888888888888\n03|00000000000004444444455555555555508888888888888888888888888888888888888888888888\n04|88888888888800000000000000000000008888888888888888888888888888888888888888888888\n05|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n06|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n07|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n08|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n09|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---is-in-sync-with-cursor-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐┌ dir-1 ───┐                                              \n02|│ dir-1             ││ dir-11  │                                              \n03|└────────────────────┘│ dir-12  │                                              \n04|~                     └──────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222200003333333333333333333333333333333333333333333333\n02|04444444555555555555500666666667708888888888888888888888888888888888888888888888\n03|00000000000000000000000444444445508888888888888888888888888888888888888888888888\n04|88888888888888888888880000000000008888888888888888888888888888888888888888888888\n05|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n06|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n07|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n08|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n09|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---is-in-sync-with-cursor-005",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐                                                          \n02|│ dir-1             │                                                          \n03|│                    │                                                          \n04|└────────────────────┘                                                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- INSERT --                                                  2,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333444444444444405555555555555555555555555555555555555555555555555555555555\n03|06666666666666666666605555555555555555555555555555555555555555555555555555555555\n04|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|77777777777722222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---never-shows-past-end-of-buffer",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|│                                                  │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|-- INSERT --                                                  8,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n10|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|77777777777722222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---never-shows-past-end-of-buffer-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|│ .a-dir                                          │                            \n10|│ a-dir                                           │                            \n11|└──────────────────────────────────────────────────┘                            \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              8,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n10|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n11|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---never-shows-past-end-of-buffer-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ a-dir                                           │        \n03|│ b-dir                                           │        \n04|│ .a-file                                         │        \n05|│ a-file                                          │        \n06|│ A-file-2                                        │        \n07|│ b-file                                          │        \n08|│ .a-dir                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|                                          8,9-7         50% \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333334444444444444444444444444444444444444444444055555555\n03|033333334444444444444444444444444444444444444444444055555555\n04|044444444444444444444444444444444444444444444444444055555555\n05|044444444444444444444444444444444444444444444444444055555555\n06|044444444444444444444444444444444444444444444444444055555555\n07|044444444444444444444444444444444444444444444444444055555555\n08|066666666666666666666666666666666666666666666666666055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---reacts-on-`VimResized`",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/.a-dir ──────────┐        \n02|│ aa-file                                         │        \n03|│ ab-file                                         │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111111111110000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|444444444444444444444444444444444444444444444444444444444444\n11|444444444444444444444444444444444444444444444444444444444444\n12|444444444444444444444444444444444444444444444444444444444444\n13|444444444444444444444444444444444444444444444444444444444444\n14|444444444444444444444444444444444444444444444444444444444444\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---reacts-on-`VimResized`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---reacts-on-`VimResized`-003",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|---------|\n1|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n2|│ .a-dir       ││ aa-file                                         │           \n3|│ a-dir        ││ ab-file                                         │           \n4|│ b-dir        │└──────────────────────────────────────────────────┘           \n5|│ .a-file      │                                                               \n6|│ a-file       │                                                               \n7|└───────────────┘                                                               \n8|                                                              1,9-7         All \n\n-|---------|---------|---------|---------|---------|---------|---------|---------|\n1|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n2|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n3|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n4|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n5|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n6|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n7|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n8|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---reacts-on-`VimResized`-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respect-'winborder'-option",
    "content": "--|---------|---------|---------|---------|\n01|╭MOCK_ROOT/tests/dir-files/common ─────╮\n02|│ .a-dir                              │\n03|│ a-dir                               │\n04|│ b-dir                               │\n05|│ .a-file                             │\n06|│ a-file                              │\n07|│ A-file-2                            │\n08|│ b-file                              │\n09|╰──────────────────────────────────────╯\n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                      1,9-7         All \n\n--|---------|---------|---------|---------|\n01|0111111111111111111111111111111111000000\n02|0222222223333333333333333333333333333330\n03|0444444455555555555555555555555555555550\n04|0444444455555555555555555555555555555550\n05|0555555555555555555555555555555555555550\n06|0555555555555555555555555555555555555550\n07|0555555555555555555555555555555555555550\n08|0555555555555555555555555555555555555550\n09|0000000000000000000000000000000000000000\n10|6666666666666666666666666666666666666666\n11|6666666666666666666666666666666666666666\n12|6666666666666666666666666666666666666666\n13|6666666666666666666666666666666666666666\n14|6666666666666666666666666666666666666666\n15|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respect-'winborder'-option-002",
    "content": "--|---------|---------|---------|---------|\n01|╔MOCK_ROOT/tests/dir-files/common ═════╗\n02|║ .a-dir                              ║\n03|║ a-dir                               ║\n04|║ b-dir                               ║\n05|║ .a-file                             ║\n06|║ a-file                              ║\n07|║ A-file-2                            ║\n08|║ b-file                              ║\n09|╚══════════════════════════════════════╝\n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                      1,9-7         All \n\n--|---------|---------|---------|---------|\n01|0111111111111111111111111111111111000000\n02|0222222223333333333333333333333333333330\n03|0444444455555555555555555555555555555550\n04|0444444455555555555555555555555555555550\n05|0555555555555555555555555555555555555550\n06|0555555555555555555555555555555555555550\n07|0555555555555555555555555555555555555550\n08|0555555555555555555555555555555555555550\n09|0000000000000000000000000000000000000000\n10|6666666666666666666666666666666666666666\n11|6666666666666666666666666666666666666666\n12|6666666666666666666666666666666666666666\n13|6666666666666666666666666666666666666666\n14|6666666666666666666666666666666666666666\n15|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respect-'winborder'-option-003",
    "content": "--|---------|---------|---------|---------|\n01|+MOCK_ROOT/tests/dir-files/common -----+\n02|| .a-dir                              |\n03|| a-dir                               |\n04|| b-dir                               |\n05|| .a-file                             |\n06|| a-file                              |\n07|| A-file-2                            |\n08|| b-file                              |\n09|+--------------------------------------+\n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                      1,9-7         All \n\n--|---------|---------|---------|---------|\n01|0111111111111111111111111111111111000000\n02|0222222223333333333333333333333333333330\n03|0444444455555555555555555555555555555550\n04|0444444455555555555555555555555555555550\n05|0555555555555555555555555555555555555550\n06|0555555555555555555555555555555555555550\n07|0555555555555555555555555555555555555550\n08|0555555555555555555555555555555555555550\n09|0000000000000000000000000000000000000000\n10|6666666666666666666666666666666666666666\n11|6666666666666666666666666666666666666666\n12|6666666666666666666666666666666666666666\n13|6666666666666666666666666666666666666666\n14|6666666666666666666666666666666666666666\n15|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respects-tabline-and-statusline-when-computing-height",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|My tabline                                                  \n2|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n3|│ .a-dir                                          │        \n4|│ a-dir                                           │        \n5|│ b-dir                                           │        \n6|└──────────────────────────────────────────────────┘        \n7|My statusline                                               \n8|                                          1,9-7         Top \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000011111111111111111111111111111111111111111111111111\n2|022222222222222222222222222222222200000000000000000033333333\n3|044444444555555555555555555555555555555555555555555066666666\n4|077777778888888888888888888888888888888888888888888066666666\n5|077777778888888888888888888888888888888888888888888066666666\n6|000000000000000000000000000000000000000000000000000066666666\n7|111111111111111111111111111111111111111111111111111111111111\n8|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respects-tabline-and-statusline-when-computing-height-002",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n2|│ .a-dir                                          │        \n3|│ a-dir                                           │        \n4|│ b-dir                                           │        \n5|│ .a-file                                         │        \n6|└──────────────────────────────────────────────────┘        \n7|My statusline                                               \n8|                                          1,9-7         Top \n\n-|---------|---------|---------|---------|---------|---------|\n1|011111111111111111111111111111111100000000000000000022222222\n2|033333333444444444444444444444444444444444444444444055555555\n3|066666667777777777777777777777777777777777777777777055555555\n4|066666667777777777777777777777777777777777777777777055555555\n5|077777777777777777777777777777777777777777777777777055555555\n6|000000000000000000000000000000000000000000000000000055555555\n7|888888888888888888888888888888888888888888888888888888888888\n8|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respects-tabline-and-statusline-when-computing-height-003",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|My tabline                                                  \n2|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n3|│ .a-dir                                          │        \n4|│ a-dir                                           │        \n5|│ b-dir                                           │        \n6|│ .a-file                                         │        \n7|└──────────────────────────────────────────────────┘        \n8|                                          1,9-7         Top \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000011111111111111111111111111111111111111111111111111\n2|022222222222222222222222222222222200000000000000000033333333\n3|044444444555555555555555555555555555555555555555555066666666\n4|077777778888888888888888888888888888888888888888888066666666\n5|077777778888888888888888888888888888888888888888888066666666\n6|088888888888888888888888888888888888888888888888888066666666\n7|000000000000000000000000000000000000000000000000000066666666\n8|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respects-tabline-and-statusline-when-computing-height-004",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n2|│ .a-dir                                          │        \n3|│ a-dir                                           │        \n4|│ b-dir                                           │        \n5|│ .a-file                                         │        \n6|│ a-file                                          │        \n7|└──────────────────────────────────────────────────┘        \n8|                                          1,9-7         Top \n\n-|---------|---------|---------|---------|---------|---------|\n1|011111111111111111111111111111111100000000000000000022222222\n2|033333333444444444444444444444444444444444444444444055555555\n3|066666667777777777777777777777777777777777777777777055555555\n4|066666667777777777777777777777777777777777777777777055555555\n5|077777777777777777777777777777777777777777777777777055555555\n6|077777777777777777777777777777777777777777777777777055555555\n7|000000000000000000000000000000000000000000000000000055555555\n8|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---respects-tabline-when-computing-position",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|My tabline                                                                      \n02|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n03|│ .a-dir                                          │                            \n04|│ a-dir                                           │                            \n05|│ b-dir                                           │                            \n06|│ .a-file                                         │                            \n07|│ a-file                                          │                            \n08|│ A-file-2                                        │                            \n09|│ b-file                                          │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000001111111111111111111111111111111111111111111111111111111111111111111111\n02|02222222222222222222222222222222220000000000000000003333333333333333333333333333\n03|04444444455555555555555555555555555555555555555555506666666666666666666666666666\n04|07777777888888888888888888888888888888888888888888806666666666666666666666666666\n05|07777777888888888888888888888888888888888888888888806666666666666666666666666666\n06|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n07|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n08|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n09|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n10|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---Windows---works-with-too-small-dimensions",
    "content": "-|---------|-----\n1|┌…iles/common ┐\n2|│ .a-dir     │\n3|│ a-dir      │\n4|│ b-dir      │\n5|│ .a-file    │\n6|│ a-file     │\n7|└─────────────┘\n8|        1,9-7  \n\n-|---------|-----\n1|011111111111110\n2|022222222333330\n3|044444445555550\n4|044444445555550\n5|055555555555550\n6|055555555555550\n7|000000000000000\n8|666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---checks-for-pending-file-system-actions",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│new                                               │                            \n04|│ a-dir                                           │                            \n05|│ b-dir                                           │                            \n06|│ .a-file                                         │                            \n07|│ a-file                                          │                            \n08|│ A-file-2                                        │                            \n09|│ b-file                                          │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,3           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n10|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---checks-for-pending-file-system-actions-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│new                                               │                            \n04|│ a-dir                                           │                            \n05|│ b-dir                                           │                            \n06|│ .a-file                                         │                            \n07|│ a-file                                          │                            \n08|│ A-file-2                                        │                            \n09|│ b-file                                          │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,3           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n10|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---checks-for-pending-file-system-actions-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|~                                                                               \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---handles-invalid-target-window",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ .a-dir                                          │        \n03|│ a-dir                                           │        \n04|│ b-dir                                           │        \n05|│ .a-file                                         │        \n06|│ a-file                                          │        \n07|│ A-file-2                                        │        \n08|│ b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|~                             │~                            \n11|~                             │~                            \n12|~                             │~                            \n13|~                             │~                            \n14|~                             │~                            \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555855555555555555555555555555555\n11|555555555555555555555555555555855555555555555555555555555555\n12|555555555555555555555555555555855555555555555555555555555555\n13|555555555555555555555555555555855555555555555555555555555555\n14|555555555555555555555555555555855555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---handles-invalid-target-window-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|~                                                           \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111111111111111111111111111111111111111111\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|~                                                                               \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---close()---works-per-tabpage",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              5,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|02222222222222222222222222222222222222222222222222205555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---go_in()---warns-about-paths-not-present-on-disk",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common──────────────────┐                            \n02|│new-file                                          │                            \n03|│ .a-dir                                          │                            \n04|│ a-dir                                           │                            \n05|│ b-dir                                           │                            \n06|│ .a-file                                         │                            \n07|│ a-file                                          │                            \n08|│ A-file-2                                        │                            \n09|│ b-file                                          │                            \n10|└──────────────────────────────────────────────────┘                            \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111100000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555566666666666666666666666666666666666666666604444444444444444444444444444\n04|07777777333333333333333333333333333333333333333333304444444444444444444444444444\n05|07777777333333333333333333333333333333333333333333304444444444444444444444444444\n06|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n07|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n08|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n09|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n10|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---go_in()---works-on-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---go_in()---works-on-directory-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---go_out()---root-update-reuses-buffers-without-their-update",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐┌ dir ──────────┐           \n02|│ dir                                             ││               │           \n03|└──────────────────────────────────────────────────┘└───────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000000222220000000000033333333333\n02|04444455555555555555555555555555555555555555555555500555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---go_out()---works-on-branch-root",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ a-dir ────────┐           \n02|│ .a-dir                                          ││ aa-dir       │           \n03|│ a-dir                                           ││ aa-file      │           \n04|│ b-dir                                           ││ ab-file      │           \n05|│ .a-file                                         │└───────────────┘           \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222200000000033333333333\n02|04444444455555555555555555555555555555555555555555500666666667777777088888888888\n03|06666666777777777777777777777777777777777777777777700555555555555555088888888888\n04|04444444555555555555555555555555555555555555555555500555555555555555088888888888\n05|05555555555555555555555555555555555555555555555555500000000000000000088888888888\n06|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n07|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n08|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n09|00000000000000000000000000000000000000000000000000008888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---go_out()---works-on-not-branch-root",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ a-dir ────────┐           \n02|│ .a-dir                                          ││ aa-dir       │           \n03|│ a-dir                                           ││ aa-file      │           \n04|│ b-dir                                           ││ ab-file      │           \n05|│ .a-file                                         │└───────────────┘           \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222200000000033333333333\n02|04444444455555555555555555555555555555555555555555500666666667777777088888888888\n03|06666666777777777777777777777777777777777777777777700555555555555555088888888888\n04|04444444555555555555555555555555555555555555555555500555555555555555088888888888\n05|05555555555555555555555555555555555555555555555555500000000000000000088888888888\n06|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n07|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n08|05555555555555555555555555555555555555555555555555508888888888888888888888888888\n09|00000000000000000000000000000000000000000000000000008888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---`content.prefix`-can-be-used-to-not-show-prefix",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│.a-dir         ││aa-file                                           │           \n03|│a-dir          ││ab-file                                           │           \n04|│b-dir          │└──────────────────────────────────────────────────┘           \n05|│.a-file        │                                                               \n06|│a-file         │                                                               \n07|│A-file-2       │                                                               \n08|│b-file         │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,5           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444445555555550055555555555555555555555555555555555555555555555555066666666666\n03|07777788888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777788888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---`content.prefix`-can-return-`nil`",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│.a-dir                                            │        \n03|│a-dir                                             │        \n04|│b-dir                                             │        \n05|│.a-file                                           │        \n06|│a-file                                            │        \n07|│A-file-2                                          │        \n08|│b-file                                            │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,5           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333344444444444444444444444444444444444444444444055555555\n03|066666777777777777777777777777777777777777777777777055555555\n04|066666777777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---`content.prefix`-can-return-`nil`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│.a-dir                                            │        \n03|│a-dir                                             │        \n04|│b-dir                                             │        \n05|│.a-file                                           │        \n06|│a-file                                            │        \n07|│A-file-2                                          │        \n08|│b-file                                            │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,5           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333344444444444444444444444444444444444444444444055555555\n03|066666777777777777777777777777777777777777777777777055555555\n04|066666777777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---`content.prefix`-can-return-`nil`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│.a-dir                                            │        \n03|│a-dir                                             │        \n04|│b-dir                                             │        \n05|│.a-file                                           │        \n06|│a-file                                            │        \n07|│A-file-2                                          │        \n08|│b-file                                            │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,5           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333344444444444444444444444444444444444444444444055555555\n03|066666777777777777777777777777777777777777777777777055555555\n04|066666777777777777777777777777777777777777777777777055555555\n05|077777777777777777777777777777777777777777777777777055555555\n06|077777777777777777777777777777777777777777777777777055555555\n07|077777777777777777777777777777777777777777777777777055555555\n08|077777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---`content.sort`-can-be-used-to-also-filter-items",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ b-dir                                           │                            \n03|│ a-dir                                           │                            \n04|│ .a-dir                                          │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666677777777777777777777777777777777777777777705555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---can-display-entries-with-newline-character",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐┌ di<NL>r ────────────────┐ \n02|│ di<NL>r                                         ││                         │ \n03|│ fi<NL>l<NL>e                                    │└─────────────────────────┘ \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000000222222222000000000000000003\n02|04444444445555555555555555555555555555555555555555500555555555555555555555555506\n03|07777777777777777777777777777777777777777777777777700000000000000000000000000006\n04|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---can-display-entries-with-newline-character-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐┌ fi<NL>l<NL>e ───────────┐ \n02|│ di<NL>r                                         ││                         │ \n03|│ fi<NL>l<NL>e                                    │└─────────────────────────┘ \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000000222222222222220000000000003\n02|04444444445555555555555555555555555555555555555555500555555555555555555555555506\n03|07777777777777777777777777777777777777777777777777700000000000000000000000000006\n04|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---focuses-on-file-entry-when-opened-from-history",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ a-dir ────────┐           \n02|│ .a-dir                                          ││ aa-dir       │           \n03|│ a-dir                                           ││ aa-file      │           \n04|│ b-dir                                           ││ ab-file      │           \n05|│ .a-file                                         │└───────────────┘           \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222200000000033333333333\n02|04444444455555555555555555555555555555555555555555500444444445555555066666666666\n03|07777777888888888888888888888888888888888888888888800555555555555555066666666666\n04|04444444555555555555555555555555555555555555555555500888888888888888066666666666\n05|05555555555555555555555555555555555555555555555555500000000000000000066666666666\n06|05555555555555555555555555555555555555555555555555506666666666666666666666666666\n07|05555555555555555555555555555555555555555555555555506666666666666666666666666666\n08|05555555555555555555555555555555555555555555555555506666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---focuses-on-file-entry-when-opened-from-history-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-dir                                          │           \n03|│ a-dir        ││ aa-file                                         │           \n04|│ b-dir        ││ ab-file                                         │           \n05|│ .a-file      │└──────────────────────────────────────────────────┘           \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550044444444555555555555555555555555555555555555555555066666666666\n03|07777777888888880055555555555555555555555555555555555555555555555555066666666666\n04|04444444555555550088888888888888888888888888888888888888888888888888066666666666\n05|05555555555555550000000000000000000000000000000000000000000000000000066666666666\n06|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n07|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n08|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---focuses-on-file-entry-when-opened-from-history-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---focuses-on-file-entry-when-opened-from-history-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/a-dir ───────────┐                            \n02|│ aa-dir                                          │                            \n03|│ aa-file                                         │                            \n04|│ ab-file                                         │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111110000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---handles-backslash-on-Unix",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ \\                                               │                            \n03|│ hello\\                                          │                            \n04|│ wo\\rld                                          │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n05|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---handles-problematic-entry-names",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ a bad-dir.name                                  │                            \n03|│ %a bad-file-name                                │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---handles-external-changes-between-calls",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ subdir ──────────────────────────────────────────┐           \n02|│ subdir       ││                                                  │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---handles-external-changes-between-calls-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│                                                  │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---is-shared-across-tabpages",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---is-shared-across-tabpages-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---is-shared-across-tabpages-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ .a-dir ───────┐           \n02|│ .a-dir                                          ││ aa-file      │           \n03|│ a-dir                                           ││ ab-file      │           \n04|│ b-dir                                           │└───────────────┘           \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222220000000033333333333\n02|04444444455555555555555555555555555555555555555555500555555555555555066666666666\n03|07777777888888888888888888888888888888888888888888800888888888888888066666666666\n04|07777777888888888888888888888888888888888888888888800000000000000000066666666666\n05|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n06|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n07|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n08|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---opens-from-history-by-default",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-dir                                          │           \n03|│ a-dir        ││ aa-file                                         │           \n04|│ b-dir        ││ ab-file                                         │           \n05|│ .a-file      │└──────────────────────────────────────────────────┘           \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550044444444555555555555555555555555555555555555555555066666666666\n03|07777777888888880055555555555555555555555555555555555555555555555555066666666666\n04|04444444555555550088888888888888888888888888888888888888888888888888066666666666\n05|05555555555555550000000000000000000000000000000000000000000000000000066666666666\n06|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n07|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n08|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---opens-from-history-by-default-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-dir                                          │           \n03|│ a-dir        ││ aa-file                                         │           \n04|│ b-dir        ││ ab-file                                         │           \n05|│ .a-file      │└──────────────────────────────────────────────────┘           \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550044444444555555555555555555555555555555555555555555066666666666\n03|07777777888888880055555555555555555555555555555555555555555555555555066666666666\n04|04444444555555550088888888888888888888888888888888888888888888888888066666666666\n05|05555555555555550000000000000000000000000000000000000000000000000000066666666666\n06|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n07|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n08|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---prefers-global-config-before-taking-from-history",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ a-dir                                           │                            \n03|│ a-file                                          │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---prefers-global-config-before-taking-from-history-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ b-dir                                           │                            \n03|│ b-file                                          │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---respects-`use_latest`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-dir                                          │           \n03|│ a-dir        ││ aa-file                                         │           \n04|│ b-dir        ││ ab-file                                         │           \n05|│ .a-file      │└──────────────────────────────────────────────────┘           \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              3,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550044444444555555555555555555555555555555555555555555066666666666\n03|07777777888888880055555555555555555555555555555555555555555555555555066666666666\n04|04444444555555550088888888888888888888888888888888888888888888888888066666666666\n05|05555555555555550000000000000000000000000000000000000000000000000000066666666666\n06|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n07|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n08|05555555555555550666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---respects-`use_latest`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---stores-whole-branch-and-not-only-visible-windows",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/.a-dir ──────────┐        \n02|│ aa-file                                         │        \n03|│ ab-file                                         │        \n04|└──────────────────────────────────────────────────┘        \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111111111110000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|000000000000000000000000000000000000000000000000000044444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|444444444444444444444444444444444444444444444444444444444444\n11|444444444444444444444444444444444444444444444444444444444444\n12|444444444444444444444444444444444444444444444444444444444444\n13|444444444444444444444444444444444444444444444444444444444444\n14|444444444444444444444444444444444444444444444444444444444444\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---history---stores-whole-branch-and-not-only-visible-windows-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---normalizes-before-first-refresh-when-focused-on-directory-with-`windows.preview`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ .a-dir ─────────────────┐ \n02|│ .a-dir                                          ││ aa-file                │ \n03|│ a-dir                                           ││ ab-file                │ \n04|│ b-dir                                           │└─────────────────────────┘ \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222220000000000000000003\n02|04444444455555555555555555555555555555555555555555500555555555555555555555555506\n03|07777777888888888888888888888888888888888888888888800888888888888888888888888806\n04|07777777888888888888888888888888888888888888888888800000000000000000000000000006\n05|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n06|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n07|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n08|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---normalizes-before-first-refresh-when-focused-on-file",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              5,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---properly-closes-currently-opened-explorer",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.filter`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.filter`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ a-dir                                           │                            \n03|│ a-file                                          │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.highlight`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03344444444444444444444444444444444444444444444444405555555555555555555555555555\n03|06677777777777777777777777777777777777777777777777705555555555555555555555555555\n04|06677777777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.highlight`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03344444455555555555555555555555555555555555555555506666666666666666666666666666\n03|07788888999999999999999999999999999999999999999999906666666666666666666666666666\n04|077:::::999999999999999999999999999999999999999999906666666666666666666666666666\n05|099:::::::9999999999999999999999999999999999999999906666666666666666666666666666\n06|09988888899999999999999999999999999999999999999999906666666666666666666666666666\n07|099::::::::999999999999999999999999999999999999999906666666666666666666666666666\n08|099::::::99999999999999999999999999999999999999999906666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.prefix`",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│-.a-dir                                           │        \n03|│-a-dir                                            │        \n04|│-b-dir                                            │        \n05|│|.a-file                                          │        \n06|│|a-file                                           │        \n07|│|A-file-2                                         │        \n08|│|b-file                                           │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,6           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|034444445555555555555555555555555555555555555555555066666666\n03|078888899999999999999999999999999999999999999999999066666666\n04|078888899999999999999999999999999999999999999999999066666666\n05|0:9999999999999999999999999999999999999999999999999066666666\n06|0:9999999999999999999999999999999999999999999999999066666666\n07|0:9999999999999999999999999999999999999999999999999066666666\n08|0:9999999999999999999999999999999999999999999999999066666666\n09|000000000000000000000000000000000000000000000000000066666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.prefix`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│|.a-dir                                           │        \n03|│|a-dir                                            │        \n04|│|b-dir                                            │        \n05|│|.a-file                                          │        \n06|│|a-file                                           │        \n07|│|A-file-2                                         │        \n08|│|b-file                                           │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,6           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|034444445555555555555555555555555555555555555555555066666666\n03|078888899999999999999999999999999999999999999999999066666666\n04|078888899999999999999999999999999999999999999999999066666666\n05|079999999999999999999999999999999999999999999999999066666666\n06|079999999999999999999999999999999999999999999999999066666666\n07|079999999999999999999999999999999999999999999999999066666666\n08|079999999999999999999999999999999999999999999999999066666666\n09|000000000000000000000000000000000000000000000000000066666666\n10|666666666666666666666666666666666666666666666666666666666666\n11|666666666666666666666666666666666666666666666666666666666666\n12|666666666666666666666666666666666666666666666666666666666666\n13|666666666666666666666666666666666666666666666666666666666666\n14|666666666666666666666666666666666666666666666666666666666666\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.sort`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ .a-file                                         │                            \n04|│ A-file-2                                        │                            \n05|│ a-dir                                           │                            \n06|│ a-file                                          │                            \n07|│ b-dir                                           │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|07777777666666666666666666666666666666666666666666605555555555555555555555555555\n06|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n07|07777777666666666666666666666666666666666666666666605555555555555555555555555555\n08|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`content.sort`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ b-file                                          │                            \n03|│ b-dir                                           │                            \n04|│ a-file                                          │                            \n05|│ a-dir                                           │                            \n06|│ A-file-2                                        │                            \n07|│ .a-file                                         │                            \n08|│ .a-dir                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555666666666666666666666666666666666666666666604444444444444444444444444444\n04|06666666666666666666666666666666666666666666666666604444444444444444444444444444\n05|05555555666666666666666666666666666666666666666666604444444444444444444444444444\n06|06666666666666666666666666666666666666666666666666604444444444444444444444444444\n07|06666666666666666666666666666666666666666666666666604444444444444444444444444444\n08|05555555566666666666666666666666666666666666666666604444444444444444444444444444\n09|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`mappings`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`mappings`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`vim.b.minifiles_config`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ a-dir                                           │                            \n03|│ a-file                                          │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.max_number`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/.a-dir ──────────┐                            \n02|│ aa-file                                         │                            \n03|│ ab-file                                         │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111111000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.max_number`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.preview`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐┌ .a-dir ─────────────────┐ \n02|│ .a-dir                                          ││ aa-file                │ \n03|│ a-dir                                           ││ ab-file                │ \n04|│ b-dir                                           │└─────────────────────────┘ \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222220000000000000000003\n02|04444444455555555555555555555555555555555555555555500555555555555555555555555506\n03|07777777888888888888888888888888888888888888888888800888888888888888888888888806\n04|07777777888888888888888888888888888888888888888888800000000000000000000000000006\n05|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n06|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n07|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n08|08888888888888888888888888888888888888888888888888806666666666666666666666666666\n09|00000000000000000000000000000000000000000000000000006666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.preview`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_focus`-and-`windows.width_nofocus`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/common ┐┌ .a-dir ────────────────────────────────┐                          \n02|│ .a-dir  ││ aa-file                               │                          \n03|│ a-dir   ││ ab-file                               │                          \n04|│ b-dir   │└────────────────────────────────────────┘                          \n05|│ .a-file │                                                                    \n06|│ a-file  │                                                                    \n07|│ A-file-2│                                                                    \n08|│ b-file  │                                                                    \n09|└──────────┘                                                                    \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222200000000000000000000000000000000033333333333333333333333333\n02|04444444455005555555555555555555555555555555555555555066666666666666666666666666\n03|07777777888008888888888888888888888888888888888888888066666666666666666666666666\n04|07777777888000000000000000000000000000000000000000000066666666666666666666666666\n05|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n06|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n07|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n08|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n09|00000000000066666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_focus`-and-`windows.width_nofocus`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/common ┐┌ .a-dir ──────────────────────┐                          \n02|│ .a-dir            ││ aa-file                     │                          \n03|│ a-dir             ││ ab-file                     │                          \n04|│ b-dir             │└──────────────────────────────┘                          \n05|│ .a-file           │                                                          \n06|│ a-file            │                                                          \n07|│ A-file-2          │                                                          \n08|│ b-file            │                                                          \n09|└────────────────────┘                                                          \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222220000000000000000000000033333333333333333333333333\n02|04444444455555555555500555555555555555555555555555555066666666666666666666666666\n03|07777777888888888888800888888888888888888888888888888066666666666666666666666666\n04|07777777888888888888800000000000000000000000000000000066666666666666666666666666\n05|08888888888888888888806666666666666666666666666666666666666666666666666666666666\n06|08888888888888888888806666666666666666666666666666666666666666666666666666666666\n07|08888888888888888888806666666666666666666666666666666666666666666666666666666666\n08|08888888888888888888806666666666666666666666666666666666666666666666666666666666\n09|00000000000000000000006666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_preview`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐┌ dir-1 ────────┐                                         \n02|│ dir-1             ││ dir-11       │                                         \n03|└────────────────────┘│ dir-12       │                                         \n04|~                     └───────────────┘                                         \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222200000000033333333333333333333333333333333333333333\n02|04444444555555555555500444444445555555066666666666666666666666666666666666666666\n03|00000000000000000000000777777778888888066666666666666666666666666666666666666666\n04|66666666666666666666660000000000000000066666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_preview`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ─────────────┐┌ dir-11 ───────┐                             \n02|│ dir-1   ││ dir-11            ││ dir-111      │                             \n03|└──────────┘│ dir-12            │└───────────────┘                             \n04|~           └────────────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222000000000000000111111110000000033333333333333333333333333333\n02|04444444555004444444455555555555500444444444555555066666666666666666666666666666\n03|00000000000007777777788888888888800000000000000000066666666666666666666666666666\n04|66666666666600000000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_preview`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ───┐┌ dir-11 ────────────┐┌ dir-111 ──────┐                 \n02|│ dir-1   ││ dir-11  ││ dir-111           ││ dir-1111     │                 \n03|└──────────┘│ dir-12  │└────────────────────┘└───────────────┘                 \n04|~           └──────────┘                                                        \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111001111111000002222222200000000000000111111111000000033333333333333333\n02|04444444555004444444455004444444445555555555500444444444455555066666666666666666\n03|00000000000007777777788000000000000000000000000000000000000000066666666666666666\n04|66666666666600000000000066666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_preview`-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/nested ┐┌ dir-1 ─────────────┐┌ dir-11 ───────┐┌ dir-111 ─┐                 \n02|│ dir-1   ││ dir-11            ││ dir-111      ││ dir-1111│                 \n03|└──────────┘│ dir-12            │└───────────────┘└──────────┘                 \n04|~           └────────────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222000000000000000111111110000000001111111110033333333333333333\n02|04444444555004444444455555555555500444444444555555004444444444066666666666666666\n03|00000000000007777777788888888888800000000000000000000000000000066666666666666666\n04|66666666666600000000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_preview`-005",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐┌ dir-1 ────────┐┌ dir-11 ──┐┌ dir-111 ─┐                 \n02|│ dir-1             ││ dir-11       ││ dir-111 ││ dir-1111│                 \n03|└────────────────────┘│ dir-12       │└──────────┘└──────────┘                 \n04|~                     └───────────────┘                                         \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222200000000002222222200002222222220033333333333333333\n02|04444444555555555555500444444445555555004444444445004444444444066666666666666666\n03|00000000000000000000000777777778888888000000000000000000000000066666666666666666\n04|66666666666666666666660000000000000000066666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---respects-`windows.width_preview`-006",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/nested ┐┌ dir-1 ───────────────────────┐                          \n02|│ dir-1             ││ dir-11                      │                          \n03|└────────────────────┘│ dir-12                      │                          \n04|~                     └──────────────────────────────┘                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222200000000000000000000000033333333333333333333333333\n02|04444444555555555555500444444445555555555555555555555066666666666666666666666666\n03|00000000000000000000000777777778888888888888888888888066666666666666666666666666\n04|66666666666666666666660000000000000000000000000000000066666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---uses-`MiniIcons.get()`-with-full-path",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│󰉋 .a-dir                                          │        \n03|│󰉋 a-dir                                           │        \n04|│󰉋 b-dir                                           │        \n05|│󱁤 .a-file                                         │        \n06|│󱁤 a-file                                          │        \n07|│󰈔 A-file-2                                        │        \n08|│󱁤 b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|                                          1,10-7        All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|066666667777777777777777777777777777777777777777777055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|088777777777777777777777777777777777777777777777777055555555\n06|088777777777777777777777777777777777777777777777777055555555\n07|088777777777777777777777777777777777777777777777777055555555\n08|088777777777777777777777777777777777777777777777777055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---uses-icon-provider",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files ────────────────────────┐┌ real ─────────┐           \n02|│󰉋 common                                          ││󰢱 a.lua        │           \n03|│󰉋 lua                                             ││󰦪 b.txt        │           \n04|│󰉋 nested                                          ││󰵸 c.gif        │           \n05|│󰉋 real                                            ││ LICENSE      │           \n06|│󰢱 init-default-explorer.lua                       ││󱁤 Makefile     │           \n07|│󰢱 mock-win-functions.lua                          ││󰈔 top-secret   │           \n08|└──────────────────────────────────────────────────┘└───────────────┘           \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              4,11-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111100000000000000000000000000222222000000000033333333333\n02|04444444455555555555555555555555555555555555555555500667777777777777088888888888\n03|09944455555555555555555555555555555555555555555555500::5555555555555088888888888\n04|04444444455555555555555555555555555555555555555555500445555555555555088888888888\n05|06666667777777777777777777777777777777777777777777700;;5555555555555088888888888\n06|04455555555555555555555555555555555555555555555555500<<5555555555555088888888888\n07|04455555555555555555555555555555555555555555555555500<<5555555555555088888888888\n08|00000000000000000000000000000000000000000000000000000000000000000000088888888888\n09|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---uses-icon-provider-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files ────────────────────────┐┌ real ─────────┐           \n02|│󰉋 common                                          ││󰢱 a.lua        │           \n03|│󰉋 lua                                             ││󰦪 b.txt        │           \n04|│󰉋 nested                                          ││󰵸 c.gif        │           \n05|│󰉋 real                                            ││ LICENSE      │           \n06|│󰢱 init-default-explorer.lua                       ││󱁤 Makefile     │           \n07|│󰢱 mock-win-functions.lua                          ││󰈔 top-secret   │           \n08|└──────────────────────────────────────────────────┘└───────────────┘           \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              4,11-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111100000000000000000000000000222222000000000033333333333\n02|04444444455555555555555555555555555555555555555555500667777777777777088888888888\n03|09944455555555555555555555555555555555555555555555500::5555555555555088888888888\n04|04444444455555555555555555555555555555555555555555500445555555555555088888888888\n05|06666667777777777777777777777777777777777777777777700;;5555555555555088888888888\n06|04455555555555555555555555555555555555555555555555500<<5555555555555088888888888\n07|04455555555555555555555555555555555555555555555555500<<5555555555555088888888888\n08|00000000000000000000000000000000000000000000000000000000000000000000088888888888\n09|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---uses-icon-provider-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files ────────────────────────┐┌ real ─────────┐           \n02|│ common                                          ││ a.lua        │           \n03|│ lua                                             ││ b.txt        │           \n04|│ nested                                          ││ c.gif        │           \n05|│ real                                            ││ LICENSE      │           \n06|│ init-default-explorer.lua                       ││ Makefile     │           \n07|│ mock-win-functions.lua                          ││ top-secret   │           \n08|└──────────────────────────────────────────────────┘└───────────────┘           \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              4,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111100000000000000000000000000222222000000000033333333333\n02|04444444455555555555555555555555555555555555555555500666666666666666077777777777\n03|04444455555555555555555555555555555555555555555555500555555555555555077777777777\n04|04444444455555555555555555555555555555555555555555500555555555555555077777777777\n05|08888886666666666666666666666666666666666666666666600555555555555555077777777777\n06|05555555555555555555555555555555555555555555555555500555555555555555077777777777\n07|05555555555555555555555555555555555555555555555555500555555555555555077777777777\n08|00000000000000000000000000000000000000000000000000000000000000000000077777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-per-tabpage",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-per-tabpage-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/a-dir ───────────┐                            \n02|│ aa-dir                                          │                            \n03|│ aa-file                                         │                            \n04|│ ab-file                                         │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111110000000000002222222222222222222222222222\n02|03333333322222222222222222222222222222222222222222204444444444444444444444444444\n03|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n04|05555555555555555555555555555555555555555555555555504444444444444444444444444444\n05|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-per-tabpage-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-with-directory-path",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-with-directory-path-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-with-directory-path-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-with-file-path",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              5,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---open()---works-with-file-path-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              5,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---does-not-update-buffers-with-`nil`-`filter`-and-`sort`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ subdir ──────────────────────────────────────────┐           \n02|│ subdir       ││                                                  │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---does-not-update-buffers-with-`nil`-`filter`-and-`sort`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ subdir ──────────────────────────────────────────┐           \n02|│ subdir       ││                                                  │           \n03|└───────────────┘└──────────────────────────────────────────────────┘           \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|00000000000000000000000000000000000000000000000000000000000000000000066666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---handles-presence-of-pending-file-system-actions",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐        \n02|│ .file                                           │        \n03|│new-file                                          │        \n04|│ file                                            │        \n05|└──────────────────────────────────────────────────┘        \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,8           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111110000000000000000000022222222\n02|033333333333333333333333333333333333333333333333333044444444\n03|055555555555555555555555555555555555555555555555555044444444\n04|033333333333333333333333333333333333333333333333333044444444\n05|000000000000000000000000000000000000000000000000000044444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---handles-presence-of-pending-file-system-actions-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OCK_ROOT/tests/dir-files/temp ┐                            \n02|│ file                        │                            \n03|└──────────────────────────────┘                            \n04|~                                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111102222222222222222222222222222\n02|033333333333333333333333333333304444444444444444444444444444\n03|000000000000000000000000000000004444444444444444444444444444\n04|444444444444444444444444444444444444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---handles-presence-of-pending-file-system-actions-003",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌OCK_ROOT/tests/dir-files/temp ┐                            \n02|│ file                        │                            \n03|│new-file-2                    │                            \n04|└──────────────────────────────┘                            \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,10          All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111102222222222222222222222222222\n02|033333333333333333333333333333304444444444444444444444444444\n03|055555555555555555555555555555504444444444444444444444444444\n04|000000000000000000000000000000004444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---handles-presence-of-pending-file-system-actions-004",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐                                           \n02|│ file         │                                           \n03|│new-file-2     │                                           \n04|└───────────────┘                                           \n05|~                                                           \n06|~                                                           \n07|~                                                           \n08|~                                                           \n09|~                                                           \n10|                                          2,10          All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111102222222222222222222222222222222222222222222\n02|033333333333333304444444444444444444444444444444444444444444\n03|055555555555555504444444444444444444444444444444444444444444\n04|000000000000000004444444444444444444444444444444444444444444\n05|444444444444444444444444444444444444444444444444444444444444\n06|444444444444444444444444444444444444444444444444444444444444\n07|444444444444444444444444444444444444444444444444444444444444\n08|444444444444444444444444444444444444444444444444444444444444\n09|444444444444444444444444444444444444444444444444444444444444\n10|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---preserves-explorer-options",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/common ┐┌ .a-dir ─────────────────────────────────────┐                     \n02|│ .a-dir  ││ aa-file                                    │                     \n03|│ a-dir   ││ ab-file                                    │                     \n04|│ b-dir   │└─────────────────────────────────────────────┘                     \n05|│ .a-file │                                                                    \n06|│ a-file  │                                                                    \n07|│ A-file-2│                                                                    \n08|│ b-file  │                                                                    \n09|└──────────┘                                                                    \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222200000000000000000000000000000000000000333333333333333333333\n02|04444444455005555555555555555555555555555555555555555555550666666666666666666666\n03|07777777888008888888888888888888888888888888888888888888880666666666666666666666\n04|07777777888000000000000000000000000000000000000000000000000666666666666666666666\n05|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n06|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n07|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n08|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n09|00000000000066666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---preserves-explorer-options-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/common ┐┌ .a-dir ──────────────────────┐                                    \n02|│ .a-dir  ││ aa-file                     │                                    \n03|│ a-dir   ││ ab-file                     │                                    \n04|│ b-dir   │└──────────────────────────────┘                                    \n05|│ .a-file │                                                                    \n06|│ a-file  │                                                                    \n07|│ A-file-2│                                                                    \n08|│ b-file  │                                                                    \n09|└──────────┘                                                                    \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111002222222200000000000000000000000333333333333333333333333333333333333\n02|04444444455005555555555555555555555555555550666666666666666666666666666666666666\n03|07777777888008888888888888888888888888888880666666666666666666666666666666666666\n04|07777777888000000000000000000000000000000000666666666666666666666666666666666666\n05|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n06|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n07|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n08|08888888888066666666666666666666666666666666666666666666666666666666666666666666\n09|00000000000066666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---updates-buffers-with-non-empty-`content`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---updates-buffers-with-non-empty-`content`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ a-dir                                           │                            \n03|│ b-dir                                           │                            \n04|│ a-file                                          │                            \n05|│ A-file-2                                        │                            \n06|│ b-file                                          │                            \n07|└──────────────────────────────────────────────────┘                            \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---updates-buffers-with-non-empty-`content`-003",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│a-dir                                             │                            \n03|│b-dir                                             │                            \n04|│a-file                                            │                            \n05|│A-file-2                                          │                            \n06|│b-file                                            │                            \n07|└──────────────────────────────────────────────────┘                            \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,5           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666677777777777777777777777777777777777777777777705555555555555555555555555555\n04|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---updates-buffers-with-non-empty-`content`-004",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│b-file                                            │                            \n03|│b-dir                                             │                            \n04|│a-file                                            │                            \n05|│a-dir                                             │                            \n06|│A-file-2                                          │                            \n07|└──────────────────────────────────────────────────┘                            \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              4,5           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n03|05555533333333333333333333333333333333333333333333304444444444444444444444444444\n04|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n05|06666677777777777777777777777777777777777777777777704444444444444444444444444444\n06|03333333333333333333333333333333333333333333333333304444444444444444444444444444\n07|00000000000000000000000000000000000000000000000000004444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---refresh()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌K_ROOT/tests/dir-files/common ┐                                                \n02|│ .a-dir                      │                                                \n03|│ a-dir                       │                                                \n04|│ b-dir                       │                                                \n05|│ .a-file                     │                                                \n06|│ a-file                      │                                                \n07|│ A-file-2                    │                                                \n08|│ b-file                      │                                                \n09|└──────────────────────────────┘                                                \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111110222222222222222222222222222222222222222222222222\n02|03333333344444444444444444444440555555555555555555555555555555555555555555555555\n03|06666666777777777777777777777770555555555555555555555555555555555555555555555555\n04|06666666777777777777777777777770555555555555555555555555555555555555555555555555\n05|07777777777777777777777777777770555555555555555555555555555555555555555555555555\n06|07777777777777777777777777777770555555555555555555555555555555555555555555555555\n07|07777777777777777777777777777770555555555555555555555555555555555555555555555555\n08|07777777777777777777777777777770555555555555555555555555555555555555555555555555\n09|00000000000000000000000000000000555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reset()---resets-all-cursors",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              7,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n04|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n05|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n06|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n07|04444444444444444444444444444444444444444444444444405555555555555555555555555555\n08|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reset()---resets-all-cursors-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reset()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ a-dir ───────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-dir                                          │           \n03|│ a-dir        ││ aa-file                                         │           \n04|│ b-dir        ││ ab-file                                         │           \n05|│ .a-file      │└──────────────────────────────────────────────────┘           \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000000000000000000000000000000000033333333333\n02|04444444455555550066666666777777777777777777777777777777777777777777088888888888\n03|06666666777777770055555555555555555555555555555555555555555555555555088888888888\n04|04444444555555550055555555555555555555555555555555555555555555555555088888888888\n05|05555555555555550000000000000000000000000000000000000000000000000000088888888888\n06|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n07|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n08|05555555555555550888888888888888888888888888888888888888888888888888888888888888\n09|00000000000000000888888888888888888888888888888888888888888888888888888888888888\n10|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reset()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐                            \n02|│ .a-dir                                          │                            \n03|│ a-dir                                           │                            \n04|│ b-dir                                           │                            \n05|│ .a-file                                         │                            \n06|│ a-file                                          │                            \n07|│ A-file-2                                        │                            \n08|│ b-file                                          │                            \n09|└──────────────────────────────────────────────────┘                            \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n04|06666666777777777777777777777777777777777777777777705555555555555555555555555555\n05|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n06|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n07|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n08|07777777777777777777777777777777777777777777777777705555555555555555555555555555\n09|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reset()---works-when-anchor-is-not-in-branch",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────────────────────────┐           \n02|│ .a-dir       ││ aa-file                                         │           \n03|│ a-dir        ││ ab-file                                         │           \n04|│ b-dir        │└──────────────────────────────────────────────────┘           \n05|│ .a-file      │                                                               \n06|│ a-file       │                                                               \n07|│ A-file-2     │                                                               \n08|│ b-file       │                                                               \n09|└───────────────┘                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,10-8        All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550055555555555555555555555555555555555555555555555555066666666666\n03|07777777888888880088888888888888888888888888888888888888888888888888066666666666\n04|07777777888888880000000000000000000000000000000000000000000000000000066666666666\n05|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n06|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n07|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n08|08888888888888880666666666666666666666666666666666666666666666666666666666666666\n09|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reset()---works-when-anchor-is-not-in-branch-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common/a-dir ───────────┐                            \n02|│ aa-dir                                          │                            \n03|│ aa-file                                         │                            \n04|│ ab-file                                         │                            \n05|└──────────────────────────────────────────────────┘                            \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111110000000000002222222222222222222222222222\n02|03333333344444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n04|06666666666666666666666666666666666666666666666666605555555555555555555555555555\n05|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---properly-places-cursors",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…/temp/dir-2/dir-23 ┐                                                          \n02|│                    │                                                          \n03|└────────────────────┘                                                          \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333333333333333304444444444444444444444444444444444444444444444444444444444\n03|00000000000000000000004444444444444444444444444444444444444444444444444444444444\n04|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n05|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n06|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n07|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n08|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n09|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n10|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n11|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444444444444444444444444444444444\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---properly-places-cursors-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ir-files/temp ┐┌ dir-2 ────────┐┌ dir-23 ────────────┐                        \n02|│ dir-1        ││ dir-21       ││                    │                        \n03|│ dir-2        ││ dir-22       │└────────────────────┘                        \n04|│ dir-3        ││ dir-23       │                                              \n05|└───────────────┘└───────────────┘                                              \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              0,0-1         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110011111110000000000222222220000000000000333333333333333333333333\n02|04444444555555550044444444555555500666666666666666666660777777777777777777777777\n03|08888888666666660044444444555555500000000000000000000000777777777777777777777777\n04|04444444555555550088888888666666607777777777777777777777777777777777777777777777\n05|00000000000000000000000000000000007777777777777777777777777777777777777777777777\n06|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n07|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n08|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n09|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n10|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n11|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n12|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n13|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n14|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ested/dir-1/dir-11 ┐                                                          \n02|│ dir-111           │                                                          \n03|└────────────────────┘                                                          \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333334444444444405555555555555555555555555555555555555555555555555555555555\n03|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n04|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ────────┐┌ dir-11 ────────────┐                        \n02|│ dir-1        ││ dir-11       ││ dir-111           │                        \n03|└───────────────┘│ dir-12       │└────────────────────┘                        \n04|~                └───────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110011111110000000000222222220000000000000333333333333333333333333\n02|04444444555555550044444444555555500444444444555555555550666666666666666666666666\n03|00000000000000000077777777888888800000000000000000000000666666666666666666666666\n04|66666666666666666000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-when-not-inside-cwd",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/common ┐                                                          \n02|│ .a-dir            │                                                          \n03|│ a-dir             │                                                          \n04|│ b-dir             │                                                          \n05|│ .a-file           │                                                          \n06|│ a-file            │                                                          \n07|│ A-file-2          │                                                          \n08|│ b-file            │                                                          \n09|└────────────────────┘                                                          \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333344444444444405555555555555555555555555555555555555555555555555555555555\n03|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n04|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n05|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n06|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n07|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n08|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n09|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-when-not-inside-cwd-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/common ┐                                                          \n02|│ .a-dir            │                                                          \n03|│ a-dir             │                                                          \n04|│ b-dir             │                                                          \n05|│ .a-file           │                                                          \n06|│ a-file            │                                                          \n07|│ A-file-2          │                                                          \n08|│ b-file            │                                                          \n09|└────────────────────┘                                                          \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333344444444444405555555555555555555555555555555555555555555555555555555555\n03|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n04|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n05|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n06|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n07|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n08|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n09|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-when-root-is-already-cwd",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/common ┐                                                          \n02|│ .a-dir            │                                                          \n03|│ a-dir             │                                                          \n04|│ b-dir             │                                                          \n05|│ .a-file           │                                                          \n06|│ a-file            │                                                          \n07|│ A-file-2          │                                                          \n08|│ b-file            │                                                          \n09|└────────────────────┘                                                          \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333344444444444405555555555555555555555555555555555555555555555555555555555\n03|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n04|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n05|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n06|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n07|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n08|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n09|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-when-root-is-already-cwd-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…s/dir-files/common ┐                                                          \n02|│ .a-dir            │                                                          \n03|│ a-dir             │                                                          \n04|│ b-dir             │                                                          \n05|│ .a-file           │                                                          \n06|│ a-file            │                                                          \n07|│ A-file-2          │                                                          \n08|│ b-file            │                                                          \n09|└────────────────────┘                                                          \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111102222222222222222222222222222222222222222222222222222222222\n02|03333333344444444444405555555555555555555555555555555555555555555555555555555555\n03|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n04|06666666777777777777705555555555555555555555555555555555555555555555555555555555\n05|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n06|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n07|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n08|07777777777777777777705555555555555555555555555555555555555555555555555555555555\n09|00000000000000000000005555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-with-preview",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…ested/dir-1/dir-11 ┐┌ dir-111 ─┐                                              \n02|│ dir-111           ││ dir-1111│                                              \n03|└────────────────────┘└──────────┘                                              \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222222003333333333333333333333333333333333333333333333\n02|04444444445555555555500444444444406666666666666666666666666666666666666666666666\n03|00000000000000000000000000000000006666666666666666666666666666666666666666666666\n04|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---reveal_cwd()---works-with-preview-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ────────┐┌ dir-11 ────────────┐┌ dir-111 ─┐            \n02|│ dir-1        ││ dir-11       ││ dir-111           ││ dir-1111│            \n03|└───────────────┘│ dir-12       │└────────────────────┘└──────────┘            \n04|~                └───────────────┘                                              \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110011111110000000000222222220000000000000011111111100333333333333\n02|04444444555555550044444444555555500444444444555555555550044444444440666666666666\n03|00000000000000000077777777888888800000000000000000000000000000000000666666666666\n04|66666666666666666000000000000000006666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---set_branch()---works",
    "content": "--|---------|---------|---------|\n01|┌…s/dir-files/common ┐        \n02|│ .a-dir            │        \n03|│ a-dir             │        \n04|│ b-dir             │        \n05|│ .a-file           │        \n06|│ a-file            │        \n07|│ A-file-2          │        \n08|│ b-file            │        \n09|└────────────────────┘        \n10|~                             \n11|~                             \n12|               1,10-8     All \n\n--|---------|---------|---------|\n01|011111111111111111111022222222\n02|033333333444444444444055555555\n03|066666667777777777777055555555\n04|066666667777777777777055555555\n05|077777777777777777777055555555\n06|077777777777777777777055555555\n07|077777777777777777777055555555\n08|077777777777777777777055555555\n09|000000000000000000000055555555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---set_branch()---works-002",
    "content": "--|---------|---------|---------|\n01|┌…files/common/a-dir ┐        \n02|│ aa-dir            │        \n03|│ aa-file           │        \n04|│ ab-file           │        \n05|└────────────────────┘        \n06|~                             \n07|~                             \n08|~                             \n09|~                             \n10|~                             \n11|~                             \n12|               1,10-8     All \n\n--|---------|---------|---------|\n01|011111111111111111111022222222\n02|033333333444444444444055555555\n03|066666666666666666666055555555\n04|066666666666666666666055555555\n05|000000000000000000000055555555\n06|555555555555555555555555555555\n07|555555555555555555555555555555\n08|555555555555555555555555555555\n09|555555555555555555555555555555\n10|555555555555555555555555555555\n11|555555555555555555555555555555\n12|222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---set_branch()---works-003",
    "content": "--|---------|---------|---------|---------|\n01|┌…s/common ┐┌ a-dir ─────────────┐      \n02|│ .a-dir  ││ aa-dir            │      \n03|│ a-dir   ││ aa-file           │      \n04|│ b-dir   ││ ab-file           │      \n05|│ .a-file │└────────────────────┘      \n06|│ a-file  │                            \n07|│ A-file-2│                            \n08|│ b-file  │                            \n09|└──────────┘                            \n10|~                                       \n11|~                                       \n12|                      1,10-8        All \n\n--|---------|---------|---------|---------|\n01|0111111111100222222200000000000000333333\n02|0444444445500666666667777777777770888888\n03|0666666677700555555555555555555550888888\n04|0444444455500555555555555555555550888888\n05|0555555555500000000000000000000000888888\n06|0555555555508888888888888888888888888888\n07|0555555555508888888888888888888888888888\n08|0555555555508888888888888888888888888888\n09|0000000000008888888888888888888888888888\n10|8888888888888888888888888888888888888888\n11|8888888888888888888888888888888888888888\n12|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---set_branch()---works-with-file-path-in-branch",
    "content": "--|---------|---------|---------|---------|\n01|┌…sts/dir-files/real ┐┌ LICENSE ─┐      \n02|│ a.lua             ││          │      \n03|│ b.txt             │└──────────┘      \n04|│ c.gif             │                  \n05|│ LICENSE           │                  \n06|│ Makefile          │                  \n07|│ top-secret        │                  \n08|└────────────────────┘                  \n09|~                                       \n10|~                                       \n11|~                                       \n12|                      4,10-8        All \n\n--|---------|---------|---------|---------|\n01|0111111111111111111110022222222200333333\n02|0444444444444444444440044444444440555555\n03|0444444444444444444440000000000000555555\n04|0444444444444444444440555555555555555555\n05|0666666666666666666660555555555555555555\n06|0444444444444444444440555555555555555555\n07|0444444444444444444440555555555555555555\n08|0000000000000000000000555555555555555555\n09|5555555555555555555555555555555555555555\n10|5555555555555555555555555555555555555555\n11|5555555555555555555555555555555555555555\n12|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---set_branch()---works-with-file-path-in-branch-002",
    "content": "--|---------|---------|---------|---------|\n01|┌…sts/dir-files/real ┐┌ LICENSE ──────┐ \n02|│ a.lua             ││               │ \n03|│ b.txt             │└───────────────┘ \n04|│ c.gif             │                  \n05|│ LICENSE           │                  \n06|│ Makefile          │                  \n07|│ top-secret        │                  \n08|└────────────────────┘                  \n09|~                                       \n10|~                                       \n11|~                                       \n12|                      4,10-8        All \n\n--|---------|---------|---------|---------|\n01|0111111111111111111110022222222200000003\n02|0444444444444444444440044444444444444405\n03|0444444444444444444440000000000000000005\n04|0444444444444444444440555555555555555555\n05|0666666666666666666660555555555555555555\n06|0444444444444444444440555555555555555555\n07|0444444444444444444440555555555555555555\n08|0000000000000000000000555555555555555555\n09|5555555555555555555555555555555555555555\n10|5555555555555555555555555555555555555555\n11|5555555555555555555555555555555555555555\n12|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---set_branch()---works-with-preview",
    "content": "--|---------|---------|---------|---------|\n01|┌…s/dir-files/common ┐┌ .a-dir ───────┐ \n02|│ .a-dir            ││ aa-file      │ \n03|│ a-dir             ││ ab-file      │ \n04|│ b-dir             │└───────────────┘ \n05|│ .a-file           │                  \n06|│ a-file            │                  \n07|│ A-file-2          │                  \n08|│ b-file            │                  \n09|└────────────────────┘                  \n10|~                                       \n11|~                                       \n12|                      1,10-8        All \n\n--|---------|---------|---------|---------|\n01|0111111111111111111110022222222000000003\n02|0444444445555555555550055555555555555506\n03|0777777788888888888880088888888888888806\n04|0777777788888888888880000000000000000006\n05|0888888888888888888880666666666666666666\n06|0888888888888888888880666666666666666666\n07|0888888888888888888880666666666666666666\n08|0888888888888888888880666666666666666666\n09|0000000000000000000000666666666666666666\n10|6666666666666666666666666666666666666666\n11|6666666666666666666666666666666666666666\n12|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---adjusts-window-width",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ─────────────┐                │        \n03|││Buffer mappings:                │                │        \n04|││                                │                │        \n05|││Close                    │ q    │                │        \n06|││Go in entry              │ <C-L>│                │        \n07|││Go in entry plus         │ L    │                │        \n08|││Go out of directory      │ h    │                │        \n09|└│Go out of directory plus │ H    │────────────────┘        \n10|~│Go to bookmark           │ '    │                         \n11|~│Reset                    │ <BS> │                         \n12|~│Reveal cwd               │ @    │                         \n13|~│Set bookmark             │ m    │                         \n14|~│Show Help                │ g?   │                         \n15|~│Synchronize              │ =    │                         \n16|~│Trim branch left         │ <    │                         \n17|~│Trim branch right        │ >    │                         \n18|~│                                │                         \n19|~│(Press `q` to close)            │                         \n20|~└────────────────────────────────┘                         \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000004444444444444444055555555\n03|004444444444444444444444444444444406666666666666666055555555\n04|006666666666666666666666666666666606666666666666666055555555\n05|006666666666666666666666666666666606666666666666666055555555\n06|006666666666666666666666666666666606666666666666666055555555\n07|006666666666666666666666666666666606666666666666666055555555\n08|006666666666666666666666666666666606666666666666666055555555\n09|006666666666666666666666666666666600000000000000000055555555\n10|506666666666666666666666666666666605555555555555555555555555\n11|506666666666666666666666666666666605555555555555555555555555\n12|506666666666666666666666666666666605555555555555555555555555\n13|506666666666666666666666666666666605555555555555555555555555\n14|506666666666666666666666666666666605555555555555555555555555\n15|506666666666666666666666666666666605555555555555555555555555\n16|506666666666666666666666666666666605555555555555555555555555\n17|506666666666666666666666666666666605555555555555555555555555\n18|506666666666666666666666666666666605555555555555555555555555\n19|506666666666666666666666666666666605555555555555555555555555\n20|500000000000000000000000000000000005555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---handles-bookmarks",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ─────────────────┐            │        \n03|││Buffer mappings:                    │            │        \n04|││                                    │            │        \n05|││Close                    │ q        │            │        \n06|││Go in entry              │ l        │            │        \n07|││Go in entry plus         │ L        │            │        \n08|││Go out of directory      │ h        │            │        \n09|└│Go out of directory plus │ H        │────────────┘        \n10|~│Go to bookmark           │ '        │                     \n11|~│Reset                    │ <BS>     │                     \n12|~│Reveal cwd               │ @        │                     \n13|~│Set bookmark             │ m        │                     \n14|~│Show Help                │ g?       │                     \n15|~│Synchronize              │ =        │                     \n16|~│Trim branch left         │ <        │                     \n17|~│Trim branch right        │ >        │                     \n18|~│                                    │                     \n19|~│Bookmarks:                          │                     \n20|~│                                    │                     \n21|~│a │ tests/dir-files                 │                     \n22|~│b │ Desc                            │                     \n23|~│c │ ~/                              │                     \n24|~│d │ Cwd                             │                     \n25|~│e │ Should use these to adjust width│                     \n26|~│~ │ ~                               │                     \n27|~│                                    │                     \n28|~│(Press `q` to close)                │                     \n29|~└────────────────────────────────────┘                     \n30|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000000000444444444444055555555\n03|004444444444444444444444444444444444440666666666666055555555\n04|006666666666666666666666666666666666660666666666666055555555\n05|006666666666666666666666666666666666660666666666666055555555\n06|006666666666666666666666666666666666660666666666666055555555\n07|006666666666666666666666666666666666660666666666666055555555\n08|006666666666666666666666666666666666660666666666666055555555\n09|006666666666666666666666666666666666660000000000000055555555\n10|506666666666666666666666666666666666660555555555555555555555\n11|506666666666666666666666666666666666660555555555555555555555\n12|506666666666666666666666666666666666660555555555555555555555\n13|506666666666666666666666666666666666660555555555555555555555\n14|506666666666666666666666666666666666660555555555555555555555\n15|506666666666666666666666666666666666660555555555555555555555\n16|506666666666666666666666666666666666660555555555555555555555\n17|506666666666666666666666666666666666660555555555555555555555\n18|506666666666666666666666666666666666660555555555555555555555\n19|506666666666666666666666666666666666660555555555555555555555\n20|506666666666666666666666666666666666660555555555555555555555\n21|506666666666666666666666666666666666660555555555555555555555\n22|506666666666666666666666666666666666660555555555555555555555\n23|506666666666666666666666666666666666660555555555555555555555\n24|506666666666666666666666666666666666660555555555555555555555\n25|506666666666666666666666666666666666660555555555555555555555\n26|506666666666666666666666666666666666660555555555555555555555\n27|506666666666666666666666666666666666660555555555555555555555\n28|506666666666666666666666666666666666660555555555555555555555\n29|500000000000000000000000000000000000000555555555555555555555\n30|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---handles-mappings-without-description",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ────────────┐                 │        \n03|││Buffer mappings:               │                 │        \n04|││                               │                 │        \n05|││Close                    │ q   │                 │        \n06|││Go in entry              │ l   │                 │        \n07|││Go in entry plus         │ L   │                 │        \n08|││Go out of directory      │ h   │                 │        \n09|└│Go out of directory plus │ H   │─────────────────┘        \n10|~│Go to bookmark           │ '   │                          \n11|~│Reset                    │ <BS>│                          \n12|~│Reveal cwd               │ @   │                          \n13|~│Set bookmark             │ m   │                          \n14|~│Show Help                │ g?  │                          \n15|~│Synchronize              │ =   │                          \n16|~│Trim branch left         │ <   │                          \n17|~│Trim branch right        │ >   │                          \n18|~│                               │                          \n19|~│(Press `q` to close)           │                          \n20|~└───────────────────────────────┘                          \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000044444444444444444055555555\n03|004444444444444444444444444444444066666666666666666055555555\n04|006666666666666666666666666666666066666666666666666055555555\n05|006666666666666666666666666666666066666666666666666055555555\n06|006666666666666666666666666666666066666666666666666055555555\n07|006666666666666666666666666666666066666666666666666055555555\n08|006666666666666666666666666666666066666666666666666055555555\n09|006666666666666666666666666666666000000000000000000055555555\n10|506666666666666666666666666666666055555555555555555555555555\n11|506666666666666666666666666666666055555555555555555555555555\n12|506666666666666666666666666666666055555555555555555555555555\n13|506666666666666666666666666666666055555555555555555555555555\n14|506666666666666666666666666666666055555555555555555555555555\n15|506666666666666666666666666666666055555555555555555555555555\n16|506666666666666666666666666666666055555555555555555555555555\n17|506666666666666666666666666666666055555555555555555555555555\n18|506666666666666666666666666666666055555555555555555555555555\n19|506666666666666666666666666666666055555555555555555555555555\n20|500000000000000000000000000000000055555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---handles-non-default-mappings",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ────────────┐                 │        \n03|││Buffer mappings:               │                 │        \n04|││                               │                 │        \n05|││Close                    │ q   │                 │        \n06|││Go in entry plus         │ l   │                 │        \n07|││Go out of directory      │ h   │                 │        \n08|││Go out of directory plus │ H   │                 │        \n09|└│Go to bookmark           │ '   │─────────────────┘        \n10|~│Reset                    │ <BS>│                          \n11|~│Reveal cwd               │ @   │                          \n12|~│Set bookmark             │ m   │                          \n13|~│Show Help                │ g?  │                          \n14|~│Synchronize              │ =   │                          \n15|~│Trim branch left         │ <   │                          \n16|~│Trim branch right        │ >   │                          \n17|~│                               │                          \n18|~│(Press `q` to close)           │                          \n19|~└───────────────────────────────┘                          \n20|~                                                           \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000044444444444444444055555555\n03|004444444444444444444444444444444066666666666666666055555555\n04|006666666666666666666666666666666066666666666666666055555555\n05|006666666666666666666666666666666066666666666666666055555555\n06|006666666666666666666666666666666066666666666666666055555555\n07|006666666666666666666666666666666066666666666666666055555555\n08|006666666666666666666666666666666066666666666666666055555555\n09|006666666666666666666666666666666000000000000000000055555555\n10|506666666666666666666666666666666055555555555555555555555555\n11|506666666666666666666666666666666055555555555555555555555555\n12|506666666666666666666666666666666055555555555555555555555555\n13|506666666666666666666666666666666055555555555555555555555555\n14|506666666666666666666666666666666055555555555555555555555555\n15|506666666666666666666666666666666055555555555555555555555555\n16|506666666666666666666666666666666055555555555555555555555555\n17|506666666666666666666666666666666055555555555555555555555555\n18|506666666666666666666666666666666055555555555555555555555555\n19|500000000000000000000000000000000055555555555555555555555555\n20|555555555555555555555555555555555555555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---opens-relatively-current-window",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌…-files/common ┐┌ .a-dir ──────────────────────┐           \n02|│ .a-dir       ││┌ 'mini.files' help ────────────┐         \n03|│ a-dir        │││Buffer mappings:               │         \n04|│ b-dir        │└│                               │         \n05|│ .a-file      │ │Close                    │ q   │         \n06|│ a-file       │ │Go in entry              │ l   │         \n07|│ A-file-2     │ │Go in entry plus         │ L   │         \n08|│ b-file       │ │Go out of directory      │ h   │         \n09|└───────────────┘ │Go out of directory plus │ H   │         \n10|~                 │Go to bookmark           │ '   │         \n11|~                 │Reset                    │ <BS>│         \n12|~                 │Reveal cwd               │ @   │         \n13|~                 │Set bookmark             │ m   │         \n14|~                 │Show Help                │ g?  │         \n15|~                 │Synchronize              │ =   │         \n16|~                 │Trim branch left         │ <   │         \n17|~                 │Trim branch right        │ >   │         \n18|~                 │                               │         \n19|~                 │(Press `q` to close)           │         \n20|~                 └───────────────────────────────┘         \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111100222222220000000000000000000000033333333333\n02|044444444555555500011111111111111111110000000000000666666666\n03|077777778888888800055555555555555555555555555555550666666666\n04|077777778888888800088888888888888888888888888888880666666666\n05|088888888888888806088888888888888888888888888888880666666666\n06|088888888888888806088888888888888888888888888888880666666666\n07|088888888888888806088888888888888888888888888888880666666666\n08|088888888888888806088888888888888888888888888888880666666666\n09|000000000000000006088888888888888888888888888888880666666666\n10|666666666666666666088888888888888888888888888888880666666666\n11|666666666666666666088888888888888888888888888888880666666666\n12|666666666666666666088888888888888888888888888888880666666666\n13|666666666666666666088888888888888888888888888888880666666666\n14|666666666666666666088888888888888888888888888888880666666666\n15|666666666666666666088888888888888888888888888888880666666666\n16|666666666666666666088888888888888888888888888888880666666666\n17|666666666666666666088888888888888888888888888888880666666666\n18|666666666666666666088888888888888888888888888888880666666666\n19|666666666666666666088888888888888888888888888888880666666666\n20|666666666666666666000000000000000000000000000000000666666666\n21|666666666666666666666666666666666666666666666666666666666666\n22|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---respects-'winborder'-option",
    "content": "--|---------|---------|---------|---------|\n01|╭╭ 'mini.files' help ────────────╮─────╮\n02|││Buffer mappings:               │     │\n03|││                               │     │\n04|││Close                    │ q   │     │\n05|││Go in entry              │ l   │     │\n06|││Go in entry plus         │ L   │     │\n07|││Go out of directory      │ h   │     │\n08|││Go out of directory plus │ H   │     │\n09|╰│Go to bookmark           │ '   │─────╯\n10|~│Reset                    │ <BS>│      \n11|~│Reveal cwd               │ @   │      \n12|~│Set bookmark             │ m   │      \n13|~│Show Help                │ g?  │      \n14|~│Synchronize              │ =   │      \n15|~│Trim branch left         │ <   │      \n16|~│Trim branch right        │ >   │      \n17|~│                               │      \n18|~│(Press `q` to close)           │      \n19|~╰───────────────────────────────╯      \n20|                      1,1           All \n\n--|---------|---------|---------|---------|\n01|0011111111111111111110000000000000000000\n02|0022222222222222222222222222222220222220\n03|0033333333333333333333333333333330333330\n04|0033333333333333333333333333333330333330\n05|0033333333333333333333333333333330333330\n06|0033333333333333333333333333333330333330\n07|0033333333333333333333333333333330333330\n08|0033333333333333333333333333333330333330\n09|0033333333333333333333333333333330000000\n10|4033333333333333333333333333333330444444\n11|4033333333333333333333333333333330444444\n12|4033333333333333333333333333333330444444\n13|4033333333333333333333333333333330444444\n14|4033333333333333333333333333333330444444\n15|4033333333333333333333333333333330444444\n16|4033333333333333333333333333333330444444\n17|4033333333333333333333333333333330444444\n18|4033333333333333333333333333333330444444\n19|4000000000000000000000000000000000444444\n20|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---respects-'winborder'-option-002",
    "content": "--|---------|---------|---------|---------|\n01|╔╔ 'mini.files' help ════════════╗═════╗\n02|║║Buffer mappings:               ║     ║\n03|║║                               ║     ║\n04|║║Close                    │ q   ║     ║\n05|║║Go in entry              │ l   ║     ║\n06|║║Go in entry plus         │ L   ║     ║\n07|║║Go out of directory      │ h   ║     ║\n08|║║Go out of directory plus │ H   ║     ║\n09|╚║Go to bookmark           │ '   ║═════╝\n10|~║Reset                    │ <BS>║      \n11|~║Reveal cwd               │ @   ║      \n12|~║Set bookmark             │ m   ║      \n13|~║Show Help                │ g?  ║      \n14|~║Synchronize              │ =   ║      \n15|~║Trim branch left         │ <   ║      \n16|~║Trim branch right        │ >   ║      \n17|~║                               ║      \n18|~║(Press `q` to close)           ║      \n19|~╚═══════════════════════════════╝      \n20|                      1,1           All \n\n--|---------|---------|---------|---------|\n01|0011111111111111111110000000000000000000\n02|0022222222222222222222222222222220222220\n03|0033333333333333333333333333333330333330\n04|0033333333333333333333333333333330333330\n05|0033333333333333333333333333333330333330\n06|0033333333333333333333333333333330333330\n07|0033333333333333333333333333333330333330\n08|0033333333333333333333333333333330333330\n09|0033333333333333333333333333333330000000\n10|4033333333333333333333333333333330444444\n11|4033333333333333333333333333333330444444\n12|4033333333333333333333333333333330444444\n13|4033333333333333333333333333333330444444\n14|4033333333333333333333333333333330444444\n15|4033333333333333333333333333333330444444\n16|4033333333333333333333333333333330444444\n17|4033333333333333333333333333333330444444\n18|4033333333333333333333333333333330444444\n19|4000000000000000000000000000000000444444\n20|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---respects-'winborder'-option-003",
    "content": "--|---------|---------|---------|---------|\n01|++ 'mini.files' help ------------+-----+\n02|||Buffer mappings:               |     |\n03|||                               |     |\n04|||Close                    │ q   |     |\n05|||Go in entry              │ l   |     |\n06|||Go in entry plus         │ L   |     |\n07|||Go out of directory      │ h   |     |\n08|||Go out of directory plus │ H   |     |\n09|+|Go to bookmark           │ '   |-----+\n10|~|Reset                    │ <BS>|      \n11|~|Reveal cwd               │ @   |      \n12|~|Set bookmark             │ m   |      \n13|~|Show Help                │ g?  |      \n14|~|Synchronize              │ =   |      \n15|~|Trim branch left         │ <   |      \n16|~|Trim branch right        │ >   |      \n17|~|                               |      \n18|~|(Press `q` to close)           |      \n19|~+-------------------------------+      \n20|                      1,1           All \n\n--|---------|---------|---------|---------|\n01|0011111111111111111110000000000000000000\n02|0022222222222222222222222222222220222220\n03|0033333333333333333333333333333330333330\n04|0033333333333333333333333333333330333330\n05|0033333333333333333333333333333330333330\n06|0033333333333333333333333333333330333330\n07|0033333333333333333333333333333330333330\n08|0033333333333333333333333333333330333330\n09|0033333333333333333333333333333330000000\n10|4033333333333333333333333333333330444444\n11|4033333333333333333333333333333330444444\n12|4033333333333333333333333333333330444444\n13|4033333333333333333333333333333330444444\n14|4033333333333333333333333333333330444444\n15|4033333333333333333333333333333330444444\n16|4033333333333333333333333333333330444444\n17|4033333333333333333333333333333330444444\n18|4033333333333333333333333333333330444444\n19|4000000000000000000000000000000000444444\n20|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│┌ 'mini.files' help ────────────┐                 │        \n03|││Buffer mappings:               │                 │        \n04|││                               │                 │        \n05|││Close                    │ q   │                 │        \n06|││Go in entry              │ l   │                 │        \n07|││Go in entry plus         │ L   │                 │        \n08|││Go out of directory      │ h   │                 │        \n09|└│Go out of directory plus │ H   │─────────────────┘        \n10|~│Go to bookmark           │ '   │                          \n11|~│Reset                    │ <BS>│                          \n12|~│Reveal cwd               │ @   │                          \n13|~│Set bookmark             │ m   │                          \n14|~│Show Help                │ g?  │                          \n15|~│Synchronize              │ =   │                          \n16|~│Trim branch left         │ <   │                          \n17|~│Trim branch right        │ >   │                          \n18|~│                               │                          \n19|~│(Press `q` to close)           │                          \n20|~└───────────────────────────────┘                          \n21|~                                                           \n22|                                          1,1           All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|003333333333333333333000000000000044444444444444444055555555\n03|006666666666666666666666666666666044444444444444444055555555\n04|004444444444444444444444444444444066666666666666666055555555\n05|004444444444444444444444444444444044444444444444444055555555\n06|004444444444444444444444444444444044444444444444444055555555\n07|004444444444444444444444444444444044444444444444444055555555\n08|004444444444444444444444444444444044444444444444444055555555\n09|004444444444444444444444444444444000000000000000000055555555\n10|504444444444444444444444444444444055555555555555555555555555\n11|504444444444444444444444444444444055555555555555555555555555\n12|504444444444444444444444444444444055555555555555555555555555\n13|504444444444444444444444444444444055555555555555555555555555\n14|504444444444444444444444444444444055555555555555555555555555\n15|504444444444444444444444444444444055555555555555555555555555\n16|504444444444444444444444444444444055555555555555555555555555\n17|504444444444444444444444444444444055555555555555555555555555\n18|504444444444444444444444444444444055555555555555555555555555\n19|504444444444444444444444444444444055555555555555555555555555\n20|500000000000000000000000000000000055555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---show_help()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/common ─────────────────┐        \n02|│ .a-dir                                          │        \n03|│ a-dir                                           │        \n04|│ b-dir                                           │        \n05|│ .a-file                                         │        \n06|│ a-file                                          │        \n07|│ A-file-2                                        │        \n08|│ b-file                                          │        \n09|└──────────────────────────────────────────────────┘        \n10|~                                                           \n11|~                                                           \n12|~                                                           \n13|~                                                           \n14|~                                                           \n15|~                                                           \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|~                                                           \n20|~                                                           \n21|~                                                           \n22|                                          3,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111111111111111111111111111111100000000000000000022222222\n02|033333333444444444444444444444444444444444444444444055555555\n03|033333334444444444444444444444444444444444444444444055555555\n04|066666667777777777777777777777777777777777777777777055555555\n05|044444444444444444444444444444444444444444444444444055555555\n06|044444444444444444444444444444444444444444444444444055555555\n07|044444444444444444444444444444444444444444444444444055555555\n08|044444444444444444444444444444444444444444444444444055555555\n09|000000000000000000000000000000000000000000000000000055555555\n10|555555555555555555555555555555555555555555555555555555555555\n11|555555555555555555555555555555555555555555555555555555555555\n12|555555555555555555555555555555555555555555555555555555555555\n13|555555555555555555555555555555555555555555555555555555555555\n14|555555555555555555555555555555555555555555555555555555555555\n15|555555555555555555555555555555555555555555555555555555555555\n16|555555555555555555555555555555555555555555555555555555555555\n17|555555555555555555555555555555555555555555555555555555555555\n18|555555555555555555555555555555555555555555555555555555555555\n19|555555555555555555555555555555555555555555555555555555555555\n20|555555555555555555555555555555555555555555555555555555555555\n21|555555555555555555555555555555555555555555555555555555555555\n22|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---synchronize()---can-update-external-file-system-changes",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/temp ───────────────────┐                            \n02|│ aaa                                             │                            \n03|│ subdir                                          │                            \n04|└──────────────────────────────────────────────────┘                            \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              2,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111000000000000000000002222222222222222222222222222\n02|03333344444444444444444444444444444444444444444444405555555555555555555555555555\n03|06666666677777777777777777777777777777777777777777705555555555555555555555555555\n04|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_left()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…/nested/dir-1 ┐┌ dir-11 ──────────────────────────────────────────┐           \n02|│ dir-11       ││ dir-111                                         │           \n03|│ dir-12       │└──────────────────────────────────────────────────┘           \n04|└───────────────┘                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222222000000000000000000000000000000000000000000033333333333\n02|04444444455555550044444444455555555555555555555555555555555555555555066666666666\n03|07777777788888880000000000000000000000000000000000000000000000000000066666666666\n04|00000000000000000666666666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_left()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/nested/dir-1/dir-11 ────┐                            \n02|│ dir-111                                         │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111111111111111111000002222222222222222222222222222\n02|03333333334444444444444444444444444444444444444444405555555555555555555555555555\n03|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n04|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_left()---works-when-in-the-middle-of-the-branch",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ─────────────┐┌ dir-11 ───────┐                        \n02|│ dir-1        ││ dir-11            ││ dir-111      │                        \n03|└───────────────┘│ dir-12            │└───────────────┘                        \n04|~                └────────────────────┘                                         \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000001111111100000000333333333333333333333333\n02|04444444555555550044444444555555555555004444444445555550666666666666666666666666\n03|00000000000000000077777777888888888888000000000000000000666666666666666666666666\n04|66666666666666666000000000000000000000066666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_left()---works-when-in-the-middle-of-the-branch-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…files/nested/dir-1 ┐┌ dir-11 ───────┐                                         \n02|│ dir-11            ││ dir-111      │                                         \n03|│ dir-12            │└───────────────┘                                         \n04|└────────────────────┘                                                          \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111100222222220000000033333333333333333333333333333333333333333\n02|04444444455555555555500444444444555555066666666666666666666666666666666666666666\n03|07777777788888888888800000000000000000066666666666666666666666666666666666666666\n04|00000000000000000000006666666666666666666666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_right()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/nested ─────────────────┐┌ dir-1 ────────┐           \n02|│ dir-1                                           ││ dir-11       │           \n03|└──────────────────────────────────────────────────┘│ dir-12       │           \n04|~                                                   └───────────────┘           \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000000222222200000000033333333333\n02|04444444555555555555555555555555555555555555555555500444444445555555066666666666\n03|00000000000000000000000000000000000000000000000000000777777778888888066666666666\n04|66666666666666666666666666666666666666666666666666660000000000000000066666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_right()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌MOCK_ROOT/tests/dir-files/nested ─────────────────┐                            \n02|│ dir-1                                           │                            \n03|└──────────────────────────────────────────────────┘                            \n04|~                                                                               \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111111111111111111111110000000000000000002222222222222222222222222222\n02|03333333444444444444444444444444444444444444444444405555555555555555555555555555\n03|00000000000000000000000000000000000000000000000000005555555555555555555555555555\n04|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n05|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n06|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n07|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n08|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n09|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n10|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n11|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n12|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n13|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n14|55555555555555555555555555555555555555555555555555555555555555555555555555555555\n15|22222222222222222222222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_right()---works-when-in-the-middle-of-the-branch",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ─────────────┐┌ dir-11 ───────┐                        \n02|│ dir-1        ││ dir-11            ││ dir-111      │                        \n03|└───────────────┘│ dir-12            │└───────────────┘                        \n04|~                └────────────────────┘                                         \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000001111111100000000333333333333333333333333\n02|04444444555555550044444444555555555555004444444445555550666666666666666666666666\n03|00000000000000000077777777888888888888000000000000000000666666666666666666666666\n04|66666666666666666000000000000000000000066666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_files.lua---trim_right()---works-when-in-the-middle-of-the-branch-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|┌…-files/nested ┐┌ dir-1 ─────────────┐                                         \n02|│ dir-1        ││ dir-11            │                                         \n03|└───────────────┘│ dir-12            │                                         \n04|~                └────────────────────┘                                         \n05|~                                                                               \n06|~                                                                               \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|                                                              1,9-7         All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|01111111111111110022222220000000000000033333333333333333333333333333333333333333\n02|04444444555555550044444444555555555555066666666666666666666666666666666666666666\n03|00000000000000000077777777888888888888066666666666666666666666666666666666666666\n04|66666666666666666000000000000000000000066666666666666666666666666666666666666666\n05|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n06|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|33333333333333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---uses-correct-working-directory-for-paths",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~           .git-dir/                   \n11|~           dir-in-git/                 \n12|~           file-in-git                 \n13|~           file-in-git_symlink-source  \n14|:Git add -- .git-dir/                   \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111122222222222222222222222222221\n11|1111111111133333333333333333333333333331\n12|1111111111133333333333333333333333333331\n13|1111111111133333333333333333333333333331\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-explicit-paths",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|~                                                 \n04|~           git-repo/                             \n05|~           mocks/                                \n06|~           deps-confirm                          \n07|~           diff-output                           \n08|~           file                                  \n09|~           file1                                 \n10|~           File2                                 \n11|~           file3                                 \n12|~           help-output                           \n13|~           log-output                            \n14|:Git add -- git-repo/                             \n15|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111222222222222222211111111111111111111111\n05|11111111111333333333333333311111111111111111111111\n06|11111111111333333333333333311111111111111111111111\n07|11111111111333333333333333311111111111111111111111\n08|11111111111333333333333333311111111111111111111111\n09|11111111111333333333333333311111111111111111111111\n10|11111111111333333333333333311111111111111111111111\n11|11111111111333333333333333311111111111111111111111\n12|11111111111333333333333333311111111111111111111111\n13|11111111111333333333333333311111111111111111111111\n14|44444444444444444444444444444444444444444444444444\n15|44444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-explicit-paths-002",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|~                                                 \n04|~                                                 \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|~           git-repo/.git-dir/                    \n11|~           git-repo/dir-in-git/                  \n12|~           git-repo/file-in-git                  \n13|~           git-repo/file-in-git_symlink-source   \n14|:Git add -- git-repo/.git-dir/                    \n15|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|11111111111222222222222222222222222222222222222211\n11|11111111111333333333333333333333333333333333333311\n12|11111111111333333333333333333333333333333333333311\n13|11111111111333333333333333333333333333333333333311\n14|44444444444444444444444444444444444444444444444444\n15|44444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-explicit-paths-003",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|~                                                 \n04|~                                                 \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|~                                                 \n11|~                                                 \n12|~                                                 \n13|~                                                 \n14|:Git add -- git-repo/.git-dir/aa                  \n15|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111\n13|11111111111111111111111111111111111111111111111111\n14|22222222222222222222222222222222222222222222222222\n15|22222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-explicit-paths-004",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|~                                                 \n04|~                                                 \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|~                                                 \n11|~                                file             \n12|~                                file1            \n13|~                                file3            \n14|:Git add -- git-repo/.git-dir/aa file             \n15|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111222222222222222211\n12|11111111111111111111111111111111333333333333333311\n13|11111111111111111111111111111111333333333333333311\n14|44444444444444444444444444444444444444444444444444\n15|44444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-explicit-paths-005",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|~                                                 \n04|~                                                 \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|~                                                 \n11|~                                                 \n12|~                                                 \n13|~                                                 \n14|:Git add -- git-repo/\\                            \n15|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111\n13|11111111111111111111111111111111111111111111111111\n14|22222222222222222222222222222222222222222222222222\n15|22222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-not-supported-command",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                 add                   \n03|~                 blame                 \n04|~                 diff                  \n05|~                 help                  \n06|~                 l                     \n07|~                 log                   \n08|~                 pull                  \n09|~                 push                  \n10|~                 reflog                \n11|~                 show                  \n12|~                 reflog delete         \n13|~                 reflog exists         \n14|~                 reflog expire         \n15|~                 reflog show           \n16|:Git doesnotexist add                   \n17|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111122222222222222221111111\n03|1111111111111111133333333333333331111111\n04|1111111111111111133333333333333331111111\n05|1111111111111111133333333333333331111111\n06|1111111111111111133333333333333331111111\n07|1111111111111111133333333333333331111111\n08|1111111111111111133333333333333331111111\n09|1111111111111111133333333333333331111111\n10|1111111111111111133333333333333331111111\n11|1111111111111111133333333333333331111111\n12|1111111111111111133333333333333331111111\n13|1111111111111111133333333333333331111111\n14|1111111111111111133333333333333331111111\n15|1111111111111111133333333333333331111111\n16|4444444444444444444444444444444444444444\n17|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-not-supported-command-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|~                                       \n16|:Git doesnotexist -                     \n17|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|1111111111111111111111111111111111111111\n16|2222222222222222222222222222222222222222\n17|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-not-supported-command-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                    git-repo/          \n07|~                    mocks/             \n08|~                    deps-confirm       \n09|~                    diff-output        \n10|~                    file               \n11|~                    file1              \n12|~                    File2              \n13|~                    file3              \n14|~                    help-output        \n15|~                    log-output         \n16|:Git doesnotexist -- git-repo/          \n17|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111122222222222222221111\n07|1111111111111111111133333333333333331111\n08|1111111111111111111133333333333333331111\n09|1111111111111111111133333333333333331111\n10|1111111111111111111133333333333333331111\n11|1111111111111111111133333333333333331111\n12|1111111111111111111133333333333333331111\n13|1111111111111111111133333333333333331111\n14|1111111111111111111133333333333333331111\n15|1111111111111111111133333333333333331111\n16|4444444444444444444444444444444444444444\n17|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~         -4                            \n04|~         -6                            \n05|~         -n                            \n06|~         -vv                           \n07|~         --all                         \n08|~         --branches                    \n09|~         --dry-run                     \n10|~         --exec=                       \n11|~         --force-with-lease            \n12|~         --ipv4                        \n13|~         --ipv6                        \n14|~         --no-force-with-lease         \n15|~         --no-signed                   \n16|~         --prune                       \n17|~         --receive-pack=               \n18|~         --signed                      \n19|:Git push -4                            \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111112222222222222222222222211111111\n04|1111111113333333333333333333333311111111\n05|1111111113333333333333333333333311111111\n06|1111111113333333333333333333333311111111\n07|1111111113333333333333333333333311111111\n08|1111111113333333333333333333333311111111\n09|1111111113333333333333333333333311111111\n10|1111111113333333333333333333333311111111\n11|1111111113333333333333333333333311111111\n12|1111111113333333333333333333333311111111\n13|1111111113333333333333333333333311111111\n14|1111111113333333333333333333333311111111\n15|1111111113333333333333333333333311111111\n16|1111111113333333333333333333333311111111\n17|1111111113333333333333333333333311111111\n18|1111111113333333333333333333333311111111\n19|4444444444444444444444444444444444444444\n20|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~            --all                      \n08|~            --branches                 \n09|~            --dry-run                  \n10|~            --exec=                    \n11|~            --force-with-lease         \n12|~            --ipv4                     \n13|~            --ipv6                     \n14|~            --no-force-with-lease      \n15|~            --no-signed                \n16|~            --prune                    \n17|~            --receive-pack=            \n18|~            --signed                   \n19|:Git push -4 --all                      \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111112222222222222222222222211111\n08|1111111111113333333333333333333333311111\n09|1111111111113333333333333333333333311111\n10|1111111111113333333333333333333333311111\n11|1111111111113333333333333333333333311111\n12|1111111111113333333333333333333333311111\n13|1111111111113333333333333333333333311111\n14|1111111111113333333333333333333333311111\n15|1111111111113333333333333333333333311111\n16|1111111111113333333333333333333333311111\n17|1111111111113333333333333333333333311111\n18|1111111111113333333333333333333333311111\n19|4444444444444444444444444444444444444444\n20|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~         --all                         \n08|~         --branches                    \n09|~         --dry-run                     \n10|~         --exec=                       \n11|~         --force-with-lease            \n12|~         --ipv4                        \n13|~         --ipv6                        \n14|~         --no-force-with-lease         \n15|~         --no-signed                   \n16|~         --prune                       \n17|~         --receive-pack=               \n18|~         --signed                      \n19|:Git push --all                         \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111112222222222222222222222211111111\n08|1111111113333333333333333333333311111111\n09|1111111113333333333333333333333311111111\n10|1111111113333333333333333333333311111111\n11|1111111113333333333333333333333311111111\n12|1111111113333333333333333333333311111111\n13|1111111113333333333333333333333311111111\n14|1111111113333333333333333333333311111111\n15|1111111113333333333333333333333311111111\n16|1111111113333333333333333333333311111111\n17|1111111113333333333333333333333311111111\n18|1111111113333333333333333333333311111111\n19|4444444444444444444444444444444444444444\n20|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|~                                       \n16|~                                       \n17|~         --no-force-with-lease         \n18|~         --no-signed                   \n19|:Git push --no-force-with-lease         \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|1111111111111111111111111111111111111111\n16|1111111111111111111111111111111111111111\n17|1111111112222222222222222222222211111111\n18|1111111113333333333333333333333311111111\n19|4444444444444444444444444444444444444444\n20|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options-005",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~         --all                         \n08|~         --branches                    \n09|~         --dry-run                     \n10|~         --exec=                       \n11|~         --force-with-lease            \n12|~         --ipv4                        \n13|~         --ipv6                        \n14|~         --no-force-with-lease         \n15|~         --no-signed                   \n16|~         --prune                       \n17|~         --receive-pack=               \n18|~         --signed                      \n19|:Git push --all origin                  \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111112222222222222222222222211111111\n08|1111111113333333333333333333333311111111\n09|1111111113333333333333333333333311111111\n10|1111111113333333333333333333333311111111\n11|1111111113333333333333333333333311111111\n12|1111111113333333333333333333333311111111\n13|1111111113333333333333333333333311111111\n14|1111111113333333333333333333333311111111\n15|1111111113333333333333333333333311111111\n16|1111111113333333333333333333333311111111\n17|1111111113333333333333333333333311111111\n18|1111111113333333333333333333333311111111\n19|4444444444444444444444444444444444444444\n20|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options-006",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|~                                       \n16|~                                       \n17|~                                       \n18|~                                       \n19|:Git l -                                \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|1111111111111111111111111111111111111111\n16|1111111111111111111111111111111111111111\n17|1111111111111111111111111111111111111111\n18|1111111111111111111111111111111111111111\n19|2222222222222222222222222222222222222222\n20|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-options-007",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~        -v                   \n07|~        --all                \n08|~        --verbose            \n09|:Git add -v                   \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111112222222222222222111111\n07|111111113333333333333333111111\n08|111111113333333333333333111111\n09|444444444444444444444444444444\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-present-command-modifiers",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~                add            \n03|~                blame          \n04|~                diff           \n05|~                help           \n06|~                l              \n07|~                log            \n08|~                pull           \n09|~                push           \n10|~                reflog         \n11|~                show           \n12|~                reflog delete  \n13|~                reflog exists  \n14|~                reflog expire  \n15|~                reflog show    \n16|:vert silent Git add            \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11111111111111112222222222222222\n03|11111111111111113333333333333333\n04|11111111111111113333333333333333\n05|11111111111111113333333333333333\n06|11111111111111113333333333333333\n07|11111111111111113333333333333333\n08|11111111111111113333333333333333\n09|11111111111111113333333333333333\n10|11111111111111113333333333333333\n11|11111111111111113333333333333333\n12|11111111111111113333333333333333\n13|11111111111111113333333333333333\n14|11111111111111113333333333333333\n15|11111111111111113333333333333333\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~        git-repo/                      \n05|~        mocks/                         \n06|~        deps-confirm                   \n07|~        diff-output                    \n08|~        file                           \n09|~        file1                          \n10|~        File2                          \n11|~        file3                          \n12|~        help-output                    \n13|~        log-output                     \n14|:Git add git-repo/                      \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111122222222222222221111111111111111\n05|1111111133333333333333331111111111111111\n06|1111111133333333333333331111111111111111\n07|1111111133333333333333331111111111111111\n08|1111111133333333333333331111111111111111\n09|1111111133333333333333331111111111111111\n10|1111111133333333333333331111111111111111\n11|1111111133333333333333331111111111111111\n12|1111111133333333333333331111111111111111\n13|1111111133333333333333331111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       git-repo/                       \n05|~       mocks/                          \n06|~       deps-confirm                    \n07|~       diff-output                     \n08|~       file                            \n09|~       file1                           \n10|~       File2                           \n11|~       file3                           \n12|~       help-output                     \n13|~       log-output                      \n14|:Git mv git-repo/                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111222222222222222211111111111111111\n05|1111111333333333333333311111111111111111\n06|1111111333333333333333311111111111111111\n07|1111111333333333333333311111111111111111\n08|1111111333333333333333311111111111111111\n09|1111111333333333333333311111111111111111\n10|1111111333333333333333311111111111111111\n11|1111111333333333333333311111111111111111\n12|1111111333333333333333311111111111111111\n13|1111111333333333333333311111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~            git-repo/                  \n05|~            mocks/                     \n06|~            deps-confirm               \n07|~            diff-output                \n08|~            file                       \n09|~            file1                      \n10|~            File2                      \n11|~            file3                      \n12|~            help-output                \n13|~            log-output                 \n14|:Git restore git-repo/                  \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111112222222222222222111111111111\n05|1111111111113333333333333333111111111111\n06|1111111111113333333333333333111111111111\n07|1111111111113333333333333333111111111111\n08|1111111111113333333333333333111111111111\n09|1111111111113333333333333333111111111111\n10|1111111111113333333333333333111111111111\n11|1111111111113333333333333333111111111111\n12|1111111111113333333333333333111111111111\n13|1111111111113333333333333333111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~       git-repo/                       \n05|~       mocks/                          \n06|~       deps-confirm                    \n07|~       diff-output                     \n08|~       file                            \n09|~       file1                           \n10|~       File2                           \n11|~       file3                           \n12|~       help-output                     \n13|~       log-output                      \n14|:Git rm git-repo/                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111222222222222222211111111111111111\n05|1111111333333333333333311111111111111111\n06|1111111333333333333333311111111111111111\n07|1111111333333333333333311111111111111111\n08|1111111333333333333333311111111111111111\n09|1111111333333333333333311111111111111111\n10|1111111333333333333333311111111111111111\n11|1111111333333333333333311111111111111111\n12|1111111333333333333333311111111111111111\n13|1111111333333333333333311111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-005",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~         git-repo/                     \n05|~         mocks/                        \n06|~         deps-confirm                  \n07|~         diff-output                   \n08|~         file                          \n09|~         file1                         \n10|~         File2                         \n11|~         file3                         \n12|~         help-output                   \n13|~         log-output                    \n14|:Git diff git-repo/                     \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111112222222222222222111111111111111\n05|1111111113333333333333333111111111111111\n06|1111111113333333333333333111111111111111\n07|1111111113333333333333333111111111111111\n08|1111111113333333333333333111111111111111\n09|1111111113333333333333333111111111111111\n10|1111111113333333333333333111111111111111\n11|1111111113333333333333333111111111111111\n12|1111111113333333333333333111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-006",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~         git-repo/                     \n05|~         mocks/                        \n06|~         deps-confirm                  \n07|~         diff-output                   \n08|~         file                          \n09|~         file1                         \n10|~         File2                         \n11|~         file3                         \n12|~         help-output                   \n13|~         log-output                    \n14|:Git grep git-repo/                     \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111112222222222222222111111111111111\n05|1111111113333333333333333111111111111111\n06|1111111113333333333333333111111111111111\n07|1111111113333333333333333111111111111111\n08|1111111113333333333333333111111111111111\n09|1111111113333333333333333111111111111111\n10|1111111113333333333333333111111111111111\n11|1111111113333333333333333111111111111111\n12|1111111113333333333333333111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-007",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~        main                           \n13|~        v0.1.0                         \n14|:Git log main                           \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111122222222222222221111111111111111\n13|1111111133333333333333331111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-008",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~         main                          \n13|~         v0.2.0                        \n14|:Git show main                          \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111112222222222222222111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-009",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~           main                        \n13|~           tmp                         \n14|:Git branch main                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111122222222222222221111111111111\n13|1111111111133333333333333331111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-010",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~           git-repo/                   \n05|~           mocks/                      \n06|~           deps-confirm                \n07|~           diff-output                 \n08|~           file                        \n09|~           file1                       \n10|~           File2                       \n11|~           file3                       \n12|~           help-output                 \n13|~           log-output                  \n14|:Git commit git-repo/                   \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111122222222222222221111111111111\n05|1111111111133333333333333331111111111111\n06|1111111111133333333333333331111111111111\n07|1111111111133333333333333331111111111111\n08|1111111111133333333333333331111111111111\n09|1111111111133333333333333331111111111111\n10|1111111111133333333333333331111111111111\n11|1111111111133333333333333331111111111111\n12|1111111111133333333333333331111111111111\n13|1111111111133333333333333331111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-011",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~          main                         \n13|~          tmp2                         \n14|:Git merge main                         \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111222222222222222211111111111111\n13|1111111111333333333333333311111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-012",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~           main                        \n13|~           tmp3                        \n14|:Git rebase main                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111122222222222222221111111111111\n13|1111111111133333333333333331111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-013",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~          main                         \n13|~          v0.3.0                       \n14|:Git reset main                         \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111222222222222222211111111111111\n13|1111111111333333333333333311111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-014",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~           main                        \n13|~           tmp4                        \n14|:Git switch main                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111122222222222222221111111111111\n13|1111111111133333333333333331111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-015",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~        v0.1.0                         \n13|~        v0.2.0                         \n14|:Git tag v0.1.0                         \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111122222222222222221111111111111111\n13|1111111133333333333333331111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-016",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~          origin                       \n13|~          upstream                     \n14|:Git fetch origin                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111222222222222222211111111111111\n13|1111111111333333333333333311111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-017",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~         origin                        \n13|~         upstream2                     \n14|:Git push origin                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111112222222222222222111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-018",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~         origin                        \n13|~         origin2                       \n14|:Git push origin                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111112222222222222222111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-019",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                main                   \n13|~                v0.4.0                 \n14|:Git push origin main                   \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111222222222222222211111111\n13|1111111111111111333333333333333311111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-020",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|:Git push origin v0.4.0                 \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|2222222222222222222222222222222222222222\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-021",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                     main              \n13|~                     v0.4.0            \n14|:Git push origin main main              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111112222222222222222111\n13|1111111111111111111113333333333333333111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-022",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~         origin                        \n13|~         upstream3                     \n14|:Git pull origin                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111112222222222222222111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-023",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~         origin                        \n13|~         origin3                       \n14|:Git pull origin                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111112222222222222222111111111111111\n13|1111111113333333333333333111111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-024",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                main                   \n13|~                v0.5.0                 \n14|:Git pull origin main                   \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111222222222222222211111111\n13|1111111111111111333333333333333311111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-025",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|:Git pull origin v0.5.0                 \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|2222222222222222222222222222222222222222\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-026",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                     main              \n13|~                     v0.5.0            \n14|:Git pull origin main main              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111112222222222222222111\n13|1111111111111111111113333333333333333111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-027",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~             main                      \n13|~             v0.6.0                    \n14|:Git checkout main                      \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111222222222222222211111111111\n13|1111111111111333333333333333311111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-028",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~           author.email                \n13|~           author.name                 \n14|:Git config author.email                \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111122222222222222221111111111111\n13|1111111111133333333333333331111111111111\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-029",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~         git                 \n06|~         everyday            \n07|~         add                 \n08|~         branch              \n09|~         checkout            \n10|~         commit              \n11|~         config              \n12|~         diff                \n13|~         fetch               \n14|~         grep                \n15|~         help                \n16|~         l                   \n17|~         log                 \n18|~         merge               \n19|~         mv                  \n20|~         pull                \n21|~         push                \n22|~         rebase              \n23|~         reset               \n24|~         restore             \n25|~         rm                  \n26|~         show                \n27|~         switch              \n28|~         tag                 \n29|:Git help git                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111222222222222222211111\n06|111111111333333333333333311111\n07|111111111333333333333333311111\n08|111111111333333333333333311111\n09|111111111333333333333333311111\n10|111111111333333333333333311111\n11|111111111333333333333333311111\n12|111111111333333333333333311111\n13|111111111333333333333333311111\n14|111111111333333333333333311111\n15|111111111333333333333333311111\n16|111111111333333333333333311111\n17|111111111333333333333333311111\n18|111111111333333333333333311111\n19|111111111333333333333333311111\n20|111111111333333333333333311111\n21|111111111333333333333333311111\n22|111111111333333333333333311111\n23|111111111333333333333333311111\n24|111111111333333333333333311111\n25|111111111333333333333333311111\n26|111111111333333333333333311111\n27|111111111333333333333333311111\n28|111111111333333333333333311111\n29|444444444444444444444444444444\n30|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommand-targets-030",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~      main                   \n08|~      v0.1.0                 \n09|:Git l main                   \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111222222222222222211111111\n08|111111333333333333333311111111\n09|444444444444444444444444444444\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommands",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~    add                        \n03|~    blame                      \n04|~    diff                       \n05|~    help                       \n06|~    l                          \n07|~    log                        \n08|~    pull                       \n09|~    push                       \n10|~    reflog                     \n11|~    show                       \n12|~    reflog delete              \n13|~    reflog exists              \n14|~    reflog expire              \n15|~    reflog show                \n16|:Git add                        \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11112222222222222222111111111111\n03|11113333333333333333111111111111\n04|11113333333333333333111111111111\n05|11113333333333333333111111111111\n06|11113333333333333333111111111111\n07|11113333333333333333111111111111\n08|11113333333333333333111111111111\n09|11113333333333333333111111111111\n10|11113333333333333333111111111111\n11|11113333333333333333111111111111\n12|11113333333333333333111111111111\n13|11113333333333333333111111111111\n14|11113333333333333333111111111111\n15|11113333333333333333111111111111\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommands-002",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~                               \n03|~                               \n04|~                               \n05|~                               \n06|~                               \n07|~                               \n08|~                               \n09|~                               \n10|~                               \n11|~                               \n12|~                               \n13|~                               \n14|~    l                          \n15|~    log                        \n16|:Git l                          \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11111111111111111111111111111111\n03|11111111111111111111111111111111\n04|11111111111111111111111111111111\n05|11111111111111111111111111111111\n06|11111111111111111111111111111111\n07|11111111111111111111111111111111\n08|11111111111111111111111111111111\n09|11111111111111111111111111111111\n10|11111111111111111111111111111111\n11|11111111111111111111111111111111\n12|11111111111111111111111111111111\n13|11111111111111111111111111111111\n14|11112222222222222222111111111111\n15|11113333333333333333111111111111\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommands-003",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~    add                        \n03|~    blame                      \n04|~    diff                       \n05|~    help                       \n06|~    l                          \n07|~    log                        \n08|~    pull                       \n09|~    push                       \n10|~    reflog                     \n11|~    show                       \n12|~    reflog delete              \n13|~    reflog exists              \n14|~    reflog expire              \n15|~    reflog show                \n16|:Git add -v                     \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11112222222222222222111111111111\n03|11113333333333333333111111111111\n04|11113333333333333333111111111111\n05|11113333333333333333111111111111\n06|11113333333333333333111111111111\n07|11113333333333333333111111111111\n08|11113333333333333333111111111111\n09|11113333333333333333111111111111\n10|11113333333333333333111111111111\n11|11113333333333333333111111111111\n12|11113333333333333333111111111111\n13|11113333333333333333111111111111\n14|11113333333333333333111111111111\n15|11113333333333333333111111111111\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommands-004",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~                               \n03|~                               \n04|~                               \n05|~                               \n06|~                               \n07|~                               \n08|~                               \n09|~                               \n10|~                               \n11|~    reflog                     \n12|~    reflog delete              \n13|~    reflog exists              \n14|~    reflog expire              \n15|~    reflog show                \n16|:Git reflog                     \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11111111111111111111111111111111\n03|11111111111111111111111111111111\n04|11111111111111111111111111111111\n05|11111111111111111111111111111111\n06|11111111111111111111111111111111\n07|11111111111111111111111111111111\n08|11111111111111111111111111111111\n09|11111111111111111111111111111111\n10|11111111111111111111111111111111\n11|11112222222222222222111111111111\n12|11113333333333333333111111111111\n13|11113333333333333333111111111111\n14|11113333333333333333111111111111\n15|11113333333333333333111111111111\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommands-005",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~                               \n03|~                               \n04|~                               \n05|~                               \n06|~                               \n07|~                               \n08|~                               \n09|~                               \n10|~                               \n11|~    reflog                     \n12|~    reflog delete              \n13|~    reflog exists              \n14|~    reflog expire              \n15|~    reflog show                \n16|:Git reflog -v                  \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11111111111111111111111111111111\n03|11111111111111111111111111111111\n04|11111111111111111111111111111111\n05|11111111111111111111111111111111\n06|11111111111111111111111111111111\n07|11111111111111111111111111111111\n08|11111111111111111111111111111111\n09|11111111111111111111111111111111\n10|11111111111111111111111111111111\n11|11112222222222222222111111111111\n12|11113333333333333333111111111111\n13|11113333333333333333111111111111\n14|11113333333333333333111111111111\n15|11113333333333333333111111111111\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua----Git---completion---works-with-subcommands-006",
    "content": "--|---------|---------|---------|--\n01|                                \n02|~                               \n03|~                               \n04|~                               \n05|~                               \n06|~                               \n07|~                               \n08|~                               \n09|~                               \n10|~                               \n11|~                               \n12|~    reflog delete              \n13|~    reflog exists              \n14|~    reflog expire              \n15|~    reflog show                \n16|:Git reflog delete              \n17|                                \n\n--|---------|---------|---------|--\n01|00000000000000000000000000000000\n02|11111111111111111111111111111111\n03|11111111111111111111111111111111\n04|11111111111111111111111111111111\n05|11111111111111111111111111111111\n06|11111111111111111111111111111111\n07|11111111111111111111111111111111\n08|11111111111111111111111111111111\n09|11111111111111111111111111111111\n10|11111111111111111111111111111111\n11|11111111111111111111111111111111\n12|11112222222222222222111111111111\n13|11113333333333333333111111111111\n14|11113333333333333333111111111111\n15|11113333333333333333111111111111\n16|44444444444444444444444444444444\n17|44444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---Tracking---redraws-statusline-when-summary-is-updated",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|main (MM)                     \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|222222222222222222222222222222\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---Tracking---redraws-statusline-when-summary-is-updated-002",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|main (M )                     \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|222222222222222222222222222222\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---Tracking---redraws-statusline-when-summary-is-updated-003",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|main (AM)                     \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|222222222222222222222222222222\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---Tracking---redraws-statusline-when-summary-is-updated-004",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|tmp (??)                      \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|222222222222222222222222222222\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---Tracking---redraws-statusline-when-summary-is-updated-005",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|tmp-2|bisect (!!)             \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111111111111111111111111111111\n09|222222222222222222222222222222\n10|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-`git-log`-output",
    "content": "--|---------|---------|---------|---------|---------|\n01|commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2   \n02|Author: Neo McVim <neo.mcvim@gmail.com>           \n03|Date:   Sat May 4 16:24:15 2024 +0300             \n04|                                                  \n05|    Commit 1                                      \n06|                                                  \n07|    Important details about commit.               \n08|    Even more details about commit.               \n09|                                                  \n10|+-- 23 lines: diff --git a/dir/file-before b/dir/f\n11|                                                  \n12|commit 7264474d3bda16d0098a7f89a4143fe4db3d82cf   \n13|Author: Neo McVim <neo.mcvim@gmail.com>           \n14|Date:   Sat May 4 16:20:29 2024 +0300             \n15|                                                  \n16|    Commit 2                                      \n17|                                                  \n18|+-- 21 lines: diff --git i/dir/file1 w/dir/file1··\n19|~                                                 \n20|~                                                 \n21|~                                                 \n22|~                                                 \n23|~                                                 \n24|~                                                 \n25|~                                                 \n26|~                                                 \n27|~                                                 \n28|~                                                 \n29|~                                                 \n30|~                                                 \n31|~                                                 \n32|~                                                 \n33|~                                                 \n34|~                                                 \n35|~                                                 \n36|~                                                 \n37|~                                                 \n38|~                                                 \n39|~                                                 \n40|~                                                 \n41|~                                                 \n42|~                                                 \n43|~                                                 \n44|~                                                 \n45|~                                                 \n46|~                                                 \n47|~                                                 \n48|~                                                 \n49|~                                                 \n50|~                                                 \n51|~                                                 \n52|~                                                 \n53|~                                                 \n54|~                                                 \n55|~                                                 \n56|~                                                 \n57|~                                                 \n58|~                                                 \n59|~                                                 \n60|~                                                 \n61|~                                                 \n62|~                                                 \n63|~                                                 \n64|~                                                 \n65|~                                                 \n66|~                                                 \n67|~                                                 \n68|~                                                 \n69|~                                                 \n70|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000012222222222222222222222222222222222222222111\n02|00000001333333333345555555555555555555411111111111\n03|00000111666666666666666666666666666661111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|77777777777777777777777777777777777777777777777777\n11|11111111111111111111111111111111111111111111111111\n12|00000012222222222222222222222222222222222222222111\n13|00000001333333333345555555555555555555411111111111\n14|00000111666666666666666666666666666661111111111111\n15|11111111111111111111111111111111111111111111111111\n16|11111111111111111111111111111111111111111111111111\n17|11111111111111111111111111111111111111111111111111\n18|77777777777777777777777777777777777777777777777777\n19|88888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888\n23|88888888888888888888888888888888888888888888888888\n24|88888888888888888888888888888888888888888888888888\n25|88888888888888888888888888888888888888888888888888\n26|88888888888888888888888888888888888888888888888888\n27|88888888888888888888888888888888888888888888888888\n28|88888888888888888888888888888888888888888888888888\n29|88888888888888888888888888888888888888888888888888\n30|88888888888888888888888888888888888888888888888888\n31|88888888888888888888888888888888888888888888888888\n32|88888888888888888888888888888888888888888888888888\n33|88888888888888888888888888888888888888888888888888\n34|88888888888888888888888888888888888888888888888888\n35|88888888888888888888888888888888888888888888888888\n36|88888888888888888888888888888888888888888888888888\n37|88888888888888888888888888888888888888888888888888\n38|88888888888888888888888888888888888888888888888888\n39|88888888888888888888888888888888888888888888888888\n40|88888888888888888888888888888888888888888888888888\n41|88888888888888888888888888888888888888888888888888\n42|88888888888888888888888888888888888888888888888888\n43|88888888888888888888888888888888888888888888888888\n44|88888888888888888888888888888888888888888888888888\n45|88888888888888888888888888888888888888888888888888\n46|88888888888888888888888888888888888888888888888888\n47|88888888888888888888888888888888888888888888888888\n48|88888888888888888888888888888888888888888888888888\n49|88888888888888888888888888888888888888888888888888\n50|88888888888888888888888888888888888888888888888888\n51|88888888888888888888888888888888888888888888888888\n52|88888888888888888888888888888888888888888888888888\n53|88888888888888888888888888888888888888888888888888\n54|88888888888888888888888888888888888888888888888888\n55|88888888888888888888888888888888888888888888888888\n56|88888888888888888888888888888888888888888888888888\n57|88888888888888888888888888888888888888888888888888\n58|88888888888888888888888888888888888888888888888888\n59|88888888888888888888888888888888888888888888888888\n60|88888888888888888888888888888888888888888888888888\n61|88888888888888888888888888888888888888888888888888\n62|88888888888888888888888888888888888888888888888888\n63|88888888888888888888888888888888888888888888888888\n64|88888888888888888888888888888888888888888888888888\n65|88888888888888888888888888888888888888888888888888\n66|88888888888888888888888888888888888888888888888888\n67|88888888888888888888888888888888888888888888888888\n68|88888888888888888888888888888888888888888888888888\n69|88888888888888888888888888888888888888888888888888\n70|99999999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-`git-log`-output-002",
    "content": "--|---------|---------|---------|---------|---------|\n01|commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2   \n02|Author: Neo McVim <neo.mcvim@gmail.com>           \n03|Date:   Sat May 4 16:24:15 2024 +0300             \n04|                                                  \n05|    Commit 1                                      \n06|                                                  \n07|    Important details about commit.               \n08|    Even more details about commit.               \n09|                                                  \n10|diff --git a/dir/file-before b/dir/file-after     \n11|index dd2b945..b81ef66 100644                     \n12|--- a/dir/file-before                             \n13|+++ b/dir/file-after                              \n14|+--- 10 lines: @@ -1,3 +1,3 @@ Hunk header 1······\n15|diff --git a/file b/file                          \n16|index a0a225b..9f8c05f 100644                     \n17|--- a/file                                        \n18|+++ b/file                                        \n19|+---  5 lines: @@ -283,4 +283,4 @@················\n20|                                                  \n21|commit 7264474d3bda16d0098a7f89a4143fe4db3d82cf   \n22|Author: Neo McVim <neo.mcvim@gmail.com>           \n23|Date:   Sat May 4 16:20:29 2024 +0300             \n24|                                                  \n25|    Commit 2                                      \n26|                                                  \n27|diff --git i/dir/file1 w/dir/file1                \n28|index dd2b945..b81ef66 100644                     \n29|--- i/dir/file1                                   \n30|+++ w/dir/file1                                   \n31|+---  8 lines: @@ -247 +247 @@ Hunk header 1······\n32|diff --git a/file.lua b/file.lua                  \n33|index a0a225b..9f8c05f 100644                     \n34|--- a/file.lua                                    \n35|+++ b/file.lua                                    \n36|+---  5 lines: @@ -1,4 +1,4 @@····················\n37|~                                                 \n38|~                                                 \n39|~                                                 \n40|~                                                 \n41|~                                                 \n42|~                                                 \n43|~                                                 \n44|~                                                 \n45|~                                                 \n46|~                                                 \n47|~                                                 \n48|~                                                 \n49|~                                                 \n50|~                                                 \n51|~                                                 \n52|~                                                 \n53|~                                                 \n54|~                                                 \n55|~                                                 \n56|~                                                 \n57|~                                                 \n58|~                                                 \n59|~                                                 \n60|~                                                 \n61|~                                                 \n62|~                                                 \n63|~                                                 \n64|~                                                 \n65|~                                                 \n66|~                                                 \n67|~                                                 \n68|~                                                 \n69|~                                                 \n70|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000012222222222222222222222222222222222222222111\n02|00000001333333333345555555555555555555411111111111\n03|00000111666666666666666666666666666661111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|22222222222222222222222222222222222222222222211111\n11|77777777777777777777777777777111111111111111111111\n12|22222222222222222222211111111111111111111111111111\n13|22222222222222222222111111111111111111111111111111\n14|88888888888888888888888888888888888888888888888888\n15|22222222222222222222222211111111111111111111111111\n16|77777777777777777777777777777111111111111111111111\n17|22222222221111111111111111111111111111111111111111\n18|22222222221111111111111111111111111111111111111111\n19|88888888888888888888888888888888888888888888888888\n20|11111111111111111111111111111111111111111111111111\n21|00000012222222222222222222222222222222222222222111\n22|00000001333333333345555555555555555555411111111111\n23|00000111666666666666666666666666666661111111111111\n24|11111111111111111111111111111111111111111111111111\n25|11111111111111111111111111111111111111111111111111\n26|11111111111111111111111111111111111111111111111111\n27|22222222222222222222222222222222221111111111111111\n28|77777777777777777777777777777111111111111111111111\n29|22222222222222211111111111111111111111111111111111\n30|22222222222222211111111111111111111111111111111111\n31|88888888888888888888888888888888888888888888888888\n32|22222222222222222222222222222222111111111111111111\n33|77777777777777777777777777777111111111111111111111\n34|22222222222222111111111111111111111111111111111111\n35|22222222222222111111111111111111111111111111111111\n36|88888888888888888888888888888888888888888888888888\n37|99999999999999999999999999999999999999999999999999\n38|99999999999999999999999999999999999999999999999999\n39|99999999999999999999999999999999999999999999999999\n40|99999999999999999999999999999999999999999999999999\n41|99999999999999999999999999999999999999999999999999\n42|99999999999999999999999999999999999999999999999999\n43|99999999999999999999999999999999999999999999999999\n44|99999999999999999999999999999999999999999999999999\n45|99999999999999999999999999999999999999999999999999\n46|99999999999999999999999999999999999999999999999999\n47|99999999999999999999999999999999999999999999999999\n48|99999999999999999999999999999999999999999999999999\n49|99999999999999999999999999999999999999999999999999\n50|99999999999999999999999999999999999999999999999999\n51|99999999999999999999999999999999999999999999999999\n52|99999999999999999999999999999999999999999999999999\n53|99999999999999999999999999999999999999999999999999\n54|99999999999999999999999999999999999999999999999999\n55|99999999999999999999999999999999999999999999999999\n56|99999999999999999999999999999999999999999999999999\n57|99999999999999999999999999999999999999999999999999\n58|99999999999999999999999999999999999999999999999999\n59|99999999999999999999999999999999999999999999999999\n60|99999999999999999999999999999999999999999999999999\n61|99999999999999999999999999999999999999999999999999\n62|99999999999999999999999999999999999999999999999999\n63|99999999999999999999999999999999999999999999999999\n64|99999999999999999999999999999999999999999999999999\n65|99999999999999999999999999999999999999999999999999\n66|99999999999999999999999999999999999999999999999999\n67|99999999999999999999999999999999999999999999999999\n68|99999999999999999999999999999999999999999999999999\n69|99999999999999999999999999999999999999999999999999\n70|::::::::::::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-`git-log`-output-003",
    "content": "--|---------|---------|---------|---------|---------|\n01|commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2   \n02|Author: Neo McVim <neo.mcvim@gmail.com>           \n03|Date:   Sat May 4 16:24:15 2024 +0300             \n04|                                                  \n05|    Commit 1                                      \n06|                                                  \n07|    Important details about commit.               \n08|    Even more details about commit.               \n09|                                                  \n10|diff --git a/dir/file-before b/dir/file-after     \n11|index dd2b945..b81ef66 100644                     \n12|--- a/dir/file-before                             \n13|+++ b/dir/file-after                              \n14|@@ -1,3 +1,3 @@ Hunk header 1                     \n15|+----  4 lines: Line 1····························\n16|@@ -317,4 +317,4 @@                               \n17|+----  4 lines: Line 11···························\n18|diff --git a/file b/file                          \n19|index a0a225b..9f8c05f 100644                     \n20|--- a/file                                        \n21|+++ b/file                                        \n22|@@ -283,4 +283,4 @@                               \n23|+----  4 lines: +++·······························\n24|                                                  \n25|commit 7264474d3bda16d0098a7f89a4143fe4db3d82cf   \n26|Author: Neo McVim <neo.mcvim@gmail.com>           \n27|Date:   Sat May 4 16:20:29 2024 +0300             \n28|                                                  \n29|    Commit 2                                      \n30|                                                  \n31|diff --git i/dir/file1 w/dir/file1                \n32|index dd2b945..b81ef66 100644                     \n33|--- i/dir/file1                                   \n34|+++ w/dir/file1                                   \n35|@@ -247 +247 @@ Hunk header 1                     \n36|+----  2 lines: -      Previous line 02···········\n37|@@ -317,4 +317,4 @@                               \n38|+----  4 lines: Line 011··························\n39|diff --git a/file.lua b/file.lua                  \n40|index a0a225b..9f8c05f 100644                     \n41|--- a/file.lua                                    \n42|+++ b/file.lua                                    \n43|@@ -1,4 +1,4 @@                                   \n44|+----  4 lines: +++·······························\n45|~                                                 \n46|~                                                 \n47|~                                                 \n48|~                                                 \n49|~                                                 \n50|~                                                 \n51|~                                                 \n52|~                                                 \n53|~                                                 \n54|~                                                 \n55|~                                                 \n56|~                                                 \n57|~                                                 \n58|~                                                 \n59|~                                                 \n60|~                                                 \n61|~                                                 \n62|~                                                 \n63|~                                                 \n64|~                                                 \n65|~                                                 \n66|~                                                 \n67|~                                                 \n68|~                                                 \n69|~                                                 \n70|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000012222222222222222222222222222222222222222111\n02|00000001333333333345555555555555555555411111111111\n03|00000111666666666666666666666666666661111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|22222222222222222222222222222222222222222222211111\n11|77777777777777777777777777777111111111111111111111\n12|22222222222222222222211111111111111111111111111111\n13|22222222222222222222111111111111111111111111111111\n14|77777777777777777777777777777111111111111111111111\n15|88888888888888888888888888888888888888888888888888\n16|77777777777777777771111111111111111111111111111111\n17|88888888888888888888888888888888888888888888888888\n18|22222222222222222222222211111111111111111111111111\n19|77777777777777777777777777777111111111111111111111\n20|22222222221111111111111111111111111111111111111111\n21|22222222221111111111111111111111111111111111111111\n22|77777777777777777771111111111111111111111111111111\n23|88888888888888888888888888888888888888888888888888\n24|11111111111111111111111111111111111111111111111111\n25|00000012222222222222222222222222222222222222222111\n26|00000001333333333345555555555555555555411111111111\n27|00000111666666666666666666666666666661111111111111\n28|11111111111111111111111111111111111111111111111111\n29|11111111111111111111111111111111111111111111111111\n30|11111111111111111111111111111111111111111111111111\n31|22222222222222222222222222222222221111111111111111\n32|77777777777777777777777777777111111111111111111111\n33|22222222222222211111111111111111111111111111111111\n34|22222222222222211111111111111111111111111111111111\n35|77777777777777777777777777777111111111111111111111\n36|88888888888888888888888888888888888888888888888888\n37|77777777777777777771111111111111111111111111111111\n38|88888888888888888888888888888888888888888888888888\n39|22222222222222222222222222222222111111111111111111\n40|77777777777777777777777777777111111111111111111111\n41|22222222222222111111111111111111111111111111111111\n42|22222222222222111111111111111111111111111111111111\n43|77777777777777711111111111111111111111111111111111\n44|88888888888888888888888888888888888888888888888888\n45|99999999999999999999999999999999999999999999999999\n46|99999999999999999999999999999999999999999999999999\n47|99999999999999999999999999999999999999999999999999\n48|99999999999999999999999999999999999999999999999999\n49|99999999999999999999999999999999999999999999999999\n50|99999999999999999999999999999999999999999999999999\n51|99999999999999999999999999999999999999999999999999\n52|99999999999999999999999999999999999999999999999999\n53|99999999999999999999999999999999999999999999999999\n54|99999999999999999999999999999999999999999999999999\n55|99999999999999999999999999999999999999999999999999\n56|99999999999999999999999999999999999999999999999999\n57|99999999999999999999999999999999999999999999999999\n58|99999999999999999999999999999999999999999999999999\n59|99999999999999999999999999999999999999999999999999\n60|99999999999999999999999999999999999999999999999999\n61|99999999999999999999999999999999999999999999999999\n62|99999999999999999999999999999999999999999999999999\n63|99999999999999999999999999999999999999999999999999\n64|99999999999999999999999999999999999999999999999999\n65|99999999999999999999999999999999999999999999999999\n66|99999999999999999999999999999999999999999999999999\n67|99999999999999999999999999999999999999999999999999\n68|99999999999999999999999999999999999999999999999999\n69|99999999999999999999999999999999999999999999999999\n70|::::::::::::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-`git-log`-output-004",
    "content": "--|---------|---------|---------|---------|---------|\n01|commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2   \n02|Author: Neo McVim <neo.mcvim@gmail.com>           \n03|Date:   Sat May 4 16:24:15 2024 +0300             \n04|                                                  \n05|    Commit 1                                      \n06|                                                  \n07|    Important details about commit.               \n08|    Even more details about commit.               \n09|                                                  \n10|diff --git a/dir/file-before b/dir/file-after     \n11|index dd2b945..b81ef66 100644                     \n12|--- a/dir/file-before                             \n13|+++ b/dir/file-after                              \n14|@@ -1,3 +1,3 @@ Hunk header 1                     \n15|       Line 1                                     \n16|-      Previous line 2                            \n17|+      Current line 2                             \n18|     Line 3                                       \n19|@@ -317,4 +317,4 @@                               \n20| Line 11                                          \n21|+Added line 12                                    \n22|+Added line 13                                    \n23|                                                  \n24|diff --git a/file b/file                          \n25|index a0a225b..9f8c05f 100644                     \n26|--- a/file                                        \n27|+++ b/file                                        \n28|@@ -283,4 +283,4 @@                               \n29| +++                                              \n30|-+++ Deleted line 112                             \n31|---- Deleted line 113                             \n32| ---                                              \n33|                                                  \n34|commit 7264474d3bda16d0098a7f89a4143fe4db3d82cf   \n35|Author: Neo McVim <neo.mcvim@gmail.com>           \n36|Date:   Sat May 4 16:20:29 2024 +0300             \n37|                                                  \n38|    Commit 2                                      \n39|                                                  \n40|diff --git i/dir/file1 w/dir/file1                \n41|index dd2b945..b81ef66 100644                     \n42|--- i/dir/file1                                   \n43|+++ w/dir/file1                                   \n44|@@ -247 +247 @@ Hunk header 1                     \n45|-      Previous line 02                           \n46|+      Current line 02                            \n47|@@ -317,4 +317,4 @@                               \n48| Line 011                                         \n49|+Added line 012                                   \n50|+Added line 013                                   \n51|                                                  \n52|diff --git a/file.lua b/file.lua                  \n53|index a0a225b..9f8c05f 100644                     \n54|--- a/file.lua                                    \n55|+++ b/file.lua                                    \n56|@@ -1,4 +1,4 @@                                   \n57| +++                                              \n58|-+++ local a = 'deleted'                          \n59|---- local b = 'lines'                            \n60| ---                                              \n61|~                                                 \n62|~                                                 \n63|~                                                 \n64|~                                                 \n65|~                                                 \n66|~                                                 \n67|~                                                 \n68|~                                                 \n69|~                                                 \n70|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000012222222222222222222222222222222222222222111\n02|00000001333333333345555555555555555555411111111111\n03|00000111666666666666666666666666666661111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|22222222222222222222222222222222222222222222211111\n11|77777777777777777777777777777111111111111111111111\n12|22222222222222222222211111111111111111111111111111\n13|22222222222222222222111111111111111111111111111111\n14|77777777777777777777777777777111111111111111111111\n15|11111111111111111111111111111111111111111111111111\n16|88888888888888888888881111111111111111111111111111\n17|33333333333333333333311111111111111111111111111111\n18|11111111111111111111111111111111111111111111111111\n19|77777777777777777771111111111111111111111111111111\n20|11111111111111111111111111111111111111111111111111\n21|33333333333333111111111111111111111111111111111111\n22|33333333333333111111111111111111111111111111111111\n23|11111111111111111111111111111111111111111111111111\n24|22222222222222222222222211111111111111111111111111\n25|77777777777777777777777777777111111111111111111111\n26|22222222221111111111111111111111111111111111111111\n27|22222222221111111111111111111111111111111111111111\n28|77777777777777777771111111111111111111111111111111\n29|11111111111111111111111111111111111111111111111111\n30|88888888888888888888811111111111111111111111111111\n31|88888888888888888888811111111111111111111111111111\n32|11111111111111111111111111111111111111111111111111\n33|11111111111111111111111111111111111111111111111111\n34|00000012222222222222222222222222222222222222222111\n35|00000001333333333345555555555555555555411111111111\n36|00000111666666666666666666666666666661111111111111\n37|11111111111111111111111111111111111111111111111111\n38|11111111111111111111111111111111111111111111111111\n39|11111111111111111111111111111111111111111111111111\n40|22222222222222222222222222222222221111111111111111\n41|77777777777777777777777777777111111111111111111111\n42|22222222222222211111111111111111111111111111111111\n43|22222222222222211111111111111111111111111111111111\n44|77777777777777777777777777777111111111111111111111\n45|88888888888888888888888111111111111111111111111111\n46|33333333333333333333331111111111111111111111111111\n47|77777777777777777771111111111111111111111111111111\n48|11111111111111111111111111111111111111111111111111\n49|33333333333333311111111111111111111111111111111111\n50|33333333333333311111111111111111111111111111111111\n51|11111111111111111111111111111111111111111111111111\n52|22222222222222222222222222222222111111111111111111\n53|77777777777777777777777777777111111111111111111111\n54|22222222222222111111111111111111111111111111111111\n55|22222222222222111111111111111111111111111111111111\n56|77777777777777711111111111111111111111111111111111\n57|11111111111111111111111111111111111111111111111111\n58|88888888888888888888888811111111111111111111111111\n59|88888888888888888888881111111111111111111111111111\n60|11111111111111111111111111111111111111111111111111\n61|99999999999999999999999999999999999999999999999999\n62|99999999999999999999999999999999999999999999999999\n63|99999999999999999999999999999999999999999999999999\n64|99999999999999999999999999999999999999999999999999\n65|99999999999999999999999999999999999999999999999999\n66|99999999999999999999999999999999999999999999999999\n67|99999999999999999999999999999999999999999999999999\n68|99999999999999999999999999999999999999999999999999\n69|99999999999999999999999999999999999999999999999999\n70|::::::::::::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-diff-patch",
    "content": "--|---------|---------|---------|---------|---------|\n01|+-- 23 lines: diff --git a/dir/file1 b/dir/file1··\n02|~                                                 \n03|~                                                 \n04|~                                                 \n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|~                                                 \n11|~                                                 \n12|~                                                 \n13|~                                                 \n14|~                                                 \n15|~                                                 \n16|~                                                 \n17|~                                                 \n18|~                                                 \n19|~                                                 \n20|~                                                 \n21|~                                                 \n22|~                                                 \n23|~                                                 \n24|~                                                 \n25|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|11111111111111111111111111111111111111111111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111\n13|11111111111111111111111111111111111111111111111111\n14|11111111111111111111111111111111111111111111111111\n15|11111111111111111111111111111111111111111111111111\n16|11111111111111111111111111111111111111111111111111\n17|11111111111111111111111111111111111111111111111111\n18|11111111111111111111111111111111111111111111111111\n19|11111111111111111111111111111111111111111111111111\n20|11111111111111111111111111111111111111111111111111\n21|11111111111111111111111111111111111111111111111111\n22|11111111111111111111111111111111111111111111111111\n23|11111111111111111111111111111111111111111111111111\n24|11111111111111111111111111111111111111111111111111\n25|22222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-diff-patch-002",
    "content": "--|---------|---------|---------|---------|---------|\n01|diff --git a/dir/file1 b/dir/file1                \n02|index dd2b945..b81ef66 100644                     \n03|--- a/dir/file1                                   \n04|+++ b/dir/file1                                   \n05|+--- 10 lines: @@ -247,3 +247,3 @@ Hunk header 1··\n06|diff --git a/file b/file                          \n07|index a0a225b..9f8c05f 100644                     \n08|--- a/file                                        \n09|+++ b/file                                        \n10|+---  5 lines: @@ -283,4 +283,4 @@················\n11|~                                                 \n12|~                                                 \n13|~                                                 \n14|~                                                 \n15|~                                                 \n16|~                                                 \n17|~                                                 \n18|~                                                 \n19|~                                                 \n20|~                                                 \n21|~                                                 \n22|~                                                 \n23|~                                                 \n24|~                                                 \n25|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000001111111111111111\n02|22222222222222222222222222222111111111111111111111\n03|00000000000000011111111111111111111111111111111111\n04|00000000000000011111111111111111111111111111111111\n05|33333333333333333333333333333333333333333333333333\n06|00000000000000000000000011111111111111111111111111\n07|22222222222222222222222222222111111111111111111111\n08|00000000001111111111111111111111111111111111111111\n09|00000000001111111111111111111111111111111111111111\n10|33333333333333333333333333333333333333333333333333\n11|44444444444444444444444444444444444444444444444444\n12|44444444444444444444444444444444444444444444444444\n13|44444444444444444444444444444444444444444444444444\n14|44444444444444444444444444444444444444444444444444\n15|44444444444444444444444444444444444444444444444444\n16|44444444444444444444444444444444444444444444444444\n17|44444444444444444444444444444444444444444444444444\n18|44444444444444444444444444444444444444444444444444\n19|44444444444444444444444444444444444444444444444444\n20|44444444444444444444444444444444444444444444444444\n21|44444444444444444444444444444444444444444444444444\n22|44444444444444444444444444444444444444444444444444\n23|44444444444444444444444444444444444444444444444444\n24|44444444444444444444444444444444444444444444444444\n25|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-diff-patch-003",
    "content": "--|---------|---------|---------|---------|---------|\n01|diff --git a/dir/file1 b/dir/file1                \n02|index dd2b945..b81ef66 100644                     \n03|--- a/dir/file1                                   \n04|+++ b/dir/file1                                   \n05|@@ -247,3 +247,3 @@ Hunk header 1                 \n06|+----  4 lines: Line 1····························\n07|@@ -317,4 +317,4 @@                               \n08|+----  4 lines: Line 11···························\n09|diff --git a/file b/file                          \n10|index a0a225b..9f8c05f 100644                     \n11|--- a/file                                        \n12|+++ b/file                                        \n13|@@ -283,4 +283,4 @@                               \n14|+----  4 lines: +++·······························\n15|~                                                 \n16|~                                                 \n17|~                                                 \n18|~                                                 \n19|~                                                 \n20|~                                                 \n21|~                                                 \n22|~                                                 \n23|~                                                 \n24|~                                                 \n25|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000001111111111111111\n02|22222222222222222222222222222111111111111111111111\n03|00000000000000011111111111111111111111111111111111\n04|00000000000000011111111111111111111111111111111111\n05|22222222222222222222222222222222211111111111111111\n06|33333333333333333333333333333333333333333333333333\n07|22222222222222222221111111111111111111111111111111\n08|33333333333333333333333333333333333333333333333333\n09|00000000000000000000000011111111111111111111111111\n10|22222222222222222222222222222111111111111111111111\n11|00000000001111111111111111111111111111111111111111\n12|00000000001111111111111111111111111111111111111111\n13|22222222222222222221111111111111111111111111111111\n14|33333333333333333333333333333333333333333333333333\n15|44444444444444444444444444444444444444444444444444\n16|44444444444444444444444444444444444444444444444444\n17|44444444444444444444444444444444444444444444444444\n18|44444444444444444444444444444444444444444444444444\n19|44444444444444444444444444444444444444444444444444\n20|44444444444444444444444444444444444444444444444444\n21|44444444444444444444444444444444444444444444444444\n22|44444444444444444444444444444444444444444444444444\n23|44444444444444444444444444444444444444444444444444\n24|44444444444444444444444444444444444444444444444444\n25|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_git.lua---diff_foldexpr()---works-in-diff-patch-004",
    "content": "--|---------|---------|---------|---------|---------|\n01|diff --git a/dir/file1 b/dir/file1                \n02|index dd2b945..b81ef66 100644                     \n03|--- a/dir/file1                                   \n04|+++ b/dir/file1                                   \n05|@@ -247,3 +247,3 @@ Hunk header 1                 \n06|       Line 1                                     \n07|-      Previous line 2                            \n08|+      Current line 2                             \n09|     Line 3                                       \n10|@@ -317,4 +317,4 @@                               \n11| Line 11                                          \n12|+Added line 12                                    \n13|+Added line 13                                    \n14|                                                  \n15|diff --git a/file b/file                          \n16|index a0a225b..9f8c05f 100644                     \n17|--- a/file                                        \n18|+++ b/file                                        \n19|@@ -283,4 +283,4 @@                               \n20| +++                                              \n21|-+++ Deleted line 112                             \n22|---- Deleted line 113                             \n23| ---                                              \n24|~                                                 \n25|                                1,1           All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000001111111111111111\n02|22222222222222222222222222222111111111111111111111\n03|00000000000000011111111111111111111111111111111111\n04|00000000000000011111111111111111111111111111111111\n05|22222222222222222222222222222222211111111111111111\n06|11111111111111111111111111111111111111111111111111\n07|33333333333333333333331111111111111111111111111111\n08|44444444444444444444411111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|22222222222222222221111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111\n12|44444444444444111111111111111111111111111111111111\n13|44444444444444111111111111111111111111111111111111\n14|11111111111111111111111111111111111111111111111111\n15|00000000000000000000000011111111111111111111111111\n16|22222222222222222222222222222111111111111111111111\n17|00000000001111111111111111111111111111111111111111\n18|00000000001111111111111111111111111111111111111111\n19|22222222222222222221111111111111111111111111111111\n20|11111111111111111111111111111111111111111111111111\n21|33333333333333333333311111111111111111111111111111\n22|33333333333333333333311111111111111111111111111111\n23|11111111111111111111111111111111111111111111111111\n24|55555555555555555555555555555555555555555555555555\n25|66666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Auto-enable---does-not-enable-in-not-proper-buffers",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[Scratch] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Auto-enable---makes-`-edit`-work",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|<terns_file 1,1\n10|<en            \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Auto-enable---makes-`-edit`-work-002",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|<terns_file 1,1\n10|<en            \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Auto-enable---works",
    "content": "--|---------|-----\n01|22abcd22       \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Autocommands---resets-on-color-scheme-change",
    "content": "--|---------|---------|---------|\n01|xxaaaxx        │aaa           \n02|~              │~             \n03|~              │~             \n04|~              │~             \n05|~              │~             \n06|~              │~             \n07|~              │~             \n08|~              │~             \n09|[No Name] 1,1   [No Name] 1,1 \n10|                              \n\n--|---------|---------|---------|\n01|001110000000000233344444444444\n02|555555555555555266666666666666\n03|555555555555555266666666666666\n04|555555555555555266666666666666\n05|555555555555555266666666666666\n06|555555555555555266666666666666\n07|555555555555555266666666666666\n08|555555555555555266666666666666\n09|777777777777777788888888888888\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Autocommands---resets-on-color-scheme-change-002",
    "content": "--|---------|---------|---------|\n01|xxaaaxx        │aaa           \n02|~              │~             \n03|~              │~             \n04|~              │~             \n05|~              │~             \n06|~              │~             \n07|~              │~             \n08|~              │~             \n09|[No Name] 1,1   [No Name] 1,1 \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000100000000000000\n02|222222222222222122222222222222\n03|222222222222222122222222222222\n04|222222222222222122222222222222\n05|222222222222222122222222222222\n06|222222222222222122222222222222\n07|222222222222222122222222222222\n08|222222222222222122222222222222\n09|333333333333333344444444444444\n10|111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Autocommands---resets-on-color-scheme-change-003",
    "content": "--|---------|---------|---------|\n01|xxaaaxx        │aaa           \n02|~              │~             \n03|~              │~             \n04|~              │~             \n05|~              │~             \n06|~              │~             \n07|~              │~             \n08|~              │~             \n09|[No Name] 1,1   [No Name] 1,1 \n10|                              \n\n--|---------|---------|---------|\n01|001110000000000211100000000000\n02|333333333333333233333333333333\n03|333333333333333233333333333333\n04|333333333333333233333333333333\n05|333333333333333233333333333333\n06|333333333333333233333333333333\n07|333333333333333233333333333333\n08|333333333333333233333333333333\n09|444444444444444455555555555555\n10|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-array-`pattern`",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxefgh         \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|001111000000000\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-array-`pattern`-002",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxefgh         \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|000000000000000\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-callable-`group`",
    "content": "--|---------|-----\n01|xxabcd         \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-callable-`pattern`",
    "content": "--|---------|-----\n01|xxabcd         \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-frontier-pattern-in-`pattern`",
    "content": "--|---------|-----\n01|abcd           \n02|xabcd          \n03|abcdx          \n04|xabcdx         \n05| abcd          \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|100001111111111\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-return-`nil`-`group`-to-not-highlight",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|xxabcd         \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|000000000000000\n03|001111000000000\n04|000000000000000\n05|001111000000000\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-return-`nil`-`pattern`-to-not-highlight",
    "content": "--|---------|-----\n01|xxabcd         \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-return-`nil`-`pattern`-to-not-highlight-002",
    "content": "--|---------|-----\n01|xxabcd         \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-submatch-in-`pattern`",
    "content": "--|---------|-----\n01|abcd           \n02|xabcd          \n03|xxabcd         \n04|xxabcdxx       \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|001100000000000\n04|001100000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-submatch-in-`pattern`-002",
    "content": "--|---------|-----\n01|abcd           \n02|xabcd          \n03|xxabcd         \n04|xxabcdxx       \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111111111111\n02|100111111111111\n03|110011111111111\n04|110011111111111\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-submatch-in-`pattern`-003",
    "content": "--|---------|-----\n01|abcd           \n02|xabcd          \n03|xxabcd         \n04|xxabcdxx       \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001100000000000\n02|000110000000000\n03|000011000000000\n04|000011000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-submatch-in-`pattern`-004",
    "content": "--|---------|-----\n01|abcd           \n02|xabcd          \n03|xxabcd         \n04|xxabcdxx       \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|100001111111111\n03|110000111111111\n04|110000111111111\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---allows-submatch-in-`pattern`-005",
    "content": "--|---------|-----\n01|abcd           \n02|xabcd          \n03|xxabcd         \n04|xxabcdxx       \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|001100000000000\n04|001100000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---respects-`extmark_opts.priority`",
    "content": "--|---------|-----\n01|abcd           \n02|abcd           \n03|abcd           \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|000011111111111\n03|000011111111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---respects-`extmark_opts.priority`-002",
    "content": "--|---------|-----\n01|abcd           \n02|abcd           \n03|abcd           \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|000011111111111\n03|222211111111111\n04|333333333333333\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---respects-`extmark_opts.priority`-003",
    "content": "--|---------|-----\n01|abcd           \n02|abcd           \n03|abcd           \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|000011111111111\n03|000011111111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---respects-`extmark_opts`",
    "content": "--|---------|-----\n01|abcd           \n02|efgh           \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|221111111111111\n03|333333333333333\n04|333333333333333\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---Highlighters---silently-skips-wrong-entries",
    "content": "--|---------|-----\n01|xxabcd         \n02|aaa            \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|000000000000000\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---disable()---works",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---disable()---works-002",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---disable()---works-in-not-current-buffer",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---disable()---works-in-not-current-buffer-002",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---does-not-flicker-during-text-insert",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,5  \n10|-- INSERT --   \n\n--|---------|-----\n01|000011111111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---does-not-flicker-during-text-insert-002",
    "content": "--|---------|-----\n01|abcd abcd      \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,10 \n10|-- INSERT --   \n\n--|---------|-----\n01|000011111111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---does-not-flicker-during-text-insert-003",
    "content": "--|---------|-----\n01|abcd abcd      \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,10 \n10|-- INSERT --   \n\n--|---------|-----\n01|000010000111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-buffer-enter",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-buffer-enter-002",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-delete-of-line-with-match",
    "content": "--|---------|-----\n01|abcd      Hello\n02|xxx            \n03|xxx            \n04|abcd      Hello\n05|xxx            \n06|xxx            \n07|abcd      Hello\n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000011111\n02|000000000000000\n03|000000000000000\n04|000000000011111\n05|000000000000000\n06|000000000000000\n07|000000000011111\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-delete-of-line-with-match-002",
    "content": "--|---------|-----\n01|xxx            \n02|xxx            \n03|abcd      Hello\n04|xxx            \n05|xxx            \n06|abcd      Hello\n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000011111\n04|000000000000000\n05|000000000000000\n06|000000000011111\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-delete-of-line-with-match-003",
    "content": "--|---------|-----\n01|xxx            \n02|xxx            \n03|xxx            \n04|xxx            \n05|abcd      Hello\n06|~              \n07|~              \n08|~              \n09|[No Name] 3,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000011111\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-delete-of-line-with-match-004",
    "content": "--|---------|-----\n01|xxx            \n02|xxx            \n03|xxx            \n04|xxx            \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 4,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-filetype-change",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-filetype-change-002",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-filetype-change-003",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-text-change",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,5  \n10|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-text-change-002",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,5  \n10|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-text-change-003",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,5  \n10|-- INSERT --   \n\n--|---------|-----\n01|000011111111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-text-change-004",
    "content": "--|---------|-----\n01|ABCD           \n02|abcd           \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,5  \n10|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-text-change-005",
    "content": "--|---------|-----\n01|ABCD           \n02|abcd           \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,5  \n10|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|111100000000000\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-window-scroll",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|xxabcdxx       \n03|xxabcdxx       \n04|xxabcdxx       \n05|xxabcdxx       \n06|xxabcdxx       \n07|xxabcdxx       \n08|xxabcdxx       \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-window-scroll-002",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|xxabcdxx       \n03|xxabcdxx       \n04|xxabcdxx       \n05|xxabcdxx       \n06|xxabcdxx       \n07|xxabcdxx       \n08|xxabcdxx       \n09|[No Name] 3,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|001111000000000\n03|001111000000000\n04|001111000000000\n05|001111000000000\n06|001111000000000\n07|001111000000000\n08|001111000000000\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-window-scroll-003",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|xxabcdxx       \n03|xxabcdxx       \n04|xxabcdxx       \n05|xxabcdxx       \n06|xxabcdxx       \n07|xxabcdxx       \n08|xxabcdxx       \n09|[No Name] 3,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|001111000000000\n03|001111000000000\n04|001111000000000\n05|001111000000000\n06|001111000000000\n07|001111000000000\n08|001111000000000\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---reacts-to-window-scroll-004",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|xxabcdxx       \n03|xxabcdxx       \n04|xxabcdxx       \n05|xxabcdxx       \n06|xxabcdxx       \n07|xxabcdxx       \n08|xxabcdxx       \n09|[No Name] 4,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|001111000000000\n03|001111000000000\n04|001111000000000\n05|001111000000000\n06|001111000000000\n07|001111000000000\n08|000000000000000\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---respects-`vim.b.minihipatterns_config`",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---respects-`vim.b.minihipatterns_config`-002",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---respects-`vim.b.minihipatterns_config`-003",
    "content": "--|---------|-----\n01|abcd           \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000011111111111\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---respects-`vim.{g,b}.minihipatterns_disable`---test-+-args-{-'b'-}",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---respects-`vim.{g,b}.minihipatterns_disable`---test-+-args-{-'g'-}",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---respects-global-config-after-`setup()`",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---works",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---works-in-not-current-buffer",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---works-in-not-normal-buffer",
    "content": "--|---------|-----\n01|xxabcdxx       \n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[Scratch] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|222222222222222\n03|222222222222222\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---enable()---works-with-defaults",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---respects-`opts.filter`",
    "content": "--|---------|-----\n01|#000000 #ffffff\n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|111111111111111\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---respects-`opts.filter`-002",
    "content": "--|---------|-----\n01|#000000 #ffffff\n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000012222222\n02|333333333333333\n03|333333333333333\n04|333333333333333\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---respects-`opts.priority`",
    "content": "--|---------|-----\n01|#000000        \n02|#000000        \n03|#000000        \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000011111111\n02|000000011111111\n03|000000011111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---respects-`opts.priority`-002",
    "content": "--|---------|-----\n01|#000000        \n02|#000000        \n03|#000000        \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000011111111\n02|000000011111111\n03|222222211111111\n04|333333333333333\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---respects-`opts.priority`-003",
    "content": "--|---------|-----\n01|#000000        \n02|#000000        \n03|#000000        \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000011111111\n02|000000011111111\n03|000000011111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---works",
    "content": "--|---------|-----\n01|#000000 #ffffff\n02|#FffFFf        \n03|#00000 #0000000\n04|#00000g        \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000012222222\n02|222222211111111\n03|111111111111111\n04|111111111111111\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---works-with-style-'#'",
    "content": "--|---------|-----\n01|#000000 #ffffff\n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|011111112111111\n02|333333333333333\n03|333333333333333\n04|333333333333333\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---works-with-style-'inline'",
    "content": "-|---------|---------|-----\n1|█#000000 █#ffffff        \n2|~                        \n3|~                        \n4|[No Name] 1,1-2          \n5|                         \n\n-|---------|---------|-----\n1|0111111112111111111111111\n2|3333333333333333333333333\n3|3333333333333333333333333\n4|4444444444444444444444444\n5|5555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---gen_highlighter---hex_color()---works-with-style-'line'",
    "content": "--|---------|-----\n01|#000000 #ffffff\n02|~              \n03|~              \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000012222222\n02|333333333333333\n03|333333333333333\n04|333333333333333\n05|333333333333333\n06|333333333333333\n07|333333333333333\n08|333333333333333\n09|444444444444444\n10|555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---setup()---auto-enables-in-all-visible-buffers",
    "content": "--|---------|---------|---------|\n01|33abcd33       │abcd abcd     \n02|~              │Abcd ABCD     \n03|~              │abcdaabcd     \n04|~              │~             \n05|~              │~             \n06|~              │~             \n07|~              │~             \n08|~              │~             \n09|[No Name] 1,1   [No Name] 1,1 \n10|                              \n\n--|---------|---------|---------|\n01|001111000000000233334333344444\n02|555555555555555244444444444444\n03|555555555555555233334333344444\n04|555555555555555266666666666666\n05|555555555555555266666666666666\n06|555555555555555266666666666666\n07|555555555555555266666666666666\n08|555555555555555266666666666666\n09|777777777777777788888888888888\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---setup()---auto-enables-in-all-visible-buffers-002",
    "content": "--|---------|---------|---------|\n01|22abcd22       │abcd abcd     \n02|~              │Abcd ABCD     \n03|~              │abcdaabcd     \n04|~              │~             \n05|~              │~             \n06|~              │~             \n07|~              │~             \n08|~              │~             \n09|[No Name] 1,1   [No Name] 1,1 \n10|                              \n\n--|---------|---------|---------|\n01|001111000000000233334333344444\n02|555555555555555244444444444444\n03|555555555555555233334333344444\n04|555555555555555266666666666666\n05|555555555555555266666666666666\n06|555555555555555266666666666666\n07|555555555555555266666666666666\n08|555555555555555266666666666666\n09|777777777777777788888888888888\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---toggle()---works",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000010000111111\n02|111111111111111\n03|000010000111111\n04|222222222222222\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---toggle()---works-002",
    "content": "--|---------|-----\n01|abcd abcd      \n02|Abcd ABCD      \n03|abcdaabcd      \n04|~              \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|111111111111111\n05|111111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|222222222222222\n10|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---update()---works",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|001111000000000\n03|001111000000000\n04|001111000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---update()---works-002",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|000000000000000\n03|000000000000000\n04|001111000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---update()---works-003",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|001111000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---update()---works-004",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|001111000000000\n03|001111000000000\n04|001111000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---update()---works-005",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_hipatterns.lua---update()---works-006",
    "content": "--|---------|-----\n01|xxabcd         \n02|xxabcd         \n03|xxabcd         \n04|xxabcd         \n05|~              \n06|~              \n07|~              \n08|~              \n09|[No Name] 1,1  \n10|               \n\n--|---------|-----\n01|001111000000000\n02|001111000000000\n03|001111000000000\n04|000000000000000\n05|222222222222222\n06|222222222222222\n07|222222222222222\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---by-default-is-not-done-for-incomplete-scope",
    "content": "--|---------|--\n01|aa          \n02|╎ bb        \n03|╎ bb        \n04|╎ bb        \n05|╎ bb        \n06|╎ bb        \n07|aa          \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 4,1\n15|            \n\n--|---------|--\n01|000000000000\n02|100000000000\n03|100000000000\n04|100000000000\n05|100000000000\n06|100000000000\n07|000000000000\n08|222222222222\n09|222222222222\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---by-default-is-not-done-for-incomplete-scope-002",
    "content": "--|---------|--\n01|aa          \n02|  bb        \n03|  bb        \n04|  bb        \n05|  bb        \n06|  bb        \n07|aa          \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 3,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|111111111111\n09|111111111111\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---by-default-is-not-done-for-incomplete-scope-003",
    "content": "--|---------|--\n01|aa          \n02|  bb        \n03|  bb        \n04|  bb        \n05|  bb        \n06|  bb        \n07|aa          \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 3,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|111111111111\n09|111111111111\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---by-default-is-not-done-for-incomplete-scope-004",
    "content": "--|---------|--\n01|aa          \n02|  bb        \n03|  bb        \n04|  bb        \n05|  bb        \n06|  bb        \n07|aa          \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 3,2\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|111111111111\n09|111111111111\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---by-default-is-not-done-for-incomplete-scope-005",
    "content": "--|---------|--\n01|aa          \n02|╎ bb        \n03|╎ bb        \n04|╎ bb        \n05|╎ bb        \n06|╎ bb        \n07|aa          \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 4,2\n15|            \n\n--|---------|--\n01|000000000000\n02|100000000000\n03|100000000000\n04|100000000000\n05|100000000000\n06|100000000000\n07|000000000000\n08|222222222222\n09|222222222222\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---implements-debounce-style-delay",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 2,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---implements-debounce-style-delay-002",
    "content": "--|---------|--\n01|aa          \n02|╎aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 2,1\n15|            \n\n--|---------|--\n01|000000000000\n02|100000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-ModeChanged-event",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|  ╎aa          \n05|  ╎aa          \n06|  ╎aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,5  \n15|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|001000000000000\n05|001000000000000\n06|001000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|222222222222222\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|333333333333333\n15|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-ModeChanged-event-002",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|   aa          \n05|   aa          \n06|   aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,5  \n15|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|111111111111111\n11|111111111111111\n12|111111111111111\n13|111111111111111\n14|222222222222222\n15|333333333333444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-ModeChanged-event-003",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|  ╎aa          \n05|  ╎aa          \n06|  ╎aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,4  \n15|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|001000000000000\n05|001000000000000\n06|001000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|222222222222222\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|333333333333333\n15|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`config.draw.delay`",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`config.draw.delay`-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`config.draw.predicate`",
    "content": "--|---------|--\n01|aa          \n02|  bb        \n03|aa          \n04|~           \n05|~           \n06|~           \n07|~           \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 2,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|111111111111\n05|111111111111\n06|111111111111\n07|111111111111\n08|111111111111\n09|111111111111\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`config.draw.predicate`-002",
    "content": "--|---------|--\n01|aa          \n02|╎ bb        \n03|aa          \n04|~           \n05|~           \n06|~           \n07|~           \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 2,1\n15|            \n\n--|---------|--\n01|000000000000\n02|100000000000\n03|000000000000\n04|222222222222\n05|222222222222\n06|222222222222\n07|222222222222\n08|222222222222\n09|222222222222\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`config.draw.predicate`-003",
    "content": "--|---------|--\n01|aa          \n02|  bb        \n03|aa          \n04|~           \n05|~           \n06|~           \n07|~           \n08|~           \n09|~           \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 2,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|111111111111\n05|111111111111\n06|111111111111\n07|111111111111\n08|111111111111\n09|111111111111\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`vim.{g,b}.miniindentscope_disable`---test-+-args-{-'b'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`vim.{g,b}.miniindentscope_disable`---test-+-args-{-'b'-}-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,4\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`vim.{g,b}.miniindentscope_disable`---test-+-args-{-'g'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-`vim.{g,b}.miniindentscope_disable`---test-+-args-{-'g'-}-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,4\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-common-events---test-+-args-{-'CursorMoved'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-common-events---test-+-args-{-'CursorMovedI'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-common-events---test-+-args-{-'TextChanged'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-common-events---test-+-args-{-'TextChangedI'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---respects-common-events---test-+-args-{-'TextChangedP'-}",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---updates-immediately-when-scopes-intersect",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|  ╎aa          \n05|  ╎aa          \n06|  ╎aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,5  \n15|               \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|001000000000000\n05|001000000000000\n06|001000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|222222222222222\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|333333333333333\n15|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---updates-immediately-when-scopes-intersect-002",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|  ╎aa          \n05|  ╎aa          \n06|  ╎            \n07|  ╎aa          \n08|  aa           \n09| aa            \n10|aa             \n11|~              \n12|~              \n13|~              \n14|[No Name] 6,4  \n15|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|001000000000000\n05|001000000000000\n06|001000000000000\n07|001000000000000\n08|000000000000000\n09|000000000000000\n10|000000000000000\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|333333333333333\n15|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---works-in-Insert-mode",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|   aa          \n05|   aa          \n06|   aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,5  \n15|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|000000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|111111111111111\n11|111111111111111\n12|111111111111111\n13|111111111111111\n14|222222222222222\n15|333333333333444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---works-in-Insert-mode-002",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|   aa          \n05|  ╎aa          \n06|   aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,5  \n15|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|000000000000000\n05|001000000000000\n06|000000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|222222222222222\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|333333333333333\n15|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---works-in-Insert-mode-003",
    "content": "--|---------|-----\n01|aa             \n02| aa            \n03|  aa           \n04|  ╎aa          \n05|  ╎aa          \n06|  ╎aa          \n07|  aa           \n08| aa            \n09|aa             \n10|~              \n11|~              \n12|~              \n13|~              \n14|[No Name] 5,5  \n15|-- INSERT --   \n\n--|---------|-----\n01|000000000000000\n02|000000000000000\n03|000000000000000\n04|001000000000000\n05|001000000000000\n06|001000000000000\n07|000000000000000\n08|000000000000000\n09|000000000000000\n10|222222222222222\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|333333333333333\n15|444444444444555\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---works-in-Normal-mode",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---works-in-Normal-mode-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---Auto-drawing---works-in-Normal-mode-003",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---does-not-overshadow-'listchars'",
    "content": "--|---------|--\n01|aa          \n02|.aa         \n03|..aa        \n04|..╎aa       \n05|..╎aa       \n06|..╎aa       \n07|..aa        \n08|.aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|100000000000\n03|110000000000\n04|112000000000\n05|112000000000\n06|112000000000\n07|110000000000\n08|100000000000\n09|000000000000\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---does-not-round-time-of-every-animation-step",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|╎  aa       \n05|╎  aa       \n06|╎  aa       \n07|╎ aa        \n08|╎aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 6,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|100000000000\n05|100000000000\n06|100000000000\n07|100000000000\n08|100000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.draw.animation`",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.draw.animation`-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.draw.animation`-003",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.draw.animation`-004",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|  ╎aa       \n05|  ╎aa       \n06|  ╎aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|001000000000\n05|001000000000\n06|001000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.draw.priority`",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|╎  aa       \n05|+  aa       \n06|╎  aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|100000000000\n05|000000000000\n06|100000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.draw.priority`-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|╎  aa       \n05|╎  aa       \n06|╎  aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,1\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|100000000000\n05|100000000000\n06|100000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.symbol`",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  -aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---respects-`config.symbol`-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  +aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---shows-symbols-on-wrapped-lines-without-overlapping",
    "content": "--|---------|-----\n01|aa             \n02|╎ aa           \n03|╎ a a a a a a a\n04| a a a a a a a \n05|a              \n06|╎ aa           \n07|aa             \n08|~              \n09|[No Name] 2,2  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|100000000000000\n03|100000000000000\n04|000000000000000\n05|000000000000000\n06|100000000000000\n07|000000000000000\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---shows-symbols-on-wrapped-lines-without-overlapping-002",
    "content": "--|---------|-----\n01|aa             \n02|╎ aa           \n03|╎ a a a a a a a\n04|╎  a a a a a a \n05|╎ a a          \n06|╎ aa           \n07|aa             \n08|~              \n09|[No Name] 2,2  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|100000000000000\n03|100000000000000\n04|100000000000000\n05|100000000000000\n06|100000000000000\n07|000000000000000\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---shows-symbols-on-wrapped-lines-without-overlapping-003",
    "content": "--|---------|-----\n01|aa             \n02|╎ aa           \n03|╎ a a a a a a a\n04|x a a a a a a a\n05|x a            \n06|╎ aa           \n07|aa             \n08|~              \n09|[No Name] 2,2  \n10|               \n\n--|---------|-----\n01|000000000000000\n02|100000000000000\n03|100000000000000\n04|200000000000000\n05|200000000000000\n06|100000000000000\n07|000000000000000\n08|222222222222222\n09|333333333333333\n10|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---works",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06| ╎ aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 6,2\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|010000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---works-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05| ╎ aa       \n06| ╎ aa       \n07| ╎aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 6,2\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|010000000000\n06|010000000000\n07|010000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---works-003",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04| ╎ aa       \n05| ╎ aa       \n06| ╎ aa       \n07| ╎aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 6,2\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|010000000000\n05|010000000000\n06|010000000000\n07|010000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---draw()---works-004",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03| ╎aa        \n04| ╎ aa       \n05| ╎ aa       \n06| ╎ aa       \n07| ╎aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 6,2\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|010000000000\n04|010000000000\n05|010000000000\n06|010000000000\n07|010000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---undraw()---works",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|  ╎aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|001000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|222222222222\n11|222222222222\n12|222222222222\n13|222222222222\n14|333333333333\n15|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_indentscope.lua---undraw()---works-002",
    "content": "--|---------|--\n01|aa          \n02| aa         \n03|  aa        \n04|   aa       \n05|   aa       \n06|   aa       \n07|  aa        \n08| aa         \n09|aa          \n10|~           \n11|~           \n12|~           \n13|~           \n14|<o Name] 5,5\n15|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|000000000000\n04|000000000000\n05|000000000000\n06|000000000000\n07|000000000000\n08|000000000000\n09|000000000000\n10|111111111111\n11|111111111111\n12|111111111111\n13|111111111111\n14|222222222222\n15|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---done-only-if-actually-jumping",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---implements-debounce-style-delay",
    "content": "-|---------|--\n1|1e2e3e      \n2|~           \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---implements-debounce-style-delay-002",
    "content": "-|---------|--\n1|1e2e3e      \n2|~           \n3|~           \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---implements-debounce-style-delay-003",
    "content": "-|---------|--\n1|1e2e3e      \n2|~           \n3|~           \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|010101000000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---never-highlights-in-Insert-mode",
    "content": "-|---------|-----\n1|1e2f           \n2|~              \n3|~              \n4|[No Name] 1,2  \n5|               \n\n-|---------|-----\n1|010000000000000\n2|222222222222222\n3|222222222222222\n4|333333333333333\n5|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---never-highlights-in-Insert-mode-002",
    "content": "-|---------|-----\n1|1f             \n2|~              \n3|~              \n4|[No Name] 1,2  \n5|-- INSERT --   \n\n-|---------|-----\n1|000000000000000\n2|111111111111111\n3|111111111111111\n4|222222222222222\n5|333333333333444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-'ignorecase'",
    "content": "-|---------|--\n1|1e2E        \n2|~           \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-'smartcase'",
    "content": "-|---------|--\n1|1e2E3e4E    \n2|~           \n3|~           \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|000100010000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'backward'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'backward'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'backward_till'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'backward_till'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'forward'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'forward'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'forward_till'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`config.delay.highlight`---test-+-args-{-'forward_till'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`vim.b.minijump_config`",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---respects-`vim.b.minijump_config`-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---stops-immediately-when-not-jumping",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---stops-immediately-when-not-jumping-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---updates-immediately-within-same-jumping",
    "content": "-|---------|--\n1|e1e2        \n2|ee          \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|010111111111\n2|001111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---updates-immediately-within-same-jumping-002",
    "content": "-|---------|--\n1|e1e2        \n2|ee          \n3|~           \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|001000000000\n2|110000000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---updates-immediately-within-same-jumping-003",
    "content": "-|---------|--\n1|e1e2        \n2|ee          \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010111111111\n2|001111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'backward'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'backward'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'backward_till'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'backward_till'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'forward'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'forward'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'forward_till'-}",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Delayed-highlighting---works---test-+-args-{-'forward_till'-}-002",
    "content": "-|---------|--\n1|1e2e        \n2|e4e5e_      \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|010100000000\n2|101010000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Jumping-with-f-t-F-T---respects-`config.silent`",
    "content": "--|---------|---------|\n01|1e2e3e4e            \n02|~                   \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Jumping-with-f-t-F-T---shows-reminder-after-one-idle-second",
    "content": "--|---------|---------|---------|---------|\n01|Lorem ipsum dolor sit amet,             \n02|consectetur adipiscing elit, sed do eius\n03|mod tempor                              \n04|incididunt ut labore et dolore magna ali\n05|qua.                                    \n06|`!@#$%^&*()_+=.,1234567890              \n07|~                                       \n08|~                                       \n09|[No Name] 1,3                           \n10|(mini.jump) Reminder to pres            \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000000\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Jumping-with-f-t-F-T---shows-reminder-after-one-idle-second-002",
    "content": "--|---------|---------|---------|---------|\n01|Lorem ipsum dolor sit amet,             \n02|consectetur adipiscing elit, sed do eius\n03|mod tempor                              \n04|incididunt ut labore et dolore magna ali\n05|qua.                                    \n06|`!@#$%^&*()_+=.,1234567890              \n07|~                                       \n08|~                                       \n09|[No Name] 1,5                           \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000000\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|2222222222222222222222222222222222222222\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Stop-jumping-after-idle---works",
    "content": "-|---------|--\n1|1e2e3e4e    \n2|ff          \n3|~           \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|010101010000\n2|000000000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Stop-jumping-after-idle---works-002",
    "content": "-|---------|--\n1|1e2e3e4e    \n2|ff          \n3|~           \n4|<o Name] 2,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump.lua---Stop-jumping-after-idle---works-if-should-be-done-before-target-highlighting",
    "content": "-|---------|--\n1|1e2e3e4e    \n2|ff          \n3|~           \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---builtin_opts.line_start---works",
    "content": "-|---------|--\n1|axx         \n2|b xxx       \n3|c           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|011111111111\n3|011111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---builtin_opts.single_character---shows-reminder-after-one-idle-second",
    "content": "-|---------|---------|---------|---------|---------|\n1|                                                  \n2|~                                                 \n3|~                                                 \n4|[No Name] 0,0-1                                   \n5|(mini.jump2d) Reminder to press a char            \n\n-|---------|---------|---------|---------|---------|\n1|00000000000000000000000000000000000000000000000000\n2|11111111111111111111111111111111111111111111111111\n3|11111111111111111111111111111111111111111111111111\n4|22222222222222222222222222222222222222222222222222\n5|33333333333333444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---builtin_opts.word_start---works",
    "content": "-|---------|---------|\n1|a bx cx.dx exx      \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01011011011011111111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---builtin_opts.word_start---works-002",
    "content": "-|---------|---------|\n1|a bx cx.xx dxx      \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01011011111011111111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---builtin_opts.word_start---works-with-multibyte-characters",
    "content": "-|---------|---------|\n1|a bы cы.dы eыы      \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01011011011011111111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---default_spotter()---correctly-merges-'overlapping'-spots",
    "content": "-|---------|---------|-----\n1|ab cd e_f                \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0010010101111111111111111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---default_spotter()---spots-before-and-after-punctuation",
    "content": "-|---------|---------|-----\n1|axb_____cxd efg          \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0101111101010001111111111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---default_spotter()---spots-first-capital-letter",
    "content": "-|---------|---------|-----\n1|axxbXxxcXXd              \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0110111011011111111111111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---default_spotter()---spots-start-and-end-of-words",
    "content": "-|---------|---------|-----\n1|a bc dxe                 \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0100101011111111111111111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---default_spotter()---works",
    "content": "-|---------|---------|-----\n1|axb c_d efg hiXj klXm    \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0101010100010010100101111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---default_spotter()---works-(almost)-with-multibyte-character",
    "content": "-|---------|---------|-----\n1|a bc dыe f_g hЫыi        \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0100101010101011011111111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---handles-patterns-with-'^'-and-'$'---test-+-args-{-'.()..$',-'none'-}",
    "content": "-|---------|---------|\n1|xxx xax             \n2|b                   \n3|xx                  \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00000100000000000000\n2|10000000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---handles-patterns-with-'^'-and-'$'---test-+-args-{-'...$',-'end'-}",
    "content": "-|---------|---------|\n1|xxx xxa             \n2|b                   \n3|xx                  \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00000010000000000000\n2|10000000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---handles-patterns-with-'^'-and-'$'---test-+-args-{-'...$',-'start'-}",
    "content": "-|---------|---------|\n1|xxx axx             \n2|b                   \n3|xx                  \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00001000000000000000\n2|10000000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---handles-patterns-with-'^'-and-'$'---test-+-args-{-'^.()..',-'none'-}",
    "content": "-|---------|---------|\n1|xax xxx             \n2|b                   \n3|xx                  \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01000000000000000000\n2|10000000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---handles-patterns-with-'^'-and-'$'---test-+-args-{-'^...',-'end'-}",
    "content": "-|---------|---------|\n1|xxa xxx             \n2|b                   \n3|xx                  \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00100000000000000000\n2|10000000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---handles-patterns-with-'^'-and-'$'---test-+-args-{-'^...',-'start'-}",
    "content": "-|---------|---------|\n1|axx xxx             \n2|b                   \n3|xx                  \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01111111111111111111\n2|01111111111111111111\n3|11111111111111111111\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---respects-`pattern`-argument",
    "content": "-|---------|---------|\n1|xxxax_xbx.xcxxx     \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00010001000100000000\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---respects-`side`-argument---test-+-args-{-'%S+',-'end'-}",
    "content": "-|---------|---------|\n1|xxa x_b x.c xxd     \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00100010001000100000\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---respects-`side`-argument---test-+-args-{-'%S+',-'start'-}",
    "content": "-|---------|---------|\n1|axx b_x c.x dxx     \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01110111011101111111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---respects-`side`-argument---test-+-args-{-'.().',-'none'-}",
    "content": "-|---------|---------|\n1|xaxbxcxdxexfxgx     \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01010101010101000000\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---works",
    "content": "-|---------|---------|\n1|axx b_c d.e fxx     \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01110101010101111111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---works-in-edge-cases",
    "content": "-|---------|---------|\n1|xxa b_c d.e xxf     \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00101010101000100000\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---works-with-multibyte-characters",
    "content": "-|---------|---------|\n1|a bcd efg hi        \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01000100010011111111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---pattern()---works-with-multibyte-characters-002",
    "content": "-|---------|---------|\n1|abc def ghi jklmn   \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00010001000100000111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---union()---works",
    "content": "-|---------|---------|-----\n1|axx b_c d_e fxx          \n2|~                        \n3|~                        \n4|[No Name] 1,1            \n5|                         \n\n-|---------|---------|-----\n1|0111010101010111111111111\n2|2222222222222222222222222\n3|2222222222222222222222222\n4|3333333333333333333333333\n5|4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---respects-`pattern`-argument",
    "content": "-|---------|---------|\n1|a b xx_xc xd.xe xxf \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01011111011011011101\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works",
    "content": "-|---------|---------|\n1|a b cx_xx dx.ex fxx \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01010111110110110111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works-002",
    "content": "-|---------|---------|\n1|a b cx_xx dx.xx exx \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01010111110111110111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works-with-anchored-patterns",
    "content": "-|---------|---------|\n1|axx xxx             \n2|bxx xxx             \n3|cx                  \n4|~                   \n5|~                   \n6|[No Name] 1,1       \n7|                    \n\n-|---------|---------|\n1|01111111111111111111\n2|01111111111111111111\n3|01111111111111111111\n4|22222222222222222222\n5|22222222222222222222\n6|33333333333333333333\n7|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works-with-anchored-patterns-002",
    "content": "-|---------|---------|\n1|xxx xxxa            \n2|xxx xxxb            \n3|xxc                 \n4|~                   \n5|~                   \n6|[No Name] 1,1       \n7|                    \n\n-|---------|---------|\n1|00000001000000000000\n2|00000001000000000000\n3|00100000000000000000\n4|22222222222222222222\n5|22222222222222222222\n6|33333333333333333333\n7|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works-with-anchored-patterns-003",
    "content": "-|---------|---------|\n1|xxxaxxx             \n2|xxxbxxx             \n3|xx                  \n4|~                   \n5|~                   \n6|[No Name] 1,1       \n7|                    \n\n-|---------|---------|\n1|00010000000000000000\n2|00010000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|22222222222222222222\n6|33333333333333333333\n7|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works-with-anchored-patterns-004",
    "content": "-|---------|---------|\n1|xxx axx             \n2|xxx bxx             \n3|xx                  \n4|~                   \n5|~                   \n6|[No Name] 1,1       \n7|                    \n\n-|---------|---------|\n1|00001000000000000000\n2|00001000000000000000\n3|00000000000000000000\n4|22222222222222222222\n5|22222222222222222222\n6|33333333333333333333\n7|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---gen_spotter---vimpattern---works-with-multibyte-characters",
    "content": "-|---------|---------|\n1|a bыы c_ы dы.eы fы  \n2|~                   \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|01011101110110110111\n2|22222222222222222222\n3|22222222222222222222\n4|33333333333333333333\n5|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---setup()---applies-`config.mappings`",
    "content": "-|---------|--\n1|axxb        \n2|cxxd        \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|011011111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---allows-`hook.before_start`-to-modify-spotter",
    "content": "-|---------|--\n1|xaxx        \n2|xbxx        \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|010000000000\n2|010000000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---handles-overlapping-multi-step-labels",
    "content": "-|---------|--\n1|jjjjkj      \n2|jkk         \n3|kkkkkk      \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000011222222\n2|011222222222\n3|000011222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---handles-overlapping-multi-step-labels-002",
    "content": "-|---------|--\n1|jjjkj       \n2|kk          \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000012222222\n2|012222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---handles-overlapping-multi-step-labels-003",
    "content": "-|---------|--\n1|jjkx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000111111111\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---handles-overlapping-multi-step-labels-004",
    "content": "-|---------|--\n1|jkxx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|001111111111\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---handles-very-big-`view.n_steps_ahead`",
    "content": "-|---------|--\n1|jjjjjk      \n2|jk          \n3|kjxkk       \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011222222\n2|012222222222\n3|012012222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---handles-very-big-`view.n_steps_ahead`-002",
    "content": "-|---------|--\n1|hhxhj       \n2|j           \n3|kxxl        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|012012222222\n2|022222222222\n3|022022222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---highlights-unique-labels-with-different-highlight-group",
    "content": "-|---------|--\n1|jxxj        \n2|k           \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|211111111111\n3|111111111111\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-current-window-during-label-computation---test-+-args-{-'bottomleft'-}",
    "content": "--|---------|---------|---------|---------|---------|\n01| 4+ [No Name]  + [No Name]                       X\n02|ax3xb                   │ex5xf                    \n03|~                       │~                        \n04|~                       │~                        \n05|[No Name] 1,1            [No Name] 1,1            \n06|cx4xd                   │gx6xh                    \n07|~                       │~                        \n08|~                       │~                        \n09|[No Name] 1,1            [No Name] 1,1            \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000111111111111111111111111111111111111\n02|23332333333333333333333342333233333333333333333333\n03|55555555555555555555555545555555555555555555555555\n04|55555555555555555555555545555555555555555555555555\n05|11111111111111111111111111111111111111111111111111\n06|26662666666666666666666642333233333333333333333333\n07|77777777777777777777777745555555555555555555555555\n08|77777777777777777777777745555555555555555555555555\n09|88888888888888888888888881111111111111111111111111\n10|33333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-current-window-during-label-computation---test-+-args-{-'topright'-}",
    "content": "--|---------|---------|---------|---------|---------|\n01| 4+ [No Name]  + [No Name]                       X\n02|ax3xb                   │ex5xf                    \n03|~                       │~                        \n04|~                       │~                        \n05|[No Name] 1,1            [No Name] 1,1            \n06|cx4xd                   │gx6xh                    \n07|~                       │~                        \n08|~                       │~                        \n09|[No Name] 1,1            [No Name] 1,1            \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000111111111111111111111111111111111111\n02|23332333333333333333333342555255555555555555555555\n03|66666666666666666666666647777777777777777777777777\n04|66666666666666666666666647777777777777777777777777\n05|11111111111111111111111118888888888888888888888888\n06|23332333333333333333333342333233333333333333333333\n07|66666666666666666666666646666666666666666666666666\n08|66666666666666666666666646666666666666666666666666\n09|11111111111111111111111111111111111111111111111111\n10|33333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-cursor-position-during-label-computation---test-+-args-{-1,-1-}",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<o Name] 1,2\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-cursor-position-during-label-computation---test-+-args-{-2,-0-}",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<Name] 2,0-1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-cursor-position-during-label-computation---test-+-args-{-3,-0-}",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<o Name] 3,1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-cursor-position-during-label-computation---test-+-args-{-3,-3-}",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<o Name] 3,4\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---ignores-not-focusable-windows",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb    xx5xx      │gx4xh   mx6xn      \n2|cx3xd    xx5xx      │ix4xj   ox6xp      \n3|ex3xf    xx5xx      │kx4xl   qx6xr      \n4|~                   │~                  \n5|[No Name] 2,1        [No Name] 2,1      \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0111011112222222222130222022202220222222\n2|0111011112222222222130222022202220222222\n3|0111011112222222222130222022202220222222\n4|4444444444444444444435555555555555555555\n5|6666666666666666666667777777777777777777\n6|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---jumps-immediately-to-single-spot",
    "content": "-|---------|--\n1|  x         \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---overrides-`config`-from-`opts`-argument",
    "content": "-|---------|--\n1|jxxj        \n2|            \n3|kxxk        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|111111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.blank`",
    "content": "-|---------|--\n1|axxb        \n2|            \n3|cxxd        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|111111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.blank`-002",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.cursor_-`---test-+-args-{-'cursor_after'-}",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │ex4xf              \n2|cx3xd               │gx4xh              \n3|xx3xx               │xx4xx              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|1111111111111111111123333333333333333333\n4|4444444444444444444445555555555555555555\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.cursor_-`---test-+-args-{-'cursor_after'-}-002",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │gx4xh              \n2|cx3xd               │ix4xj              \n3|ex3xf               │kx4xl              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.cursor_-`---test-+-args-{-'cursor_at'-}",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │ex4xf              \n2|xx3xx               │xx4xx              \n3|cx3xd               │gx4xh              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|1111111111111111111123333333333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.cursor_-`---test-+-args-{-'cursor_at'-}-002",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │gx4xh              \n2|cx3xd               │ix4xj              \n3|ex3xf               │kx4xl              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.cursor_-`---test-+-args-{-'cursor_before'-}",
    "content": "-|---------|---------|---------|---------|\n1|xx3xx               │xx4xx              \n2|ax3xb               │ex4xf              \n3|cx3xd               │gx4xh              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000012222222222222222222\n2|3000300000000000000013222322222222222222\n3|3000300000000000000013222322222222222222\n4|4444444444444444444445555555555555555555\n5|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.cursor_-`---test-+-args-{-'cursor_before'-}-002",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │gx4xh              \n2|cx3xd               │ix4xj              \n3|ex3xf               │kx4xl              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.fold`",
    "content": "-|---------|--\n1|axxb        \n2|+--  2 lines\n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|222222222222\n3|333333333333\n4|444444444444\n5|555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_lines.fold`-002",
    "content": "-|---------|--\n1|axxb        \n2|c--  2 lines\n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|022222222222\n3|333333333333\n4|444444444444\n5|555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_windows`---test-+-args-{-{current-=-false,not_current-=-false}-}",
    "content": "-|---------|---------|---------|---------|\n1|xx3xx               │xx4xx              \n2|xx3xx               │xx4xx              \n3|xx3xx               │xx4xx              \n4|[No Name] 2,1        [No Name] 2,1      \n5|(mini.jump2d) No spots to show.         \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000012222222222222222222\n2|0000000000000000000012222222222222222222\n3|0000000000000000000012222222222222222222\n4|3333333333333333333334444444444444444444\n5|5555555555555522222222222222222222222222\n6|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_windows`---test-+-args-{-{current-=-false,not_current-=-false}-}-002",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │gx4xh              \n2|cx3xd               │ix4xj              \n3|ex3xf               │kx4xl              \n4|[No Name] 2,1        [No Name] 2,1      \n5|(mini.jump2d) No spots to show.         \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|6666666666666633333333333333333333333333\n6|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_windows`---test-+-args-{-{current-=-false}-}",
    "content": "-|---------|---------|---------|---------|\n1|xx3xx               │ax4xb              \n2|xx3xx               │cx4xd              \n3|xx3xx               │ex4xf              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000012333233333333333333\n2|0000000000000000000012333233333333333333\n3|0000000000000000000012333233333333333333\n4|4444444444444444444445555555555555555555\n5|0000000000000000000000000000000000000000\n6|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_windows`---test-+-args-{-{current-=-false}-}-002",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │gx4xh              \n2|cx3xd               │ix4xj              \n3|ex3xf               │kx4xl              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_windows`---test-+-args-{-{not_current-=-false}-}",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │xx4xx              \n2|cx3xd               │xx4xx              \n3|ex3xf               │xx4xx              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111123333333333333333333\n2|0111011111111111111123333333333333333333\n3|0111011111111111111123333333333333333333\n4|4444444444444444444445555555555555555555\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`allowed_windows`---test-+-args-{-{not_current-=-false}-}-002",
    "content": "-|---------|---------|---------|---------|\n1|ax3xb               │gx4xh              \n2|cx3xd               │ix4xj              \n3|ex3xf               │kx4xl              \n4|[No Name] 2,1        [No Name] 2,1      \n5|                                        \n6|                                        \n\n-|---------|---------|---------|---------|\n1|0111011111111111111120333033333333333333\n2|0111011111111111111120333033333333333333\n3|0111011111111111111120333033333333333333\n4|4444444444444444444445555555555555555555\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`config.silent`",
    "content": "--|---------|---------|\n01|axxb                \n02|c                   \n03|dxxe                \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|01101111111111111111\n02|01111111111111111111\n03|01101111111111111111\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|33333333333333333333\n10|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`labels`",
    "content": "-|---------|--\n1|jxxj        \n2|j           \n3|kxxk        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`labels`-002",
    "content": "-|---------|--\n1|axxa        \n2|a           \n3|bxxb        \n4|<Name] 2,0-1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`opts.hl_group_dim`",
    "content": "-|---------|--\n1|jxxk        \n2|            \n3|dimx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|222222222222\n3|333222222222\n4|444444444444\n5|555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`spotter`",
    "content": "-|---------|--\n1|axxx        \n2|b           \n3|cxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|011111111111\n3|011111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`spotter`-002",
    "content": "-|---------|--\n1|xaxx        \n2|b           \n3|xcxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|010000000000\n2|100000000000\n3|010000000000\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.dim`",
    "content": "-|---------|--\n1|jxxj        \n2|k           \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.dim`-002",
    "content": "-|---------|--\n1|jxxk        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.dim`-003",
    "content": "-|---------|--\n1|jxxk        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.n_steps_ahead`",
    "content": "-|---------|--\n1|jjxjj       \n2|jk          \n3|kjxkk       \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|012012222222\n2|012222222222\n3|012012222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.n_steps_ahead`-002",
    "content": "-|---------|--\n1|jjxjk       \n2|k           \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|012012222222\n2|022222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.n_steps_ahead`-003",
    "content": "-|---------|--\n1|jxxk        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.n_steps_ahead`-004",
    "content": "-|---------|--\n1|jjjjjk      \n2|jk          \n3|kjxkk       \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|011011222222\n2|012222222222\n3|012012222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`view.n_steps_ahead`-005",
    "content": "-|---------|--\n1|jjxjk       \n2|k           \n3|xxxx        \n4|<o Name] 1,4\n5|            \n\n-|---------|--\n1|012012222222\n2|022222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`vim.{g,b}.minijump2d_disable`---test-+-args-{-'b'-}",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-`vim.{g,b}.minijump2d_disable`---test-+-args-{-'g'-}",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-folds",
    "content": "-|---------|--\n1|axxb        \n2|c--  2 lines\n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|022222222222\n3|333333333333\n4|444444444444\n5|555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---respects-folds-002",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<Name] 2,0-1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---shows-reminder-after-one-idle-second",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|jxxj                                                        \n2|j                                                           \n3|kxxk                                                        \n4|[No Name] 1,1                                               \n5|(mini.jump2d) Reminder to press encoding symbol             \n\n-|---------|---------|---------|---------|---------|---------|\n1|011011111111111111111111111111111111111111111111111111111111\n2|011111111111111111111111111111111111111111111111111111111111\n3|011011111111111111111111111111111111111111111111111111111111\n4|222222222222222222222222222222222222222222222222222222222222\n5|333333333333334444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---shows-reminder-after-one-idle-second-002",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|jxxj                                                        \n2|k                                                           \n3|xxxx                                                        \n4|[No Name] 1,1                                               \n5|                                                            \n\n-|---------|---------|---------|---------|---------|---------|\n1|011011111111111111111111111111111111111111111111111111111111\n2|011111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111111111111111111\n4|222222222222222222222222222222222222222222222222222222222222\n5|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---shows-reminder-after-one-idle-second-003",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|jxxj                                                        \n2|k                                                           \n3|xxxx                                                        \n4|[No Name] 1,1                                               \n5|(mini.jump2d) Reminder to press encoding symbol             \n\n-|---------|---------|---------|---------|---------|---------|\n1|011011111111111111111111111111111111111111111111111111111111\n2|011111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111111111111111111\n4|222222222222222222222222222222222222222222222222222222222222\n5|333333333333334444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---stops-jumping-if-not-label-was-typed---test-+-args-{-'-C-c-'-}",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---stops-jumping-if-not-label-was-typed---test-+-args-{-'-Down-'-}",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---stops-jumping-if-not-label-was-typed---test-+-args-{-'-Esc-'-}",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---traverses-floating-windows-at-the-end",
    "content": "-|---------|--\n1|exxf        \n2|cxxd        \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011022222222\n2|022022222222\n3|333333333333\n4|444444444444\n5|111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---traverses-visible-'regular'-windows-based-on-their-layout",
    "content": "--|---------|---------|---------|---------|---------|\n01| 4+ [No Name]  + [No Name]                       X\n02|ax3xb                    │gx5xh                   \n03|~                        │~                       \n04|~                        │~                       \n05|[No Name] 1,1             [No Name] 1,1           \n06|cx4xd                   │ex6xf                    \n07|~                       │~                        \n08|~                       │~                        \n09|[No Name] 1,1            [No Name] 1,1            \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000111111111111111111111111111111111111\n02|23332333333333333333333334255525555555555555555555\n03|66666666666666666666666664777777777777777777777777\n04|66666666666666666666666664777777777777777777777777\n05|88888888888888888888888888111111111111111111111111\n06|25552555555555555555555542555255555555555555555555\n07|77777777777777777777777747777777777777777777777777\n08|77777777777777777777777747777777777777777777777777\n09|11111111111111111111111111111111111111111111111111\n10|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---uses-`-CR-`-to-jump-to-first-available-spot",
    "content": "-|---------|---------|\n1|a a b b c c d d e f \n2|g h i j k l m n o p \n3|q r s t u v w x y z \n4|[No Name] 1,10      \n5|                    \n\n-|---------|---------|\n1|01010101010101010101\n2|01010101010101010101\n3|01010101010101010101\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---uses-`spotter`-with-correct-arguments",
    "content": "-|---------|---------|---------|---------|\n1|jxxx                │kyyy               \n2|j                   │k--  2 lines: yyyy·\n3|jxxx                │~                  \n4|[No Name] 1,1        aaa 1,1            \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0111111111111111111120333333333333333333\n2|0111111111111111111120444444444444444444\n3|0111111111111111111125555555555555555555\n4|6666666666666666666667777777777777777777\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---uses-only-all-visible-windows-by-default",
    "content": "--|---------|---------|---------|---------|---------|\n01| 4+ [No Name]  + [No Name]                       X\n02|ax3xb                   │ex5xf                    \n03|~                       │~                        \n04|~                       │~                        \n05|[No Name] 1,1            [No Name] 1,1            \n06|cx4xd                   │gx6xh                    \n07|~                       │~                        \n08|~                       │~                        \n09|[No Name] 1,1            [No Name] 1,1            \n10|                                                  \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000111111111111111111111111111111111111\n02|23332333333333333333333342555255555555555555555555\n03|66666666666666666666666647777777777777777777777777\n04|66666666666666666666666647777777777777777777777777\n05|88888888888888888888888881111111111111111111111111\n06|25552555555555555555555542555255555555555555555555\n07|77777777777777777777777747777777777777777777777777\n08|77777777777777777777777747777777777777777777777777\n09|11111111111111111111111111111111111111111111111111\n10|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---uses-only-visible-lines",
    "content": "-|---------|--\n1|2xxx        \n2|3xxx        \n3|<o Name] 2,1\n4|            \n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|000000000000\n5|022222222220\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---uses-only-visible-lines-002",
    "content": "-|---------|--\n1|axxb        \n2|cxxd        \n3|<o Name] 2,1\n4|            \n5|            \n\n-|---------|--\n1|011011111111\n2|011011111111\n3|222222222222\n4|111111111111\n5|133333333331\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-002",
    "content": "-|---------|--\n1|xxxx        \n2|            \n3|xxxx        \n4|<o Name] 3,4\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-in-Operator-pending-mode",
    "content": "-|---------|--\n1|axxb        \n2|c           \n3|dxxe        \n4|<o Name] 1,1\n5| d          \n\n-|---------|--\n1|011011111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-in-Operator-pending-mode-002",
    "content": "-|---------|--\n1|x           \n2|            \n3|xxxx        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-in-Operator-pending-mode-003",
    "content": "-|---------|--\n1|a           \n2|b           \n3|cxxd        \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|011111111111\n2|011111111111\n3|011011111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-in-Operator-pending-mode-004",
    "content": "-|---------|--\n1|xxxx        \n2|~           \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-in-Visual-mode",
    "content": "-|---------|---------|---------|---------|\n1|axxb                                    \n2|c                                       \n3|dxxe                                    \n4|[No Name] 1,1                           \n5|-- VISUAL --                            \n\n-|---------|---------|---------|---------|\n1|0110111111111111111111111111111111111111\n2|0111111111111111111111111111111111111111\n3|0110111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222\n5|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---start()---works-in-Visual-mode-002",
    "content": "-|---------|---------|---------|---------|\n1|xxxx                                    \n2|                                        \n3|xxxx                                    \n4|[No Name] 3,1                           \n5|-- VISUAL --                            \n\n-|---------|---------|---------|---------|\n1|0000111111111111111111111111111111111111\n2|0111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222\n5|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---stop()---clears-all-highlighting",
    "content": "-|---------|--\n1|axxb        \n2|cxxd        \n3|            \n4|~           \n5|<o Name] 1,1\n6|            \n\n-|---------|--\n1|011011111111\n2|011011111111\n3|222222222222\n4|111111111111\n5|333333333333\n6|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---stop()---clears-all-highlighting-002",
    "content": "-|---------|--\n1|xxxx        \n2|xxxx        \n3|            \n4|~           \n5|<o Name] 1,1\n6|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n6|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---stop()---works",
    "content": "--|---------|--\n01|axxb        \n02|cxxd        \n03|~           \n04|~           \n05|~           \n06|~           \n07|~           \n08|~           \n09|<o Name] 1,1\n10|            \n\n--|---------|--\n01|011011111111\n02|011011111111\n03|222222222222\n04|222222222222\n05|222222222222\n06|222222222222\n07|222222222222\n08|222222222222\n09|333333333333\n10|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_jump2d.lua---stop()---works-002",
    "content": "--|---------|--\n01|xxxx        \n02|xxxx        \n03|~           \n04|~           \n05|~           \n06|~           \n07|~           \n08|~           \n09|<o Name] 1,1\n10|            \n\n--|---------|--\n01|000000000000\n02|000000000000\n03|111111111111\n04|111111111111\n05|111111111111\n06|111111111111\n07|111111111111\n08|111111111111\n09|222222222222\n10|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Cursor-in-map-window---opens-enough-folds-in-source-window",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|+--  3 lines: a  aaa┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05|  a  aaa  a  aaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|        a a a a     ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|a a a a a a a a     ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|  a  aaa  a  aaa    ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09| a a a aaaaaaaaa              \n10|a a a a a a a a               \n11|  a  aaa  a  aaa              \n12|        a a a a               \n13| a a a a a a a a              \n14|  a  aaa  a  aaa              \n15| a a a aaaaaaaaa              \n16| a a a a a a a a              \n17|  a  aaa  a  aaa              \n18|        a a a a               \n19|aaaaaaaaaaaaaaaa              \n20|  a  aaa  a  aaa              \n21| a a a aaaaaaaaa              \n22|aaaaaaaaaaaaaaaa              \n23|~                             \n24|~                             \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|333333333333333333331222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|555555555555555555554444444444\n24|555555555555555555554444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Cursor-in-map-window---opens-enough-folds-in-source-window-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 4,1                 \n30|               2,3        All \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Pure-scrollbar---is-active-when-width-is-lower-than-offset",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa            █ \n02|        a a a a             ┃ \n03|                            ┃ \n04|  a  aaa  a  aaa            ┃ \n05| a a a aaaaaaaaa            ┃ \n06|                            ┃ \n07|  a  aaa  a  aaa            ┃ \n08|        a a a a             ┃ \n09|a a a a a a a a             ┃ \n10|  a  aaa  a  aaa            ┃ \n11| a a a aaaaaaaaa            ┃ \n12|a a a a a a a a             ┃ \n13|  a  aaa  a  aaa            ┃ \n14|        a a a a             ┃ \n15| a a a a a a a a            ┃ \n16|  a  aaa  a  aaa            ┃ \n17| a a a aaaaaaaaa            ┃ \n18| a a a a a a a a            ┃ \n19|  a  aaa  a  aaa            ┃ \n20|        a a a a             ┃ \n21|aaaaaaaaaaaaaaaa            ┃ \n22|  a  aaa  a  aaa            ┃ \n23| a a a aaaaaaaaa            ┃ \n24|aaaaaaaaaaaaaaaa            ┃ \n25|~                           ┃ \n26|~                           ┃ \n27|~                           ┃ \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000012\n02|000000000000000000000000000012\n03|000000000000000000000000000012\n04|000000000000000000000000000012\n05|000000000000000000000000000012\n06|000000000000000000000000000012\n07|000000000000000000000000000012\n08|000000000000000000000000000012\n09|000000000000000000000000000012\n10|000000000000000000000000000012\n11|000000000000000000000000000012\n12|000000000000000000000000000012\n13|000000000000000000000000000012\n14|000000000000000000000000000012\n15|000000000000000000000000000012\n16|000000000000000000000000000012\n17|000000000000000000000000000012\n18|000000000000000000000000000012\n19|000000000000000000000000000012\n20|000000000000000000000000000012\n21|000000000000000000000000000012\n22|000000000000000000000000000012\n23|000000000000000000000000000012\n24|000000000000000000000000000012\n25|333333333333333333333333333312\n26|333333333333333333333333333312\n27|333333333333333333333333333312\n28|333333333333333333333333333322\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Pure-scrollbar---is-active-when-width-is-lower-than-offset-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa           >< \n02|        a a a a            ┃  \n03|                           ┃  \n04|  a  aaa  a  aaa           ┃  \n05| a a a aaaaaaaaa           ┃  \n06|                           ┃  \n07|  a  aaa  a  aaa           ┃  \n08|        a a a a            ┃  \n09|a a a a a a a a            ┃  \n10|  a  aaa  a  aaa           ┃  \n11| a a a aaaaaaaaa           ┃  \n12|a a a a a a a a            ┃  \n13|  a  aaa  a  aaa           ┃  \n14|        a a a a            ┃  \n15| a a a a a a a a           ┃  \n16|  a  aaa  a  aaa           ┃  \n17| a a a aaaaaaaaa           ┃  \n18| a a a a a a a a           ┃  \n19|  a  aaa  a  aaa           ┃  \n20|        a a a a            ┃  \n21|aaaaaaaaaaaaaaaa           ┃  \n22|  a  aaa  a  aaa           ┃  \n23| a a a aaaaaaaaa           ┃  \n24|aaaaaaaaaaaaaaaa           ┃  \n25|~                          ┃  \n26|~                          ┃  \n27|~                          ┃  \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000112\n02|000000000000000000000000000122\n03|000000000000000000000000000122\n04|000000000000000000000000000122\n05|000000000000000000000000000122\n06|000000000000000000000000000122\n07|000000000000000000000000000122\n08|000000000000000000000000000122\n09|000000000000000000000000000122\n10|000000000000000000000000000122\n11|000000000000000000000000000122\n12|000000000000000000000000000122\n13|000000000000000000000000000122\n14|000000000000000000000000000122\n15|000000000000000000000000000122\n16|000000000000000000000000000122\n17|000000000000000000000000000122\n18|000000000000000000000000000122\n19|000000000000000000000000000122\n20|000000000000000000000000000122\n21|000000000000000000000000000122\n22|000000000000000000000000000122\n23|000000000000000000000000000122\n24|000000000000000000000000000122\n25|333333333333333333333333333122\n26|333333333333333333333333333122\n27|333333333333333333333333333122\n28|333333333333333333333333333222\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Pure-scrollbar---is-active-when-width-is-lower-than-offset-003",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa          >< 🬊\n02|        a a a a           ┃  🬎\n03|                          ┃  🬸\n04|  a  aaa  a  aaa          ┃  █\n05| a a a aaaaaaaaa          ┃  🬸\n06|                          ┃  █\n07|  a  aaa  a  aaa          ┃  🬸\n08|        a a a a           ┃  █\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000001122\n02|000000000000000000000000001222\n03|000000000000000000000000001222\n04|000000000000000000000000001222\n05|000000000000000000000000001222\n06|000000000000000000000000001222\n07|000000000000000000000000001222\n08|000000000000000000000000001222\n09|000000000000000000000000003333\n10|000000000000000000000000003333\n11|000000000000000000000000003333\n12|000000000000000000000000003333\n13|000000000000000000000000003333\n14|000000000000000000000000003333\n15|000000000000000000000000003333\n16|000000000000000000000000003333\n17|000000000000000000000000003333\n18|000000000000000000000000003333\n19|000000000000000000000000003333\n20|000000000000000000000000003333\n21|000000000000000000000000003333\n22|000000000000000000000000003333\n23|000000000000000000000000003333\n24|000000000000000000000000003333\n25|444444444444444444444444443333\n26|444444444444444444444444443333\n27|444444444444444444444444443333\n28|444444444444444444444444443333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Pure-scrollbar---works",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa             █\n02|        a a a a              ┃\n03|                             ┃\n04|  a  aaa  a  aaa             ┃\n05| a a a aaaaaaaaa             ┃\n06|                             ┃\n07|  a  aaa  a  aaa             ┃\n08|        a a a a              ┃\n09|a a a a a a a a              ┃\n10|  a  aaa  a  aaa             ┃\n11| a a a aaaaaaaaa             ┃\n12|a a a a a a a a              ┃\n13|  a  aaa  a  aaa             ┃\n14|        a a a a              ┃\n15| a a a a a a a a             ┃\n16|  a  aaa  a  aaa             ┃\n17| a a a aaaaaaaaa             ┃\n18| a a a a a a a a             ┃\n19|  a  aaa  a  aaa             ┃\n20|        a a a a              ┃\n21|aaaaaaaaaaaaaaaa             ┃\n22|  a  aaa  a  aaa             ┃\n23| a a a aaaaaaaaa             ┃\n24|aaaaaaaaaaaaaaaa             ┃\n25|~                            ┃\n26|~                            ┃\n27|~                            ┃\n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000001\n02|000000000000000000000000000001\n03|000000000000000000000000000001\n04|000000000000000000000000000001\n05|000000000000000000000000000001\n06|000000000000000000000000000001\n07|000000000000000000000000000001\n08|000000000000000000000000000001\n09|000000000000000000000000000001\n10|000000000000000000000000000001\n11|000000000000000000000000000001\n12|000000000000000000000000000001\n13|000000000000000000000000000001\n14|000000000000000000000000000001\n15|000000000000000000000000000001\n16|000000000000000000000000000001\n17|000000000000000000000000000001\n18|000000000000000000000000000001\n19|000000000000000000000000000001\n20|000000000000000000000000000001\n21|000000000000000000000000000001\n22|000000000000000000000000000001\n23|000000000000000000000000000001\n24|000000000000000000000000000001\n25|222222222222222222222222222221\n26|222222222222222222222222222221\n27|222222222222222222222222222221\n28|222222222222222222222222222223\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Pure-scrollbar---works-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa             ┃\n02|        a a a a              ┃\n03|                             ┃\n04|  a  aaa  a  aaa             ┃\n05| a a a aaaaaaaaa             ┃\n06|                             ┃\n07|  a  aaa  a  aaa             ┃\n08|        a a a a              ┃\n09|a a a a a a a a              ┃\n10|  a  aaa  a  aaa             ┃\n11| a a a aaaaaaaaa             ┃\n12|a a a a a a a a              ┃\n13|  a  aaa  a  aaa             ┃\n14|        a a a a              ┃\n15| a a a a a a a a             ┃\n16|  a  aaa  a  aaa             ┃\n17| a a a aaaaaaaaa             ┃\n18| a a a a a a a a             ┃\n19|  a  aaa  a  aaa             ┃\n20|        a a a a              ┃\n21|aaaaaaaaaaaaaaaa             ┃\n22|  a  aaa  a  aaa             ┃\n23| a a a aaaaaaaaa             ┃\n24|aaaaaaaaaaaaaaaa             ┃\n25|~                            ┃\n26|~                            ┃\n27|~                            █\n28|~                             \n29|[No Name] 24,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000001\n02|000000000000000000000000000001\n03|000000000000000000000000000001\n04|000000000000000000000000000001\n05|000000000000000000000000000001\n06|000000000000000000000000000001\n07|000000000000000000000000000001\n08|000000000000000000000000000001\n09|000000000000000000000000000001\n10|000000000000000000000000000001\n11|000000000000000000000000000001\n12|000000000000000000000000000001\n13|000000000000000000000000000001\n14|000000000000000000000000000001\n15|000000000000000000000000000001\n16|000000000000000000000000000001\n17|000000000000000000000000000001\n18|000000000000000000000000000001\n19|000000000000000000000000000001\n20|000000000000000000000000000001\n21|000000000000000000000000000001\n22|000000000000000000000000000001\n23|000000000000000000000000000001\n24|000000000000000000000000000001\n25|222222222222222222222222222221\n26|222222222222222222222222222221\n27|222222222222222222222222222221\n28|222222222222222222222222222223\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Scrollbar---updates-on-cursor-movement",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Scrollbar---updates-on-cursor-movement-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     █ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 4,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Scrollbar---updates-on-cursor-movement-003",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     █ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 4,6                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Scrollbar---updates-on-cursor-movement-004",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     █ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 24,6                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Scrollbar---updates-on-source-window-scrolling",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    █ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 21,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Scrollbar---updates-on-source-window-scrolling-002",
    "content": "--|---------|---------|---------|\n01|        a a a a        🬀🬁🬂🬃🬄🬅🬆\n02|a a a a a a a a       🬇🬈🬉🬊🬋🬌🬍🬎\n03|  a  aaa  a  aaa    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04| a a a aaaaaaaaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05|a a a a a a a a     ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|  a  aaa  a  aaa    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|        a a a a     █ 🬭🬮🬯🬰🬱🬲🬳🬴\n08| a a a a a a a a    ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|  a  aaa  a  aaa              \n10| a a a aaaaaaaaa              \n11| a a a a a a a a              \n12|  a  aaa  a  aaa              \n13|        a a a a               \n14|aaaaaaaaaaaaaaaa              \n15|  a  aaa  a  aaa              \n16| a a a aaaaaaaaa              \n17|aaaaaaaaaaaaaaaa              \n18|~                             \n19|~                             \n20|~                             \n21|~                             \n22|~                             \n23|~                             \n24|~                             \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 21,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001111111111\n02|000000000000000000001111111111\n03|000000000000000000002111111111\n04|000000000000000000002111111111\n05|000000000000000000002111111111\n06|000000000000000000002111111111\n07|000000000000000000002111111111\n08|000000000000000000002111111111\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|444444444444444444443333333333\n19|444444444444444444443333333333\n20|444444444444444444443333333333\n21|444444444444444444443333333333\n22|444444444444444444443333333333\n23|444444444444444444443333333333\n24|444444444444444444443333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---does-not-account-for-folds",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a     ┃  🬀🬁🬂🬃🬄🬅🬆\n10|  a  aaa  a  aaa    ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n11| a a a aaaaaaaaa      🬏🬐🬑🬒🬓▌🬔🬕\n12|a a a a a a a a       🬖🬗🬘🬙🬚🬛🬜🬝\n13|  a  aaa  a  aaa      🬞🬟🬠🬡🬢🬣🬤🬥\n14|        a a a a       🬦🬧▐🬨🬩🬪🬫🬬\n15| a a a a a a a a      🬭🬮🬯🬰🬱🬲🬳🬴\n16|  a  aaa  a  aaa      🬵🬶🬷🬸🬹🬺🬻█\n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|  a  aaa  a  aaa              \n26|        a a a a               \n27|                              \n28|  a  aaa  a  aaa              \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000002222222222\n12|000000000000000000002222222222\n13|000000000000000000002222222222\n14|000000000000000000002222222222\n15|000000000000000000002222222222\n16|000000000000000000002222222222\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|000000000000000000003333333333\n26|000000000000000000003333333333\n27|000000000000000000003333333333\n28|000000000000000000003333333333\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---does-not-account-for-folds-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    █ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|+-- 25 lines: a  aaa┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a     ┃  🬀🬁🬂🬃🬄🬅🬆\n10|  a  aaa  a  aaa    ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n11| a a a aaaaaaaaa    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n12|a a a a a a a a     ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n13|  a  aaa  a  aaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n14|        a a a a     ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n15| a a a a a a a a    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n16|  a  aaa  a  aaa    ┃ 🬵🬶🬷🬸🬹🬺🬻█\n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 7,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|333333333333333333331222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000001222222222\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---does-not-account-for-folds-003",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|+-- 25 lines: a  aaa┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a     ┃  🬀🬁🬂🬃🬄🬅🬆\n10|  a  aaa  a  aaa    ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n11| a a a aaaaaaaaa    █ 🬏🬐🬑🬒🬓▌🬔🬕\n12|a a a a a a a a     ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n13|  a  aaa  a  aaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n14|        a a a a     ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n15| a a a a a a a a    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n16|  a  aaa  a  aaa    ┃ 🬵🬶🬷🬸🬹🬺🬻█\n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 32,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|333333333333333333331222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000001222222222\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---does-not-respect-'winborder'-option",
    "content": "--|---------|---------|\n01|          █         \n02|~                   \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 0,0-1     \n15|                    \n\n--|---------|---------|\n01|00000000001222222222\n02|33333333334444444444\n03|33333333334444444444\n04|33333333334444444444\n05|33333333334444444444\n06|33333333334444444444\n07|33333333334444444444\n08|33333333334444444444\n09|33333333334444444444\n10|33333333334444444444\n11|33333333334444444444\n12|33333333334444444444\n13|33333333334444444444\n14|55555555555555555555\n15|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-buffer-enter",
    "content": "--|---------|---------|---------|\n01|aa                  █ █       \n02|aa                  ┃2 🬉🬄     \n03|aa                            \n04|   aa                         \n05|   aa                         \n06|~                             \n07|~                             \n08|~                             \n09|~                             \n10|~                             \n11|~                             \n12|~                             \n13|~                             \n14|~                             \n15|~                             \n16|~                             \n17|~                             \n18|~                             \n19|~                             \n20|~                             \n21|~                             \n22|~                             \n23|~                             \n24|~                             \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001233322222\n03|000000000000000000004444444444\n04|000000000000000000004444444444\n05|000000000000000000004444444444\n06|555555555555555555554444444444\n07|555555555555555555554444444444\n08|555555555555555555554444444444\n09|555555555555555555554444444444\n10|555555555555555555554444444444\n11|555555555555555555554444444444\n12|555555555555555555554444444444\n13|555555555555555555554444444444\n14|555555555555555555554444444444\n15|555555555555555555554444444444\n16|555555555555555555554444444444\n17|555555555555555555554444444444\n18|555555555555555555554444444444\n19|555555555555555555554444444444\n20|555555555555555555554444444444\n21|555555555555555555554444444444\n22|555555555555555555554444444444\n23|555555555555555555554444444444\n24|555555555555555555554444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-buffer-enter-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █2 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001233333333\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-buffer-write",
    "content": "--|---------|---------|\n01|aaa       █         \n02|   aa               \n03|   aa               \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 3,6       \n15|-- INSERT --        \n\n--|---------|---------|\n01|00000000001222222222\n02|00000000003333333333\n03|00000000003333333333\n04|44444444443333333333\n05|44444444443333333333\n06|44444444443333333333\n07|44444444443333333333\n08|44444444443333333333\n09|44444444443333333333\n10|44444444443333333333\n11|44444444443333333333\n12|44444444443333333333\n13|44444444443333333333\n14|55555555555555555555\n15|66666666666677777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-buffer-write-002",
    "content": "--|---------|---------|\n01|aaa       █2🬂🬧🬓     \n02|   aa               \n03|   aa               \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 3,6       \n15|-- INSERT --        \n\n--|---------|---------|\n01|00000000001233322222\n02|00000000004444444444\n03|00000000004444444444\n04|55555555554444444444\n05|55555555554444444444\n06|55555555554444444444\n07|55555555554444444444\n08|55555555554444444444\n09|55555555554444444444\n10|55555555554444444444\n11|55555555554444444444\n12|55555555554444444444\n13|55555555554444444444\n14|66666666666666666666\n15|77777777777788888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-mode-change-to-Normal",
    "content": "--|---------|---------|\n01|   bb     █2🬂🬦🬓     \n02|   bb               \n03|bb                  \n04|aa                  \n05|   aa               \n06|   aa               \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 4,1       \n15|-- INSERT --        \n\n--|---------|---------|\n01|00000000001233322222\n02|00000000004444444444\n03|00000000004444444444\n04|00000000004444444444\n05|00000000004444444444\n06|00000000004444444444\n07|55555555554444444444\n08|55555555554444444444\n09|55555555554444444444\n10|55555555554444444444\n11|55555555554444444444\n12|55555555554444444444\n13|55555555554444444444\n14|66666666666666666666\n15|77777777777788888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-mode-change-to-Normal-002",
    "content": "--|---------|---------|\n01|   bb     ┃2🬭🬉🬄     \n02|   bb     █2🬂🬦🬓     \n03|bb                  \n04|aa                  \n05|   aa               \n06|   aa               \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 4,1       \n15|                    \n\n--|---------|---------|\n01|00000000001233322222\n02|00000000001233322222\n03|00000000004444444444\n04|00000000004444444444\n05|00000000004444444444\n06|00000000004444444444\n07|55555555554444444444\n08|55555555554444444444\n09|55555555554444444444\n10|55555555554444444444\n11|55555555554444444444\n12|55555555554444444444\n13|55555555554444444444\n14|66666666666666666666\n15|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-text-change-in-Normal-mode",
    "content": "--|---------|---------|\n01|aaa       █2🬂🬧🬓     \n02|   aa               \n03|   aa               \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 3,1       \n15|                    \n\n--|---------|---------|\n01|00000000001233322222\n02|00000000004444444444\n03|00000000004444444444\n04|55555555554444444444\n05|55555555554444444444\n06|55555555554444444444\n07|55555555554444444444\n08|55555555554444444444\n09|55555555554444444444\n10|55555555554444444444\n11|55555555554444444444\n12|55555555554444444444\n13|55555555554444444444\n14|66666666666666666666\n15|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-text-change-in-Normal-mode-002",
    "content": "--|---------|---------|\n01|aaa       █ 🬂🬀      \n02|~                   \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|~                   \n11|~                   \n12|~                   \n13|~                   \n14|[No Name] 1,1       \n15|                    \n\n--|---------|---------|\n01|00000000001222222222\n02|33333333334444444444\n03|33333333334444444444\n04|33333333334444444444\n05|33333333334444444444\n06|33333333334444444444\n07|33333333334444444444\n08|33333333334444444444\n09|33333333334444444444\n10|33333333334444444444\n11|33333333334444444444\n12|33333333334444444444\n13|33333333334444444444\n14|55555555555555555555\n15|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-vim-resize",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █2 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a     ┃2 🬀🬁🬂🬃🬄🬅🬆\n10|  a  aaa  a  aaa    ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n11| a a a aaaaaaaaa      🬏🬐🬑🬒🬓▌🬔🬕\n12|a a a a a a a a       🬖🬗🬘🬙🬚🬛🬜🬝\n13|  a  aaa  a  aaa      🬞🬟🬠🬡🬢🬣🬤🬥\n14|        a a a a       🬦🬧▐🬨🬩🬪🬫🬬\n15| a a a a a a a a      🬭🬮🬯🬰🬱🬲🬳🬴\n16|  a  aaa  a  aaa      🬵🬶🬷🬸🬹🬺🬻█\n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|  a  aaa  a  aaa              \n26|        a a a a               \n27|                              \n28|  a  aaa  a  aaa              \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001233333333\n08|000000000000000000001222222222\n09|000000000000000000001233333333\n10|000000000000000000001233333333\n11|000000000000000000002233333333\n12|000000000000000000002222222222\n13|000000000000000000002233333333\n14|000000000000000000002222222222\n15|000000000000000000002233333333\n16|000000000000000000002222222222\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|000000000000000000004444444444\n26|000000000000000000004444444444\n27|000000000000000000004444444444\n28|000000000000000000004444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---Window---fully-updates-on-vim-resize-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █2 🬐🬠🬰🬀🬐🬡🬰\n02|        a a a a     ┃2🬁🬅🬉🬍🬒🬕🬙🬝\n03|                    ┃ 🬮🬲🬶🬺🬮🬲🬶🬺\n04|  a  aaa  a  aaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n05| a a a aaaaaaaaa      🬇🬗▐🬸🬋🬛🬫█\n06|                      🬩🬹🬩🬹🬺🬺🬺🬺\n07|  a  aaa  a  aaa      🬂🬆🬊🬎🬒🬕🬙🬝\n08|        a a a a      2🬇🬈🬉🬊🬋🬌🬍🬎\n09|a a a a a a a a       🬏🬐🬯🬰🬓▌🬳🬴\n10|  a  aaa  a  aaa      🬅🬔🬤🬳🬆🬕🬥🬴\n11| a a a aaaaaaaaa      🬠🬤▐🬫🬰🬴🬸█\n12|a a a a a a a a       🬯🬳🬷🬻🬳🬳🬻🬻\n13|  a  aaa  a  aaa      🬵🬶🬷🬸🬹🬺🬻█\n14|[No Name] 1,1                 \n15|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001222222222\n04|000000000000000000001233333333\n05|000000000000000000002222222222\n06|000000000000000000002233333333\n07|000000000000000000002233333333\n08|000000000000000000002233333333\n09|000000000000000000002233333333\n10|000000000000000000002222222222\n11|000000000000000000002233333333\n12|000000000000000000002233333333\n13|000000000000000000002222222222\n14|444444444444444444444444444444\n15|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_encode_symbols---can-be-used-as-`MiniMap.config.symbols.encode`",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  ▌▐█ ▌▐█\n02|        a a a a     ┃     ▌▌▌▌\n03|                    ┃         \n04|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n05| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n06|                    ┃         \n07|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n08|        a a a a     ┃     ▌▌▌▌\n09|a a a a a a a a     ┃ ▌▌▌▌▌▌▌▌\n10|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n11| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n12|a a a a a a a a     ┃ ▌▌▌▌▌▌▌▌\n13|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n14|        a a a a     ┃     ▌▌▌▌\n15| a a a a a a a a    ┃ ▐▐▐▐▐▐▐▐\n16|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n17| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n18| a a a a a a a a    ┃ ▐▐▐▐▐▐▐▐\n19|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n20|        a a a a     ┃     ▌▌▌▌\n21|aaaaaaaaaaaaaaaa    ┃ ████████\n22|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n23| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n24|aaaaaaaaaaaaaaaa    ┃ ████████\n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000001222222222\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000001222222222\n18|000000000000000000001222222222\n19|000000000000000000001222222222\n20|000000000000000000001222222222\n21|000000000000000000001222222222\n22|000000000000000000001222222222\n23|000000000000000000001222222222\n24|000000000000000000001222222222\n25|333333333333333333334444444444\n26|333333333333333333334444444444\n27|333333333333333333334444444444\n28|333333333333333333334444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_encode_symbols---can-be-used-as-part-of-`opts.symbols.encode`",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  ▌▐█ ▌▐█\n02|        a a a a     ┃     ▌▌▌▌\n03|                    ┃         \n04|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n05| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n06|                    ┃         \n07|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n08|        a a a a     ┃     ▌▌▌▌\n09|a a a a a a a a     ┃ ▌▌▌▌▌▌▌▌\n10|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n11| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n12|a a a a a a a a     ┃ ▌▌▌▌▌▌▌▌\n13|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n14|        a a a a     ┃     ▌▌▌▌\n15| a a a a a a a a    ┃ ▐▐▐▐▐▐▐▐\n16|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n17| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n18| a a a a a a a a    ┃ ▐▐▐▐▐▐▐▐\n19|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n20|        a a a a     ┃     ▌▌▌▌\n21|aaaaaaaaaaaaaaaa    ┃ ████████\n22|  a  aaa  a  aaa    ┃  ▌▐█ ▌▐█\n23| a a a aaaaaaaaa    ┃ ▐▐▐▐████\n24|aaaaaaaaaaaaaaaa    ┃ ████████\n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000001222222222\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000001222222222\n18|000000000000000000001222222222\n19|000000000000000000001222222222\n20|000000000000000000001222222222\n21|000000000000000000001222222222\n22|000000000000000000001222222222\n23|000000000000000000001222222222\n24|000000000000000000001222222222\n25|333333333333333333334444444444\n26|333333333333333333334444444444\n27|333333333333333333334444444444\n28|333333333333333333334444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---respects-documented-keymaps",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃8🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃8🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃8🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,5                \n30|/ a    ... [57/94]            \n\n--|---------|---------|---------|\n01|011011000110110000002344444444\n02|000000011111111000002344444444\n03|000000000000000000002344444444\n04|011011000110110000002344444444\n05|111111110000000000002344444444\n06|000000000000000000002344444444\n07|011011000110110000002344444444\n08|000000011111111000002344444444\n09|011111111111111000005555555555\n10|011011000110110000005555555555\n11|111111110000000000005555555555\n12|011111111111111000005555555555\n13|011011000110110000005555555555\n14|000000011111111000005555555555\n15|111166111111111100005555555555\n16|011011000110110000005555555555\n17|111111110000000000005555555555\n18|111111111111111100005555555555\n19|011011000110110000005555555555\n20|000000011111111000005555555555\n21|000000000000000000005555555555\n22|011011000110110000005555555555\n23|111111110000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---respects-documented-keymaps-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃8🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃8🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃8🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,5                \n30|? a    ... [57/94]            \n\n--|---------|---------|---------|\n01|011011000110110000002344444444\n02|000000011111111000002344444444\n03|000000000000000000002344444444\n04|011011000110110000002344444444\n05|111111110000000000002344444444\n06|000000000000000000002344444444\n07|011011000110110000002344444444\n08|000000011111111000002344444444\n09|011111111111111000005555555555\n10|011011000110110000005555555555\n11|111111110000000000005555555555\n12|011111111111111000005555555555\n13|011011000110110000005555555555\n14|000000011111111000005555555555\n15|111166111111111100005555555555\n16|011011000110110000005555555555\n17|111111110000000000005555555555\n18|111111111111111100005555555555\n19|011011000110110000005555555555\n20|000000011111111000005555555555\n21|000000000000000000005555555555\n22|011011000110110000005555555555\n23|111111110000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---respects-documented-keymaps-003",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃6 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃5🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃6🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃5🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,10               \n30|/\\<a\\> ... [49/76]            \n\n--|---------|---------|---------|\n01|001000000010000000002344444444\n02|000000001010101000002344444444\n03|000000000000000000002344444444\n04|001000000010000000002344444444\n05|010101000000000000002344444444\n06|000000000000000000002344444444\n07|001000000010000000002344444444\n08|000000001010101000002344444444\n09|101010101010101000005555555555\n10|001000000010000000005555555555\n11|010101000000000000005555555555\n12|101010101010101000005555555555\n13|001000000010000000005555555555\n14|000000001010101000005555555555\n15|010101010601010100005555555555\n16|001000000010000000005555555555\n17|010101000000000000005555555555\n18|010101010101010100005555555555\n19|001000000010000000005555555555\n20|000000001010101000005555555555\n21|000000000000000000005555555555\n22|001000000010000000005555555555\n23|010101000000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---respects-documented-keymaps-004",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃6 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃5🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃6🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃5🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,10               \n30|?\\<a\\> ... [49/76]            \n\n--|---------|---------|---------|\n01|001000000010000000002344444444\n02|000000001010101000002344444444\n03|000000000000000000002344444444\n04|001000000010000000002344444444\n05|010101000000000000002344444444\n06|000000000000000000002344444444\n07|001000000010000000002344444444\n08|000000001010101000002344444444\n09|101010101010101000005555555555\n10|001000000010000000005555555555\n11|010101000000000000005555555555\n12|101010101010101000005555555555\n13|001000000010000000005555555555\n14|000000001010101000005555555555\n15|010101010601010100005555555555\n16|001000000010000000005555555555\n17|010101000000000000005555555555\n18|010101010101010100005555555555\n19|001000000010000000005555555555\n20|000000001010101000005555555555\n21|000000000000000000005555555555\n22|001000000010000000005555555555\n23|010101000000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---updates-when-appropriate",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃8🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃8🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃8🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|011011000110110000002344444444\n02|000000011111111000002344444444\n03|000000000000000000002344444444\n04|011011000110110000002344444444\n05|111111110000000000002344444444\n06|000000000000000000002344444444\n07|011011000110110000002344444444\n08|000000011111111000002344444444\n09|011111111111111000005555555555\n10|011011000110110000005555555555\n11|111111110000000000005555555555\n12|011111111111111000005555555555\n13|011011000110110000005555555555\n14|000000011111111000005555555555\n15|116611111111111100005555555555\n16|011011000110110000005555555555\n17|111111110000000000005555555555\n18|111111111111111100005555555555\n19|011011000110110000005555555555\n20|000000011111111000005555555555\n21|000000000000000000005555555555\n22|011011000110110000005555555555\n23|111111110000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---updates-when-appropriate-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---updates-when-appropriate-003",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃8🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃8🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃8🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|011011000110110000002344444444\n02|000000011111111000002344444444\n03|000000000000000000002344444444\n04|011011000110110000002344444444\n05|111111110000000000002344444444\n06|000000000000000000002344444444\n07|011011000110110000002344444444\n08|000000011111111000002344444444\n09|011111111111111000005555555555\n10|011011000110110000005555555555\n11|111111110000000000005555555555\n12|011111111111111000005555555555\n13|011011000110110000005555555555\n14|000000011111111000005555555555\n15|116611111111111100005555555555\n16|011011000110110000005555555555\n17|111111110000000000005555555555\n18|111111111111111100005555555555\n19|011011000110110000005555555555\n20|000000011111111000005555555555\n21|000000000000000000005555555555\n22|011011000110110000005555555555\n23|111111110000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---updates-when-appropriate-004",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---updates-when-appropriate-005",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃8🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃8🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃8🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|011011000110110000002344444444\n02|000000011111111000002344444444\n03|000000000000000000002344444444\n04|011011000110110000002344444444\n05|111111110000000000002344444444\n06|000000000000000000002344444444\n07|011011000110110000002344444444\n08|000000011111111000002344444444\n09|011111111111111000005555555555\n10|011011000110110000005555555555\n11|111111110000000000005555555555\n12|011111111111111000005555555555\n13|011011000110110000005555555555\n14|000000011111111000005555555555\n15|116611111111111100005555555555\n16|011011000110110000005555555555\n17|111111110000000000005555555555\n18|111111111111111100005555555555\n19|011011000110110000005555555555\n20|000000011111111000005555555555\n21|000000000000000000005555555555\n22|011011000110110000005555555555\n23|111111110000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---works",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃8🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃+🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃+🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █+🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃+🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃8🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃8🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|011011000110110000002344444444\n02|000000011111111000002344444444\n03|000000000000000000002344444444\n04|011011000110110000002344444444\n05|111111110000000000002344444444\n06|000000000000000000002344444444\n07|011011000110110000002344444444\n08|000000011111111000002344444444\n09|011111111111111000005555555555\n10|011011000110110000005555555555\n11|111111110000000000005555555555\n12|011111111111111000005555555555\n13|011011000110110000005555555555\n14|000000011111111000005555555555\n15|116611111111111100005555555555\n16|011011000110110000005555555555\n17|111111110000000000005555555555\n18|111111111111111100005555555555\n19|011011000110110000005555555555\n20|000000011111111000005555555555\n21|000000000000000000005555555555\n22|011011000110110000005555555555\n23|111111110000000000005555555555\n24|000000000000000000005555555555\n25|777777777777777777775555555555\n26|777777777777777777775555555555\n27|777777777777777777775555555555\n28|777777777777777777775555555555\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---builtin_search()---works-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,3                \n30|/ a    ... [56/94]            \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---respects-`hl_groups`-argument",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001233333333\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---respects-`hl_groups`-argument-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001222222222\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---respects-`hl_groups`-argument-003",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---respects-`hl_groups`-argument-004",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃8 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃3🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001244444444\n04|000000000000000000001255555555\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001233333333\n09|000000000000000000006666666666\n10|000000000000000000006666666666\n11|000000000000000000006666666666\n12|000000000000000000006666666666\n13|000000000000000000006666666666\n14|000000000000000000006666666666\n15|000000000000000000006666666666\n16|000000000000000000006666666666\n17|000000000000000000006666666666\n18|000000000000000000006666666666\n19|000000000000000000006666666666\n20|000000000000000000006666666666\n21|000000000000000000006666666666\n22|000000000000000000006666666666\n23|000000000000000000006666666666\n24|000000000000000000006666666666\n25|777777777777777777776666666666\n26|777777777777777777776666666666\n27|777777777777777777776666666666\n28|777777777777777777776666666666\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---updates-when-appropriate",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---updates-when-appropriate-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃5 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃2🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001233333333\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diagnostic()---works",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃5 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃2🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001233333333\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---diff()---works",
    "content": "--|---------|---------|---------|\n01|▒ uuu               █2█▌      \n02|▒ vvv               ┃2█▌      \n03|  aaa               ┃3█▌      \n04|▒ bbb               ┃3█▌      \n05|  ddd               ┃ 🬂🬀      \n06|▒ EEE                         \n07|▒ FFF                         \n08|▒ GGG                         \n09|▒ HHH                         \n10|▒ III                         \n11|▒ JJJ                         \n12|▒ KKK                         \n13|▒ LLL                         \n14|~                             \n15|~                             \n16|~                             \n17|~                             \n18|~                             \n19|[No Name] 1,1                 \n20|                              \n\n--|---------|---------|---------|\n01|001111111111111111112344333333\n02|001111111111111111112355333333\n03|661111111111111111112377333333\n04|881111111111111111112344333333\n05|661111111111111111112344333333\n06|99111111111111111111::::::::::\n07|99111111111111111111::::::::::\n08|99111111111111111111::::::::::\n09|99111111111111111111::::::::::\n10|99111111111111111111::::::::::\n11|99111111111111111111::::::::::\n12|99111111111111111111::::::::::\n13|99111111111111111111::::::::::\n14|66666666666666666666::::::::::\n15|66666666666666666666::::::::::\n16|66666666666666666666::::::::::\n17|66666666666666666666::::::::::\n18|66666666666666666666::::::::::\n19|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n20|<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---gitsigns()---respects-`hl_groups`-argument",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---gitsigns()---updates-when-appropriate",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃  🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---gitsigns()---updates-when-appropriate-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃3 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃3🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃3🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001244444444\n03|000000000000000000001255555555\n04|000000000000000000001233333333\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001233333333\n09|000000000000000000006666666666\n10|000000000000000000006666666666\n11|000000000000000000006666666666\n12|000000000000000000006666666666\n13|000000000000000000006666666666\n14|000000000000000000006666666666\n15|000000000000000000006666666666\n16|000000000000000000006666666666\n17|000000000000000000006666666666\n18|000000000000000000006666666666\n19|000000000000000000006666666666\n20|000000000000000000006666666666\n21|000000000000000000006666666666\n22|000000000000000000006666666666\n23|000000000000000000006666666666\n24|000000000000000000006666666666\n25|777777777777777777776666666666\n26|777777777777777777776666666666\n27|777777777777777777776666666666\n28|777777777777777777776666666666\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---gen_integration---gitsigns()---works",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃3 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃3🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃3🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001244444444\n03|000000000000000000001255555555\n04|000000000000000000001233333333\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001233333333\n09|000000000000000000006666666666\n10|000000000000000000006666666666\n11|000000000000000000006666666666\n12|000000000000000000006666666666\n13|000000000000000000006666666666\n14|000000000000000000006666666666\n15|000000000000000000006666666666\n16|000000000000000000006666666666\n17|000000000000000000006666666666\n18|000000000000000000006666666666\n19|000000000000000000006666666666\n20|000000000000000000006666666666\n21|000000000000000000006666666666\n22|000000000000000000006666666666\n23|000000000000000000006666666666\n24|000000000000000000006666666666\n25|777777777777777777776666666666\n26|777777777777777777776666666666\n27|777777777777777777776666666666\n28|777777777777777777776666666666\n29|888888888888888888888888888888\n30|999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---allows-more-than-single-character-in-scroll-symbols",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    >|< 🬁🬁🬂🬍🬉🬆\n02|        a a a a     ||  🬅🬍🬊🬍🬍🬎\n03|                    ||  🬯🬠🬒🬻▐🬕\n04|  a  aaa  a  aaa    ||  🬳🬫🬙🬻🬫🬝\n05| a a a aaaaaaaaa    ||  🬑🬯🬡🬜🬷🬥\n06|                    ||  🬔🬻🬨🬜🬻🬬\n07|  a  aaa  a  aaa    ||  🬯🬯🬰🬻🬷🬴\n08|        a a a a     ||  🬳🬻🬸🬻🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001112222222\n02|000000000000000000001122222222\n03|000000000000000000001122222222\n04|000000000000000000001122222222\n05|000000000000000000001122222222\n06|000000000000000000001122222222\n07|000000000000000000001122222222\n08|000000000000000000001122222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---can-open-pure-scrollbar",
    "content": "--|---------|---------|---------|\n01|        a a a a               \n02|                             ┃\n03|  a  aaa  a  aaa             ┃\n04| a a a aaaaaaaaa             ┃\n05|                             ┃\n06|  a  aaa  a  aaa             ┃\n07|        a a a a              ┃\n08|a a a a a a a a              ┃\n09|  a  aaa  a  aaa             ┃\n10| a a a aaaaaaaaa             ┃\n11|a a a a a a a a              ┃\n12|  a  aaa  a  aaa             ┃\n13|        a a a a              ┃\n14| a a a a a a a a             ┃\n15|  a  aaa  a  aaa             ┃\n16| a a a aaaaaaaaa             ┃\n17| a a a a a a a a             █\n18|  a  aaa  a  aaa             ┃\n19|        a a a a              ┃\n20|aaaaaaaaaaaaaaaa             ┃\n21|  a  aaa  a  aaa             ┃\n22| a a a aaaaaaaaa             ┃\n23|aaaaaaaaaaaaaaaa             ┃\n24|~                            ┃\n25|~                            ┃\n26|~                            ┃\n27|~                            ┃\n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000001\n02|000000000000000000000000000002\n03|000000000000000000000000000002\n04|000000000000000000000000000002\n05|000000000000000000000000000002\n06|000000000000000000000000000002\n07|000000000000000000000000000002\n08|000000000000000000000000000002\n09|000000000000000000000000000002\n10|000000000000000000000000000002\n11|000000000000000000000000000002\n12|000000000000000000000000000002\n13|000000000000000000000000000002\n14|000000000000000000000000000002\n15|000000000000000000000000000002\n16|000000000000000000000000000002\n17|000000000000000000000000000002\n18|000000000000000000000000000002\n19|000000000000000000000000000002\n20|000000000000000000000000000002\n21|000000000000000000000000000002\n22|000000000000000000000000000002\n23|000000000000000000000000000002\n24|333333333333333333333333333332\n25|333333333333333333333333333332\n26|333333333333333333333333333332\n27|333333333333333333333333333332\n28|333333333333333333333333333331\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---respects-`MiniMapNormal`-highlight-group",
    "content": "--|---------|---------|---------|\n01|bbbbbaaa  a  aaa    █  🬀🬁🬂🬃🬄🬅🬆\n02|bbbbb   a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|bbbbb               ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|bbbbbaaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05|bbbbba aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|bbbbb               ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|bbbbbaaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|bbbbb   a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|bbbbb a a a a a               \n10|bbbbbaaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000001111111111111112333333333\n02|000001111111111111112333333333\n03|000001111111111111112333333333\n04|000001111111111111112333333333\n05|000001111111111111112333333333\n06|000001111111111111112333333333\n07|000001111111111111112333333333\n08|000001111111111111112333333333\n09|000001111111111111114444444444\n10|000001111111111111114444444444\n11|111111111111111111114444444444\n12|111111111111111111114444444444\n13|111111111111111111114444444444\n14|111111111111111111114444444444\n15|111111111111111111114444444444\n16|111111111111111111114444444444\n17|111111111111111111114444444444\n18|111111111111111111114444444444\n19|111111111111111111114444444444\n20|111111111111111111114444444444\n21|111111111111111111114444444444\n22|111111111111111111114444444444\n23|111111111111111111114444444444\n24|111111111111111111114444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---respects-`opts.integrations`-argument",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █2 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001233333333\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---respects-`opts.symbols`-argument",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    > 12341234\n02|        a a a a     + 11112222\n03|                    + 11111111\n04|  a  aaa  a  aaa    + 12341234\n05| a a a aaaaaaaaa    + 33334444\n06|                    + 11111111\n07|  a  aaa  a  aaa    + 12341234\n08|        a a a a     + 11112222\n09|a a a a a a a a     + 22222222\n10|  a  aaa  a  aaa    + 12341234\n11| a a a aaaaaaaaa    + 33334444\n12|a a a a a a a a     + 22222222\n13|  a  aaa  a  aaa    + 12341234\n14|        a a a a     + 11112222\n15| a a a a a a a a    + 33333333\n16|  a  aaa  a  aaa    + 12341234\n17| a a a aaaaaaaaa    + 33334444\n18| a a a a a a a a    + 33333333\n19|  a  aaa  a  aaa    + 12341234\n20|        a a a a     + 11112222\n21|aaaaaaaaaaaaaaaa    + 44444444\n22|  a  aaa  a  aaa    + 12341234\n23| a a a aaaaaaaaa    + 33334444\n24|aaaaaaaaaaaaaaaa    + 44444444\n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000001222222222\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000001222222222\n18|000000000000000000001222222222\n19|000000000000000000001222222222\n20|000000000000000000001222222222\n21|000000000000000000001222222222\n22|000000000000000000001222222222\n23|000000000000000000001222222222\n24|000000000000000000001222222222\n25|333333333333333333334444444444\n26|333333333333333333334444444444\n27|333333333333333333334444444444\n28|333333333333333333334444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---respects-`opts.symbols`-argument-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa      🬀🬁🬂🬃🬄🬅🬆 \n02|        a a a a      🬇🬈🬉🬊🬋🬌🬍🬎 \n03|                     🬏🬐🬑🬒🬓▌🬔🬕 \n04|  a  aaa  a  aaa     🬖🬗🬘🬙🬚🬛🬜🬝 \n05| a a a aaaaaaaaa     🬞🬟🬠🬡🬢🬣🬤🬥 \n06|                     🬦🬧▐🬨🬩🬪🬫🬬 \n07|  a  aaa  a  aaa     🬭🬮🬯🬰🬱🬲🬳🬴 \n08|        a a a a      🬵🬶🬷🬸🬹🬺🬻█ \n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001111111111\n02|000000000000000000001111111111\n03|000000000000000000001111111111\n04|000000000000000000001111111111\n05|000000000000000000001111111111\n06|000000000000000000001111111111\n07|000000000000000000001111111111\n08|000000000000000000001111111111\n09|000000000000000000002222222222\n10|000000000000000000002222222222\n11|000000000000000000002222222222\n12|000000000000000000002222222222\n13|000000000000000000002222222222\n14|000000000000000000002222222222\n15|000000000000000000002222222222\n16|000000000000000000002222222222\n17|000000000000000000002222222222\n18|000000000000000000002222222222\n19|000000000000000000002222222222\n20|000000000000000000002222222222\n21|000000000000000000002222222222\n22|000000000000000000002222222222\n23|000000000000000000002222222222\n24|000000000000000000002222222222\n25|333333333333333333332222222222\n26|333333333333333333332222222222\n27|333333333333333333332222222222\n28|333333333333333333332222222222\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---respects-`opts.window`-argument",
    "content": "--|---------|---------|---------|\n01|█ 🬀🬁🬂🬃🬄🬅🬆      a              \n02|┃🬇🬈🬉🬊🬋🬌🬍🬎                     \n03|┃🬏🬐🬑🬒🬓▌🬔🬕                     \n04|┃🬖🬗🬘🬙🬚🬛🬜🬝      a              \n05|┃🬞🬟🬠🬡🬢🬣🬤🬥      a              \n06|┃🬦🬧▐🬨🬩🬪🬫🬬                     \n07|┃🬭🬮🬯🬰🬱🬲🬳🬴      a              \n08|┃🬵🬶🬷🬸🬹🬺🬻█                     \n09|                              \n10|               a              \n11|               a              \n12|                              \n13|               a              \n14|                              \n15|               a              \n16|               a              \n17|               a              \n18|               a              \n19|               a              \n20|                              \n21|               a              \n22|               a              \n23|               a              \n24|               a              \n25|                              \n26|                              \n27|                              \n28|                              \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|011111111111111222222222222222\n02|011111111111111222222222222222\n03|011111111111111222222222222222\n04|011111111111111222222222222222\n05|011111111111111222222222222222\n06|011111111111111222222222222222\n07|011111111111111222222222222222\n08|011111111111111222222222222222\n09|333333333333333222222222222222\n10|333333333333333222222222222222\n11|333333333333333222222222222222\n12|333333333333333222222222222222\n13|333333333333333222222222222222\n14|333333333333333222222222222222\n15|333333333333333222222222222222\n16|333333333333333222222222222222\n17|333333333333333222222222222222\n18|333333333333333222222222222222\n19|333333333333333222222222222222\n20|333333333333333222222222222222\n21|333333333333333222222222222222\n22|333333333333333222222222222222\n23|333333333333333222222222222222\n24|333333333333333222222222222222\n25|333333333333333444444444444444\n26|333333333333333444444444444444\n27|333333333333333444444444444444\n28|333333333333333444444444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---shows-appropriate-integration-counts",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █  ███ ███\n02|        a a a a     ┃2    ████\n03|                    ┃3        \n04|  a  aaa  a  aaa    ┃4 ███ ███\n05| a a a aaaaaaaaa    ┃5████████\n06|                    ┃6        \n07|  a  aaa  a  aaa    ┃7 ███ ███\n08|        a a a a     ┃8    ████\n09|a a a a a a a a     ┃9████████\n10|  a  aaa  a  aaa    ┃+ ███ ███\n11| a a a aaaaaaaaa    ┃+████████\n12|a a a a a a a a     ┃ ████████\n13|  a  aaa  a  aaa    ┃  ███ ███\n14|        a a a a     ┃     ████\n15| a a a a a a a a    ┃ ████████\n16|  a  aaa  a  aaa    ┃  ███ ███\n17| a a a aaaaaaaaa    ┃ ████████\n18| a a a a a a a a    ┃ ████████\n19|  a  aaa  a  aaa    ┃  ███ ███\n20|        a a a a     ┃     ████\n21|aaaaaaaaaaaaaaaa    ┃ ████████\n22|  a  aaa  a  aaa    ┃  ███ ███\n23| a a a aaaaaaaaa    ┃ ████████\n24|aaaaaaaaaaaaaaaa    ┃ ████████\n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001233333333\n05|000000000000000000001233333333\n06|000000000000000000001233333333\n07|000000000000000000001233333333\n08|000000000000000000001233333333\n09|000000000000000000001233333333\n10|000000000000000000001233333333\n11|000000000000000000001233333333\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000001222222222\n18|000000000000000000001222222222\n19|000000000000000000001222222222\n20|000000000000000000001222222222\n21|000000000000000000001222222222\n22|000000000000000000001222222222\n23|000000000000000000001222222222\n24|000000000000000000001222222222\n25|444444444444444444445555555555\n26|444444444444444444445555555555\n27|444444444444444444445555555555\n28|444444444444444444445555555555\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---open()---works",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃2 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001233333333\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`opts.integrations`-argument",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █2 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    ┃ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001233333333\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`opts.symbols`-argument",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    > 12341234\n02|        a a a a     + 11112222\n03|                    + 11111111\n04|  a  aaa  a  aaa    + 12341234\n05| a a a aaaaaaaaa    + 33334444\n06|                    + 11111111\n07|  a  aaa  a  aaa    + 12341234\n08|        a a a a     + 11112222\n09|a a a a a a a a     + 22222222\n10|  a  aaa  a  aaa    + 12341234\n11| a a a aaaaaaaaa    + 33334444\n12|a a a a a a a a     + 22222222\n13|  a  aaa  a  aaa    + 12341234\n14|        a a a a     + 11112222\n15| a a a a a a a a    + 33333333\n16|  a  aaa  a  aaa    + 12341234\n17| a a a aaaaaaaaa    + 33334444\n18| a a a a a a a a    + 33333333\n19|  a  aaa  a  aaa    + 12341234\n20|        a a a a     + 11112222\n21|aaaaaaaaaaaaaaaa    + 44444444\n22|  a  aaa  a  aaa    + 12341234\n23| a a a aaaaaaaaa    + 33334444\n24|aaaaaaaaaaaaaaaa    + 44444444\n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000001222222222\n10|000000000000000000001222222222\n11|000000000000000000001222222222\n12|000000000000000000001222222222\n13|000000000000000000001222222222\n14|000000000000000000001222222222\n15|000000000000000000001222222222\n16|000000000000000000001222222222\n17|000000000000000000001222222222\n18|000000000000000000001222222222\n19|000000000000000000001222222222\n20|000000000000000000001222222222\n21|000000000000000000001222222222\n22|000000000000000000001222222222\n23|000000000000000000001222222222\n24|000000000000000000001222222222\n25|333333333333333333334444444444\n26|333333333333333333334444444444\n27|333333333333333333334444444444\n28|333333333333333333334444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`opts.window`-argument",
    "content": "--|---------|---------|---------|\n01|█ 🬀🬁🬂🬃🬄🬅🬆      a              \n02|┃🬇🬈🬉🬊🬋🬌🬍🬎                     \n03|┃🬏🬐🬑🬒🬓▌🬔🬕                     \n04|┃🬖🬗🬘🬙🬚🬛🬜🬝      a              \n05|┃🬞🬟🬠🬡🬢🬣🬤🬥      a              \n06|┃🬦🬧▐🬨🬩🬪🬫🬬                     \n07|┃🬭🬮🬯🬰🬱🬲🬳🬴      a              \n08|┃🬵🬶🬷🬸🬹🬺🬻█                     \n09|                              \n10|               a              \n11|               a              \n12|                              \n13|               a              \n14|                              \n15|               a              \n16|               a              \n17|               a              \n18|               a              \n19|               a              \n20|                              \n21|               a              \n22|               a              \n23|               a              \n24|               a              \n25|                              \n26|                              \n27|                              \n28|                              \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|011111111111111222222222222222\n02|011111111111111222222222222222\n03|011111111111111222222222222222\n04|011111111111111222222222222222\n05|011111111111111222222222222222\n06|011111111111111222222222222222\n07|011111111111111222222222222222\n08|011111111111111222222222222222\n09|333333333333333222222222222222\n10|333333333333333222222222222222\n11|333333333333333222222222222222\n12|333333333333333222222222222222\n13|333333333333333222222222222222\n14|333333333333333222222222222222\n15|333333333333333222222222222222\n16|333333333333333222222222222222\n17|333333333333333222222222222222\n18|333333333333333222222222222222\n19|333333333333333222222222222222\n20|333333333333333222222222222222\n21|333333333333333222222222222222\n22|333333333333333222222222222222\n23|333333333333333222222222222222\n24|333333333333333222222222222222\n25|333333333333333444444444444444\n26|333333333333333444444444444444\n27|333333333333333444444444444444\n28|333333333333333444444444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`parts`-argument",
    "content": "--|---------|---------|---------|\n01|                    █         \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~                             \n09|~                             \n10|~                             \n11|~                             \n12|~                             \n13|~                             \n14|~                             \n15|~                             \n16|~                             \n17|~                             \n18|~                             \n19|~                             \n20|~                             \n21|~                             \n22|~                             \n23|~                             \n24|~                             \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 0,0-1               \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|333333333333333333334444444444\n03|333333333333333333334444444444\n04|333333333333333333334444444444\n05|333333333333333333334444444444\n06|333333333333333333334444444444\n07|333333333333333333334444444444\n08|333333333333333333334444444444\n09|333333333333333333334444444444\n10|333333333333333333334444444444\n11|333333333333333333334444444444\n12|333333333333333333334444444444\n13|333333333333333333334444444444\n14|333333333333333333334444444444\n15|333333333333333333334444444444\n16|333333333333333333334444444444\n17|333333333333333333334444444444\n18|333333333333333333334444444444\n19|333333333333333333334444444444\n20|333333333333333333334444444444\n21|333333333333333333334444444444\n22|333333333333333333334444444444\n23|333333333333333333334444444444\n24|333333333333333333334444444444\n25|333333333333333333334444444444\n26|333333333333333333334444444444\n27|333333333333333333334444444444\n28|333333333333333333334444444444\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`parts`-argument-002",
    "content": "--|---------|---------|---------|\n01|aa aa aa            █         \n02|aa aa aa                      \n03|aa aa aa                      \n04|aa aa aa                      \n05|aa aa aa                      \n06|aa aa aa                      \n07|aa aa aa                      \n08|aa aa aa                      \n09|aa aa aa                      \n10|aa aa aa                      \n11|aa aa aa                      \n12|aa aa aa                      \n13|aa aa aa                      \n14|aa aa aa                      \n15|aa aa aa                      \n16|aa aa aa                      \n17|aa aa aa                      \n18|aa aa aa                      \n19|aa aa aa                      \n20|aa aa aa                      \n21|aa aa aa                      \n22|aa aa aa                      \n23|aa aa aa                      \n24|aa aa aa                      \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000003333333333\n03|000000000000000000003333333333\n04|000000000000000000003333333333\n05|000000000000000000003333333333\n06|000000000000000000003333333333\n07|000000000000000000003333333333\n08|000000000000000000003333333333\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`parts`-argument-003",
    "content": "--|---------|---------|---------|\n01|aa aa aa              █▐▌█    \n02|aa aa aa              █▐▌█    \n03|aa aa aa              █▐▌█    \n04|aa aa aa              █▐▌█    \n05|aa aa aa              █▐▌█    \n06|aa aa aa              █▐▌█    \n07|aa aa aa              █▐▌█    \n08|aa aa aa              █▐▌█    \n09|aa aa aa                      \n10|aa aa aa                      \n11|aa aa aa                      \n12|aa aa aa                      \n13|aa aa aa                      \n14|aa aa aa                      \n15|aa aa aa                      \n16|aa aa aa                      \n17|aa aa aa                      \n18|aa aa aa                      \n19|aa aa aa                      \n20|aa aa aa                      \n21|aa aa aa                      \n22|aa aa aa                      \n23|aa aa aa                      \n24|aa aa aa                      \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001111111111\n02|000000000000000000001111111111\n03|000000000000000000001111111111\n04|000000000000000000001111111111\n05|000000000000000000001111111111\n06|000000000000000000001111111111\n07|000000000000000000001111111111\n08|000000000000000000001111111111\n09|000000000000000000002222222222\n10|000000000000000000002222222222\n11|000000000000000000002222222222\n12|000000000000000000002222222222\n13|000000000000000000002222222222\n14|000000000000000000002222222222\n15|000000000000000000002222222222\n16|000000000000000000002222222222\n17|000000000000000000002222222222\n18|000000000000000000002222222222\n19|000000000000000000002222222222\n20|000000000000000000002222222222\n21|000000000000000000002222222222\n22|000000000000000000002222222222\n23|000000000000000000002222222222\n24|000000000000000000002222222222\n25|333333333333333333332222222222\n26|333333333333333333332222222222\n27|333333333333333333332222222222\n28|333333333333333333332222222222\n29|444444444444444444444444444444\n30|555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`parts`-argument-004",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃ █▐▌█    \n02|        a a a a     ┃ █▐▌█    \n03|                    ┃ █▐▌█    \n04|  a  aaa  a  aaa    ┃ █▐▌█    \n05| a a a aaaaaaaaa    █ █▐▌█    \n06|                    ┃ █▐▌█    \n07|  a  aaa  a  aaa    ┃ █▐▌█    \n08|        a a a a     ┃ █▐▌█    \n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000001222222222\n03|000000000000000000001222222222\n04|000000000000000000001222222222\n05|000000000000000000001222222222\n06|000000000000000000001222222222\n07|000000000000000000001222222222\n08|000000000000000000001222222222\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`parts`-argument-005",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃2█▐▌█    \n02|        a a a a     ┃ █▐▌█    \n03|                    ┃ █▐▌█    \n04|  a  aaa  a  aaa    ┃ █▐▌█    \n05| a a a aaaaaaaaa    █ █▐▌█    \n06|                    ┃ █▐▌█    \n07|  a  aaa  a  aaa    ┃ █▐▌█    \n08|        a a a a     ┃ █▐▌█    \n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233332222\n02|000000000000000000001233332222\n03|000000000000000000001233332222\n04|000000000000000000001222222222\n05|000000000000000000001233332222\n06|000000000000000000001222222222\n07|000000000000000000001233332222\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`vim.{g,b}.minimap_disable`---test-+-args-{-'b'-}",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █         \n02|        a a a a               \n03|                              \n04|  a  aaa  a  aaa              \n05| a a a aaaaaaaaa              \n06|                              \n07|  a  aaa  a  aaa              \n08|        a a a a               \n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000003333333333\n03|000000000000000000003333333333\n04|000000000000000000003333333333\n05|000000000000000000003333333333\n06|000000000000000000003333333333\n07|000000000000000000003333333333\n08|000000000000000000003333333333\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---respects-`vim.{g,b}.minimap_disable`---test-+-args-{-'g'-}",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █         \n02|        a a a a               \n03|                              \n04|  a  aaa  a  aaa              \n05| a a a aaaaaaaaa              \n06|                              \n07|  a  aaa  a  aaa              \n08|        a a a a               \n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 1,1                 \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000003333333333\n03|000000000000000000003333333333\n04|000000000000000000003333333333\n05|000000000000000000003333333333\n06|000000000000000000003333333333\n07|000000000000000000003333333333\n08|000000000000000000003333333333\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---works",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    █         \n02|        a a a a               \n03|                              \n04|  a  aaa  a  aaa              \n05| a a a aaaaaaaaa              \n06|                              \n07|  a  aaa  a  aaa              \n08|        a a a a               \n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|000000000000000000003333333333\n03|000000000000000000003333333333\n04|000000000000000000003333333333\n05|000000000000000000003333333333\n06|000000000000000000003333333333\n07|000000000000000000003333333333\n08|000000000000000000003333333333\n09|000000000000000000003333333333\n10|000000000000000000003333333333\n11|000000000000000000003333333333\n12|000000000000000000003333333333\n13|000000000000000000003333333333\n14|000000000000000000003333333333\n15|000000000000000000003333333333\n16|000000000000000000003333333333\n17|000000000000000000003333333333\n18|000000000000000000003333333333\n19|000000000000000000003333333333\n20|000000000000000000003333333333\n21|000000000000000000003333333333\n22|000000000000000000003333333333\n23|000000000000000000003333333333\n24|000000000000000000003333333333\n25|444444444444444444443333333333\n26|444444444444444444443333333333\n27|444444444444444444443333333333\n28|444444444444444444443333333333\n29|555555555555555555555555555555\n30|666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_map.lua---refresh()---works-002",
    "content": "--|---------|---------|---------|\n01|  a  aaa  a  aaa    ┃2 🬀🬁🬂🬃🬄🬅🬆\n02|        a a a a     ┃ 🬇🬈🬉🬊🬋🬌🬍🬎\n03|                    ┃ 🬏🬐🬑🬒🬓▌🬔🬕\n04|  a  aaa  a  aaa    ┃ 🬖🬗🬘🬙🬚🬛🬜🬝\n05| a a a aaaaaaaaa    █ 🬞🬟🬠🬡🬢🬣🬤🬥\n06|                    ┃ 🬦🬧▐🬨🬩🬪🬫🬬\n07|  a  aaa  a  aaa    ┃ 🬭🬮🬯🬰🬱🬲🬳🬴\n08|        a a a a     ┃ 🬵🬶🬷🬸🬹🬺🬻█\n09|a a a a a a a a               \n10|  a  aaa  a  aaa              \n11| a a a aaaaaaaaa              \n12|a a a a a a a a               \n13|  a  aaa  a  aaa              \n14|        a a a a               \n15| a a a a a a a a              \n16|  a  aaa  a  aaa              \n17| a a a aaaaaaaaa              \n18| a a a a a a a a              \n19|  a  aaa  a  aaa              \n20|        a a a a               \n21|aaaaaaaaaaaaaaaa              \n22|  a  aaa  a  aaa              \n23| a a a aaaaaaaaa              \n24|aaaaaaaaaaaaaaaa              \n25|~                             \n26|~                             \n27|~                             \n28|~                             \n29|[No Name] 15,1                \n30|                              \n\n--|---------|---------|---------|\n01|000000000000000000001233333333\n02|000000000000000000001233333333\n03|000000000000000000001233333333\n04|000000000000000000001222222222\n05|000000000000000000001233333333\n06|000000000000000000001222222222\n07|000000000000000000001233333333\n08|000000000000000000001222222222\n09|000000000000000000004444444444\n10|000000000000000000004444444444\n11|000000000000000000004444444444\n12|000000000000000000004444444444\n13|000000000000000000004444444444\n14|000000000000000000004444444444\n15|000000000000000000004444444444\n16|000000000000000000004444444444\n17|000000000000000000004444444444\n18|000000000000000000004444444444\n19|000000000000000000004444444444\n20|000000000000000000004444444444\n21|000000000000000000004444444444\n22|000000000000000000004444444444\n23|000000000000000000004444444444\n24|000000000000000000004444444444\n25|555555555555555555554444444444\n26|555555555555555555554444444444\n27|555555555555555555554444444444\n28|555555555555555555554444444444\n29|666666666666666666666666666666\n30|777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-'winborder'-option",
    "content": "-|---------|---------|---------|\n1|╭ Zoom ──────────────────────╮\n2|│                            │\n3|│~                           │\n4|╰────────────────────────────╯\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222220\n3|033333333333333333333333333330\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-'winborder'-option-002",
    "content": "-|---------|---------|---------|\n1|╔ Zoom ══════════════════════╗\n2|║                            ║\n3|║~                           ║\n4|╚════════════════════════════╝\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222220\n3|033333333333333333333333333330\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-'winborder'-option-003",
    "content": "-|---------|---------|---------|\n1|+ Zoom ----------------------+\n2||                            |\n3||~                           |\n4|+----------------------------+\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222220\n3|033333333333333333333333333330\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument",
    "content": "-|---------|---------|---------|\n1|                              \n2|~                             \n3|~                             \n4|~                             \n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|000000000000000000001111111111\n2|222222222222222222223333333333\n3|222222222222222222223333333333\n4|222222222222222222224444444444\n5|111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-002",
    "content": "-|---------|---------|---------|\n1|╔ Zoom ══════════════════════╗\n2|║                            ║\n3|║~                           ║\n4|╚════════════════════════════╝\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222220\n3|033333333333333333333333333330\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-003",
    "content": "-|---------|---------|---------|\n1|┌…to check truncation┐        \n2|│                    │        \n3|│~                   │        \n4|└────────────────────┘        \n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111111111111111111022222222\n2|033333333333333333333044444444\n3|055555555555555555555044444444\n4|000000000000000000000066666666\n5|222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-004",
    "content": "-|---------|---------|---------|\n1|x Zoom xxxxxxxxxxxxxxxxxxxxxxx\n2|                              \n3|~                             \n4|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|222222222222222222222222222222\n3|333333333333333333333333333333\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-005",
    "content": "-|---------|---------|---------|\n1|x                            x\n2|x~                           x\n3|x~                           x\n4|x~                           x\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111111111111111111111111110\n2|022222222222222222222222222220\n3|022222222222222222222222222220\n4|022222222222222222222222222220\n5|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-006",
    "content": "-|---------|---------|---------|\n1|! Zoom xxxxxxxxxxxxxxxxxxxxxxx\n2|x                             \n3|x~                            \n4|x~                            \n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222222\n3|033333333333333333333333333333\n4|033333333333333333333333333333\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-007",
    "content": "-|---------|---------|---------|\n1|x                            x\n2|x~                           x\n3|x~                           x\n4|x~                           x\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111111111111111111111111110\n2|022222222222222222222222222220\n3|022222222222222222222222222220\n4|022222222222222222222222222220\n5|333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-008",
    "content": "-|---------|---------|---------|\n1|! Zoom xxxxxxxxxxxxxxxxxxxxxx!\n2|x                            x\n3|x~                           x\n4|!xxxxxxxxxxxxxxxxxxxxxxxxxxxx!\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222220\n3|033333333333333333333333333330\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---respects-`config`-argument-009",
    "content": "-|---------|---------|---------|\n1|x Zoom xxxxxxxxxxxxxxxxxxxxxxx\n2|x                            x\n3|x~                           x\n4|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n5|               0,0-1      All \n\n-|---------|---------|---------|\n1|011111100000000000000000000000\n2|022222222222222222222222222220\n3|033333333333333333333333333330\n4|000000000000000000000000000000\n5|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_misc.lua---zoom()---works",
    "content": "-|---------|---------|\n1|aaa                 \n2|bbb                 \n3|~                   \n4|~                   \n5|          1,1   All \n\n-|---------|---------|\n1|00000000000000000000\n2|00000000000000000000\n3|11111111111111111111\n4|11111111111111111111\n5|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---handles-not-present-data",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:56 │ fruits-lsp: Testing (0%)          │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---handles-not-present-data-002",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:57 │ fruits-lsp: Testing (0%)          │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---handles-not-present-data-003",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:58 │ fruits-lsp: Testing (100%)        │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---respects-`lsp_progress.duration_last`",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:58 │ fruits-lsp: Testing done (100%)   │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---respects-`lsp_progress.duration_last`-002",
    "content": "-|---------|---------|---------|---------|---------|\n1|                                                  \n2|~                                                 \n3|~                                                 \n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00000000000000000000000000000000000000000000000000\n2|11111111111111111111111111111111111111111111111111\n3|11111111111111111111111111111111111111111111111111\n4|11111111111111111111111111111111111111111111111111\n5|11111111111111111111111111111111111111111111111111\n6|11111111111111111111111111111111111111111111111111\n7|22222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---works",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:56 │ fruits-lsp: Testing 0/1 (0%)      │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---works-002",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:57 │ fruits-lsp: Testing 1/1 (100%)    │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---works-003",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:58 │ fruits-lsp: Testing done (100%)   │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---works-004",
    "content": "-|---------|---------|---------|---------|---------|\n1|   ┌ Notifications ──────────────────────────────┐\n2|~  │12:34:58 │ fruits-lsp: Testing done (100%)   │\n3|~  └─────────────────────────────────────────────┘\n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00012222222222222221111111111111111111111111111111\n2|33314444444444444444444444444444444444444444444441\n3|33311111111111111111111111111111111111111111111111\n4|33333333333333333333333333333333333333333333333333\n5|33333333333333333333333333333333333333333333333333\n6|33333333333333333333333333333333333333333333333333\n7|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---LSP-progress---works-005",
    "content": "-|---------|---------|---------|---------|---------|\n1|                                                  \n2|~                                                 \n3|~                                                 \n4|~                                                 \n5|~                                                 \n6|~                                                 \n7|                                0,0-1         All \n\n-|---------|---------|---------|---------|---------|\n1|00000000000000000000000000000000000000000000000000\n2|11111111111111111111111111111111111111111111111111\n3|11111111111111111111111111111111111111111111111111\n4|11111111111111111111111111111111111111111111111111\n5|11111111111111111111111111111111111111111111111111\n6|11111111111111111111111111111111111111111111111111\n7|22222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---computes-default-dimensions-based-on-buffer-content",
    "content": "--|---------|---------|---------|---------|-----\n01|                               ┌…ifications ┐\n02|~                              │12:34:56 │ a│\n03|~                              └────────────┘\n04|~                                            \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000000012222222222221\n02|333333333333333333333333333333314444444444441\n03|333333333333333333333333333333311111111111111\n04|333333333333333333333333333333333333333333333\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---computes-default-dimensions-based-on-buffer-content-002",
    "content": "--|---------|---------|---------|---------|-----\n01|                             ┌…otifications ┐\n02|~                            │12:34:57 │ aaa│\n03|~                            │12:34:56 │ a  │\n04|~                            └──────────────┘\n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000001222222222222221\n02|333333333333333333333333333331444444444444441\n03|333333333333333333333333333331444444444444441\n04|333333333333333333333333333331111111111111111\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---fully-updates-on-vim-resize",
    "content": "--|---------|---------|---------|---------|---------|\n01|                             ┌ Notifications ────┐\n02|~                            │12:34:56 │ A very l│\n03|~                            │ong notification   │\n04|~                            └───────────────────┘\n05|~                                                 \n06|~                                                 \n07|~                                                 \n08|~                                                 \n09|~                                                 \n10|                                0,0-1         All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000122222222222222211111\n02|33333333333333333333333333333144444444444444444441\n03|33333333333333333333333333333144444444444444444441\n04|33333333333333333333333333333111111111111111111111\n05|33333333333333333333333333333333333333333333333333\n06|33333333333333333333333333333333333333333333333333\n07|33333333333333333333333333333333333333333333333333\n08|33333333333333333333333333333333333333333333333333\n09|33333333333333333333333333333333333333333333333333\n10|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---fully-updates-on-vim-resize-002",
    "content": "--|---------|---------|-----\n01|              ┌…cations ┐\n02|~             │12:34:56 │\n03|~             ││ A very │\n04|~             │long noti│\n05|~             │fication │\n06|~             └─────────┘\n07|~                        \n08|~                        \n09|~                        \n10|             0,0-1   All \n\n--|---------|---------|-----\n01|0000000000000012222222221\n02|3333333333333314444444441\n03|3333333333333314444444441\n04|3333333333333314444444441\n05|3333333333333314444444441\n06|3333333333333311111111111\n07|3333333333333333333333333\n08|3333333333333333333333333\n09|3333333333333333333333333\n10|5555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---fully-updates-on-vim-resize-003",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|~                                                 \n03|~                                                 \n04|~                  ┌ Notifications ────┐          \n05|~                  │12:34:58 │ A very l│          \n06|~                  │ong notification   │          \n07|~                  └───────────────────┘          \n08|~                                                 \n09|~                                                 \n10|~                                                 \n11|~                                                 \n12|~                                                 \n13|~                                                 \n14|~                                                 \n15|                                0,0-1         All \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111\n04|11111111111111111112333333333333333222221111111111\n05|11111111111111111112444444444444444444421111111111\n06|11111111111111111112444444444444444444421111111111\n07|11111111111111111112222222222222222222221111111111\n08|11111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111\n10|11111111111111111111111111111111111111111111111111\n11|11111111111111111111111111111111111111111111111111\n12|11111111111111111111111111111111111111111111111111\n13|11111111111111111111111111111111111111111111111111\n14|11111111111111111111111111111111111111111111111111\n15|55555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---fully-updates-on-vim-resize-004",
    "content": "--|---------|---------|-----\n01|                         \n02|~                        \n03|~        ┌…cations ┐     \n04|~        │12:34:58 │     \n05|~        ││ A very │     \n06|~        │long noti│     \n07|~        │fication │     \n08|~        └─────────┘     \n09|~                        \n10|             0,0-1   All \n\n--|---------|---------|-----\n01|0000000000000000000000000\n02|1111111111111111111111111\n03|1111111112333333333211111\n04|1111111112444444444211111\n05|1111111112444444444211111\n06|1111111112444444444211111\n07|1111111112444444444211111\n08|1111111112222222222211111\n09|1111111111111111111111111\n10|5555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---handles-width-computation-for-empty-lines-inside-notification-buffer",
    "content": "-|---------|---------|\n1|                 ┌…┐\n2|~                │ │\n3|~                │ │\n4|~                └─┘\n5|~                   \n6|~                   \n7|          0,0-1 All \n\n-|---------|---------|\n1|00000000000000000121\n2|33333333333333333141\n3|33333333333333333141\n4|33333333333333333111\n5|33333333333333333333\n6|33333333333333333333\n7|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-'winborder'-option",
    "content": "--|---------|---------|---------|---------|-----\n01|                           ╭ Notifications ─╮\n02|~                          │12:34:56 │ Hello│\n03|~                          ╰────────────────╯\n04|~                                            \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000122222222222222211\n02|333333333333333333333333333144444444444444441\n03|333333333333333333333333333111111111111111111\n04|333333333333333333333333333333333333333333333\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-'winborder'-option-002",
    "content": "--|---------|---------|---------|---------|-----\n01|                           ╔ Notifications ═╗\n02|~                          ║12:34:58 │ Hello║\n03|~                          ╚════════════════╝\n04|~                                            \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000122222222222222211\n02|333333333333333333333333333144444444444444441\n03|333333333333333333333333333111111111111111111\n04|333333333333333333333333333333333333333333333\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-'winborder'-option-003",
    "content": "--|---------|---------|---------|---------|-----\n01|                           + Notifications -+\n02|~                          |12:35:00 │ Hello|\n03|~                          +----------------+\n04|~                                            \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000122222222222222211\n02|333333333333333333333333333144444444444444441\n03|333333333333333333333333333111111111111111111\n04|333333333333333333333333333333333333333333333\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`content.format`",
    "content": "--|---------|---------|---------|---------|-----\n01|                                      ┌…ons ┐\n02|~                                     │Hello│\n03|~                                     └─────┘\n04|~                                            \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000001222221\n02|333333333333333333333333333333333333331444441\n03|333333333333333333333333333333333333331111111\n04|333333333333333333333333333333333333333333333\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`content.sort`",
    "content": "--|---------|---------|---------|---------|-----\n01|                           ┌ Notifications ─┐\n02|~                          │12:34:56 │ Hello│\n03|~                          │12:34:57 │ World│\n04|~                          └────────────────┘\n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000122222222222222211\n02|333333333333333333333333333144444444444444441\n03|333333333333333333333333333144444444444444441\n04|333333333333333333333333333111111111111111111\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.config`",
    "content": "--|---------|---------|---------|---------|-----\n01|               12:34:57 │ World              \n02|~                                            \n03|~                                            \n04|~                                            \n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000111111111111111111111111111111\n02|222222222222222222222222222222222222222222222\n03|222222222222222222222222222222222222222222222\n04|222222222222222222222222222222222222222222222\n05|222222222222222222222222222222222222222222222\n06|222222222222222222222222222222222222222222222\n07|222222222222222222222222222222222222222222222\n08|222222222222222222222222222222222222222222222\n09|222222222222222222222222222222222222222222222\n10|222222222222222222222222222222222222222222222\n11|222222222222222222222222222222222222222222222\n12|333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.config`-002",
    "content": "--|---------|---------|---------|---------|-----\n01|                  ╔…itle to check truncation╗\n02|~                 ║12:34:57 │ World         ║\n03|~                 ║12:34:56 │ Hello         ║\n04|~                 ║                         ║\n05|~                 ║                         ║\n06|~                 ║                         ║\n07|~                 ╚═════════════════════════╝\n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000122222222222222222222222221\n02|333333333333333333144444444444444444444444441\n03|333333333333333333144444444444444444444444441\n04|333333333333333333155555555555555555555555551\n05|333333333333333333155555555555555555555555551\n06|333333333333333333155555555555555555555555551\n07|333333333333333333111111111111111111111111111\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.config`-003",
    "content": "--|---------|---------|---------|---------|-----\n01|┌…jklmnopqrstuvwxyzabcdefgijklmnopqrstuvwxyz┐\n02|│12:34:57 │ World                           │\n03|│12:34:56 │ Hello                           │\n04|└───────────────────────────────────────────┘\n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|011111111111111111111111111111111111111111110\n02|022222222222222222222222222222222222222222220\n03|022222222222222222222222222222222222222222220\n04|000000000000000000000000000000000000000000000\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.max_width_share`",
    "content": "--|---------|---------|---------|---------|-----\n01|          ┌ Notifications ──────────────────┐\n02|~         │12:34:56 │ A very-very-very-very-│\n03|~         │very long notification           │\n04|~         └─────────────────────────────────┘\n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000012222222222222221111111111111111111\n02|333333333314444444444444444444444444444444441\n03|333333333314444444444444444444444444444444441\n04|333333333311111111111111111111111111111111111\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.max_width_share`-002",
    "content": "--|---------|---------|---------|---------|-----\n01|┌ Notifications ────────────────────────────┐\n02|│12:34:56 │ A very-very-very-very-very long │\n03|│notification                               │\n04|└───────────────────────────────────────────┘\n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|011111111111111100000000000000000000000000000\n02|022222222222222222222222222222222222222222220\n03|022222222222222222222222222222222222222222220\n04|000000000000000000000000000000000000000000000\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.max_width_share`-003",
    "content": "--|---------|---------|---------|---------|-----\n01|┌ Notifications ────────────────────────────┐\n02|│12:34:56 │ A very-very-very-very-very long │\n03|│notification                               │\n04|└───────────────────────────────────────────┘\n05|~                                            \n06|~                                            \n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|011111111111111100000000000000000000000000000\n02|022222222222222222222222222222222222222222220\n03|022222222222222222222222222222222222222222220\n04|000000000000000000000000000000000000000000000\n05|333333333333333333333333333333333333333333333\n06|333333333333333333333333333333333333333333333\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-`window.max_width_share`-004",
    "content": "--|---------|---------|---------|---------|-----\n01|                                          ┌…┐\n02|~                                         │1│\n03|~                                         │2│\n04|~                                         │:│\n05|~                                         │3│\n06|~                                         │4│\n07|~                                         │:│\n08|~                                         │5│\n09|~                                         │6│\n10|~                                         │ │\n11|~                                         └─┘\n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000000000000000000121\n02|333333333333333333333333333333333333333333141\n03|333333333333333333333333333333333333333333141\n04|333333333333333333333333333333333333333333141\n05|333333333333333333333333333333333333333333141\n06|333333333333333333333333333333333333333333141\n07|333333333333333333333333333333333333333333141\n08|333333333333333333333333333333333333333333141\n09|333333333333333333333333333333333333333333141\n10|333333333333333333333333333333333333333333141\n11|333333333333333333333333333333333333333333111\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline",
    "content": "-|---------|---------|\n1| [No Name]          \n2|                ┌… ┐\n3|~               │#7│\n4|~               │#6│\n5|~               └──┘\n6|[No Name] 0,0-1     \n7|                    \n\n-|---------|---------|\n1|00000000000111111111\n2|22222222222222223443\n3|55555555555555553663\n4|55555555555555553663\n5|55555555555555553333\n6|77777777777777777777\n7|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-002",
    "content": "-|---------|---------|\n1| [No Name]          \n2|                ┌… ┐\n3|~               │#7│\n4|~               │#6│\n5|~               │#5│\n6|~               └──┘\n7|          0,0-1 All \n\n-|---------|---------|\n1|00000000000111111111\n2|22222222222222223443\n3|55555555555555553663\n4|55555555555555553663\n5|55555555555555553663\n6|55555555555555553333\n7|77777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-003",
    "content": "-|---------|---------|\n1|                ┌… ┐\n2|~               │#7│\n3|~               │#6│\n4|~               │#5│\n5|~               └──┘\n6|[No Name] 0,0-1     \n7|                    \n\n-|---------|---------|\n1|00000000000000001221\n2|33333333333333331441\n3|33333333333333331441\n4|33333333333333331441\n5|33333333333333331111\n6|55555555555555555555\n7|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-004",
    "content": "-|---------|---------|\n1|                ┌… ┐\n2|~               │#7│\n3|~               │#6│\n4|~               │#5│\n5|~               │#4│\n6|~               └──┘\n7|          0,0-1 All \n\n-|---------|---------|\n1|00000000000000001221\n2|33333333333333331441\n3|33333333333333331441\n4|33333333333333331441\n5|33333333333333331441\n6|33333333333333331111\n7|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-005",
    "content": "-|---------|---------|\n1| [No Name]          \n2|                  #7\n3|~                 #6\n4|~                 #5\n5|~                 #4\n6|[No Name] 0,0-1     \n7|                    \n\n-|---------|---------|\n1|00000000000111111111\n2|22222222222222222233\n3|44444444444444444433\n4|44444444444444444433\n5|44444444444444444433\n6|55555555555555555555\n7|66666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-006",
    "content": "-|---------|---------|\n1| [No Name]          \n2|                  #7\n3|~                 #6\n4|~                 #5\n5|~                 #4\n6|~                 #3\n7|          0,0-1 All \n\n-|---------|---------|\n1|00000000000111111111\n2|22222222222222222233\n3|44444444444444444433\n4|44444444444444444433\n5|44444444444444444433\n6|44444444444444444433\n7|55555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-007",
    "content": "-|---------|---------|\n1|                  #7\n2|~                 #6\n3|~                 #5\n4|~                 #4\n5|~                 #3\n6|[No Name] 0,0-1     \n7|                    \n\n-|---------|---------|\n1|00000000000000000011\n2|22222222222222222211\n3|22222222222222222211\n4|22222222222222222211\n5|22222222222222222211\n6|33333333333333333333\n7|44444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-008",
    "content": "-|---------|---------|\n1|                  #7\n2|~                 #6\n3|~                 #5\n4|~                 #4\n5|~                 #3\n6|~                 #2\n7|          0,0-1 All \n\n-|---------|---------|\n1|00000000000000000011\n2|22222222222222222211\n3|22222222222222222211\n4|22222222222222222211\n5|22222222222222222211\n6|22222222222222222211\n7|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-009",
    "content": "-|---------|---------|\n1|                  #7\n2|~                 #6\n3|~                 #5\n4|~                 #4\n5|                    \n6|                    \n7|          0,0-1 All \n\n-|---------|---------|\n1|00000000000000000011\n2|22222222222222222211\n3|22222222222222222211\n4|22222222222222222211\n5|00000000000000000000\n6|00000000000000000000\n7|00000000003333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---respects-tabline-statusline-cmdline-010",
    "content": "-|---------|---------|\n1|                  #7\n2|~                 #6\n3|~                 #5\n4|~                 #4\n5|~                 #3\n6|~                 #2\n7|~                 #1\n\n-|---------|---------|\n1|00000000000000000011\n2|22222222222222222211\n3|22222222222222222211\n4|22222222222222222211\n5|22222222222222222211\n6|22222222222222222211\n7|22222222222222222211\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---shows-start-of-buffer-if-it-does-not-fit-whole",
    "content": "--|---------|---------|---------|---------|-----\n01|                             ┌…otifications ┐\n02|~                            │12:35:15 │ #20│\n03|~                            │12:35:14 │ #19│\n04|~                            │12:35:13 │ #18│\n05|~                            │12:35:12 │ #17│\n06|~                            │12:35:11 │ #16│\n07|~                            │12:35:10 │ #15│\n08|~                            │12:35:09 │ #14│\n09|~                            │12:35:08 │ #13│\n10|~                            │12:35:07 │ #12│\n11|~                            └──────────────┘\n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000001222222222222221\n02|333333333333333333333333333331444444444444441\n03|333333333333333333333333333331444444444444441\n04|333333333333333333333333333331444444444444441\n05|333333333333333333333333333331444444444444441\n06|333333333333333333333333333331444444444444441\n07|333333333333333333333333333331444444444444441\n08|333333333333333333333333333331444444444444441\n09|333333333333333333333333333331444444444444441\n10|333333333333333333333333333331444444444444441\n11|333333333333333333333333333331111111111111111\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---works-with-multiline-messages",
    "content": "--|---------|---------|---------|---------|-----\n01|                           ┌ Notifications ─┐\n02|~                          │12:34:57 │ Hello│\n03|~                          │Again           │\n04|~                          │12:34:56 │ Hello│\n05|~                          │Brave           │\n06|~                          │World           │\n07|~                          └────────────────┘\n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000122222222222222211\n02|333333333333333333333333333144444444444444441\n03|333333333333333333333333333144444444444444441\n04|333333333333333333333333333144444444444444441\n05|333333333333333333333333333144444444444444441\n06|333333333333333333333333333144444444444444441\n07|333333333333333333333333333111111111111111111\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---wraps-text",
    "content": "--|---------|---------|---------|---------|-----\n01|                          ┌ Notifications ──┐\n02|~                         │12:34:56 │ A very│\n03|~                         │ big notification│\n04|~                         │ message which sh│\n05|~                         │ould be wrapped  │\n06|~                         └─────────────────┘\n07|~                                            \n08|~                                            \n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000001222222222222222111\n02|333333333333333333333333331444444444444444441\n03|333333333333333333333333331444444444444444441\n04|333333333333333333333333331444444444444444441\n05|333333333333333333333333331444444444444444441\n06|333333333333333333333333331111111111111111111\n07|333333333333333333333333333333333333333333333\n08|333333333333333333333333333333333333333333333\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---Window---wraps-text-002",
    "content": "--|---------|---------|---------|---------|-----\n01|                          ┌ Notifications ──┐\n02|~                         │12:34:57 │ Anothe│\n03|~                         │r wrapped message│\n04|~                         │12:34:56 │ A very│\n05|~                         │ big notification│\n06|~                         │ message which sh│\n07|~                         │ould be wrapped  │\n08|~                         └─────────────────┘\n09|~                                            \n10|~                                            \n11|~                                            \n12|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000001222222222222222111\n02|333333333333333333333333331444444444444444441\n03|333333333333333333333333331444444444444444441\n04|333333333333333333333333331444444444444444441\n05|333333333333333333333333331444444444444444441\n06|333333333333333333333333331444444444444444441\n07|333333333333333333333333331444444444444444441\n08|333333333333333333333333331111111111111111111\n09|333333333333333333333333333333333333333333333\n10|333333333333333333333333333333333333333333333\n11|333333333333333333333333333333333333333333333\n12|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---add()---allows-empty-string-message",
    "content": "-|---------|---------|---------|---------|-----\n1|                                ┌…fications ┐\n2|~                               │12:34:56 │ │\n3|~                               └───────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000001222222222221\n2|333333333333333333333333333333331444444444441\n3|333333333333333333333333333333331111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---add()---works",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---clear()---works",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:57 │ World│\n3|~                          │12:34:56 │ Hello│\n4|~                          └────────────────┘\n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333155555555555555551\n4|333333333333333333333333333111111111111111111\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---clear()---works-002",
    "content": "-|---------|---------|---------|---------|-----\n1|                                             \n2|~                                            \n3|~                                            \n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111\n5|111111111111111111111111111111111111111111111\n6|111111111111111111111111111111111111111111111\n7|222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---make_notify()---works",
    "content": "--|---------|---------|---------|---------|-----\n01|                           ┌ Notifications ─┐\n02|~                          │12:34:56 │ error│\n03|~                          │12:34:57 │ warn │\n04|~                          │12:34:58 │ info │\n05|~                          │12:34:59 │ debug│\n06|~                          │12:35:00 │ trace│\n07|~                          │12:35:01 │ off  │\n08|~                          └────────────────┘\n09|~                                            \n10|                           0,0-1         All \n\n--|---------|---------|---------|---------|-----\n01|000000000000000000000000000122222222222222211\n02|333333333333333333333333333144444444444444441\n03|333333333333333333333333333155555555555555551\n04|333333333333333333333333333166666666666666661\n05|333333333333333333333333333177777777777777771\n06|333333333333333333333333333188888888888888881\n07|333333333333333333333333333199999999999999991\n08|333333333333333333333333333111111111111111111\n09|333333333333333333333333333333333333333333333\n10|:::::::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---refresh()---respects-`vim.{g,b}.mininotify_disable`---test-+-args-{-'b'-}",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---refresh()---respects-`vim.{g,b}.mininotify_disable`---test-+-args-{-'b'-}-002",
    "content": "-|---------|---------|---------|---------|-----\n1|                                             \n2|~                                            \n3|~                                            \n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111\n5|111111111111111111111111111111111111111111111\n6|111111111111111111111111111111111111111111111\n7|222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---refresh()---respects-`vim.{g,b}.mininotify_disable`---test-+-args-{-'b'-}-003",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---refresh()---respects-`vim.{g,b}.mininotify_disable`---test-+-args-{-'g'-}",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---refresh()---respects-`vim.{g,b}.mininotify_disable`---test-+-args-{-'g'-}-002",
    "content": "-|---------|---------|---------|---------|-----\n1|                                             \n2|~                                            \n3|~                                            \n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111\n5|111111111111111111111111111111111111111111111\n6|111111111111111111111111111111111111111111111\n7|222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---refresh()---respects-`vim.{g,b}.mininotify_disable`---test-+-args-{-'g'-}-003",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---remove()---works",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---remove()---works-002",
    "content": "-|---------|---------|---------|---------|-----\n1|                                             \n2|~                                            \n3|~                                            \n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111\n5|111111111111111111111111111111111111111111111\n6|111111111111111111111111111111111111111111111\n7|222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---remove()---works-with-several-active-notifications",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:57 │ World│\n3|~                          │12:34:56 │ Hello│\n4|~                          └────────────────┘\n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333155555555555555551\n4|333333333333333333333333333111111111111111111\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---remove()---works-with-several-active-notifications-002",
    "content": "-|---------|---------|---------|---------|-----\n1|                           ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---show_history()---respects-`content.format`",
    "content": "-|---------|---------|---------|---------|-----\n1|New message                ┌ Notifications ─┐\n2|~                          │12:34:56 │ Hello│\n3|~                          └────────────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           1,1           All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|333333333333333333333333333111111111111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---show_history()---reuses-history-buffer",
    "content": "-|---------|---------|---------|---------|-----\n1|12:34:56 │ Hello           ┌ Notifications ─┐\n2|12:34:57 │ World           │12:34:57 │ World│\n3|~                          │12:34:56 │ Hello│\n4|~                          └────────────────┘\n5|~                                            \n6|~                                            \n7|                           1,1           All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|000000000000000000000000000133333333333333331\n3|444444444444444444444444444133333333333333331\n4|444444444444444444444444444111111111111111111\n5|444444444444444444444444444444444444444444444\n6|444444444444444444444444444444444444444444444\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---show_history()---shows-all-notifications",
    "content": "-|---------|---------|---------|---------|-----\n1|12:34:56 │ Hello           ┌ Notifications ─┐\n2|12:34:57 │ World           │12:34:58 │ Brave│\n3|12:34:58 │ Brave           │12:34:56 │ Hello│\n4|~                          └────────────────┘\n5|~                                            \n6|~                                            \n7|                           1,1           All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|555555555555555555555555555166666666666666661\n4|777777777777777777777777777111111111111111111\n5|777777777777777777777777777777777777777777777\n6|777777777777777777777777777777777777777777777\n7|888888888888888888888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---show_history()---sorts-by-update-time",
    "content": "-|---------|---------|---------|---------|-----\n1|12:34:56 │ Hello           ┌ Notifications ─┐\n2|12:34:58 │ Brave           │12:34:58 │ Brave│\n3|12:34:59 │ WORLD           │12:34:56 │ Hello│\n4|~                          │12:34:59 │ WORLD│\n5|~                          └────────────────┘\n6|~                                            \n7|                           1,1           All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|000000000000000000000000000133333333333333331\n3|000000000000000000000000000133333333333333331\n4|444444444444444444444444444133333333333333331\n5|444444444444444444444444444111111111111111111\n6|444444444444444444444444444444444444444444444\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---show_history()---works",
    "content": "-|---------|---------|---------|---------|-----\n1|12:34:56 │ Hello           ┌ Notifications ─┐\n2|12:34:57 │ World           │12:34:57 │ World│\n3|~                          │12:34:56 │ Hello│\n4|~                          └────────────────┘\n5|~                                            \n6|~                                            \n7|                           1,1           All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000122222222222222211\n2|333333333333333333333333333144444444444444441\n3|555555555555555555555555555166666666666666661\n4|555555555555555555555555555111111111111111111\n5|555555555555555555555555555555555555555555555\n6|555555555555555555555555555555555555555555555\n7|777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---update()---works",
    "content": "-|---------|---------|---------|---------|-----\n1|                                  ┌…cations ┐\n2|~                                 │OLD Hello│\n3|~                                 └─────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000000012222222221\n2|333333333333333333333333333333333314444444441\n3|333333333333333333333333333333333311111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_notify.lua---update()---works-002",
    "content": "-|---------|---------|---------|---------|-----\n1|                                  ┌…cations ┐\n2|~                                 │NEW World│\n3|~                                 └─────────┘\n4|~                                            \n5|~                                            \n6|~                                            \n7|                           0,0-1         All \n\n-|---------|---------|---------|---------|-----\n1|000000000000000000000000000000000012222222221\n2|333333333333333333333333333333333314444444441\n3|333333333333333333333333333333333311111111111\n4|333333333333333333333333333333333333333333333\n5|333333333333333333333333333333333333333333333\n6|333333333333333333333333333333333333333333333\n7|555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---can-be-canceled",
    "content": "-|---------|--\n1|aa bb       \n2|~           \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|001111111111\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---can-be-canceled-002",
    "content": "-|---------|--\n1|aa bb       \n2|~           \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---correctly-highlights-first-step-with-'selection=exclusive'",
    "content": "-|---------|--\n1|aaa bbb     \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|001111111111\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---highlights-first-step---test-+-args-{-'blockwise'-}",
    "content": "-|---------|--\n1|aa aa       \n2|bb          \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|001111111111\n2|001111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---highlights-first-step---test-+-args-{-'charwise'-}",
    "content": "-|---------|--\n1|aa aa       \n2|bb          \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|001111111111\n2|111111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---highlights-first-step---test-+-args-{-'linewise'-}",
    "content": "-|---------|--\n1|aa aa       \n2|bb          \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000001111111\n2|111111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---works-with-multibyte-characters",
    "content": "-|---------|--\n1|  ыыы ффф   \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|001100000000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---works-with-multibyte-characters-002",
    "content": "-|---------|--\n1|  ╔═╗ ╚═╝   \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|001100000000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---works-with-multibyte-characters-003",
    "content": "-|---------|--\n1|  🬕🬂🬨  🬲🬭🬷  \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|001100000000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---works-with-multibyte-characters-004",
    "content": "-|---------|--\n1|  ыыы ффф   \n2|  эээ ююю   \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000111\n2|111111111111\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Exchange---works-with-multibyte-characters-005",
    "content": "-|---------|--\n1|  ыыы ффф   \n2|  эээ ююю   \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|001100000000\n2|001100000000\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Multiply---works-with-`cmdheight=0`",
    "content": "-|---------|---------|\n1|aa bb               \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Multiply---works-with-`cmdheight=0`-002",
    "content": "-|---------|---------|\n1|aaaa bb             \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Replace---works-with-`cmdheight=0`",
    "content": "-|---------|---------|\n1|aa bb               \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_operators.lua---Replace---works-with-`cmdheight=0`-002",
    "content": "-|---------|---------|\n1|aa aa               \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pairs.lua----BS--action---works",
    "content": "--|---------|--\n01|            \n02|~           \n03|~           \n04|~           \n05|~           \n06|~           \n07|~           \n08|~           \n09|<Name] 1,0-1\n10|:aabb       \n\n--|---------|--\n01|000000000000\n02|111111111111\n03|111111111111\n04|111111111111\n05|111111111111\n06|111111111111\n07|111111111111\n08|111111111111\n09|222222222222\n10|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua----Pick---has-proper-complete",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~     buffers                 \n04|~     cli                     \n05|~     files                   \n06|~     grep                    \n07|~     grep_live               \n08|~     help                    \n09|~     resume                  \n10|:Pick buffers                 \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111112222222222222222111111111\n04|111113333333333333333111111111\n05|111113333333333333333111111111\n06|111113333333333333333111111111\n07|111113333333333333333111111111\n08|111113333333333333333111111111\n09|111113333333333333333111111111\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua----Pick---has-proper-complete-002",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~     buffers                 \n09|~     files                   \n10|:Pick buffers                 \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111112222222222222222111111111\n09|111113333333333333333111111111\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua----Pick---has-proper-complete-003",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|~                             \n04|~                             \n05|~                             \n06|~                             \n07|~                             \n08|~     buffers                 \n09|~     files                   \n10|:Pick buffers x               \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|111111111111111111111111111111\n04|111111111111111111111111111111\n05|111111111111111111111111111111\n06|111111111111111111111111111111\n07|111111111111111111111111111111\n08|111112222222222222222111111111\n09|111113333333333333333111111111\n10|444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua----Pick---works",
    "content": "--|---------|---------|---------|---------|\n01|MIT (c)                                 \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ tests/dir-pick/real-f…│              \n07|│  [No Name]             │              \n08|│ tests/dir-pick/real-f…│              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffers ──────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555556211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777776211111111111111\n09|2888888888888888888888888211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2888888888888888888888888211111111111111\n14|2999999999222222229999999211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua----Pick---works-002",
    "content": "--|---------|---------|---------|---------|\n01|MIT (c)                                 \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ tests/dir-pick/real-f…│              \n07|│  [No Name]             │              \n08|│  [Scratch]             │              \n09|│ tests/dir-pick/real-f…│              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffers ──────── 1|4|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555556211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777776211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2888888888888888888888888211111111111111\n14|2999999999222222229999999211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Caret---moves-by-query-parts",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> abcd▏──┐    \n04|│         │    \n05|│         │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233444452221111\n04|266666666621111\n05|277777777721111\n06|277777777721111\n07|277777777721111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Caret---moves-by-query-parts-002",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ab▏cd──┐    \n04|│         │    \n05|│         │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233445442221111\n04|266666666621111\n05|277777777721111\n06|277777777721111\n07|277777777721111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Caret---moves-by-query-parts-003",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏abcd──┐    \n04|│         │    \n05|│         │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233455552221111\n04|266666666621111\n05|277777777721111\n06|277777777721111\n07|277777777721111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Caret---works",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ac▏b───┐    \n04|│         │    \n05|│         │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233445422221111\n04|266666666621111\n05|277777777721111\n06|277777777721111\n07|277777777721111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Caret---works-002",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> a▏b────┐    \n04|│         │    \n05|│         │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233454222221111\n04|266666666621111\n05|277777777721111\n06|277777777721111\n07|277777777721111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Caret---works-003",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> a▏─────┐    \n04|│a        │    \n05|│         │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233452222221111\n04|267777777721111\n05|288888888821111\n06|288888888821111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Choose---works-for-split-tab-variations",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|[No Name] 0,0-1                         \n09|                                        \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|2222222222222222222222222222222222222222\n09|3333333333333333333333333333333333333333\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|4444444444444444444444444444444444444444\n15|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Choose---works-for-split-tab-variations-002",
    "content": "--|---------|---------|---------|---------|\n01|                    │                   \n02|~                   │~                  \n03|~                   │~                  \n04|~                   │~                  \n05|~                   │~                  \n06|~                   │~                  \n07|~                   │~                  \n08|[No Name] 0,0-1      [No Name] 0,0-1    \n09|                                        \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000012222222222222222222\n02|3333333333333333333314444444444444444444\n03|3333333333333333333314444444444444444444\n04|3333333333333333333314444444444444444444\n05|3333333333333333333314444444444444444444\n06|3333333333333333333314444444444444444444\n07|3333333333333333333314444444444444444444\n08|5555555555555555555556666666666666666666\n09|2222222222222222222222222222222222222222\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|4444444444444444444444444444444444444444\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Choose---works-for-split-tab-variations-003",
    "content": "--|---------|---------|---------|---------|\n01| 3 [No Name]  [No Name]                X\n02|                                        \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0100000000000111111111110000000000000000\n02|2222222222222222222222222222222222222222\n03|3333333333333333333333333333333333333333\n04|3333333333333333333333333333333333333333\n05|3333333333333333333333333333333333333333\n06|3333333333333333333333333333333333333333\n07|3333333333333333333333333333333333333333\n08|3333333333333333333333333333333333333333\n09|3333333333333333333333333333333333333333\n10|3333333333333333333333333333333333333333\n11|3333333333333333333333333333333333333333\n12|3333333333333333333333333333333333333333\n13|3333333333333333333333333333333333333333\n14|3333333333333333333333333333333333333333\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---is-updated-after-moving-marking-current-item",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│General                 │              \n07|│Source name   │ My name │              \n08|│Source cwd    │ tests/di│              \n09|│Total items   │ 3       │              \n10|│Matched items │ 3       │              \n11|│Marked items  │ 0       │              \n12|│Current index │ 1       │              \n13|│                        │              \n14|└ My name ──────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444455555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333222222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---is-updated-after-moving-marking-current-item-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│General                 │              \n07|│Source name   │ My name │              \n08|│Source cwd    │ tests/di│              \n09|│Total items   │ 3       │              \n10|│Matched items │ 3       │              \n11|│Marked items  │ 0       │              \n12|│Current index │ 2       │              \n13|│                        │              \n14|└ My name ──────── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444455555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333222222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---is-updated-after-moving-marking-current-item-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│General                 │              \n07|│Source name   │ My name │              \n08|│Source cwd    │ tests/di│              \n09|│Total items   │ 3       │              \n10|│Matched items │ 3       │              \n11|│Marked items  │ 1       │              \n12|│Current index │ 2       │              \n13|│                        │              \n14|└ My name ────── 2|3|1/3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444455555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333222222333333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---is-updated-after-moving-marking-current-item-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│General                 │              \n07|│Source name   │ My name │              \n08|│Source cwd    │ tests/di│              \n09|│Total items   │ 3       │              \n10|│Matched items │ 3       │              \n11|│Marked items  │ 0       │              \n12|│Current index │ 2       │              \n13|│                        │              \n14|└ My name ──────── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444455555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333222222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---respects-custom-mappings",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌ Info ───────────────────────────────┐                     \n02|│General                              │                     \n03|│Source name   │ My name              │                     \n04|│Source cwd    │ tests/dir-pick       │                     \n05|│Total items   │ 3                    │                     \n06|│Matched items │ 3                    │                     \n07|│Marked items  │ 0                    │                     \n08|│Current index │ 1                    │                     \n09|│                                     │                     \n10|│Mappings (custom)                    │                     \n11|│Another action │ <C-e>               │                     \n12|│Custom action  │ <C-d>               │                     \n13|│Dup key action │ <Left>              │                     \n14|│                                     │                     \n15|│Mappings (built-in)                  │                     \n16|│Caret right       │ <Right>          │                     \n17|│Choose            │ a                │                     \n18|│Delete char       │ <BS>             │                     \n19|│Delete char right │ <Del>            │                     \n20|│Delete left       │ <C-u>            │                     \n21|│Delete word       │ <C-w>            │                     \n22|└ My name ───────────────────── 1|3|3 ┘                     \n23|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111100000000000000000000000000000000222222222222222222222\n02|033333334444444444444444444444444444440555555555555555555555\n03|044444444444444444444444444444444444440555555555555555555555\n04|044444444444444444444444444444444444440555555555555555555555\n05|044444444444444444444444444444444444440555555555555555555555\n06|044444444444444444444444444444444444440555555555555555555555\n07|044444444444444444444444444444444444440555555555555555555555\n08|044444444444444444444444444444444444440555555555555555555555\n09|044444444444444444444444444444444444440555555555555555555555\n10|033333333333333333444444444444444444440555555555555555555555\n11|044444444444444444444444444444444444440555555555555555555555\n12|044444444444444444444444444444444444440555555555555555555555\n13|044444444444444444444444444444444444440555555555555555555555\n14|044444444444444444444444444444444444440555555555555555555555\n15|033333333333333333334444444444444444440555555555555555555555\n16|044444444444444444444444444444444444440555555555555555555555\n17|044444444444444444444444444444444444440555555555555555555555\n18|044444444444444444444444444444444444440555555555555555555555\n19|044444444444444444444444444444444444440555555555555555555555\n20|044444444444444444444444444444444444440555555555555555555555\n21|044444444444444444444444444444444444440555555555555555555555\n22|011111111100000000000000000000011111110555555555555555555555\n23|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---supports-vertical-and-horizontal-scroll",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│l                       │              \n07|│ name   │ <No name>     │              \n08|│ cwd    │ tests/dir-pick│              \n09|│items   │ 1             │              \n10|│d items │ 1             │              \n11|│ items  │ 0             │              \n12|│t index │ 1             │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2455555555555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---supports-vertical-and-horizontal-scroll-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│General                 │              \n07|│Source name   │ <No name│              \n08|│Source cwd    │ tests/di│              \n09|│Total items   │ 1       │              \n10|│Matched items │ 1       │              \n11|│Marked items  │ 0       │              \n12|│Current index │ 1       │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444455555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---supports-vertical-and-horizontal-scroll-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│Current index │ 1       │              \n07|│                        │              \n08|│Mappings (built-in)     │              \n09|│Caret left        │ <Lef│              \n10|│Caret right       │ <Rig│              \n11|│Choose            │ <CR>│              \n12|│Choose in split   │ <C-s│              \n13|│Choose in tabpage │ <C-t│              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2555555555555555555544444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---supports-vertical-and-horizontal-scroll-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Info ──────────────────┐              \n06|│General                 │              \n07|│Source name   │ <No name│              \n08|│Source cwd    │ tests/di│              \n09|│Total items   │ 1       │              \n10|│Matched items │ 1       │              \n11|│Marked items  │ 0       │              \n12|│Current index │ 1       │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333222222222222222222211111111111111\n06|2444444455555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Info-view---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|┌ Info ───────────────────────────────┐                     \n02|│General                              │                     \n03|│Source name   │ My name              │                     \n04|│Source cwd    │ tests/dir-pick       │                     \n05|│Total items   │ 3                    │                     \n06|│Matched items │ 3                    │                     \n07|│Marked items  │ 0                    │                     \n08|│Current index │ 1                    │                     \n09|│                                     │                     \n10|│Mappings (built-in)                  │                     \n11|│Caret left        │ <Left>           │                     \n12|│Caret right       │ <Right>          │                     \n13|│Choose            │ <CR>             │                     \n14|│Choose in split   │ <C-s>            │                     \n15|│Choose in tabpage │ <C-t>            │                     \n16|│Choose in vsplit  │ <C-v>            │                     \n17|│Choose marked     │ <M-CR>           │                     \n18|│Delete char       │ <BS>             │                     \n19|│Delete char right │ <Del>            │                     \n20|│Delete left       │ <C-u>            │                     \n21|│Delete word       │ <C-w>            │                     \n22|│Mark              │ <C-x>            │                     \n23|│Mark all          │ <C-a>            │                     \n24|│Move down         │ <C-n>            │                     \n25|│Move start        │ <C-g>            │                     \n26|│Move up           │ <C-p>            │                     \n27|│Paste             │ <C-r>            │                     \n28|│Refine            │ <C-Space>        │                     \n29|│Refine marked     │ <M-Space>        │                     \n30|│Scroll down       │ <C-f>            │                     \n31|│Scroll left       │ <C-h>            │                     \n32|│Scroll right      │ <C-l>            │                     \n33|│Scroll up         │ <C-b>            │                     \n34|│Stop              │ <Esc>            │                     \n35|│Toggle info       │ <S-Tab>          │                     \n36|│Toggle preview    │ <Tab>            │                     \n37|│                                     │                     \n38|│                                     │                     \n39|└ My name ───────────────────── 1|3|3 ┘                     \n40|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|011111100000000000000000000000000000000222222222222222222222\n02|033333334444444444444444444444444444440555555555555555555555\n03|044444444444444444444444444444444444440555555555555555555555\n04|044444444444444444444444444444444444440555555555555555555555\n05|044444444444444444444444444444444444440555555555555555555555\n06|044444444444444444444444444444444444440555555555555555555555\n07|044444444444444444444444444444444444440555555555555555555555\n08|044444444444444444444444444444444444440555555555555555555555\n09|044444444444444444444444444444444444440555555555555555555555\n10|033333333333333333334444444444444444440555555555555555555555\n11|044444444444444444444444444444444444440555555555555555555555\n12|044444444444444444444444444444444444440555555555555555555555\n13|044444444444444444444444444444444444440555555555555555555555\n14|044444444444444444444444444444444444440555555555555555555555\n15|044444444444444444444444444444444444440555555555555555555555\n16|044444444444444444444444444444444444440555555555555555555555\n17|044444444444444444444444444444444444440555555555555555555555\n18|044444444444444444444444444444444444440555555555555555555555\n19|044444444444444444444444444444444444440555555555555555555555\n20|044444444444444444444444444444444444440555555555555555555555\n21|044444444444444444444444444444444444440555555555555555555555\n22|044444444444444444444444444444444444440555555555555555555555\n23|044444444444444444444444444444444444440555555555555555555555\n24|044444444444444444444444444444444444440555555555555555555555\n25|044444444444444444444444444444444444440555555555555555555555\n26|044444444444444444444444444444444444440555555555555555555555\n27|044444444444444444444444444444444444440555555555555555555555\n28|044444444444444444444444444444444444440555555555555555555555\n29|044444444444444444444444444444444444440555555555555555555555\n30|044444444444444444444444444444444444440555555555555555555555\n31|044444444444444444444444444444444444440555555555555555555555\n32|044444444444444444444444444444444444440555555555555555555555\n33|044444444444444444444444444444444444440555555555555555555555\n34|044444444444444444444444444444444444440555555555555555555555\n35|044444444444444444444444444444444444440555555555555555555555\n36|044444444444444444444444444444444444440555555555555555555555\n37|066666666666666666666666666666666666660555555555555555555555\n38|066666666666666666666666666666666666660555555555555555555555\n39|011111111100000000000000000000011111110555555555555555555555\n40|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-002",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-003",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|066666666605555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-004",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|044444444405555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-005",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-006",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|066666666605555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-007",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|044444444405555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-008",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|066666666605555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-009",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|044444444405555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-010",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-011",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|044444444405555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-012",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|066666666605555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-013",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-014",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-015",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-016",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-017",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│2        │    \n3|│3        │    \n4|│4        │    \n5|│5        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-018",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│2        │    \n3|│3        │    \n4|│4        │    \n5|│5        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-019",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-020",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-021",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|044444444405555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-022",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-023",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│6        │    \n3|│7        │    \n4|│8        │    \n5|│9        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|044444444405555\n4|044444444405555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-024",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│4        │    \n3|│5        │    \n4|│6        │    \n5|│7        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|044444444405555\n5|044444444405555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---properly-computes-items-range-to-show-025",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│1        │    \n3|│2        │    \n4|│3        │    \n5|│4        │    \n6|└…o name> ┘    \n7|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|066666666605555\n5|066666666605555\n6|077777777705555\n7|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---shows-marked-items-across-queries",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│ab          │      \n06|│b           │      \n07|│bb          │      \n08|│            │      \n09|└ <No name> ─┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26677777777772111111\n06|27777777777772111111\n07|27777777777772111111\n08|28888888888882111111\n09|29999999999922111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---shows-marked-items-across-queries-002",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> b▏────────┐      \n04|│b           │      \n05|│bb          │      \n06|│ab          │      \n07|│            │      \n08|│            │      \n09|└ <No name> ─┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23345222222222111111\n04|26777777777772111111\n05|28999999999992111111\n06|2:;99999999992111111\n07|2<<<<<<<<<<<<2111111\n08|2<<<<<<<<<<<<2111111\n09|2===========22111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---supports-horizontal-scroll",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│… 1      │    \n05|│…long it…│    \n06|│… 3      │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|256666666621111\n05|257777777521111\n06|257777777721111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---supports-horizontal-scroll-002",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│…        │    \n05|│…ng item…│    \n06|│…        │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|256666666621111\n05|257777777521111\n06|257777777721111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---supports-horizontal-scroll-003",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│…        │    \n05|│…ng item…│    \n06|│…        │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|256666666621111\n05|257777777521111\n06|257777777721111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---supports-horizontal-scroll-004",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│…        │    \n05|│…ng item…│    \n06|│…        │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|256666666621111\n05|257777777521111\n06|256666666621111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---supports-horizontal-scroll-005",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│         │    \n05|│…tem 2   │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|255555555521111\n05|267777777721111\n06|255555555521111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---supports-horizontal-scroll-006",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│…rt 1    │    \n05|│…y long …│    \n06|│…rt 3    │    \n07|│         │    \n08|│         │    \n09|└…o name> ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|256666666621111\n05|256666666521111\n06|257777777721111\n07|288888888821111\n08|288888888821111\n09|299999999921111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│x2                │          \n05|│x1                │          \n06|│bb                │          \n07|│b                 │          \n08|│a                 │          \n09|└> ▏───────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|244444444444444444421111111111\n08|255555555555555555521111111111\n09|266722222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-002",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│x2                │          \n05|│x1                │          \n06|│bb                │          \n07|│b                 │          \n08|│a                 │          \n09|└> ▏───────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|255555555555555555521111111111\n08|244444444444444444421111111111\n09|266722222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-003",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│                  │          \n05|│                  │          \n06|│                  │          \n07|│bb                │          \n08|│b                 │          \n09|└> b▏──────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|254444444444444444421111111111\n08|267777777777777777721111111111\n09|2889:2222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-004",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│                  │          \n05|│                  │          \n06|│                  │          \n07|│bb                │          \n08|│b                 │          \n09|└> b▏──────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|256666666666666666621111111111\n08|274444444444444444421111111111\n09|2889:2222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-005",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│                  │          \n05|│                  │          \n06|│                  │          \n07|│bb                │          \n08|│b                 │          \n09|└> b▏──────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|254444444444444444421111111111\n08|267777777777777777721111111111\n09|2889:2222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-006",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│Item x2           │          \n05|│Item x1           │          \n06|│Item bb           │          \n07|│Item b            │          \n08|│Item a            │          \n09|└> ▏───────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|244444444444444444421111111111\n08|255555555555555555521111111111\n09|266722222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-007",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│Item x2           │          \n05|│Item x1           │          \n06|│Item bb           │          \n07|│Item b            │          \n08|│Item a            │          \n09|└> ▏───────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|255555555555555555521111111111\n08|244444444444444444421111111111\n09|266722222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-008",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│                  │          \n05|│                  │          \n06|│                  │          \n07|│Item bb           │          \n08|│Item b            │          \n09|└> b▏──────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|244444444444444444421111111111\n08|255555555555555555521111111111\n09|266782222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-009",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│                  │          \n05|│                  │          \n06|│                  │          \n07|│Item bb           │          \n08|│Item b            │          \n09|└> b▏──────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|255555555555555555521111111111\n08|244444444444444444421111111111\n09|266782222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Main-view---works-with-`content_from_bottom`=true-010",
    "content": "--|---------|---------|---------|\n01|                              \n02|~                             \n03|┌ <No name> ───────┐          \n04|│                  │          \n05|│                  │          \n06|│                  │          \n07|│Item bb           │          \n08|│Item b            │          \n09|└> b▏──────────────┘          \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000000000000000\n02|111111111111111111111111111111\n03|233333333333222222221111111111\n04|244444444444444444421111111111\n05|244444444444444444421111111111\n06|244444444444444444421111111111\n07|244444444444444444421111111111\n08|255555555555555555521111111111\n09|266782222222222222221111111111\n10|000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Mark---works-without-items-set",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│         │    \n3|│         │    \n4|└─────────┘    \n5|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|000000000005555\n5|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Matching---dedicated-event-can-update-window-config",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|┌> ▏─────────────────────┐              \n12|│ab                      │              \n13|│bb                      │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|2334222222222222222222222211111111111111\n12|2555555555555555555555555211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Matching---dedicated-event-can-update-window-config-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|┌> a▏────────────────────┐              \n13|│ab                      │              \n14|└ <No name> ────── 1|1|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|2334522222222222222222222211111111111111\n13|2677777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Matching---dedicated-event-can-update-window-config-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|┌> ax▏───────────────────┐              \n13|│                        │              \n14|└ <No name> ────── -|0|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|2334452222222222222222222211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Matching---dedicated-event-can-update-window-config-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|┌> ▏─────────────────────┐              \n12|│ab                      │              \n13|│bb                      │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|2334222222222222222222222211111111111111\n12|2555555555555555555555555211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Move---works-when-no-items-are-set",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│         │    \n3|│         │    \n4|└─────────┘    \n5|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|000000000005555\n5|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border",
    "content": "--|---------|---------|\n01|┌> ▏───────────────┐\n02|│a                 │\n03|│                  │\n04|│                  │\n05|│                  │\n06|│                  │\n07|│                  │\n08|│                  │\n09|│                  │\n10|└ My name ── 1|1|1 ┘\n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333330\n03|04444444444444444440\n04|04444444444444444440\n05|04444444444444444440\n06|04444444444444444440\n07|04444444444444444440\n08|04444444444444444440\n09|04444444444444444440\n10|05555555550055555550\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-002",
    "content": "--|---------|---------|\n01|a> ▏bbbbbbbbbbbbbbbc\n02|ha                 d\n03|h                  d\n04|h                  d\n05|h                  d\n06|h                  d\n07|h                  d\n08|h                  d\n09|h                  d\n10|g My name ff 1|1|1 e\n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333330\n03|04444444444444444440\n04|04444444444444444440\n05|04444444444444444440\n06|04444444444444444440\n07|04444444444444444440\n08|04444444444444444440\n09|04444444444444444440\n10|05555555550055555550\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-003",
    "content": "--|---------|---------|\n01|b> ▏bbbbbbbbbbbbbbbc\n02|a                  d\n03|                   d\n04|                   d\n05|                   d\n06|                   d\n07|                   d\n08|                   d\n09|                   d\n10|f My name fff 1|1|1e\n\n--|---------|---------|\n01|01120000000000000000\n02|33333333333333333330\n03|44444444444444444440\n04|44444444444444444440\n05|44444444444444444440\n06|44444444444444444440\n07|44444444444444444440\n08|44444444444444444440\n09|44444444444444444440\n10|05555555550005555550\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-004",
    "content": "--|---------|---------|\n01|a> ▏bbbbbbbbbbbbbbbb\n02|ha                  \n03|h                   \n04|h                   \n05|h                   \n06|h                   \n07|h                   \n08|h                   \n09|h                   \n10|g My name fff 1|1|1 \n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333333\n03|04444444444444444444\n04|04444444444444444444\n05|04444444444444444444\n06|04444444444444444444\n07|04444444444444444444\n08|04444444444444444444\n09|04444444444444444444\n10|05555555550005555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-005",
    "content": "--|---------|---------|\n01|b> ▏bbbbbbbbbbbbbbbb\n02|a                   \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|f My name ffff 1|1|1\n\n--|---------|---------|\n01|01120000000000000000\n02|33333333333333333333\n03|44444444444444444444\n04|44444444444444444444\n05|44444444444444444444\n06|44444444444444444444\n07|44444444444444444444\n08|44444444444444444444\n09|44444444444444444444\n10|05555555550000555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-006",
    "content": "--|---------|---------|\n01|ha                 d\n02|h                  d\n03|h                  d\n04|h                  d\n05|h                  d\n06|h                  d\n07|h                  d\n08|h                  d\n09|h                  d\n10|g My name ff 1|1|1 e\n\n--|---------|---------|\n01|01111111111111111110\n02|02222222222222222220\n03|02222222222222222220\n04|02222222222222222220\n05|02222222222222222220\n06|02222222222222222220\n07|02222222222222222220\n08|02222222222222222220\n09|02222222222222222220\n10|03333333330033333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-007",
    "content": "--|---------|---------|\n01|a> ▏bbbbbbbbbbbbbbbc\n02|ha                 d\n03|h                  d\n04|h                  d\n05|h                  d\n06|h                  d\n07|h                  d\n08|h                  d\n09|h                  d\n10|h                  d\n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333330\n03|04444444444444444440\n04|04444444444444444440\n05|04444444444444444440\n06|04444444444444444440\n07|04444444444444444440\n08|04444444444444444440\n09|04444444444444444440\n10|04444444444444444440\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-008",
    "content": "--|---------|---------|\n01|ha                 d\n02|h                  d\n03|h                  d\n04|h                  d\n05|h                  d\n06|h                  d\n07|h                  d\n08|h                  d\n09|h                  d\n10|h                  d\n\n--|---------|---------|\n01|01111111111111111110\n02|02222222222222222220\n03|02222222222222222220\n04|02222222222222222220\n05|02222222222222222220\n06|02222222222222222220\n07|02222222222222222220\n08|02222222222222222220\n09|02222222222222222220\n10|02222222222222222220\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-009",
    "content": "--|---------|---------|\n01|a> ▏bbbbbbbbbbbbbbbc\n02|da                 d\n03|d                  d\n04|d                  d\n05|d                  d\n06|d                  d\n07|d                  d\n08|d                  d\n09|d                  d\n10|c My name bb 1|1|1 a\n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333330\n03|04444444444444444440\n04|04444444444444444440\n05|04444444444444444440\n06|04444444444444444440\n07|04444444444444444440\n08|04444444444444444440\n09|04444444444444444440\n10|05555555550055555550\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-010",
    "content": "--|---------|---------|\n01|a> ▏bbbbbbbbbbbbbbba\n02|ba                 b\n03|b                  b\n04|b                  b\n05|b                  b\n06|b                  b\n07|b                  b\n08|b                  b\n09|b                  b\n10|a My name bb 1|1|1 a\n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333330\n03|04444444444444444440\n04|04444444444444444440\n05|04444444444444444440\n06|04444444444444444440\n07|04444444444444444440\n08|04444444444444444440\n09|04444444444444444440\n10|05555555550055555550\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-011",
    "content": "--|---------|---------|\n01|a> ▏aaaaaaaaaaaaaaaa\n02|aa                 a\n03|a                  a\n04|a                  a\n05|a                  a\n06|a                  a\n07|a                  a\n08|a                  a\n09|a                  a\n10|a My name aa 1|1|1 a\n\n--|---------|---------|\n01|01120000000000000000\n02|03333333333333333330\n03|04444444444444444440\n04|04444444444444444440\n05|04444444444444444440\n06|04444444444444444440\n07|04444444444444444440\n08|04444444444444444440\n09|04444444444444444440\n10|05555555550055555550\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-012",
    "content": "--|---------|---------|\n01|b> ▏bbbbbbbbbbbbbbbb\n02|a                   \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|b My name bbbb 1|1|1\n\n--|---------|---------|\n01|01120000000000000000\n02|33333333333333333333\n03|44444444444444444444\n04|44444444444444444444\n05|44444444444444444444\n06|44444444444444444444\n07|44444444444444444444\n08|44444444444444444444\n09|44444444444444444444\n10|05555555550000555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-013",
    "content": "--|---------|---------|\n01|da                 d\n02|d                  d\n03|d                  d\n04|d                  d\n05|d                  d\n06|d                  d\n07|d                  d\n08|d                  d\n09|d                  d\n10|d                  d\n\n--|---------|---------|\n01|01111111111111111110\n02|02222222222222222220\n03|02222222222222222220\n04|02222222222222222220\n05|02222222222222222220\n06|02222222222222222220\n07|02222222222222222220\n08|02222222222222222220\n09|02222222222222222220\n10|02222222222222222220\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-014",
    "content": "--|---------|---------|\n01|a                   \n02|                    \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|11111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-015",
    "content": "--|---------|---------|\n01|a                   \n02|                    \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|11111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---adjusts-dimensions-respecting-border-016",
    "content": "--|---------|---------|\n01| > ▏                \n02|a                   \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|  My name      1|1|1\n\n--|---------|---------|\n01|01120000000000000000\n02|33333333333333333333\n03|44444444444444444444\n04|44444444444444444444\n05|44444444444444444444\n06|44444444444444444444\n07|44444444444444444444\n08|44444444444444444444\n09|44444444444444444444\n10|05555555550000555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---allows-'none'-as-border",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05| > ▏                                    \n06|a                                       \n07|                                        \n08|                                        \n09|                                        \n10|                                        \n11|                                        \n12|                                        \n13|                                        \n14|  My name          1|1|1                \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222221111111111111111\n06|5555555555555555555555551111111111111111\n07|6666666666666666666666661111111111111111\n08|6666666666666666666666661111111111111111\n09|6666666666666666666666661111111111111111\n10|6666666666666666666666661111111111111111\n11|6666666666666666666666661111111111111111\n12|6666666666666666666666661111111111111111\n13|6666666666666666666666661111111111111111\n14|2777777777222222227777771111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---allows-very-large-dimensions",
    "content": "--|---------|---------|---------|---------|\n01|┌> ▏───────────────────────────────────┐\n02|│a                                     │\n03|│                                      │\n04|│                                      │\n05|│                                      │\n06|│                                      │\n07|│                                      │\n08|│                                      │\n09|│                                      │\n10|│                                      │\n11|│                                      │\n12|│                                      │\n13|│                                      │\n14|└ My name ────────────────────── 1|1|1 ┘\n15|                                        \n\n--|---------|---------|---------|---------|\n01|0112000000000000000000000000000000000000\n02|0333333333333333333333333333333333333330\n03|0444444444444444444444444444444444444440\n04|0444444444444444444444444444444444444440\n05|0444444444444444444444444444444444444440\n06|0444444444444444444444444444444444444440\n07|0444444444444444444444444444444444444440\n08|0444444444444444444444444444444444444440\n09|0444444444444444444444444444444444444440\n10|0444444444444444444444444444444444444440\n11|0444444444444444444444444444444444444440\n12|0444444444444444444444444444444444444440\n13|0444444444444444444444444444444444444440\n14|0555555555000000000000000000000055555550\n15|6666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---correctly-infers-footer-empty-space",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|╔> ▏═════════════════════╗              \n06|║a                       ║              \n07|║                        ║              \n08|║                        ║              \n09|║                        ║              \n10|║                        ║              \n11|║                        ║              \n12|║                        ║              \n13|║                        ║              \n14|╚ <No name> ══════ 1|1|1 ╝              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---correctly-infers-footer-empty-space-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|!> ▏@@@@@@@@@@@@@@@@@@@@@#              \n06|*a                       $              \n07|*                        $              \n08|*                        $              \n09|*                        $              \n10|*                        $              \n11|*                        $              \n12|*                        $              \n13|*                        $              \n14|& <No name> ^^^^^^ 1|1|1 %              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---correctly-infers-footer-empty-space-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|!> ▏@@@@@@@@@@@@@@@@@@@@@#              \n06|*a                       $              \n07|*                        $              \n08|*                        $              \n09|*                        $              \n10|*                        $              \n11|*                        $              \n12|*                        $              \n13|*                        $              \n14|& <No name> ^^^^^^ 1|1|1 %              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0223000000000000000000000011111111111111\n06|0444444444444444444444444011111111111111\n07|0555555555555555555555555011111111111111\n08|0555555555555555555555555011111111111111\n09|0555555555555555555555555011111111111111\n10|0555555555555555555555555011111111111111\n11|0555555555555555555555555011111111111111\n12|0555555555555555555555555011111111111111\n13|0555555555555555555555555011111111111111\n14|0666666666667777776666666011111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---correctly-infers-footer-empty-space-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|! <No name> @@@@@@ 1|1|1 #              \n06|*                        $              \n07|*                        $              \n08|*                        $              \n09|*                        $              \n10|*                        $              \n11|*                        $              \n12|*                        $              \n13|*a                       $              \n14|&> ▏^^^^^^^^^^^^^^^^^^^^^%              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333332222223333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2555555555555555555555555211111111111111\n14|2667222222222222222222222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---does-not-show-footer-if-items-are-not-set",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└────────────────────────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2222222222222222222222222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---is-shown-over-number-and-sign-columns",
    "content": "--|---------|---------|\n01|    1 a             \n02|    2 b             \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└ <No name> ─┘      \n10|                    \n\n--|---------|---------|\n01|00000011111111111111\n02|00000011111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662000000\n07|26666666666662000000\n08|26666666666662000000\n09|27777777777722000000\n10|11111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-'winborder'-option",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|╭> ▏─────────────────────╮              \n06|│a                       │              \n07|│b                       │              \n08|│c                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|╰ <No name> ────── 1|3|3 ╯              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-'winborder'-option-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|╔> ▏═════════════════════╗              \n06|║a                       ║              \n07|║b                       ║              \n08|║c                       ║              \n09|║                        ║              \n10|║                        ║              \n11|║                        ║              \n12|║                        ║              \n13|║                        ║              \n14|╚ <No name> ══════ 1|3|3 ╝              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-'winborder'-option-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05| > ▏                                    \n06|a                                       \n07|b                                       \n08|c                                       \n09|                                        \n10|                                        \n11|                                        \n12|                                        \n13|                                        \n14|  <No name>        1|3|3                \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222221111111111111111\n06|5555555555555555555555551111111111111111\n07|6666666666666666666666661111111111111111\n08|6666666666666666666666661111111111111111\n09|7777777777777777777777771111111111111111\n10|7777777777777777777777771111111111111111\n11|7777777777777777777777771111111111111111\n12|7777777777777777777777771111111111111111\n13|7777777777777777777777771111111111111111\n14|2888888888882222228888881111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-'winborder'-option-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|+> ▏---------------------+              \n06||a                       |              \n07||b                       |              \n08||c                       |              \n09||                        |              \n10||                        |              \n11||                        |              \n12||                        |              \n13||                        |              \n14|+ <No name> ------ 1|3|3 +              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-`options.content_from_bottom`-with-footer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ <No name> ────── 1|2|2 ┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│b                       │              \n13|│a                       │              \n14|└> ▏─────────────────────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333332222223333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2555555555555555555555555211111111111111\n14|2667222222222222222222222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-tabline,-statusline,-'cmdheight'",
    "content": "--|---------|---------|\n01|My tabline          \n02|                    \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|└ My name ───┘      \n09|My statusline       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222555555\n04|26666666666662555555\n05|27777777777772555555\n06|27777777777772555555\n07|27777777777772555555\n08|28888888882222555555\n09|00000000000000000000\n10|11111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-tabline,-statusline,-'cmdheight'-002",
    "content": "--|---------|---------|\n01|My tabline          \n02|                    \n03|~                   \n04|┌> ▏─────────┐      \n05|│a           │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└ My name ───┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22222222222222222222\n04|34453333333333222222\n05|36666666666663222222\n06|37777777777773222222\n07|37777777777773222222\n08|37777777777773222222\n09|38888888883333222222\n10|11111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-tabline,-statusline,-'cmdheight'-003",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|└ My name ───┘      \n09|My statusline       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662111111\n07|26666666666662111111\n08|27777777772222111111\n09|88888888888888888888\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-tabline,-statusline,-'cmdheight'-004",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└ My name ───┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662111111\n07|26666666666662111111\n08|26666666666662111111\n09|27777777772222111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-tabline,-statusline,-'cmdheight'-005",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|└ My name ───┘      \n09|                    \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662111111\n07|26666666666662111111\n08|27777777772222111111\n09|88888888888888888888\n10|88888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---respects-tabline,-statusline,-'cmdheight'-006",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|│            │      \n10|└ My name ───┘      \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662111111\n07|26666666666662111111\n08|26666666666662111111\n09|26666666666662111111\n10|27777777772222111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---sanitizes-picker-name",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏───────────────────────────────────┐\n06|│a                                     │\n07|│                                      │\n08|│                                      │\n09|│                                      │\n10|│                                      │\n11|│                                      │\n12|│                                      │\n13|│                                      │\n14|└ Bad multi line picker name  ── 1|1|1 ┘\n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222222222222222222\n06|2555555555555555555555555555555555555552\n07|2666666666666666666666666666666666666662\n08|2666666666666666666666666666666666666662\n09|2666666666666666666666666666666666666662\n10|2666666666666666666666666666666666666662\n11|2666666666666666666666666666666666666662\n12|2666666666666666666666666666666666666662\n13|2666666666666666666666666666666666666662\n14|2777777777777777777777777777772277777772\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---sanitizes-picker-name-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Bad multi line picker name  ── 1|1|1 ┐\n06|│                                      │\n07|│                                      │\n08|│                                      │\n09|│                                      │\n10|│                                      │\n11|│                                      │\n12|│                                      │\n13|│a                                     │\n14|└> ▏───────────────────────────────────┘\n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333333332233333332\n06|2444444444444444444444444444444444444442\n07|2444444444444444444444444444444444444442\n08|2444444444444444444444444444444444444442\n09|2444444444444444444444444444444444444442\n10|2444444444444444444444444444444444444442\n11|2444444444444444444444444444444444444442\n12|2444444444444444444444444444444444444442\n13|2555555555555555555555555555555555555552\n14|2667222222222222222222222222222222222222\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---shows-prompt",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│            │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└────────────┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662111111\n07|26666666666662111111\n08|26666666666662111111\n09|22222222222222111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---shows-prompt-002",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> a▏────────┐      \n04|│            │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└────────────┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23345222222222111111\n04|26666666666662111111\n05|27777777777772111111\n06|27777777777772111111\n07|27777777777772111111\n08|27777777777772111111\n09|22222222222222111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---shows-prompt-003",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> a b▏──────┐      \n04|│            │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└────────────┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23344452222222111111\n04|26666666666662111111\n05|27777777777772111111\n06|27777777777772111111\n07|27777777777772111111\n08|27777777777772111111\n09|22222222222222111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---shows-prompt-004",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> a ▏b──────┐      \n04|│            │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└────────────┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23344542222222111111\n04|26666666666662111111\n05|27777777777772111111\n06|27777777777772111111\n07|27777777777772111111\n08|27777777777772111111\n09|22222222222222111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---shows-prompt-005",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> a▏ b──────┐      \n04|│            │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└────────────┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23345442222222111111\n04|26666666666662111111\n05|27777777777772111111\n06|27777777777772111111\n07|27777777777772111111\n08|27777777777772111111\n09|22222222222222111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-footer",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|┌> ▏─────────┐      \n04|│a           │      \n05|│            │      \n06|│            │      \n07|│            │      \n08|│            │      \n09|└… long name ┘      \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|23342222222222111111\n04|25555555555552111111\n05|26666666666662111111\n06|26666666666662111111\n07|26666666666662111111\n08|26666666666662111111\n09|27777777777772111111\n10|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-footer-002",
    "content": "--|---------|---------|---------|--------\n01|                                      \n02|~                                     \n03|┌> ▏────────────────────┐             \n04|│a                      │             \n05|│                       │             \n06|│                       │             \n07|│                       │             \n08|│                       │             \n09|└ Very long name ───────┘             \n10|                                      \n\n--|---------|---------|---------|--------\n01|00000000000000000000000000000000000000\n02|11111111111111111111111111111111111111\n03|23342222222222222222222221111111111111\n04|25555555555555555555555521111111111111\n05|26666666666666666666666621111111111111\n06|26666666666666666666666621111111111111\n07|26666666666666666666666621111111111111\n08|26666666666666666666666621111111111111\n09|27777777777777777222222221111111111111\n10|00000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-footer-003",
    "content": "--|---------|---------|---------|---------\n01|                                       \n02|~                                      \n03|┌> ▏─────────────────────┐             \n04|│a                       │             \n05|│                        │             \n06|│                        │             \n07|│                        │             \n08|│                        │             \n09|└ Very long name ─ 1|1|1 ┘             \n10|                                       \n\n--|---------|---------|---------|---------\n01|000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111\n03|233422222222222222222222221111111111111\n04|255555555555555555555555521111111111111\n05|266666666666666666666666621111111111111\n06|266666666666666666666666621111111111111\n07|266666666666666666666666621111111111111\n08|266666666666666666666666621111111111111\n09|277777777777777772777777721111111111111\n10|000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…цф_!Ы!┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334444555211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-002",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…цф!Ы!_┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334445554211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-003",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…ц!Ы!ф_┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-004",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…й!Ы!ц…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-005",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…c!Ы!й…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-006",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>ab!Ы!c…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-007",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>a!Ы!bc…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334555444211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-008",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>!Ы!abc…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334445555211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-009",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…hij!Ы!┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334444555211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-010",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…h!Ы!ij┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-011",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>…e!Ы!f…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-012",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>ab!Ы!c…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334455544211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---truncates-prompt-013",
    "content": "--|---------|-------\n01|                 \n02|~                \n03|┌<ы>!Ы!abc…┐     \n04|│          │     \n05|│          │     \n06|│          │     \n07|│          │     \n08|│          │     \n09|└ Test ────┘     \n10|                 \n\n--|---------|-------\n01|00000000000000000\n02|11111111111111111\n03|23334445555211111\n04|26666666666211111\n05|27777777777211111\n06|27777777777211111\n07|27777777777211111\n08|27777777777211111\n09|28888882222211111\n10|00000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---uses-footer-for-extra-info",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│bb                      │              \n09|│bbb                     │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── 1|4|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888222222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---uses-footer-for-extra-info-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> b▏────────────────────┐              \n06|│b                       │              \n07|│bb                      │              \n08|│bbb                     │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── 1|3|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2677777777777777777777777211111111111111\n07|2899999999999999999999999211111111111111\n08|2899999999999999999999999211111111111111\n09|2::::::::::::::::::::::::211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;22222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---uses-footer-for-extra-info-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> b▏────────────────────┐              \n06|│b                       │              \n07|│bb                      │              \n08|│bbb                     │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── 2|3|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2677777777777777777777777211111111111111\n07|2899999999999999999999999211111111111111\n08|2677777777777777777777777211111111111111\n09|2::::::::::::::::::::::::211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;22222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---uses-footer-for-extra-info-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> b▏────────────────────┐              \n06|│b                       │              \n07|│bb                      │              \n08|│bbb                     │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ────── 2|3|1/4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2677777777777777777777777211111111111111\n07|289::::::::::::::::::::::211111111111111\n08|2677777777777777777777777211111111111111\n09|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n10|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n11|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n12|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n13|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n14|2<<<<<<<<<222222<<<<<<<<<211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---uses-footer-for-extra-info-005",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> b▏────────────────────┐              \n06|│b                       │              \n07|│bb                      │              \n08|│bbb                     │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── 2|3|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2677777777777777777777777211111111111111\n07|2899999999999999999999999211111111111111\n08|2677777777777777777777777211111111111111\n09|2::::::::::::::::::::::::211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;22222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---uses-footer-for-extra-info-006",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> bx▏───────────────────┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── -|0|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334452222222222222222222211111111111111\n06|2666666666666666666666666211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888222222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Overall-view---works-with-small-available-dimensions",
    "content": "-|---------|---------|---------|---------|\n1|┌> ▏─────────────────────┐              \n2|│a                       │              \n3|└ My name ──────── 1|1|1 ┘              \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0112000000000000000000000033333333333333\n2|0444444444444444444444444055555555555555\n3|0666666666000000006666666055555555555555\n4|5555555555555555555555555555555555555555\n5|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Paste---works",
    "content": "-|---------|-----\n1|┌> hello▏─┐    \n2|│         │    \n3|│         │    \n4|└…o name> ┘    \n5|               \n\n-|---------|-----\n1|011222223004444\n2|055555555506666\n3|077777777706666\n4|088888888806666\n5|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Paste---works-002",
    "content": "-|---------|-----\n1|┌> ыфя▏───┐    \n2|│         │    \n3|│         │    \n4|└…o name> ┘    \n5|               \n\n-|---------|-----\n1|011222300004444\n2|055555555506666\n3|077777777706666\n4|088888888806666\n5|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Paste---works-003",
    "content": "-|---------|-----\n1|┌> a b c▏─┐    \n2|│         │    \n3|│         │    \n4|└…o name> ┘    \n5|               \n\n-|---------|-----\n1|011222223004444\n2|055555555506666\n3|077777777706666\n4|088888888806666\n5|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---does-explicit-redraw-several-times",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ a ─────────────────────┐              \n06|│A highlight             │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Preview redraw ─ 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333333333323333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---does-explicit-redraw-several-times-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ a ─────────────────────┐              \n06|│A highlight             │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Preview redraw ─ 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444445555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333333333323333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---is-updated-after-moving-current-item",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ a ─────────────────────┐              \n06|│\"a\"                     │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333222222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---is-updated-after-moving-current-item-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ b ─────────────────────┐              \n06|│\"b\"                     │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ My name ──────── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333222222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…g item ┐                              \n06|│+   Tabs│                              \n07|│    Spac│                              \n08|│        │                              \n09|│        │                              \n10|│        │                              \n11|│        │                              \n12|│        │                              \n13|│        │                              \n14|└… name> ┘                              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332111111111111111111111111111111\n06|2444455552111111111111111111111111111111\n07|2555555552111111111111111111111111111111\n08|2666666662111111111111111111111111111111\n09|2666666662111111111111111111111111111111\n10|2666666662111111111111111111111111111111\n11|2666666662111111111111111111111111111111\n12|2666666662111111111111111111111111111111\n13|2666666662111111111111111111111111111111\n14|2333333332111111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────┐                              \n06|│a long …│                              \n07|│        │                              \n08|│        │                              \n09|│        │                              \n10|│        │                              \n11|│        │                              \n12|│        │                              \n13|│        │                              \n14|└… name> ┘                              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222111111111111111111111111111111\n06|2555555562111111111111111111111111111111\n07|2777777772111111111111111111111111111111\n08|2777777772111111111111111111111111111111\n09|2777777772111111111111111111111111111111\n10|2777777772111111111111111111111111111111\n11|2777777772111111111111111111111111111111\n12|2777777772111111111111111111111111111111\n13|2777777772111111111111111111111111111111\n14|2888888882111111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…g item ┐                              \n06|│    Tabs│                              \n07|│    Spac│                              \n08|│        │                              \n09|│        │                              \n10|│        │                              \n11|│        │                              \n12|│        │                              \n13|│        │                              \n14|└… name> ┘                              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332111111111111111111111111111111\n06|2444444442111111111111111111111111111111\n07|2444444442111111111111111111111111111111\n08|2555555552111111111111111111111111111111\n09|2555555552111111111111111111111111111111\n10|2555555552111111111111111111111111111111\n11|2555555552111111111111111111111111111111\n12|2555555552111111111111111111111111111111\n13|2555555552111111111111111111111111111111\n14|2333333332111111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---respects-global-value-of-'list'-and-'listchars'-option-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────┐                              \n06|│a long …│                              \n07|│        │                              \n08|│        │                              \n09|│        │                              \n10|│        │                              \n11|│        │                              \n12|│        │                              \n13|│        │                              \n14|└… name> ┘                              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222111111111111111111111111111111\n06|2555555562111111111111111111111111111111\n07|2777777772111111111111111111111111111111\n08|2777777772111111111111111111111111111111\n09|2777777772111111111111111111111111111111\n10|2777777772111111111111111111111111111111\n11|2777777772111111111111111111111111111111\n12|2777777772111111111111111111111111111111\n13|2777777772111111111111111111111111111111\n14|2888888882111111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---supports-vertical-and-horizontal-scroll",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│1                       │              \n07|│2                       │              \n08|│3                       │              \n09|│4                       │              \n10|│5                       │              \n11|│6                       │              \n12|│7                       │              \n13|│8                       │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---supports-vertical-and-horizontal-scroll-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---supports-vertical-and-horizontal-scroll-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 7                  │              \n07|│Line 8                  │              \n08|│Line 9                  │              \n09|│Line 10                 │              \n10|│Line 11                 │              \n11|│Line 12                 │              \n12|│Line 13                 │              \n13|│Line 14                 │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---supports-vertical-and-horizontal-scroll-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Preview---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ My name ──────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333222222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Refine---works",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> b▏─────┐    \n04|│b        │    \n05|│ba       │    \n06|│bb       │    \n07|│ab       │    \n08|│         │    \n09|└ My name ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233452222221111\n04|267777777721111\n05|289999999921111\n06|289999999921111\n07|298999999921111\n08|2:::::::::21111\n09|2;;;;;;;;;21111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Refine---works-002",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│b        │    \n05|│ba       │    \n06|│bb       │    \n07|│ab       │    \n08|│         │    \n09|└…Refine) ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|255555555521111\n05|266666666621111\n06|266666666621111\n07|266666666621111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Refine---works-003",
    "content": "--|---------|-----\n01|               \n02|~              \n03|┌> ▏──────┐    \n04|│ab       │    \n05|│ba       │    \n06|│         │    \n07|│         │    \n08|│         │    \n09|└…fine 2) ┘    \n10|               \n\n--|---------|-----\n01|000000000000000\n02|111111111111111\n03|233422222221111\n04|255555555521111\n05|266666666621111\n06|277777777721111\n07|277777777721111\n08|277777777721111\n09|288888888821111\n10|000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---Refine---works-when-no-items-are-set",
    "content": "-|---------|-----\n1|┌> ▏──────┐    \n2|│         │    \n3|│         │    \n4|└─────────┘    \n5|               \n\n-|---------|-----\n1|011200000003333\n2|044444444405555\n3|066666666605555\n4|000000000005555\n5|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.buffers()---respects-`local_opts.include_current`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|MIT (c)                                                               \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│ tests/dir-pick/real-files/b.txt          │                         \n05|│  [No Name]                                │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Buffers ─────────────────────────── 1|2|2 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2777777777777777777777777777777777777777777721111111111111111111111111\n07|2777777777777777777777777777777777777777777721111111111111111111111111\n08|2777777777777777777777777777777777777777777721111111111111111111111111\n09|2888888888222222222222222222222222222888888821111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.buffers()---respects-`local_opts.include_unlisted`",
    "content": "--|---------|---------|---------|---------|\n01|MIT (c)                                 \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│ tests/dir-pick/real-f…│              \n07|│  [No Name]             │              \n08|│  [Scratch]             │              \n09|│ tests/dir-pick/real-f…│              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffers ──────── 1|4|4 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555556211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777776211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2888888888888888888888888211111111111111\n14|2999999999222222229999999211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.buffers()---respects-`source.show`-from-config",
    "content": "--|---------|---------|---------|---------|\n01|MIT (c)                                 \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│tests/dir-pick/real-fil…│              \n07|│[No Name]               │              \n08|│tests/dir-pick/real-fil…│              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Buffers ──────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555556211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777776211111111111111\n09|2888888888888888888888888211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2888888888888888888888888211111111111111\n14|2999999999222222229999999211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.buffers()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|MIT (c)                                                               \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│ tests/dir-pick/real-files/b.txt          │                         \n05|│  [No Name]                                │                         \n06|│ tests/dir-pick/real-files/LICENSE        │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Buffers ─────────────────────────── 1|3|3 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2666666666666666666666666666666666666666666621111111111111111111111111\n07|2777777777777777777777777777777777777777777721111111111111111111111111\n08|2777777777777777777777777777777777777777777721111111111111111111111111\n09|2888888888222222222222222222222222222888888821111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.files()---respects-`source.show`-from-config",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|┌> ▏──────────────────────────────────┐                     \n04|│tests/dir-pick/real-files/b.txt      │                     \n05|│tests/dir-pick                       │                     \n06|│                                     │                     \n07|│                                     │                     \n08|│                                     │                     \n09|└ Files (rg) ────────────────── 1|2|2 ┘                     \n10|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|233422222222222222222222222222222222222111111111111111111111\n04|255555555555555555555555555555555555552111111111111111111111\n05|266666666666666666666666666666666666662111111111111111111111\n06|277777777777777777777777777777777777772111111111111111111111\n07|277777777777777777777777777777777777772111111111111111111111\n08|277777777777777777777777777777777777772111111111111111111111\n09|288888888888822222222222222222288888882111111111111111111111\n10|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.files()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|~                                                           \n03|┌> ▏──────────────────────────────────┐                     \n04|│ tests/dir-pick/real-files/b.txt    │                     \n05|│ tests/dir-pick/real-files/LICENSE  │                     \n06|│ tests/dir-pick                     │                     \n07|│                                     │                     \n08|│                                     │                     \n09|└ Files (rg) ────────────────── 1|3|3 ┘                     \n10|                                                            \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111\n03|233422222222222222222222222222222222222111111111111111111111\n04|255555555555555555555555555555555555552111111111111111111111\n05|266666666666666666666666666666666666662111111111111111111111\n06|277666666666666666666666666666666666662111111111111111111111\n07|288888888888888888888888888888888888882111111111111111111111\n08|288888888888888888888888888888888888882111111111111111111111\n09|299999999999922222222222222222299999992111111111111111111111\n10|000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.grep()---respects-`source.show`-from-config",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│tests/dir-pick/real-files/b.txt│1│1        │                         \n05|│                                           │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Grep (rg) ───────────────────────── 1|1|1 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2666666666666666666666666666666666666666666621111111111111111111111111\n07|2666666666666666666666666666666666666666666621111111111111111111111111\n08|2666666666666666666666666666666666666666666621111111111111111111111111\n09|2777777777772222222222222222222222222777777721111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.grep()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|~                                                                     \n04|~                                                                     \n05|~                                                                     \n06|~                                                                     \n07|~                                                                     \n08|~                                                                     \n09|~                                                                     \n10|(mini.pick) Grep pattern: b                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111111111111111111111111111111111\n10|2222222222222222222222222233333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.grep()---works-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│ tests/dir-pick/real-files/a.lua│3│3│a    │                         \n05|│ tests/dir-pick/real-files/b.txt│1│1│b    │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Grep (rg) ───────────────────────── 1|2|2 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2777777777777777777777777777777777777777777721111111111111111111111111\n07|2777777777777777777777777777777777777777777721111111111111111111111111\n08|2777777777777777777777777777777777777777777721111111111111111111111111\n09|2888888888882222222222222222222222222888888821111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.grep_live()---has-custom-'add-glob'-mapping",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> ▏────────────────────────────────────────┐                         \n04|│                                           │                         \n05|│                                           │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Grep live (rg) ──────────────────── -|0|0 ┘                         \n10|Glob pattern:                                                         \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222222221111111111111111111111111\n04|2555555555555555555555555555555555555555555521111111111111111111111111\n05|2666666666666666666666666666666666666666666621111111111111111111111111\n06|2666666666666666666666666666666666666666666621111111111111111111111111\n07|2666666666666666666666666666666666666666666621111111111111111111111111\n08|2666666666666666666666666666666666666666666621111111111111111111111111\n09|2777777777777777722222222222222222222777777721111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.grep_live()---respects-`source.show`-from-config",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> b▏───────────────────────────────────────┐                         \n04|│tests/dir-pick/real-files/b.txt│1│1        │                         \n05|│                                           │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Grep live (rg) ──────────────────── 1|1|1 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334522222222222222222222222222222222222222221111111111111111111111111\n04|2666666666666666666666666667666666666666666621111111111111111111111111\n05|2888888888888888888888888888888888888888888821111111111111111111111111\n06|2888888888888888888888888888888888888888888821111111111111111111111111\n07|2888888888888888888888888888888888888888888821111111111111111111111111\n08|2888888888888888888888888888888888888888888821111111111111111111111111\n09|2999999999999999922222222222222222222999999921111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.grep_live()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                      \n02|~                                                                     \n03|┌> bt▏──────────────────────────────────────┐                         \n04|│ tests/dir-pick/real-files/b.txt│1│1│b    │                         \n05|│                                           │                         \n06|│                                           │                         \n07|│                                           │                         \n08|│                                           │                         \n09|└ Grep live (rg) ──────────────────── 1|1|1 ┘                         \n10|                                                                      \n\n--|---------|---------|---------|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111111111111111111111111111111111\n03|2334452222222222222222222222222222222222222221111111111111111111111111\n04|2666666666666666666666666666676766666666666621111111111111111111111111\n05|2888888888888888888888888888888888888888888821111111111111111111111111\n06|2888888888888888888888888888888888888888888821111111111111111111111111\n07|2888888888888888888888888888888888888888888821111111111111111111111111\n08|2888888888888888888888888888888888888888888821111111111111111111111111\n09|2999999999999999922222222222222222222999999921111111111111111111111111\n10|0000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---handles-consecutive-applications",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                :helpg :helpgrep        \n03|:helpg[rep] {pattern}[@xx]              \n04|                        Search all help \n05|text files and make a list of lines     \n06|                        in which {patter\n07|n} matches.  Jumps to the first match.  \n08|                        The optional [@x\n09|x] specifies that only matches in the   \n10|                        \"xx\" language ar\n11|e to be found.                          \n12|                        You can navig@@@\n13|helphelp.txt 112,8-57                   \n14|                                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000111111022222222200000000\n03|0000000000003333333330000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000003333333\n07|3300000000000000000000000000000000000000\n08|0000000000000000000000000000000000000000\n09|0000000000000000000000000000000000000000\n10|0000000000000000000000000000000000000000\n11|0000000000000000000000000000000000000000\n12|0000000000000000000000000000000000000444\n13|5555555555555555555555555555555555555555\n14|6666666666666666666666666666666666666666\n15|6666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---has-proper-preview",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|aa                                                                              \n02|bb                                                                              \n03|aa                                                                              \n04|~                                                                               \n05|┌ ! ──────────────────────────────────────────────┐                             \n06|│                                                 │                             \n07|│!{motion}{filter}       Filter {motion} text line│                             \n08|│                        program {filter}.        │                             \n09|│                                                 │                             \n10|│                                                 │                             \n11|│!!{filter}              Filter [count] lines thro│                             \n12|│                        {filter}.                │                             \n13|│                                                 │                             \n14|└ Help ──────────────────────────── 1|11861|11861 ┘                             \n15|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|23332222222222222222222222222222222222222222222222211111111111111111111111111111\n06|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n07|24444444444444444444444444444444555555554444444444211111111111111111111111111111\n08|24444444444444444444444444444444455555555444444444211111111111111111111111111111\n09|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n10|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n11|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n12|24444444444444444444444445555555544444444444444444211111111111111111111111111111\n13|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n14|23333332222222222222222222222222222333333333333333211111111111111111111111111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│!                       │              \n07|│!!                      │              \n08|│#                       │              \n09|│#{}                     │              \n10|│$                       │              \n11|│$HOME                   │              \n12|│$HOME-windows           │              \n13|│$MYGVIMRC               │              \n14|└ Help ─── 1|11722|11722 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777222777777777777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                !                       \n03|!{motion}{filter}       Filter {motion} \n04|text lines through the external         \n05|                        program {filter}\n06|.                                       \n07|                                        \n08|                                        \n09|                !!                      \n10|!!{filter}              Filter [count] l\n11|ines through the external program       \n12|                        {filter}.       \n13|change.txt 551,8-57                     \n14|                                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000100000000000000000000000\n03|0000000000000000000000000000000222222220\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000022222222\n06|0000000000000000000000000000000000000000\n07|0000000000000000000000000000000000000000\n08|0000000000000000000000000000000000000000\n09|0000000000000000330000000000000000000000\n10|0000000000000000000000000000000000000000\n11|0000000000000000000000000000000000000000\n12|0000000000000000000000002222222200000000\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---works-for-help-tags-with-special-characters",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|~                                                                               \n04|~                                                                               \n05|┌ c_CTRL-K ───────────────────────────────────────┐                             \n06|│CTRL-K {char1} {char2}                           │                             \n07|│                enter digraph (see |digraphs|).  │                             \n08|│                key, the code for that key is ins│                             \n09|│                                                 │                             \n10|│CTRL-R {register}                                │                             \n11|│                Insert the contents of a numbered│                             \n12|│                typing CTRL-R and the second char│                             \n13|│                to indicate that you are expected│                             \n14|└ Help ──────────────────────────────── 1|1|11861 ┘                             \n15|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|23333333333222222222222222222222222222222222222222211111111111111111111111111111\n06|24444444555555545555555444444444444444444444444444211111111111111111111111111111\n07|24444444444444444444444444444444444466666666664444211111111111111111111111111111\n08|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n09|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n10|24444444555555555544444444444444444444444444444444211111111111111111111111111111\n11|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n12|24444444444444444444444477777744444444444444444444211111111111111111111111111111\n13|24444444444444444444444444444444444444444444444444211111111111111111111111111111\n14|23333332222222222222222222222222222222233333333333211111111111111111111111111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---works-when-help-window-is-already-opened",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                !                       \n03|!{motion}{filter}       Filter {motion} \n04|text lines through the external         \n05|                        program {filter}\n06|.                                       \n07|                                        \n08|                                        \n09|                !!                      \n10|!!{filter}              Filter [count] l\n11|ines through the external program       \n12|                        {filter}.       \n13|change.txt 551,8-57                     \n14|                                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000100000000000000000000000\n03|0000000000000000000000000000000222222220\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000022222222\n06|0000000000000000000000000000000000000000\n07|0000000000000000000000000000000000000000\n08|0000000000000000000000000000000000000000\n09|0000000000000000330000000000000000000000\n10|0000000000000000000000000000000000000000\n11|0000000000000000000000000000000000000000\n12|0000000000000000000000002222222200000000\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---works-with-`builtin.resume()`",
    "content": "--|---------|---------|---------|---------|\n01|                        help <Help>     \n02|:h :help <F1> i_<F1> i_<Help>           \n03|<Help>          or                      \n04|:h[elp]                 Open a window an\n05|d display the help file in read-only    \n06|                        mode.  If there \n07|is a help window open already, use      \n08|                        that one.  Other\n09|wise, if the current window uses the    \n10|                        full width of th\n11|e screen or is at least 80 characters   \n12|                        wide, the hel@@@\n13|helphelp.txt 14,25-46                   \n14|                                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000001111022222200000\n02|3304444405555066666607777777700000000000\n03|8888880000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000000\n07|0000000000000000000000000000000000000000\n08|0000000000000000000000000000000000000000\n09|0000000000000000000000000000000000000000\n10|0000000000000000000000000000000000000000\n11|0000000000000000000000000000000000000000\n12|0000000000000000000000000000000000000999\n13|::::::::::::::::::::::::::::::::::::::::\n14|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n15|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.help()---works-with-`builtin.resume()`-002",
    "content": "--|---------|---------|---------|---------|\n01|                        help <Help>     \n02|:h :help <F1> i_<F1> i_<Help>           \n03|<Help>          or                      \n04|:h[elp]                 Open a window an\n05|d display the help file in read-only    \n06|                        mode.  If there \n07|is a help window open already, use      \n08|                        that one.  Other\n09|wise, if the current window uses the    \n10|                        full width of th\n11|e screen or is at least 80 characters   \n12|                        wide, the hel@@@\n13|helphelp.txt 14,25-46                   \n14|                                        \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000001111022222200000\n02|3304444405555066666607777777700000000000\n03|8888880000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000000\n07|0000000000000000000000000000000000000000\n08|0000000000000000000000000000000000000000\n09|0000000000000000000000000000000000000000\n10|0000000000000000000000000000000000000000\n11|0000000000000000000000000000000000000000\n12|0000000000000000000000000000000000000999\n13|::::::::::::::::::::::::::::::::::::::::\n14|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n15|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---builtin.resume()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> b▏────────────────────┐              \n06|│b                       │              \n07|│bb                      │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2677777777777777777777777211111111111111\n07|2899999999999999999999999211111111111111\n08|2::::::::::::::::::::::::211111111111111\n09|2::::::::::::::::::::::::211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;;;222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_match()---works-with-active-picker",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> a▏────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|4|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2677777777777777777777777211111111111111\n07|2899999999999999999999999211111111111111\n08|2899999999999999999999999211111111111111\n09|2998999999999999999999999211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;;;222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_match()---works-with-active-picker-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ab▏───────────────────┐              \n06|│abc                     │              \n07|│a_b_c                   │              \n08|│a_b_b                   │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334452222222222222222222211111111111111\n06|2667777777777777777777777211111111111111\n07|2898999999999999999999999211111111111111\n08|2898999999999999999999999211111111111111\n09|2::::::::::::::::::::::::211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;;;222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---can-be-used-in-outside-preview-window",
    "content": "--|---------|---------|---------|---------|\n01|                       ┌───────────────┐\n02|~                      │Line 4         │\n03|~                      │Line 5         │\n04|~                      │Line 6         │\n05|┌> ▏─────────────────────┐─────────────┘\n06|│b.txt                   │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000011111111111111111\n02|2222222222222222222222213333333333333331\n03|2222222222222222222222214444444444444441\n04|2222222222222222222222213333333333333331\n05|1556111111111111111111111111111111111111\n06|1444444444444444444444444122222222222222\n07|1777777777777777777777777122222222222222\n08|1777777777777777777777777122222222222222\n09|1777777777777777777777777122222222222222\n10|1777777777777777777777777122222222222222\n11|1777777777777777777777777122222222222222\n12|1777777777777777777777777122222222222222\n13|1777777777777777777777777122222222222222\n14|1888888888881111118888888122222222222222\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---does-not-highlight-big-files",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ick/real-files/big.lua ┐              \n06|│local a = \"aaaaaaaaaaaaa│              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---does-not-highlight-big-files-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer item ───────────┐              \n06|│local a = \"aaaaaaaaaaaaa│              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333322222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---has-fallback",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌ -1 ────────────────────┐              \n04|│-1                      │              \n05|│                        │              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|└ <No name> ────── 1|2|2 ┘              \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2333322222222222222222222211111111111111\n04|2444444444444444444444444211111111111111\n05|2555555555555555555555555211111111111111\n06|2555555555555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2333333333332222223333333211111111111111\n10|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---has-fallback-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌ Random table ──────────┐              \n04|│{                       │              \n05|│  text = \"Random table\" │              \n06|│}                       │              \n07|│                        │              \n08|│                        │              \n09|└ <No name> ────── 2|2|2 ┘              \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2333333333333332222222222211111111111111\n04|2444444444444444444444444211111111111111\n05|2444444444444444444444444211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2333333333332222223333333211111111111111\n10|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---has-syntax-highlighting-in-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ee-sitter highlighting ┐              \n06|│local a = 1             │              \n07|│local t = {             │              \n08|│  x = math.max(1, 2),   │              \n09|│  y = math.min(1, 2),   │              \n10|│}                       │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444445555565555555555555211111111111111\n07|2444445555575555555555555211111111111111\n08|255855577779:::9695699555211111111111111\n09|255855577779:::9695699555211111111111111\n10|2755555555555555555555555211111111111111\n11|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n12|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n13|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---has-syntax-highlighting-in-buffer-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Built-in syntax ───────┐              \n06|│VAR ?= 1                │              \n07|│                        │              \n08|│all: test               │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333332222222211111111111111\n06|2444455555555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2666655555555555555555555211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---has-syntax-highlighting-in-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/a.lua ┐              \n06|│local a = 1             │              \n07|│local t = {             │              \n08|│  x = math.max(1, 2),   │              \n09|│  y = math.min(1, 2),   │              \n10|│}                       │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444445555565555555555555211111111111111\n07|2444445555575555555555555211111111111111\n08|255855577779:::9695699555211111111111111\n09|255855577779:::9695699555211111111111111\n10|2755555555555555555555555211111111111111\n11|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n12|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n13|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---has-syntax-highlighting-in-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ck/real-files/Makefile ┐              \n06|│VAR ?= 1                │              \n07|│                        │              \n08|│all: test               │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444455555555555555555555211111111111111\n07|2555555555555555555555555211111111111111\n08|2666655555555555555555555211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---loads-context-in-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---loads-context-in-buffer-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 7                  │              \n07|│Line 8                  │              \n08|│Line 9                  │              \n09|│Line 10                 │              \n10|│Line 11                 │              \n11|│Line 12                 │              \n12|│Line 13                 │              \n13|│Line 14                 │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---loads-context-in-buffer-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 13                 │              \n07|│Line 14                 │              \n08|│Line 15                 │              \n09|│Line 16                 │              \n10|│Line 17                 │              \n11|│Line 18                 │              \n12|│Line 19                 │              \n13|│Line 20                 │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---loads-context-in-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---loads-context-in-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 7                  │              \n07|│Line 8                  │              \n08|│Line 9                  │              \n09|│Line 10                 │              \n10|│Line 11                 │              \n11|│Line 12                 │              \n12|│Line 13                 │              \n13|│Line 14                 │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---loads-context-in-file-path-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 13                 │              \n07|│Line 14                 │              \n08|│Line 15                 │              \n09|│Line 16                 │              \n10|│Line 17                 │              \n11|│Line 18                 │              \n12|│Line 19                 │              \n13|│Line 20                 │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.line_position`---1-+-args-{-'bottom'-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ck/real-files/b.txt│10 ┐              \n06|│Line 3                  │              \n07|│Line 4                  │              \n08|│Line 5                  │              \n09|│Line 6                  │              \n10|│Line 7                  │              \n11|│Line 8                  │              \n12|│Line 9                  │              \n13|│Line 10                 │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.line_position`---1-+-args-{-'bottom'-}-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 5                  │              \n07|│Line 6                  │              \n08|│Line 7                  │              \n09|│Line 8                  │              \n10|│Line 9                  │              \n11|│Line 10                 │              \n12|│Line 11                 │              \n13|│Line 12                 │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.line_position`---1-+-args-{-'center'-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ck/real-files/b.txt│10 ┐              \n06|│Line 7                  │              \n07|│Line 8                  │              \n08|│Line 9                  │              \n09|│Line 10                 │              \n10|│Line 11                 │              \n11|│Line 12                 │              \n12|│Line 13                 │              \n13|│Line 14                 │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2555555555555555555555555211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.line_position`---1-+-args-{-'center'-}-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 9                  │              \n07|│Line 10                 │              \n08|│Line 11                 │              \n09|│Line 12                 │              \n10|│Line 13                 │              \n11|│Line 14                 │              \n12|│Line 15                 │              \n13|│Line 16                 │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2555555555555555555555555211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.line_position`---1-+-args-{-'top'-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ck/real-files/b.txt│10 ┐              \n06|│Line 10                 │              \n07|│Line 11                 │              \n08|│Line 12                 │              \n09|│Line 13                 │              \n10|│Line 14                 │              \n11|│Line 15                 │              \n12|│Line 16                 │              \n13|│Line 17                 │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.line_position`---1-+-args-{-'top'-}-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 12                 │              \n07|│Line 13                 │              \n08|│Line 14                 │              \n09|│Line 15                 │              \n10|│Line 16                 │              \n11|│Line 17                 │              \n12|│Line 18                 │              \n13|│Line 19                 │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.n_context_lines`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ick/real-files/b.txt│4 ┐              \n06|│Line 4                  │              \n07|│Line 5                  │              \n08|│Line 6                  │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`opts.n_context_lines`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer ────────────────┐              \n06|│Line 7                  │              \n07|│Line 8                  │              \n08|│Line 9                  │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333332222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---respects-`source.cwd`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ b.txt ─────────────────┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333322222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-line-in-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Line in buffer ────────┐              \n06|│Line 4 in buffer 2      │              \n07|│Line 5 in buffer 2      │              \n08|│Line 6 in buffer 2      │              \n09|│Line 7 in buffer 2      │              \n10|│Line 8 in buffer 2      │              \n11|│Line 9 in buffer 2      │              \n12|│Line 10 in buffer 2     │              \n13|│Line 11 in buffer 2     │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333322222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-line-in-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ick/real-files/b.txt│3 ┐              \n06|│Line 3                  │              \n07|│Line 4                  │              \n08|│Line 5                  │              \n09|│Line 6                  │              \n10|│Line 7                  │              \n11|│Line 8                  │              \n12|│Line 9                  │              \n13|│Line 10                 │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-line-in-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…l-files/b.txt│as-table ┐              \n06|│Line 6                  │              \n07|│Line 7                  │              \n08|│Line 8                  │              \n09|│Line 9                  │              \n10|│Line 10                 │              \n11|│Line 11                 │              \n12|│Line 12                 │              \n13|│Line 13                 │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-position-in-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Position in buffer ────┐              \n06|│Line 6 in buffer 2      │              \n07|│Line 7 in buffer 2      │              \n08|│Line 8 in buffer 2      │              \n09|│Line 9 in buffer 2      │              \n10|│Line 10 in buffer 2     │              \n11|│Line 11 in buffer 2     │              \n12|│Line 12 in buffer 2     │              \n13|│Line 13 in buffer 2     │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333332222211111111111111\n06|2445444444444444444444444211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-position-in-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…k/real-files/b.txt│3│4 ┐              \n06|│Line 3                  │              \n07|│Line 4                  │              \n08|│Line 5                  │              \n09|│Line 6                  │              \n10|│Line 7                  │              \n11|│Line 8                  │              \n12|│Line 9                  │              \n13|│Line 10                 │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444544444444444444444444211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-position-in-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…l-files/b.txt│as-table ┐              \n06|│Line 6                  │              \n07|│Line 7                  │              \n08|│Line 8                  │              \n09|│Line 9                  │              \n10|│Line 10                 │              \n11|│Line 11                 │              \n12|│Line 12                 │              \n13|│Line 13                 │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2454444444444444444444444211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-region-in-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…eline region in buffer ┐              \n06|│Line 8 in buffer 2      │              \n07|│Line 9 in buffer 2      │              \n08|│Line 10 in buffer 2     │              \n09|│Line 11 in buffer 2     │              \n10|│Line 12 in buffer 2     │              \n11|│Line 13 in buffer 2     │              \n12|│Line 14 in buffer 2     │              \n13|│Line 15 in buffer 2     │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2445554444444444444444444211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-region-in-buffer-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…lines region in buffer ┐              \n06|│Line 10 in buffer 2     │              \n07|│Line 11 in buffer 2     │              \n08|│Line 12 in buffer 2     │              \n09|│Line 13 in buffer 2     │              \n10|│Line 14 in buffer 2     │              \n11|│Line 15 in buffer 2     │              \n12|│Line 16 in buffer 2     │              \n13|│Line 17 in buffer 2     │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2445555555555555555544444211111111111111\n07|2555555555555555555566666211111111111111\n08|2555666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-region-in-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…s/b.txt│region-oneline ┐              \n06|│Line 8                  │              \n07|│Line 9                  │              \n08|│Line 10                 │              \n09|│Line 11                 │              \n10|│Line 12                 │              \n11|│Line 13                 │              \n12|│Line 14                 │              \n13|│Line 15                 │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2445544444444444444444444211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---shows-region-in-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…b.txt│region-manylines ┐              \n06|│Line 9                  │              \n07|│Line 10                 │              \n08|│Line 11                 │              \n09|│Line 12                 │              \n10|│Line 13                 │              \n11|│Line 14                 │              \n12|│Line 15                 │              \n13|│Line 16                 │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2445555444444444444444444211111111111111\n07|2555555566666666666666666211111111111111\n08|2555666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-URI-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ick/real-files/LICENSE ┐              \n06|│MIT (c)                 │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ 2 ─────────────────────┐              \n06|│This is buffer #1       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-buffer-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ 2 ─────────────────────┐              \n06|│This is buffer #1       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-buffer-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer #2 ─────────────┐              \n06|│This is buffer #2       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 3|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333332222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-buffer-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer #3 ─────────────┐              \n06|│This is buffer #3       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 4|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333332222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-buffer-005",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ Buffer #4 ─────────────┐              \n06|│This is buffer #4       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 5|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333332222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-directory-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ tests/dir-pick ────────┐              \n06|│builtin-tests/          │              \n07|│file                    │              \n08|│lua/                    │              \n09|│mocks/                  │              \n10|│real-files/             │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333322222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-directory-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ts/dir-pick/real-files ┐              \n06|│LICENSE                 │              \n07|│Makefile                │              \n08|│a.lua                   │              \n09|│b.txt                   │              \n10|│c.gif                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/b.txt ┐              \n06|│Line 1                  │              \n07|│Line 2                  │              \n08|│Line 3                  │              \n09|│Line 4                  │              \n10|│Line 5                  │              \n11|│Line 6                  │              \n12|│Line 7                  │              \n13|│Line 8                  │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2444444444444444444444444211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ick/real-files/LICENSE ┐              \n06|│MIT (c)                 │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-file-path-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…-pick/real-files/c.gif ┐              \n06|│-Non-text-file-         │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 3|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-file-path-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌…ck/real-files/Makefile ┐              \n06|│-No-access-             │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-file-path-with-tilde",
    "content": "-|---------|-----\n1|┌…LICENSE ┐    \n2|│MIT (c)  │    \n3|│         │    \n4|└…o name> ┘    \n5|               \n\n-|---------|-----\n1|011111111102222\n2|033333333304444\n3|055555555504444\n4|011111111104444\n5|222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-relative-file-path",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ a.lua ─────────────────┐              \n06|│local a = 1             │              \n07|│local t = {             │              \n08|│  x = math.max(1, 2),   │              \n09|│  y = math.min(1, 2),   │              \n10|│}                       │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333322222222222222222211111111111111\n06|2444445555565555555555555211111111111111\n07|2444445555575555555555555211111111111111\n08|255855577779:::9695699555211111111111111\n09|255855577779:::9695699555211111111111111\n10|2755555555555555555555555211111111111111\n11|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n12|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n13|2;;;;;;;;;;;;;;;;;;;;;;;;211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-for-relative-file-path-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ { path = \"file\" } ─────┐              \n06|│file                    │              \n07|│                        │              \n08|│aaa                     │              \n09|│bbb                     │              \n10|│ccc                     │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333333333333322222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-without-active-picker",
    "content": "--|---------|---------|---------|---------|\n01|Line 1                                  \n02|Line 2                                  \n03|Line 3                                  \n04|Line 4                                  \n05|Line 5                                  \n06|Line 6                                  \n07|Line 7                                  \n08|Line 8                                  \n09|Line 9                                  \n10|Line 10                                 \n11|Line 11                                 \n12|Line 12                                 \n13|Line 13                                 \n14|Line 14                                 \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000000\n07|0000000000000000000000000000000000000000\n08|0000000000000000000000000000000000000000\n09|0000000000000000000000000000000000000000\n10|0000000000000000000000000000000000000000\n11|0000000000000000000000000000000000000000\n12|0000000000000000000000000000000000000000\n13|0000000000000000000000000000000000000000\n14|0000000000000000000000000000000000000000\n15|1111111111111111111111111111111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_preview()---works-without-active-picker-002",
    "content": "--|---------|---------|---------|---------|\n01|MIT (c)                                 \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-edge-cases",
    "content": "-|---------|-----\n1|  │1           \n2|  │1│1         \n3|~              \n4|~              \n5|               \n\n-|---------|-----\n1|001111111111111\n2|001111111111111\n3|222222222222222\n4|222222222222222\n5|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-query-similar-to-`default_match`",
    "content": "--|---------|-----\n01|abc            \n02|_abc           \n03|a_bc           \n04|ab_c           \n05|abc_           \n06|*abc           \n07|'abc           \n08|^abc           \n09|abc$           \n10|a b c          \n11|~              \n12|~              \n13|~              \n14|~              \n15|               \n\n--|---------|-----\n01|001111111111111\n02|100111111111111\n03|010111111111111\n04|001111111111111\n05|001111111111111\n06|100111111111111\n07|100111111111111\n08|100111111111111\n09|001111111111111\n10|010111111111111\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|222222222222222\n15|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-query-similar-to-`default_match`-002",
    "content": "--|---------|-----\n01|abc            \n02|_abc           \n03|a_bc           \n04|ab_c           \n05|abc_           \n06|*abc           \n07|'abc           \n08|^abc           \n09|abc$           \n10|a b c          \n11|~              \n12|~              \n13|~              \n14|~              \n15|               \n\n--|---------|-----\n01|001111111111111\n02|100111111111111\n03|111111111111111\n04|001111111111111\n05|001111111111111\n06|100111111111111\n07|100111111111111\n08|100111111111111\n09|001111111111111\n10|111111111111111\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|222222222222222\n15|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-query-similar-to-`default_match`-003",
    "content": "--|---------|-----\n01|abc            \n02|_abc           \n03|a_bc           \n04|ab_c           \n05|abc_           \n06|*abc           \n07|'abc           \n08|^abc           \n09|abc$           \n10|a b c          \n11|~              \n12|~              \n13|~              \n14|~              \n15|               \n\n--|---------|-----\n01|001111111111111\n02|111111111111111\n03|111111111111111\n04|001111111111111\n05|001111111111111\n06|111111111111111\n07|111111111111111\n08|111111111111111\n09|001111111111111\n10|111111111111111\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|222222222222222\n15|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-query-similar-to-`default_match`-004",
    "content": "--|---------|-----\n01|abc            \n02|_abc           \n03|a_bc           \n04|ab_c           \n05|abc_           \n06|*abc           \n07|'abc           \n08|^abc           \n09|abc$           \n10|a b c          \n11|~              \n12|~              \n13|~              \n14|~              \n15|               \n\n--|---------|-----\n01|011000000000000\n02|001100000000000\n03|001100000000000\n04|000000000000000\n05|000000000000000\n06|001100000000000\n07|001100000000000\n08|001100000000000\n09|000000000000000\n10|000000000000000\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|222222222222222\n15|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-query-similar-to-`default_match`-005",
    "content": "--|---------|-----\n01|abc            \n02|_abc           \n03|a_bc           \n04|ab_c           \n05|abc_           \n06|*abc           \n07|'abc           \n08|^abc           \n09|abc$           \n10|a b c          \n11|~              \n12|~              \n13|~              \n14|~              \n15|               \n\n--|---------|-----\n01|000111111111111\n02|100011111111111\n03|111111111111111\n04|001011111111111\n05|000111111111111\n06|100011111111111\n07|100011111111111\n08|100011111111111\n09|000111111111111\n10|111111111111111\n11|222222222222222\n12|222222222222222\n13|222222222222222\n14|222222222222222\n15|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---handles-stritems-with-non-trivial-whitespace",
    "content": "--|---------|---------|\n01|With newline        \n02|With CR             \n03|EndsWithCR          \n04|EndsWithNL          \n05|EndsWithCRLF        \n06|With   tab          \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-'ignorecase'-'smartcase'",
    "content": "-|---------|--\n1|a_b         \n2|a_B         \n3|A_b         \n4|A_B         \n5|~           \n6|~           \n7|            \n\n-|---------|--\n1|010111111111\n2|111111111111\n3|111111111111\n4|111111111111\n5|222222222222\n6|222222222222\n7|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-'ignorecase'-'smartcase'-002",
    "content": "-|---------|--\n1|a_b         \n2|a_B         \n3|A_b         \n4|A_B         \n5|~           \n6|~           \n7|            \n\n-|---------|--\n1|000000000000\n2|101000000000\n3|000000000000\n4|000000000000\n5|222222222222\n6|222222222222\n7|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-'ignorecase'-'smartcase'-003",
    "content": "-|---------|--\n1|a_b         \n2|a_B         \n3|A_b         \n4|A_B         \n5|~           \n6|~           \n7|            \n\n-|---------|--\n1|010111111111\n2|010111111111\n3|010111111111\n4|010111111111\n5|222222222222\n6|222222222222\n7|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-'ignorecase'-'smartcase'-004",
    "content": "-|---------|--\n1|a_b         \n2|a_B         \n3|A_b         \n4|A_B         \n5|~           \n6|~           \n7|            \n\n-|---------|--\n1|010111111111\n2|010111111111\n3|010111111111\n4|010111111111\n5|222222222222\n6|222222222222\n7|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-'ignorecase'-'smartcase'-005",
    "content": "-|---------|--\n1|a_b         \n2|a_B         \n3|A_b         \n4|A_B         \n5|~           \n6|~           \n7|            \n\n-|---------|--\n1|010111111111\n2|010111111111\n3|010111111111\n4|010111111111\n5|222222222222\n6|222222222222\n7|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-'ignorecase'-'smartcase'-006",
    "content": "-|---------|--\n1|a_b         \n2|a_B         \n3|A_b         \n4|A_B         \n5|~           \n6|~           \n7|            \n\n-|---------|--\n1|000000000000\n2|101000000000\n3|000000000000\n4|000000000000\n5|222222222222\n6|222222222222\n7|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.icons`",
    "content": "--|---------|---------|---------|---------|-----\n01|FFtests/dir-pick/real-files/LICENSE          \n02|FFtests/dir-pick/real-files/Makefile         \n03|FFtests/dir-pick/real-files/a.lua            \n04|FFtests/dir-pick/real-files/b.txt            \n05|FFtests/dir-pick/real-files/c.gif            \n06|DDtests/dir-pick                             \n07|FFtests/dir-pick/file                        \n08|NNnon-existing                               \n09|NNnon-string                                 \n10|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|001111111211121111111111111111111111111111111\n03|001111111211121111111111111111111111111111111\n04|001111111211121111111111111111111111111111111\n05|001111111211121111111111111111111111111111111\n06|331111111211121111111111111111111111111111111\n07|001111111211121111111111111111111111111111111\n08|001111112112111111111111111111111111111111111\n09|001111111111111111111111111111111111111111111\n10|444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.icons`-002",
    "content": "--|---------|---------|---------|---------|-----\n01| tests/dir-pick/real-files/LICENSE          \n02|󱁤 tests/dir-pick/real-files/Makefile         \n03|󰢱 tests/dir-pick/real-files/a.lua            \n04|󰦪 tests/dir-pick/real-files/b.txt            \n05|󰵸 tests/dir-pick/real-files/c.gif            \n06|󰉋 tests/dir-pick                             \n07|󰈔 tests/dir-pick/file                        \n08|NNnon-existing                               \n09|NNnon-string                                 \n10|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|331111111211121111111111111111111111111111111\n03|441111111211121111111111111111111111111111111\n04|551111111211121111111111111111111111111111111\n05|441111111211121111111111111111111111111111111\n06|441111111211121111111111111111111111111111111\n07|331111111211121111111111111111111111111111111\n08|661111112112111111111111111111111111111111111\n09|661111111111111111111111111111111111111111111\n10|777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.icons`-003",
    "content": "--|---------|---------|---------|---------|-----\n01| tests/dir-pick/real-files/LICENSE          \n02| tests/dir-pick/real-files/Makefile         \n03| tests/dir-pick/real-files/a.lua            \n04| tests/dir-pick/real-files/b.txt            \n05| tests/dir-pick/real-files/c.gif            \n06|DDtests/dir-pick                             \n07|FFtests/dir-pick/file                        \n08|NNnon-existing                               \n09|NNnon-string                                 \n10|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|331111111211121111111111111111111111111111111\n03|441111111211121111111111111111111111111111111\n04|551111111211121111111111111111111111111111111\n05|661111111211121111111111111111111111111111111\n06|771111111211121111111111111111111111111111111\n07|881111111211121111111111111111111111111111111\n08|881111112112111111111111111111111111111111111\n09|881111111111111111111111111111111111111111111\n10|999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.show_icons`",
    "content": "--|---------|---------|---------|---------|-----\n01| tests/dir-pick/real-files/LICENSE          \n02| tests/dir-pick/real-files/Makefile         \n03| tests/dir-pick/real-files/a.lua            \n04| tests/dir-pick/real-files/b.txt            \n05| tests/dir-pick/real-files/c.gif            \n06| tests/dir-pick                             \n07| tests/dir-pick/file                        \n08|  non-existing                               \n09|  non-string                                 \n10| prefer-path-field                          \n11| buffer-prefer-path-field                   \n12| buffer-use-buf-name                        \n13|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|001111111211121111111111111111111111111111111\n03|001111111211121111111111111111111111111111111\n04|001111111211121111111111111111111111111111111\n05|001111111211121111111111111111111111111111111\n06|331111111211121111111111111111111111111111111\n07|001111111211121111111111111111111111111111111\n08|001111112112111111111111111111111111111111111\n09|001111111111111111111111111111111111111111111\n10|001111111111111111111111111111111111111111111\n11|331111111111111111111111111111111111111111111\n12|001111111111111111111111111111111111111111111\n13|444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.show_icons`-002",
    "content": "--|---------|---------|---------|---------|-----\n01| tests/dir-pick/real-files/LICENSE          \n02|󱁤 tests/dir-pick/real-files/Makefile         \n03|󰢱 tests/dir-pick/real-files/a.lua            \n04|󰦪 tests/dir-pick/real-files/b.txt            \n05|󰵸 tests/dir-pick/real-files/c.gif            \n06|󰉋 tests/dir-pick                             \n07|󰈔 tests/dir-pick/file                        \n08|  non-existing                               \n09|  non-string                                 \n10|󰈔 prefer-path-field                          \n11|󰉋 buffer-prefer-path-field                   \n12|󰈔 buffer-use-buf-name                        \n13|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|331111111211121111111111111111111111111111111\n03|441111111211121111111111111111111111111111111\n04|551111111211121111111111111111111111111111111\n05|441111111211121111111111111111111111111111111\n06|441111111211121111111111111111111111111111111\n07|331111111211121111111111111111111111111111111\n08|661111112112111111111111111111111111111111111\n09|661111111111111111111111111111111111111111111\n10|331111111111111111111111111111111111111111111\n11|441111111111111111111111111111111111111111111\n12|331111111111111111111111111111111111111111111\n13|777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.show_icons`-003",
    "content": "--|---------|---------|---------|---------|-----\n01| tests/dir-pick/real-files/LICENSE          \n02|󱁤 tests/dir-pick/real-files/Makefile         \n03|󰢱 tests/dir-pick/real-files/a.lua            \n04|󰦪 tests/dir-pick/real-files/b.txt            \n05|󰵸 tests/dir-pick/real-files/c.gif            \n06|󰉋 tests/dir-pick                             \n07|󰈔 tests/dir-pick/file                        \n08|  non-existing                               \n09|  non-string                                 \n10|󰈔 prefer-path-field                          \n11|󰉋 buffer-prefer-path-field                   \n12|󰈔 buffer-use-buf-name                        \n13|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|331111111211121111111111111111111111111111111\n03|441111111211121111111111111111111111111111111\n04|551111111211121111111111111111111111111111111\n05|441111111211121111111111111111111111111111111\n06|441111111211121111111111111111111111111111111\n07|331111111211121111111111111111111111111111111\n08|661111112112111111111111111111111111111111111\n09|661111111111111111111111111111111111111111111\n10|331111111111111111111111111111111111111111111\n11|441111111111111111111111111111111111111111111\n12|331111111111111111111111111111111111111111111\n13|777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---respects-`opts.show_icons`-004",
    "content": "--|---------|---------|---------|---------|-----\n01| tests/dir-pick/real-files/LICENSE          \n02| tests/dir-pick/real-files/Makefile         \n03| tests/dir-pick/real-files/a.lua            \n04| tests/dir-pick/real-files/b.txt            \n05| tests/dir-pick/real-files/c.gif            \n06| tests/dir-pick                             \n07| tests/dir-pick/file                        \n08|  non-existing                               \n09|  non-string                                 \n10| prefer-path-field                          \n11| buffer-prefer-path-field                   \n12| buffer-use-buf-name                        \n13|                                             \n\n--|---------|---------|---------|---------|-----\n01|001111111211121111111111111111111111111111111\n02|331111111211121111111111111111111111111111111\n03|441111111211121111111111111111111111111111111\n04|551111111211121111111111111111111111111111111\n05|661111111211121111111111111111111111111111111\n06|771111111211121111111111111111111111111111111\n07|881111111211121111111111111111111111111111111\n08|881111112112111111111111111111111111111111111\n09|881111111111111111111111111111111111111111111\n10|881111111111111111111111111111111111111111111\n11|771111111111111111111111111111111111111111111\n12|881111111111111111111111111111111111111111111\n13|999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---shows-best-match",
    "content": "--|---------|---------|\n01|a__b_a__b_ab        \n02|a__b_ab_a__b        \n03|ab_a__b_a__b        \n04|ab__ab              \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|00000000001100000000\n02|00000110000000000000\n03|11000000000000000000\n04|11000000000000000000\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---shows-best-match-002",
    "content": "--|---------|---------|\n01|aabbccddee          \n02|~                   \n03|~                   \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|01101010100000000000\n02|22222222222222222222\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ab▏───────────────────┐              \n06|│abc                     │              \n07|│a_bc                    │              \n08|│a__bc                   │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334452222222222222222222211111111111111\n06|2667777777777777777777777211111111111111\n07|2898999999999999999999999211111111111111\n08|2899899999999999999999999211111111111111\n09|2::::::::::::::::::::::::211111111111111\n10|2::::::::::::::::::::::::211111111111111\n11|2::::::::::::::::::::::::211111111111111\n12|2::::::::::::::::::::::::211111111111111\n13|2::::::::::::::::::::::::211111111111111\n14|2;;;;;;;;;;;222222;;;;;;;211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-with-multibyte-characters",
    "content": "--|---------|---------|\n01|ыdф                 \n02|ыы_d_ф              \n03|_ыы_d_ф             \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|01011111111111111111\n02|10111011111111111111\n03|11011101111111111111\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-with-multibyte-characters-002",
    "content": "--|---------|---------|\n01|ыdф                 \n02|ыы_d_ф              \n03|_ыы_d_ф             \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|01000000000000000000\n02|00010000000000000000\n03|00001000000000000000\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-with-non-single-char-entries-queries",
    "content": "--|---------|---------|\n01|_abc                \n02|a_bc                \n03|ab_c                \n04|abc_                \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|01110000000000000000\n02|00000000000000000000\n03|11010000000000000000\n04|11100000000000000000\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-with-non-single-char-entries-queries-002",
    "content": "--|---------|---------|\n01|_abc                \n02|a_bc                \n03|ab_c                \n04|abc_                \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|01110000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|11100000000000000000\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-with-non-single-char-entries-queries-003",
    "content": "--|---------|---------|\n01|_abc                \n02|a_bc                \n03|ab_c                \n04|abc_                \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|11111111111111111111\n06|11111111111111111111\n07|11111111111111111111\n08|11111111111111111111\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-without-active-picker",
    "content": "--|---------|---------|\n01|abc                 \n02|a_bc                \n03|a__bc               \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|00111111111111111111\n02|01011111111111111111\n03|01101111111111111111\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---default_show()---works-without-active-picker-002",
    "content": "--|---------|---------|\n01|def                 \n02|d_ef                \n03|d__ef               \n04|~                   \n05|~                   \n06|~                   \n07|~                   \n08|~                   \n09|~                   \n10|                    \n\n--|---------|---------|\n01|00111111111111111111\n02|01011111111111111111\n03|01101111111111111111\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---refresh()---is-called-on-`VimResized`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---refresh()---is-called-on-`VimResized`-002",
    "content": "--|---------|---------|\n01|                    \n02|~                   \n03|~                   \n04|~                   \n05|┌> ▏─────────┐      \n06|│a_b_c       │      \n07|│abc         │      \n08|│a_b_b       │      \n09|│c_a_a       │      \n10|│b_c_c       │      \n11|│            │      \n12|│            │      \n13|│            │      \n14|└ <No name> ─┘      \n15|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|11111111111111111111\n04|11111111111111111111\n05|23342222222222111111\n06|25555555555552111111\n07|26666666666662111111\n08|26666666666662111111\n09|26666666666662111111\n10|26666666666662111111\n11|27777777777772111111\n12|27777777777772111111\n13|27777777777772111111\n14|28888888888822111111\n15|00000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---refresh()---recomputes-window-config",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏───────┐                            \n06|│a         │                            \n07|│b         │                            \n08|│c         │                            \n09|│          │                            \n10|│          │                            \n11|│          │                            \n12|│          │                            \n13|│          │                            \n14|└…No name> ┘                            \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222221111111111111111111111111111\n06|2555555555521111111111111111111111111111\n07|2666666666621111111111111111111111111111\n08|2666666666621111111111111111111111111111\n09|2777777777721111111111111111111111111111\n10|2777777777721111111111111111111111111111\n11|2777777777721111111111111111111111111111\n12|2777777777721111111111111111111111111111\n13|2777777777721111111111111111111111111111\n14|2888888888821111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---refresh()---recomputes-window-config-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────┐                  \n06|│a                   │                  \n07|│b                   │                  \n08|│c                   │                  \n09|│                    │                  \n10|│                    │                  \n11|│                    │                  \n12|│                    │                  \n13|│                    │                  \n14|└ <No name> ── 1|3|3 ┘                  \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222111111111111111111\n06|2555555555555555555552111111111111111111\n07|2666666666666666666662111111111111111111\n08|2666666666666666666662111111111111111111\n09|2777777777777777777772111111111111111111\n10|2777777777777777777772111111111111111111\n11|2777777777777777777772111111111111111111\n12|2777777777777777777772111111111111111111\n13|2777777777777777777772111111111111111111\n14|2888888888882288888882111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---refresh()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---refresh()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏───────┐                            \n06|│a_b_c     │                            \n07|│abc       │                            \n08|│a_b_b     │                            \n09|│c_a_a     │                            \n10|│b_c_c     │                            \n11|│          │                            \n12|│          │                            \n13|│          │                            \n14|└…No name> ┘                            \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222221111111111111111111111111111\n06|2555555555521111111111111111111111111111\n07|2666666666621111111111111111111111111111\n08|2666666666621111111111111111111111111111\n09|2666666666621111111111111111111111111111\n10|2666666666621111111111111111111111111111\n11|2777777777721111111111111111111111111111\n12|2777777777721111111111111111111111111111\n13|2777777777721111111111111111111111111111\n14|2888888888821111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_items()---recomputes-visible-range",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│c                       │              \n07|│d                       │              \n08|│e                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_match_inds()---can-set-current-match-index",
    "content": "--|---------|---------|---------|-----\n01|                                   \n02|~                                  \n03|┌> ▏──────────────────┐            \n04|│a                    │            \n05|│b                    │            \n06|│c                    │            \n07|│da                   │            \n08|│                     │            \n09|└ <No name> ─── 3|4|4 ┘            \n10|                                   \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111111111111111111111111\n03|23342222222222222222222111111111111\n04|25555555555555555555552111111111111\n05|25555555555555555555552111111111111\n06|26666666666666666666662111111111111\n07|25555555555555555555552111111111111\n08|27777777777777777777772111111111111\n09|28888888888822288888882111111111111\n10|00000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_match_inds()---can-set-marked-match-indexes",
    "content": "--|---------|---------|---------|-----\n01|                                   \n02|~                                  \n03|┌> ▏──────────────────┐            \n04|│a                    │            \n05|│b                    │            \n06|│c                    │            \n07|│da                   │            \n08|│                     │            \n09|└ <No name> ─ 1|4|2/4 ┘            \n10|                                   \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111111111111111111111111\n03|23342222222222222222222111111111111\n04|25555555555555555555552111111111111\n05|26777777777777777777772111111111111\n06|27777777777777777777772111111111111\n07|26677777777777777777772111111111111\n08|28888888888888888888882111111111111\n09|29999999999929999999992111111111111\n10|00000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_match_inds()---can-set-marked-match-indexes-002",
    "content": "--|---------|---------|---------|-----\n01|                                   \n02|~                                  \n03|┌> ▏──────────────────┐            \n04|│a                    │            \n05|│b                    │            \n06|│c                    │            \n07|│da                   │            \n08|│                     │            \n09|└ <No name> ─ 1|4|1/4 ┘            \n10|                                   \n\n--|---------|---------|---------|-----\n01|00000000000000000000000000000000000\n02|11111111111111111111111111111111111\n03|23342222222222222222222111111111111\n04|25555555555555555555552111111111111\n05|26666666666666666666662111111111111\n06|27666666666666666666662111111111111\n07|26666666666666666666662111111111111\n08|28888888888888888888882111111111111\n09|29999999999929999999992111111111111\n10|00000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_match_inds()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│b                       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_opts()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│bb                      │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_opts()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~    ┌> ▏─────────────────────┐         \n06|~    │a                       │         \n07|~    │b                       │         \n08|~    │bb                      │         \n09|~    │                        │         \n10|~    │                        │         \n11|~    │                        │         \n12|~    │                        │         \n13|~    │                        │         \n14|~    └ My name ──────── 1|3|3 ┘         \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111123342222222222222222222222111111111\n06|1111125555555555555555555555552111111111\n07|1111126666666666666666666666662111111111\n08|1111126666666666666666666666662111111111\n09|1111127777777777777777777777772111111111\n10|1111127777777777777777777777772111111111\n11|1111127777777777777777777777772111111111\n12|1111127777777777777777777777772111111111\n13|1111127777777777777777777777772111111111\n14|1111128888888882222222288888882111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_opts()---works-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~    ┌> ▏─────────────────────┐         \n06|~    │b                       │         \n07|~    │                        │         \n08|~    │                        │         \n09|~    │                        │         \n10|~    │                        │         \n11|~    │                        │         \n12|~    │                        │         \n13|~    │                        │         \n14|~    └ My other name ── 1|1|3 ┘         \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111123342222222222222222222222111111111\n06|1111125555555555555555555555552111111111\n07|1111126666666666666666666666662111111111\n08|1111126666666666666666666666662111111111\n09|1111126666666666666666666666662111111111\n10|1111126666666666666666666666662111111111\n11|1111126666666666666666666666662111111111\n12|1111126666666666666666666666662111111111\n13|1111126666666666666666666666662111111111\n14|1111127777777777777772277777772111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---set_picker_query()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> bb▏───────────────────┐              \n06|│bb                      │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334452222222222222222222211111111111111\n06|2667777777777777777777777211111111111111\n07|2888888888888888888888888211111111111111\n08|2888888888888888888888888211111111111111\n09|2888888888888888888888888211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2888888888888888888888888211111111111111\n14|2999999999992222229999999211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---can-be-started-without-explicit-items",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└────────────────────────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2222222222222222222222222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---correctly-computes-stritems",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|~                                                                               \n03|~                                                                               \n04|~                                                                               \n05|┌> ▏──────────────────────────────────────────────┐                             \n06|│string_item                                      │                             \n07|│table_item                                       │                             \n08|│{ a = \"fallback item\", b = 1 }                   │                             \n09|│string_item_from_callable                        │                             \n10|│table_item_from_callable                         │                             \n11|│{ c = \"fallback item from callable\", d = 1 }     │                             \n12|│                                                 │                             \n13|│                                                 │                             \n14|└ <No name> ─────────────────────────────── 1|6|6 ┘                             \n15|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|23342222222222222222222222222222222222222222222222211111111111111111111111111111\n06|25555555555555555555555555555555555555555555555555211111111111111111111111111111\n07|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n08|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n09|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n10|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n11|26666666666666666666666666666666666666666666666666211111111111111111111111111111\n12|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n13|27777777777777777777777777777777777777777777777777211111111111111111111111111111\n14|28888888888822222222222222222222222222222228888888211111111111111111111111111111\n15|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`options.content_from_bottom`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ <No name> ────── 1|2|2 ┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│b                       │              \n13|│a                       │              \n14|└> ▏─────────────────────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333333333332222223333333211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2444444444444444444444444211111111111111\n12|2444444444444444444444444211111111111111\n13|2555555555555555555555555211111111111111\n14|2667222222222222222222222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.items`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.items`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│c                       │              \n07|│d                       │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.items`-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│e                       │              \n07|│f                       │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.items`-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│g                       │              \n07|│h                       │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.match`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│b                       │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.name`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ Hello ────────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888822222222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.preview`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ a ─────────────────────┐              \n06|│Preview: a              │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.preview`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ b ─────────────────────┐              \n06|│Preview: b              │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 2|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.show`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│__a                     │              \n07|│__b                     │              \n08|│__bb                    │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`source.show`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> b▏────────────────────┐              \n06|│__b                     │              \n07|│__bb                    │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334522222222222222222222211111111111111\n06|2666666666666666666666666211111111111111\n07|2777777777777777777777777211111111111111\n08|2888888888888888888888888211111111111111\n09|2888888888888888888888888211111111111111\n10|2888888888888888888888888211111111111111\n11|2888888888888888888888888211111111111111\n12|2888888888888888888888888211111111111111\n13|2888888888888888888888888211111111111111\n14|2999999999992222229999999211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`vim.b.minipick_config`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|┌> ▏───────┐                            \n05|│a         │                            \n06|│b         │                            \n07|│c         │                            \n08|│          │                            \n09|│          │                            \n10|│          │                            \n11|│          │                            \n12|│          │                            \n13|└…No name> ┘                            \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|2334222222221111111111111111111111111111\n05|2555555555521111111111111111111111111111\n06|2666666666621111111111111111111111111111\n07|2666666666621111111111111111111111111111\n08|2777777777721111111111111111111111111111\n09|2777777777721111111111111111111111111111\n10|2777777777721111111111111111111111111111\n11|2777777777721111111111111111111111111111\n12|2777777777721111111111111111111111111111\n13|2888888888821111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.config`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|╔> ▏═════════════════════╗              \n06|║a                       ║              \n07|║b                       ║              \n08|║c                       ║              \n09|║                        ║              \n10|║                        ║              \n11|║                        ║              \n12|║                        ║              \n13|║                        ║              \n14|╚ <No name> ══════ 1|3|3 ╝              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.config`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|┌> ▏───────────────────────────────────┐\n04|│a                                     │\n05|│b                                     │\n06|│c                                     │\n07|│                                      │\n08|│                                      │\n09|│                                      │\n10|│                                      │\n11|│                                      │\n12|└ <No name> ──────────────────── 1|3|3 ┘\n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|2334222222222222222222222222222222222222\n04|2555555555555555555555555555555555555552\n05|2666666666666666666666666666666666666662\n06|2666666666666666666666666666666666666662\n07|2777777777777777777777777777777777777772\n08|2777777777777777777777777777777777777772\n09|2777777777777777777777777777777777777772\n10|2777777777777777777777777777777777777772\n11|2777777777777777777777777777777777777772\n12|2888888888882222222222222222222288888882\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.prompt_caret`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> +─────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│c                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.prompt_caret`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> a+b───────────────────┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── -|0|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334542222222222222222222211111111111111\n06|2666666666666666666666666211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.prompt_prefix`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌$>  ▏───────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│c                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333342222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.prompt_prefix`-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌$>  a▏b─────────────────┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── -|0|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333345422222222222222222211111111111111\n06|2666666666666666666666666211111111111111\n07|2777777777777777777777777211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.prompt_prefix`-003",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌▏───────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│c                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2322222222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2555555555555555555555555211111111111111\n08|2555555555555555555555555211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-`window.prompt_prefix`-004",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌a▏b─────────────────────┐              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── -|0|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2343222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2666666666666666666666666211111111111111\n12|2666666666666666666666666211111111111111\n13|2666666666666666666666666211111111111111\n14|2777777777772222227777777211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---respects-global-config",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|┌> ▏─────────────────────┐              \n03|│a                       │              \n04|│b                       │              \n05|│c                       │              \n06|│                        │              \n07|│                        │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|└ <No name> ────── 1|3|3 ┘              \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1223111111111111111111111144444444444444\n03|1555555555555555555555555144444444444444\n04|1666666666666666666666666144444444444444\n05|1666666666666666666666666144444444444444\n06|1777777777777777777777777144444444444444\n07|1777777777777777777777777144444444444444\n08|1777777777777777777777777144444444444444\n09|1777777777777777777777777144444444444444\n10|1777777777777777777777777144444444444444\n11|1888888888881111118888888144444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|4444444444444444444444444444444444444444\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---stops-currently-active-picker",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│d                       │              \n07|│e                       │              \n08|│f                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---stops-improperly-aborted-previous-picker",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│c                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|3|3 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---stops-improperly-aborted-previous-picker-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏───────┐                            \n06|│d         │                            \n07|│e         │                            \n08|│f         │                            \n09|│          │                            \n10|│          │                            \n11|│          │                            \n12|│          │                            \n13|│          │                            \n14|└…No name> ┘                            \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222221111111111111111111111111111\n06|2555555555521111111111111111111111111111\n07|2666666666621111111111111111111111111111\n08|2666666666621111111111111111111111111111\n09|2777777777721111111111111111111111111111\n10|2777777777721111111111111111111111111111\n11|2777777777721111111111111111111111111111\n12|2777777777721111111111111111111111111111\n13|2777777777721111111111111111111111111111\n14|2888888888821111111111111111111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---tracks-lost-focus",
    "content": "--|---------|---------|---------|---------|\n01|aa bb                                   \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a                       │              \n07|│b                       │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---tracks-lost-focus-002",
    "content": "--|---------|---------|---------|---------|\n01|aa bb                                   \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---tracks-lost-focus-003",
    "content": "--|---------|---------|---------|---------|\n01|aa bb                                   \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|\"a_b_c\"                                 \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---works-on-Neovim-0.9",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌────────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└────────────────────────┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2222222222222222222222222211111111111111\n06|2333333333333333333333333211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2444444444444444444444444211111111111111\n10|2444444444444444444444444211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2222222222222222222222222211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---works-on-Neovim-0.9-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|\"a_b_c\"                                 \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---works-with-window-footer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---start()---works-with-window-footer-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|\"a_b_c\"                                 \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---stop()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│a_b_c                   │              \n07|│abc                     │              \n08|│a_b_b                   │              \n09|│c_a_a                   │              \n10|│b_c_c                   │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|5|5 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2666666666666666666666666211111111111111\n09|2666666666666666666666666211111111111111\n10|2666666666666666666666666211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---stop()---works-002",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|~                                       \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|1111111111111111111111111111111111111111\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|1111111111111111111111111111111111111111\n14|1111111111111111111111111111111111111111\n15|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---ui_select()---respects-`opts.preview_item`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ abc ───────────────────┐              \n06|│My preview              │              \n07|│Var = abc               │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333332222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2555555555555555555555555211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---ui_select()---respects-`start_opts`",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏───────────────────────────────────┐\n06|│a                                     │\n07|│b                                     │\n08|│                                      │\n09|│                                      │\n10|│                                      │\n11|│                                      │\n12|│                                      │\n13|│                                      │\n14|└ Select: ────────────────────── 1|2|2 ┘\n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222222222222222222\n06|2555555555555555555555555555555555555552\n07|2666666666666666666666666666666666666662\n08|2777777777777777777777777777777777777772\n09|2777777777777777777777777777777777777772\n10|2777777777777777777777777777777777777772\n11|2777777777777777777777777777777777777772\n12|2777777777777777777777777777777777777772\n13|2777777777777777777777777777777777777772\n14|2888888888222222222222222222222288888882\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---ui_select()---shows-only-original-item-in-preview",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌ abc ───────────────────┐              \n06|│{                       │              \n07|│  var = \"abc\"           │              \n08|│}                       │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|1|1 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2333332222222222222222222211111111111111\n06|2444444444444444444444444211111111111111\n07|2444444444444444444444444211111111111111\n08|2444444444444444444444444211111111111111\n09|2555555555555555555555555211111111111111\n10|2555555555555555555555555211111111111111\n11|2555555555555555555555555211111111111111\n12|2555555555555555555555555211111111111111\n13|2555555555555555555555555211111111111111\n14|2333333333332222223333333211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_pick.lua---ui_select()---works",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|~                                       \n03|~                                       \n04|~                                       \n05|┌> ▏─────────────────────┐              \n06|│-1                      │              \n07|│-2                      │              \n08|│                        │              \n09|│                        │              \n10|│                        │              \n11|│                        │              \n12|│                        │              \n13|│                        │              \n14|└ <No name> ────── 1|2|2 ┘              \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|1111111111111111111111111111111111111111\n03|1111111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|2334222222222222222222222211111111111111\n06|2555555555555555555555555211111111111111\n07|2666666666666666666666666211111111111111\n08|2777777777777777777777777211111111111111\n09|2777777777777777777777777211111111111111\n10|2777777777777777777777777211111111111111\n11|2777777777777777777777777211111111111111\n12|2777777777777777777777777211111111111111\n13|2777777777777777777777777211111111111111\n14|2888888888882222228888888211111111111111\n15|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Interaction-with-built-in-completion---no-affect-of-'exausted'-popup-during-jump",
    "content": "-|---------|---------|---------|---------|\n1|abc ax x∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,9                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000110230000000000000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Interaction-with-built-in-completion---squashed-tabstops",
    "content": "-|---------|---------|---------|---------|\n1|abcxabcxabc∎                            \n2|abcxabc                                 \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- Back at original                     \n\n-|---------|---------|---------|---------|\n1|0001000100023333333333333333333333333333\n2|4444444444444445555555555555555555555555\n3|5555555555555555555555555555555555555555\n4|5555555555555555555555555555555555555555\n5|5555555555555555555555555555555555555555\n6|5555555555555555555555555555555555555555\n7|6666666666666666666666666666666666666666\n8|7778888888888888888999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Interaction-with-built-in-completion---squashed-tabstops-002",
    "content": "-|---------|---------|---------|---------|\n1|abcxyabcxyabc∎                          \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- Back at original                     \n\n-|---------|---------|---------|---------|\n1|0001100011000233333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6667777777777777777888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---autostop---is-not-triggered-if-final-tabstop-is-not-current",
    "content": "-|---------|---------|---------|---------|\n1|T1=• T0=new∎                            \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,11-12                       \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000000020000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---are-always-shown-all-at-once",
    "content": "-|---------|---------|---------|---------|\n1|T1=bb T2=d∎                             \n2|~  bb                                   \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100002300000000000000000000000000000\n2|4455555555555555554444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---are-always-shown-all-at-once-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=• T2=d∎                              \n2|~   aa                                  \n3|~   bb                                  \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4-5                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000023000000000000000000000000000000\n2|4445555555555555555444444444444444444444\n3|4445555555555555555444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---are-always-shown-all-at-once-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=• T2=d∎                              \n2|~       dd                              \n3|~       cc                              \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,9-10                        \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000023000000000000000000000000000000\n2|4444444555555555555555544444444444444444\n3|4444444555555555555555544444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---work-with-default-'completeopt'",
    "content": "-|---------|---------|---------|---------|\n1|T1=aa T2=dd∎                            \n2|~  aa                                   \n3|~  bb                                   \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100002230000000000000000000000000000\n2|4455555555555555554444444444444444444444\n3|4466666666666666664444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|7777777777777777777777777777777777777777\n8|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---work-with-default-'completeopt'-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=aa T2=dd∎                            \n2|~  aa                                   \n3|~  bb                                   \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100002230000000000000000000000000000\n2|4455555555555555554444444444444444444444\n3|4466666666666666664444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|7777777777777777777777777777777777777777\n8|8888888888889999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---works",
    "content": "-|---------|---------|---------|---------|\n1|T1=aa T2=dd∎                            \n2|~  aa                                   \n3|~  bb                                   \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100002230000000000000000000000000000\n2|4455555555555555554444444444444444444444\n3|4455555555555555554444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---choices---works-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=• T2=dd∎                             \n2|~   aa                                  \n3|~   bb                                  \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4-5                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000022300000000000000000000000000000\n2|4445555555555555555444444444444444444444\n3|4445555555555555555444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---does-not-show-'Pattern-not-found'-message",
    "content": "-|---------|---------|---------|---------|\n1|T1= T2=aa T0=                           \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|[No Name] 1,8                           \n7|                                        \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|2222222222222222222222222222222222222222\n7|3333333333333333333333333333333333333333\n8|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---highlighting---uses-same-highlighting-for-whole-placeholder-for-current-tabstop",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=••> •• ∎ •                       \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111111022030200000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---highlighting---uses-same-highlighting-for-whole-placeholder-for-current-tabstop-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=••> •• ∎ •                       \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,8-9                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111221022030400000000000000000000000\n2|5555555555555555555555555555555555555555\n3|5555555555555555555555555555555555555555\n4|5555555555555555555555555555555555555555\n5|5555555555555555555555555555555555555555\n6|5555555555555555555555555555555555555555\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---highlighting---uses-same-highlighting-for-whole-placeholder-for-current-tabstop-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=••> •• ∎ •                       \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,8-10                        \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111121012030200000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---are-updated-immediately-when-typing",
    "content": "-|---------|---------|---------|---------|\n1|T1=ab_T1=ab∎                            \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100001120000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---are-updated-immediately-when-typing-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=ab                                   \n2|_T1=ab                                  \n3|∎                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 2,1                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100000000000000000000000000000000000\n2|0000110000000000000000000000000000000000\n3|2000000000000000000000000000000000000000\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---are-updated-immediately-when-typing-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=ab                                   \n2|c_T1=ab                                 \n3|c∎                                      \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 2,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100000000000000000000000000000000000\n2|1000011000000000000000000000000000000000\n3|1200000000000000000000000000000000000000\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---jumps-to-the-first-node",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=•> T2=• T1=<T2=•>∎               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111110000200001111113000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---jumps-to-the-first-node-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=•> T2=• T1=<T2=•>∎               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,8-9                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111210000200001111213000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---jumps-to-the-first-node-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=x T2=• T1=x∎                         \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,9-10                        \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000020000130000000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---validates-that-session-data-is-valid",
    "content": "-|---------|---------|---------|---------|\n1|T1=x                                    \n2|T0=                                     \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|0000000000000000000000000000000000000000\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n7|2222222222222222222222222222222222222222\n8|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---linked-tabstops---validates-that-session-data-is-valid-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=                                     \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,3                           \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n7|2222222222222222222222222222222222222222\n8|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---can-be-done-outside-of-current-session-region",
    "content": "-|---------|---------|---------|---------|\n1|T1= T0=                                 \n2|                                        \n3|U1=• U0=∎                               \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 3,4-5                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|0000000000000000000000000000000000000000\n3|0001000020000000000000000000000000000000\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---does-not-nest-if-no-tabstops-in-new-session",
    "content": "-|---------|---------|---------|---------|\n1|T1=just text T0=∎                       \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,13                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111111110000200000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---works-and-triggers-events",
    "content": "-|---------|---------|---------|---------|\n1|T1=• T0=∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4-5                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000020000000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---works-and-triggers-events-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1=• U0=∎ T0=                        \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,7-8                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000001000020000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---works-and-triggers-events-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1=V1=vvv V0=∎ U0= T0=               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,13                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000000001110000200000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---works-and-triggers-events-004",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1=V1=vvv V0= U0=∎ T0=               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,13                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000001111111111000020000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---nesting---works-and-triggers-events-005",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1=V1=vvv V0= U0= T0=∎               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,13                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111111111111111100002000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---persists-after-`-edit`",
    "content": "-|---------|---------|---------|---------|\n1|T1=• T0=∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|Dummy statusline                        \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000020000000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---preserves-order-of-'squashed'-empty-tabstops",
    "content": "-|---------|---------|---------|---------|\n1|••• ••• ••• ••• ••• •••∎                \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0112011210121102101211032222222222222222\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---preserves-order-of-'squashed'-empty-tabstops-002",
    "content": "-|---------|---------|---------|---------|\n1|••• ••• ••• ••• ••• •••∎                \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-3                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0123021310231203201321043333333333333333\n2|5555555555555555555555555555555555555555\n3|5555555555555555555555555555555555555555\n4|5555555555555555555555555555555555555555\n5|5555555555555555555555555555555555555555\n6|5555555555555555555555555555555555555555\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---preserves-order-of-'squashed'-empty-tabstops-003",
    "content": "-|---------|---------|---------|---------|\n1|••• ••• ••• ••• ••• •••∎                \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-4                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0012010200120102100210032222222222222222\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---preserves-order-of-'squashed'-empty-tabstops-004",
    "content": "-|---------|---------|---------|---------|\n1|••∎                                     \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-3                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0123333333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Session---preserves-order-of-'squashed'-empty-tabstops-005",
    "content": "-|---------|---------|---------|---------|\n1|••∎                                     \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-4                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0012222222222222222222222222222222222222\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---intertwined-nested-tabstops",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=•> and T2=•∎                     \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111110000000023000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---intertwined-nested-tabstops-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=x and T2=•∎                          \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000000002300000000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---intertwined-nested-tabstops-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=x and T2=y∎                          \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,14                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000000002300000000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---intertwined-nested-tabstops-004",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=•> and T2=•∎                     \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,8-9                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111210000000023000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---intertwined-nested-tabstops-005",
    "content": "-|---------|---------|---------|---------|\n1|T1=<T2=x> and T2=x∎                     \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,9                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111210000000023000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---intertwined-nested-tabstops-006",
    "content": "-|---------|---------|---------|---------|\n1|T1=y and T2=x∎                          \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000000002300000000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops",
    "content": "-|---------|---------|---------|---------|\n1|••• •• •∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001221231111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops,-another",
    "content": "-|---------|---------|---------|---------|\n1|• •• •••∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0120122031111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops,-another-002",
    "content": "-|---------|---------|---------|---------|\n1|• •• •••∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2-4                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0122132241111111111111111111111111111111\n2|5555555555555555555555555555555555555555\n3|5555555555555555555555555555555555555555\n4|5555555555555555555555555555555555555555\n5|5555555555555555555555555555555555555555\n6|5555555555555555555555555555555555555555\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops,-another-003",
    "content": "-|---------|---------|---------|---------|\n1|• •• •••∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,3-7                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0100122231111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops,-another-004",
    "content": "-|---------|---------|---------|---------|\n1|a a a∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101021111111111111111111111111111111111\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops,-another-005",
    "content": "-|---------|---------|---------|---------|\n1|a b b∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0121231111111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops,-another-006",
    "content": "-|---------|---------|---------|---------|\n1|a b c∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101231111111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops-002",
    "content": "-|---------|---------|---------|---------|\n1|••• •• •∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-3                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0112112342222222222222222222222222222222\n2|5555555555555555555555555555555555555555\n3|5555555555555555555555555555555555555555\n4|5555555555555555555555555555555555555555\n5|5555555555555555555555555555555555555555\n6|5555555555555555555555555555555555555555\n7|6666666666666666666666666666666666666666\n8|7777777777778888888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops-003",
    "content": "-|---------|---------|---------|---------|\n1|••• •• •∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-4                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0012012132222222222222222222222222222222\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops-004",
    "content": "-|---------|---------|---------|---------|\n1|a a a∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101021111111111111111111111111111111111\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops-005",
    "content": "-|---------|---------|---------|---------|\n1|b b a∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101231111111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---nested-empty-tabstops-006",
    "content": "-|---------|---------|---------|---------|\n1|c b a∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0121231111111111111111111111111111111111\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-consecutive-tabstops",
    "content": "-|---------|---------|---------|---------|\n1|•••••∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001123333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-consecutive-tabstops-002",
    "content": "-|---------|---------|---------|---------|\n1|aaa••∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001123333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-consecutive-tabstops-003",
    "content": "-|---------|---------|---------|---------|\n1|aaabb∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001123333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-consecutive-tabstops-004",
    "content": "-|---------|---------|---------|---------|\n1|aaa••∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4-5                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001123333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-consecutive-tabstops-005",
    "content": "-|---------|---------|---------|---------|\n1|•••••∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001123333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-interleaving-tabstops",
    "content": "-|---------|---------|---------|---------|\n1|•••••∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101023333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-interleaving-tabstops-002",
    "content": "-|---------|---------|---------|---------|\n1|a•a•a∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101023333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-interleaving-tabstops-003",
    "content": "-|---------|---------|---------|---------|\n1|ababa∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,3                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101023333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-interleaving-tabstops-004",
    "content": "-|---------|---------|---------|---------|\n1|a•a•a∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2-3                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101023333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-empty-interleaving-tabstops-005",
    "content": "-|---------|---------|---------|---------|\n1|•••••∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101023333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-tabstops-with-placeholders",
    "content": "-|---------|---------|---------|---------|\n1|•aa•aa•∎                                \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0110110233333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-tabstops-with-placeholders-002",
    "content": "-|---------|---------|---------|---------|\n1|xaaxaax∎                                \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,2                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0110110233333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Tricky-snippets---squashed-linked-tabstops-with-placeholders-003",
    "content": "-|---------|---------|---------|---------|\n1|xyxyx∎                                  \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,3                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0101023333333333333333333333333333333333\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders",
    "content": "-|---------|---------|---------|---------|\n1|T1=<aaa> T0=<bbb>                       \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111100002222200000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=x T0=<bbb>                           \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000022222000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=x T0=<bbb>                           \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,9                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000022222000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders-004",
    "content": "-|---------|---------|---------|---------|\n1|T1=x T0=y                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,10                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n7|2222222222222222222222222222222222222222\n8|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders-005",
    "content": "-|---------|---------|---------|---------|\n1|T1=aa                                   \n2|bb                                      \n3| T0=∎                                   \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001100000000000000000000000000000000000\n2|1100000000000000000000000000000000000000\n3|0000200000000000000000000000000000000000\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders-006",
    "content": "-|---------|---------|---------|---------|\n1|T1=x T0=∎                               \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,5                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000020000000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---placeholders-007",
    "content": "-|---------|---------|---------|---------|\n1|Text placeholder                        \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,6                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000011111111111000000000000000000000000\n2|2222222222222222222222222222222222222222\n3|2222222222222222222222222222222222222222\n4|2222222222222222222222222222222222222222\n5|2222222222222222222222222222222222222222\n6|2222222222222222222222222222222222222222\n7|3333333333333333333333333333333333333333\n8|4444444444445555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---tabstop",
    "content": "-|---------|---------|---------|---------|\n1|•∎                                      \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0122222222222222222222222222222222222222\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---Various-snippets---tabstop-002",
    "content": "-|---------|---------|---------|---------|\n1|•∎                                      \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,1-2                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0122222222222222222222222222222222222222\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---default_insert()---respects-`opts.empty_tabstop`-and-`opts.empty_tabstop_final`",
    "content": "-|---------|---------|---------|---------|\n1|T1=! T2=! T0=?                          \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,4-5                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001000020000300000000000000000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---default_insert()---respects-`opts.lookup`",
    "content": "-|---------|---------|---------|---------|\n1|aaa xxx tabstop tabstop •∎              \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,16                          \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000000011111110111111102300000000000000\n2|4444444444444444444444444444444444444444\n3|4444444444444444444444444444444444444444\n4|4444444444444444444444444444444444444444\n5|4444444444444444444444444444444444444444\n6|4444444444444444444444444444444444444444\n7|5555555555555555555555555555555555555555\n8|6666666666667777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---session.stop()---ensures-next-nested-session-is-valid",
    "content": "-|---------|---------|---------|---------|\n1|V1= V0=                                 \n2|T1=• T0=∎                               \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,3                           \n8|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|0001000020000000000000000000000000000000\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---session.stop()---works",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1=• U0=∎ T0=                        \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,7-8                         \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000001000020000000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---session.stop()---works-002",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1= U0= T0=∎                         \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,7                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0001111111000020000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|3333333333333333333333333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n6|3333333333333333333333333333333333333333\n7|4444444444444444444444444444444444444444\n8|5555555555556666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_snippets.lua---session.stop()---works-003",
    "content": "-|---------|---------|---------|---------|\n1|T1=U1= U0= T0=                          \n2|~                                       \n3|~                                       \n4|~                                       \n5|~                                       \n6|~                                       \n7|[No Name] 1,7                           \n8|-- INSERT --                            \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111\n4|1111111111111111111111111111111111111111\n5|1111111111111111111111111111111111111111\n6|1111111111111111111111111111111111111111\n7|2222222222222222222222222222222222222222\n8|3333333333334444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---'Recent-files'-section---displays-only-readable-files",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|                 Good afternoon, MINI                                           \n05|                                                                                \n06|                 Recent files                                                   \n07|                 ░ README.md                                                    \n08|                                                                                \n09|                 Builtin actions                                                \n10|                 ░ Edit new buffer                                              \n11|                 ░ Quit Neovim                                                  \n12|                                                                                \n13|                 Type query to filter items                                     \n14|                 <BS> deletes latest character from query                       \n15|                 <Esc> resets current query                                     \n16|                 <Down/Up>, <C-n/p>, <M-j/k> move current item                  \n17|                 <CR> executes action of current item                           \n18|                 <C-c> closes this buffer                                       \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 7,18                                                    \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000000111111111111111111110000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000000222222222222000000000000000000000000000000000000000000000000000\n07|00000000000000000334555555550000000000000000000000000000000000000000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000000222222222222222000000000000000000000000000000000000000000000000\n10|00000000000000000334555555555555550000000000000000000000000000000000000000000000\n11|00000000000000000334555555555500000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000000333333333333333333333333330000000000000000000000000000000000000\n14|00000000000000000333333333333333333333333333333333333333300000000000000000000000\n15|00000000000000000333333333333333333333333330000000000000000000000000000000000000\n16|00000000000000000333333333333333333333333333333333333333333333000000000000000000\n17|00000000000000000333333333333333333333333333333333333000000000000000000000000000\n18|00000000000000000333333333333333333333333000000000000000000000000000000000000000\n19|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n20|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n21|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n22|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n23|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n24|88888888888888855555555555555555555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---'Recent-files'-section---present-even-if-no-recent-files",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---'Sessions'-section---present-even-if-no-sessions-detected",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|              Good afternoon, MINI                                              \n04|                                                                                \n05|              Sessions                                                          \n06|              ░ There are no detected sessions in 'mini.sessions'               \n07|                                                                                \n08|              Recent files                                                      \n09|              ░ There are no recent files (`v:oldfiles` is empty)               \n10|                                                                                \n11|              Builtin actions                                                   \n12|              ░ Edit new buffer                                                 \n13|              ░ Quit Neovim                                                     \n14|                                                                                \n15|              Type query to filter items                                        \n16|              <BS> deletes latest character from query                          \n17|              <Esc> resets current query                                        \n18|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n19|              <CR> executes action of current item                              \n20|              <C-c> closes this buffer                                          \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 12,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n04|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|00000000000000222222220000000000000000000000000000000000000000000000000000000000\n06|00000000000000334444444444444455555555555555555555555555555555555000000000000000\n07|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n08|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n09|00000000000000334444444444444455555555555555555555555555555555555000000000000000\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n11|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n12|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n13|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n14|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n17|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n18|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n19|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n20|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---'Sessions'-section---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|              Good afternoon, MINI                                              \n03|                                                                                \n04|              Sessions                                                          \n05|              ░ Session.vim (local)                                             \n06|              ░ session_global.lua                                              \n07|                                                                                \n08|              Recent files                                                      \n09|              ░ There are no recent files (`v:oldfiles` is empty)               \n10|                                                                                \n11|              Builtin actions                                                   \n12|              ░ Edit new buffer                                                 \n13|              ░ Quit Neovim                                                     \n14|                                                                                \n15|              Type query to filter items                                        \n16|              <BS> deletes latest character from query                          \n17|              <Esc> resets current query                                        \n18|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n19|              <CR> executes action of current item                              \n20|              <C-c> closes this buffer                                          \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 5,15                                                    \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000222222220000000000000000000000000000000000000000000000000000000000\n05|00000000000000334444444455555555555000000000000000000000000000000000000000000000\n06|00000000000000334444444455555555550000000000000000000000000000000000000000000000\n07|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n08|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n09|00000000000000336777777777777777777777777777777777777777777777777000000000000000\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n11|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n12|00000000000000334555555555555550000000000000000000000000000000000000000000000000\n13|00000000000000334555555555500000000000000000000000000000000000000000000000000000\n14|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n17|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n18|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n19|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n20|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::55555555555555555555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---computes-`header`-depending-on-time-of-day---test-+-args-{-'00'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good evening, MINI                                                \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---computes-`header`-depending-on-time-of-day---test-+-args-{-'04'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good morning, MINI                                                \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---computes-`header`-depending-on-time-of-day---test-+-args-{-'08'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good morning, MINI                                                \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---computes-`header`-depending-on-time-of-day---test-+-args-{-'12'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---computes-`header`-depending-on-time-of-day---test-+-args-{-'16'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---computes-`header`-depending-on-time-of-day---test-+-args-{-'20'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good evening, MINI                                                \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Default-content---works",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---uses-`MiniStarterItemBullet`",
    "content": "--|---------|---------|---------|---------|\n01|A                                       \n02|░ aaab                                  \n03|░ aaba                                  \n04|                                        \n05|B                                       \n06|░ abaa                                  \n07|░ baaa                                  \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0111111111111111111111111111111111111111\n02|2233341111111111111111111111111111111111\n03|2233341111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0111111111111111111111111111111111111111\n06|2233441111111111111111111111111111111111\n07|2234441111111111111111111111111111111111\n08|5555555555555555555555555555555555555555\n09|5555555555555555555555555555555555555555\n10|5555555555555555555555555555555555555555\n11|5555555555555555555555555555555555555555\n12|5555555555555555555555555555555555555555\n13|5555555555555555555555555555555555555555\n14|6666666666666666666666666666666666666666\n15|7777777777777774444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---uses-`MiniStarterItemBullet`-002",
    "content": "--|---------|---------|---------|---------|\n01|A                                       \n02|░ aaab                                  \n03|░ aaba                                  \n04|                                        \n05|B                                       \n06|░ abaa                                  \n07|░ baaa                                  \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0111111111111111111111111111111111111111\n02|2233341111111111111111111111111111111111\n03|2233341111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0111111111111111111111111111111111111111\n06|2233441111111111111111111111111111111111\n07|2234441111111111111111111111111111111111\n08|5555555555555555555555555555555555555555\n09|5555555555555555555555555555555555555555\n10|5555555555555555555555555555555555555555\n11|5555555555555555555555555555555555555555\n12|5555555555555555555555555555555555555555\n13|5555555555555555555555555555555555555555\n14|6666666666666666666666666666666666666666\n15|7777777777777774444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---works-for-current-item",
    "content": "--|---------|---------|---------|---------|\n01|Hello                                   \n02|                                        \n03|A                                       \n04|aaab                                    \n05|aaba                                    \n06|                                        \n07|B                                       \n08|abaa                                    \n09|baaa                                    \n10|                                        \n11|World                                   \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 4,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000011111111111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|2111111111111111111111111111111111111111\n04|3334111111111111111111111111111111111111\n05|5556111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|2111111111111111111111111111111111111111\n08|5566111111111111111111111111111111111111\n09|5666111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|7777711111111111111111111111111111111111\n12|8888888888888888888888888888888888888888\n13|8888888888888888888888888888888888888888\n14|9999999999999999999999999999999999999999\n15|:::::::::::::::6666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---works-for-current-item-002",
    "content": "--|---------|---------|---------|---------|\n01|Hello                                   \n02|                                        \n03|A                                       \n04|aaab                                    \n05|aaba                                    \n06|                                        \n07|B                                       \n08|abaa                                    \n09|baaa                                    \n10|                                        \n11|World                                   \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 5,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000011111111111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|2111111111111111111111111111111111111111\n04|3334111111111111111111111111111111111111\n05|5556111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|2111111111111111111111111111111111111111\n08|3344111111111111111111111111111111111111\n09|3444111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|7777711111111111111111111111111111111111\n12|8888888888888888888888888888888888888888\n13|8888888888888888888888888888888888888888\n14|9999999999999999999999999999999999999999\n15|:::::::::::::::4444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---works-for-querying",
    "content": "--|---------|---------|---------|---------|\n01|Hello                                   \n02|                                        \n03|A                                       \n04|aaab                                    \n05|aaba                                    \n06|                                        \n07|B                                       \n08|abaa                                    \n09|baaa                                    \n10|                                        \n11|World                                   \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 4,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000011111111111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|2111111111111111111111111111111111111111\n04|3334111111111111111111111111111111111111\n05|3334111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|2111111111111111111111111111111111111111\n08|3344111111111111111111111111111111111111\n09|3444111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|5555511111111111111111111111111111111111\n12|6666666666666666666666666666666666666666\n13|6666666666666666666666666666666666666666\n14|7777777777777777777777777777777777777777\n15|8888888888888884444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---works-for-querying-002",
    "content": "--|---------|---------|---------|---------|\n01|Hello                                   \n02|                                        \n03|A                                       \n04|aaab                                    \n05|aaba                                    \n06|                                        \n07|B                                       \n08|abaa                                    \n09|baaa                                    \n10|                                        \n11|World                                   \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 4,1             \n15|(mini.starter) Query: a                 \n\n--|---------|---------|---------|---------|\n01|0000011111111111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|2111111111111111111111111111111111111111\n04|3445111111111111111111111111111111111111\n05|3445111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|2111111111111111111111111111111111111111\n08|3455111111111111111111111111111111111111\n09|6777111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|8888811111111111111111111111111111111111\n12|9999999999999999999999999999999999999999\n13|9999999999999999999999999999999999999999\n14|::::::::::::::::::::::::::::::::::::::::\n15|;;;;;;;;;;;;;;;5555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Highlighting---works-for-querying-003",
    "content": "--|---------|---------|---------|---------|\n01|Hello                                   \n02|                                        \n03|A                                       \n04|aaab                                    \n05|aaba                                    \n06|                                        \n07|B                                       \n08|abaa                                    \n09|baaa                                    \n10|                                        \n11|World                                   \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 8,1             \n15|(mini.starter) Query: ab                \n\n--|---------|---------|---------|---------|\n01|0000011111111111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|2111111111111111111111111111111111111111\n04|3334111111111111111111111111111111111111\n05|3334111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|2111111111111111111111111111111111111111\n08|5566111111111111111111111111111111111111\n09|3444111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|7777711111111111111111111111111111111111\n12|8888888888888888888888888888888888888888\n13|8888888888888888888888888888888888888888\n14|9999999999999999999999999999999999999999\n15|:::::::::::::::6666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Querying---works-with-`cmdheight=0`",
    "content": "--|---------|---------|---------|---------|---------|\n01|                                                  \n02|  Good afternoon, MINI                            \n03|                                                  \n04|  A                                               \n05|  ░ aaab                                          \n06|  ░ aaba                                          \n07|                                                  \n08|  B                                               \n09|  ░ abaa                                          \n10|  ░ baaa                                          \n11|                                                  \n12|  Type query to filter items                      \n13|  <BS> deletes latest character from query        \n14|  <Esc> resets current query                      \n15|  <Down/Up>, <C-n/p>, <M-j/k> move current item   \n16|  <CR> executes action of current item            \n17|  <C-c> closes this buffer                        \n18|~                                                 \n19|~                                                 \n20|ministarter://2/welcome 5,3                       \n\n--|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000\n02|00111111111111111111110000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000\n04|00200000000000000000000000000000000000000000000000\n05|00334456000000000000000000000000000000000000000000\n06|00334456000000000000000000000000000000000000000000\n07|00000000000000000000000000000000000000000000000000\n08|00200000000000000000000000000000000000000000000000\n09|00337788000000000000000000000000000000000000000000\n10|00337888000000000000000000000000000000000000000000\n11|00000000000000000000000000000000000000000000000000\n12|00333333333333333333333333330000000000000000000000\n13|00333333333333333333333333333333333333333300000000\n14|00333333333333333333333333330000000000000000000000\n15|00333333333333333333333333333333333333333333333000\n16|00333333333333333333333333333333333333000000000000\n17|00333333333333333333333333000000000000000000000000\n18|99999999999999999999999999999999999999999999999999\n19|99999999999999999999999999999999999999999999999999\n20|::::::::::::::::::::::::::::::::::::::::::::::::::\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---Resize---updates-Starter-buffer",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|                                        \n04|                 Header                 \n05|                                        \n06|                 A                      \n07|                 ░ aaab                 \n08|                 ░ aaba                 \n09|                                        \n10|                 B                      \n11|                 ░ abaa                 \n12|                 ░ baaa                 \n13|                                        \n14|                 Footer                 \n15|~                                       \n16|~                                       \n17|~                                       \n18|~                                       \n19|ministarter://2/welcome 7,18            \n20|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000011111100000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000020000000000000000000000\n07|0000000000000000033444500000000000000000\n08|0000000000000000033444500000000000000000\n09|0000000000000000000000000000000000000000\n10|0000000000000000020000000000000000000000\n11|0000000000000000033445500000000000000000\n12|0000000000000000033455500000000000000000\n13|0000000000000000000000000000000000000000\n14|0000000000000000033333300000000000000000\n15|6666666666666666666666666666666666666666\n16|6666666666666666666666666666666666666666\n17|6666666666666666666666666666666666666666\n18|6666666666666666666666666666666666666666\n19|7777777777777777777777777777777777777777\n20|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---adding_bullet()---respects-`bullet`-argument",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|Good afternoon, MINI                                        \n02|                                                            \n03|Recent files                                                \n04|> There are no recent files (`v:oldfiles` is empty)         \n05|                                                            \n06|Builtin actions                                             \n07|> Edit new buffer                                           \n08|> Quit Neovim                                               \n09|                                                            \n10|Type query to filter items                                  \n11|<BS> deletes latest character from query                    \n12|<Esc> resets current query                                  \n13|<Down/Up>, <C-n/p>, <M-j/k> move current item               \n14|<CR> executes action of current item                        \n15|<C-c> closes this buffer                                    \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|ministarter://2/welcome 7,1                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000001111111111111111111111111111111111111111\n02|111111111111111111111111111111111111111111111111111111111111\n03|222222222222111111111111111111111111111111111111111111111111\n04|334555555555555555555555555555555555555555555555555111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|222222222222222111111111111111111111111111111111111111111111\n07|336777777777777771111111111111111111111111111111111111111111\n08|336777777777711111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|333333333333333333333333331111111111111111111111111111111111\n11|333333333333333333333333333333333333333311111111111111111111\n12|333333333333333333333333331111111111111111111111111111111111\n13|333333333333333333333333333333333333333333333111111111111111\n14|333333333333333333333333333333333333111111111111111111111111\n15|333333333333333333333333111111111111111111111111111111111111\n16|888888888888888888888888888888888888888888888888888888888888\n17|888888888888888888888888888888888888888888888888888888888888\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---adding_bullet()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|Good afternoon, MINI                                        \n02|                                                            \n03|Recent files                                                \n04|░ There are no recent files (`v:oldfiles` is empty)         \n05|                                                            \n06|Builtin actions                                             \n07|░ Edit new buffer                                           \n08|░ Quit Neovim                                               \n09|                                                            \n10|Type query to filter items                                  \n11|<BS> deletes latest character from query                    \n12|<Esc> resets current query                                  \n13|<Down/Up>, <C-n/p>, <M-j/k> move current item               \n14|<CR> executes action of current item                        \n15|<C-c> closes this buffer                                    \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|ministarter://2/welcome 7,1                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000001111111111111111111111111111111111111111\n02|111111111111111111111111111111111111111111111111111111111111\n03|222222222222111111111111111111111111111111111111111111111111\n04|334555555555555555555555555555555555555555555555555111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|222222222222222111111111111111111111111111111111111111111111\n07|336777777777777771111111111111111111111111111111111111111111\n08|336777777777711111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|333333333333333333333333331111111111111111111111111111111111\n11|333333333333333333333333333333333333333311111111111111111111\n12|333333333333333333333333331111111111111111111111111111111111\n13|333333333333333333333333333333333333333333333111111111111111\n14|333333333333333333333333333333333333111111111111111111111111\n15|333333333333333333333333111111111111111111111111111111111111\n16|888888888888888888888888888888888888888888888888888888888888\n17|888888888888888888888888888888888888888888888888888888888888\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---handles-small-windows",
    "content": "--|---------|---------|---------|---------|\n01|AA│                                     \n02|aa│~                                    \n03|<1│~                                    \n04|  │~                                    \n05|~ │~                                    \n06|~ │~                                    \n07|~ │~                                    \n08|~ │~                                    \n09|~ │~                                    \n10|~ │~                                    \n11|~ │~                                    \n12|~ │~                                    \n13|~ │~                                    \n14|<1 [No Name] 0,0-1                      \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0012222222222222222222222222222222222222\n02|3214444444444444444444444444444444444444\n03|5514444444444444444444444444444444444444\n04|2214444444444444444444444444444444444444\n05|4414444444444444444444444444444444444444\n06|4414444444444444444444444444444444444444\n07|4414444444444444444444444444444444444444\n08|4414444444444444444444444444444444444444\n09|4414444444444444444444444444444444444444\n10|4414444444444444444444444444444444444444\n11|4414444444444444444444444444444444444444\n12|4414444444444444444444444444444444444444\n13|4414444444444444444444444444444444444444\n14|6666666666666666666666666666666666666666\n15|7777777777777772222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---has-output-respecting-`buf_id`-argument",
    "content": "--|---------|---------|---------|---------|\n01|                   │                    \n02|~                  │                    \n03|~                  │                    \n04|~                  │                    \n05|~                  │                    \n06|~                  │        AAA         \n07|[No Name] 0,0-1    │        aaa         \n08|                   │        bbb         \n09|~                  │~                   \n10|~                  │~                   \n11|~                  │~                   \n12|~                  │~                   \n13|~                  │~                   \n14|[No Name] 0,0-1     <ter://2/welcome 7,9\n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000122222222222222222222\n02|3333333333333333333122222222222222222222\n03|3333333333333333333122222222222222222222\n04|3333333333333333333122222222222222222222\n05|3333333333333333333122222222222222222222\n06|3333333333333333333122222222444222222222\n07|5555555555555555555122222222600222222222\n08|0000000000000000000122222222600222222222\n09|3333333333333333333177777777777777777777\n10|3333333333333333333177777777777777777777\n11|3333333333333333333177777777777777777777\n12|3333333333333333333177777777777777777777\n13|3333333333333333333177777777777777777777\n14|5555555555555555555588888888888888888888\n15|9999999999999990000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---has-output-respecting-`buf_id`-argument-002",
    "content": "--|---------|---------|---------|---------|\n01|     │                                  \n02|~    │                                  \n03|~    │                                  \n04|~    │                                  \n05|~    │                                  \n06|~    │               AAA                \n07|<,0-1│               aaa                \n08|     │               bbb                \n09|~    │~                                 \n10|~    │~                                 \n11|~    │~                                 \n12|~    │~                                 \n13|~    │~                                 \n14|<,0-1 ministarter://2/welcome 7,16      \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000012222222222222222222222222222222222\n02|3333312222222222222222222222222222222222\n03|3333312222222222222222222222222222222222\n04|3333312222222222222222222222222222222222\n05|3333312222222222222222222222222222222222\n06|3333312222222222222224442222222222222222\n07|5555512222222222222226222222222222222222\n08|2222212222222222222226222222222222222222\n09|7777717777777777777777777777777777777777\n10|7777717777777777777777777777777777777777\n11|7777717777777777777777777777777777777777\n12|7777717777777777777777777777777777777777\n13|7777717777777777777777777777777777777777\n14|8888888888888888888888888888888888888888\n15|9999999999999992222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''center',-'bottom''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|                                        \n04|                                        \n05|                                        \n06|                  AAA                   \n07|                  aaa                   \n08|                  bbb                   \n09|ministarter://2/welcome 7,19            \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000001110000000000000000000\n07|0000000000000000002330000000000000000000\n08|0000000000000000002330000000000000000000\n09|4444444444444444444444444444444444444444\n10|5555555555555553333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''center',-'center''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|                  AAA                   \n04|                  aaa                   \n05|                  bbb                   \n06|~                                       \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 4,19            \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000001110000000000000000000\n04|0000000000000000002330000000000000000000\n05|0000000000000000002330000000000000000000\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|5555555555555555555555555555555555555555\n10|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''center',-'top''-}",
    "content": "--|---------|---------|---------|---------|\n01|                  AAA                   \n02|                  aaa                   \n03|                  bbb                   \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 2,19            \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000001110000000000000000000\n02|0000000000000000002330000000000000000000\n03|0000000000000000002330000000000000000000\n04|4444444444444444444444444444444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|5555555555555555555555555555555555555555\n10|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''left',-'bottom''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|                                        \n04|                                        \n05|                                        \n06|AAA                                     \n07|aaa                                     \n08|bbb                                     \n09|ministarter://2/welcome 7,1             \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|1110000000000000000000000000000000000000\n07|2330000000000000000000000000000000000000\n08|2330000000000000000000000000000000000000\n09|4444444444444444444444444444444444444444\n10|5555555555555553333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''left',-'center''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|AAA                                     \n04|aaa                                     \n05|bbb                                     \n06|~                                       \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 4,1             \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|1110000000000000000000000000000000000000\n04|2330000000000000000000000000000000000000\n05|2330000000000000000000000000000000000000\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|5555555555555555555555555555555555555555\n10|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''left',-'top''-}",
    "content": "--|---------|---------|---------|---------|\n01|AAA                                     \n02|aaa                                     \n03|bbb                                     \n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 2,1             \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0001111111111111111111111111111111111111\n02|2331111111111111111111111111111111111111\n03|2331111111111111111111111111111111111111\n04|4444444444444444444444444444444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|5555555555555555555555555555555555555555\n10|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''right',-'bottom''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|                                        \n04|                                        \n05|                                        \n06|                                     AAA\n07|                                     aaa\n08|                                     bbb\n09|ministarter://2/welcome 7,38            \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000111\n07|0000000000000000000000000000000000000233\n08|0000000000000000000000000000000000000233\n09|4444444444444444444444444444444444444444\n10|5555555555555553333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''right',-'center''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                        \n02|                                        \n03|                                     AAA\n04|                                     aaa\n05|                                     bbb\n06|~                                       \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 4,38            \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000111\n04|0000000000000000000000000000000000000233\n05|0000000000000000000000000000000000000233\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|5555555555555555555555555555555555555555\n10|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---respects-arguments---test-+-args-{-''right',-'top''-}",
    "content": "--|---------|---------|---------|---------|\n01|                                     AAA\n02|                                     aaa\n03|                                     bbb\n04|~                                       \n05|~                                       \n06|~                                       \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 2,38            \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000111\n02|0000000000000000000000000000000000000233\n03|0000000000000000000000000000000000000233\n04|4444444444444444444444444444444444444444\n05|4444444444444444444444444444444444444444\n06|4444444444444444444444444444444444444444\n07|4444444444444444444444444444444444444444\n08|4444444444444444444444444444444444444444\n09|5555555555555555555555555555555555555555\n10|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---aligning()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|Good afternoon, MINI                                        \n02|                                                            \n03|Recent files                                                \n04|There are no recent files (`v:oldfiles` is empty)           \n05|                                                            \n06|Builtin actions                                             \n07|Edit new buffer                                             \n08|Quit Neovim                                                 \n09|                                                            \n10|Type query to filter items                                  \n11|<BS> deletes latest character from query                    \n12|<Esc> resets current query                                  \n13|<Down/Up>, <C-n/p>, <M-j/k> move current item               \n14|<CR> executes action of current item                        \n15|<C-c> closes this buffer                                    \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|ministarter://2/welcome 7,1                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000001111111111111111111111111111111111111111\n02|111111111111111111111111111111111111111111111111111111111111\n03|222222222222111111111111111111111111111111111111111111111111\n04|344444444444444444444444444444444444444444444444411111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|222222222222222111111111111111111111111111111111111111111111\n07|566666666666666111111111111111111111111111111111111111111111\n08|566666666661111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|777777777777777777777777771111111111111111111111111111111111\n11|777777777777777777777777777777777777777711111111111111111111\n12|777777777777777777777777771111111111111111111111111111111111\n13|777777777777777777777777777777777777777777777111111111111111\n14|777777777777777777777777777777777777111111111111111111111111\n15|777777777777777777777777111111111111111111111111111111111111\n16|888888888888888888888888888888888888888888888888888888888888\n17|888888888888888888888888888888888888888888888888888888888888\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---indexing()---respects-arguments---test-+-args-{-''all',-nil'-}",
    "content": "--|---------|---------|---------|---------|\n01|AAA                                     \n02|1. a                                    \n03|2. aa                                   \n04|                                        \n05|BBB                                     \n06|3. b                                    \n07|4. bb                                   \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0001111111111111111111111111111111111111\n02|2333111111111111111111111111111111111111\n03|2333311111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0001111111111111111111111111111111111111\n06|2333111111111111111111111111111111111111\n07|2333311111111111111111111111111111111111\n08|4444444444444444444444444444444444444444\n09|4444444444444444444444444444444444444444\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---indexing()---respects-arguments---test-+-args-{-''section',-nil'-}",
    "content": "--|---------|---------|---------|---------|\n01|AAA                                     \n02|a1. a                                   \n03|a2. aa                                  \n04|                                        \n05|BBB                                     \n06|b1. b                                   \n07|b2. bb                                  \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0001111111111111111111111111111111111111\n02|2233311111111111111111111111111111111111\n03|2233331111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0001111111111111111111111111111111111111\n06|2233311111111111111111111111111111111111\n07|2233331111111111111111111111111111111111\n08|4444444444444444444444444444444444444444\n09|4444444444444444444444444444444444444444\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---indexing()---respects-arguments---test-+-args-{-'nil,-{-'AAA'-}'-}",
    "content": "--|---------|---------|---------|---------|\n01|AAA                                     \n02|a                                       \n03|aa                                      \n04|                                        \n05|BBB                                     \n06|1. b                                    \n07|2. bb                                   \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0001111111111111111111111111111111111111\n02|2111111111111111111111111111111111111111\n03|2211111111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0001111111111111111111111111111111111111\n06|2333111111111111111111111111111111111111\n07|2333311111111111111111111111111111111111\n08|4444444444444444444444444444444444444444\n09|4444444444444444444444444444444444444444\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---indexing()---respects-arguments---test-+-args-{-'nil,-{}'-}",
    "content": "--|---------|---------|---------|---------|\n01|AAA                                     \n02|1. a                                    \n03|2. aa                                   \n04|                                        \n05|BBB                                     \n06|3. b                                    \n07|4. bb                                   \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0001111111111111111111111111111111111111\n02|2333111111111111111111111111111111111111\n03|2333311111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0001111111111111111111111111111111111111\n06|2333111111111111111111111111111111111111\n07|2333311111111111111111111111111111111111\n08|4444444444444444444444444444444444444444\n09|4444444444444444444444444444444444444444\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---indexing()---works",
    "content": "--|---------|---------|---------|---------|\n01|AAA                                     \n02|1. a                                    \n03|2. aa                                   \n04|                                        \n05|BBB                                     \n06|3. b                                    \n07|4. bb                                   \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|~                                       \n13|~                                       \n14|ministarter://2/welcome 2,1             \n15|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0001111111111111111111111111111111111111\n02|2333111111111111111111111111111111111111\n03|2333311111111111111111111111111111111111\n04|1111111111111111111111111111111111111111\n05|0001111111111111111111111111111111111111\n06|2333111111111111111111111111111111111111\n07|2333311111111111111111111111111111111111\n08|4444444444444444444444444444444444444444\n09|4444444444444444444444444444444444444444\n10|4444444444444444444444444444444444444444\n11|4444444444444444444444444444444444444444\n12|4444444444444444444444444444444444444444\n13|4444444444444444444444444444444444444444\n14|5555555555555555555555555555555555555555\n15|6666666666666663333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---padding()---respects-arguments---test-+-args-{-'0,-2'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|                                                            \n03|Good afternoon, MINI                                        \n04|                                                            \n05|Recent files                                                \n06|There are no recent files (`v:oldfiles` is empty)           \n07|                                                            \n08|Builtin actions                                             \n09|Edit new buffer                                             \n10|Quit Neovim                                                 \n11|                                                            \n12|Type query to filter items                                  \n13|<BS> deletes latest character from query                    \n14|<Esc> resets current query                                  \n15|<Down/Up>, <C-n/p>, <M-j/k> move current item               \n16|<CR> executes action of current item                        \n17|<C-c> closes this buffer                                    \n18|~                                                           \n19|ministarter://2/welcome 9,1                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|000000000000000000000000000000000000000000000000000000000000\n03|111111111111111111110000000000000000000000000000000000000000\n04|000000000000000000000000000000000000000000000000000000000000\n05|222222222222000000000000000000000000000000000000000000000000\n06|344444444444444444444444444444444444444444444444400000000000\n07|000000000000000000000000000000000000000000000000000000000000\n08|222222222222222000000000000000000000000000000000000000000000\n09|566666666666666000000000000000000000000000000000000000000000\n10|566666666660000000000000000000000000000000000000000000000000\n11|000000000000000000000000000000000000000000000000000000000000\n12|777777777777777777777777770000000000000000000000000000000000\n13|777777777777777777777777777777777777777700000000000000000000\n14|777777777777777777777777770000000000000000000000000000000000\n15|777777777777777777777777777777777777777777777000000000000000\n16|777777777777777777777777777777777777000000000000000000000000\n17|777777777777777777777777000000000000000000000000000000000000\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---padding()---respects-arguments---test-+-args-{-'2,-0'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|  Good afternoon, MINI                                      \n02|                                                            \n03|  Recent files                                              \n04|  There are no recent files (`v:oldfiles` is empty)         \n05|                                                            \n06|  Builtin actions                                           \n07|  Edit new buffer                                           \n08|  Quit Neovim                                               \n09|                                                            \n10|  Type query to filter items                                \n11|  <BS> deletes latest character from query                  \n12|  <Esc> resets current query                                \n13|  <Down/Up>, <C-n/p>, <M-j/k> move current item             \n14|  <CR> executes action of current item                      \n15|  <C-c> closes this buffer                                  \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|ministarter://2/welcome 7,3                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|001111111111111111111100000000000000000000000000000000000000\n02|000000000000000000000000000000000000000000000000000000000000\n03|002222222222220000000000000000000000000000000000000000000000\n04|003444444444444444444444444444444444444444444444444000000000\n05|000000000000000000000000000000000000000000000000000000000000\n06|002222222222222220000000000000000000000000000000000000000000\n07|005666666666666660000000000000000000000000000000000000000000\n08|005666666666600000000000000000000000000000000000000000000000\n09|000000000000000000000000000000000000000000000000000000000000\n10|007777777777777777777777777700000000000000000000000000000000\n11|007777777777777777777777777777777777777777000000000000000000\n12|007777777777777777777777777700000000000000000000000000000000\n13|007777777777777777777777777777777777777777777770000000000000\n14|007777777777777777777777777777777777770000000000000000000000\n15|007777777777777777777777770000000000000000000000000000000000\n16|888888888888888888888888888888888888888888888888888888888888\n17|888888888888888888888888888888888888888888888888888888888888\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---padding()---respects-arguments---test-+-args-{-'2,-2'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|                                                            \n03|  Good afternoon, MINI                                      \n04|                                                            \n05|  Recent files                                              \n06|  There are no recent files (`v:oldfiles` is empty)         \n07|                                                            \n08|  Builtin actions                                           \n09|  Edit new buffer                                           \n10|  Quit Neovim                                               \n11|                                                            \n12|  Type query to filter items                                \n13|  <BS> deletes latest character from query                  \n14|  <Esc> resets current query                                \n15|  <Down/Up>, <C-n/p>, <M-j/k> move current item             \n16|  <CR> executes action of current item                      \n17|  <C-c> closes this buffer                                  \n18|~                                                           \n19|ministarter://2/welcome 9,3                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|000000000000000000000000000000000000000000000000000000000000\n03|001111111111111111111100000000000000000000000000000000000000\n04|000000000000000000000000000000000000000000000000000000000000\n05|002222222222220000000000000000000000000000000000000000000000\n06|003444444444444444444444444444444444444444444444444000000000\n07|000000000000000000000000000000000000000000000000000000000000\n08|002222222222222220000000000000000000000000000000000000000000\n09|005666666666666660000000000000000000000000000000000000000000\n10|005666666666600000000000000000000000000000000000000000000000\n11|000000000000000000000000000000000000000000000000000000000000\n12|007777777777777777777777777700000000000000000000000000000000\n13|007777777777777777777777777777777777777777000000000000000000\n14|007777777777777777777777777700000000000000000000000000000000\n15|007777777777777777777777777777777777777777777770000000000000\n16|007777777777777777777777777777777777770000000000000000000000\n17|007777777777777777777777770000000000000000000000000000000000\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---gen_hook---padding()---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|Good afternoon, MINI                                        \n02|                                                            \n03|Recent files                                                \n04|There are no recent files (`v:oldfiles` is empty)           \n05|                                                            \n06|Builtin actions                                             \n07|Edit new buffer                                             \n08|Quit Neovim                                                 \n09|                                                            \n10|Type query to filter items                                  \n11|<BS> deletes latest character from query                    \n12|<Esc> resets current query                                  \n13|<Down/Up>, <C-n/p>, <M-j/k> move current item               \n14|<CR> executes action of current item                        \n15|<C-c> closes this buffer                                    \n16|~                                                           \n17|~                                                           \n18|~                                                           \n19|ministarter://2/welcome 7,1                                 \n20|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000001111111111111111111111111111111111111111\n02|111111111111111111111111111111111111111111111111111111111111\n03|222222222222111111111111111111111111111111111111111111111111\n04|344444444444444444444444444444444444444444444444411111111111\n05|111111111111111111111111111111111111111111111111111111111111\n06|222222222222222111111111111111111111111111111111111111111111\n07|566666666666666111111111111111111111111111111111111111111111\n08|566666666661111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111\n10|777777777777777777777777771111111111111111111111111111111111\n11|777777777777777777777777777777777777777711111111111111111111\n12|777777777777777777777777771111111111111111111111111111111111\n13|777777777777777777777777777777777777777777777111111111111111\n14|777777777777777777777777777777777777111111111111111111111111\n15|777777777777777777777777111111111111111111111111111111111111\n16|888888888888888888888888888888888888888888888888888888888888\n17|888888888888888888888888888888888888888888888888888888888888\n18|888888888888888888888888888888888888888888888888888888888888\n19|999999999999999999999999999999999999999999999999999999999999\n20|:::::::::::::::666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---get_content()---works",
    "content": "--|---------|---------|---------|---------|\n01|Hello                                   \n02|                                        \n03|Section a                               \n04|a                                       \n05|                                        \n06|World                                   \n07|~                                       \n08|~                                       \n09|ministarter://2/welcome 4,1             \n10|(mini.starter) Query:                   \n\n--|---------|---------|---------|---------|\n01|0000011111111111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|2222222221111111111111111111111111111111\n04|3111111111111111111111111111111111111111\n05|1111111111111111111111111111111111111111\n06|4444411111111111111111111111111111111111\n07|5555555555555555555555555555555555555555\n08|5555555555555555555555555555555555555555\n09|6666666666666666666666666666666666666666\n10|7777777777777778888888888888888888888888\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---open()---respects-`vim.b.ministarter_config`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|Hello                                                                           \n02|                                                                                \n03|Recent files                                                                    \n04|There are no recent files (`v:oldfiles` is empty)                               \n05|                                                                                \n06|Builtin actions                                                                 \n07|Edit new buffer                                                                 \n08|Quit Neovim                                                                     \n09|                                                                                \n10|World                                                                           \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|~                                                                               \n16|~                                                                               \n17|~                                                                               \n18|~                                                                               \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 7,1                                                     \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000111111111111111111111111111111111111111111111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|22222222222211111111111111111111111111111111111111111111111111111111111111111111\n04|34444444444444444444444444444444444444444444444441111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|22222222222222211111111111111111111111111111111111111111111111111111111111111111\n07|56666666666666611111111111111111111111111111111111111111111111111111111111111111\n08|56666666666111111111111111111111111111111111111111111111111111111111111111111111\n09|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|77777111111111111111111111111111111111111111111111111111111111111111111111111111\n11|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n12|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n13|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n14|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n15|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n16|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n17|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n18|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::66666666666666666666666666666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---refresh()---respects-`config.silent`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---refresh()---respects-`config.silent`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|                                                                                \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---refresh()---respects-`vim.b.ministarter_config`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|              Good afternoon, MINI                                              \n05|                                                                                \n06|              Recent files                                                      \n07|              ░ There are no recent files (`v:oldfiles` is empty)               \n08|                                                                                \n09|              Builtin actions                                                   \n10|              ░ Edit new buffer                                                 \n11|              ░ Quit Neovim                                                     \n12|                                                                                \n13|              Type query to filter items                                        \n14|              <BS> deletes latest character from query                          \n15|              <Esc> resets current query                                        \n16|              <Down/Up>, <C-n/p>, <M-j/k> move current item                     \n17|              <CR> executes action of current item                              \n18|              <C-c> closes this buffer                                          \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 10,15                                                   \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000111111111111111111110000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000222222222222000000000000000000000000000000000000000000000000000000\n07|00000000000000334555555555555555555555555555555555555555555555555000000000000000\n08|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n09|00000000000000222222222222222000000000000000000000000000000000000000000000000000\n10|00000000000000336777777777777770000000000000000000000000000000000000000000000000\n11|00000000000000336777777777700000000000000000000000000000000000000000000000000000\n12|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n13|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n14|00000000000000333333333333333333333333333333333333333300000000000000000000000000\n15|00000000000000333333333333333333333333330000000000000000000000000000000000000000\n16|00000000000000333333333333333333333333333333333333333333333000000000000000000000\n17|00000000000000333333333333333333333333333333333333000000000000000000000000000000\n18|00000000000000333333333333333333333333000000000000000000000000000000000000000000\n19|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n20|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n21|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n22|88888888888888888888888888888888888888888888888888888888888888888888888888888888\n23|99999999999999999999999999999999999999999999999999999999999999999999999999999999\n24|:::::::::::::::77777777777777777777777777777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---refresh()---respects-`vim.b.ministarter_config`-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|Hello                                                                           \n02|                                                                                \n03|AAA                                                                             \n04|aaa                                                                             \n05|                                                                                \n06|World                                                                           \n07|~                                                                               \n08|~                                                                               \n09|~                                                                               \n10|~                                                                               \n11|~                                                                               \n12|~                                                                               \n13|~                                                                               \n14|~                                                                               \n15|~                                                                               \n16|~                                                                               \n17|~                                                                               \n18|~                                                                               \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 4,1                                                     \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000111111111111111111111111111111111111111111111111111111111111111111111111111\n02|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|22211111111111111111111111111111111111111111111111111111111111111111111111111111\n04|34411111111111111111111111111111111111111111111111111111111111111111111111111111\n05|11111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|55555111111111111111111111111111111111111111111111111111111111111111111111111111\n07|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n08|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n09|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n10|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n11|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n12|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n13|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n14|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n15|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n16|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n17|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n18|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n19|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n20|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n21|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n22|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n23|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n24|88888888888888844444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---sections---recent_files()---correctly-identifies-files-from-current-directory",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|                                                                                \n05|                                                                                \n06|                Good afternoon, MINI                                            \n07|                                                                                \n08|                Recent files (current directory)                                \n09|                ░ There are no recent files in current directory                \n10|                                                                                \n11|                Type query to filter items                                      \n12|                <BS> deletes latest character from query                        \n13|                <Esc> resets current query                                      \n14|                <Down/Up>, <C-n/p>, <M-j/k> move current item                   \n15|                <CR> executes action of current item                            \n16|                <C-c> closes this buffer                                        \n17|~                                                                               \n18|~                                                                               \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 9,17                                                    \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000001111111111111111111100000000000000000000000000000000000000000000\n07|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n08|00000000000000002222222222222222222222222222222200000000000000000000000000000000\n09|00000000000000003345555555555555555555555555555555555555555555550000000000000000\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n11|00000000000000003333333333333333333333333300000000000000000000000000000000000000\n12|00000000000000003333333333333333333333333333333333333333000000000000000000000000\n13|00000000000000003333333333333333333333333300000000000000000000000000000000000000\n14|00000000000000003333333333333333333333333333333333333333333330000000000000000000\n15|00000000000000003333333333333333333333333333333333330000000000000000000000000000\n16|00000000000000003333333333333333333333330000000000000000000000000000000000000000\n17|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n18|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n19|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n20|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n21|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n22|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n23|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n24|88888888888888899999999999999999999999999999999999999999999999999999999999999999\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---sections---recent_files()---respects-`show_path`",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|                                                                                \n05|                                                                                \n06|                 Good afternoon, MINI                                           \n07|                                                                                \n08|                 Recent files                                                   \n09|                 ░ file1__hello__                                               \n10|                                                                                \n11|                 Type query to filter items                                     \n12|                 <BS> deletes latest character from query                       \n13|                 <Esc> resets current query                                     \n14|                 <Down/Up>, <C-n/p>, <M-j/k> move current item                  \n15|                 <CR> executes action of current item                           \n16|                 <C-c> closes this buffer                                       \n17|~                                                                               \n18|~                                                                               \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 9,18                                                    \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000000111111111111111111110000000000000000000000000000000000000000000\n07|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n08|00000000000000000222222222222000000000000000000000000000000000000000000000000000\n09|00000000000000000334555555555555500000000000000000000000000000000000000000000000\n10|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n11|00000000000000000333333333333333333333333330000000000000000000000000000000000000\n12|00000000000000000333333333333333333333333333333333333333300000000000000000000000\n13|00000000000000000333333333333333333333333330000000000000000000000000000000000000\n14|00000000000000000333333333333333333333333333333333333333333333000000000000000000\n15|00000000000000000333333333333333333333333333333333333000000000000000000000000000\n16|00000000000000000333333333333333333333333000000000000000000000000000000000000000\n17|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n18|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n19|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n20|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n21|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n22|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n23|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n24|88888888888888855555555555555555555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---sections---recent_files()---respects-files-in-subdirectories",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                \n02|                                                                                \n03|                                                                                \n04|                                                                                \n05|                                                                                \n06|                 Good afternoon, MINI                                           \n07|                                                                                \n08|                 Recent files (current directory)                               \n09|                 ░ file1 (file1)                                                \n10|                 ░ file2 (subdir/file2)                                         \n11|                                                                                \n12|                 Type query to filter items                                     \n13|                 <BS> deletes latest character from query                       \n14|                 <Esc> resets current query                                     \n15|                 <Down/Up>, <C-n/p>, <M-j/k> move current item                  \n16|                 <CR> executes action of current item                           \n17|                 <C-c> closes this buffer                                       \n18|~                                                                               \n19|~                                                                               \n20|~                                                                               \n21|~                                                                               \n22|~                                                                               \n23|ministarter://2/welcome 9,18                                                    \n24|(mini.starter) Query:                                                           \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|\n01|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n03|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n04|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n05|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n06|00000000000000000111111111111111111110000000000000000000000000000000000000000000\n07|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n08|00000000000000000222222222222222222222222222222220000000000000000000000000000000\n09|00000000000000000334444455555555000000000000000000000000000000000000000000000000\n10|00000000000000000334444455555555555555500000000000000000000000000000000000000000\n11|00000000000000000000000000000000000000000000000000000000000000000000000000000000\n12|00000000000000000333333333333333333333333330000000000000000000000000000000000000\n13|00000000000000000333333333333333333333333333333333333333300000000000000000000000\n14|00000000000000000333333333333333333333333330000000000000000000000000000000000000\n15|00000000000000000333333333333333333333333333333333333333333333000000000000000000\n16|00000000000000000333333333333333333333333333333333333000000000000000000000000000\n17|00000000000000000333333333333333333333333000000000000000000000000000000000000000\n18|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n19|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n20|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n21|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n22|66666666666666666666666666666666666666666666666666666666666666666666666666666666\n23|77777777777777777777777777777777777777777777777777777777777777777777777777777777\n24|88888888888888855555555555555555555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_starter.lua---sections---works",
    "content": "--|---------|---------|---------|---------|---------|---------|\n01|                                                            \n02|    Builtin actions                                         \n03|    ░ Edit new buffer                                       \n04|    ░ Quit Neovim                                           \n05|                                                            \n06|    Recent files                                            \n07|    ░ There are no recent files (`v:oldfiles` is empty)     \n08|                                                            \n09|    Sessions                                                \n10|    ░ 'mini.sessions' is not set up                         \n11|                                                            \n12|    Pick                                                    \n13|    ░ Command history                                       \n14|    ░ Explorer                                              \n15|    ░ Files                                                 \n16|    ░ Grep live                                             \n17|    ░ Help tags                                             \n18|    ░ Visited paths                                         \n19|                                                            \n20|    Telescope                                               \n21|    ░ Browser                                               \n22|    ░ Command history                                       \n23|    ░ Files                                                 \n24|    ░ Help tags                                             \n25|    ░ Live grep                                             \n26|    ░ Old files                                             \n27|~                                                           \n28|~                                                           \n29|ministarter://2/welcome 3,5                                 \n30|(mini.starter) Query:                                       \n\n--|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000\n02|000011111111111111100000000000000000000000000000000000000000\n03|000022334444444444444000000000000000000000000000000000000000\n04|000022344444444440000000000000000000000000000000000000000000\n05|000000000000000000000000000000000000000000000000000000000000\n06|000011111111111100000000000000000000000000000000000000000000\n07|000022566666666666666666666666666666666666666666666666600000\n08|000000000000000000000000000000000000000000000000000000000000\n09|000011111111000000000000000000000000000000000000000000000000\n10|000022566666666666666666666666666660000000000000000000000000\n11|000000000000000000000000000000000000000000000000000000000000\n12|000011110000000000000000000000000000000000000000000000000000\n13|000022333333333333333000000000000000000000000000000000000000\n14|000022334444440000000000000000000000000000000000000000000000\n15|000022333330000000000000000000000000000000000000000000000000\n16|000022344444444000000000000000000000000000000000000000000000\n17|000022333333333000000000000000000000000000000000000000000000\n18|000022344444444444400000000000000000000000000000000000000000\n19|000000000000000000000000000000000000000000000000000000000000\n20|000011111111100000000000000000000000000000000000000000000000\n21|000022344444400000000000000000000000000000000000000000000000\n22|000022333333333333333000000000000000000000000000000000000000\n23|000022333330000000000000000000000000000000000000000000000000\n24|000022333333333000000000000000000000000000000000000000000000\n25|000022344444444000000000000000000000000000000000000000000000\n26|000022344444444000000000000000000000000000000000000000000000\n27|777777777777777777777777777777777777777777777777777777777777\n28|777777777777777777777777777777777777777777777777777777777777\n29|888888888888888888888888888888888888888888888888888888888888\n30|999999999999999444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_statusline.lua---Default-content---active---test-+-args-{-120-}",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|aaaaaaaaa                                                                                                               │                                       \n2|~                                                                                                                       │~                                      \n3|~                                                                                                                       │~                                      \n4| Normal   main|bisect (MM)  #4 +3 ~2 -1  E4 W3 I2 H1 󰰎 + <tatusline/mocked.lua  󰢱 lua utf-8[unix] 10B  2/9 1|1│ 2|9   [No Name]                              \n5|/a                                                                                                                                            [2/9]             \n\n-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|0100000002222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223444444444444444444444444444444444444444\n2|5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555553666666666666666666666666666666666666666\n3|5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555553666666666666666666666666666666666666666\n4|7777777788888888888888888888888888888888888888888888888888889999999999999999999999888888888888888888888887777777777777779:::::::::::::::::::::::::::::::::::::::\n5|4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_statusline.lua---Default-content---active---test-+-args-{-39-}",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|aaaaaaaaa                              │                                                                                                                        \n2|~                                      │~                                                                                                                       \n3|~                                      │~                                                                                                                       \n4| N <statusline/mocked.lua  󰢱 lua  1│ 2  [No Name]                                                                                                               \n5|/a                                                                                                                                            [2/9]             \n\n-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|0100000002222222222222222222222222222223444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n2|5555555555555555555555555555555555555553666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666\n3|5555555555555555555555555555555555555553666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666\n4|7778888888888888888888888899999997777778::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n5|4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_statusline.lua---Default-content---active---test-+-args-{-40-}",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|aaaaaaaaa                               │                                                                                                                       \n2|~                                       │~                                                                                                                      \n3|~                                       │~                                                                                                                      \n4| N   main|bisect (MM) <ua  󰢱 lua  1│ 2  [No Name]                                                                                                              \n5|/a                                                                                                                                            [2/9]             \n\n-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|0100000002222222222222222222222222222222344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n2|5555555555555555555555555555555555555555366666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666\n3|5555555555555555555555555555555555555555366666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666\n4|77788888888888888888888999988888887777779:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n5|4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_statusline.lua---Default-content---active---test-+-args-{-75-}",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|aaaaaaaaa                                                                  │                                                                                    \n2|~                                                                          │~                                                                                   \n3|~                                                                          │~                                                                                   \n4| N   main|bisect (MM)  #4 +3 ~2 -1  E4 W3 I2 H1 󰰎 + <lua  2/9 1|1│ 2|9   [No Name]                                                                           \n5|/a                                                                                                                                            [2/9]             \n\n-|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n1|0100000002222222222222222222222222222222222222222222222222222222222222222223444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n2|5555555555555555555555555555555555555555555555555555555555555555555555555553666666666666666666666666666666666666666666666666666666666666666666666666666666666666\n3|5555555555555555555555555555555555555555555555555555555555555555555555555553666666666666666666666666666666666666666666666666666666666666666666666666666666666666\n4|7778888888888888888888888888888888888888888888888888888888887777777777777779::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n5|4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_statusline.lua---Default-content---inactive-is-evaluated-in-the-context-of-its-window",
    "content": "--|---------|---------|---------|\n01|                    │         \n02|~                   │~        \n03|~                   │~        \n04|~                   │~        \n05|~                   │~        \n06|~                   │~        \n07|~                   │~        \n08|~                   │~        \n09|1001                 1000     \n10|                              \n\n--|---------|---------|---------|\n01|000000000000000000001222222222\n02|333333333333333333331444444444\n03|333333333333333333331444444444\n04|333333333333333333331444444444\n05|333333333333333333331444444444\n06|333333333333333333331444444444\n07|333333333333333333331444444444\n08|333333333333333333331444444444\n09|555555555555555555555666666666\n10|222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Add-surrounding---respects-`config.silent`",
    "content": "--|---------|---------|\n01| aaa                \n02|[No Name] 1,2       \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|         g@iw       \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Add-surrounding---shows-reminder-after-one-idle-second",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1| (aaa)                                                                \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,3                                                         \n5|(mini.surround) Reminder to press output surrounding id               \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Add-surrounding---shows-reminder-after-one-idle-second-002",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1| ((aaa))                                                              \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,4                                                         \n5|                                                                      \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Add-surrounding---works-with-`cmdheight=0`",
    "content": "-|---------|---------|\n1|aa bb               \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Add-surrounding---works-with-`cmdheight=0`-002",
    "content": "-|---------|---------|\n1|aa bb               \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Add-surrounding---works-with-`cmdheight=0`-003",
    "content": "-|---------|---------|\n1|(aa) bb             \n2|~                   \n3|~                   \n4|~                   \n5|~                   \n6|~                   \n7|My statusline       \n\n-|---------|---------|\n1|00000000000000000000\n2|11111111111111111111\n3|11111111111111111111\n4|11111111111111111111\n5|11111111111111111111\n6|11111111111111111111\n7|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---Function-call---colors-its-prompts",
    "content": "-|---------|---------|---------|---------|\n1|(aaa)                                   \n2|[No Name] 1,3                           \n3|(mini.surround) Function name: hello    \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222222222222222333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---Function-call---colors-its-prompts-002",
    "content": "-|---------|---------|---------|---------|\n1|hello(aaa)                              \n2|[No Name] 1,7                           \n3|                                        \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222222222222222222222222\n4|2222222222222222222222222222222222222222\n5|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---Tag---colors-its-prompts",
    "content": "-|---------|---------|---------|---------|\n1|(aaa)                                   \n2|[No Name] 1,3                           \n3|(mini.surround) Tag: hello              \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222223333333333333333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---Tag---colors-its-prompts-002",
    "content": "-|---------|---------|---------|---------|\n1|<hello>aaa</hello>                      \n2|[No Name] 1,8                           \n3|                                        \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222222222222222222222222\n4|2222222222222222222222222222222222222222\n5|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---User-prompt---colors-its-prompts",
    "content": "-|---------|---------|---------|---------|\n1|(aaa)                                   \n2|[No Name] 1,3                           \n3|(mini.surround) Left surrounding: xxx   \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222222222222222222333333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---User-prompt---colors-its-prompts-002",
    "content": "-|---------|---------|---------|---------|\n1|(aaa)                                   \n2|[No Name] 1,3                           \n3|(mini.surround) Right surrounding: yyy  \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222222222222222222233333\n4|3333333333333333333333333333333333333333\n5|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Builtin---User-prompt---colors-its-prompts-003",
    "content": "-|---------|---------|---------|---------|\n1|xxxaaayyy                               \n2|[No Name] 1,4                           \n3|                                        \n4|                                        \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111\n3|2222222222222222222222222222222222222222\n4|2222222222222222222222222222222222222222\n5|2222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Delete-surrounding---respects-`config.silent`",
    "content": "--|---------|---------|\n01|<aaa>               \n02|[No Name] 1,2       \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|         g@<20>     \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Delete-surrounding---respects-`config.silent`-002",
    "content": "--|---------|---------|\n01|<aaa>               \n02|[No Name] 1,2       \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Delete-surrounding---shows-reminder-after-one-idle-second",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,2                                                         \n5|(mini.surround) Reminder to press input surrounding id                \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Delete-surrounding---shows-reminder-after-one-idle-second-002",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|aaa                                                                   \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,1                                                         \n5|                                                                      \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Find-surrounding---shows-reminder-after-one-idle-second",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,5                                                         \n5|(mini.surround) Reminder to press input surrounding id                \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0111011111111111111111111111111111111111111111111111111111111111111111\n2|2222222222222222222222222222222222222222222222222222222222222222222222\n3|2222222222222222222222222222222222222222222222222222222222222222222222\n4|3333333333333333333333333333333333333333333333333333333333333333333333\n5|4444444444444444555555555555555555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Find-surrounding---shows-reminder-after-one-idle-second-002",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(aaa)                                                                 \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,1                                                         \n5|                                                                      \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0111011111111111111111111111111111111111111111111111111111111111111111\n2|2222222222222222222222222222222222222222222222222222222222222222222222\n3|2222222222222222222222222222222222222222222222222222222222222222222222\n4|3333333333333333333333333333333333333333333333333333333333333333333333\n5|4444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---removes-highlighting-in-correct-buffer",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|(bbb)                         │(aaa)                        \n2|~                             │~                            \n3|~                             │~                            \n4|current 1,3                    [No Name] 1,3                \n5|                                                            \n\n-|---------|---------|---------|---------|---------|---------|\n1|011101111111111111111111111111203330333333333333333333333333\n2|444444444444444444444444444444255555555555555555555555555555\n3|444444444444444444444444444444255555555555555555555555555555\n4|666666666666666666666666666666677777777777777777777777777777\n5|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---removes-highlighting-in-correct-buffer-002",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|(bbb)                         │(aaa)                        \n2|~                             │~                            \n3|~                             │~                            \n4|current 1,3                    [No Name] 1,3                \n5|                                                            \n\n-|---------|---------|---------|---------|---------|---------|\n1|011101111111111111111111111111233333333333333333333333333333\n2|444444444444444444444444444444255555555555555555555555555555\n3|444444444444444444444444444444255555555555555555555555555555\n4|666666666666666666666666666666677777777777777777777777777777\n5|333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---removes-highlighting-per-line",
    "content": "-|---------|--\n1|(aaa)       \n2|(bbb)       \n3|~           \n4|<o Name] 2,3\n5|            \n\n-|---------|--\n1|011101111111\n2|011101111111\n3|222222222222\n4|333333333333\n5|111111111111\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---removes-highlighting-per-line-002",
    "content": "-|---------|--\n1|(aaa)       \n2|(bbb)       \n3|~           \n4|<o Name] 2,3\n5|            \n\n-|---------|--\n1|000000000000\n2|100010000000\n3|222222222222\n4|333333333333\n5|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---removes-highlighting-per-line-003",
    "content": "-|---------|--\n1|(aaa)       \n2|(bbb)       \n3|~           \n4|<o Name] 2,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---respects-`config.n_lines`",
    "content": "--|---------|---------|---------|---------|\n01|(                                       \n02|                                        \n03|                                        \n04|a                                       \n05|                                        \n06|                                        \n07|)                                       \n08|~                                       \n09|~                                       \n10|~                                       \n11|~                                       \n12|[No Name] 4,1                           \n13|(mini.surround) No surrounding \")\" found\n14| within 2 lines and `config.search_metho\n15|d = 'cover'`.                           \n\n--|---------|---------|---------|---------|\n01|0000000000000000000000000000000000000000\n02|0000000000000000000000000000000000000000\n03|0000000000000000000000000000000000000000\n04|0000000000000000000000000000000000000000\n05|0000000000000000000000000000000000000000\n06|0000000000000000000000000000000000000000\n07|0000000000000000000000000000000000000000\n08|1111111111111111111111111111111111111111\n09|1111111111111111111111111111111111111111\n10|1111111111111111111111111111111111111111\n11|1111111111111111111111111111111111111111\n12|2222222222222222222222222222222222222222\n13|3333333333333333444444444444444444444444\n14|4444444444444444444444444444444444444444\n15|4444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---respects-`v-count`-for-input-surrounding",
    "content": "-|---------|--\n1|(a(b(c)b)a) \n2|~           \n3|~           \n4|<o Name] 1,6\n5|            \n\n-|---------|--\n1|001000001000\n2|222222222222\n3|222222222222\n4|333333333333\n5|044444444440\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---respects-`vim.b.minisurround_config`",
    "content": "-|---------|--\n1|>aaa<       \n2|bbb         \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|011101111111\n2|111111111111\n3|222222222222\n4|333333333333\n5|144444444441\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---respects-`vim.b.minisurround_config`-002",
    "content": "-|---------|--\n1|>aaa<       \n2|bbb         \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---respects-`vim.{g,b}.minisurround_disable`---test-+-args-{-'b'-}",
    "content": "-|---------|--\n1|(aaa)       \n2|bbb         \n3|~           \n4|<o Name] 2,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---respects-`vim.{g,b}.minisurround_disable`---test-+-args-{-'g'-}",
    "content": "-|---------|--\n1|(aaa)       \n2|bbb         \n3|~           \n4|<o Name] 2,3\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|111111111111\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-in-extended-mappings",
    "content": "-|---------|-----\n1|(aa) (bb) (cc) \n2|~              \n3|~              \n4|[No Name] 1,2  \n5|               \n\n-|---------|-----\n1|000001001000000\n2|222222222222222\n3|222222222222222\n4|333333333333333\n5|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-in-extended-mappings-002",
    "content": "-|---------|-----\n1|(aa) (bb) (cc) \n2|~              \n3|~              \n4|[No Name] 1,13 \n5|               \n\n-|---------|-----\n1|000001001000000\n2|222222222222222\n3|222222222222222\n4|333333333333333\n5|444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-in-extended-mappings-003",
    "content": "-|---------|-----\n1|(aa) (bb) (cx) \n2|~              \n3|~              \n4|[No Name] 1,13 \n5|               \n\n-|---------|-----\n1|000000000000000\n2|111111111111111\n3|111111111111111\n4|222222222222222\n5|333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-with-multiline-input-surroundings",
    "content": "-|---------|--\n1|xxx(        \n2|aaa         \n3|)xxx        \n4|<o Name] 2,2\n5|            \n\n-|---------|--\n1|000100000000\n2|101000000000\n3|100000000000\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-with-multiline-input-surroundings-002",
    "content": "-|---------|--\n1|xxx(        \n2|aaa         \n3|)xxx        \n4|<o Name] 2,2\n5|            \n\n-|---------|--\n1|000100000000\n2|000000000000\n3|100000000000\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-with-multiline-input-surroundings-003",
    "content": "-|---------|--\n1|xxx(        \n2|aaa         \n3|)xxx        \n4|<o Name] 2,2\n5|            \n\n-|---------|--\n1|000000000000\n2|101000000000\n3|000000000000\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-with-multiline-input-surroundings-004",
    "content": "-|---------|--\n1|xxx(        \n2|aaa         \n3|)xxx        \n4|<o Name] 2,2\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|022222222220\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-without-dot-repeat",
    "content": "-|---------|--\n1|(aaa) (bbb) \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|011101111111\n2|222222222222\n3|222222222222\n4|333333333333\n5|144444444441\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-without-dot-repeat-002",
    "content": "-|---------|--\n1|(aaa) (bbb) \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|011101111111\n2|222222222222\n3|222222222222\n4|333333333333\n5|144444444441\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-without-dot-repeat-003",
    "content": "-|---------|--\n1|(aaa) (bbb) \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Highlight-surrounding---works-without-dot-repeat-004",
    "content": "-|---------|--\n1|(axa) (bbb) \n2|~           \n3|~           \n4|<o Name] 1,3\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|033333333330\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Replace-surrounding---respects-`config.silent`",
    "content": "--|---------|---------|\n01|<aaa>               \n02|[No Name] 1,2       \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|         g@<20>     \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Replace-surrounding---respects-`config.silent`-002",
    "content": "--|---------|---------|\n01|<aaa>               \n02|[No Name] 1,2       \n03|                    \n04|                    \n05|                    \n06|                    \n07|                    \n08|                    \n09|                    \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|11111111111111111111\n03|22222222222222222222\n04|22222222222222222222\n05|22222222222222222222\n06|22222222222222222222\n07|22222222222222222222\n08|22222222222222222222\n09|22222222222222222222\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Replace-surrounding---shows-reminder-after-one-idle-second",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(<aaa>)                                                               \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,3                                                         \n5|(mini.surround) Reminder to press input surrounding id                \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Replace-surrounding---shows-reminder-after-one-idle-second-002",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|(<aaa>)                                                               \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,3                                                         \n5|(mini.surround) Reminder to press output surrounding id               \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---Replace-surrounding---shows-reminder-after-one-idle-second-003",
    "content": "-|---------|---------|---------|---------|---------|---------|---------|\n1|<<aaa>>                                                               \n2|~                                                                     \n3|~                                                                     \n4|[No Name] 1,2                                                         \n5|                                                                      \n\n-|---------|---------|---------|---------|---------|---------|---------|\n1|0000000000000000000000000000000000000000000000000000000000000000000000\n2|1111111111111111111111111111111111111111111111111111111111111111111111\n3|1111111111111111111111111111111111111111111111111111111111111111111111\n4|2222222222222222222222222222222222222222222222222222222222222222222222\n5|3333333333333333333333333333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_surround.lua---gen_spec---input---treesitter()---works-with-empty-region",
    "content": "--|---------|---------|---------|---------|\n01|local M = {}                            \n02|                                        \n03|function M.a(u, vv, www)                \n04|  return function() print(u .. vv) end  \n05|end                                     \n06|                                        \n07|M.b = function()                        \n08|  local x = 1 + 1                       \n09|  print('1 + 1 = ' .. x)                \n10|  return true                           \n11|end                                     \n12|                                        \n13|return M                                \n14|tests/mock-treesitter/lua-file.lua 10,3 \n15|                                        \n\n--|---------|---------|---------|---------|\n01|0000012131441111111111111111111111111111\n02|1111111111111111111111111111111111111111\n03|0000000012565751775177751111111111111111\n04|1188888810000000055144444531331335100011\n05|0001111111111111111111111111111111111111\n06|1111111111111111111111111111111111111111\n07|2561310000000055111111111111111111111111\n08|1100000131312131211111111111111111111111\n09|1144444599999999991331351111111111111111\n10|11::::::;2222111111111111111111111111111\n11|0001111111111111111111111111111111111111\n12|1111111111111111111111111111111111111111\n13|8888881211111111111111111111111111111111\n14|<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n15|11111111111111111111111111111==========1\n"
  },
  {
    "path": "tests/screenshots/tests-test_tabline.lua---Screen---works",
    "content": "-|---------|---------|---------|---------|\n1| aaa  bbb  ccc                          \n2|                                        \n3|~                                       \n4|aaa 0,0-1                               \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000011111111111111111111111111111111111\n2|2222222222222222222222222222222222222222\n3|3333333333333333333333333333333333333333\n4|4444444444444444444444444444444444444444\n5|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_tabline.lua---Screen---works-002",
    "content": "-|---------|---------|---------|---------|\n1| aaa  bbb  ccc                          \n2|                                        \n3|~                                       \n4|bbb 0,0-1                               \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000011111000000000000000000000000000000\n2|2222222222222222222222222222222222222222\n3|3333333333333333333333333333333333333333\n4|4444444444444444444444444444444444444444\n5|5555555555555555555555555555555555555555\n"
  },
  {
    "path": "tests/screenshots/tests-test_tabline.lua---Screen---works-003",
    "content": "-|---------|---------|---------|---------|\n1| aaa  bbb  ccc                          \n2|                                        \n3|~                                       \n4|ccc 0,0-1                               \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000011111222220000000000000000000000000\n2|3333333333333333333333333333333333333333\n3|4444444444444444444444444444444444444444\n4|5555555555555555555555555555555555555555\n5|6666666666666666666666666666666666666666\n"
  },
  {
    "path": "tests/screenshots/tests-test_tabline.lua---Screen---works-004",
    "content": "-|---------|---------|---------|---------|\n1| Tab 2/2  aaa  bbb  ccc  ddd            \n2|                                        \n3|~                                       \n4|ddd 0,0-1                               \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000001111122222111113333311111111111\n2|4444444444444444444444444444444444444444\n3|5555555555555555555555555555555555555555\n4|6666666666666666666666666666666666666666\n5|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_tabline.lua---Screen---works-005",
    "content": "-|---------|---------|---------|---------|\n1| Tab 2/2  aaa  bbb  ccc  ddd  eee       \n2|                    │                   \n3|~                   │~                  \n4|eee 0,0-1            ddd 0,0-1          \n5|                                        \n\n-|---------|---------|---------|---------|\n1|0000000001111122222111113333344444111111\n2|5555555555555555555567777777777777777777\n3|8888888888888888888869999999999999999999\n4|:::::::::::::::::::::1111111111111111111\n5|7777777777777777777777777777777777777777\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---expect---reference_screenshot()---correctly-infers-reference-path",
    "content": "-|---------|---------|\n1|This path should be \n2|correctly inferred w\n3|ithout suffix       \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00000000000000000000\n2|00000000000000000000\n3|00000000000000000000\n4|11111111111111111111\n5|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---expect---reference_screenshot()---correctly-infers-reference-path-002",
    "content": "-|---------|---------|\n1|This path should hav\n2|e suffix 002        \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00000000000000000000\n2|00000000000000000000\n3|11111111111111111111\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---expect---reference_screenshot()---correctly-infers-reference-path-004",
    "content": "-|---------|---------|\n1|This path should hav\n2|e suffix 004        \n3|~                   \n4|[No Name] 1,1       \n5|                    \n\n-|---------|---------|\n1|00000000000000000000\n2|00000000000000000000\n3|11111111111111111111\n4|22222222222222222222\n5|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---expect---reference_screenshot()---correctly-sanitizes-path-for-Windows-",
    "content": "-|---------|--\n1|Path should \n2|be correctly\n3| sanitized  \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---expect---reference_screenshot()---correctly-sanitizes-path-for-Windows-#2-",
    "content": "-|---------|--\n1|Path should \n2|be correctly\n3| sanitized  \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|000000000000\n3|000000000000\n4|111111111111\n5|222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---expect---reference_screenshot()---works-with-multibyte-characters",
    "content": "-|---------|--\n1|  1  2    \n2|~           \n3|~           \n4|<o Name] 1,1\n5|            \n\n-|---------|--\n1|000000000000\n2|111111111111\n3|111111111111\n4|222222222222\n5|333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---buffer---test-+-args-{-''-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|~                                                                                                                       \n03|~                                                                                                                       \n04|~                                                                                                                       \n05|~                                                                                                                       \n06|~                                                                                                                       \n07|~                                                                                                                       \n08|~                                                                                                                       \n09|~                                                                                                                       \n10|~                                                                                                                       \n11|~                                                                                                                       \n12|~                                                                                                                       \n13|~                                                                                                                       \n14|~                     ┌ Test results ────────────────────────────────────────────────────────────┐                      \n15|~                     │Total number of cases: 9                                                  │                      \n16|~                     │Total number of groups: 1                                                 │                      \n17|~                     │                                                                          │                      \n18|~                     │tests/dir-test/testref_reporters.lua: oOxXoOxXO                           │                      \n19|~                     │                                                                          │                      \n20|~                     │Fails (4) and Notes (5)                                                   │                      \n21|~                     │                                                                          │                      \n22|~                     │FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom │                      \n23|~                     │error                                                                     │                      \n24|~                     │  Traceback:                                                              │                      \n25|~                     │    tests/dir-test/testref_reporters.lua:9                                │                      \n26|~                     │                                                                          │                      \n27|~                     │FAIL in tests/dir-test/testref_reporters.lua | first group | fail with not│                      \n28|~                     │es: Custom error after note                                               │                      \n29|~                     │  Traceback:                                                              │                      \n30|~                     │    tests/dir-test/testref_reporters.lua:12                               │                      \n31|~                     │                                                                          │                      \n32|~                     │FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom│                      \n33|~                     │ error #2                                                                 │                      \n34|~                     │  Traceback:                                                              │                      \n35|~                     │    tests/dir-test/testref_reporters.lua:18                               │                      \n36|~                     │                                                                          │                      \n37|~                     │FAIL in tests/dir-test/testref_reporters.lua | second group | fail with no│                      \n38|~                     │tes: Custom error after note #2                                           │                      \n39|~                     │  Traceback:                                                              │                      \n40|~                     │    tests/dir-test/testref_reporters.lua:21                               │                      \n41|~                     │                                                                          │                      \n42|~                     │NOTE in tests/dir-test/testref_reporters.lua | first group | pass with not│                      \n43|~                     │es: Passed note                                                           │                      \n44|~                     │                                                                          │                      \n45|~                     │NOTE in tests/dir-test/testref_reporters.lua | first group | fail with not│                      \n46|~                     │es: Failed note                                                           │                      \n47|~                     │                                                                          │                      \n48|~                     │NOTE in tests/dir-test/testref_reporters.lua | second group | pass with no│                      \n49|~                     │tes: Passed note #2                                                       │                      \n50|~                     │                                                                          │                      \n51|~                     │NOTE in tests/dir-test/testref_reporters.lua | second group | fail with no│                      \n52|~                     │tes: Failed note #2                                                       │                      \n53|~                     │                                                                          │                      \n54|~                     │NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name│                      \n55|~                     │ | case with \\n in name: Passed note #3                                   │                      \n56|~                     │                                                                          │                      \n57|~                     │                                                                          │                      \n58|~                     └──────────────────────────────────────────────────────────────────────────┘                      \n59|~                                                                                                                       \n60|~                                                                                                                       \n61|~                                                                                                                       \n62|~                                                                                                                       \n63|~                                                                                                                       \n64|~                                                                                                                       \n65|~                                                                                                                       \n66|~                                                                                                                       \n67|~                                                                                                                       \n68|~                                                                                                                       \n69|[No Name] 0,0-1                                                                                                         \n70|                                                                                                      6,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111123333333333333322222222222222222222222222222222222222222222222222222222222221111111111111111111111\n15|111111111111111111111124444444444444444444444555555555555555555555555555555555555555555555555555521111111111111111111111\n16|111111111111111111111124444444444444444444444455555555555555555555555555555555555555555555555555521111111111111111111111\n17|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n18|111111111111111111111125555555555555555555555555555555555555566776677655555555555555555555555555521111111111111111111111\n19|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n20|111111111111111111111124444444444444444444444455555555555555555555555555555555555555555555555555521111111111111111111111\n21|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n22|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n23|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n24|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n25|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n26|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n27|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n28|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n29|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n30|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n31|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n32|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n33|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n34|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n35|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n36|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n37|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n38|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n39|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n40|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n41|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n42|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n43|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n44|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n45|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n46|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n47|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n48|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n49|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n50|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n51|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n52|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n53|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n54|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n55|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n56|111111111111111111111128888888888888888888888888888888888888888888888888888888888888888888888888821111111111111111111111\n57|111111111111111111111128888888888888888888888888888888888888888888888888888888888888888888888888821111111111111111111111\n58|111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111\n59|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n60|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n61|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n62|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n63|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n64|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n65|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n66|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n67|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n68|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n69|999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999\n70|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---buffer---test-+-args-{-'group_depth=2'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|~                                                                                                                       \n03|~                                                                                                                       \n04|~                                                                                                                       \n05|~                                                                                                                       \n06|~                                                                                                                       \n07|~                                                                                                                       \n08|~                                                                                                                       \n09|~                                                                                                                       \n10|~                                                                                                                       \n11|~                                                                                                                       \n12|~                                                                                                                       \n13|~                                                                                                                       \n14|~                     ┌ Test results ────────────────────────────────────────────────────────────┐                      \n15|~                     │Total number of cases: 9                                                  │                      \n16|~                     │Total number of groups: 3                                                 │                      \n17|~                     │                                                                          │                      \n18|~                     │tests/dir-test/testref_reporters.lua | first group: oOxX                  │                      \n19|~                     │tests/dir-test/testref_reporters.lua | second group: oOxX                 │                      \n20|~                     │tests/dir-test/testref_reporters.lua | third group with \\n in name: O     │                      \n21|~                     │                                                                          │                      \n22|~                     │Fails (4) and Notes (5)                                                   │                      \n23|~                     │                                                                          │                      \n24|~                     │FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom │                      \n25|~                     │error                                                                     │                      \n26|~                     │  Traceback:                                                              │                      \n27|~                     │    tests/dir-test/testref_reporters.lua:9                                │                      \n28|~                     │                                                                          │                      \n29|~                     │FAIL in tests/dir-test/testref_reporters.lua | first group | fail with not│                      \n30|~                     │es: Custom error after note                                               │                      \n31|~                     │  Traceback:                                                              │                      \n32|~                     │    tests/dir-test/testref_reporters.lua:12                               │                      \n33|~                     │                                                                          │                      \n34|~                     │FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom│                      \n35|~                     │ error #2                                                                 │                      \n36|~                     │  Traceback:                                                              │                      \n37|~                     │    tests/dir-test/testref_reporters.lua:18                               │                      \n38|~                     │                                                                          │                      \n39|~                     │FAIL in tests/dir-test/testref_reporters.lua | second group | fail with no│                      \n40|~                     │tes: Custom error after note #2                                           │                      \n41|~                     │  Traceback:                                                              │                      \n42|~                     │    tests/dir-test/testref_reporters.lua:21                               │                      \n43|~                     │                                                                          │                      \n44|~                     │NOTE in tests/dir-test/testref_reporters.lua | first group | pass with not│                      \n45|~                     │es: Passed note                                                           │                      \n46|~                     │                                                                          │                      \n47|~                     │NOTE in tests/dir-test/testref_reporters.lua | first group | fail with not│                      \n48|~                     │es: Failed note                                                           │                      \n49|~                     │                                                                          │                      \n50|~                     │NOTE in tests/dir-test/testref_reporters.lua | second group | pass with no│                      \n51|~                     │tes: Passed note #2                                                       │                      \n52|~                     │                                                                          │                      \n53|~                     │NOTE in tests/dir-test/testref_reporters.lua | second group | fail with no│                      \n54|~                     │tes: Failed note #2                                                       │                      \n55|~                     │                                                                          │                      \n56|~                     │NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name│                      \n57|~                     │ | case with \\n in name: Passed note #3                                   │                      \n58|~                     └──────────────────────────────────────────────────────────────────────────┘                      \n59|~                                                                                                                       \n60|~                                                                                                                       \n61|~                                                                                                                       \n62|~                                                                                                                       \n63|~                                                                                                                       \n64|~                                                                                                                       \n65|~                                                                                                                       \n66|~                                                                                                                       \n67|~                                                                                                                       \n68|~                                                                                                                       \n69|[No Name] 0,0-1                                                                                                         \n70|                                                                                                      8,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111123333333333333322222222222222222222222222222222222222222222222222222222222221111111111111111111111\n15|111111111111111111111124444444444444444444444555555555555555555555555555555555555555555555555555521111111111111111111111\n16|111111111111111111111124444444444444444444444455555555555555555555555555555555555555555555555555521111111111111111111111\n17|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n18|111111111111111111111125555555555555555555555555555555555555555555555555555667755555555555555555521111111111111111111111\n19|111111111111111111111125555555555555555555555555555555555555555555555555555566775555555555555555521111111111111111111111\n20|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555565555521111111111111111111111\n21|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n22|111111111111111111111124444444444444444444444455555555555555555555555555555555555555555555555555521111111111111111111111\n23|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n24|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n25|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n26|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n27|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n28|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n29|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n30|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n31|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n32|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n33|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n34|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n35|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n36|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n37|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n38|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n39|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n40|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n41|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n42|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n43|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n44|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n45|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n46|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n47|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n48|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n49|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n50|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n51|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n52|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n53|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n54|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n55|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n56|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n57|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n58|111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111\n59|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n60|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n61|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n62|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n63|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n64|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n65|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n66|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n67|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n68|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n69|888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\n70|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---buffer---test-+-args-{-'window={border='double',title=('a')-rep(200)}'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|~                                                                                                                       \n03|~                                                                                                                       \n04|~                                                                                                                       \n05|~                                                                                                                       \n06|~                                                                                                                       \n07|~                                                                                                                       \n08|~                                                                                                                       \n09|~                                                                                                                       \n10|~                                                                                                                       \n11|~                                                                                                                       \n12|~                                                                                                                       \n13|~                                                                                                                       \n14|~                     ╔…aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa╗                      \n15|~                     ║Total number of cases: 9                                                  ║                      \n16|~                     ║Total number of groups: 1                                                 ║                      \n17|~                     ║                                                                          ║                      \n18|~                     ║tests/dir-test/testref_reporters.lua: oOxXoOxXO                           ║                      \n19|~                     ║                                                                          ║                      \n20|~                     ║Fails (4) and Notes (5)                                                   ║                      \n21|~                     ║                                                                          ║                      \n22|~                     ║FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom ║                      \n23|~                     ║error                                                                     ║                      \n24|~                     ║  Traceback:                                                              ║                      \n25|~                     ║    tests/dir-test/testref_reporters.lua:9                                ║                      \n26|~                     ║                                                                          ║                      \n27|~                     ║FAIL in tests/dir-test/testref_reporters.lua | first group | fail with not║                      \n28|~                     ║es: Custom error after note                                               ║                      \n29|~                     ║  Traceback:                                                              ║                      \n30|~                     ║    tests/dir-test/testref_reporters.lua:12                               ║                      \n31|~                     ║                                                                          ║                      \n32|~                     ║FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom║                      \n33|~                     ║ error #2                                                                 ║                      \n34|~                     ║  Traceback:                                                              ║                      \n35|~                     ║    tests/dir-test/testref_reporters.lua:18                               ║                      \n36|~                     ║                                                                          ║                      \n37|~                     ║FAIL in tests/dir-test/testref_reporters.lua | second group | fail with no║                      \n38|~                     ║tes: Custom error after note #2                                           ║                      \n39|~                     ║  Traceback:                                                              ║                      \n40|~                     ║    tests/dir-test/testref_reporters.lua:21                               ║                      \n41|~                     ║                                                                          ║                      \n42|~                     ║NOTE in tests/dir-test/testref_reporters.lua | first group | pass with not║                      \n43|~                     ║es: Passed note                                                           ║                      \n44|~                     ║                                                                          ║                      \n45|~                     ║NOTE in tests/dir-test/testref_reporters.lua | first group | fail with not║                      \n46|~                     ║es: Failed note                                                           ║                      \n47|~                     ║                                                                          ║                      \n48|~                     ║NOTE in tests/dir-test/testref_reporters.lua | second group | pass with no║                      \n49|~                     ║tes: Passed note #2                                                       ║                      \n50|~                     ║                                                                          ║                      \n51|~                     ║NOTE in tests/dir-test/testref_reporters.lua | second group | fail with no║                      \n52|~                     ║tes: Failed note #2                                                       ║                      \n53|~                     ║                                                                          ║                      \n54|~                     ║NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name║                      \n55|~                     ║ | case with \\n in name: Passed note #3                                   ║                      \n56|~                     ║                                                                          ║                      \n57|~                     ║                                                                          ║                      \n58|~                     ╚══════════════════════════════════════════════════════════════════════════╝                      \n59|~                                                                                                                       \n60|~                                                                                                                       \n61|~                                                                                                                       \n62|~                                                                                                                       \n63|~                                                                                                                       \n64|~                                                                                                                       \n65|~                                                                                                                       \n66|~                                                                                                                       \n67|~                                                                                                                       \n68|~                                                                                                                       \n69|[No Name] 0,0-1                                                                                                         \n70|                                                                                                      6,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111123333333333333333333333333333333333333333333333333333333333333333333333333321111111111111111111111\n15|111111111111111111111124444444444444444444444555555555555555555555555555555555555555555555555555521111111111111111111111\n16|111111111111111111111124444444444444444444444455555555555555555555555555555555555555555555555555521111111111111111111111\n17|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n18|111111111111111111111125555555555555555555555555555555555555566776677655555555555555555555555555521111111111111111111111\n19|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n20|111111111111111111111124444444444444444444444455555555555555555555555555555555555555555555555555521111111111111111111111\n21|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n22|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n23|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n24|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n25|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n26|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n27|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n28|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n29|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n30|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n31|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n32|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n33|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n34|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n35|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n36|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n37|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n38|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n39|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n40|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n41|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n42|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n43|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n44|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n45|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n46|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n47|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n48|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n49|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n50|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n51|111111111111111111111127777555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n52|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n53|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n54|111111111111111111111126666555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n55|111111111111111111111125555555555555555555555555555555555555555555555555555555555555555555555555521111111111111111111111\n56|111111111111111111111128888888888888888888888888888888888888888888888888888888888888888888888888821111111111111111111111\n57|111111111111111111111128888888888888888888888888888888888888888888888888888888888888888888888888821111111111111111111111\n58|111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111\n59|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n60|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n61|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n62|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n63|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n64|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n65|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n66|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n67|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n68|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n69|999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999\n70|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---buffer---test-+-args-{-'window={width=0.9-vim.o.columns,col=0.05-vim.o.columns}'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|~                                                                                                                       \n03|~                                                                                                                       \n04|~                                                                                                                       \n05|~                                                                                                                       \n06|~                                                                                                                       \n07|~                                                                                                                       \n08|~                                                                                                                       \n09|~                                                                                                                       \n10|~                                                                                                                       \n11|~                                                                                                                       \n12|~                                                                                                                       \n13|~                                                                                                                       \n14|~     ╭ Test results ──────────────────────────────────────────────────────────────────────────────────────────────╮    \n15|~     │Total number of cases: 9                                                                                    │    \n16|~     │Total number of groups: 1                                                                                   │    \n17|~     │                                                                                                            │    \n18|~     │tests/dir-test/testref_reporters.lua: oOxXoOxXO                                                             │    \n19|~     │                                                                                                            │    \n20|~     │Fails (4) and Notes (5)                                                                                     │    \n21|~     │                                                                                                            │    \n22|~     │FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom error                             │    \n23|~     │  Traceback:                                                                                                │    \n24|~     │    tests/dir-test/testref_reporters.lua:9                                                                  │    \n25|~     │                                                                                                            │    \n26|~     │FAIL in tests/dir-test/testref_reporters.lua | first group | fail with notes: Custom error after note       │    \n27|~     │  Traceback:                                                                                                │    \n28|~     │    tests/dir-test/testref_reporters.lua:12                                                                 │    \n29|~     │                                                                                                            │    \n30|~     │FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom error #2                         │    \n31|~     │  Traceback:                                                                                                │    \n32|~     │    tests/dir-test/testref_reporters.lua:18                                                                 │    \n33|~     │                                                                                                            │    \n34|~     │FAIL in tests/dir-test/testref_reporters.lua | second group | fail with notes: Custom error after note #2   │    \n35|~     │  Traceback:                                                                                                │    \n36|~     │    tests/dir-test/testref_reporters.lua:21                                                                 │    \n37|~     │                                                                                                            │    \n38|~     │NOTE in tests/dir-test/testref_reporters.lua | first group | pass with notes: Passed note                   │    \n39|~     │                                                                                                            │    \n40|~     │NOTE in tests/dir-test/testref_reporters.lua | first group | fail with notes: Failed note                   │    \n41|~     │                                                                                                            │    \n42|~     │NOTE in tests/dir-test/testref_reporters.lua | second group | pass with notes: Passed note #2               │    \n43|~     │                                                                                                            │    \n44|~     │NOTE in tests/dir-test/testref_reporters.lua | second group | fail with notes: Failed note #2               │    \n45|~     │                                                                                                            │    \n46|~     │NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name | case with \\n in name: Passed no│    \n47|~     │te #3                                                                                                       │    \n48|~     │                                                                                                            │    \n49|~     │                                                                                                            │    \n50|~     │                                                                                                            │    \n51|~     │                                                                                                            │    \n52|~     │                                                                                                            │    \n53|~     │                                                                                                            │    \n54|~     │                                                                                                            │    \n55|~     │                                                                                                            │    \n56|~     │                                                                                                            │    \n57|~     │                                                                                                            │    \n58|~     ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯    \n59|~                                                                                                                       \n60|~                                                                                                                       \n61|~                                                                                                                       \n62|~                                                                                                                       \n63|~                                                                                                                       \n64|~                                                                                                                       \n65|~                                                                                                                       \n66|~                                                                                                                       \n67|~                                                                                                                       \n68|~                                                                                                                       \n69|[No Name] 0,0-1                                                                                                         \n70|                                                                                                      6,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111233333333333333222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111\n15|111111244444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n16|111111244444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n17|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n18|111111255555555555555555555555555555555555555667766776555555555555555555555555555555555555555555555555555555555555521111\n19|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n20|111111244444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n21|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n22|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n23|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n24|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n25|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n26|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n27|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n28|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n29|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n30|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n31|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n32|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n33|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n34|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n35|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n36|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n37|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n38|111111266665555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n39|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n40|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n41|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n42|111111266665555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n43|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n44|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n45|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n46|111111266665555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n47|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n48|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n49|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n50|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n51|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n52|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n53|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n54|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n55|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n56|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n57|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n58|111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111\n59|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n60|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n61|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n62|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n63|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n64|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n65|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n66|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n67|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n68|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n69|999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999\n70|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---buffer---test-+-args-{-'window={width=0.9-vim.o.columns,col=0.05-vim.o.columns}'-}-002",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|                                                                                                                        \n02|~                                                                                                                       \n03|~                                                                                                                       \n04|~                                                                                                                       \n05|~                                                                                                                       \n06|~                                                                                                                       \n07|~                                                                                                                       \n08|~                                                                                                                       \n09|~                                                                                                                       \n10|~                                                                                                                       \n11|~                                                                                                                       \n12|~                                                                                                                       \n13|~                                                                                                                       \n14|~     + Test results ----------------------------------------------------------------------------------------------+    \n15|~     |Total number of cases: 9                                                                                    |    \n16|~     |Total number of groups: 1                                                                                   |    \n17|~     |                                                                                                            |    \n18|~     |tests/dir-test/testref_reporters.lua: oOxXoOxXO                                                             |    \n19|~     |                                                                                                            |    \n20|~     |Fails (4) and Notes (5)                                                                                     |    \n21|~     |                                                                                                            |    \n22|~     |FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom error                             |    \n23|~     |  Traceback:                                                                                                |    \n24|~     |    tests/dir-test/testref_reporters.lua:9                                                                  |    \n25|~     |                                                                                                            |    \n26|~     |FAIL in tests/dir-test/testref_reporters.lua | first group | fail with notes: Custom error after note       |    \n27|~     |  Traceback:                                                                                                |    \n28|~     |    tests/dir-test/testref_reporters.lua:12                                                                 |    \n29|~     |                                                                                                            |    \n30|~     |FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom error #2                         |    \n31|~     |  Traceback:                                                                                                |    \n32|~     |    tests/dir-test/testref_reporters.lua:18                                                                 |    \n33|~     |                                                                                                            |    \n34|~     |FAIL in tests/dir-test/testref_reporters.lua | second group | fail with notes: Custom error after note #2   |    \n35|~     |  Traceback:                                                                                                |    \n36|~     |    tests/dir-test/testref_reporters.lua:21                                                                 |    \n37|~     |                                                                                                            |    \n38|~     |NOTE in tests/dir-test/testref_reporters.lua | first group | pass with notes: Passed note                   |    \n39|~     |                                                                                                            |    \n40|~     |NOTE in tests/dir-test/testref_reporters.lua | first group | fail with notes: Failed note                   |    \n41|~     |                                                                                                            |    \n42|~     |NOTE in tests/dir-test/testref_reporters.lua | second group | pass with notes: Passed note #2               |    \n43|~     |                                                                                                            |    \n44|~     |NOTE in tests/dir-test/testref_reporters.lua | second group | fail with notes: Failed note #2               |    \n45|~     |                                                                                                            |    \n46|~     |NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name | case with \\n in name: Passed no|    \n47|~     |te #3                                                                                                       |    \n48|~     |                                                                                                            |    \n49|~     |                                                                                                            |    \n50|~     |                                                                                                            |    \n51|~     |                                                                                                            |    \n52|~     |                                                                                                            |    \n53|~     |                                                                                                            |    \n54|~     |                                                                                                            |    \n55|~     |                                                                                                            |    \n56|~     |                                                                                                            |    \n57|~     |                                                                                                            |    \n58|~     +------------------------------------------------------------------------------------------------------------+    \n59|~                                                                                                                       \n60|~                                                                                                                       \n61|~                                                                                                                       \n62|~                                                                                                                       \n63|~                                                                                                                       \n64|~                                                                                                                       \n65|~                                                                                                                       \n66|~                                                                                                                       \n67|~                                                                                                                       \n68|~                                                                                                                       \n69|[No Name] 0,0-1                                                                                                         \n70|                                                                                                      6,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n02|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111233333333333333222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111\n15|111111244444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n16|111111244444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n17|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n18|111111255555555555555555555555555555555555555667766776555555555555555555555555555555555555555555555555555555555555521111\n19|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n20|111111244444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n21|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n22|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n23|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n24|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n25|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n26|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n27|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n28|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n29|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n30|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n31|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n32|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n33|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n34|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n35|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n36|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n37|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n38|111111266665555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n39|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n40|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n41|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n42|111111266665555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n43|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n44|111111277775555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n45|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n46|111111266665555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n47|111111255555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555521111\n48|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n49|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n50|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n51|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n52|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n53|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n54|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n55|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n56|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n57|111111288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888821111\n58|111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111\n59|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n60|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n61|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n62|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n63|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n64|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n65|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n66|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n67|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n68|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n69|999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999\n70|000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---stdout---test-+-args-{-''-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|Total number of cases: 9                                                                                                \n02|Total number of groups: 1                                                                                               \n03|                                                                                                                        \n04|tests/dir-test/testref_reporters.lua: oOxXoOxXO                                                                         \n05|                                                                                                                        \n06|Fails (4) and Notes (5)                                                                                                 \n07|                                                                                                                        \n08|FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom error                                         \n09|  Traceback:                                                                                                            \n10|    tests/dir-test/testref_reporters.lua:9                                                                              \n11|                                                                                                                        \n12|FAIL in tests/dir-test/testref_reporters.lua | first group | fail with notes: Custom error after note                   \n13|  Traceback:                                                                                                            \n14|    tests/dir-test/testref_reporters.lua:12                                                                             \n15|                                                                                                                        \n16|FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom error #2                                     \n17|  Traceback:                                                                                                            \n18|    tests/dir-test/testref_reporters.lua:18                                                                             \n19|                                                                                                                        \n20|FAIL in tests/dir-test/testref_reporters.lua | second group | fail with notes: Custom error after note #2               \n21|  Traceback:                                                                                                            \n22|    tests/dir-test/testref_reporters.lua:21                                                                             \n23|                                                                                                                        \n24|NOTE in tests/dir-test/testref_reporters.lua | first group | pass with notes: Passed note                               \n25|                                                                                                                        \n26|NOTE in tests/dir-test/testref_reporters.lua | first group | fail with notes: Failed note                               \n27|                                                                                                                        \n28|NOTE in tests/dir-test/testref_reporters.lua | second group | pass with notes: Passed note #2                           \n29|                                                                                                                        \n30|NOTE in tests/dir-test/testref_reporters.lua | second group | fail with notes: Failed note #2                           \n31|                                                                                                                        \n32|NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name | case with \\n in name: Passed note #3       \n33|                                                                                                                        \n34|[Process exited 1]                                                                                                      \n35|                                                                                                      1,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111112233223321111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n16|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n18|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n19|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n21|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n24|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n25|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n26|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n27|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n28|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n29|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n30|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n31|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n32|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n33|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n34|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n35|444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---stdout---test-+-args-{-'TEST_GROUP_DEPTH=2'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|Total number of cases: 9                                                                                                \n02|Total number of groups: 3                                                                                               \n03|                                                                                                                        \n04|tests/dir-test/testref_reporters.lua | first group: oOxX                                                                \n05|tests/dir-test/testref_reporters.lua | second group: oOxX                                                               \n06|tests/dir-test/testref_reporters.lua | third group with \\n in name: O                                                   \n07|                                                                                                                        \n08|Fails (4) and Notes (5)                                                                                                 \n09|                                                                                                                        \n10|FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom error                                         \n11|  Traceback:                                                                                                            \n12|    tests/dir-test/testref_reporters.lua:9                                                                              \n13|                                                                                                                        \n14|FAIL in tests/dir-test/testref_reporters.lua | first group | fail with notes: Custom error after note                   \n15|  Traceback:                                                                                                            \n16|    tests/dir-test/testref_reporters.lua:12                                                                             \n17|                                                                                                                        \n18|FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom error #2                                     \n19|  Traceback:                                                                                                            \n20|    tests/dir-test/testref_reporters.lua:18                                                                             \n21|                                                                                                                        \n22|FAIL in tests/dir-test/testref_reporters.lua | second group | fail with notes: Custom error after note #2               \n23|  Traceback:                                                                                                            \n24|    tests/dir-test/testref_reporters.lua:21                                                                             \n25|                                                                                                                        \n26|NOTE in tests/dir-test/testref_reporters.lua | first group | pass with notes: Passed note                               \n27|                                                                                                                        \n28|NOTE in tests/dir-test/testref_reporters.lua | first group | fail with notes: Failed note                               \n29|                                                                                                                        \n30|NOTE in tests/dir-test/testref_reporters.lua | second group | pass with notes: Passed note #2                           \n31|                                                                                                                        \n32|NOTE in tests/dir-test/testref_reporters.lua | second group | fail with notes: Failed note #2                           \n33|                                                                                                                        \n34|NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name | case with \\n in name: Passed note #3       \n35|                                                                                                      1,1           Top \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111111111111111111122331111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111112233111111111111111111111111111111111111111111111111111111111111111\n06|111111111111111111111111111111111111111111111111111111111111111111112111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n16|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n18|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n19|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n21|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n24|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n25|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n26|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n27|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n28|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n29|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n30|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n31|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n32|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n33|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n34|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n35|444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_test.lua---gen_reporter---stdout---test-+-args-{-'TEST_QUIT_ON_FINISH=false'-}",
    "content": "--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|Total number of cases: 9                                                                                                \n02|Total number of groups: 1                                                                                               \n03|                                                                                                                        \n04|tests/dir-test/testref_reporters.lua: oOxXoOxXO                                                                         \n05|                                                                                                                        \n06|Fails (4) and Notes (5)                                                                                                 \n07|                                                                                                                        \n08|FAIL in tests/dir-test/testref_reporters.lua | first group | fail: Custom error                                         \n09|  Traceback:                                                                                                            \n10|    tests/dir-test/testref_reporters.lua:9                                                                              \n11|                                                                                                                        \n12|FAIL in tests/dir-test/testref_reporters.lua | first group | fail with notes: Custom error after note                   \n13|  Traceback:                                                                                                            \n14|    tests/dir-test/testref_reporters.lua:12                                                                             \n15|                                                                                                                        \n16|FAIL in tests/dir-test/testref_reporters.lua | second group | fail: Custom error #2                                     \n17|  Traceback:                                                                                                            \n18|    tests/dir-test/testref_reporters.lua:18                                                                             \n19|                                                                                                                        \n20|FAIL in tests/dir-test/testref_reporters.lua | second group | fail with notes: Custom error after note #2               \n21|  Traceback:                                                                                                            \n22|    tests/dir-test/testref_reporters.lua:21                                                                             \n23|                                                                                                                        \n24|NOTE in tests/dir-test/testref_reporters.lua | first group | pass with notes: Passed note                               \n25|                                                                                                                        \n26|NOTE in tests/dir-test/testref_reporters.lua | first group | fail with notes: Failed note                               \n27|                                                                                                                        \n28|NOTE in tests/dir-test/testref_reporters.lua | second group | pass with notes: Passed note #2                           \n29|                                                                                                                        \n30|NOTE in tests/dir-test/testref_reporters.lua | second group | fail with notes: Failed note #2                           \n31|                                                                                                                        \n32|NOTE in tests/dir-test/testref_reporters.lua | third group with \\n in name | case with \\n in name: Passed note #3       \n33|                                                                                                                        \n34|                                                                                                                        \n35|                                                                                                      1,1           All \n\n--|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|\n01|000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n02|000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n03|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n04|111111111111111111111111111111111111112233223321111111111111111111111111111111111111111111111111111111111111111111111111\n05|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n06|000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n07|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n08|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n09|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n10|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n11|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n12|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n13|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n14|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n15|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n16|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n17|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n18|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n19|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n20|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n21|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n22|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n23|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n24|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n25|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n26|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n27|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n28|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n29|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n30|333311111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n31|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n32|222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n33|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n34|111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n35|444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-BufEnter-BufLeave",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-BufEnter-BufLeave-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-BufEnter-BufLeave-003",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-InsertEnter-InsertLeave",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-InsertEnter-InsertLeave-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222233333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-InsertEnter-InsertLeave-003",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-OptionSet",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-OptionSet-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-WinEnter-WinLeave",
    "content": "--|---------|---------|---------|---------|\n01|aa                  │aa                 \n02|aa                  │aa                 \n03|aa                  │aa                 \n04|aa                  │aa                 \n05|aa                  │aa                 \n06|aa                  │aa                 \n07|  aa                │  aa               \n08|        aa          │        aa         \n09|aaa 1,1              bbb 1,1            \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0010000000000000000023333333333333333333\n02|0011000000000000000023333333333333333333\n03|0011111100000000000023333333333333333333\n04|0011111111111111000023333333333333333333\n05|0011111100000000000023333333333333333333\n06|0011111110000000000023333333333333333333\n07|0000000000000000000023333333333333333333\n08|0000000000000000000023333333333333333333\n09|4444444444444444444445555555555555555555\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-WinEnter-WinLeave-002",
    "content": "--|---------|---------|---------|---------|\n01|aa                 │aa                  \n02|aa                 │aa                  \n03|aa                 │aa                  \n04|aa                 │aa                  \n05|aa                 │aa                  \n06|aa                 │aa                  \n07|  aa               │  aa                \n08|        aa         │        aa          \n09|aaa 1,1             bbb 1,1             \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0000000000000000000122322222222222222222\n02|0000000000000000000122332222222222222222\n03|0000000000000000000122333333222222222222\n04|0000000000000000000122333333333333332222\n05|0000000000000000000122333333222222222222\n06|0000000000000000000122333333322222222222\n07|0000000000000000000122222222222222222222\n08|0000000000000000000122222222222222222222\n09|4444444444444444444455555555555555555555\n10|0000000000000000000000000000000000000000\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-autohighlighting---respects-WinEnter-WinLeave-003",
    "content": "--|---------|---------|---------|---------|\n01|aa                  │aa                 \n02|aa                  │aa                 \n03|aa                  │aa                 \n04|aa                  │aa                 \n05|aa                  │aa                 \n06|aa                  │aa                 \n07|  aa                │  aa               \n08|        aa          │        aa         \n09|aaa 1,1              bbb 1,1            \n10|                                        \n\n--|---------|---------|---------|---------|\n01|0010000000000000000023333333333333333333\n02|0011000000000000000023333333333333333333\n03|0011111100000000000023333333333333333333\n04|0011111111111111000023333333333333333333\n05|0011111100000000000023333333333333333333\n06|0011111110000000000023333333333333333333\n07|0000000000000000000023333333333333333333\n08|0000000000000000000023333333333333333333\n09|4444444444444444444445555555555555555555\n10|3333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---Trailspace-highlighting-on-startup---works",
    "content": "-|---------|--\n1|aa          \n2|~           \n3|~           \n4|<ce/file 1,1\n5|            \n\n-|---------|--\n1|001100000000\n2|222222222222\n3|222222222222\n4|333333333333\n5|444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`config.only_in_normal_buffers`---test-+-args-{-false,-''-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`config.only_in_normal_buffers`---test-+-args-{-false,-'help'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`config.only_in_normal_buffers`---test-+-args-{-false,-'nofile'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[Scratch] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`config.only_in_normal_buffers`---test-+-args-{-true,-''-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`config.only_in_normal_buffers`---test-+-args-{-true,-'help'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`config.only_in_normal_buffers`---test-+-args-{-true,-'nofile'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[Scratch] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`vim.b.minitrailspace_config`",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[Scratch] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`vim.{g,b}.minitrailspace_disable`---test-+-args-{-'b'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---respects-`vim.{g,b}.minitrailspace_disable`---test-+-args-{-'g'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-after-`clearmatches()`",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-after-`clearmatches()`-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-only-in-Normal-mode---test-+-args-{-'-'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|:                   \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-only-in-Normal-mode---test-+-args-{-'R'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|-- REPLACE --       \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222223333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-only-in-Normal-mode---test-+-args-{-'i'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|-- INSERT --        \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222233333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---highlight()---works-only-in-Normal-mode---test-+-args-{-'v'-}",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|-- VISUAL1          \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222233333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---unhighlight()---works",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00100000000000000000\n02|00110000000000000000\n03|00111111000000000000\n04|00111111111111110000\n05|00111111000000000000\n06|00111111100000000000\n07|00000000000000000000\n08|00000000000000000000\n09|22222222222222222222\n10|33333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---unhighlight()---works-002",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_trailspace.lua---unhighlight()---works-after-`clearmatches()`",
    "content": "--|---------|---------|\n01|aa                  \n02|aa                  \n03|aa                  \n04|aa                  \n05|aa                  \n06|aa                  \n07|  aa                \n08|        aa          \n09|[No Name] 1,1       \n10|                    \n\n--|---------|---------|\n01|00000000000000000000\n02|00000000000000000000\n03|00000000000000000000\n04|00000000000000000000\n05|00000000000000000000\n06|00000000000000000000\n07|00000000000000000000\n08|00000000000000000000\n09|11111111111111111111\n10|22222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---add_label()---asks-user-for-label-if-it-is-not-supplied",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                                                           \n3|~                                                           \n4|~                                                           \n5|Enter label to add:                                         \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111111111111111111\n5|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---add_label()---asks-user-for-label-if-it-is-not-supplied-002",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                   aaa                                     \n3|~                   abb                                     \n4|~                   bbb                                     \n5|Enter label to add: aaa                                     \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111122222222222222221111111111111111111111111\n3|111111111111111111133333333333333331111111111111111111111111\n4|111111111111111111133333333333333331111111111111111111111111\n5|444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---add_label()---asks-user-for-label-if-it-is-not-supplied-003",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                                                           \n3|~                   aaa                                     \n4|~                   abb                                     \n5|Enter label to add: aaa                                     \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111111111111111111\n3|111111111111111111122222222222222221111111111111111111111111\n4|111111111111111111133333333333333331111111111111111111111111\n5|444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---add_label()---works",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                                                           \n3|~                                                           \n4|~                                                           \n5|(mini.visits) Added \"aaa\" label.                            \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111111111111111111\n5|222222222222223333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---remove_label()---asks-user-for-label-if-it-is-not-supplied",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                                                           \n3|~                                                           \n4|~                                                           \n5|Enter label to remove:                                      \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111111111111111111\n5|222222222222222222222222222222222222222222222222222222222222\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---remove_label()---asks-user-for-label-if-it-is-not-supplied-002",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                      aaa                                  \n3|~                      abb                                  \n4|~                      bbb                                  \n5|Enter label to remove: aaa                                  \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111122222222222222221111111111111111111111\n3|111111111111111111111133333333333333331111111111111111111111\n4|111111111111111111111133333333333333331111111111111111111111\n5|444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---remove_label()---asks-user-for-label-if-it-is-not-supplied-003",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                                                           \n3|~                      aaa                                  \n4|~                      abb                                  \n5|Enter label to remove: aaa                                  \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111122222222222222221111111111111111111111\n4|111111111111111111111133333333333333331111111111111111111111\n5|444444444444444444444444444444444444444444444444444444444444\n"
  },
  {
    "path": "tests/screenshots/tests-test_visits.lua---remove_label()---works",
    "content": "-|---------|---------|---------|---------|---------|---------|\n1|                                                            \n2|~                                                           \n3|~                                                           \n4|~                                                           \n5|(mini.visits) Removed \"aaa\" label.                          \n\n-|---------|---------|---------|---------|---------|---------|\n1|000000000000000000000000000000000000000000000000000000000000\n2|111111111111111111111111111111111111111111111111111111111111\n3|111111111111111111111111111111111111111111111111111111111111\n4|111111111111111111111111111111111111111111111111111111111111\n5|222222222222223333333333333333333333333333333333333333333333\n"
  },
  {
    "path": "tests/test_ai.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('ai', config) end\nlocal unload_module = function() child.mini_unload('ai') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n\nlocal get_mode = function() return child.api.nvim_get_mode()['mode'] end\n\nlocal validate_edit = function(before_lines, before_cursor, after_lines, after_cursor, ...)\n  child.ensure_normal_mode()\n\n  set_lines(before_lines)\n  set_cursor(unpack(before_cursor))\n\n  type_keys(...)\n\n  eq(get_lines(), after_lines)\n  eq(get_cursor(), after_cursor)\nend\n\nlocal validate_edit1d = function(before_line, before_column, after_line, after_column, ...)\n  validate_edit({ before_line }, { 1, before_column }, { after_line }, { 1, after_column }, ...)\nend\n\nlocal validate_next_region = function(keys, next_region)\n  type_keys(keys)\n  -- Should put cursor at the right edge of selection (as it is done for\n  -- built-in textobjects in Visual mode)\n  eq({ { child.fn.line('v'), child.fn.col('v') }, { child.fn.line('.'), child.fn.col('.') } }, next_region)\nend\n\nlocal validate_next_region1d = function(keys, next_region)\n  type_keys(keys)\n  eq({ child.fn.col('v'), child.fn.col('.') }, next_region)\nend\n\nlocal validate_tobj = function(lines, cursor, keys, expected, vis_mode)\n  vis_mode = vim.api.nvim_replace_termcodes(vis_mode or 'v', true, true, true)\n\n  child.ensure_normal_mode()\n  set_lines(lines)\n  set_cursor(unpack(cursor))\n  type_keys(vis_mode, keys)\n  eq(get_mode(), vis_mode)\n\n  -- Allow supplying number items to verify linewise selection\n  local expected_from = type(expected[1]) == 'number' and expected[1] or { expected[1][1], expected[1][2] - 1 }\n  local expected_to = type(expected[2]) == 'number' and expected[2] or { expected[2][1], expected[2][2] - 1 }\n  child.expect_visual_marks(expected_from, expected_to)\nend\n\nlocal validate_tobj1d = function(line, column, keys, expected)\n  validate_tobj({ line }, { 1, column }, keys, { { 1, expected[1] }, { 1, expected[2] } })\nend\n\nlocal validate_no_tobj = function(lines, cursor, keys, vis_mode)\n  vis_mode = vim.api.nvim_replace_termcodes(vis_mode or 'v', true, true, true)\n\n  child.ensure_normal_mode()\n  set_lines(lines)\n  set_cursor(unpack(cursor))\n\n  type_keys(vis_mode, keys)\n  eq(get_mode(), 'n')\n  eq(get_cursor(), cursor)\n  expect.match(get_latest_message(), 'No textobject')\nend\n\nlocal validate_no_tobj1d = function(line, column, keys) validate_no_tobj({ line }, { 1, column }, keys) end\n\n-- Time constants\nlocal reminder_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniAi)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniAi.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniAi.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('custom_textobjects', vim.NIL)\n  expect_config('mappings.around', 'a')\n  expect_config('mappings.inside', 'i')\n  expect_config('mappings.around_next', 'an')\n  expect_config('mappings.inside_next', 'in')\n  expect_config('mappings.around_last', 'al')\n  expect_config('mappings.inside_last', 'il')\n  expect_config('mappings.goto_left', 'g[')\n  expect_config('mappings.goto_right', 'g]')\n  expect_config('n_lines', 50)\n  expect_config('search_method', 'cover_or_next')\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ n_lines = 10 })\n  eq(child.lua_get('MiniAi.config.n_lines'), 10)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ custom_textobjects = 'a' }, 'custom_textobjects', 'table')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { around = 1 } }, 'mappings.around', 'string')\n  expect_config_error({ mappings = { inside = 1 } }, 'mappings.inside', 'string')\n  expect_config_error({ mappings = { around_next = 1 } }, 'mappings.around_next', 'string')\n  expect_config_error({ mappings = { inside_next = 1 } }, 'mappings.inside_next', 'string')\n  expect_config_error({ mappings = { around_last = 1 } }, 'mappings.around_last', 'string')\n  expect_config_error({ mappings = { inside_last = 1 } }, 'mappings.inside_last', 'string')\n  expect_config_error({ mappings = { goto_left = 1 } }, 'mappings.goto_left', 'string')\n  expect_config_error({ mappings = { goto_right = 1 } }, 'mappings.goto_right', 'string')\n  expect_config_error({ n_lines = 'a' }, 'n_lines', 'number')\n  expect_config_error({ search_method = 1 }, 'search_method', 'one of')\n  expect_config_error({ silent = 1 }, 'silent', 'boolean')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('xmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('a', 'Around'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('x', 'a')\n  child.api.nvim_del_keymap('x', 'an')\n  child.api.nvim_del_keymap('x', 'al')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { around = '', around_next = '', around_last = '' } })\n  eq(has_map('a', 'Around'), false)\nend\n\nlocal find_textobject = function(...) return child.lua_get('MiniAi.find_textobject(...)', { ... }) end\n\nlocal validate_find = function(lines, cursor, args, expected)\n  set_lines(lines)\n  set_cursor(cursor[1], cursor[2])\n\n  local new_expected\n  if expected == nil then\n    new_expected = vim.NIL\n  else\n    new_expected = {\n      from = { line = expected[1][1], col = expected[1][2] },\n      to = { line = expected[2][1], col = expected[2][2] },\n      vis_mode = expected.vis_mode,\n    }\n  end\n\n  eq(find_textobject(unpack(args)), new_expected)\nend\n\nlocal validate_find1d = function(line, column, args, expected)\n  local new_expected\n  if expected ~= nil then new_expected = { { 1, expected[1] }, { 1, expected[2] } } end\n  validate_find({ line }, { 1, column }, args, new_expected)\nend\n\nT['find_textobject()'] = new_set()\n\nT['find_textobject()']['works'] = function() validate_find1d('aa(bb)cc', 3, { 'a', ')' }, { 3, 6 }) end\n\nT['find_textobject()']['respects `id` argument'] = function() validate_find1d('(aa[bb]cc)', 4, { 'a', ']' }, { 4, 7 }) end\n\nT['find_textobject()']['respects `ai_type` argument'] = function()\n  validate_find1d('aa(bb)cc', 3, { 'i', ')' }, { 4, 5 })\nend\n\nT['find_textobject()']['respects `opts.n_lines`'] = function()\n  local lines = { '(', '', 'a', '', ')' }\n  validate_find(lines, { 3, 1 }, { 'a', ')', { n_lines = 1 } }, nil)\n  validate_find(lines, { 3, 1 }, { 'a', ')', { n_lines = 2 } }, { { 1, 1 }, { 5, 1 } })\n\n  -- Should handle 0\n  validate_find(lines, { 3, 1 }, { 'a', ')', { n_lines = 0 } }, nil)\nend\n\nT['find_textobject()']['respects `opts.n_times`'] = function()\n  local line, column = '(aa(bb)cc)', 4\n  validate_find1d(line, column, { 'a', ')', { n_times = 1 } }, { 4, 7 })\n  validate_find1d(line, column, { 'a', ')', { n_times = 2 } }, { 1, 10 })\n  validate_find1d(line, column, { 'i', ')', { n_times = 2 } }, { 2, 9 })\n\n  -- Should handle 0\n  validate_find1d(line, 0, { 'a', ')', { n_times = 0 } }, nil)\nend\n\nT['find_textobject()']['respects `opts.reference_region`'] = function()\n  local line = 'aa(bb(cc)dd)ee'\n  local new_opts = function(from, to)\n    return { reference_region = { from = { line = 1, col = from }, to = { line = 1, col = to } } }\n  end\n\n  validate_find1d(line, 0, { 'a', ')', new_opts(7, 7) }, { 6, 9 })\n  validate_find1d(line, 0, { 'a', ')', new_opts(7, 9) }, { 6, 9 })\n  validate_find1d(line, 0, { 'a', ')', new_opts(6, 8) }, { 6, 9 })\n\n  -- Even if reference region is a valid text object, it should select another\n  -- one. This enables evolving of textobjects during consecutive calls.\n  validate_find1d(line, 0, { 'a', ')', new_opts(6, 9) }, { 3, 12 })\n  validate_find1d(line, 0, { 'a', ')', new_opts(3, 12) }, nil)\n\n  -- Allows empty reference region\n  local empty_opts = { reference_region = { from = { line = 1, col = 6 } } }\n  validate_find1d(line, 0, { 'a', ')', empty_opts }, { 6, 9 })\nend\n\nT['find_textobject()']['respects `opts.search_method`'] = function()\n  local line = '(aa)bbb(cc)'\n  local new_opts = function(search_method) return { search_method = search_method } end\n\n  -- By default should be 'cover_or_next'\n  validate_find1d(line, 4, { 'a', ')' }, { 8, 11 })\n\n  validate_find1d(line, 1, { 'a', ')', new_opts('cover_or_next') }, { 1, 4 })\n  validate_find1d(line, 4, { 'a', ')', new_opts('cover_or_next') }, { 8, 11 })\n  validate_find1d(line, 8, { 'a', ')', new_opts('cover_or_next') }, { 8, 11 })\n\n  validate_find1d(line, 1, { 'a', ')', new_opts('cover') }, { 1, 4 })\n  validate_find1d(line, 4, { 'a', ')', new_opts('cover') }, nil)\n  validate_find1d(line, 8, { 'a', ')', new_opts('cover') }, { 8, 11 })\n\n  validate_find1d(line, 1, { 'a', ')', new_opts('cover_or_prev') }, { 1, 4 })\n  validate_find1d(line, 4, { 'a', ')', new_opts('cover_or_prev') }, { 1, 4 })\n  validate_find1d(line, 8, { 'a', ')', new_opts('cover_or_prev') }, { 8, 11 })\n\n  validate_find1d(line, 1, { 'a', ')', new_opts('cover_or_nearest') }, { 1, 4 })\n  validate_find1d(line, 4, { 'a', ')', new_opts('cover_or_nearest') }, { 1, 4 })\n  validate_find1d(line, 5, { 'a', ')', new_opts('cover_or_nearest') }, { 1, 4 })\n  validate_find1d(line, 6, { 'a', ')', new_opts('cover_or_nearest') }, { 8, 11 })\n  validate_find1d(line, 8, { 'a', ')', new_opts('cover_or_nearest') }, { 8, 11 })\n\n  -- Should validate `opts.search_method`\n  expect.error(function() find_textobject('a', ')', { search_method = 'aaa' }) end, 'one of')\nend\n\nT['find_textobject()']['respects custom textobjects'] = function()\n  local line, column = 'aabbcc', 0\n\n  validate_find1d(line, column, { 'a', 'c' }, nil)\n  child.lua([[MiniAi.config.custom_textobjects = { c = { '()c()' } }]])\n  validate_find1d(line, column, { 'a', 'c' }, { 5, 5 })\nend\n\nT['find_textobject()']['works on multiple lines'] = function()\n  local lines, cursor = { '(aa', '(bb', 'cc', 'dd)', 'ee)' }, { 3, 0 }\n  validate_find(lines, cursor, { 'a', ')' }, { { 2, 1 }, { 4, 3 } })\n  validate_find(lines, cursor, { 'i', ')' }, { { 2, 2 }, { 4, 2 } })\n  validate_find(lines, cursor, { 'a', ')', { n_times = 2 } }, { { 1, 1 }, { 5, 3 } })\n  validate_find(lines, cursor, { 'i', ')', { n_times = 2 } }, { { 1, 2 }, { 5, 2 } })\n\n  -- Region over multiple lines is not empty (it has newline)\n  validate_find({ 'aa(', ')' }, { 1, 1 }, { 'i', ')' }, { { 1, 4 }, { 1, 4 } })\nend\n\nT['find_textobject()']['may return position after line end'] = function()\n  -- This powers multiline collapsing (calling `di)` leads to '()' single line)\n  validate_find({ '(', 'aa', ')' }, { 2, 0 }, { 'i', ')' }, { { 1, 2 }, { 2, 3 } })\nend\n\nT['find_textobject()']['works with multibyte characters'] = function()\n  -- Each multibyte character takes two column counts\n  local line = '(ыы)ффф(ыы)'\n  validate_find1d(line, 1, { 'a', ')' }, { 1, 6 })\n  validate_find1d(line, 1, { 'a', ')', { n_times = 2 } }, { 13, 18 })\n  validate_find1d(line, 6, { 'a', ')' }, { 13, 18 })\nend\n\nT['find_textobject()']['handles cursor on textobject edge'] = function()\n  validate_find1d('aa(bb)cc', 2, { 'a', ')' }, { 3, 6 })\n  validate_find1d('aa(bb)cc', 2, { 'i', ')' }, { 4, 5 })\n\n  validate_find1d('aa(bb)cc', 5, { 'a', ')' }, { 3, 6 })\n  validate_find1d('aa(bb)cc', 5, { 'i', ')' }, { 4, 5 })\nend\n\nT['find_textobject()']['first searches within current line'] = function()\n  local lines, cursor = { '(', 'aa(bb)', ')' }, { 2, 0 }\n  validate_find(lines, cursor, { 'a', ')' }, { { 2, 3 }, { 2, 6 } })\n  validate_find(lines, cursor, { 'a', ')', { search_method = 'cover' } }, { { 1, 1 }, { 3, 1 } })\nend\n\nT['find_textobject()']['handles `n_times > 1` with matches on current line'] = function()\n  local lines, cursor = { '((', 'aa(bb)cc(dd)', '))' }, { 2, 0 }\n  validate_find(lines, cursor, { 'a', ')', { n_times = 1 } }, { { 2, 3 }, { 2, 6 } })\n  validate_find(lines, cursor, { 'a', ')', { n_times = 2 } }, { { 2, 9 }, { 2, 12 } })\n  validate_find(lines, cursor, { 'a', ')', { n_times = 3 } }, { { 1, 2 }, { 3, 1 } })\n  validate_find(lines, cursor, { 'a', ')', { n_times = 4 } }, { { 1, 1 }, { 3, 2 } })\nend\n\nT['find_textobject()']['allows empty output region'] = function()\n  set_lines({ 'aa()bb(cc)' })\n\n  for i = 1, 2 do\n    set_cursor(1, i)\n    eq(find_textobject('i', ')'), { from = { line = 1, col = 4 } })\n    eq(find_textobject('i', ')', { n_times = 2 }), { from = { line = 1, col = 8 }, to = { line = 1, col = 9 } })\n  end\nend\n\nT['find_textobject()']['ensures that output is not covered by reference'] = function()\n  set_lines({ 'aa()bb(cc)dd(ee)' })\n  set_cursor(1, 0)\n\n  -- Non-empty reference\n  eq(\n    find_textobject('i', ')', { reference_region = { from = { line = 1, col = 8 }, to = { line = 1, col = 9 } } }),\n    { from = { line = 1, col = 14 }, to = { line = 1, col = 15 } }\n  )\n\n  -- Empty reference\n  eq(\n    find_textobject('i', ')', { reference_region = { from = { line = 1, col = 4 } } }),\n    { from = { line = 1, col = 8 }, to = { line = 1, col = 9 } }\n  )\nend\n\nT['find_textobject()']['handles function as textobject spec'] = new_set()\n\nT['find_textobject()']['handles function as textobject spec']['returns composed pattern'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    x = function(...) _G.args = {...}; return {'x()x()x'} end\n  }]])\n\n  validate_find1d('aaxxxbb', 0, { 'a', 'x' }, { 3, 5 })\n  -- Should be called with arguments after expanding defaults\n  --stylua: ignore\n  eq(\n    child.lua_get('_G.args'),\n    {\n      'a', 'x',\n      {\n        n_lines = 50,\n        n_times = 1,\n        reference_region = { from = { line = 1, col = 1 } },\n        search_method = 'cover_or_next',\n      },\n    }\n  )\nend\n\nT['find_textobject()']['handles function as textobject spec']['returns region'] = function()\n  -- Should take arguments from corresponding `find_textobject()` call\n  child.lua([[_G.full_buffer = function(ai_type, id, opts)\n    local from = { line = 1, col = 1 }\n    local to = { line = vim.fn.line('$'), col = vim.fn.getline('$'):len() }\n    if ai_type == 'i' then to.col = to.col - 1 end\n    return { from = from, to = to }\n  end]])\n  child.lua([[MiniAi.config.custom_textobjects = { g = _G.full_buffer }]])\n  validate_find({ 'aaaaa', 'bbbb', 'ccc' }, { 2, 0 }, { 'a', 'g' }, { { 1, 1 }, { 3, 3 } })\n  validate_find({ 'aaaaa', 'bbbb', 'ccc' }, { 2, 0 }, { 'i', 'g' }, { { 1, 1 }, { 3, 2 } })\n\n  -- Should return region as is (taking precedence over options)\n  child.lua('MiniAi.config.n_lines = 0')\n  child.lua([[MiniAi.config.search_method = 'next']])\n  validate_find({ 'aaaaa', 'bbbb', 'ccc' }, { 2, 0 }, { 'a', 'g' }, { { 1, 1 }, { 3, 3 } })\nend\n\nT['find_textobject()']['handles function as textobject spec']['returns array of regions'] = function()\n  -- Should take arguments from corresponding `find_textobject()` call\n  child.lua([[_G.fixed_regions = function(_, _, _)\n    local res = {}\n    res[1] = { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } }\n    res[2] = { from = { line = 1, col = 1 }, to = { line = 1, col = 4 } }\n    res[3] = { from = { line = 2, col = 1 }, to = { line = 2, col = 2 } }\n    res[4] = { from = { line = 2, col = 1 }, to = { line = 2, col = 4 } }\n    return res\n  end]])\n  child.lua([[MiniAi.config.custom_textobjects = { r = _G.fixed_regions }]])\n\n  local lines = { 'aaaaa', 'bbbb', 'ccc' }\n  validate_find(lines, { 1, 0 }, { 'a', 'r' }, { { 1, 1 }, { 1, 2 } })\n  validate_find(lines, { 1, 3 }, { 'a', 'r' }, { { 1, 1 }, { 1, 4 } })\n  validate_find(lines, { 1, 4 }, { 'a', 'r' }, { { 2, 1 }, { 2, 2 } })\n  validate_find(lines, { 3, 0 }, { 'a', 'r' }, nil)\n\n  -- Should pick best region according to options\n  child.lua([[MiniAi.config.n_lines = 0]])\n  validate_find(lines, { 1, 4 }, { 'a', 'r' }, nil)\n\n  child.lua([[MiniAi.config.n_lines = 10]])\n  child.lua([[MiniAi.config.search_method = 'cover']])\n  validate_find(lines, { 1, 4 }, { 'a', 'r' }, nil)\n\n  -- Should account for region `vis_mode`\n  child.lua([[_G.line_regions = function(_, _, _)\n    return {\n      { from = { line = 1, col = 1 }, to = { line = 2, col = 1 }, vis_mode = 'V' },\n      { from = { line = 3, col = 1 }, to = { line = 4, col = 1 }, vis_mode = 'V' },\n    }\n  end]])\n  child.lua([[MiniAi.config.custom_textobjects = { m = _G.line_regions }]])\n\n  local ref_region_1 = { { 1, 1 }, { 2, 1 }, vis_mode = 'V' }\n  validate_find({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 1, 0 }, { 'a', 'm' }, ref_region_1)\n  local ref_region_2 = { { 3, 1 }, { 4, 1 }, vis_mode = 'V' }\n  validate_find({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 3, 0 }, { 'a', 'm' }, ref_region_2)\nend\n\nT['find_textobject()']['handles function as specification item'] = function()\n  child.lua([[_G.c_spec = {\n    '%b()',\n    function(s, init) if init > 1 then return end; return 2, s:len() end,\n    '^().*().$'\n  }]])\n  child.lua([[MiniAi.config.custom_textobjects = { c = _G.c_spec }]])\n  validate_find1d('aa(bb)', 0, { 'a', 'c' }, { 4, 6 })\n  validate_find1d('aa(bb)', 0, { 'i', 'c' }, { 4, 5 })\nend\n\nT['find_textobject()']['handles callable table'] = new_set()\n\nT['find_textobject()']['handles callable table']['as textobject spec'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    x = setmetatable({}, {__call = function() return {'x()x()x'} end})\n  }]])\n\n  validate_find1d('aaxxxbb', 0, { 'a', 'x' }, { 3, 5 })\nend\n\nT['find_textobject()']['handles callable table']['as specification item'] = function()\n  child.lua([[_G.c_spec = {\n    '%b()',\n    setmetatable({}, {__call = function(_, s, init) if init > 1 then return end; return 2, s:len() end}),\n    '^().*().$'\n  }]])\n  child.lua([[MiniAi.config.custom_textobjects = { c = _G.c_spec }]])\n  validate_find1d('aa(bb)', 0, { 'a', 'c' }, { 4, 6 })\n  validate_find1d('aa(bb)', 0, { 'i', 'c' }, { 4, 5 })\nend\n\nT['find_textobject()']['shows message if no region is found'] = function()\n  -- Make all showed messages full width\n  child.o.cmdheight = 10\n\n  local validate = function(msg, args)\n    child.cmd('messages clear')\n    validate_find1d('aa', 0, args, nil)\n    eq(get_latest_message(), msg)\n  end\n\n  validate(\n    [[(mini.ai) No textobject \"a)\" found covering region within 50 lines and `search_method = 'cover_or_next'`.]],\n    { 'a', ')' }\n  )\n  validate(\n    [[(mini.ai) No textobject \"i]\" found covering region 2 times within 1 line and `search_method = 'cover'`.]],\n    { 'i', ']', { n_times = 2, n_lines = 1, search_method = 'cover' } }\n  )\n  validate(\n    [[(mini.ai) No textobject \"i]\" found covering region 0 times within 0 lines and `search_method = 'cover_or_next'`.]],\n    { 'i', ']', { n_times = 0, n_lines = 0 } }\n  )\nend\n\nT['find_textobject()']['respects `config.silent`'] = function()\n  child.lua('MiniAi.config.silent = true')\n\n  validate_find1d('aa', 0, { 'a', ')' }, nil)\n  eq(get_latest_message(), '')\nend\n\nT['find_textobject()']['respects `vim.b.miniai_config`'] = function()\n  child.b.miniai_config = { search_method = 'cover' }\n  validate_find1d('aa(bb)', 0, { 'a', ')' }, nil)\nend\n\nlocal validate_move = function(lines, cursor, args, expected)\n  set_lines(lines)\n  set_cursor(cursor[1], cursor[2])\n  child.lua([[MiniAi.move_cursor(...)]], args)\n  eq(get_cursor(), { expected[1], expected[2] })\nend\n\nlocal validate_move1d = function(line, column, args, expected)\n  validate_move({ line }, { 1, column }, args, { 1, expected })\nend\n\nT['move_cursor()'] = new_set()\n\nT['move_cursor()']['works'] = function() validate_move1d('aa(bbb)', 4, { 'left', 'a', ')' }, 2) end\n\nT['move_cursor()']['respects `side` argument'] = function()\n  local line = '(aa)bb(cc)'\n  validate_move1d(line, 1, { 'left', 'a', ')' }, 0)\n  validate_move1d(line, 1, { 'right', 'a', ')' }, 3)\n  validate_move1d(line, 4, { 'left', 'a', ')' }, 6)\n  validate_move1d(line, 4, { 'right', 'a', ')' }, 9)\n  validate_move1d(line, 7, { 'left', 'a', ')' }, 6)\n  validate_move1d(line, 7, { 'right', 'a', ')' }, 9)\n\n  -- It should validate `side` argument\n  expect.error(\n    function() child.lua([[MiniAi.move_cursor('leftright', 'a', ')')]]) end,\n    vim.pesc([[(mini.ai) `side` should be one of 'left' or 'right'.]])\n  )\nend\n\nT['move_cursor()']['respects `ai_type` argument'] = function()\n  validate_move1d('aa(bbb)', 4, { 'left', 'i', ')' }, 3)\n  validate_move1d('aa(bbb)', 4, { 'right', 'i', ')' }, 5)\nend\n\nT['move_cursor()']['respects `id` argument'] = function() validate_move1d('aa[bbb]', 4, { 'left', 'a', ']' }, 2) end\n\nT['move_cursor()']['respects `opts` argument'] = function()\n  validate_move1d('aa(bbb)cc(ddd)', 4, { 'left', 'a', ')', { n_times = 2 } }, 9)\nend\n\nT['move_cursor()']['always jumps exactly `opts.n_times` times'] = function()\n  -- It can be not that way if cursor is on edge of one of target textobjects\n  local line = 'aa(bb)cc(dd)ee(ff)'\n  validate_move1d(line, 0, { 'left', 'a', ')', { n_times = 2 } }, 8) -- 0->2->8\n  validate_move1d(line, 2, { 'left', 'a', ')', { n_times = 2 } }, 14) -- 2->8->14\n  validate_move1d(line, 3, { 'left', 'a', ')', { n_times = 2 } }, 8) -- 3->2->8\n  validate_move1d(line, 5, { 'left', 'a', ')', { n_times = 2 } }, 8) -- 5->2->8\n\n  validate_move1d(line, 0, { 'right', 'a', ')', { n_times = 2 } }, 11) -- 0->5->11\n  validate_move1d(line, 2, { 'right', 'a', ')', { n_times = 2 } }, 11) -- 2->5->11\n  validate_move1d(line, 3, { 'right', 'a', ')', { n_times = 2 } }, 11) -- 3->5->11\n  validate_move1d(line, 5, { 'right', 'a', ')', { n_times = 2 } }, 17) -- 5->11->17\nend\n\nT['move_cursor()']['opens just enough folds'] = function()\n  set_lines({ '(aa', 'b)', 'c', 'd' })\n\n  -- Manually create two nested closed folds\n  set_cursor(3, 0)\n  type_keys('zf', 'G')\n  type_keys('zf', 'gg')\n  eq(child.fn.foldlevel(1), 1)\n  eq(child.fn.foldlevel(3), 2)\n  eq(child.fn.foldclosed(2), 1)\n  eq(child.fn.foldclosed(3), 1)\n\n  -- Moving cursor should open just enough folds\n  set_cursor(1, 1)\n  child.lua([[MiniAi.move_cursor('right', 'a', ')')]])\n  eq(get_cursor(), { 2, 1 })\n  eq(child.fn.foldclosed(2), -1)\n  eq(child.fn.foldclosed(3), 3)\nend\n\nT['move_cursor()']['adds jumplist entry'] = function()\n  set_lines({ '(aa', 'b)' })\n\n  local validate = function(init_pos, direction, ref_pos)\n    set_cursor(unpack(init_pos))\n    child.lua('MiniAi.move_cursor(\"' .. direction .. '\", \"a\", \")\")')\n    eq(get_cursor(), ref_pos)\n    type_keys('``')\n    eq(get_cursor(), init_pos)\n  end\n\n  validate({ 1, 1 }, 'right', { 2, 1 })\n  validate({ 2, 1 }, 'left', { 1, 0 })\nend\n\nT['move_cursor()']['handles function as textobject spec'] = function()\n  -- Should call it only once\n  child.lua('_G.n = 0')\n  child.lua([[MiniAi.config.custom_textobjects = { c = function() _G.n = _G.n + 1; return { '()c()' } end }]])\n  validate_move1d('aabbcc', 0, { 'left', 'a', 'c' }, 4)\n  eq(child.lua_get('_G.n'), 1)\nend\n\nT['move_cursor()']['works with empty region'] = function()\n  validate_move1d('f()', 0, { 'left', 'i', ')' }, 2)\n  validate_move1d('f()', 0, { 'right', 'i', ')' }, 2)\nend\n\nT['move_cursor()']['works with multibyte characters'] = function()\n  validate_move1d(' (ыыы) ', 0, { 'left', 'a', ')' }, 1)\n  validate_move1d(' (ыыы) ', 0, { 'right', 'a', ')' }, 8)\nend\n\nT['gen_spec'] = new_set()\n\nT['gen_spec']['argument()'] = new_set()\n\nT['gen_spec']['argument()']['works'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = { A = MiniAi.gen_spec.argument() }]])\n\n  validate_find1d('f(aa, bb)', 0, { 'a', 'A' }, { 3, 5 })\n  validate_find1d('f(aa, bb)', 0, { 'i', 'A' }, { 3, 4 })\nend\n\nT['gen_spec']['argument()']['respects `opts.brackets`'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = { A = MiniAi.gen_spec.argument({ brackets = { '%b()' } }) }]])\n\n  validate_find1d('(aa, bb)', 0, { 'a', 'A' }, { 2, 4 })\n  validate_find1d('[aa, bb]', 0, { 'a', 'A' }, nil)\n  validate_find1d('{aa, bb}', 0, { 'a', 'A' }, nil)\nend\n\nT['gen_spec']['argument()']['respects `opts.separator`'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    A = MiniAi.gen_spec.argument({ separator = ';' }),\n    B = MiniAi.gen_spec.argument({ separator = '[,;]' }),\n    C = MiniAi.gen_spec.argument({ separator = '%s*,%s*' }),\n    D = MiniAi.gen_spec.argument({ separator = ', ,' }),\n  }]])\n\n  validate_find1d('(aa, bb; cc, dd)', 0, { 'a', 'A', { n_times = 1 } }, { 2, 8 })\n  validate_find1d('(aa, bb; cc, dd)', 0, { 'a', 'A', { n_times = 2 } }, { 8, 15 })\n\n  validate_find1d('(aa, bb; cc, dd)', 0, { 'a', 'B', { n_times = 1 } }, { 2, 4 })\n  validate_find1d('(aa, bb; cc, dd)', 0, { 'a', 'B', { n_times = 2 } }, { 4, 7 })\n  validate_find1d('(aa, bb; cc, dd)', 0, { 'a', 'B', { n_times = 3 } }, { 8, 11 })\n  validate_find1d('(aa, bb; cc, dd)', 0, { 'a', 'B', { n_times = 4 } }, { 12, 15 })\n\n  validate_find1d('(aa , bb , cc)', 0, { 'a', 'C', { n_times = 1 } }, { 2, 6 })\n  validate_find1d('(aa , bb , cc)', 0, { 'a', 'C', { n_times = 2 } }, { 4, 8 })\n  validate_find1d('(aa , bb , cc)', 0, { 'a', 'C', { n_times = 3 } }, { 9, 13 })\n\n  validate_find1d('(aa , bb , cc)', 0, { 'i', 'C', { n_times = 1 } }, { 2, 3 })\n  validate_find1d('(aa , bb , cc)', 0, { 'i', 'C', { n_times = 2 } }, { 7, 8 })\n  validate_find1d('(aa , bb , cc)', 0, { 'i', 'C', { n_times = 3 } }, { 12, 13 })\n\n  validate_find1d('(aa, bb , , cc, dd)', 0, { 'a', 'D', { n_times = 1 } }, { 2, 11 })\n  validate_find1d('(aa, bb , , cc, dd)', 0, { 'a', 'D', { n_times = 2 } }, { 9, 18 })\n\n  validate_find1d('(aa, bb , , cc, dd)', 0, { 'i', 'D', { n_times = 1 } }, { 2, 7 })\n  validate_find1d('(aa, bb , , cc, dd)', 0, { 'i', 'D', { n_times = 2 } }, { 13, 18 })\nend\n\nT['gen_spec']['argument()']['respects `opts.exclude_regions`'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    A = MiniAi.gen_spec.argument({ exclude_regions = { '\".-\"' } }),\n  }]])\n\n  -- Comma inside `()` should not be excluded\n  validate_find1d('(aa, (bb, cc))', 4, { 'a', 'A' }, { 4, 8 })\nend\n\nT['gen_spec']['function_call()'] = new_set()\n\nT['gen_spec']['function_call()']['works'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = { F = MiniAi.gen_spec.function_call() }]])\n\n  validate_find1d('f.g_h(x)', 0, { 'a', 'F' }, { 1, 8 })\n  validate_find1d('f.g_h(x)', 0, { 'i', 'F' }, { 7, 7 })\nend\n\nT['gen_spec']['function_call()']['respects `opts.name_pattern`'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = { F = MiniAi.gen_spec.function_call({ name_pattern = '[%w_]' }) }]])\n\n  validate_find1d('f.g_h(x)', 0, { 'a', 'F' }, { 3, 8 })\n  validate_find1d('f.g_h(x)', 0, { 'i', 'F' }, { 7, 7 })\nend\n\nT['gen_spec']['pair()'] = new_set()\n\nT['gen_spec']['pair()']['works'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = { x = MiniAi.gen_spec.pair('x', 'y') }]])\n\n  validate_find1d('aaxbbycc', 3, { 'a', 'x' }, { 3, 6 })\n  validate_find1d('aaxbbycc', 3, { 'i', 'x' }, { 4, 5 })\nend\n\n--stylua: ignore\nT['gen_spec']['pair()']['validates arguments'] = function()\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair(1, 'y')]]) end, '`left`.*string')\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair('x', 1)]]) end, '`right`.*string')\n\n  -- For balanced and greedy types arguments should be single character\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair('xx', 'y', { type = 'balanced' })]]) end, '`left`.*single.*balanced')\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair('x', 'yy', { type = 'balanced' })]]) end, '`left`.*single.*balanced')\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair('xx', 'y', { type = 'greedy' })]]) end, '`left`.*single.*greedy')\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair('x', 'yy', { type = 'greedy' })]]) end, '`left`.*single.*greedy')\n\n  -- `opts.type` should be one of pre-defined characters\n  expect.error(function() child.lua([[MiniAi.gen_spec.pair('x', 'y', { type = 'aaa' })]]) end, 'opts.type.*one of')\nend\n\nT['gen_spec']['pair()']['respects `opts.type`'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    _ = MiniAi.gen_spec.pair('_', '_', { type = 'non-balanced' }),\n    x = MiniAi.gen_spec.pair('_', '_', { type = 'balanced' }),\n    b = MiniAi.gen_spec.pair('(', ')', { type = 'balanced' }),\n    y = MiniAi.gen_spec.pair('_', '_', { type = 'greedy' }),\n  }]])\n\n  -- Non-balanced pair\n  validate_find1d('_a_b_c_', 0, { 'a', '_', { n_times = 1 } }, { 1, 3 })\n  validate_find1d('_a_b_c_', 0, { 'a', '_', { n_times = 2 } }, { 3, 5 })\n  validate_find1d('_a_b_c_', 0, { 'a', '_', { n_times = 3 } }, { 5, 7 })\n  validate_find1d('_a_b_c_', 0, { 'i', '_' }, { 2, 2 })\n\n  -- Balanced pair\n  validate_find1d('_a_b_c_', 0, { 'a', 'x', { n_times = 1 } }, { 1, 3 })\n  validate_find1d('_a_b_c_', 0, { 'a', 'x', { n_times = 2 } }, { 5, 7 })\n  validate_find1d('_a_b_c_', 0, { 'i', 'x' }, { 2, 2 })\n\n  -- Should also work with \"special\" characters\n  validate_find1d('((aa))', 2, { 'a', 'b', { n_times = 1 } }, { 2, 5 })\n  validate_find1d('((aa))', 2, { 'a', 'b', { n_times = 2 } }, { 1, 6 })\n\n  -- Greedy pair\n  validate_find1d('__a__b_', 0, { 'a', 'y', { n_times = 1 } }, { 1, 5 })\n  validate_find1d('__a__b_', 0, { 'a', 'y', { n_times = 2 } }, { 4, 7 })\n  validate_find1d('__a__b_', 0, { 'i', 'y' }, { 3, 3 })\nend\n\nT['gen_spec']['treesitter()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Mock tree-sitter queries\n      child.cmd('noautocmd set rtp+=tests/mock-treesitter')\n\n      -- Start editing reference file\n      child.cmd('edit tests/mock-treesitter/lua-file.lua')\n      child.lua('vim.treesitter.start()')\n\n      -- Define \"function definition\" textobject\n      child.lua([[MiniAi.config.custom_textobjects = {\n        F = MiniAi.gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' })\n      }]])\n    end,\n  },\n})\n\nT['gen_spec']['treesitter()']['works'] = function()\n  local lines = get_lines()\n  validate_find(lines, { 1, 0 }, { 'a', 'F' }, { { 3, 1 }, { 5, 3 } })\n  validate_find(lines, { 1, 0 }, { 'i', 'F' }, { { 4, 3 }, { 4, 38 } })\n  validate_find(lines, { 13, 0 }, { 'a', 'F' }, nil)\n\n  -- Should prefer match on current line over multiline covering\n  validate_find(lines, { 4, 0 }, { 'a', 'F' }, { { 4, 10 }, { 4, 38 } })\n\n  -- Should prefer range from metadata instead of node itself. This is useful,\n  -- for example, with `#offset!` directive to create more precise captures.\n  validate_find(lines, { 9, 0 }, { 'i', 'F' }, { { 8, 3 }, { 10, 13 } })\nend\n\nT['gen_spec']['treesitter()']['allows array of captures'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    o = MiniAi.gen_spec.treesitter({ a = { '@function.outer', '@return.outer' }, i = { '@function.inner', '@return.inner' } })\n  }]])\n\n  local lines = get_lines()\n  validate_find(lines, { 10, 2 }, { 'a', 'o' }, { { 10, 3 }, { 10, 13 } })\n  validate_find(lines, { 10, 2 }, { 'i', 'o' }, { { 10, 10 }, { 10, 13 } })\n\n  validate_find(lines, { 10, 2 }, { 'a', 'o', { n_times = 2 } }, { { 7, 7 }, { 11, 3 } })\n  validate_find(lines, { 10, 2 }, { 'i', 'o', { n_times = 2 } }, { { 8, 3 }, { 10, 13 } })\n\n  validate_find(lines, { 13, 0 }, { 'a', 'o' }, { { 13, 1 }, { 13, 8 } })\nend\n\nT['gen_spec']['treesitter()']['respects `opts.use_nvim_treesitter`'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    F = MiniAi.gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' }),\n    o = MiniAi.gen_spec.treesitter({ a = '@plugin_return', i = '@plugin_return' }),\n    O = MiniAi.gen_spec.treesitter(\n      { a = '@plugin_return', i = '@plugin_return' },\n      { use_nvim_treesitter = true }\n    )\n  }]])\n  local lines = get_lines()\n\n  -- By default it should be `false`\n  validate_find(lines, { 1, 0 }, { 'a', 'F' }, { { 3, 1 }, { 5, 3 } })\n  validate_find(lines, { 1, 0 }, { 'a', 'o' }, nil)\n  validate_find(lines, { 1, 0 }, { 'a', 'O' }, nil)\n\n  child.cmd('noautocmd set rtp+=tests/dir-ai/mock-nvim-treesitter')\n  validate_find(lines, { 1, 0 }, { 'a', 'F' }, { { 3, 1 }, { 5, 3 } })\n  validate_find(lines, { 1, 0 }, { 'a', 'o' }, nil)\n  validate_find(lines, { 1, 0 }, { 'a', 'O' }, { { 4, 3 }, { 4, 38 } })\n\n  -- Should prefer range from metadata instead of node itself. This is useful,\n  -- for example, with `#offset!` directive to create more precise captures.\n  validate_find(lines, { 9, 0 }, { 'i', 'F' }, { { 8, 3 }, { 10, 13 } })\nend\n\nT['gen_spec']['treesitter()']['works with directives'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    S = MiniAi.gen_spec.treesitter({ a = '@string', i = '@string_offset' }),\n  }]])\n  local lines = get_lines()\n  validate_find(lines, { 9, 9 }, { 'i', 'S' }, { { 9, 10 }, { 9, 16 } })\nend\n\nT['gen_spec']['treesitter()']['works with quantified captures'] = function()\n  if child.fn.has('nvim-0.10') == 0 then\n    MiniTest.skip('`Query:iter_matches()` returning several nodes requires Neovim>=0.10')\n  end\n\n  child.lua([[MiniAi.config.custom_textobjects = {\n    P = MiniAi.gen_spec.treesitter({ a = '@parameter.outer', i = '@parameter.inner' }),\n  }]])\n\n  -- \"Around\" parameter should include whitespace and comma\n  local lines = get_lines()\n  validate_find(lines, { 3, 0 }, { 'i', 'P' }, { { 3, 14 }, { 3, 14 } })\n  validate_find(lines, { 3, 0 }, { 'a', 'P' }, { { 3, 14 }, { 3, 15 } })\n  validate_find(lines, { 3, 0 }, { 'i', 'P', { n_times = 2 } }, { { 3, 17 }, { 3, 18 } })\n  validate_find(lines, { 3, 0 }, { 'a', 'P', { n_times = 2 } }, { { 3, 15 }, { 3, 18 } })\n  validate_find(lines, { 3, 0 }, { 'i', 'P', { n_times = 3 } }, { { 3, 21 }, { 3, 23 } })\n  validate_find(lines, { 3, 0 }, { 'a', 'P', { n_times = 3 } }, { { 3, 19 }, { 3, 23 } })\nend\n\nT['gen_spec']['treesitter()']['works with parent of injected language'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`LanguageTree:parent()` requires Neovim>=0.10') end\n\n  local lines = {\n    'local foo = function()',\n    '  vim.cmd([[',\n    'set cursorline',\n    ']])',\n    'end',\n  }\n  validate_find(lines, { 3, 0 }, { 'a', 'F' }, { { 1, 13 }, { 5, 3 } })\nend\n\nT['gen_spec']['treesitter()']['works with row-exclusive, col-0 end range'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = {\n    c = MiniAi.gen_spec.treesitter({ a = '@chunk.outer', i = '@chunk.outer' }),\n  }]])\n\n  local lines = get_lines()\n  validate_find(lines, { 1, 0 }, { 'a', 'c' }, { { 1, 1 }, { 13, 9 } })\nend\n\nT['gen_spec']['treesitter()']['respects plugin options'] = function()\n  local lines = get_lines()\n\n  -- `opts.n_lines`\n  child.lua('MiniAi.config.n_lines = 0')\n  validate_find(lines, { 9, 0 }, { 'a', 'F' }, nil)\n\n  -- `opts.search_method`\n  child.lua('MiniAi.config.n_lines = 50')\n  child.lua('MiniAi.config.search_method = \"next\"')\n  validate_find(lines, { 9, 0 }, { 'a', 'F' }, nil)\nend\n\nT['gen_spec']['treesitter()']['validates `ai_captures` argument'] = function()\n  local validate = function(args)\n    expect.error(function() child.lua('MiniAi.gen_spec.treesitter(...)', { args }) end, 'ai_captures')\n  end\n\n  validate('a')\n  validate({})\n  -- Each `a` and `i` should be a string starting with '@'\n  validate({ a = 1 })\n  validate({ a = 'function.outer' })\n  validate({ a = { 1 } })\n  validate({ a = { 'function.outer' } })\n  validate({ i = 1 })\n  validate({ i = 'function.inner' })\n  validate({ i = { 1 } })\n  validate({ i = { 'function.inner' } })\nend\n\nT['gen_spec']['treesitter()']['validates builtin treesitter presence'] = function()\n  -- Query\n  child.bo.filetype = 'vim'\n  expect.error(\n    function() child.lua('MiniAi.find_textobject(\"a\", \"F\")') end,\n    '%(mini%.ai%) Can not get query for buffer 1 and language \"vim\"%.'\n  )\n\n  -- - Should show local language in error message\n  child.cmd('edit tmp.lua')\n  set_lines({ 'vim.cmd([[', 'setlocal cursorline', ']])' })\n  set_cursor(2, 0)\n  expect.error(\n    function() child.lua('MiniAi.find_textobject(\"a\", \"F\")') end,\n    '%(mini%.ai%) Can not get query for buffer 2 and language \"vim\"%.'\n  )\n\n  -- Parser\n  child.cmd('enew')\n  child.bo.filetype = 'aaa'\n  expect.error(\n    function() child.lua('MiniAi.find_textobject(\"a\", \"F\")') end,\n    '%(mini%.ai%) Can not get parser for buffer 3 and language \"aaa\"%.'\n  )\n\n  -- - Should respect registered language for a filetype\n  child.lua('vim.treesitter.language.register(\"my_aaa\", \"aaa\")')\n  expect.error(\n    function() child.lua('MiniAi.find_textobject(\"a\", \"F\")') end,\n    '%(mini%.ai%) Can not get parser for buffer 3 and language \"my_aaa\"%.'\n  )\n\n  -- - Should show each language\n  if child.fn.has('nvim-0.10') == 0 then return end\n  child.cmd('enew')\n  child.bo.filetype = 'help'\n  set_lines({ '>vim', '    set cursorline', '<' })\n  set_cursor(2, 0)\n  expect.error(\n    function() child.lua('MiniAi.find_textobject(\"a\", \"F\")') end,\n    '%(mini%.ai%) Can not get query for buffer 3 and languages \"vim\", \"vimdoc\"%.'\n  )\n\n  -- - Should show each language once\n  child.cmd('edit tmp.vim')\n  set_lines({ 'set indentexpr=VimIndent()' })\n  set_cursor(1, 0)\n  expect.error(\n    function() child.lua('MiniAi.find_textobject(\"a\", \"F\")') end,\n    '%(mini%.ai%) Can not get query for buffer 4 and language \"vim\"%.'\n  )\nend\n\nT['gen_spec']['user_prompt()'] = new_set()\n\n-- More tests are done in `T['Builtin']['User prompt']`\nT['gen_spec']['user_prompt()']['works'] = function()\n  -- Define custom \"user prompt\" textobject\n  child.lua('MiniAi.config.custom_textobjects = { [\"/\"] = MiniAi.gen_spec.user_prompt() }')\n\n  -- Single character edges\n  validate_tobj1d('__e__o__', 0, 'a/e<CR>o<CR>', { 3, 6 })\n  validate_tobj1d('__e__o__', 0, 'i/e<CR>o<CR>', { 4, 5 })\n\n  -- Multiple character edges\n  validate_tobj1d('__ef__op__', 0, 'a/ef<CR>op<CR>', { 3, 8 })\n  validate_tobj1d('__ef__op__', 0, 'i/ef<CR>op<CR>', { 5, 6 })\n\n  -- Supports dot-repeat\n  set_lines({ '_e--o_', '+e---o+' })\n  set_cursor(1, 0)\n  type_keys('da', '/', 'e<CR>', 'o<CR>')\n  eq(get_lines(), { '__', '+e---o+' })\n  type_keys('j', '.')\n  eq(get_lines(), { '__', '++' })\n\n  set_lines({ '_r--t_' })\n  set_cursor(1, 0)\n  type_keys('di', '/', 'r<CR>', 't<CR>')\n  eq(get_lines(), { '_rt_' })\nend\n\nlocal validate_select = function(lines, cursor, args, expected)\n  child.ensure_normal_mode()\n  set_lines(lines)\n  set_cursor(unpack(cursor))\n  child.lua([[MiniAi.select_textobject(...)]], args)\n\n  local expected_mode = (args[3] or {}).vis_mode or 'v'\n  eq(get_mode(), vim.api.nvim_replace_termcodes(expected_mode, true, true, true))\n\n  -- Allow supplying number items to verify linewise selection\n  local expected_from = type(expected[1]) == 'number' and expected[1] or { expected[1][1], expected[1][2] - 1 }\n  local expected_to = type(expected[2]) == 'number' and expected[2] or { expected[2][1], expected[2][2] - 1 }\n  child.expect_visual_marks(expected_from, expected_to)\nend\n\nlocal validate_select1d = function(line, column, args, expected)\n  validate_select({ line }, { 1, column }, args, { { 1, expected[1] }, { 1, expected[2] } })\nend\n\nT['select_textobject()'] = new_set()\n\nT['select_textobject()']['works'] = function() validate_select1d('aa(bb)', 3, { 'a', ')' }, { 3, 6 }) end\n\nT['select_textobject()']['respects `ai_type` argument'] = function()\n  validate_select1d('aa(bb)', 3, { 'i', ')' }, { 4, 5 })\nend\n\nT['select_textobject()']['respects `id` argument'] = function()\n  validate_select1d('aa[bb]', 3, { 'a', ']' }, { 3, 6 })\n  validate_select1d('aa[bb]', 3, { 'i', ']' }, { 4, 5 })\nend\n\nT['select_textobject()']['respects `opts` argument'] = function()\n  validate_select1d('aa(bb)cc(dd)', 4, { 'a', ')', { n_times = 2 } }, { 9, 12 })\nend\n\nT['select_textobject()']['respects `opts.vis_mode`'] = function()\n  local lines, cursor = { '(a', 'a', 'a)' }, { 2, 0 }\n  validate_select(lines, cursor, { 'a', ')', { vis_mode = 'v' } }, { { 1, 1 }, { 3, 2 } })\n  validate_select(lines, cursor, { 'a', ')', { vis_mode = 'V' } }, { 1, 3 })\n  validate_select(lines, cursor, { 'a', ')', { vis_mode = '<C-v>' } }, { { 1, 1 }, { 3, 2 } })\nend\n\nT['select_textobject()']['works with empty region'] = function() validate_select1d('a()', 0, { 'i', ')' }, { 3, 3 }) end\n\nT['select_textobject()']['allows selecting past line end'] = function()\n  child.o.virtualedit, child.o.whichwrap = 'block', 'b,s'\n  validate_select({ '(', 'a', ')' }, { 2, 0 }, { 'i', ')' }, { { 1, 2 }, { 2, 2 } })\n  eq(child.o.virtualedit, 'block')\n  eq(child.o.whichwrap, 'b,s')\nend\n\nT['select_textobject()'][\"respects 'selection=exclusive'\"] = function()\n  child.o.selection = 'exclusive'\n\n  local validate = function(ai_type, after)\n    set_lines({ ' (aaa) ' })\n    set_cursor(1, 3)\n    child.lua([[MiniAi.select_textobject(...)]], { ai_type, ')' })\n    type_keys('d')\n    eq(get_lines(), { after })\n  end\n\n  validate('i', ' () ')\n  validate('a', '  ')\n\n  -- Works with empty regions\n  validate_select1d(' () ', 0, { 'i', ')' }, { 3, 3 })\nend\n\nT['select_textobject()']['respects `vis_mode` from textobject region'] = function()\n  -- Should respect `vis_mode` in a region\n  local validate = function(tobj_vis_mode, type_vis_mode)\n    local lua_cmd = string.format(\n      [[_G.cur_line = function(ai_type, id, opts)\n        return { from = { line = vim.fn.line('.'), col = 1 }, vis_mode = '%s' }\n      end]],\n      tobj_vis_mode\n    )\n    child.lua(lua_cmd)\n    child.lua([[MiniAi.config.custom_textobjects = { c = _G.cur_line }]])\n\n    set_lines({ 'aaaa', 'bbbb' })\n    type_keys(type_vis_mode, 'ac')\n    eq(child.fn.mode(), tobj_vis_mode)\n\n    child.ensure_normal_mode()\n  end\n\n  validate('v', 'V')\n  validate('v', '\\22')\n  validate('V', 'v')\n  validate('V', '\\22')\n  validate('\\22', 'v')\n  validate('\\22', 'V')\nend\n\nT['Search method'] = new_set()\n\nT['Search method']['works with \"cover\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'cover' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('aa (bb) cc', 4, { 4, 7 })\n  validate1d('aa (bb) cc', 0, nil)\n  validate1d('aa (bb) cc', 9, nil)\n  validate({ '(', 'a', ')' }, { 2, 0 }, { { 1, 1 }, { 3, 1 } })\n\n  -- Works when cursor is on edge\n  validate1d('aa(bb)', 2, { 3, 6 })\n  validate1d('aa(bb)', 5, { 3, 6 })\n\n  -- Should prefer smallest covering\n  validate1d('((a))', 2, { 2, 4 })\n\n  -- Should ignore any non-covering textobject on current line\n  validate({ '(', '(aa) bb (cc)', ')' }, { 2, 5 }, { { 1, 1 }, { 3, 1 } })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(', '(aa (bb) (cc))', ')' }, { 2, 5 }\n  validate_n_times(lines, cursor, 1, { { 2, 5 }, { 2, 8 } })\n  validate_n_times(lines, cursor, 2, { { 2, 1 }, { 2, 14 } })\n  validate_n_times(lines, cursor, 3, { { 1, 1 }, { 3, 1 } })\nend\n\nT['Search method']['works with \"cover\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'cover']])\n\n  for i = 3, 6 do\n    validate_edit1d('(aa(bb))', i, '(aa)', 3, 'ca)')\n    validate_edit1d('(aa(bb))', i, '(aa)', 3, 'da)')\n\n    validate_edit1d('(aa(bb))', i, '(aa())', 4, 'ci)')\n    validate_edit1d('(aa(bb))', i, '(aa())', 4, 'di)')\n  end\nend\n\nT['Search method']['works with \"cover_or_next\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover_or_next' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'cover_or_next' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('aa (bb)', 0, { 4, 7 })\n  validate({ 'aa', '(bb)' }, { 1, 0 }, { { 2, 1 }, { 2, 4 } })\n\n  -- Works when cursor is on edge\n  validate1d('aa(bb)', 2, { 3, 6 })\n  validate1d('aa(bb)', 5, { 3, 6 })\n\n  -- Should prefer covering textobject if both are on the same line\n  validate1d('(aa) (bb)', 2, { 1, 4 })\n  validate1d('(aa (bb))', 2, { 1, 9 })\n\n  -- Should prefer covering textobject if both are not on the same line\n  validate({ '(aa', ') (bb)' }, { 1, 1 }, { { 1, 1 }, { 2, 1 } })\n\n  -- Should prefer next textobject if covering is not on same line\n  validate({ '(a (bb)', ')' }, { 1, 1 }, { { 1, 4 }, { 1, 7 } })\n\n  -- Should ignore presence of \"previous\" textobject (even on same line)\n  validate({ '(aa) bb (cc)' }, { 1, 5 }, { { 1, 9 }, { 1, 12 } })\n  validate({ '(aa) bb', '(cc)' }, { 1, 5 }, { { 2, 1 }, { 2, 4 } })\n  validate({ '(aa) (', '(bb) cc)' }, { 2, 5 }, { { 1, 6 }, { 2, 8 } })\n\n  -- Should choose closest textobject based on distance between left edges\n  validate1d('aa(bb(cc)dddddddddd)', 0, { 3, 20 })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover_or_next', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(', 'aa (bb) (cc) )' }, { 2, 0 }\n  validate_n_times(lines, cursor, 1, { { 2, 4 }, { 2, 7 } })\n  validate_n_times(lines, cursor, 2, { { 2, 9 }, { 2, 12 } })\n  validate_n_times(lines, cursor, 3, { { 1, 1 }, { 2, 14 } })\nend\n\nT['Search method']['works with \"cover_or_next\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'cover_or_next']])\n\n  for i = 4, 10 do\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb', 7, 'ca)')\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb', 6, 'da)')\n\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb()', 8, 'ci)')\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb()', 8, 'di)')\n  end\nend\n\nT['Search method']['works with \"cover_or_prev\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover_or_prev' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'cover_or_prev' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('(aa) bb', 5, { 1, 4 })\n  validate({ '(aa)', 'bb' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n\n  -- Works when cursor is on edge\n  validate1d('aa(bb)', 2, { 3, 6 })\n  validate1d('aa(bb)', 5, { 3, 6 })\n\n  -- Should prefer covering textobject if both are on the same line\n  validate1d('(aa) (bb)', 6, { 6, 9 })\n  validate1d('((aa) bb)', 6, { 1, 9 })\n\n  -- Should prefer covering textobject if both are not on the same line\n  validate({ '((aa)', 'bb)' }, { 2, 0 }, { { 1, 1 }, { 2, 3 } })\n\n  -- Should prefer previous textobject if covering is not on same line\n  validate({ '((aa) b', ')' }, { 1, 6 }, { { 1, 2 }, { 1, 5 } })\n\n  -- Should ignore presence of \"next\" textobject (even on same line)\n  validate({ '(aa) bb (cc)' }, { 1, 5 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa)', 'bb (cc)' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa) (', 'bb (cc))' }, { 2, 0 }, { { 1, 6 }, { 2, 8 } })\n\n  -- Should choose closest textobject based on distance between right edges\n  validate1d('(aaaaaaaaaa(bb)cc)dd', 19, { 1, 18 })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover_or_prev', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(', '(aa) (bb) cc )' }, { 2, 10 }\n  validate_n_times(lines, cursor, 1, { { 2, 6 }, { 2, 9 } })\n  validate_n_times(lines, cursor, 2, { { 2, 1 }, { 2, 4 } })\n  validate_n_times(lines, cursor, 3, { { 1, 1 }, { 2, 14 } })\nend\n\nT['Search method']['works with \"cover_or_prev\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'cover_or_prev']])\n\n  for i = 0, 6 do\n    validate_edit1d('(aa)bbb(cc)', i, 'bbb(cc)', 0, 'ca)')\n    validate_edit1d('(aa)bbb(cc)', i, 'bbb(cc)', 0, 'da)')\n\n    validate_edit1d('(aa)bbb(cc)', i, '()bbb(cc)', 1, 'ci)')\n    validate_edit1d('(aa)bbb(cc)', i, '()bbb(cc)', 1, 'di)')\n  end\nend\n\nT['Search method']['works with \"cover_or_nearest\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover_or_nearest' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'cover_or_nearest' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('(aa) bbb (cc)', 5, { 1, 4 })\n  validate1d('(aa) bbb (cc)', 6, { 1, 4 })\n  validate1d('(aa) bbb (cc)', 7, { 10, 13 })\n\n  validate({ '(aa)', 'bbb', '(cc)' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa)', 'bbb', '(cc)' }, { 2, 1 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa)', 'bbb', '(cc)' }, { 2, 2 }, { { 3, 1 }, { 3, 4 } })\n\n  -- Works when cursor is on edge\n  validate1d('aa(bb)', 2, { 3, 6 })\n  validate1d('aa(bb)', 5, { 3, 6 })\n\n  -- Should prefer covering textobject if alternative is on the same line\n  validate1d('((aa)  (bb))', 5, { 1, 12 })\n  validate1d('((aa)  (bb))', 6, { 1, 12 })\n\n  -- Should prefer covering textobject if both are not on the same line\n  validate({ '(aa', ') (bb)' }, { 1, 1 }, { { 1, 1 }, { 2, 1 } })\n  validate({ '((aa)', 'bb)' }, { 2, 0 }, { { 1, 1 }, { 2, 3 } })\n\n  -- Should prefer nearest textobject if covering is not on same line\n  validate({ '((aa) bbb (cc)', ')' }, { 1, 6 }, { { 1, 2 }, { 1, 5 } })\n  validate({ '((aa) bbb (cc)', ')' }, { 1, 7 }, { { 1, 2 }, { 1, 5 } })\n  validate({ '((aa) bbb (cc)', ')' }, { 1, 8 }, { { 1, 11 }, { 1, 14 } })\n\n  -- Should choose closest textobject based on minimum distance between\n  -- corresponding edges\n  local validate_distance = function(region_cols, expected)\n    local reference_region = { from = { line = 1, col = region_cols[1] }, to = { line = 1, col = region_cols[2] } }\n    validate_find1d(\n      '(aa)bbb(cc)',\n      0,\n      { 'a', ')', { search_method = 'cover_or_nearest', reference_region = reference_region } },\n      expected\n    )\n  end\n\n  validate_distance({ 2, 5 }, { 1, 4 })\n  validate_distance({ 2, 9 }, { 1, 4 })\n  validate_distance({ 5, 6 }, { 1, 4 })\n  validate_distance({ 5, 7 }, { 1, 4 })\n  validate_distance({ 6, 7 }, { 8, 11 })\n  validate_distance({ 3, 10 }, { 8, 11 })\n  validate_distance({ 7, 10 }, { 8, 11 })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'cover_or_nearest', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(aaaaa', '(bb) cc (dd))' }, { 2, 5 }\n  validate_n_times(lines, cursor, 1, { { 2, 1 }, { 2, 4 } })\n  validate_n_times(lines, cursor, 2, { { 2, 9 }, { 2, 12 } })\n  -- It enters cycle because two textobjects are nearest to each other\n  validate_n_times(lines, cursor, 3, { { 2, 1 }, { 2, 4 } })\nend\n\nT['Search method']['works with \"cover_or_nearest\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'cover_or_nearest']])\n\n  for i = 0, 5 do\n    validate_edit1d('(aa)bbb(cc)', i, 'bbb(cc)', 0, 'ca)')\n    validate_edit1d('(aa)bbb(cc)', i, 'bbb(cc)', 0, 'da)')\n\n    validate_edit1d('(aa)bbb(cc)', i, '()bbb(cc)', 1, 'ci)')\n    validate_edit1d('(aa)bbb(cc)', i, '()bbb(cc)', 1, 'di)')\n  end\n  for i = 6, 10 do\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb', 7, 'ca)')\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb', 6, 'da)')\n\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb()', 8, 'ci)')\n    validate_edit1d('(aa)bbb(cc)', i, '(aa)bbb()', 8, 'di)')\n  end\nend\n\nT['Search method']['works with \"next\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'next' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'next' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('aa (bb)', 0, { 4, 7 })\n  validate({ 'aa', '(bb)' }, { 1, 0 }, { { 2, 1 }, { 2, 4 } })\n\n  -- Works when cursor is on edge (should prefer next one)\n  validate1d('aa(bb)(cc)', 2, { 7, 10 })\n  validate1d('aa(bb)(cc)', 5, { 7, 10 })\n\n  -- Should NOT prefer covering textobject if both are on the same line\n  validate1d('(aa) (bb)', 2, { 6, 9 })\n  validate1d('(aa (bb))', 2, { 5, 8 })\n\n  -- Should NOT prefer covering textobject if both are not on the same line\n  validate({ '(aa', ') (bb)' }, { 1, 1 }, { { 2, 3 }, { 2, 6 } })\n\n  -- Should prefer next textobject if covering is not on same line\n  validate({ '(a (bb)', ')' }, { 1, 1 }, { { 1, 4 }, { 1, 7 } })\n\n  -- Should ignore presence of \"previous\" textobject (even on same line)\n  validate({ '(aa) bb (cc)' }, { 1, 5 }, { { 1, 9 }, { 1, 12 } })\n  validate({ '(aa) bb', '(cc)' }, { 1, 5 }, { { 2, 1 }, { 2, 4 } })\n  validate({ '(aa) (', '(bb) cc)' }, { 2, 5 }, nil)\n\n  -- Should choose closest textobject based on distance between left edges\n  validate1d('aa(bb(cc)dddddddddd)', 0, { 3, 20 })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'next', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(', 'aa (bb) (cc) )' }, { 2, 0 }\n  validate_n_times(lines, cursor, 1, { { 2, 4 }, { 2, 7 } })\n  validate_n_times(lines, cursor, 2, { { 2, 9 }, { 2, 12 } })\n  validate_n_times(lines, cursor, 3, nil)\nend\n\nT['Search method']['works with \"next\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'next']])\n\n  for i = 4, 8 do\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)', 9, 'ca)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)', 8, 'da)')\n\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)()', 10, 'ci)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)()', 10, 'di)')\n  end\nend\n\nT['Search method']['works with \"prev\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'prev' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'prev' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('(aa) bb', 5, { 1, 4 })\n  validate({ '(aa)', 'bb' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n\n  -- Works when cursor is on edge\n  validate1d('(aa)(bb)', 4, { 1, 4 })\n  validate1d('(aa)(bb)', 7, { 1, 4 })\n\n  -- Should NOT prefer covering textobject if both are on the same line\n  validate1d('(aa) (bb)', 6, { 1, 4 })\n  validate1d('((aa) bb)', 6, { 2, 5 })\n\n  -- Should NOT prefer covering textobject if both are not on the same line\n  validate({ '((aa)', 'bb)' }, { 2, 0 }, { { 1, 2 }, { 1, 5 } })\n\n  -- Should ignore presence of \"next\" textobject (even on same line)\n  validate({ '(aa) bb (cc)' }, { 1, 5 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa)', 'bb (cc)' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa) (', 'bb (cc))' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n\n  -- Should choose closest textobject based on distance between right edges\n  validate1d('(aaaaaaaaaa(bb)cc)dd', 19, { 1, 18 })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'prev', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(', '(aa) (bb) cc )' }, { 2, 10 }\n  validate_n_times(lines, cursor, 1, { { 2, 6 }, { 2, 9 } })\n  validate_n_times(lines, cursor, 2, { { 2, 1 }, { 2, 4 } })\n  validate_n_times(lines, cursor, 3, nil)\nend\n\nT['Search method']['works with \"prev\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'prev']])\n\n  for i = 4, 8 do\n    validate_edit1d('(aa)(bbb)(cc)', i, '(bbb)(cc)', 0, 'ca)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '(bbb)(cc)', 0, 'da)')\n\n    validate_edit1d('(aa)(bbb)(cc)', i, '()(bbb)(cc)', 1, 'ci)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '()(bbb)(cc)', 1, 'di)')\n  end\nend\n\nT['Search method']['works with \"nearest\"'] = function()\n  local validate = function(lines, cursor, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'nearest' } }, expected)\n  end\n\n  local validate1d = function(line, column, expected)\n    validate_find1d(line, column, { 'a', ')', { search_method = 'nearest' } }, expected)\n  end\n\n  -- Works (on same line and on multiple lines)\n  validate1d('(aa) bbb (cc)', 5, { 1, 4 })\n  validate1d('(aa) bbb (cc)', 6, { 1, 4 })\n  validate1d('(aa) bbb (cc)', 7, { 10, 13 })\n\n  validate({ '(aa)', 'bbb', '(cc)' }, { 2, 0 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa)', 'bbb', '(cc)' }, { 2, 1 }, { { 1, 1 }, { 1, 4 } })\n  validate({ '(aa)', 'bbb', '(cc)' }, { 2, 2 }, { { 3, 1 }, { 3, 4 } })\n\n  -- Works when cursor is on edge\n  validate1d('(aa)(bb)(cc)', 4, { 1, 4 })\n  validate1d('(aa)(bb)(cc)', 7, { 9, 12 })\n\n  -- Should NOT prefer covering textobject if alternative is on the same line\n  validate1d('((aa)   (bb))', 5, { 2, 5 })\n  validate1d('((aa)   (bb))', 7, { 9, 12 })\n  -- Here is it still left because distance is measured for empty region at\n  -- cursor (for which left block is closer)\n  validate1d('((aa)  (bb))', 6, { 2, 5 })\n\n  -- Should NOT prefer covering textobject if both are not on the same line\n  validate({ '(aa', ') (bb)' }, { 1, 1 }, { { 2, 3 }, { 2, 6 } })\n  validate({ '((aa)', 'bb)' }, { 2, 0 }, { { 1, 2 }, { 1, 5 } })\n\n  -- Should prefer nearest textobject if covering is not on same line\n  validate({ '((aa) bbb (cc)', ')' }, { 1, 6 }, { { 1, 2 }, { 1, 5 } })\n  validate({ '((aa) bbb (cc)', ')' }, { 1, 7 }, { { 1, 2 }, { 1, 5 } })\n  validate({ '((aa) bbb (cc)', ')' }, { 1, 8 }, { { 1, 11 }, { 1, 14 } })\n\n  -- Should choose closest textobject based on minimum distance between\n  -- corresponding edges\n  local validate_distance = function(region_cols, expected)\n    local reference_region = { from = { line = 1, col = region_cols[1] }, to = { line = 1, col = region_cols[2] } }\n    validate_find1d(\n      '(aa)bbb(cc)',\n      0,\n      { 'a', ')', { search_method = 'nearest', reference_region = reference_region } },\n      expected\n    )\n  end\n\n  validate_distance({ 2, 5 }, { 1, 4 })\n  validate_distance({ 2, 9 }, { 1, 4 })\n  validate_distance({ 5, 6 }, { 1, 4 })\n  validate_distance({ 5, 7 }, { 1, 4 })\n  validate_distance({ 6, 7 }, { 8, 11 })\n  validate_distance({ 3, 10 }, { 8, 11 })\n  validate_distance({ 7, 10 }, { 8, 11 })\n\n  -- Works with `n_times`\n  local validate_n_times = function(lines, cursor, n_times, expected)\n    validate_find(lines, cursor, { 'a', ')', { search_method = 'nearest', n_times = n_times } }, expected)\n  end\n\n  local lines, cursor = { '(aaaaa', '(bb) cc (dd))' }, { 2, 5 }\n  validate_n_times(lines, cursor, 1, { { 2, 1 }, { 2, 4 } })\n  validate_n_times(lines, cursor, 2, { { 2, 9 }, { 2, 12 } })\n  -- It enters cycle because two textobjects are nearest to each other\n  validate_n_times(lines, cursor, 3, { { 2, 1 }, { 2, 4 } })\nend\n\nT['Search method']['works with \"nearest\" in Operator-pending mode'] = function()\n  child.lua([[MiniAi.config.search_method = 'nearest']])\n\n  for i = 4, 6 do\n    validate_edit1d('(aa)(bbb)(cc)', i, '(bbb)(cc)', 0, 'ca)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '(bbb)(cc)', 0, 'da)')\n\n    validate_edit1d('(aa)(bbb)(cc)', i, '()(bbb)(cc)', 1, 'ci)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '()(bbb)(cc)', 1, 'di)')\n  end\n  for i = 7, 8 do\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)', 9, 'ca)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)', 8, 'da)')\n\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)()', 10, 'ci)')\n    validate_edit1d('(aa)(bbb)(cc)', i, '(aa)(bbb)()', 10, 'di)')\n  end\nend\n\n-- Integration tests ==========================================================\nT['Textobject'] = new_set()\n\nT['Textobject']['works in Visual mode'] = function()\n  local lines, cursor = { 'aa(bb', 'cccc', 'dd)ee' }, { 2, 0 }\n  validate_tobj(lines, cursor, 'a)', { { 1, 3 }, { 3, 3 } }, 'v')\n  validate_tobj(lines, cursor, 'a)', { 1, 3 }, 'V')\n  validate_tobj(lines, cursor, 'a)', { { 1, 3 }, { 3, 3 } }, '<C-v>')\n\n  -- Exits Visual mode if textobject is not found\n  set_lines({ 'aa' })\n  set_cursor(1, 0)\n\n  type_keys('v', 'a)')\n  eq(get_cursor(), { 1, 0 })\n  expect.match(get_latest_message(), 'a%)')\n  eq(get_mode(), 'n')\nend\n\nT['Textobject']['works in Operator-pending mode'] = function()\n  local lines, cursor = { 'aa(bb', 'cccc', 'dd)ee' }, { 2, 0 }\n  validate_edit(lines, cursor, { 'aaee' }, { 1, 2 }, 'da)')\n  validate_edit(lines, cursor, { 'aaee' }, { 1, 2 }, 'dva)')\n  validate_edit(lines, cursor, { '' }, { 1, 0 }, 'dVa)')\n  validate_edit(lines, cursor, { 'aabb', 'ccc', 'ddee' }, { 1, 2 }, 'd<C-v>a)')\nend\n\nT['Textobject']['can be cancelled'] = function()\n  local validate = function(keys, mode)\n    set_lines({ 'aaa' })\n    set_cursor(1, 1)\n    type_keys(keys, '<Esc>')\n\n    eq(child.api.nvim_get_mode().mode, mode)\n    type_keys('<Esc>')\n\n    eq(get_lines(), { 'aaa' })\n    eq(get_cursor(), { 1, 1 })\n\n    child.ensure_normal_mode()\n  end\n\n  -- Visual mode should be cancelled without leaving Visual mode\n  validate({ 'v', 'i' }, 'v')\n\n  -- Operator-pending mode should be cancelled into Normal mode\n  validate({ 'd', 'i' }, 'n')\nend\n\nT['Textobject']['works with different mappings'] = function()\n  reload_module({ mappings = { around = 'A', inside = 'I' } })\n\n  validate_tobj1d('aa(bb)', 0, 'A)', { 3, 6 })\n  validate_tobj1d('aa(bb)', 0, 'I)', { 4, 5 })\nend\n\nT['Textobject']['allows dot-repeat'] = function()\n  set_lines({ '((aa)bb)', '(cc)dd' })\n  set_cursor(1, 2)\n\n  type_keys('da)')\n  eq(get_lines(), { '(bb)', '(cc)dd' })\n  eq(get_cursor(), { 1, 1 })\n\n  type_keys('.')\n  eq(get_lines(), { '', '(cc)dd' })\n  eq(get_cursor(), { 1, 0 })\n\n  -- Allows not immediate dot-repeat\n  type_keys('j', '.')\n  eq(get_lines(), { '', 'dd' })\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['Textobject']['collapses multiline textobject'] = function()\n  local lines = { '(', 'a', ')' }\n  validate_edit(lines, { 2, 0 }, { '' }, { 1, 0 }, 'da)')\n\n  local validate = function()\n    validate_edit(lines, { 1, 0 }, { '()' }, { 1, 1 }, 'di)')\n    validate_edit(lines, { 2, 0 }, { '()' }, { 1, 1 }, 'di)')\n    validate_edit(lines, { 3, 0 }, { '()' }, { 1, 1 }, 'di)')\n  end\n\n  child.o.selection = 'inclusive'\n  validate()\n  child.o.selection = 'exclusive'\n  validate()\nend\n\nT['Textobject']['works with multibyte characters'] = function()\n  -- Each multibyte character takes two column counts\n  local line = '(ыы)ффф(ыы)'\n  validate_edit1d(line, 1, 'ффф(ыы)', 0, 'da)')\n  validate_edit1d(line, 1, '()ффф(ыы)', 1, 'di)')\n  validate_edit1d(line, 6, '(ыы)ффф', 10, 'da)')\n  validate_edit1d(line, 6, '(ыы)ффф()', 13, 'di)')\nend\n\nT['Textobject']['respects `v:count`'] = function()\n  validate_tobj1d('(aa)bb(cc)dd(ee)', 0, '2a)', { 7, 10 })\n  validate_tobj1d('(aa)bb(cc)dd(ee)', 0, '3a)', { 13, 16 })\n\n  -- Don't do anything if not enough is present\n  validate_no_tobj1d('(aa)bb(cc)dd(ee)', 0, '4a)')\nend\n\nT['Textobject'][\"respects 'selection=exclusive'\"] = function()\n  child.o.selection = 'exclusive'\n\n  local validate = function(ai_type, after)\n    set_lines({ ' (aaa) ' })\n    set_cursor(1, 2)\n    type_keys('v', ai_type, ')', 'd')\n    eq(get_lines(), { after })\n  end\n\n  validate('i', ' () ')\n  validate('a', '  ')\nend\n\nT['Textobject']['falls back in case of absent textobject id'] = function()\n  -- Set low `timeoutlen` to simulate its expiration\n  child.o.timeoutlen = 5\n\n  local validate = function(line, column, keys, expected)\n    child.ensure_normal_mode()\n    set_lines({ line })\n    set_cursor(1, column)\n    type_keys(10, 'v', keys[1], keys[2])\n\n    child.expect_visual_marks({ 1, expected[1] - 1 }, { 1, expected[2] - 1 })\n  end\n\n  -- Builtin textobject\n  local pattern = 'mini.*ai'\n  -- Visual mode\n  expect.match(child.fn.maparg('a', 'x'), pattern)\n  validate('aaa bbb', 0, { 'a', 'w' }, { 1, 4 })\n\n  expect.match(child.fn.maparg('i', 'x'), pattern)\n  validate('aaa bbb', 0, { 'i', 'w' }, { 1, 3 })\n\n  -- Operator-pending mode\n  expect.match(child.fn.maparg('a', 'o'), pattern)\n  validate_edit1d('aaa bbb', 0, 'bbb', 0, 20, 'd', 'a', 'w')\n\n  expect.match(child.fn.maparg('i', 'o'), pattern)\n  validate_edit1d('aaa bbb', 0, ' bbb', 0, 10, 'd', 'i', 'w')\n\n  -- Custom textobject\n  local map = function(mode, lhs)\n    child.api.nvim_set_keymap(mode, lhs, '<Cmd>lua vim.api.nvim_win_set_cursor(0, { 1, 5 })<CR>', { noremap = true })\n  end\n\n  -- Visual mode\n  map('x', 'ac')\n  validate('aaa bbb', 0, { 'a', 'c' }, { 1, 6 })\n\n  map('x', 'ic')\n  validate('aaa bbb', 0, { 'i', 'c' }, { 1, 6 })\n\n  -- Operator-pending mode\n  map('o', 'ac')\n  validate_edit1d('aaa bbb', 0, 'bb', 0, 10, 'd', 'a', 'c')\n\n  map('o', 'ic')\n  validate_edit1d('aaa bbb', 0, 'bb', 0, 10, 'd', 'i', 'c')\nend\n\nT['Textobject']['falls back in case of absent textobject id and different main mapping'] = function()\n  reload_module({ mappings = { around = 'A', inside = 'I' } })\n\n  -- Set low `timeoutlen` to simulate its expiration\n  child.o.timeoutlen = 5\n\n  local validate = function(line, column, keys, expected)\n    child.ensure_normal_mode()\n    set_lines({ line })\n    set_cursor(1, column)\n    type_keys(10, 'v', keys[1], keys[2])\n\n    child.expect_visual_marks({ 1, expected[1] - 1 }, { 1, expected[2] - 1 })\n  end\n\n  -- Custom textobject\n  local map = function(mode, lhs)\n    child.api.nvim_set_keymap(mode, lhs, '<Cmd>lua vim.api.nvim_win_set_cursor(0, { 1, 5 })<CR>', { noremap = true })\n  end\n\n  -- Visual mode\n  map('x', 'Ac')\n  validate('aaa bbb', 0, { 'A', 'c' }, { 1, 6 })\n\n  map('x', 'Ic')\n  validate('aaa bbb', 0, { 'I', 'c' }, { 1, 6 })\n\n  -- Operator-pending mode\n  map('o', 'Ac')\n  validate_edit1d('aaa bbb', 0, 'bb', 0, 10, 'd', 'A', 'c')\n\n  map('o', 'Ic')\n  validate_edit1d('aaa bbb', 0, 'bb', 0, 10, 'd', 'I', 'c')\nend\n\nT['Textobject'][\"works with 'langmap'\"] = function()\n  -- Useful for different keyboard layouts. See\n  -- https://github.com/nvim-mini/mini.nvim/issues/195\n  child.o.langmap = 'ki,ik'\n\n  local validate_visual = function(line, column, keys, expected)\n    child.ensure_normal_mode()\n    set_lines({ line })\n    set_cursor(1, column)\n    type_keys(10, 'v', keys[1], keys[2])\n\n    child.expect_visual_marks({ 1, expected[1] - 1 }, { 1, expected[2] - 1 })\n  end\n\n  local map = function(mode, lhs)\n    child.api.nvim_set_keymap(mode, lhs, '<Cmd>lua vim.api.nvim_win_set_cursor(0, { 1, 5 })<CR>', { noremap = true })\n  end\n\n  -- Visual mode\n  -- - Registered textobject\n  validate_visual('aa(bb)cc', 3, { 'k', ')' }, { 4, 5 })\n\n  -- - Default textobject\n  validate_visual('aa bb cc', 3, { 'k', 'w' }, { 4, 5 })\n\n  -- - Custom textobject\n  map('x', 'ic')\n  validate_visual('aa bb cc', 3, { 'k', 'c' }, { 4, 6 })\n\n  -- Operator-pending mode\n  -- - Registered textobject\n  validate_edit1d('aa(bb)cc', 3, 'aa()cc', 3, 'dk)')\n\n  -- - Default textobject\n  validate_edit1d('aa bb cc', 3, 'aa  cc', 3, 'dkw')\n\n  -- - Custom textobject\n  map('o', 'ic')\n  validate_edit1d('aa bb cc', 3, 'aa  cc', 3, 'dkc')\nend\n\nT['Textobject']['works with empty output region'] = function()\n  local validate = function(start_column)\n    validate_edit1d('a()b', start_column, 'a()b', 2, 'ci)')\n    eq(get_mode(), 'i')\n\n    validate_edit1d('a()b', start_column, 'a()b', 2, 'di)')\n  end\n\n  validate(0)\n  validate(1)\n\n  child.o.selection = 'exclusive'\n  validate(0)\n  validate(1)\nend\n\nT['Textobject']['handles horizontal view for out of view textobjects'] = function()\n  child.o.wrap = false\n  child.set_size(10, 25)\n\n  local validate = function(line, cursor_col, leftcol, keys, ref_leftcol)\n    set_lines({ line })\n    set_cursor(1, cursor_col)\n    child.fn.winrestview({ leftcol = leftcol })\n    type_keys(keys)\n    eq(child.fn.winsaveview().leftcol, ref_leftcol)\n\n    child.ensure_normal_mode()\n  end\n\n  -- Should try to do as least horizontal scroll as possible\n  local partially_visible_right = 'abcdefghijklmnopqrst \"xxxxx\"'\n  validate(partially_visible_right, 0, 0, { 'c', 'i', '\"' }, 0)\n  validate(partially_visible_right, 0, 0, { 'v', 'i', '\"' }, 2)\n\n  local completely_to_right = 'abcdefghijklmnopqrst        \"xxxxx\"'\n  validate(completely_to_right, 0, 0, { 'c', 'i', '\"' }, 5)\n  validate(completely_to_right, 0, 0, { 'v', 'i', '\"' }, 9)\n\n  local partially_visible_left = '\"xxxxx\" abcdefghijklmnopqrst'\n  validate(partially_visible_left, 8, 3, { 'c', 'il', '\"' }, 1)\n  validate(partially_visible_left, 8, 3, { 'v', 'il', '\"' }, 3)\n\n  local completely_to_left = '\"xxxxx\"        abcdefghijklmnopqrst'\n  validate(completely_to_left, 34, 10, { 'c', 'il', '\"' }, 1)\n  validate(completely_to_left, 34, 10, { 'v', 'il', '\"' }, 5)\n\n  local outside_left_right = '\"xxxxx abcdefghijklmnopqrst xxxxx\"'\n  validate(outside_left_right, 12, 4, { 'c', 'i', '\"' }, 1)\n  validate(outside_left_right, 12, 4, { 'v', 'i', '\"' }, 8)\nend\n\nT['Textobject']['works in command-line window'] = function()\n  child.set_size(20, 40)\n\n  local validate = function(before_line, after_line, keys)\n    -- Open command-line window\n    type_keys('q:')\n    eq(child.fn.getcmdwintype(), ':')\n\n    type_keys('i', before_line, '<Esc>')\n    type_keys(keys)\n    eq(child.fn.getline('.'), after_line)\n\n    -- It shouldn't close command-line window\n    eq(child.fn.getcmdwintype(), ':')\n    type_keys('<Esc>')\n    child.cmd('close')\n  end\n\n  validate('(aaa)', '(...)', 'vi)r.')\n  validate('(aaa)', '.....', 'va)r.')\n\n  validate('(aaa)', '()', 'di)')\n  validate('(aaa)', '', 'da)')\n\n  validate('fun(aaa)', 'fun()', 'cif')\n  validate('fun(aaa)', '', 'caf')\nend\n\nT['Textobject']['ensures that output is not covered by reference'] = function()\n  -- Non-empty region\n  set_lines({ 'aa(bb)cc(dd)' })\n  set_cursor(1, 3)\n  type_keys('vl', 'i)')\n  eq({ child.fn.col('v'), child.fn.col('.') }, { 10, 11 })\n\n  -- Empty region\n  validate_tobj1d('a()b(c)', 2, 'i)', { 6, 6 })\n  -- Probably not very consistent with non-empty case, because `ci)` in 'a(a)b'\n  -- on right ')' allows \"going backwards\" and deleting inside '(a)'. But this\n  -- is consistent with \"ensure textobject is not covering reference\" and\n  -- `ci)` <=> `vi)c` equivalence.\n  validate_edit1d('a()b(c)', 2, 'a()b()', 5, 'di)')\n  validate_edit1d('a()b(c)', 2, 'a()b()', 5, 'ci)')\nend\n\nT['Textobject']['opens just enough folds'] = function()\n  set_lines({ '(a', 'b', 'c', 'd', 'e', 'f)' })\n\n  -- Manually create two nested closed folds\n  set_cursor(1, 0)\n  type_keys('zf', 'j')\n  set_cursor(3, 0)\n  type_keys('zf', 'j')\n  set_cursor(5, 0)\n  type_keys('zf', 'j')\n  eq(child.fn.foldclosed(2), 1)\n  eq(child.fn.foldclosed(4), 3)\n  eq(child.fn.foldclosed(6), 5)\n\n  -- Selecting textobject should open just enough folds\n  set_cursor(1, 0)\n  type_keys('v', 'i', ')')\n  eq(child.fn.foldclosed(2), -1)\n  eq(child.fn.foldclosed(4), 3)\n  eq(child.fn.foldclosed(6), -1)\nend\n\nT['Textobject']['shows reminder after one idle second'] = new_set({ parametrize = { { 'a' }, { 'i' } } }, {\n  test = function(key)\n    child.set_size(5, 70)\n    child.o.cmdheight = 1\n\n    -- Both mappings are applied only after `timeoutlen` milliseconds, because\n    -- there are `an`/`in`/`al`/`il` mappings.\n    -- Wait fixed time after that.\n    child.o.timeoutlen = 2 * small_time\n    local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n    set_lines({ '(aaa)' })\n    set_cursor(1, 1)\n\n    type_keys('v', key)\n    sleep(total_wait_time)\n\n    -- Should show helper message without adding it to `:messages` and causing\n    -- hit-enter-prompt\n    eq(get_latest_message(), '')\n    child.expect_screenshot({ redraw = false })\n\n    -- Should clear afterwards\n    type_keys(')')\n    child.expect_screenshot({ redraw = false })\n  end,\n})\n\nT['Textobject']['shows message if no textobject is found'] = function()\n  -- Make all showed messages full width\n  child.o.cmdheight = 10\n\n  local validate = function(keys, msg)\n    child.cmd('messages clear')\n    set_lines({ 'aa' })\n    set_cursor(1, 0)\n    type_keys('v', keys)\n    eq(get_cursor(), { 1, 0 })\n    eq(get_latest_message(), msg)\n  end\n\n  validate(\n    'a)',\n    [[(mini.ai) No textobject \"a)\" found covering region within 50 lines and `search_method = 'cover_or_next'`.]]\n  )\n\n  child.lua([[MiniAi.config.n_lines = 1; MiniAi.config.search_method = 'cover']])\n  validate(\n    '2i]',\n    [[(mini.ai) No textobject \"i]\" found covering region 2 times within 1 line and `search_method = 'cover'`.]]\n  )\nend\n\nT['Textobject']['shows message for empty textobject in Operator-pending mode'] = function()\n  child.o.eventignore = ''\n  set_lines({ 'a()' })\n  set_cursor(1, 0)\n\n  type_keys('yi)')\n  eq(child.fn.mode(), 'n')\n  eq(get_cursor(), { 1, 0 })\n  eq(get_latest_message(), '(mini.ai) Textobject region is empty. Nothing is done.')\n  eq(child.o.eventignore, '')\nend\n\nT['Textobject']['respects `vim.{g,b}.miniai_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].miniai_disable = true\n\n    -- It should fallback to Neovim builtin behavior\n    validate_tobj1d('(  aa  )', 0, 'i(', { 2, 7 })\n\n    -- It shouldn't recognize new textobjects\n    validate_edit1d('*bb*', 1, '*bb*', 1, 'ci*')\n  end,\n})\n\nT['Textobject']['respects `config.silent`'] = function()\n  child.set_size(5, 40)\n  child.o.showcmd = false\n  child.lua('MiniAi.config.silent = true')\n\n  child.o.timeoutlen = 2 * small_time\n  local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n  set_lines({ '(aaa)' })\n  set_cursor(1, 1)\n\n  type_keys('v', 'a')\n  sleep(total_wait_time)\n\n  -- Should not show helper message\n  child.expect_screenshot()\n\n  -- Finish user input for cleaner Neovim restart\n  type_keys(')')\nend\n\nT['Textobject next/last'] = new_set()\n\nT['Textobject next/last']['works in Visual mode'] = function()\n  local lines, cursor\n\n  -- Next\n  lines, cursor = { '(aa)(bb', 'cccc', 'dd)(ee)' }, { 1, 1 }\n  validate_tobj(lines, cursor, 'an)', { { 1, 5 }, { 3, 3 } }, 'v')\n  validate_tobj(lines, cursor, 'in)', { { 1, 6 }, { 3, 2 } }, 'v')\n  validate_tobj(lines, cursor, 'an)', { 1, 3 }, 'V')\n  validate_tobj(lines, cursor, 'in)', { 1, 3 }, 'V')\n  validate_tobj(lines, cursor, 'an)', { { 1, 5 }, { 3, 3 } }, '<C-v>')\n  validate_tobj(lines, cursor, 'in)', { { 1, 6 }, { 3, 2 } }, '<C-v>')\n\n  -- Last\n  lines, cursor = { '(aa)(bb', 'cccc', 'dd)(ee)' }, { 3, 5 }\n  validate_tobj(lines, cursor, 'al)', { { 1, 5 }, { 3, 3 } }, 'v')\n  validate_tobj(lines, cursor, 'il)', { { 1, 6 }, { 3, 2 } }, 'v')\n  validate_tobj(lines, cursor, 'al)', { 1, 3 }, 'V')\n  validate_tobj(lines, cursor, 'il)', { 1, 3 }, 'V')\n  validate_tobj(lines, cursor, 'al)', { { 1, 5 }, { 3, 3 } }, '<C-v>')\n  validate_tobj(lines, cursor, 'il)', { { 1, 6 }, { 3, 2 } }, '<C-v>')\nend\n\nT['Textobject next/last']['works in Operator-pending mode'] = function()\n  local lines, cursor\n\n  -- Next\n  lines, cursor = { '(aa)(bb', 'ccccc', 'dddd)ee' }, { 1, 0 }\n  validate_edit(lines, cursor, { '(aa)ee' }, { 1, 4 }, 'dan)')\n  validate_edit(lines, cursor, { '(aa)ee' }, { 1, 4 }, 'dvan)')\n  validate_edit(lines, cursor, { '' }, { 1, 0 }, 'dVan)')\n  validate_edit(lines, cursor, { '(aa)bb', 'cccc', 'ddddee' }, { 1, 4 }, 'd<C-v>an)')\n\n  -- Last\n  lines, cursor = { 'aa(bbbb', 'ccccc', 'dd)(ee)' }, { 3, 5 }\n  validate_edit(lines, cursor, { 'aa(ee)' }, { 1, 2 }, 'dal)')\n  validate_edit(lines, cursor, { 'aa(ee)' }, { 1, 2 }, 'dval)')\n  validate_edit(lines, cursor, { '' }, { 1, 0 }, 'dVal)')\n  validate_edit(lines, cursor, { 'aabbbb', 'cccc', 'dd(ee)' }, { 1, 2 }, 'd<C-v>al)')\nend\n\nT['Textobject next/last']['works with different mappings'] = function()\n  reload_module({ mappings = { around_next = 'An', around_last = 'Al', inside_next = 'In', inside_last = 'Il' } })\n\n  validate_tobj1d('(aa)(bb)', 1, 'An)', { 5, 8 })\n  validate_tobj1d('(aa)(bb)', 1, 'In)', { 6, 7 })\n  validate_tobj1d('(aa)(bb)', 5, 'Al)', { 1, 4 })\n  validate_tobj1d('(aa)(bb)', 5, 'Il)', { 2, 3 })\nend\n\nT['Textobject next/last']['allows dot-repeat'] = function()\n  -- Next\n  set_lines({ '(aa)(bb)', '(cc)(dd)' })\n  set_cursor(1, 1)\n\n  type_keys('dan)')\n  eq(get_lines(), { '(aa)', '(cc)(dd)' })\n  eq(get_cursor(), { 1, 3 })\n\n  type_keys('.')\n  eq(get_lines(), { '(aa)', '(dd)' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Allows not immediate dot-repeat\n  type_keys('k', '.')\n  eq(get_lines(), { '(aa)', '' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Last\n  set_lines({ '(aa)(bb)', '(cc)(dd)' })\n  set_cursor(2, 6)\n\n  type_keys('dal)')\n  eq(get_lines(), { '(aa)(bb)', '(dd)' })\n  eq(get_cursor(), { 2, 0 })\n\n  type_keys('.')\n  eq(get_lines(), { '(aa)', '(dd)' })\n  eq(get_cursor(), { 1, 3 })\n\n  -- Allows not immediate dot-repeat\n  type_keys('j', '.')\n  eq(get_lines(), { '', '(dd)' })\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Textobject next/last']['respects `v:count`'] = function()\n  validate_tobj1d('(aa)(bb)(cc)(dd)', 1, '2an)', { 9, 12 })\n  validate_tobj1d('(aa)(bb)(cc)(dd)', 1, '2in)', { 10, 11 })\n  validate_tobj1d('(aa)(bb)(cc)(dd)', 1, '3an)', { 13, 16 })\n\n  validate_tobj1d('(aa)(bb)(cc)(dd)', 14, '2al)', { 5, 8 })\n  validate_tobj1d('(aa)(bb)(cc)(dd)', 14, '2il)', { 6, 7 })\n  validate_tobj1d('(aa)(bb)(cc)(dd)', 14, '3al)', { 1, 4 })\n\n  -- Don't do anything if not enough is present\n  validate_no_tobj1d('(aa)(bb)(cc)(dd)', 1, '4an)')\n  validate_no_tobj1d('(aa)(bb)(cc)(dd)', 14, '4al)')\nend\n\nlocal validate_motion = function(lines, cursor, keys, expected)\n  set_lines(lines)\n  set_cursor(cursor[1], cursor[2])\n  type_keys(keys)\n  eq(get_cursor(), { expected[1], expected[2] })\nend\n\nlocal validate_motion1d = function(line, column, keys, expected)\n  validate_motion({ line }, { 1, column }, keys, { 1, expected })\nend\n\nT['Motion'] = new_set()\n\nT['Motion']['works in Normal mode'] = function()\n  validate_motion1d('aa(bbb)', 4, 'g[)', 2)\n  validate_motion1d('aa(bbb)', 4, 'g])', 6)\nend\n\nT['Motion']['works in Visual mode'] = function()\n  validate_motion1d('aa(bbb)', 4, 'vg[)', 2)\n\n  child.ensure_normal_mode()\n  validate_motion1d('aa(bbb)', 4, 'vg])', 6)\nend\n\nT['Motion']['works in Operator-pending mode'] = function()\n  local validate = function(motion_keys, after_line, after_column)\n    validate_edit1d('aa(bbb)', 4, after_line, after_column, 'd' .. motion_keys .. ')')\n\n    child.ensure_normal_mode()\n    validate_edit1d('aa(bbb)', 4, after_line, after_column, 'c' .. motion_keys .. ')')\n    eq(get_mode(), 'i')\n  end\n\n  validate('g[', 'aabb)', 2)\n  validate('g]', 'aa(b)', 4)\nend\n\nT['Motion']['allows with dot-repeat'] = function()\n  -- Assumes `g[` has same implementation\n  set_lines({ '(aa)  (bb)', '(cc)' })\n  set_cursor(1, 0)\n\n  type_keys('dg])')\n  eq(get_lines(), { ')  (bb)', '(cc)' })\n\n  type_keys('.')\n  eq(get_lines(), { ')', '(cc)' })\n\n  -- Allows not immediate dot-repeat\n  type_keys('j0', '.')\n  eq(get_lines(), { ')', ')' })\nend\n\nT['Motion']['works with different mappings'] = function()\n  reload_module({ mappings = { goto_left = 'g{', goto_right = 'g}' } })\n\n  validate_motion1d('aa(bbb)', 4, 'g{)', 2)\n  validate_motion1d('aa(bbb)', 4, 'g})', 6)\nend\n\nT['Motion']['treats `side` as edge of textobject'] = function()\n  local line = '(aa)bb(cc)'\n  validate_motion1d(line, 1, 'g[)', 0)\n  validate_motion1d(line, 1, 'g])', 3)\n  validate_motion1d(line, 4, 'g[)', 6)\n  validate_motion1d(line, 4, 'g])', 9)\n  validate_motion1d(line, 7, 'g[)', 6)\n  validate_motion1d(line, 7, 'g])', 9)\nend\n\nT['Motion']['respects `v:count`'] = function()\n  validate_motion1d('aa(bb)cc(dd)', 0, '2g[)', 8)\n  validate_motion1d('aa(bb)cc(dd)', 0, '2g])', 11)\n\n  -- It should do exactly `v:count` actual jumps. It can be not that way if\n  -- cursor is on edge of one of target textobjects\n  local line = 'aa(bb)cc(dd)ee(ff)'\n  validate_motion1d(line, 0, '2g[)', 8) -- 0->2->8\n  validate_motion1d(line, 2, '2g[)', 14) -- 2->8->14\n  validate_motion1d(line, 3, '2g[)', 8) -- 3->2->8\n  validate_motion1d(line, 5, '2g[)', 8) -- 5->2->8\n\n  validate_motion1d(line, 0, '2g])', 11) -- 0->5->11\n  validate_motion1d(line, 2, '2g])', 11) -- 2->5->11\n  validate_motion1d(line, 3, '2g])', 11) -- 3->5->11\n  validate_motion1d(line, 5, '2g])', 17) -- 5->11->17\nend\n\nT['Motion']['works with multibyte characters'] = function()\n  validate_motion1d(' (ыыы) ', 0, 'g[)', 1)\n  validate_motion1d(' (ыыы) ', 0, 'g])', 8)\nend\n\nT['Motion']['works with special textobject id'] = function()\n  validate_motion1d([[aa\\bb\\cc]], 4, [[g[\\]], 3)\n  validate_motion({ 'aa', 'bb', 'cc' }, { 1, 0 }, 'g[<C-j>', { 2, 0 })\nend\n\nT['Motion']['respects `vim.{g,b}.miniai_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].miniai_disable = true\n\n    set_lines({ '  (aaa)  ' })\n    set_cursor(1, 4)\n\n    -- Here `)` should serve as builtin motion after unsuccessful use of motion\n    type_keys('g[)')\n    eq(get_cursor(), { 1, 8 })\n\n    type_keys('g])')\n    eq(get_cursor(), { 1, 8 })\n  end,\n})\n\nT['Builtin'] = new_set()\n\nlocal brackets = {\n  ['('] = { '(', ')', 'open' },\n  [')'] = { '(', ')', 'close' },\n  ['['] = { '[', ']', 'open' },\n  [']'] = { '[', ']', 'close' },\n  ['{'] = { '{', '}', 'open' },\n  ['}'] = { '{', '}', 'close' },\n  ['<'] = { '<', '>', 'open' },\n  ['>'] = { '<', '>', 'close' },\n}\n\nT['Builtin']['Bracket'] = new_set({ parametrize = vim.tbl_map(function(x) return { x } end, vim.tbl_keys(brackets)) })\n\nT['Builtin']['Bracket']['works'] = function(key)\n  local left, right, side = unpack(brackets[key])\n\n  -- Single line\n  validate_tobj1d(left .. 'aa' .. right, 0, { 'a', key }, { 1, 4 })\n  validate_tobj1d(left .. 'aa' .. right, 0, { 'i', key }, { 2, 3 })\n\n  -- Multiline. End of line is considered to be whitespace, so should be\n  -- ignored by open brackets.\n  validate_tobj({ left, 'aa', right }, { 2, 0 }, { 'a', key }, { { 1, 1 }, { 3, 1 } })\n  local multiline_i_expected = side == 'open' and { { 2, 1 }, { 2, 2 } } or { { 1, 2 }, { 2, 3 } }\n  validate_tobj({ left, 'aa', right }, { 2, 0 }, { 'i', key }, multiline_i_expected)\nend\n\nT['Builtin']['Bracket']['works consecutively'] = function(key)\n  local left, right, side = unpack(brackets[key])\n\n  -- Reference: {'(', 'aa(bb)cc(dd)', ')'}\n  set_lines({ left, string.format('aa%sbb%scc%sdd%s', left, right, left, right), right })\n  set_cursor(2, 0)\n\n  -- `a`\n  type_keys('v')\n  validate_next_region({ 'a', key }, { { 2, 3 }, { 2, 6 } })\n  validate_next_region({ 'a', key }, { { 2, 9 }, { 2, 12 } })\n  validate_next_region({ 'a', key }, { { 1, 1 }, { 3, 1 } })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(2, 0)\n  type_keys('v')\n  validate_next_region({ 'i', key }, { { 2, 4 }, { 2, 5 } })\n  validate_next_region({ 'i', key }, { { 2, 10 }, { 2, 11 } })\n  local i_expected = side == 'open' and { { 2, 1 }, { 2, 12 } } or { { 1, 2 }, { 2, 13 } }\n  validate_next_region({ 'i', key }, i_expected)\nend\n\nT['Builtin']['Bracket']['handles inner whitespace'] = function(key)\n  local left, right, side = unpack(brackets[key])\n\n  -- Open brackets should exclude inner edge whitespace.\n  validate_tobj1d(left .. 'aa ' .. right, 0, { 'i', key }, side == 'open' and { 2, 3 } or { 2, 4 })\n  validate_tobj1d(left .. ' aa' .. right, 0, { 'i', key }, side == 'open' and { 3, 4 } or { 2, 4 })\n  validate_tobj1d(left .. ' aa ' .. right, 0, { 'i', key }, side == 'open' and { 3, 4 } or { 2, 5 })\n\n  -- Should also handle only inner whitespace\n  local whitespace_line = left .. '  ' .. right\n  local after_line = side == 'open' and whitespace_line or (left .. right)\n  local after_column = side == 'open' and 3 or 1\n  validate_edit1d(whitespace_line, 0, after_line, after_column, { 'ci', key })\n  validate_edit1d(whitespace_line, 0, after_line, after_column, { 'di', key })\nend\n\nT['Builtin']['Bracket']['is balanced'] = function(key)\n  local left, right, _ = unpack(brackets[key])\n  -- Reference: 'a(()'\n  local line = 'a' .. left .. left .. right\n  validate_tobj1d(line, 0, { 'a', key }, { 3, 4 })\nend\n\nT['Builtin']['Bracket']['works with empty region'] = function(key)\n  -- Emulate \"replace\" from 'mini.operators'\n  child.lua([[\n    _G.MiniOperators = {}\n    _G.MiniOperators.replace = function(mode)\n      if mode == nil then\n        vim.o.operatorfunc = 'v:lua.MiniOperators.replace'\n        return 'g@'\n      end\n      vim.fn.setreg('a', 'xxx')\n      vim.cmd('normal! `[v`]\"aP`[')\n    end\n\n    vim.keymap.set('n', 'gr', _G.MiniOperators.replace, { expr = true })\n    -- Delete conflicting default `gri` mapping\n    pcall(vim.keymap.del, 'n', 'gri')\n  ]])\n\n  -- Validate\n  local left, right, _ = unpack(brackets[key])\n\n  local line = 'a' .. left .. right\n  for i = 0, 1 do\n    validate_tobj1d(line, i, { 'i', key }, { 3, 3 })\n    validate_edit1d(line, i, line, 2, { 'ci', key })\n    validate_edit1d(line, i, line, 2, { 'di', key })\n\n    validate_edit1d(line, i, 'a' .. left .. 'xxx' .. right, 2, { 'gri', key })\n  end\nend\n\nT['Builtin']['Brackets alias'] = new_set()\n\nT['Builtin']['Brackets alias']['works'] = function()\n  -- Single line\n  validate_tobj1d('(aa)', 0, 'ab', { 1, 4 })\n  validate_tobj1d('[aa]', 0, 'ab', { 1, 4 })\n  validate_tobj1d('{aa}', 0, 'ab', { 1, 4 })\n\n  validate_tobj1d('(aa)', 0, 'ib', { 2, 3 })\n  validate_tobj1d('[aa]', 0, 'ib', { 2, 3 })\n  validate_tobj1d('{aa}', 0, 'ib', { 2, 3 })\n\n  -- Multiline\n  local lines = { '{', 'aa(bb)cc[dd]', '}' }\n  validate_tobj(lines, { 2, 0 }, 'ab', { { 2, 3 }, { 2, 6 } })\n  validate_tobj(lines, { 2, 0 }, '2ab', { { 2, 9 }, { 2, 12 } })\n  validate_tobj(lines, { 2, 0 }, '3ab', { { 1, 1 }, { 3, 1 } })\n\n  -- Balanced\n  validate_tobj1d('a(()', 0, 'ab', { 3, 4 })\n  validate_tobj1d('a[[]', 0, 'ab', { 3, 4 })\n  validate_tobj1d('a{{}', 0, 'ab', { 3, 4 })\nend\n\nT['Builtin']['Brackets alias']['works consecutively'] = function()\n  set_lines({ '{([aa])}' })\n  set_cursor(1, 3)\n\n  -- `a`\n  type_keys('v')\n  validate_next_region1d('ab', { 3, 6 })\n  validate_next_region1d('ab', { 2, 7 })\n  validate_next_region1d('ab', { 1, 8 })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(1, 3)\n  type_keys('v')\n  validate_next_region1d('ib', { 4, 5 })\n  validate_next_region1d('ib', { 3, 6 })\n  validate_next_region1d('ib', { 2, 7 })\nend\n\nT['Builtin']['Quote'] = new_set({ parametrize = { { '\"' }, { \"'\" }, { '`' } } })\n\nT['Builtin']['Quote']['works'] = function(key)\n  -- Single line\n  validate_tobj1d(key .. ' aa ' .. key, 0, 'a' .. key, { 1, 6 })\n  validate_tobj1d(key .. ' aa ' .. key, 0, 'i' .. key, { 2, 5 })\n\n  -- Multiline\n  validate_tobj({ key, 'aa', key }, { 2, 0 }, 'a' .. key, { { 1, 1 }, { 3, 1 } })\n  validate_tobj({ key, 'aa', key }, { 2, 0 }, 'i' .. key, { { 1, 2 }, { 2, 3 } })\nend\n\nT['Builtin']['Quote']['works consecutively'] = function(key)\n  -- Reference: { 'aa(bb)cc(dd)' }\n  set_lines({ string.format('aa%sbb%scc%sdd%s', key, key, key, key) })\n  set_cursor(1, 0)\n\n  -- `a`\n  type_keys('v')\n  validate_next_region1d('a' .. key, { 3, 6 })\n  validate_next_region1d('a' .. key, { 9, 12 })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(1, 0)\n  type_keys('v')\n  validate_next_region1d('i' .. key, { 4, 5 })\n  validate_next_region1d('i' .. key, { 10, 11 })\nend\n\nT['Builtin']['Quote']['is balanced'] = function(key)\n  -- Here by \"balanced\" it means that it counts in consecutive pairs from start\n  -- of neighborhood.\n\n  -- Single line. Reference: 'aa\"bb\"cc\"dd\"'\n  local line = string.format('aa%sbb%scc%sdd%s', key, key, key, key)\n  validate_tobj1d(line, 0, 'a' .. key, { 3, 6 })\n  validate_tobj1d(line, 0, '2a' .. key, { 9, 12 })\n\n  -- Multiple lines. Here there is an issue with transitioning from current\n  -- line to full neighborhood, but it should be rare and thus acceptable.\n  -- Reference: {'(', 'aa(bb)cc(dd)', ')'}\n  local lines, cursor = { key, string.format('aa%sbb%scc%sdd%s', key, key, key, key), key }, { 2, 0 }\n  validate_tobj(lines, cursor, 'a' .. key, { { 2, 3 }, { 2, 6 } })\n  validate_tobj(lines, cursor, '2a' .. key, { { 2, 9 }, { 2, 12 } })\n  -- Here, ideally, it should be { { 1, 1 }, { 3, 1 } }\n  validate_tobj(lines, cursor, '3a' .. key, { { 2, 12 }, { 3, 1 } })\nend\n\nT['Builtin']['Quote']['works with empty region'] = function(key)\n  local line = 'a' .. key .. key\n  for i = 0, 1 do\n    validate_tobj1d(line, i, 'i' .. key, { 3, 3 })\n    validate_edit1d(line, i, line, 2, 'ci' .. key)\n    validate_edit1d(line, i, line, 2, 'di' .. key)\n  end\nend\n\nT['Builtin']['Quotes alias'] = new_set()\n\nT['Builtin']['Quotes alias']['works'] = function()\n  validate_tobj1d(\"'aa'\", 0, 'aq', { 1, 4 })\n  validate_tobj1d('\"aa\"', 0, 'aq', { 1, 4 })\n  validate_tobj1d('`aa`', 0, 'aq', { 1, 4 })\n\n  validate_tobj1d(\"'aa'\", 0, 'iq', { 2, 3 })\n  validate_tobj1d('\"aa\"', 0, 'iq', { 2, 3 })\n  validate_tobj1d('`aa`', 0, 'iq', { 2, 3 })\n\n  local lines = { '`', [[aa'bb'cc\"dd\"]], '`' }\n  validate_tobj(lines, { 2, 0 }, 'aq', { { 2, 3 }, { 2, 6 } })\n  validate_tobj(lines, { 2, 0 }, '2aq', { { 2, 9 }, { 2, 12 } })\n  validate_tobj(lines, { 2, 0 }, '3aq', { { 1, 1 }, { 3, 1 } })\n\n  -- Balanced\n  validate_tobj1d(\"a''''\", 0, '2aq', { 4, 5 })\n  validate_tobj1d('a\"\"\"\"', 0, '2aq', { 4, 5 })\n  validate_tobj1d('a````', 0, '2aq', { 4, 5 })\nend\n\nT['Builtin']['Quotes alias']['works consecutively'] = function()\n  -- `a`\n  set_lines({ [[`\"'aa'\"`]] })\n  set_cursor(1, 3)\n\n  type_keys('v')\n  validate_next_region1d('aq', { 3, 6 })\n  validate_next_region1d('aq', { 2, 7 })\n  validate_next_region1d('aq', { 1, 8 })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(1, 3)\n  type_keys('v')\n  validate_next_region1d('iq', { 4, 5 })\n  validate_next_region1d('iq', { 3, 6 })\n  validate_next_region1d('iq', { 2, 7 })\n\n  -- Nested unbalanced pairs\n  child.ensure_normal_mode()\n  set_lines({ [[\"aa'bb'cc'\"dd`'`]] })\n  set_cursor(1, 4)\n\n  type_keys('v')\n  validate_next_region1d('aq', { 4, 7 })\n  validate_next_region1d('aq', { 1, 11 })\n  validate_next_region1d('aq', { 10, 15 })\n  validate_next_region1d('aq', { 14, 16 })\nend\n\nT['Builtin']['Argument'] = new_set()\n\nT['Builtin']['Argument']['works'] = function()\n  -- Don't check on first comma, as it is ambiguous\n  for i = 2, 3 do\n    validate_tobj1d('f(xx, yy, tt)', i, 'aa', { 3, 5 })\n    validate_tobj1d('f(xx, yy, tt)', i, 'ia', { 3, 4 })\n  end\n  for i = 5, 7 do\n    validate_tobj1d('f(xx, yy, tt)', i, 'aa', { 5, 8 })\n    validate_tobj1d('f(xx, yy, tt)', i, 'ia', { 7, 8 })\n  end\n  for i = 8, 11 do\n    validate_tobj1d('f(xx, yy, tt)', i, 'aa', { 9, 12 })\n    validate_tobj1d('f(xx, yy, tt)', i, 'ia', { 11, 12 })\n  end\nend\n\nT['Builtin']['Argument']['works consecutively'] = function()\n  -- `a` textobject\n  set_lines({ 'f(xx, yy, tt)' })\n  set_cursor(1, 0)\n  type_keys('v')\n  validate_next_region1d('aa', { 3, 5 })\n  validate_next_region1d('aa', { 5, 8 })\n  validate_next_region1d('aa', { 9, 12 })\n\n  -- `i` textobject\n  child.ensure_normal_mode()\n  set_lines({ 'f(xx, yy, tt)' })\n  set_cursor(1, 0)\n  type_keys('v')\n  validate_next_region1d('ia', { 3, 4 })\n  validate_next_region1d('ia', { 7, 8 })\n  validate_next_region1d('ia', { 11, 12 })\nend\n\nT['Builtin']['Argument']['is ambiguous on first comma'] = function()\n  -- It chooses argument with smaller width. This is not good, but is a result\n  -- of compromise over comma asymmetry.\n  validate_tobj1d('f(x, yyyyyy)', 3, 'aa', { 3, 4 })\n  validate_tobj1d('f(xxxxxx, y)', 8, 'aa', { 9, 11 })\n\n  -- It is also true if separator pattern includes whitespace\n  child.lua([[MiniAi.config.custom_textobjects = { A = MiniAi.gen_spec.argument({ separator = '%s*,%s*' }) }]])\n  validate_tobj1d('f(x , yyyyyy)', 5, 'aA', { 3, 6 })\n  validate_tobj1d('f(xxxxxx , y)', 8, 'aA', { 9, 12 })\nend\n\nT['Builtin']['Argument']['works inside all balanced brackets'] = function()\n  validate_tobj1d('(xx, yy)', 2, 'aa', { 2, 4 })\n  validate_tobj1d('[xx, yy]', 2, 'aa', { 2, 4 })\n  validate_tobj1d('{xx, yy}', 2, 'aa', { 2, 4 })\nend\n\nT['Builtin']['Argument']['ignores commas inside balanced brackets'] = function()\n  validate_tobj1d('f(xx, (yy, tt))', 5, 'aa', { 5, 14 })\n  validate_tobj1d('f(xx, [yy, tt])', 5, 'aa', { 5, 14 })\n  validate_tobj1d('f(xx, {yy, tt})', 5, 'aa', { 5, 14 })\n\n  validate_tobj1d('f((xx, yy) , tt)', 10, 'aa', { 3, 12 })\n  validate_tobj1d('f([xx, yy] , tt)', 10, 'aa', { 3, 12 })\n  validate_tobj1d('f({xx, yy} , tt)', 10, 'aa', { 3, 12 })\nend\n\nT['Builtin']['Argument']['ignores commas inside balanced quotes'] = function()\n  validate_tobj1d([[f(xx, 'yy, tt', 'aa, bb')]], 5, 'aa', { 5, 14 })\n  validate_tobj1d([[f(xx, 'yy, tt', 'aa, bb')]], 15, 'aa', { 15, 24 })\n\n  validate_tobj1d([[f(xx, \"yy, tt\", \"aa, bb\")]], 5, 'aa', { 5, 14 })\n  validate_tobj1d([[f(xx, \"yy, tt\", \"aa, bb\")]], 15, 'aa', { 15, 24 })\n\n  validate_tobj1d([[f('xx, yy' , tt)]], 10, 'aa', { 3, 12 })\n  validate_tobj1d([[f(\"xx, yy\" , tt)]], 10, 'aa', { 3, 12 })\nend\n\nT['Builtin']['Argument']['ignores empty arguments'] = function()\n  validate_tobj1d('f(,)', 0, 'aa', { 3, 3 })\n  validate_tobj1d('f(,)', 0, 'ia', { 3, 3 })\n\n  validate_tobj1d('f(, xx)', 0, 'aa', { 3, 3 })\n  validate_tobj1d('f(, xx)', 0, 'ia', { 3, 3 })\n  validate_tobj1d('f(, xx)', 0, '2aa', { 3, 6 })\n  validate_tobj1d('f(, xx)', 0, '2ia', { 5, 6 })\n\n  validate_tobj1d('f(,, xx)', 0, 'aa', { 3, 3 })\n  validate_tobj1d('f(,, xx)', 0, 'ia', { 3, 3 })\n  validate_tobj1d('f(,, xx)', 0, '2aa', { 4, 7 })\n  validate_tobj1d('f(,, xx)', 0, '2ia', { 6, 7 })\n\n  validate_tobj1d('f(xx,, yy)', 0, 'aa', { 3, 5 })\n  validate_tobj1d('f(xx,, yy)', 0, 'ia', { 3, 4 })\n  validate_tobj1d('f(xx,, yy)', 0, '2aa', { 6, 9 })\n  validate_tobj1d('f(xx,, yy)', 0, '2ia', { 8, 9 })\n\n  validate_tobj1d('f(xx, yy,, tt)', 0, '1aa', { 3, 5 })\n  validate_tobj1d('f(xx, yy,, tt)', 0, '2aa', { 5, 8 })\n  validate_tobj1d('f(xx, yy,, tt)', 0, '3aa', { 9, 9 })\n  validate_tobj1d('f(xx, yy,, tt)', 0, '4aa', { 10, 13 })\n\n  validate_tobj1d('f(xx,,)', 0, 'aa', { 3, 5 })\n  validate_tobj1d('f(xx,,)', 0, 'ia', { 3, 4 })\n  validate_tobj1d('f(xx,,)', 0, '2aa', { 6, 6 })\n  validate_tobj1d('f(xx,,)', 0, '2ia', { 7, 7 })\n\n  validate_tobj1d('f(xx,)', 0, 'aa', { 3, 5 })\n  validate_tobj1d('f(xx,)', 0, 'ia', { 3, 4 })\nend\n\nT['Builtin']['Argument']['works with whitespace argument'] = function()\n  -- Single argument\n  validate_tobj1d('f(  )', 0, 'aa', { 3, 4 })\n\n  -- First argument (should ignore whitespace)\n  validate_tobj1d('f(  ,x)', 0, 'aa', { 5, 5 })\n  validate_tobj1d('f(  ,x)', 0, 'ia', { 5, 5 })\n\n  -- Last argument (should ignore whitespace). It misbehaves (`aa` selects all\n  -- insteadd of only separator and `ia` goes to rightmost point instead of to\n  -- right of separator), but it is acceptable because it is a rare case.\n  validate_tobj1d('f(x,  )', 0, '2aa', { 4, 6 })\n  validate_tobj1d('f(x,  )', 0, '2ia', { 7, 7 })\n\n  -- Middle argument\n  validate_tobj1d('f(x,  ,y)', 0, '2aa', { 4, 6 })\n  validate_tobj1d('f(x,  ,y)', 0, '2ia', { 7, 7 })\nend\n\nT['Builtin']['Argument']['does not match with cursor on covering bracket'] = function()\n  child.lua([[MiniAi.config.search_method = 'cover']])\n\n  validate_no_tobj1d('f(a)', 1, 'aa')\n  validate_no_tobj1d('f(a)', 1, 'ia')\n  validate_no_tobj1d('f(a)', 3, 'aa')\n  validate_no_tobj1d('f(a)', 3, 'ia')\nend\n\nT['Builtin']['Argument']['ignores empty brackets'] = function()\n  validate_no_tobj1d('f()', 0, 'aa')\n  validate_no_tobj1d('f()', 0, 'ia')\nend\n\nT['Builtin']['Argument']['works with single argument'] = function()\n  validate_tobj1d('f(x)', 0, 'aa', { 3, 3 })\n  validate_tobj1d('f(x)', 0, 'ia', { 3, 3 })\n  validate_tobj1d('f(xx)', 0, 'aa', { 3, 4 })\n  validate_tobj1d('f(xx)', 0, 'ia', { 3, 4 })\n\n  -- Edge whitespace should be a part of `aa`\n  validate_tobj1d('f( x)', 0, 'aa', { 3, 4 })\n  validate_tobj1d('f( x)', 0, 'ia', { 4, 4 })\n  validate_tobj1d('f(x )', 0, 'aa', { 3, 4 })\n  validate_tobj1d('f(x )', 0, 'ia', { 3, 3 })\n  validate_tobj1d('f( x )', 0, 'aa', { 3, 5 })\n  validate_tobj1d('f( x )', 0, 'ia', { 4, 4 })\nend\n\nT['Builtin']['Argument']['handles first and last arguments'] = function()\n  -- `aa` should work on edge whitespace but ignore it in output (if more than\n  -- 2 arguments)\n\n  for i = 2, 7 do\n    validate_tobj1d('f(  xx  ,  yy  )', i, 'aa', { 5, 9 })\n    validate_tobj1d('f(  xx  ,  yy  )', i, 'ia', { 5, 6 })\n  end\n  for i = 9, 14 do\n    validate_tobj1d('f(  xx  ,  yy  )', i, 'aa', { 9, 13 })\n    validate_tobj1d('f(  xx  ,  yy  )', i, 'ia', { 12, 13 })\n  end\n\n  -- Edge whitespace should be recognized as part of current argument even in\n  -- presence of a bigger covering one\n  validate_tobj1d('g(f(  xx  ,  yy  ))', 4, 'aa', { 7, 11 })\n  validate_tobj1d('g(f(  xx  ,  yy  ))', 16, 'aa', { 11, 15 })\n\n  -- Newline character should also be ignored\n  local lines, cursor = { 'f(  ', '  aa,', '  bb', '  )' }, { 1, 0 }\n  validate_tobj(lines, cursor, 'aa', { { 2, 3 }, { 2, 5 } })\n  validate_tobj(lines, cursor, 'ia', { { 2, 3 }, { 2, 4 } })\n  validate_tobj(lines, cursor, '2aa', { { 2, 5 }, { 3, 4 } })\n  validate_tobj(lines, cursor, '2ia', { { 3, 3 }, { 3, 4 } })\nend\n\n--stylua: ignore\nT['Builtin']['Argument']['works with whitespace padding in separator pattern'] = function()\n  child.lua([[MiniAi.config.custom_textobjects = { A = MiniAi.gen_spec.argument({ separator = '%s*,%s*' }) }]])\n\n  -- Visual mode\n  for i = 2, 5 do\n    validate_tobj1d('f(  xx  ,  yy  ,  zz  )', i, 'aA', { 5, 11 })\n    validate_tobj1d('f(  xx  ,  yy  ,  zz  )', i, 'iA', { 5, 6 })\n  end\n  for i = 11, 12 do\n    validate_tobj1d('f(  xx  ,  yy  ,  zz  )', i, 'aA', { 7, 13 })\n    validate_tobj1d('f(  xx  ,  yy  ,  zz  )', i, 'iA', { 12, 13 })\n  end\n  for i = 18, 21 do\n    validate_tobj1d('f(  xx  ,  yy  ,  zz  )', i, 'aA', { 14, 20 })\n    validate_tobj1d('f(  xx  ,  yy  ,  zz  )', i, 'iA', { 19, 20 })\n  end\n\n  -- Operator-pending mode\n  validate_edit1d('f( xx  ,   yy    ,     zz )', 3,  'f( yy    ,     zz )', 3, 'daA')\n  validate_edit1d('f( xx  ,   yy    ,     zz )', 11, 'f( xx    ,     zz )', 5, 'daA')\n  validate_edit1d('f( xx  ,   yy    ,     zz )', 23, 'f( xx  ,   yy )',    13, 'daA')\nend\n\nT['Builtin']['Argument']['works in Operator-pending mode'] = function()\n  local validate = function(before_line, before_column, after_line, after_column, keys)\n    validate_edit1d(before_line, before_column, after_line, after_column, 'd' .. keys)\n    validate_edit1d(before_line, before_column, after_line, after_column, 'c' .. keys)\n    eq(child.fn.mode(), 'i')\n  end\n\n  -- Normal cases\n  validate('f(x)', 2, 'f()', 2, 'aa')\n  validate('f(x)', 2, 'f()', 2, 'ia')\n\n  validate('f(  x)', 2, 'f()', 2, 'aa')\n  validate('f(  x)', 2, 'f(  )', 4, 'ia')\n\n  validate('f(x  )', 2, 'f()', 2, 'aa')\n  validate('f(x  )', 2, 'f(  )', 2, 'ia')\n\n  validate('f(  x  )', 2, 'f()', 2, 'aa')\n  validate('f(  x  )', 2, 'f(    )', 4, 'ia')\n\n  validate('f(x, y, t)', 2, 'f( y, t)', 2, 'aa')\n  validate('f(x, y, t)', 2, 'f(, y, t)', 2, 'ia')\n  validate('f(x, y, t)', 5, 'f(x, t)', 3, 'aa')\n  validate('f(x, y, t)', 5, 'f(x, , t)', 5, 'ia')\n  validate('f(x, y, t)', 8, 'f(x, y)', 6, 'aa')\n  validate('f(x, y, t)', 8, 'f(x, y, )', 8, 'ia')\n\n  -- Edge cases\n  validate('f( )', 2, 'f()', 2, 'aa')\n  validate('f( )', 2, 'f( )', 3, 'ia')\n\n  validate('f(  ,x)', 0, 'f(  x)', 4, 'aa')\n  validate('f(  ,x)', 0, 'f(  ,x)', 4, 'ia')\n  -- Not ideal but acceptable behavior (see case for whitespace argument)\n  validate('f(x,  )', 0, 'f(x)', 3, '2aa')\n  validate('f(x,  )', 0, 'f(x,  )', 6, '2ia')\n\n  validate('f(x,,)', 4, 'f(x,)', 4, 'aa')\n  validate('f(x,,)', 4, 'f(x,,)', 5, 'ia')\nend\n\nT['Builtin']['Function call'] = new_set()\n\nT['Builtin']['Function call']['works'] = function()\n  -- Single line\n  validate_tobj1d('ff(aa, bb)', 0, 'af', { 1, 10 })\n  validate_tobj1d('ff(aa, bb)', 0, 'if', { 4, 9 })\n\n  -- Multiple lines\n  validate_tobj({ 'ff(', 'aa, bb', ')' }, { 1, 0 }, 'af', { { 1, 1 }, { 3, 1 } })\n  validate_tobj({ 'ff(', 'aa, bb', ')' }, { 1, 0 }, 'if', { { 1, 4 }, { 2, 7 } })\n\n  -- Empty arguments\n  validate_tobj1d('ff()', 0, 'af', { 1, 4 })\n  validate_tobj1d('ff()', 0, 'if', { 4, 4 })\n  validate_edit1d('ff()', 0, 'ff()', 3, 'di)')\n  validate_edit1d('ff()', 0, 'ff()', 3, 'ci)')\nend\n\nT['Builtin']['Function call']['works consecutively'] = function()\n  set_lines({ 'ff(', 'gg(aa) hh(bb)', ')' })\n  set_cursor(2, 0)\n\n  -- `a`\n  type_keys('v')\n  validate_next_region('af', { { 2, 1 }, { 2, 6 } })\n  validate_next_region('af', { { 2, 8 }, { 2, 13 } })\n  validate_next_region('af', { { 1, 1 }, { 3, 1 } })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(2, 0)\n  type_keys('v')\n  validate_next_region('if', { { 2, 4 }, { 2, 5 } })\n  validate_next_region('if', { { 2, 11 }, { 2, 12 } })\n  validate_next_region('if', { { 1, 4 }, { 2, 14 } })\nend\n\nT['Builtin']['Function call']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n\n  -- It does not take into account that part is inside string\n  validate_tobj1d([[ff(aa, ')', bb)]], 0, 'af', { 1, 9 })\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_tobj({ 'ff(', '# )', ')' }, { 1, 0 }, 'af', { { 1, 1 }, { 2, 3 } })\nend\n\nT['Builtin']['Function call']['is detected with \"_\" and \".\" in name'] = function()\n  validate_tobj1d('ff_ff(aa)', 0, 'af', { 1, 9 })\n  validate_tobj1d('ff.ff(aa)', 0, 'af', { 1, 9 })\n\n  validate_tobj1d('big-ff_ff.ff(aa)', 0, 'af', { 5, 16 })\n  validate_tobj1d('big ff_ff.ff(aa)', 0, 'af', { 5, 16 })\n  validate_tobj1d('[(ff(aa))]', 0, 'af', { 3, 8 })\nend\n\nT['Builtin']['Function call']['has limited support of multibyte characters'] = function()\n  -- It doesn't support multibyte characters in name due to Lua patterns nature\n  validate_no_tobj1d('ыы(aa)', 0, 'af')\n\n  -- But it should work with multibyte characters inside parenthesis\n  validate_tobj1d('ff(ыы, фф)', 0, 'af', { 1, 14 })\nend\n\nT['Builtin']['Tag'] = new_set()\n\nT['Builtin']['Tag']['works'] = function()\n  -- Sinle line\n  validate_tobj1d('<x>aaa</x>', 0, 'at', { 1, 10 })\n  validate_tobj1d('<x>aaa</x>', 0, 'it', { 4, 6 })\n\n  -- Multiple lines line\n  validate_tobj({ '<x>', 'aaa', '</x>' }, { 2, 0 }, 'at', { { 1, 1 }, { 3, 4 } })\n  validate_tobj({ '<x>', 'aaa', '</x>' }, { 2, 0 }, 'it', { { 1, 4 }, { 2, 4 } })\n\n  -- Should work with empty tag name\n  validate_tobj1d('<>aaa</>', 3, 'at', { 1, 8 })\n\n  -- Should work with empty region\n  validate_tobj1d('<x></x>', 0, 'it', { 4, 4 })\n  validate_edit1d('<x></x>', 0, '<x></x>', 3, 'dit')\n  validate_edit1d('<x></x>', 0, '<x></x>', 3, 'cit')\nend\n\nT['Builtin']['Tag']['works consecutively'] = function()\n  -- Even with same tags, but not covering\n  set_lines({ '<x>', 'aa <y>bb</y> <y>cc</y>', '</x>' })\n  set_cursor(2, 0)\n\n  -- `a`\n  type_keys('v')\n  validate_next_region('at', { { 2, 4 }, { 2, 12 } })\n  validate_next_region('at', { { 2, 14 }, { 2, 22 } })\n  validate_next_region('at', { { 1, 1 }, { 3, 4 } })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(2, 0)\n  type_keys('v')\n  validate_next_region('it', { { 2, 7 }, { 2, 8 } })\n  validate_next_region('it', { { 2, 17 }, { 2, 18 } })\n  validate_next_region('it', { { 1, 4 }, { 2, 23 } })\nend\n\nT['Builtin']['Tag']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n\n  -- It does not take into account that part is inside string\n  validate_tobj1d([[<x> '</x>' </x>]], 0, 'at', { 1, 9 })\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_tobj({ '<x>', '# </x>', '</x>' }, { 2, 0 }, 'at', { { 1, 1 }, { 2, 6 } })\n\n  -- It can select tags that don't contain same tags inside\n  validate_no_tobj1d('<x><x>aaa</x></x>', 7, '2at')\nend\n\nT['Builtin']['Tag']['allows extra symbols in opening tag'] = function()\n  validate_tobj1d('<x bbb cc_dd!>aaa</x>', 0, 'at', { 1, 21 })\n\n  -- Symbol `<` is not allowed\n  validate_no_tobj1d('<x <>aaa</x>', 0, 'at')\nend\n\nT['Builtin']['Tag']['detects covering with smallest width'] = function()\n  -- In all cases width of `<y>...</y>` is smaller than of `<x>...</x>`\n  validate_tobj1d('<x>  <y>a</x></y>', 8, 'at', { 6, 17 })\n  validate_tobj1d('<y><x>a</y>  </x>', 6, 'at', { 1, 11 })\n\n  -- Width should be from the left-most point to right-most\n  validate_tobj1d('<y><x bbb>a</y></x>', 10, 'at', { 1, 15 })\n\n  -- Works with identical nested tags\n  validate_tobj1d('<x><x>aaa</x></x>', 7, 'at', { 4, 13 })\nend\n\nT['Builtin']['Tag']['works in edge cases'] = function()\n  -- Nesting different tags\n  validate_tobj1d('<x><y></y></x>', 1, 'at', { 1, 14 })\n  validate_tobj1d('<x><y></y></x>', 3, 'at', { 4, 10 })\n\n  -- End of overlapping tags\n  validate_tobj1d('<y><x></y></x>', 12, 'at', { 4, 14 })\n\n  -- `>` between tags\n  validate_tobj1d('<x>>aaa</x>', 0, 'at', { 1, 11 })\n\n  -- Similar but different names shouldn't match\n  validate_no_tobj1d('<xy>aaa</x>', 0, 'at')\nend\n\nT['Builtin']['Tag']['has limited support of multibyte characters'] = function()\n  -- It doesn't support multibyte characters in name due to Lua patterns nature\n  validate_no_tobj1d('<ы>aaa</ы>', 0, 'at')\n\n  -- But it should work with multibyte characters inside tag\n  validate_tobj1d('<x>ыыы</x>', 0, 'at', { 1, 13 })\nend\n\nT['Builtin']['User prompt'] = new_set()\n\nT['Builtin']['User prompt']['works'] = function()\n  -- Single character edges\n  validate_tobj1d('__e__o__', 0, 'a?e<CR>o<CR>', { 3, 6 })\n  validate_tobj1d('__e__o__', 0, 'i?e<CR>o<CR>', { 4, 5 })\n\n  -- Multiple character edges\n  validate_tobj1d('__ef__op__', 0, 'a?ef<CR>op<CR>', { 3, 8 })\n  validate_tobj1d('__ef__op__', 0, 'i?ef<CR>op<CR>', { 5, 6 })\nend\n\nT['Builtin']['User prompt']['works consecutively'] = function()\n  local keys\n\n  -- Single character edges\n  keys = { 'a?', 'e<CR>', 'o<CR>' }\n  set_lines({ 'e_e_o_e_o_o' })\n  set_cursor(1, 0)\n\n  type_keys('v')\n  validate_next_region1d(keys, { 3, 5 })\n  validate_next_region1d(keys, { 7, 9 })\n\n  -- Prompt can be changed\n  validate_next_region1d({ 'a?', 'o<CR>', 'o<CR>' }, { 5, 9 })\n\n  -- `i` textobject\n  child.ensure_normal_mode()\n  keys = { 'i?', 'e<CR>', 'o<CR>' }\n  set_cursor(1, 0)\n\n  type_keys('v')\n  validate_next_region1d(keys, { 4, 4 })\n  validate_next_region1d(keys, { 8, 8 })\n\n  -- Multiple character edges\n  child.ensure_normal_mode()\n  keys = { 'a?', 'ef<CR>', 'op<CR>' }\n  set_lines({ 'ef_ef_op_ef_oq_op' })\n  set_cursor(1, 0)\n\n  type_keys('v')\n  validate_next_region1d(keys, { 4, 8 })\n  validate_next_region1d(keys, { 10, 17 })\nend\n\nT['Builtin']['User prompt']['works with empty region'] = function() validate_tobj1d('_eo', 0, 'i?e<CR>o<CR>', { 3, 3 }) end\n\nT['Builtin']['User prompt']['can not be covering'] = function()\n  set_lines({ 'e_e_o_o' })\n  set_cursor(1, 0)\n  local keys = { 'a?', 'e<CR>', 'o<CR>' }\n\n  type_keys('v')\n  validate_next_region1d(keys, { 3, 5 })\n\n  -- Can't result into covering, so no more matches\n  type_keys(keys)\n  eq(get_mode(), 'n')\n  eq(get_cursor(), { 1, 4 })\n  expect.match(get_latest_message(), 'a%?')\nend\n\nT['Builtin']['User prompt']['allows dot-repeat'] = function()\n  local keys = { 'a?', 'e<CR>', 'o<CR>' }\n  set_lines({ 'e1_e2_o3_e4_o5_o6', 'e7_o8' })\n  set_cursor(1, 0)\n\n  type_keys('d', keys)\n  eq(get_lines(), { 'e1_3_e4_o5_o6', 'e7_o8' })\n  type_keys('.')\n  eq(get_lines(), { 'e1_3_5_o6', 'e7_o8' })\n\n  -- Allows not immediate dot-repeat\n  type_keys('j0', '.')\n  eq(get_lines(), { 'e1_3_5_o6', '8' })\nend\n\nT['Builtin']['User prompt']['detects covering with smallest width'] = function()\n  local keys = { 'a?', '**<CR>', '**<CR>' }\n  validate_tobj1d('**a**aa**', 4, keys, { 1, 5 })\n  validate_tobj1d('**aa**a**', 4, keys, { 5, 9 })\nend\n\nT['Builtin']['User prompt']['works with special characters in prompt'] = function()\n  -- \"Lua pattern\" special\n  validate_tobj1d('aa.bb%', 0, { 'a?', '.<CR>', '%<CR>' }, { 3, 6 })\n\n  -- \"Multibyte\" special. Each multibyte character takes two column counts.\n  validate_tobj1d('ы ы ф', 0, { 'a?', 'ы<CR>', 'ф<CR>' }, { 4, 7 })\nend\n\nT['Builtin']['User prompt']['handles <C-c>, <Esc>, <CR> in user input'] = function()\n  local validate_nothing = function(ai_type, key)\n    validate_edit1d('(aaa)', 2, '(aaa)', 2, { 'v', ai_type, '?', key })\n    validate_edit1d('(aaa)', 2, '(aaa)', 2, { 'v', ai_type, '?', '(<CR>', key })\n  end\n\n  -- Should do nothing on any `<C-c>` and `<Esc>` (in both input and output)\n  validate_nothing('a', '<Esc>')\n  validate_nothing('i', '<Esc>')\n  validate_nothing('a', '<C-c>')\n  validate_nothing('i', '<C-c>')\n  -- Should stop on `<CR>` because can't use empty string in pattern search\n  validate_nothing('a', '<CR>')\n  validate_nothing('i', '<CR>')\nend\n\nT['Builtin']['User prompt']['colors its prompts'] = function()\n  child.set_size(5, 40)\n  child.o.showmode = false\n\n  set_lines({ '_aaa!' })\n  set_cursor(1, 2)\n  type_keys('v', 'a?', '_')\n  child.expect_screenshot()\n  type_keys('<CR>', '!')\n  child.expect_screenshot()\n  type_keys('<CR>')\n\n  -- Should clean command line afterwards\n  child.expect_screenshot()\nend\n\nT['Builtin']['User prompt']['works in edge cases'] = function()\n  -- It can't contain edge characters inside\n  validate_tobj1d('aa(bb(cc))', 0, { 'a?', '(<CR>', ')<CR>' }, { 6, 9 })\nend\n\nT['Builtin']['Default'] = new_set()\n\nT['Builtin']['Default']['works'] = function()\n  -- Should allow all possible `getcharstr()` output (but not Latin letters)\n  -- Should include only right edge\n\n  local chars = { ',', '.', '_', '*', '-', '0', '1', ' ', '\\t', '\\\\', '\\r' }\n  for _, key in ipairs(chars) do\n    -- Single line\n    validate_tobj1d('a' .. key .. 'bb' .. key, 0, 'a' .. key, { 3, 5 })\n    validate_tobj1d('a' .. key .. 'bb' .. key, 0, 'i' .. key, { 3, 4 })\n\n    -- Multiple lines\n    validate_tobj({ key, 'aa', key }, { 2, 0 }, 'a' .. key, { { 1, 2 }, { 3, 1 } })\n    validate_tobj({ key, 'aa', key }, { 2, 0 }, 'i' .. key, { { 1, 2 }, { 2, 3 } })\n  end\nend\n\nT['Builtin']['Default']['supports any identifier which can be `getcharstr()` output'] = function()\n  -- - <C-j> is '\\n'\n  validate_edit({ 'aaa', 'bbb', 'ccc' }, { 2, 0 }, { 'aaa', 'ccc' }, { 2, 0 }, 'd', 'a', '<C-j>')\n  -- - Actually used multibyte (not like `<BS>`)\n  validate_edit1d('aыbbы', 0, 'aы', 1, 'd', 'a', 'ы')\n  validate_edit1d('a“bb“', 0, 'a“', 1, 'd', 'a', '“')\nend\n\nT['Builtin']['Default']['includes maximum right edge characters'] = function()\n  validate_tobj1d('aa_bb__cc___', 0, 'a_', { 4, 7 })\n  validate_tobj1d('aa_bb__cc___', 0, 'i_', { 4, 5 })\n  validate_tobj1d('aa_bb__cc___', 7, 'a_', { 8, 12 })\n  validate_tobj1d('aa_bb__cc___', 7, 'i_', { 8, 9 })\nend\n\nT['Builtin']['Default']['works consecutively'] = function()\n  set_lines({ 'aa_bb__cc___', 'dd__' })\n  set_cursor(1, 0)\n\n  -- `a`\n  type_keys('v')\n  validate_next_region('a_', { { 1, 4 }, { 1, 7 } })\n  validate_next_region('a_', { { 1, 8 }, { 1, 12 } })\n  validate_next_region('a_', { { 1, 13 }, { 2, 4 } })\n\n  -- `i`\n  child.ensure_normal_mode()\n  set_cursor(1, 3)\n  type_keys('v')\n  validate_next_region('i_', { { 1, 4 }, { 1, 5 } })\n  validate_next_region('i_', { { 1, 8 }, { 1, 9 } })\n  validate_next_region('i_', { { 1, 13 }, { 2, 2 } })\nend\n\nT['Builtin']['Default']['works with empty region'] = function()\n  validate_tobj1d('a__bb_', 0, 'i_', { 3, 3 })\n  validate_edit1d('a__bb_', 0, 'a__bb_', 2, 'di_')\n  validate_edit1d('a__bb_', 0, 'a__bb_', 2, 'ci_')\n\n  validate_tobj1d('____', 0, 'i_', { 2, 2 })\n  validate_edit1d('____', 0, '____', 1, 'di_')\n  validate_edit1d('____', 0, '____', 1, 'ci_')\nend\n\nT['Builtin']['Default']['can not be covering'] = function()\n  set_lines({ '_aa_bb_' })\n  set_cursor(1, 0)\n\n  type_keys('v')\n  validate_next_region1d('a_', { 2, 4 })\n  validate_next_region1d('a_', { 5, 7 })\n\n  -- Can't result into covering, so no more matches\n  type_keys('a_')\n  eq(get_mode(), 'n')\n  eq(get_cursor(), { 1, 6 })\n  expect.match(get_latest_message(), 'a_')\nend\n\nT['Builtin']['Default']['detects covering with smallest width'] = function()\n  validate_edit1d('_a_bb_', 2, '__bb_', 1, 'di_')\n  validate_edit1d('_aa_b_', 3, '_aa__', 4, 'di_')\n\n  validate_edit1d('_a_b_c_b_a_', 5, '_a_b__b_a_', 5, 'di_')\nend\n\nlocal set_custom_tobj = function(tbl) child.lua('MiniAi.config.custom_textobjects = ' .. vim.inspect(tbl)) end\n\nT['Custom textobject'] = new_set()\n\nT['Custom textobject']['works'] = function()\n  -- From `MiniAi.config`\n  child.lua([[MiniAi.config.custom_textobjects = { x = { 'x()x()x' } }]])\n  validate_tobj1d('aaxxxbb', 0, 'ax', { 3, 5 })\n  validate_tobj1d('aaxxxbb', 0, 'ix', { 4, 4 })\n\n  -- From `vim.b.miniai_config`\n  child.b.miniai_config = { custom_textobjects = { x = { 'y()y()y' } } }\n  validate_tobj1d('aayyybb', 0, 'ax', { 3, 5 })\n  validate_tobj1d('aayyybb', 0, 'ix', { 4, 4 })\nend\n\nT['Custom textobject']['supports any identifier which can be `getcharstr()` output'] = function()\n  child.lua([[\n    MiniAi.config.custom_textobjects = {\n      ['\\22'] = { '@().-()#' },\n      ['ы']   = { 'Ы().-()Ы' },\n      ['「']  = { '「().-()」' },\n    }\n  ]])\n\n  validate_edit({ '@aaa#' }, { 1, 3 }, { '@#' }, { 1, 1 }, 'd', 'i', '<C-v>')\n  validate_edit({ 'ЫaaaЫ' }, { 1, 3 }, { 'ЫЫ' }, { 1, 2 }, 'd', 'i', 'ы')\n  validate_edit({ '「aaa」' }, { 1, 3 }, { '「」' }, { 1, 3 }, 'd', 'i', '「')\nend\n\nT['Custom textobject']['overrides module builtin'] = function()\n  set_custom_tobj({ a = { 'a()a()a' } })\n  validate_tobj1d('__aaa__', 0, 'aa', { 3, 5 })\n  validate_no_tobj1d('ff(xx)', 0, 'aa')\nend\n\nT['Custom textobject']['allows reverting to external mapping'] = function()\n  -- Neovim's builtin\n  set_custom_tobj({ b = false })\n  validate_tobj1d('([{ aaa }])', 5, 'ab', { 1, 11 })\n\n  -- Manual external mapping\n  set_custom_tobj({ f = false })\n  child.api.nvim_set_keymap('x', 'af', 'iw', { noremap = true })\n\n  child.o.timeoutlen = 5\n  set_lines({ 'func(xxx)' })\n  set_cursor(1, 0)\n  type_keys(10, 'v', 'a', 'f')\n  child.expect_visual_marks({ 1, 0 }, { 1, 3 })\nend\n\nT['Custom textobject']['works consecutively'] = function()\n  set_custom_tobj({ x = { 'x()x()x' } })\n  set_lines({ 'xxxxx' })\n  set_cursor(1, 0)\n\n  type_keys('v')\n  validate_next_region1d('ax', { 1, 3 })\n  validate_next_region1d('ax', { 2, 4 })\n  validate_next_region1d('ax', { 3, 5 })\nend\n\nT['Custom textobject']['expands specification'] = function()\n  -- Expantion of array item in multiple arrays\n  -- Here this is identical to taking the best match among {'xxx', '.().().'}\n  -- and {'aaa', '.().().'}\n  set_custom_tobj({ x = { { 'xxx', 'aaa' }, '.().().' } })\n\n  validate_tobj1d('xxxaaaxxx', 0, 'ax', { 1, 3 })\n  validate_tobj1d('xxxaaaxxx', 0, 'ix', { 2, 2 })\n  validate_tobj1d('xxxaaaxxx', 0, '2ix', { 5, 5 })\n  validate_tobj1d('xxxaaaxxx', 0, '3ix', { 8, 8 })\n\n  -- Array items are allowed to be arrays themselves. Here this is identical to\n  -- taking the best match among\n  -- {'%b()', '^. .* .$', '^.().*().$'} (balanced `()` with inner spaces) and\n  -- {'%b[]', '^.[^ ].*[^ ].$', '^.().*().$'} (balanced `[]` without it).\n  set_custom_tobj({ y = { { { '%b()', '^. .* .$' }, { '%b[]', '^.[^ ].*[^ ].$' } }, '^.().*().$' } })\n\n  validate_tobj1d('( a ) (b) [ c ] [ddd]', 0, 'ay', { 1, 5 })\n  validate_tobj1d('( a ) (b) [ c ] [ddd]', 0, 'iy', { 2, 4 })\n  validate_tobj1d('( a ) (b) [ c ] [ddd]', 0, '2ay', { 17, 21 })\n  validate_tobj1d('( a ) (b) [ c ] [ddd]', 0, '2iy', { 18, 20 })\nend\n\nT['Custom textobject']['handles function as textobject spec'] = function()\n  -- Function which returns composed pattern\n  child.lua([[MiniAi.config.custom_textobjects = {\n    x = function(...) _G.args = {...}; return {'x()x()x'} end\n  }]])\n\n  validate_tobj1d('aaxxxbb', 0, 'ax', { 3, 5 })\n  -- Should be called with arguments after expanding defaults\n  --stylua: ignore\n  eq(\n    child.lua_get('_G.args'),\n    {\n      'a', 'x',\n      {\n        n_lines = 50,\n        n_times = 1,\n        reference_region = { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } },\n        search_method = 'cover_or_next',\n      },\n    }\n  )\n\n  -- Function which returns region. Should take arguments from corresponding\n  -- `find_textobject()` call.\n  child.lua([[_G.full_buffer = function(ai_type, id, opts)\n    local from = { line = 1, col = 1 }\n    local to = { line = vim.fn.line('$'), col = vim.fn.getline('$'):len() }\n    if ai_type == 'i' then to.col = to.col - 1 end\n    return { from = from, to = to }\n  end]])\n  child.lua([[MiniAi.config.custom_textobjects = { g = _G.full_buffer }]])\n  validate_tobj({ 'aaaaa', 'bbbb', 'ccc' }, { 2, 0 }, 'ag', { { 1, 1 }, { 3, 3 } })\n  validate_tobj({ 'aaaaa', 'bbbb', 'ccc' }, { 2, 0 }, 'ig', { { 1, 1 }, { 3, 2 } })\n\n  -- Function which returns region array\n  child.lua([[_G.long_lines = function(_, _, _)\n    local res = {}\n    for i = 1, vim.api.nvim_buf_line_count(0) do\n      local cur_line = vim.fn.getline(i)\n      if vim.fn.strdisplaywidth(cur_line) > 80 then\n        local region = { from = { line = i, col = 1 }, to = { line = i, col = cur_line:len() } }\n        table.insert(res, region)\n      end\n    end\n    return res\n  end]])\n  child.lua('MiniAi.config.custom_textobjects = { L = _G.long_lines }')\n\n  local lines = { string.rep('a', 80), string.rep('b', 81), string.rep('c', 80), string.rep('d', 81) }\n  validate_tobj(lines, { 1, 0 }, 'aL', { { 2, 1 }, { 2, 81 } })\n  validate_tobj(lines, { 2, 0 }, 'aL', { { 2, 1 }, { 2, 81 } })\n\n  child.lua([[MiniAi.config.search_method = 'next']])\n  validate_tobj(lines, { 2, 0 }, 'aL', { { 4, 1 }, { 4, 81 } })\n\n  child.lua('MiniAi.config.n_lines = 0')\n  validate_no_tobj(lines, { 2, 0 }, 'aL')\n\n  -- Function which returns region array with `vis_mode` set\n  child.lua([[MiniAi.config.search_method = 'cover']])\n  child.lua('MiniAi.config.n_lines = 50')\n  child.lua([[_G.line_regions = function(_, _, _)\n    return {\n      { from = { line = 1, col = 1 }, to = { line = 2, col = 1 }, vis_mode = 'V' },\n      { from = { line = 3, col = 1 }, to = { line = 4, col = 1 }, vis_mode = 'V' },\n    }\n  end]])\n  child.lua('MiniAi.config.custom_textobjects = { m = _G.line_regions }')\n\n  set_lines({ 'aaa', 'bbb', 'ccc', 'ddd' })\n  set_cursor(3, 0)\n  type_keys('d', 'a', 'm')\n  eq(get_lines(), { 'aaa', 'bbb' })\nend\n\nT['Custom textobject']['handles function as specification item'] = function()\n  child.lua([[_G.c_spec = {\n    '%b()',\n    function(s, init) if init > 1 then return end; return 2, s:len() end,\n    '^().*().$'\n  }]])\n  child.lua([[MiniAi.config.custom_textobjects = { c = _G.c_spec }]])\n  validate_tobj1d('aa(bb)', 0, 'ac', { 4, 6 })\n  validate_tobj1d('aa(bb)', 0, 'ic', { 4, 5 })\nend\n\nT['Custom textobject']['handles different extractions in last spec item'] = new_set({\n  parametrize = {\n    { 'xxx', { 1, 3 }, { 1, 3 } },\n    { 'x()x()x', { 1, 3 }, { 2, 2 } },\n    { '()x()x()x()', { 1, 3 }, { 2, 2 } },\n    { 'x()()()xx()', { 2, 3 }, { 2, 2 } },\n    { '()xx()()()x', { 1, 2 }, { 3, 3 } },\n  },\n}, {\n  test = function(pattern, a_result, i_result)\n    set_custom_tobj({ x = { pattern } })\n    validate_tobj1d('xxx', 0, 'ax', a_result)\n    validate_tobj1d('xxx', 0, 'ix', i_result)\n  end,\n})\n\nT['Custom textobject']['works with special patterns'] = new_set()\n\nT['Custom textobject']['works with special patterns']['%bxx'] = function()\n  -- `%bxx` should represent balanced character\n  set_custom_tobj({ e = { '%bee' } })\n\n  local line = 'e e e e e'\n  for i = 0, 2 do\n    validate_tobj1d(line, i, 'ae', { 1, 3 })\n  end\n  for i = 3, 6 do\n    validate_tobj1d(line, i, 'ae', { 5, 7 })\n  end\n  for i = 7, 8 do\n    validate_no_tobj1d(line, i, 'ae')\n  end\nend\n\nT['Custom textobject']['works with special patterns']['x.-y'] = function()\n  -- `x.-y` should match the smallest possible width\n  set_custom_tobj({ x = { 'e.-o', '^.().*().$' } })\n  validate_tobj1d('e e o o e o', 0, 'ax', { 3, 5 })\n  validate_tobj1d('e e o o e o', 0, '2ax', { 9, 11 })\n\n  -- `x.-y` should work with `a%.-a` and `a.%-a`\n  set_custom_tobj({ y = { 'y%.-y' } })\n  validate_tobj1d('y.y yay y..y', 0, 'ay', { 1, 3 })\n  validate_tobj1d('y.y yay y..y', 0, '2ay', { 9, 12 })\n\n  set_custom_tobj({ c = { 'c.%-c' } })\n  validate_tobj1d('c_-c c__c c+-c', 0, 'ac', { 1, 4 })\n  validate_tobj1d('c_-c c__c c+-c', 0, '2ac', { 11, 14 })\n\n  -- `x.-y` should allow patterns with `+` quantifiers\n  -- To improve, force other character in between (`%f[x]x+[^x]-x+%f[^x]`)\n  set_custom_tobj({ r = { 'r+.-r+' } })\n  validate_tobj1d('rraarr', 0, 'ar', { 5, 6 })\n  validate_tobj1d('rrrr', 0, 'ar', { 3, 4 })\nend\n\nT['Custom textobject']['works with empty region'] = function()\n  set_custom_tobj({ x = { 'x()()()xx()' } })\n  validate_tobj1d('xxx', 0, 'ix', { 2, 2 })\n  validate_edit1d('xxx', 0, 'xxx', 1, 'dix')\n  validate_edit1d('xxx', 0, 'xxx', 1, 'cix')\nend\n\nT['Custom textobject']['works with quantifiers in patterns'] = function()\n  set_custom_tobj({ x = { '%f[x]x+%f[^x]' } })\n  validate_tobj1d('axaxxaxxx', 0, 'ax', { 2, 2 })\n  validate_tobj1d('axaxxaxxx', 0, '2ax', { 4, 5 })\n  validate_tobj1d('axaxxaxxx', 0, '3ax', { 7, 9 })\nend\n\nT['Custom textobject']['works with multibyte characters'] = function()\n  set_custom_tobj({ x = { 'ыы фф', '^.-() ().-$' } })\n  validate_tobj1d('ыы ыы фф фф', 0, 'ax', { 6, 13 })\nend\n\nT['Custom textobject']['documented examples'] = new_set()\n\nT['Custom textobject']['documented examples']['function call with name from user input'] = function()\n  child.lua([[_G.fun_prompt = function()\n    local left_edge = vim.pesc(vim.fn.input('Function name: '))\n    return { string.format('%s+%%b()', left_edge), '^.-%(().*()%)$' }\n  end]])\n  child.lua('MiniAi.config.custom_textobjects = { F = _G.fun_prompt }')\n\n  validate_tobj1d('aa(xx) bb(xx)', 0, 'aFbb<CR>', { 8, 13 })\n  validate_tobj1d('aa(xx) bb(xx)', 0, 'iFbb<CR>', { 11, 12 })\nend\n\nT['Custom textobject']['documented examples']['full buffer'] = function()\n  child.lua([[_G.full_buffer = function()\n    local from = { line = 1, col = 1 }\n    local to = { line = vim.fn.line('$'), col = math.max(vim.fn.getline('$'):len(), 1) }\n    return { from = from, to = to, vis_mode = 'V' }\n  end]])\n  child.lua('MiniAi.config.custom_textobjects = { g = _G.full_buffer }')\n\n  validate_tobj({ 'aaaa', 'bbb', 'cc' }, { 2, 0 }, 'ag', { 1, 3 }, 'V')\n  validate_tobj({ '' }, { 1, 0 }, 'ag', { 1, 1 }, 'V')\nend\n\nT['Custom textobject']['documented examples']['wide lines'] = function()\n  child.lua([[_G.long_lines = function(_, _, _)\n    local res = {}\n    for i = 1, vim.api.nvim_buf_line_count(0) do\n      local cur_line = vim.fn.getline(i)\n      if vim.fn.strdisplaywidth(cur_line) > 80 then\n        local region = { from = { line = i, col = 1 }, to = { line = i, col = cur_line:len() } }\n        table.insert(res, region)\n      end\n    end\n    return res\n  end]])\n  child.lua('MiniAi.config.custom_textobjects = { L = _G.long_lines }')\n\n  local lines = { string.rep('a', 80), string.rep('b', 81), string.rep('c', 80), string.rep('d', 81) }\n  validate_tobj(lines, { 1, 0 }, 'aL', { { 2, 1 }, { 2, 81 } })\n  validate_tobj(lines, { 2, 0 }, 'aL', { { 2, 1 }, { 2, 81 } })\n\n  child.lua([[MiniAi.config.search_method = 'next']])\n  validate_tobj(lines, { 2, 0 }, 'aL', { { 4, 1 }, { 4, 81 } })\n\n  child.lua([[MiniAi.config.n_lines = 0]])\n  validate_no_tobj(lines, { 2, 0 }, 'aL')\nend\n\nT['Custom textobject']['documented examples']['balanced parenthesis with big enough width'] = function()\n  child.lua([[_G.wide_parens_spec = {\n    '%b()',\n    function(s, init)\n      if init > 1 or s:len() < 5 then return end\n      return 1, s:len()\n    end,\n    '^.().*().$'\n  }]])\n  child.lua('MiniAi.config.custom_textobjects = { p = _G.wide_parens_spec }')\n\n  validate_tobj1d('() (a) (aa) (aaa)', 0, 'ap', { 13, 17 })\nend\n\nT['Custom textobject']['documented examples']['word'] = function()\n  set_custom_tobj({ w = { '()()%f[%w]%w+()[ \\t]*()' } })\n\n  validate_tobj1d('  aaa  bb_cc.dd ', 0, 'aw', { 3, 7 })\n  validate_tobj1d('  aaa  bb_cc.dd ', 0, 'iw', { 3, 5 })\n  validate_tobj1d('  aaa  bb_cc.dd ', 0, '2aw', { 8, 9 })\n  validate_tobj1d('  aaa  bb_cc.dd ', 0, '3aw', { 11, 12 })\n  validate_tobj1d('  aaa  bb_cc.dd ', 0, '4aw', { 14, 16 })\n\n  validate_tobj({ 'aaa ' }, { 1, 0 }, 'aw', { { 1, 1 }, { 1, 4 } })\n  validate_tobj({ 'aaa\\t' }, { 1, 0 }, 'aw', { { 1, 1 }, { 1, 4 } })\n  validate_tobj({ 'aaa', 'bbb' }, { 1, 0 }, 'aw', { { 1, 1 }, { 1, 3 } })\nend\n\nT['Custom textobject']['documented examples']['camel case word'] = function()\n  set_custom_tobj({\n    c = {\n      { '%u[%l%d]+%f[^%l%d]', '%f[%S][%l%d]+%f[^%l%d]', '%f[%P][%l%d]+%f[^%l%d]', '^[%l%d]+%f[^%l%d]' },\n      '^().*()$',\n    },\n  })\n\n  validate_tobj1d('  aaaBbb_ccc_Ddd', 0, 'ac', { 3, 5 })\n  validate_tobj1d('  aaaBbb_ccc_Ddd', 0, '2ac', { 6, 8 })\n  validate_tobj1d('  aaaBbb_ccc_Ddd', 0, '3ac', { 10, 12 })\n  validate_tobj1d('  aaaBbb_ccc_Ddd', 0, '4ac', { 14, 16 })\n  validate_tobj1d('aaa', 0, 'ac', { 1, 3 })\n\n  validate_no_tobj1d('  A', 0, 'ac')\nend\n\nT['Custom textobject']['documented examples']['number'] = function()\n  set_custom_tobj({ N = { '%f[%d]%d+' } })\n\n  validate_tobj1d(' 1 10_11', 0, 'aN', { 2, 2 })\n  validate_tobj1d(' 1 10_11', 0, '2aN', { 4, 5 })\n  validate_tobj1d(' 1 10_11', 0, '3aN', { 7, 8 })\nend\n\nT['Custom textobject']['documented examples']['date'] = function()\n  set_custom_tobj({ d = { '()%d%d%d%d%-%d%d%-%d%d()' } })\n\n  validate_tobj1d(' 2022-07-26 9999-99-99', 0, 'ad', { 2, 11 })\n  validate_tobj1d(' 2022-07-26 9999-99-99', 0, '2ad', { 13, 22 })\nend\n\nT['Custom textobject']['documented examples']['Lua block string'] = function()\n  set_custom_tobj({ s = { '%[%[().-()%]%]' } })\n  validate_tobj1d([=[aa[[bb]]]=], 0, 'as', { 3, 8 })\n  validate_tobj1d([=[aa[[bb]]]=], 0, 'is', { 5, 6 })\n\n  local line = [=[aa[[]]]=]\n  validate_tobj1d(line, 0, 'is', { 5, 5 })\n  validate_edit1d(line, 0, line, 4, 'dis')\n  validate_edit1d(line, 0, line, 4, 'cis')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_align.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('align', config) end\nlocal unload_module = function() child.mini_unload('align') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\nlocal set_config_steps = function(tbl)\n  for key, value in pairs(tbl) do\n    child.lua('MiniAlign.config.steps.' .. key .. ' = ' .. value)\n  end\nend\n\nlocal set_config_opts = function(tbl)\n  for key, value in pairs(tbl) do\n    child.lua('MiniAlign.config.options.' .. key .. ' = ' .. vim.inspect(value))\n  end\nend\n\nlocal validate_step = function(var_name, step_name)\n  eq(child.lua_get(('type(%s)'):format(var_name)), 'table')\n\n  local keys = child.lua_get(('vim.tbl_keys(%s)'):format(var_name))\n  table.sort(keys)\n  eq(keys, { 'action', 'name' })\n\n  eq(child.lua_get(('type(%s.name)'):format(var_name)), 'string')\n  if step_name ~= nil then eq(child.lua_get(('%s.name'):format(var_name)), step_name) end\n\n  eq(child.lua_get(('vim.is_callable(%s.action)'):format(var_name)), true)\nend\n\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n\nlocal get_mode = function() return child.api.nvim_get_mode()['mode'] end\n\nlocal eq_tostring = function(var_name1, var_name2)\n  local cmd = string.format('tostring(%s) == tostring(%s)', var_name1, var_name2)\n  eq(child.lua_get(cmd), true)\nend\n\n-- Time constants\nlocal show_state_delay, error_message_force_delay = 1000, 500\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniAlign)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniAlign.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniAlign.config.' .. field), value) end\n  local expect_config_type = function(field, type_val)\n    eq(child.lua_get('type(MiniAlign.config.' .. field .. ')'), type_val)\n  end\n\n  -- Check default values\n  expect_config('mappings.start', 'ga')\n  expect_config('mappings.start_with_preview', 'gA')\n\n  expect_config_type('modifiers.s', 'function')\n  expect_config_type('modifiers.j', 'function')\n  expect_config_type('modifiers.m', 'function')\n  expect_config_type('modifiers.f', 'function')\n  expect_config_type('modifiers.t', 'function')\n  expect_config_type('modifiers.p', 'function')\n  expect_config_type(\n    string.format('modifiers[\"%s\"]', child.api.nvim_replace_termcodes('<BS>', true, true, true)),\n    'function'\n  )\n  expect_config_type('modifiers[\"=\"]', 'function')\n  expect_config_type('modifiers[\",\"]', 'function')\n  expect_config_type('modifiers[\" \"]', 'function')\n\n  expect_config('options.split_pattern', '')\n  expect_config('options.justify_side', 'left')\n  expect_config('options.merge_delimiter', '')\n\n  expect_config('steps.pre_split', {})\n  expect_config('steps.split', vim.NIL)\n  expect_config('steps.pre_justify', {})\n  expect_config('steps.justify', vim.NIL)\n  expect_config('steps.pre_merge', {})\n  expect_config('steps.merge', vim.NIL)\n\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ options = { justify_side = 'center' } })\n  eq(child.lua_get('MiniAlign.config.options.justify_side'), 'center')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { start = 1 } }, 'mappings.start', 'string')\n  expect_config_error({ mappings = { start_with_preview = 1 } }, 'mappings.start_with_preview', 'string')\n  expect_config_error({ modifiers = 'a' }, 'modifiers', 'table')\n  expect_config_error({ modifiers = { x = 1 } }, 'modifiers[\"x\"]', 'callable')\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ steps = { pre_split = 1 } }, 'steps.pre_split', 'array of steps')\n  expect_config_error({ steps = { split = 1 } }, 'steps.split', 'step')\n  expect_config_error({ steps = { pre_justify = 1 } }, 'steps.pre_justify', 'array of steps')\n  expect_config_error({ steps = { justify = 1 } }, 'steps.justify', 'step')\n  expect_config_error({ steps = { pre_merge = 1 } }, 'steps.pre_merge', 'array of steps')\n  expect_config_error({ steps = { merge = 1 } }, 'steps.merge', 'step')\n  expect_config_error({ silent = 'a' }, 'silent', 'boolean')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('xmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('ga', 'Align'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('x', 'ga')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { start = '' } })\n  eq(has_map('ga', 'Align'), false)\nend\n\nlocal validate_align_strings = function(input_strings, opts, ref_strings, steps)\n  local output = child.lua_get('MiniAlign.align_strings(...)', { input_strings, opts or {}, steps or {} })\n  eq(output, ref_strings)\nend\n\nT['align_strings()'] = new_set()\n\nT['align_strings()']['works'] = function()\n  validate_align_strings({ 'a=b', 'aa=b' }, { split_pattern = '=' }, { 'a =b', 'aa=b' })\nend\n\nT['align_strings()']['validates `strings` argument'] = function()\n  expect.error(function() child.lua([[MiniAlign.align_strings({'a', 1})]]) end, 'string')\n  expect.error(function() child.lua([[MiniAlign.align_strings('a')]]) end, 'array')\nend\n\nT['align_strings()']['respects `strings` argument'] = function()\n  validate_align_strings({ 'aaa=b', 'aa=b' }, { split_pattern = '=' }, { 'aaa=b', 'aa =b' })\nend\n\nT['align_strings()']['respects `opts` argument'] = function()\n  -- Should take default values from `MiniAlign.config.options`\n  child.lua([[MiniAlign.config.options.test = 'xxx']])\n  child.lua([[ MiniAlign.config.steps.pre_split = {\n    MiniAlign.new_step('test', function(strings, opts) strings[1] = opts.test end)\n  }]])\n  eq(child.lua_get([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, { split_pattern = '=' }, {})]]), { 'xxx', 'aa=b' })\nend\n\nT['align_strings()']['respects `opts.split_pattern`'] = function()\n  -- Single string\n  validate_align_strings({ 'a,b', 'aa,b' }, { split_pattern = ',' }, { 'a ,b', 'aa,b' })\n\n  -- Array of strings (should be recycled)\n  validate_align_strings(\n    { 'a,b=c,d=e,', 'aa,bb=cc,dd=ee,' },\n    { split_pattern = { ',', '=' } },\n    { 'a ,b =c ,d =e ,', 'aa,bb=cc,dd=ee,' }\n  )\nend\n\nT['align_strings()']['respects `opts.justify_side` argument'] = function()\n  -- Single string\n  --stylua: ignore start\n  validate_align_strings({ 'a=b', 'aaa=b' }, { split_pattern = '=', justify_side = 'left' },   { 'a  =b', 'aaa=b' })\n  validate_align_strings({ 'a=b', 'aaa=b' }, { split_pattern = '=', justify_side = 'center' }, { ' a =b', 'aaa=b' })\n  validate_align_strings({ 'a=b', 'aaa=b' }, { split_pattern = '=', justify_side = 'right' },  { '  a=b', 'aaa=b' })\n  validate_align_strings({ 'a=b', 'aaa=b' }, { split_pattern = '=', justify_side = 'none' },   { 'a=b',   'aaa=b' })\n  --stylua: ignore end\n\n  -- Array of strings (should be recycled)\n  validate_align_strings(\n    { 'a=b=c=d=e', 'aaa  =bbb  =ccc  =ddd  =eee' },\n    { split_pattern = '%s*=', justify_side = { 'left', 'center', 'right' } },\n    -- Part resulted from separator is treated the same as any other part\n    { 'a   =   b=   c   =d   =   e', 'aaa  =bbb  =ccc  =ddd  =eee' }\n  )\nend\n\nT['align_strings()']['respects `opts.merge_delimiter` argument'] = function()\n  -- Single string\n  validate_align_strings({ 'a=b' }, { split_pattern = '=', merge_delimiter = '-' }, { 'a-=-b' })\n\n  -- Array of strings (should be recycled)\n  validate_align_strings(\n    { 'a=b=c=' },\n    { split_pattern = '=', merge_delimiter = { '-', '!' } },\n    -- Part resulted from separator is treated the same as any other part\n    { 'a-=!b-=!c-=' }\n  )\nend\n\nT['align_strings()']['same `opts` is used for all steps'] = function()\n  -- So that it can be used by steps to pass information to later steps\n  set_config_steps({\n    pre_split = [[{ MiniAlign.new_step('sss', function(strings, opts) opts.sss = 'sss' end) }]],\n    merge = [[MiniAlign.new_step('mmm', function(parts, opts) return { opts.sss } end)]],\n  })\n  validate_align_strings({ 'a=b' }, { split_pattern = '=' }, { 'sss' })\nend\n\nT['align_strings()']['validates `steps` argument'] = function()\n  -- `split_pattern` is `''` by default but it is needed for `align_strings()`\n  set_config_opts({ split_pattern = '=' })\n\n  local validate = function(steps_str, error_pattern)\n    expect.error(function()\n      local cmd = string.format([[MiniAlign.align_strings({'a=b', 'aa=b'}, {}, %s)]], steps_str)\n      child.lua(cmd)\n    end, error_pattern)\n  end\n\n  validate([[{ pre_split = 1 }]], 'pre_split.*array of steps')\n  validate([[{ pre_split = { function() end } }]], 'pre_split.*array of steps')\n\n  validate([[{ split = 1 }]], 'split.*step')\n  validate([[{ split = function() end }]], 'split.*step')\n\n  validate([[{ pre_justify = 1 }]], 'pre_justify.*array of steps')\n  validate([[{ pre_justify = { function() end } }]], 'pre_justify.*array of steps')\n\n  validate([[{ justify = 1 }]], 'justify.*step')\n  validate([[{ justify = function() end }]], 'justify.*step')\n\n  validate([[{ pre_merge = 1 }]], 'pre_merge.*array of steps')\n  validate([[{ pre_merge = { function() end } }]], 'pre_merge.*array of steps')\n\n  validate([[{ merge = 1 }]], 'merge.*step')\n  validate([[{ merge = function() end }]], 'merge.*step')\nend\n\nT['align_strings()']['respects `steps.pre_split` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local step_str, cmd\n\n  -- Array of steps\n  step_str = [[MiniAlign.new_step('tmp', function(strings) strings[1] = 'a=b' end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'aaa=b', 'aa=b' }, {}, { pre_split = { %s } })]], step_str)\n  eq(child.lua_get(cmd), { 'a =b', 'aa=b' })\n\n  -- Should validate that step correctly modified in place\n  step_str = [[MiniAlign.new_step('tmp', function(strings) strings[1] = 1 end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { pre_split = { %s } })]], step_str)\n  expect.error(function() child.lua(cmd) end, 'Step `tmp` of `pre_split` should preserve structure of `strings`.')\n\n  -- Uses `MiniAlign.config.steps` as default\n  set_config_steps({ pre_split = [[{ MiniAlign.new_step('tmp', function(strings) strings[1] = 'a=b' end) }]] })\n  validate_align_strings({ 'aaa=b', 'aa=b' }, { split_pattern = '=' }, { 'a =b', 'aa=b' })\n\n  -- Is called with `opts`\n  step_str = [[MiniAlign.new_step('tmp', function(strings, opts) strings[1] = opts.tmp end)]]\n  cmd =\n    string.format([[MiniAlign.align_strings({ 'aaa=b', 'aa=b' }, { tmp = 'xxx' }, { pre_split = { %s } })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx', 'aa=b' })\nend\n\nT['align_strings()']['respects `steps.split` argument'] = function()\n  local step_str, cmd\n\n  -- Action output should be parts or convertible to it.\n  step_str = [[MiniAlign.new_step('tmp', function(strings) return { { 'a', 'b' }, {'aa', 'b'} } end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { split = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'a b', 'aab' })\n\n  step_str =\n    [[MiniAlign.new_step('tmp', function(strings) return MiniAlign.as_parts({ { 'a', 'b' }, {'aa', 'b'} }) end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { split = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'a b', 'aab' })\n\n  -- Uses `MiniAlign.config.steps` as default\n  set_config_steps({\n    split = [[MiniAlign.new_step('tmp', function(strings) return MiniAlign.as_parts({ { 'a', 'b' }, {'aa', 'b'} }) end)]],\n  })\n  validate_align_strings({ 'a,b', 'aa,b' }, {}, { 'a b', 'aab' })\n\n  -- Should validate that step's output is convertible to parts\n  step_str = [[MiniAlign.new_step('tmp', function(strings) return { { 'a', 1 }, {'aa', 'b'} } end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { split = %s })]], step_str)\n  expect.error(function() child.lua(cmd) end, 'convertible to parts')\n\n  -- Is called with `opts`\n  step_str = [[MiniAlign.new_step('tmp', function(strings, opts) return MiniAlign.as_parts(opts.tmp) end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, { tmp = { { 'xxx' } } }, { split = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx' })\nend\n\nT['align_strings()']['respects `steps.pre_justify` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local step_str, cmd\n\n  -- Array of steps\n  step_str = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 'xxx' end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'aaa=b', 'aa=b' }, {}, { pre_justify = { %s } })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx=b', 'aa =b' })\n\n  -- Should validate that step correctly modified in place\n  step_str = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 1 end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { pre_justify = { %s } })]], step_str)\n  local ref_text = 'Step `tmp` of `pre_justify` should preserve structure of `parts`. See `:h MiniAlign.as_parts()`.'\n  expect.error(function() child.lua(cmd) end, vim.pesc(ref_text))\n\n  -- Uses `MiniAlign.config.steps` as default\n  set_config_steps({ pre_justify = [[{ MiniAlign.new_step('tmp', function(parts) parts[1][1] = 'xxx' end) }]] })\n  validate_align_strings({ 'aaa=b', 'aa=b' }, { split_pattern = '=' }, { 'xxx=b', 'aa =b' })\n\n  -- Is called with `opts`\n  step_str = [[MiniAlign.new_step('tmp', function(parts, opts) parts[1][1] = opts.tmp end)]]\n  cmd =\n    string.format([[MiniAlign.align_strings({ 'aaa=b', 'aa=b' }, { tmp = 'xxx' }, { pre_justify = { %s } })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx=b', 'aa =b' })\nend\n\nT['align_strings()']['respects `steps.justify` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local step_str, cmd\n\n  -- Action should modify parts in place.\n  step_str = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 'xxx' end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { justify = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx=b', 'aa=b' })\n\n  -- Uses `MiniAlign.config.steps` as default\n  set_config_steps({\n    justify = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 'xxx' end)]],\n  })\n  validate_align_strings({ 'a=b', 'aa=b' }, { split_pattern = '=' }, { 'xxx=b', 'aa=b' })\n\n  -- Should validate that step correctly modified in place\n  step_str = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 1 end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { justify = %s })]], step_str)\n  local ref_text = 'Step `tmp` of `justify` should preserve structure of `parts`. See `:h MiniAlign.as_parts()`.'\n  expect.error(function() child.lua(cmd) end, vim.pesc(ref_text))\n\n  -- Is called with `opts`\n  step_str = [[MiniAlign.new_step('tmp', function(parts, opts) parts[1][1] = opts.tmp end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, { tmp = 'xxx' }, { justify = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx=b', 'aa=b' })\nend\n\nT['align_strings()']['respects `steps.pre_merge` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local step_str, cmd\n\n  -- Array of steps\n  step_str = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 'xxx' end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'aaa=b', 'aa=b' }, {}, { pre_merge = { %s } })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx=b', 'aa =b' })\n\n  -- Should validate that step correctly modified in place\n  step_str = [[MiniAlign.new_step('tmp', function(parts) parts[1][1] = 1 end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { pre_merge = { %s } })]], step_str)\n  local ref_text = 'Step `tmp` of `pre_merge` should preserve structure of `parts`. See `:h MiniAlign.as_parts()`.'\n  expect.error(function() child.lua(cmd) end, vim.pesc(ref_text))\n\n  -- Uses `MiniAlign.config.steps` as default\n  set_config_steps({ pre_merge = [[{ MiniAlign.new_step('tmp', function(parts) parts[1][1] = 'xxx' end) }]] })\n  validate_align_strings({ 'aaa=b', 'aa=b' }, { split_pattern = '=' }, { 'xxx=b', 'aa =b' })\n\n  -- Is called with `opts`\n  step_str = [[MiniAlign.new_step('tmp', function(parts, opts) parts[1][1] = opts.tmp end)]]\n  cmd =\n    string.format([[MiniAlign.align_strings({ 'aaa=b', 'aa=b' }, { tmp = 'xxx' }, { pre_merge = { %s } })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx=b', 'aa =b' })\nend\n\nT['align_strings()']['respects `steps.merge` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local step_str, cmd\n\n  -- Action should return array of strings.\n  step_str = [[MiniAlign.new_step('tmp', function(parts) return { 'xxx' } end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { merge = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx' })\n\n  -- Uses `MiniAlign.config.steps` as default\n  set_config_steps({ merge = [[MiniAlign.new_step('tmp', function(parts) return { 'xxx' } end)]] })\n  validate_align_strings({ 'a=b' }, { split_pattern = '=' }, { 'xxx' })\n\n  -- Should validate that output is an array of strings\n  step_str = [[MiniAlign.new_step('tmp', function(parts) return { 'a', 1 } end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, {}, { merge = %s })]], step_str)\n  expect.error(function() child.lua(cmd) end, vim.pesc('Output of `merge` step should be array of strings.'))\n\n  -- Is called with `opts`\n  step_str = [[MiniAlign.new_step('tmp', function(parts, opts) return { opts.tmp } end)]]\n  cmd = string.format([[MiniAlign.align_strings({ 'a=b', 'aa=b' }, { tmp = 'xxx' }, { merge = %s })]], step_str)\n  eq(child.lua_get(cmd), { 'xxx' })\nend\n\nT['align_strings()']['works with multibyte characters'] = function()\n  validate_align_strings(\n    { 'ыффццц', 'ыыыффц' },\n    { split_pattern = 'ф', justify_side = 'center', merge_delimiter = 'ю' },\n    { ' ы юфюфюццц', 'ыыыюфюфю ц' }\n  )\nend\n\nT['align_strings()']['works in edge cases'] = function()\n  validate_align_strings({}, {}, {})\n  validate_align_strings({ '' }, {}, { '' })\n  validate_align_strings({ '', '' }, {}, { '', '' })\n  validate_align_strings({ '', ' ' }, {}, { '', ' ' })\nend\n\nT['align_strings()']['does not affect input array'] = function()\n  child.lua([[strings = { 'a=b', 'aa=b' }]])\n  child.lua([[pre_split = { MiniAlign.new_step('aaa', function(s, _) s[1] = 'xxx' end) }]])\n  child.lua([[MiniAlign.align_strings(strings, { split_pattern = '=' }, { pre_split = pre_split })]])\n  eq(child.lua_get('strings'), { 'a=b', 'aa=b' })\nend\n\nT['align_strings()']['respects `vim.b.minialign_config`'] = function()\n  child.b.minialign_config = { options = { split_pattern = '=' } }\n  validate_align_strings({ 'a=b', 'aa=b' }, {}, { 'a =b', 'aa=b' })\n\n  -- Should take precedence over global cofnfig\n  set_config_opts({ split_pattern = ',' })\n  validate_align_strings({ 'a=b', 'aa=b' }, {}, { 'a =b', 'aa=b' })\nend\n\nlocal is_parts = function(var_name)\n  local cmd = string.format('getmetatable(%s).class', var_name)\n  eq(child.lua_get(cmd), 'parts')\nend\n\nT['as_parts()'] = new_set()\n\nT['as_parts()']['works'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a', 'b' }, { 'c' } })]])\n  eq(child.lua_get('type(parts.get_dims)'), 'function')\nend\n\nT['as_parts()']['validates arguments'] = function()\n  local validate = function(input_str, err_pattern)\n    expect.error(function() child.lua('MiniAlign.as_parts(' .. input_str .. ')') end, err_pattern)\n  end\n\n  validate('', 'Input of `as_parts%(%)` should be table')\n  validate('1', 'table')\n  validate([[{ 'a' }]], 'Input of `as_parts%(%)` values should be an array of strings')\n  validate([[{ { 1 } }]], 'array of strings')\n  validate([[{ { 'a' }, 'a' }]], 'array of strings')\nend\n\nT['as_parts()']['works with empty table'] = function()\n  -- Empty parts\n  child.lua('empty = MiniAlign.as_parts({})')\n  is_parts('empty')\n\n  -- All methods should work\n  local validate_method = function(method_call, output, ...)\n    child.lua('empty = MiniAlign.as_parts({})')\n    local cmd = string.format('empty.%s', method_call)\n    if output ~= nil then\n      eq(child.lua_get(cmd, { ... }), output)\n    else\n      child.lua(cmd, { ... })\n      eq(child.lua_get('empty'), {})\n    end\n  end\n\n  validate_method([[apply_inplace(function(s) return 'a' end)]])\n  validate_method('group()')\n  validate_method('pair()')\n  validate_method('trim()')\n\n  validate_method('apply(function(s) return 1 end)', {})\n  validate_method('get_dims()', { row = 0, col = 0 })\n  validate_method('slice_col(1)', {})\n  validate_method('slice_row(1)', {})\nend\n\nT['as_parts()']['`apply()` method'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a', 'b' }, { 'c' } })]])\n  eq(\n    child.lua_get('parts.apply(function(x, data) return x .. data.row .. data.col end)'),\n    { { 'a11', 'b12' }, { 'c21' } }\n  )\nend\n\nT['as_parts()']['`apply_inplace()` method'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a', 'b' }, { 'c' } })]])\n  child.lua('new_parts = parts.apply_inplace(function(x, data) return x .. data.row .. data.col end)')\n  eq(child.lua_get('parts'), { { 'a11', 'b12' }, { 'c21' } })\n\n  -- Should return itself to enable chaining\n  eq_tostring('parts', 'new_parts')\nend\n\nT['as_parts()']['`get_dims()` method'] = function()\n  local validate = function(arr2d_str, dims)\n    local cmd = string.format('MiniAlign.as_parts(%s).get_dims()', arr2d_str)\n    eq(child.lua_get(cmd), dims)\n  end\n\n  validate([[{ { 'a' } }]], { row = 1, col = 1 })\n  validate([[{ { 'a', 'b' } }]], { row = 1, col = 2 })\n  validate([[{ { 'a', 'b' }, { 'c' } }]], { row = 2, col = 2 })\n  validate([[{ { 'a', 'b' }, { 'c', 'd', 'e' } }]], { row = 2, col = 3 })\n  validate([[{}]], { row = 0, col = 0 })\nend\n\nlocal validate_parts_group = function(arr2d_str, mask_str, output, direction)\n  child.lua(('parts = MiniAlign.as_parts(%s)'):format(arr2d_str))\n  direction = direction == nil and '' or (', ' .. vim.inspect(direction))\n  child.lua(('new_parts = parts.group(%s%s)'):format(mask_str, direction))\n  eq(child.lua_get('parts'), output)\n\n  -- Should return itself to enable chaining\n  eq_tostring('parts', 'new_parts')\nend\n\nT['as_parts()']['`group()` method'] = new_set()\n\nT['as_parts()']['`group()` method']['works'] = function()\n  validate_parts_group(\n    [[{ { 'a', 'b', 'c' }, { 'd' } }]],\n    '{ { false, false, true }, { true } }',\n    { { 'abc' }, { 'd' } }\n  )\nend\n\nT['as_parts()']['`group()` method']['respects `mask` argument'] = function()\n  local arr2d_str\n\n  arr2d_str = [[{ { 'a', 'b' } }]]\n  validate_parts_group(arr2d_str, '{ { false, false } }', { { 'ab' } })\n  validate_parts_group(arr2d_str, '{ { false, true } }', { { 'ab' } })\n  validate_parts_group(arr2d_str, '{ { true, false } }', { { 'a', 'b' } })\n  validate_parts_group(arr2d_str, '{ { true, true } }', { { 'a', 'b' } })\n\n  arr2d_str = [[{ { 'a', 'b' }, { 'c', 'd', 'e' } }]]\n  validate_parts_group(arr2d_str, '{ { false, true }, { true, false, true } }', { { 'ab' }, { 'c', 'de' } })\n\n  -- Default direction is 'left'\n  arr2d_str = [[{ { 'a', 'b', 'c', 'd' } }]]\n  validate_parts_group(arr2d_str, '{ { false, true, false, false } }', { { 'ab', 'cd' } })\nend\n\nT['as_parts()']['`group()` method']['respects `direction` argument'] = function()\n  local validate = function(...)\n    local dots = { ... }\n    table.insert(dots, 'right')\n    validate_parts_group(unpack(dots))\n  end\n\n  local arr2d_str\n\n  arr2d_str = [[{ { 'a', 'b' } }]]\n  validate(arr2d_str, '{ { false, false } }', { { 'ab' } })\n  validate(arr2d_str, '{ { false, true } }', { { 'a', 'b' } })\n  validate(arr2d_str, '{ { true, false } }', { { 'ab' } })\n  validate(arr2d_str, '{ { true, true } }', { { 'a', 'b' } })\n\n  arr2d_str = [[{ { 'a', 'b' }, { 'c', 'd', 'e' } }]]\n  validate(arr2d_str, '{ { false, true }, { true, false, true } }', { { 'a', 'b' }, { 'cd', 'e' } })\n\n  -- Should differ from default 'left' direction\n  arr2d_str = [[{ { 'a', 'b', 'c', 'd' } }]]\n  validate(arr2d_str, '{ { false, true, false, false } }', { { 'a', 'bcd' } })\nend\n\nT['as_parts()']['`pair()` method'] = new_set()\n\nT['as_parts()']['`pair()` method']['works'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a' }, { 'b', 'c' }, { 'd', 'e', 'f' } })]])\n  child.lua('new_parts = parts.pair()')\n  eq(child.lua_get('parts'), { { 'a' }, { 'bc' }, { 'de', 'f' } })\n\n  -- Should return itself to enable chaining\n  eq_tostring('parts', 'new_parts')\nend\n\nT['as_parts()']['`pair()` method']['respects `direction` argument'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a' }, { 'b', 'c' }, { 'd', 'e', 'f' } })]])\n  child.lua([[parts.pair('right')]])\n  eq(child.lua_get('parts'), { { 'a' }, { 'bc' }, { 'd', 'ef' } })\nend\n\nT['as_parts()']['`slice_col()` method'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a' }, { 'b', 'c' }, { 'd' } })]])\n\n  eq(child.lua_get('parts.slice_col(0)'), {})\n  eq(child.lua_get('parts.slice_col(1)'), { 'a', 'b', 'd' })\n  -- `slice_col()` may not return array (table with only 1, ..., n keys)\n  eq(child.lua_get([[vim.deep_equal(parts.slice_col(2), { [2] = 'c' })]]), true)\n  eq(child.lua_get('parts.slice_col(3)'), {})\nend\n\nT['as_parts()']['`slice_row()` method'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { 'a' }, { 'b', 'c' } })]])\n\n  eq(child.lua_get('parts.slice_row(0)'), {})\n  eq(child.lua_get('parts.slice_row(1)'), { 'a' })\n  eq(child.lua_get('parts.slice_row(2)'), { 'b', 'c' })\n  eq(child.lua_get('parts.slice_col(3)'), {})\nend\n\nT['as_parts()']['`trim()` method'] = new_set()\n\nT['as_parts()']['`trim()` method']['works'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { ' a ', ' b ', ' c', 'd ', 'e' }, { '  f ' } })]])\n  child.lua('new_parts = parts.trim()')\n  -- By default trims from both directions and keeps indentation (left\n  -- whitespace of every first row string)\n  eq(child.lua_get('parts'), { { ' a', 'b', 'c', 'd', 'e' }, { '  f' } })\n\n  -- Should return itself to enable chaining\n  eq_tostring('parts', 'new_parts')\nend\n\nT['as_parts()']['`trim()` method']['validates arguments'] = function()\n  child.lua([[parts = MiniAlign.as_parts({ { ' a ' } })]])\n  local err_pattern\n\n  -- `direction`\n  err_pattern = '`direction` should be one of \"both\", \"left\", \"none\", \"right\"'\n  expect.error(function() child.lua([[parts.trim(1)]]) end, err_pattern)\n  expect.error(function() child.lua([[parts.trim('a')]]) end, err_pattern)\n\n  -- `indent`\n  err_pattern = '`indent` should be one of \"high\", \"keep\", \"low\", \"remove\"'\n  expect.error(function() child.lua([[parts.trim('both', 1)]]) end, err_pattern)\n  expect.error(function() child.lua([[parts.trim('both', 'a')]]) end, err_pattern)\nend\n\nT['as_parts()']['`trim()` method']['respects `direction` argument'] = function()\n  local validate = function(direction, output)\n    child.lua([[parts = MiniAlign.as_parts({ { ' a ', ' b ', ' c', 'd ', 'e' }, { '  f ' } })]])\n    child.lua(([[parts.trim('%s')]]):format(direction))\n    eq(child.lua_get('parts'), output)\n  end\n\n  --stylua: ignore start\n  validate('both',  { { ' a',  'b',   'c',  'd',  'e' }, { '  f' } })\n  validate('left',  { { ' a ', 'b ',  'c',  'd ', 'e' }, { '  f ' } })\n  validate('right', { { ' a',  ' b',  ' c', 'd',  'e' }, { '  f' } })\n  validate('none',  { { ' a ', ' b ', ' c', 'd ', 'e' }, { '  f ' } })\n  --stylua: ignore end\nend\n\nT['as_parts()']['`trim()` method']['respects `indent` argument'] = function()\n  local validate = function(indent, output)\n    child.lua([[parts = MiniAlign.as_parts({ { ' a ', ' b ' }, { '  c ', ' d ' } })]])\n    child.lua(([[parts.trim('both', '%s')]]):format(indent))\n    eq(child.lua_get('parts'), output)\n  end\n\n  --stylua: ignore start\n  validate('keep',   { { ' a',  'b' }, { '  c', 'd' } })\n  validate('low',    { { ' a',  'b' }, { ' c',  'd' } })\n  validate('high',   { { '  a', 'b' }, { '  c', 'd' } })\n  validate('remove', { { 'a',   'b' }, { 'c',   'd' } })\n  --stylua: ignore end\nend\n\nT['new_step()'] = new_set()\n\nT['new_step()']['works'] = function()\n  child.lua([[step = MiniAlign.new_step('aaa', function() end)]])\n  validate_step('step', 'aaa')\n\n  -- Allows callable table as action\n  child.lua([[action = setmetatable({}, { __call = function() end })]])\n  child.lua([[step = MiniAlign.new_step('aaa', action)]])\n  validate_step('step', 'aaa')\nend\n\nT['new_step()']['validates arguments'] = function()\n  local validate = function(args_str, err_pattern)\n    expect.error(function() child.lua('MiniAlign.new_step(' .. args_str .. ')') end, err_pattern)\n  end\n\n  validate([[1]], 'Step name should be string')\n  validate([['aaa', 1]], 'Step action should be callable')\nend\n\nT['gen_step'] = new_set()\n\nT['gen_step']['default_split()'] = new_set({\n  hooks = { pre_case = function() set_config_steps({ split = [[MiniAlign.gen_step.default_split('test')]] }) end },\n})\n\nT['gen_step']['default_split()']['works'] = function()\n  -- Returns proper step\n  child.lua([[step = MiniAlign.gen_step.default_split()]])\n  validate_step('step', 'split')\n\n  -- Single string\n  validate_align_strings({ 'a,b', 'aa,b' }, { split_pattern = ',' }, { 'a ,b', 'aa,b' })\n\n  -- Array of strings (should be recycled)\n  validate_align_strings({ 'a,b', 'aa,b' }, { split_pattern = { ',' } }, { 'a ,b', 'aa,b' })\n  validate_align_strings(\n    { 'a,b=c,d=e,', 'aa,bb=cc,dd=ee,' },\n    { split_pattern = { ',', '=' } },\n    { 'a ,b =c ,d =e ,', 'aa,bb=cc,dd=ee,' }\n  )\nend\n\nT['gen_step']['default_split()']['verifies relevant options'] = function()\n  local pat = 'Option `split_pattern`.*string or array of strings'\n  expect.error(function() child.lua('MiniAlign.align_strings({ \"a\" }, { split_pattern = 1 }, {})') end, pat)\n  pat = 'Option `split_exclude_patterns`.*array of strings'\n  expect.error(function() child.lua('MiniAlign.align_strings({ \"a\" }, { split_exclude_patterns = 1 }, {})') end, pat)\nend\n\nT['gen_step']['default_split()']['allows split Lua pattern'] = function()\n  set_config_opts({ split_pattern = '%s*=%s*', merge_delimiter = '-' })\n  validate_align_strings({ 'a=b  =c=  d  =  e' }, {}, { 'a-=-b-  =-c-=  -d-  =  -e' })\nend\n\nT['gen_step']['default_split()']['verifies bad split pattern'] = function()\n  local pat = vim.pesc('(mini.align) Pattern \"%f[%s]\" can not advance search.')\n  expect.error(function() child.lua('MiniAlign.align_strings({ \"a \" }, { split_pattern = \"%f[%s]\" })') end, pat)\nend\n\nT['gen_step']['default_split()']['works with different number of output parts'] = function()\n  set_config_opts({ split_pattern = ',', merge_delimiter = '-' })\n  validate_align_strings({ 'a', 'b,', 'c,d' }, {}, { 'a', 'b-,', 'c-,-d' })\nend\n\nT['gen_step']['default_split()']['works with empty input strings'] = function()\n  child.lua('step = MiniAlign.gen_step.default_split()')\n  eq(\n    child.lua_get([[step.action({ 'a=b', '', '=', '' }, { split_pattern = '=' })]]),\n    { { 'a', '=', 'b' }, { '' }, { '', '=' }, { '' } }\n  )\nend\n\nT['gen_step']['default_split()']['works with no split pattern found'] = function()\n  set_config_opts({ split_pattern = ',', merge_delimiter = '-' })\n\n  -- In some lines\n  validate_align_strings({ 'a,b', 'a=b' }, { justify_side = 'center' }, { ' a -,-b', 'a=b' })\n\n  -- In all lines\n  validate_align_strings({ 'a=b', 'a=bb' }, {}, { 'a=b', 'a=bb' })\nend\n\nT['gen_step']['default_split()']['works with special split patterns'] = function()\n  set_config_opts({ merge_delimiter = '-' })\n\n  -- Treat `''` as no split pattern is found\n  set_config_opts({ split_pattern = '' })\n  validate_align_strings({ 'a=b', 'a=bbb' }, {}, { 'a=b', 'a=bbb' })\n\n  -- Treat `'.'` as any character is a split\n  set_config_opts({ split_pattern = '.' })\n  validate_align_strings({ 'a=b', 'a=bbb' }, {}, { 'a-=-b', 'a-=-b-b-b' })\n\n  -- Works with `^`\n  set_config_opts({ split_pattern = '^.' })\n  validate_align_strings({ 'a=b', 'a=bbb' }, {}, { 'a-=b', 'a-=bbb' })\n\n  -- Works with `$`\n  set_config_opts({ split_pattern = '.$' })\n  validate_align_strings({ 'a=b', 'a=bbb' }, {}, { 'a=  -b', 'a=bb-b' })\nend\n\nT['gen_step']['default_split()']['respects `split_exclude_patterns` option'] = function()\n  validate_align_strings(\n    { [[a=\"==\"'=='b=c]], 'a=b=c' },\n    { split_pattern = '=', split_exclude_patterns = { [[\".-\"]], [['.-']] } },\n    { [[a=\"==\"'=='b=c]], 'a=b        =c' }\n  )\n\n  -- Split match should be ignored if any its edge is inside any forbidden span\n  validate_align_strings(\n    { 'a\"<\"=b<\"=c', 'a<\"=b' },\n    { split_pattern = '<\"=', split_exclude_patterns = { [[\".-\"]] } },\n    { 'a\"<\"=b<\"=c', 'a     <\"=b' }\n  )\nend\n\nT['gen_step']['default_split()']['works with special exclude patterns'] = function()\n  local lines = { 'a=b', 'cc=d', 'eee=f' }\n  local output_lines = { 'a=b', 'cc =d', 'eee=f' }\n\n  -- Start of line\n  validate_align_strings(lines, { split_pattern = '=', split_exclude_patterns = { '^a.*' } }, output_lines)\n\n  -- End of line\n  validate_align_strings(lines, { split_pattern = '=', split_exclude_patterns = { 'a.*$' } }, output_lines)\n\n  -- Both start of line and end of line\n  validate_align_strings(lines, { split_pattern = '=', split_exclude_patterns = { '^a.*$' } }, output_lines)\nend\n\n--stylua: ignore\nT['gen_step']['default_split()']['matches inside forbidden spans do not affect split pattern recycling'] = function()\n  validate_align_strings(\n    { [[a,\"b=b\"=c,d]], 'aa,bb=cc,dd' },\n    { split_pattern = { ',', '=' }, split_exclude_patterns = { [[\".-\"]] } },\n    { [[a ,\"b=b\"=c ,d]], 'aa,bb   =cc,dd' }\n  )\nend\n\nT['gen_step']['default_justify()'] = new_set({\n  hooks = {\n    pre_case = function() set_config_steps({ justify = [[MiniAlign.gen_step.default_justify('test')]] }) end,\n  },\n})\n\nT['gen_step']['default_justify()']['works'] = function()\n  -- Returns proper step\n  child.lua([[step = MiniAlign.gen_step.default_justify()]])\n  validate_step('step', 'justify')\n\n  -- Single string\n  set_config_opts({ split_pattern = '=' })\n\n  --stylua: ignore start\n  validate_align_strings({ 'a=b', 'aaa=b' }, { justify_side = 'left' },   { 'a  =b', 'aaa=b' })\n  validate_align_strings({ 'a=b', 'aaa=b' }, { justify_side = 'center' }, { ' a =b', 'aaa=b' })\n  validate_align_strings({ 'a=b', 'aaa=b' }, { justify_side = 'right' },  { '  a=b', 'aaa=b' })\n  validate_align_strings({ 'a=b', 'aaa=b' }, { justify_side = 'none' },   { 'a=b',   'aaa=b' })\n  --stylua: ignore end\n\n  -- Array of strings (should be recycled)\n  set_config_opts({ split_pattern = '%s*=' })\n  validate_align_strings(\n    { 'a=b=c=d=e', 'aaa  =bbb  =ccc  =ddd  =eee' },\n    { justify_side = { 'left', 'center', 'right' } },\n    -- Part resulted from separator is treated the same as any other part\n    { 'a   =   b=   c   =d   =   e', 'aaa  =bbb  =ccc  =ddd  =eee' }\n  )\nend\n\nT['gen_step']['default_justify()']['verifies relevant options'] = function()\n  local pat = 'Option `justify_side`.*one of.*or array'\n  expect.error(function() child.lua('MiniAlign.align_strings({ \"a\" }, { justify_side = 1 }, {})') end, pat)\nend\n\nT['gen_step']['default_justify()']['works with multibyte characters'] = function()\n  set_config_opts({ split_pattern = '=' })\n\n  --stylua: ignore start\n  validate_align_strings({ 'ы=ю', 'ыыы=ююю' }, { justify_side = 'left' },   { 'ы  =ю',   'ыыы=ююю' })\n  validate_align_strings({ 'ы=ю', 'ыыы=ююю' }, { justify_side = 'center' }, { ' ы = ю',  'ыыы=ююю' })\n  validate_align_strings({ 'ы=ю', 'ыыы=ююю' }, { justify_side = 'right' },  { '  ы=  ю', 'ыыы=ююю' })\n  validate_align_strings({ 'ы=ю', 'ыыы=ююю' }, { justify_side = 'none' },   { 'ы=ю',     'ыыы=ююю' })\n  --stylua: ignore end\nend\n\nT['gen_step']['default_justify()']['does not add trailing whitespace'] = function()\n  set_config_opts({ split_pattern = '=' })\n\n  --stylua: ignore start\n  validate_align_strings({ 'a=b', '', 'a=bbb' }, { justify_side = 'left' },   { 'a=b',   '', 'a=bbb' })\n  validate_align_strings({ 'a=b', '', 'a=bbb' }, { justify_side = 'center' }, { 'a= b',  '', 'a=bbb' })\n  validate_align_strings({ 'a=b', '', 'a=bbb' }, { justify_side = 'right' },  { 'a=  b', '', 'a=bbb' })\n  validate_align_strings({ 'a=b', '', 'a=bbb' }, { justify_side = 'none' },   { 'a=b',   '', 'a=bbb' })\n  --stylua: ignore end\n\n  -- Also shouldn't add trailing whitespace in multicharacter split\n  validate_align_strings({ 'aa==bb', 'c=' }, { split_pattern = '=+' }, { 'aa==bb', 'c =' })\nend\n\nT['gen_step']['default_justify()']['last row element width is ignored for left justify side'] = function()\n  set_config_opts({ split_pattern = '=', justify_side = 'left' })\n\n  -- It won't be padded so shouldn't contribute to column width\n  validate_align_strings({ 'a=b', 'aa=b', 'aaaaa' }, {}, { 'a =b', 'aa=b', 'aaaaa' })\n  validate_align_strings({ 'a=b=c', 'a=bb=c', 'a=bbbbb' }, {}, { 'a=b =c', 'a=bb=c', 'a=bbbbb' })\nend\n\nT['gen_step']['default_justify()']['prefers padding left for center justify side'] = function()\n  set_config_opts({ split_pattern = '=', justify_side = 'center' })\n\n  validate_align_strings({ 'a=b', 'aaaa=b' }, {}, { '  a =b', 'aaaa=b' })\nend\n\nT['gen_step']['default_justify()']['output step uses `opts.justify_offsets`'] = function()\n  set_config_opts({ split_pattern = '=' })\n\n  -- Using `opts.justify_offsets` allows to respect string prefixes but without\n  -- processing them. So in this case output should be the same as with\n  -- `{ '   a=b', '  a=b', 'a=b' }` and equal offsets (but without indents).\n  validate_align_strings({ 'a=b', 'a=b', 'a=b' }, { justify_offsets = { 3, 2, 0 } }, { 'a=b', 'a =b', 'a   =b' })\nend\n\nT['gen_step']['default_merge()'] = new_set({\n  hooks = {\n    pre_case = function() set_config_steps({ merge = [[MiniAlign.gen_step.default_merge('test')]] }) end,\n  },\n})\n\nT['gen_step']['default_merge()']['works'] = function()\n  set_config_opts({ split_pattern = '=' })\n\n  -- Returns proper step\n  child.lua([[step = MiniAlign.gen_step.default_merge()]])\n  validate_step('step', 'merge')\n\n  -- Single string\n  validate_align_strings({ 'a=b' }, { merge_delimiter = '-' }, { 'a-=-b' })\n\n  -- Array of strings (should be recycled)\n  validate_align_strings(\n    { 'a=b=c=' },\n    { merge_delimiter = { '-', '!' } },\n    -- Part resulted from separator is treated the same as any other part\n    { 'a-=!b-=!c-=' }\n  )\nend\n\nT['gen_step']['default_merge()']['works in edge cases'] = function()\n  validate_align_strings({}, {}, {})\n  validate_align_strings({ '' }, {}, { '' })\n  validate_align_strings({ '', '' }, {}, { '', '' })\n  validate_align_strings({ '', ' ' }, {}, { '', ' ' })\nend\n\nT['gen_step']['default_merge()']['verifies relevant options'] = function()\n  local pat = 'Option `merge_delimiter`.*string or array of strings'\n  expect.error(function() child.lua('MiniAlign.align_strings({ \"a\" }, { merge_delimiter = 1 }, {})') end, pat)\nend\n\nT['gen_step']['default_merge()']['does not merge empty strings in parts'] = function()\n  set_config_opts({ split_pattern = '=' })\n\n  -- Shouldn't result into adding extra merge\n  validate_align_strings({ 'a===b' }, { merge_delimiter = '-' }, { 'a-=-=-=-b' })\n  validate_align_strings({ '=a' }, { merge_delimiter = '-' }, { '=-a' })\nend\n\nT['gen_step']['default_merge()']['preserves indentation with whitespace in merge delimmiter'] = function()\n  set_config_opts({ split_pattern = '=' })\n\n  -- Should not add whitespace to the first part if all of them are indent\n  validate_align_strings({ ' =a=b', '  =c=d' }, { merge_delimiter = ' ' }, { '  = a = b', '  = c = d' })\n  validate_align_strings({ ' =a=b', '=c=d' }, { merge_delimiter = ' ' }, { ' = a = b', ' = c = d' })\n  validate_align_strings({ '=a=b', '=c=d' }, { merge_delimiter = ' ' }, { '= a = b', '= c = d' })\n\n  validate_align_strings({ ' =a=b', '  =c=d' }, { merge_delimiter = ' _' }, { '  _= _a _= _b', '  _= _c _= _d' })\n\n  validate_align_strings({ ' =a=b', 'x=c=d' }, { merge_delimiter = ' ' }, { '  = a = b', 'x = c = d' })\n\n  child.o.tabstop = 2\n  validate_align_strings({ '\\t=a=b', '\\t\\t=c=d' }, { merge_delimiter = '\\t' }, { '\\t  =\\ta\\t=\\tb', '\\t\\t=\\tc\\t=\\td' })\n  validate_align_strings({ '\\t=a=b', '\\t\\t=c=d' }, { merge_delimiter = ' ' }, { '\\t  = a = b', '\\t\\t= c = d' })\nend\n\nT['gen_step']['filter()'] = new_set()\n\nT['gen_step']['filter()']['works'] = function()\n  set_config_opts({ split_pattern = '=', justify_side = 'center' })\n\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.filter('n == 1') }]] })\n  validate_align_strings({ 'a=b=c', 'aaa=bbb=ccc' }, {}, { ' a =  b=c', 'aaa=bbb=ccc' })\n\n  -- `nil` allowed as input\n  eq(child.lua_get('MiniAlign.gen_step.filter()'), vim.NIL)\nend\n\nT['gen_step']['filter()']['validates input'] = function()\n  local pat = '%(mini%.align%) \"%(\" is not a valid filter expression'\n  expect.error(function() child.lua('MiniAlign.gen_step.filter(\"(\")') end, pat)\nend\n\nT['gen_step']['filter()']['handles special input'] = function()\n  -- `nil`\n  eq(child.lua_get('MiniAlign.gen_step.filter()'), vim.NIL)\n\n  -- `''` (treated as `true`, i.e. nothing is filtered out)\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.filter('') }]] })\n  set_config_opts({ split_pattern = '=' })\n  validate_align_strings({ 'a=b=c', 'aaa=bbb=ccc' }, {}, { 'a  =b  =c', 'aaa=bbb=ccc' })\nend\n\nT['gen_step']['filter()']['allows special variables'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local set = function(expr)\n    set_config_steps({ pre_justify = ([[{ MiniAlign.gen_step.filter(%s) }]]):format(vim.inspect(expr)) })\n  end\n\n  --stylua:ignore start\n  set('row == 2 or row == 3')\n  validate_align_strings({ 'a=b=c', 'aa=bb=cc', 'aaa=bbb=ccc' }, {}, { 'a=b=c', 'aa =bb =cc', 'aaa=bbb=ccc' })\n\n  set('row ~= ROW')\n  validate_align_strings({ 'a=b=c', 'aa=bb=cc', 'aaa=bbb=ccc' }, {}, { 'a =b =c', 'aa=bb=cc', 'aaa=bbb=ccc' })\n\n  set('col > 1')\n  validate_align_strings({ 'a=b=c', 'aa=bb=cc', 'aaa=bbb=ccc' }, {}, { 'a=  b  =c', 'aa= bb =cc', 'aaa=bbb=ccc' })\n\n  set('col >= COL - 1')\n  validate_align_strings({ 'a=b=c', 'aa=bb=cc', 'aaa=bbb=ccc' }, {}, { 'a=b=    c', 'aa=bb=  cc', 'aaa=bbb=ccc' })\n  --stylua:ignore end\nend\n\nT['gen_step']['filter()']['allows usage of global objects'] = function()\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.filter('row ~= first_row') }]] })\n  set_config_opts({ split_pattern = '=' })\n  child.lua('_G.first_row = 1')\n  validate_align_strings({ 'a=b=c', 'aa=bb=cc', 'aaa=bbb=ccc' }, {}, { 'a=b=c', 'aa =bb =cc', 'aaa=bbb=ccc' })\nend\n\nT['gen_step']['ignore_split()'] = new_set()\n\nT['gen_step']['ignore_split()']['works'] = function()\n  child.lua([[step = MiniAlign.gen_step.ignore_split()]])\n  validate_step('step', 'ignore')\n\n  -- With default arguments should ignore inside `\"` and comments\n  child.o.commentstring = '# %s'\n  set_config_steps({ pre_split = [[{ MiniAlign.gen_step.ignore_split() }]] })\n  validate_align_strings(\n    { '# aaaa=b', 'a\"=====\"=b', 'a=b' },\n    { split_pattern = '=' },\n    { '# aaaa=b', 'a\"=====\"=b', 'a       =b' }\n  )\nend\n\nT['gen_step']['ignore_split()']['validates input'] = function()\n  local pat = 'Argument `patterns`.*array of strings'\n  expect.error(function() child.lua('MiniAlign.gen_step.ignore_split(\"(\")') end, pat)\n  pat = 'Argument `exclude_comment`.*boolean'\n  expect.error(function() child.lua('MiniAlign.gen_step.ignore_split({}, 1)') end, pat)\nend\n\nT['gen_step']['ignore_split()']['respects `patterns` argument'] = function()\n  set_config_steps({ pre_split = [[{ MiniAlign.gen_step.ignore_split({ '*.-*' }) }]] })\n  validate_align_strings({ 'a\"=\"b', 'a*=*=b', 'a=b' }, { split_pattern = '=' }, { 'a\"  =\"b', 'a*=*=b', 'a   =b' })\n\n  -- Shouldn't add duplicates\n  child.lua([[test_step = MiniAlign.new_step(\n    'test',\n    function(strings, opts) _G.split_exclude_patterns = opts.split_exclude_patterns end\n  )]])\n  child.o.commentstring = '# %s'\n  set_config_steps({ pre_split = [[{ MiniAlign.gen_step.ignore_split({ '*.-*', '\".-\"' }), test_step }]] })\n  set_config_opts({ split_exclude_patterns = { '\".-\"' } })\n\n  child.lua([[MiniAlign.align_strings({'a'})]])\n  eq(child.lua_get('_G.split_exclude_patterns'), { '\".-\"', '*.-*', '# .*' })\nend\n\nT['gen_step']['ignore_split()']['respects `exclude_comment` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  child.o.commentstring = '# %s'\n\n  set_config_steps({ pre_split = [[{ MiniAlign.gen_step.ignore_split({}, true) }]] })\n  validate_align_strings({ '# aaa=b', 'a=b', 'aa=b' }, {}, { '# aaa=b', 'a =b', 'aa=b' })\n\n  set_config_steps({ pre_split = [[{ MiniAlign.gen_step.ignore_split({}, false) }]] })\n  validate_align_strings({ '# aaa=b', 'a=b', 'aa=b' }, {}, { '# aaa=b', 'a    =b', 'aa   =b' })\n\n  -- Should work with both `xxx%s` and `xxx%syyy` type of comments\n  child.o.commentstring = '/ %s /'\n  set_config_steps({ pre_split = [[{ MiniAlign.gen_step.ignore_split({}, true) }]] })\n  validate_align_strings(\n    { 'a/ = /=b/ = /=c', 'a=b=c', '/ == /' },\n    {},\n    { 'a/ = /=b/ = /=c', 'a     =b     =c', '/ == /' }\n  )\nend\n\nT['gen_step']['pair()'] = new_set()\n\nT['gen_step']['pair()']['works'] = function()\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.pair() }]] })\n  set_config_opts({ split_pattern = ',', justify_side = 'center' })\n\n  eq(child.lua_get('MiniAlign.config.steps.pre_justify[1].name'), 'pair')\n\n  validate_align_strings({ 'a,b,c', 'aaa,bbb,c' }, {}, { ' a,  b, c', 'aaa,bbb,c' })\nend\n\nT['gen_step']['pair()']['respects `direction` argument'] = function()\n  set_config_opts({ split_pattern = ',', justify_side = 'center' })\n\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.pair('left') }]] })\n  validate_align_strings({ 'a,b,c', 'aaa,bbb,c' }, {}, { ' a,  b, c', 'aaa,bbb,c' })\n\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.pair('right') }]] })\n  validate_align_strings({ 'a,b,c', 'aaa,bbb,c' }, {}, { ' a  ,b ,c', 'aaa,bbb,c' })\nend\n\nT['gen_step']['trim()'] = new_set()\n\nT['gen_step']['trim()']['works'] = function()\n  set_config_steps({ pre_justify = [[{ MiniAlign.gen_step.trim() }]] })\n  set_config_opts({ split_pattern = '=' })\n\n  eq(child.lua_get('MiniAlign.config.steps.pre_justify[1].name'), 'trim')\n\n  validate_align_strings({ ' a  = b  =  c = d', '  e = ' }, {}, { ' a =b=c=d', '  e=' })\nend\n\nT['gen_step']['trim()']['respects `direction` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local set = function(direction)\n    set_config_steps({ pre_justify = ([[{ MiniAlign.gen_step.trim(%s) }]]):format(vim.inspect(direction)) })\n  end\n\n  set('both')\n  validate_align_strings({ ' a =b = c=d' }, {}, { ' a=b=c=d' })\n\n  set('left')\n  validate_align_strings({ ' a =b = c=d' }, {}, { ' a =b =c=d' })\n\n  set('right')\n  validate_align_strings({ ' a =b = c=d' }, {}, { ' a=b= c=d' })\nend\n\nT['gen_step']['trim()']['respects `indent` argument'] = function()\n  set_config_opts({ split_pattern = '=' })\n  local set = function(indent)\n    set_config_steps({ pre_justify = ([[{ MiniAlign.gen_step.trim('both', %s) }]]):format(vim.inspect(indent)) })\n  end\n\n  set('keep')\n  validate_align_strings({ ' a ', '  b ' }, {}, { ' a', '  b' })\n\n  set('low')\n  validate_align_strings({ ' a ', '  b ' }, {}, { ' a', ' b' })\n\n  set('high')\n  validate_align_strings({ ' a ', '  b ' }, {}, { '  a', '  b' })\n\n  set('remove')\n  validate_align_strings({ ' a ', '  b ' }, {}, { 'a', 'b' })\nend\n\n-- Integration tests ==========================================================\nlocal validate_keys = function(input_lines, keys, output_lines)\n  set_lines(input_lines)\n  set_cursor(1, 0)\n  type_keys(keys)\n  eq(get_lines(), output_lines)\nend\n\nT['Align'] = new_set()\n\nT['Align']['works'] = function()\n  -- Use neutral split pattern to avoid testing builtin modifiers\n  validate_keys({ 'a_b', 'aaa_b' }, { 'Vj', 'ga', '_' }, { 'a  _b', 'aaa_b' })\n\n  -- Allows non-split related modifiers\n  validate_keys({ 'a_b', 'aaa_b' }, { 'V1j', 'ga', 'jc', '_' }, { ' a _b', 'aaa_b' })\nend\n\nT['Align']['works in Normal mode'] = function()\n  -- Should accept any textobject or motion\n  validate_keys({ 'a_b', 'aaa_b', '', 'aaaaa_b' }, { 'ga', 'Vip', '_' }, { 'a  _b', 'aaa_b', '', 'aaaaa_b' })\n  eq(get_cursor(), { 1, 0 })\n\n  validate_keys({ 'a_b', 'aaa_c' }, { 'ga', [[/_\\zsc<CR>]], '_' }, { 'a  _b', 'aaa_c' })\nend\n\nT['Align']['allows dot-repeat'] = function()\n  set_lines({ 'a_b', 'aaa_b', '', 'aaaaa_b', 'a_b' })\n  set_cursor(1, 0)\n  type_keys('ga', 'Vip', '_')\n  eq(get_lines(), { 'a  _b', 'aaa_b', '', 'aaaaa_b', 'a_b' })\n\n  set_cursor(4, 0)\n  type_keys('.')\n  eq(get_lines(), { 'a  _b', 'aaa_b', '', 'aaaaa_b', 'a    _b' })\nend\n\nT['Align']['works in Visual charwise mode'] = function()\n  -- Should use visual selection to extract strings and correctly place result\n  -- Should return to Normal mode after finish\n  validate_keys({ 'a_b', 'aaa_b' }, { 'v', '1j4l', 'ga', '_' }, { 'a  _b', 'aaa_b' })\n  eq(get_cursor(), { 2, 4 })\n  eq(get_mode(), 'n')\n\n  -- Respects offset of first line\n  set_lines({ 'xx_xxa_b', 'a_b' })\n  set_cursor(1, 5)\n  type_keys('vj', 'ga', '_')\n  eq(get_lines(), { 'xx_xxa_b', 'a     _b' })\n\n  -- Allows using non-split related modifiers\n  validate_keys({ 'a_b', 'aaa_b' }, { 'v', '1j4l', 'ga', 'jc', '_' }, { ' a _b', 'aaa_b' })\n\n  -- Should align for second `_` because it is not inside selection\n  validate_keys({ 'a_b_c', 'aaa_bbb_ccc' }, { 'v', '/bb_<CR>', 'ga', '_' }, { 'a  _b_c', 'aaa_bbb_ccc' })\n\n  -- Can use `$` without `end_col out of bounds`\n  validate_keys({ 'a_b', 'aaa_b' }, { 'v', '1j$', 'ga', '_' }, { 'a  _b', 'aaa_b' })\nend\n\nT['Align']['works in Visual linewise mode'] = function()\n  validate_keys({ 'a_b_c', 'aaa_bbb_ccc' }, { 'V', 'ip', 'ga', '_' }, { 'a  _b  _c', 'aaa_bbb_ccc' })\n  eq(get_mode(), 'n')\n\n  -- Allows using non-split related modifiers\n  validate_keys({ 'a_b', 'aaa_b' }, { 'V', '1j', 'ga', 'jc', '_' }, { ' a _b', 'aaa_b' })\nend\n\nT['Align']['works in Visual blockwise mode'] = function()\n  validate_keys({ 'a_b_c', 'aaa_bbb_c' }, { '<C-v>', '1j3l', 'ga', '_' }, { 'a  _b_c', 'aaa_bbb_c' })\n  eq(get_mode(), 'n')\n\n  child.o.virtualedit = 'block'\n\n  -- Selection goes over empty line (at start/middle/end of selection)\n  validate_keys({ '', 'a_b_c', 'aaa_bbb_c' }, { '<C-v>', '2j3l', 'ga', '_' }, { '', 'a  _b_c', 'aaa_bbb_c' })\n  validate_keys({ 'a_b_c', '', 'aaa_bbb_c' }, { '<C-v>', '2j3l', 'ga', '_' }, { 'a  _b_c', '', 'aaa_bbb_c' })\n  validate_keys({ 'a_b_c', 'aaa_bbb_c', '' }, { '<C-v>', '2j3l', 'ga', '_' }, { 'a  _b_c', 'aaa_bbb_c', '' })\n\n  -- Works when selection goes past the line (only right column, both columns)\n  validate_keys({ 'a_b', 'aa_b', 'aaa_b' }, { '1l', '<C-v>', '2j2l', 'ga', '_' }, { 'a  _b', 'aa _b', 'aaa_b' })\n  validate_keys({ 'a_b', 'aaa_b', 'aaaa_b' }, { '2j3l', '<C-v>', '2k2l', 'ga', '_' }, { 'a_b', 'aaa _b', 'aaaa_b' })\n\n  -- Correctly works in presence of multibyte characters\n  validate_keys({ 'ыы_ф', 'ыыы_ф' }, { '1l', '<C-v>', '1j3l', 'ga', '_' }, { 'ыы _ф', 'ыыы_ф' })\n\n  -- Correctly selects in presence of wide characters\n  validate_keys({ 'の', '_', 'a_' }, { '<C-v>2j', 'ga', '_' }, { 'の', ' _', 'a_' })\nend\n\nT['Align']['works independently with :normal command'] = function()\n  -- Works for each line individually when running under :normal command\n  validate_keys({ 'a   _b', 'aa  _b', 'aaa _b' }, { ':%normal ga_t_<CR>' }, { 'a_b', 'aa_b', 'aaa_b' })\n  validate_keys({ 'a   _  b', 'aa  _  b', 'aaa _  b' }, { ':%normal ga_ A;<CR>' }, { 'a _ b;', 'aa _ b;', 'aaa _ b;' })\nend\n\nT['Align']['registers visual selection'] = function()\n  set_lines({ 'a_b', 'aa_b', 'vvv', 'vvv' })\n\n  -- Make preceding visual selection\n  set_cursor(3, 0)\n  type_keys('V', 'j', 'u')\n\n  -- Align in Visual mode\n  set_cursor(1, 0)\n  type_keys('V', 'j', 'ga', '_')\n  eq(get_lines(), { 'a _b', 'aa_b', 'vvv', 'vvv' })\n\n  -- Verify that Visual selection got updated\n  type_keys('gv')\n  eq(get_mode(), 'V')\n  eq(child.fn.getpos('v'), { 0, 1, 1, 0 })\nend\n\nT['Align']['works with different mapping'] = function()\n  unload_module()\n  child.api.nvim_del_keymap('n', 'ga')\n  child.api.nvim_del_keymap('x', 'ga')\n  load_module({ mappings = { start = 'gl' } })\n\n  validate_keys({ 'a_b', 'aaa_b' }, { 'gl', 'Vj', '_' }, { 'a  _b', 'aaa_b' })\n  validate_keys({ 'a_b', 'aaa_b' }, { 'Vj', 'gl', '_' }, { 'a  _b', 'aaa_b' })\nend\n\nT['Align']['works with multibyte characters'] = function()\n  local before, after = { 'ыффцццф', 'ыыыффцф' }, { 'ы  ффцццф', 'ыыыффц  ф' }\n  validate_keys(before, { 'Vj', 'ga', 'ф' }, after)\n  validate_keys(before, { '<C-v>$j', 'ga', 'ф' }, after)\nend\n\nT['Align']['works with wide characters'] = function()\n  -- Wide characters may or may not be designed to occupy more than a one cell\n  -- NOTE: deliberately do not account for 'ambiwidth=double' option as it does\n  -- not look reasonable (two cells for Cyrillic) and adds extra complexity\n  local before, after = { 'ыыффццф', 'ыфのфцф' }, { 'ыыф  фццф', 'ы фのфц ф' }\n  validate_keys(before, { 'Vj', 'ga', 'ф' }, after)\n  validate_keys(before, { '<C-v>$j', 'ga', 'ф' }, after)\nend\n\nT['Align']['works with combining characters'] = function(mode)\n  -- 0xCC 0x81 is the UTF-8 representation of U+0301 COMBINING ACUTE ACCENT. It\n  -- is zero-width when combined with the preceding character.\n  local before, after = { 'aá_e\\xcc\\x81e_', 'aa_e_' }, { 'aá_e\\xcc\\x81e_', 'aa_e _' }\n  validate_keys(before, { 'Vj', 'ga', '_' }, after)\n  validate_keys(before, { '<C-v>$j', 'ga', '_' }, after)\nend\n\nT['Align']['does not ask for modifier if `split_pattern` is not default'] = function()\n  set_config_opts({ split_pattern = '_' })\n  set_lines({ 'a_b', 'aa_b' })\n  set_cursor(1, 0)\n  type_keys('Vj', 'ga')\n  eq(get_lines(), { 'a _b', 'aa_b' })\nend\n\nT['Align']['treats non-config modifier as explicit split pattern'] = function()\n  validate_keys({ 'a.b', 'aaa.b' }, { 'ga', 'Vj', '.' }, { 'a  .b', 'aaa.b' })\n  validate_keys({ 'a(b', 'aaa(b' }, { 'ga', 'Vj', '(' }, { 'a  (b', 'aaa(b' })\nend\n\nT['Align']['stops on `<Esc>` and `<C-c>`'] = function()\n  for _, stop_key in ipairs({ '<Esc>', '<C-c>' }) do\n    validate_keys({ 'a_b', 'aa_b' }, { 'Vj', 'ga', stop_key }, { 'a_b', 'aa_b' })\n    eq(get_mode(), 'n')\n  end\nend\n\nT['Align']['has guard against infinite loop'] = function()\n  set_lines({ 'a_b', 'aa_b' })\n  set_cursor(1, 0)\n  type_keys('Vj', 'ga')\n  eq(get_mode(), 'V')\n\n  for _ = 1, 1001 do\n    type_keys('m', ' ', '<CR>')\n  end\n  eq(get_mode(), 'n')\n  eq(get_latest_message(), '(mini.align) Too many modifiers typed.')\nend\n\nT['Align']['does not stop on error during modifier execution'] = function()\n  child.lua([[MiniAlign.config.modifiers.e = function() error('Bad modifier') end]])\n\n  set_lines({ 'a_b', 'aa_b' })\n  set_cursor(1, 0)\n\n  -- Error in modifier execution should lead to a pause to make message visible\n  local before_time = vim.loop.hrtime()\n  type_keys('Vj', 'ga', 'e')\n  local duration = 0.000001 * (vim.loop.hrtime() - before_time)\n  eq(error_message_force_delay <= duration and duration <= error_message_force_delay + 2 * small_time, true)\n  expect.match(get_latest_message(), '^%(mini.align%) Modifier \"e\" should be properly callable%. Reason:')\nend\n\nT['Align']['validates steps after each modifier'] = function()\n  child.lua([[MiniAlign.config.modifiers.e = function(steps) steps.pre_split = 1 end]])\n  set_lines({ 'a_b', 'aa_b' })\n  set_cursor(1, 0)\n  type_keys('Vj', 'ga')\n  expect.error(function() type_keys('e', '_') end, 'pre_split.*array of steps')\nend\n\nT['Align']['shows state after one idle second'] = new_set({\n  parametrize = { { 'Normal' }, { 'Visual' } },\n}, {\n  test = function(test_mode)\n    -- Check this only on Neovim>=0.11, as there is a slight change in\n    -- highlighting command line area\n    if child.fn.has('nvim-0.11') == 0 then return end\n    helpers.skip_if_slow()\n\n    local expect_screenshot = function() child.expect_screenshot({ redraw = false }) end\n    child.set_size(12, 20)\n    child.o.cmdheight = 5\n\n    -- Prompts message in debounce-style fashion\n    set_lines({ 'a_b', 'aa_b' })\n    set_cursor(1, 0)\n    local keys = test_mode == 'Normal' and { 'ga', 'Vip' } or { 'Vip', 'ga' }\n    type_keys(unpack(keys))\n\n    sleep(show_state_delay - small_time)\n    -- Should show no state\n    expect_screenshot()\n    type_keys('j')\n    -- Should show state of modifier 'j'\n    expect_screenshot()\n    type_keys('r')\n    -- Should show effect of hitting `r` and redraw if `showmode` is set (which\n    -- it is by default)\n    sleep(show_state_delay - small_time)\n    -- Should still not show state\n    expect_screenshot()\n    sleep(small_time + small_time)\n    -- Should now show state\n    expect_screenshot()\n\n    -- Should show state immediately if it was already shown\n    type_keys('j', 'c')\n    expect_screenshot()\n\n    -- Ending alignment should remove shown state\n    type_keys('_')\n    expect_screenshot()\n  end,\n})\n\nT['Align']['showing state does not cause hit-enter-prompt'] = function()\n  child.set_size(6, 20)\n  child.o.cmdheight = 2\n  set_lines({ 'a_b', 'aa_b' })\n  set_cursor(1, 0)\n\n  type_keys('ga', 'Vj')\n  sleep(show_state_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Align']['cleans command line only if state was shown'] = function()\n  child.set_size(12, 20)\n  child.cmd([[echo 'My echo']])\n  validate_keys({ 'a_b', 'aa_b' }, { 'ga', 'ip', '_' }, { 'a _b', 'aa_b' })\n  child.expect_screenshot()\nend\n\n--stylua: ignore\nT['Align'][\"respects 'selection=exclusive'\"] = function()\n  child.o.selection = 'exclusive'\n\n  -- Normal mode charwise\n  validate_keys({ 'a_b_c', 'aa_bb_cc' }, { 'ga', 'v', [[/bb\\zs_<CR>]], '_' }, { 'a _b_c', 'aa_bb_cc' })\n  validate_keys({ 'ы_ю_я', 'ыы_юю_яя' }, { 'ga', 'v', [[/юю\\zs_<CR>]], '_' }, { 'ы _ю_я', 'ыы_юю_яя' })\n\n  -- Normal mode blockwise\n  validate_keys({ 'a_b_c', 'aa_bb_cc' }, { 'ga', '<C-v>', [[/bb\\zs_<CR>]], '_' }, { 'a _b_c', 'aa_bb_cc' })\n  validate_keys({ 'ы_ю_я', 'ыы_юю_яя' }, { 'ga', '<C-v>', [[/юю\\zs_<CR>]], '_' }, { 'ы _ю_я', 'ыы_юю_яя' })\n\n  -- Visual mode\n  validate_keys({ 'a_b_c', 'aa_bb_cc' }, { 'v1j5l', 'ga', '_' }, { 'a _b_c', 'aa_bb_cc' })\n  validate_keys({ 'ы_ю_я', 'ыы_юю_яя' }, { 'v1j5l', 'ga', '_' }, { 'ы _ю_я', 'ыы_юю_яя' })\n\n  -- Visual mode blockwise\n  validate_keys({ 'a_b_c', 'aa_bb_cc' }, { '<C-v>', '1j5l', 'ga', '_' }, { 'a _b_c', 'aa_bb_cc' })\n  validate_keys({ 'ы_ю_я', 'ыы_юю_яя' }, { '<C-v>', '1j5l', 'ga', '_' }, { 'ы _ю_я', 'ыы_юю_яя' })\nend\n\nT['Align']['does not affect marks'] = function()\n  local validate = function(start_keys)\n    set_lines({ 'a_b', 'aa_b', 'aaa_b' })\n    child.fn.setpos(\"'a\", { 0, 1, 1, 0 })\n    child.fn.setpos(\"'b\", { 0, 3, 1, 0 })\n    set_cursor(1, 0)\n\n    type_keys(start_keys, '_')\n    eq(get_lines(), { 'a _b', 'aa_b', 'aaa_b' })\n    eq(child.api.nvim_buf_get_mark(0, 'a'), { 1, 0 })\n    eq(child.api.nvim_buf_get_mark(0, 'b'), { 3, 0 })\n  end\n\n  -- Normal mode\n  validate({ 'ga', 'v', [[2/_\\zsb]], '<CR>' })\n  validate({ 'ga', 'V', 'j' })\n  validate({ 'ga', '<C-v>', [[2/_\\zsb]], '<CR>' })\n\n  -- Visual mode\n  validate({ 'v', [[2/_\\zsb]], '<CR>', 'ga' })\n  validate({ 'V', 'j', 'ga' })\n  validate({ '<C-v>', [[2/_\\zsb]], '<CR>', 'ga' })\nend\n\nT['Align']['respects `vim.{g,b}.minialign_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minialign_disable = true\n\n    validate_keys({ 'a_b', 'aa_b' }, { 'Vj', 'ga', '_' }, { 'a_b', 'aa_b' })\n  end,\n})\n\nT['Align']['respects `config.silent`'] = function()\n  child.set_size(12, 20)\n  child.lua('MiniAlign.config.silent = true')\n\n  -- Should not prompt message after idle second\n  set_lines({ 'a_b', 'aa_b' })\n  set_cursor(1, 0)\n  type_keys('Vip', 'ga')\n\n  sleep(show_state_delay + small_time)\n  child.expect_screenshot()\nend\n\n-- Test mostly \"preview\" part. Hope that other is covered in 'Align' tests.\nT['Align with preview'] =\n  new_set({ hooks = {\n    pre_case = function()\n      child.set_size(12, 30)\n      child.o.cmdheight = 5\n    end,\n  } })\n\nT['Align with preview']['works'] = new_set({\n  parametrize = {\n    { 'Normal-char' },\n    { 'Normal-line' },\n    { 'Normal-block' },\n    { 'Visual-char' },\n    { 'Visual-line' },\n    { 'Visual-block' },\n  },\n}, {\n  test = function(test_mode)\n    set_lines({ 'a_b_c', 'aaa_bbb_ccc' })\n    set_cursor(1, 0)\n    child.fn.setpos(\"'a\", { 0, 2, 5, 0 })\n\n    local init_keys = ({\n      ['Normal-char'] = { 'gA', 'v', '`a' },\n      ['Normal-line'] = { 'gA', 'V', 'j' },\n      ['Normal-block'] = { 'gA', '<C-v>', '`a' },\n      ['Visual-char'] = { 'v', '`a', 'gA' },\n      ['Visual-line'] = { 'V', 'j', 'gA' },\n      ['Visual-block'] = { '<C-v>', '`a', 'gA' },\n    })[test_mode]\n    type_keys(init_keys)\n\n    -- Should show state immediately\n    child.expect_screenshot()\n\n    -- Should show result and not stop preview\n    type_keys('_')\n    child.expect_screenshot()\n\n    type_keys('j', 'r')\n    child.expect_screenshot()\n\n    type_keys('m', '-', '<CR>')\n    child.expect_screenshot()\n\n    -- Hitting `<CR>` accepts current result and echoes status\n    type_keys('<CR>')\n    -- This should start Insert mode and not right justify by 'a'\n    type_keys('a')\n    child.expect_screenshot()\n  end,\n})\n\nT['Align with preview']['correctly shows all steps in status'] = function()\n  child.set_size(12, 30)\n  child.o.cmdheight = 5\n\n  child.lua('_G.dummy_step = function(name) return MiniAlign.new_step(name, function() end) end')\n  set_config_steps({ pre_split = [[{ _G.dummy_step('sss1'), _G.dummy_step('sss2') }]] })\n  set_config_steps({ pre_justify = [[{ _G.dummy_step('jjj1'), _G.dummy_step('jjj2') }]] })\n  set_config_steps({ pre_merge = [[{ _G.dummy_step('mmm1'), _G.dummy_step('mmm2') }]] })\n\n  set_lines({ 'a_b', 'aa_b' })\n  type_keys('gA', 'ip', '_')\n  child.expect_screenshot()\nend\n\nT['Align with preview']['uses option names for main steps'] = function()\n  child.set_size(12, 30)\n  child.o.cmdheight = 5\n  set_config_steps({ split = [[MiniAlign.gen_step.default_split('aaa')]] })\n  set_config_steps({ justify = [[MiniAlign.gen_step.default_justify('bbb')]] })\n  set_config_steps({ merge = [[MiniAlign.gen_step.default_merge('ccc')]] })\n\n  -- Should show option names instead of step names\n  set_lines({ 'a_b', 'aa_b' })\n  type_keys('gA', 'ip')\n  child.expect_screenshot()\nend\n\nT['Align with preview']['stops preview after `<Esc>` and `<C-c>`'] = function()\n  -- Don't show mode because it causes hit-enter-prompt with Visual selection\n  child.o.showmode = false\n  local validate = function(init_keys, stop_key)\n    child.ensure_normal_mode()\n\n    local lines = { 'a_b', 'aa_b' }\n    set_lines(lines)\n    set_cursor(1, 0)\n    type_keys(init_keys, '_')\n    -- Justify to right side\n    type_keys('jr')\n    eq(get_lines(), { ' a_b', 'aa_b' })\n\n    -- Should reset text to its initial form\n    type_keys(stop_key)\n    eq(get_mode(), 'n')\n    eq(get_lines(), lines)\n    -- This should start Insert mode and not right justify by 'a'\n    type_keys('a')\n    eq(get_mode(), 'i')\n  end\n\n  -- Normal mode\n  validate({ 'gA', 'Vj' }, '<Esc>')\n  validate({ 'gA', 'Vj' }, '<C-c>')\n\n  -- Visual mode\n  validate({ 'Vj', 'gA' }, '<Esc>')\n  validate({ 'Vj', 'gA' }, '<C-c>')\nend\n\nT['Align with preview']['correctly restores visual selection'] = new_set(\n  { parametrize = { { 'Visual-char' }, { 'Visual-line' }, { 'Visual-block' } } },\n  {\n    test = function(test_mode)\n      set_lines({ 'a_b_c', 'aaa_bbb_ccc', '', 'previous selection' })\n      child.fn.setpos(\"'a\", { 0, 2, 5, 0 })\n\n      -- Make \"previous selection\" to complicate setup\n      set_cursor(4, 9)\n      type_keys('v', '8l', '<Esc>')\n\n      set_cursor(1, 0)\n      local init_keys = ({\n        ['Visual-char'] = { 'v', '`a', 'gA' },\n        ['Visual-line'] = { 'V', 'j', 'gA' },\n        ['Visual-block'] = { '<C-v>', '`a', 'gA' },\n      })[test_mode]\n      type_keys(init_keys, '_')\n      child.expect_screenshot()\n\n      -- Make undo of current result and redo alignment\n      type_keys('jr')\n      child.expect_screenshot()\n    end,\n  }\n)\n\nT['Align with preview']['processes region before first modifier'] = function()\n  set_config_opts({ split_pattern = '_', merge_delimiter = '--' })\n  set_lines({ 'a_b', 'aaa_b' })\n  set_cursor(1, 0)\n  type_keys('Vj', 'gA')\n  eq(get_lines(), { 'a  --_--b', 'aaa--_--b' })\nend\n\nT['Align with preview']['respects `vim.{g,b}.minialign_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minialign_disable = true\n\n    local lines = { 'a_b', 'aa_b' }\n    set_lines(lines)\n    set_cursor(1, 0)\n    type_keys('Vj', 'gA', '_', '<CR>')\n    eq(get_lines(), lines)\n  end,\n})\n\nT['Align with preview']['respects `config.silent`'] = function()\n  child.set_size(12, 20)\n  child.lua('MiniAlign.config.silent = true')\n\n  set_lines({ 'a_b_c', 'aaa_bbb_ccc' })\n  set_cursor(1, 0)\n  type_keys('V', 'j', 'gA')\n\n  -- Should not show helper message\n  child.expect_screenshot()\nend\n\nlocal init_preview_align = function(lines, keys)\n  child.ensure_normal_mode()\n  set_lines(lines or { 'a_b', 'aaa_b' })\n  set_cursor(1, 0)\n  type_keys(keys or { 'Vj', 'gA' })\nend\n\nlocal validate_modifier_stops = function(modifier_key, stop_key)\n  local lines = { 'a_b', 'aaa_b' }\n  init_preview_align(lines)\n\n  type_keys(modifier_key, stop_key)\n  eq(get_mode(), 'V')\n  eq(get_lines(), lines)\n\n  -- Aligning should still be active\n  type_keys('_')\n  eq(get_lines(), { 'a  _b', 'aaa_b' })\nend\n\nT['Modifiers'] =\n  new_set({ hooks = {\n    pre_case = function()\n      child.set_size(12, 30)\n      child.o.cmdheight = 5\n    end,\n  } })\n\nT['Modifiers']['s'] = new_set()\n\nT['Modifiers']['s']['works'] = function()\n  set_lines({ 'a_b', 'aaa_b' })\n  set_cursor(1, 0)\n  type_keys('ga', 'ip')\n\n  type_keys('s')\n  child.expect_screenshot()\n  type_keys('_', '<CR>')\n  child.expect_screenshot()\nend\n\nT['Modifiers']['s']['stops on `<Esc>` and `<C-c>`'] = function()\n  validate_modifier_stops('s', '<Esc>')\n  validate_modifier_stops('s', '<C-c>')\nend\n\nT['Modifiers']['s']['allows empty input'] = function()\n  set_config_opts({ justify_side = 'right' })\n  local lines = { 'a_b', 'aaa_b' }\n  init_preview_align(lines)\n  type_keys('s', '<CR>')\n\n  -- Using `''` as split means that strings act as single-cell rows\n  eq(get_lines(), { '  a_b', 'aaa_b' })\nend\n\nT['Modifiers']['j'] = new_set()\n\nT['Modifiers']['j']['works'] = new_set({\n  -- Test for all actionable values and one not actionable (should do nothing)\n  parametrize = { { 'l' }, { 'c' }, { 'r' }, { 'n' }, { 'u' } },\n}, {\n  test = function(user_key)\n    set_config_opts({ split_pattern = '_' })\n    if user_key == 'l' then set_config_opts({ justify_side = 'right' }) end\n\n    init_preview_align()\n\n    type_keys('j')\n    child.expect_screenshot()\n\n    type_keys(user_key)\n    child.expect_screenshot()\n  end,\n})\n\nT['Modifiers']['j']['stops on `<Esc>` and `<C-c>`'] = function()\n  local validate = function(stop_key)\n    local lines = { 'a_b', 'aaa_b' }\n    init_preview_align(lines)\n\n    type_keys('j', stop_key)\n\n    -- Aligning should still be active\n    eq(get_mode(), 'V')\n    type_keys('_')\n    eq(get_lines(), { 'a  _b', 'aaa_b' })\n  end\n\n  validate('<Esc>')\n  validate('<C-c>')\nend\n\nT['Modifiers']['m'] = new_set()\n\nT['Modifiers']['m']['works'] = function()\n  set_lines({ 'a_b', 'aaa_b' })\n  set_cursor(1, 0)\n  type_keys('ga', 'ip')\n\n  type_keys('m')\n  child.expect_screenshot()\n  type_keys('--', '<CR>')\n  type_keys('_')\n  child.expect_screenshot()\nend\n\nT['Modifiers']['m']['stops on `<Esc>` and `<C-c>`'] = function()\n  validate_modifier_stops('m', '<Esc>')\n  validate_modifier_stops('m', '<C-c>')\nend\n\nT['Modifiers']['m']['allows empty input'] = function()\n  set_config_opts({ split_pattern = '_', merge_delimiter = '--' })\n  local lines = { 'a_b', 'aaa_b' }\n  init_preview_align(lines)\n  eq(get_lines(), { 'a  --_--b', 'aaa--_--b' })\n\n  -- Should result into `merge = ''`\n  type_keys('m', '<CR>')\n  eq(get_lines(), { 'a  _b', 'aaa_b' })\nend\n\nT['Modifiers']['f'] = new_set()\n\nT['Modifiers']['f']['works'] = function()\n  set_lines({ 'a_b', 'aa_b', 'aaa_b' })\n  set_cursor(1, 0)\n  type_keys('ga', 'ip')\n\n  type_keys('f')\n  child.expect_screenshot()\n\n  type_keys('row ~= 1', '<CR>')\n  type_keys('_')\n  eq(get_lines(), { 'a_b', 'aa _b', 'aaa_b' })\nend\n\nT['Modifiers']['f']['stops on `<Esc>` and `<C-c>`'] = function()\n  validate_modifier_stops('f', '<Esc>')\n  validate_modifier_stops('f', '<C-c>')\nend\n\nT['Modifiers']['f']['allows empty input'] = function()\n  set_config_opts({ split_pattern = '_' })\n  init_preview_align()\n\n  -- Should result into having `''` as special input (filter step without actual filtering)\n  type_keys('f', '<CR>')\n  child.expect_screenshot()\nend\n\nT['Modifiers']['i'] = new_set()\n\nT['Modifiers']['i']['works'] = function()\n  child.o.commentstring = '# %s'\n  init_preview_align({ '# aaaaa=b', '\"aaaaa=b\"', 'a=b', 'aa=b' }, { 'V3j', 'gA' })\n\n  type_keys('s', '=', '<CR>')\n  child.expect_screenshot()\n\n  type_keys('i')\n  child.expect_screenshot()\nend\n\nT['Modifiers']['p'] = new_set()\n\nT['Modifiers']['p']['works'] = function()\n  set_config_opts({ split_pattern = '_' })\n  init_preview_align({ 'a_b_c', 'aaa_bbb_ccc' })\n\n  eq(get_lines(), { 'a  _b  _c', 'aaa_bbb_ccc' })\n  type_keys('p')\n  child.expect_screenshot()\n  eq(get_lines(), { 'a_  b_  c', 'aaa_bbb_ccc' })\nend\n\nT['Modifiers']['t'] = new_set()\n\nT['Modifiers']['t']['works'] = function()\n  set_config_opts({ split_pattern = '_' })\n  init_preview_align({ ' a _ b _ c', '  aaa _ bbb _  ccc' })\n\n  eq(get_lines(), { ' a    _ b   _ c', '  aaa _ bbb _  ccc' })\n  type_keys('t')\n  child.expect_screenshot()\n  eq(get_lines(), { ' a   _b  _c', '  aaa_bbb_ccc' })\nend\n\nT['Modifiers']['<BS>'] = new_set()\n\nT['Modifiers']['<BS>']['works'] = new_set({ parametrize = { { 'pre_split' }, { 'pre_justify' }, { 'pre_merge' } } }, {\n  test = function(pre_step_name)\n    set_config_steps({ [pre_step_name] = [[{ MiniAlign.new_step('aaa', function() end) }]] })\n    init_preview_align()\n    child.expect_screenshot()\n    type_keys('<BS>')\n    child.expect_screenshot()\n  end,\n})\n\nT['Modifiers']['<BS>']['does nothing if no pre-steps'] = function()\n  local lines = { 'a_b', 'aaa_b' }\n  init_preview_align(lines)\n  child.expect_screenshot()\n  type_keys('<BS>')\n  child.expect_screenshot()\n\n  -- Aligning should still be active\n  type_keys('_')\n  eq(get_lines(), { 'a  _b', 'aaa_b' })\nend\n\nT['Modifiers']['<BS>']['prompts to choose if ambiguous'] = function()\n  child.lua('_G.dummy_step = function(name) return MiniAlign.new_step(name, function() end) end')\n  set_config_steps({ pre_split = [[{ _G.dummy_step('sss') }]] })\n  set_config_steps({ pre_justify = [[{ _G.dummy_step('jjj') }]] })\n  set_config_steps({ pre_merge = [[{ _G.dummy_step('mmm') }]] })\n\n  set_lines({ 'a_b', 'aa_b' })\n  type_keys('gA', 'ip', '_')\n  child.expect_screenshot()\n\n  type_keys('<BS>')\n  child.expect_screenshot()\n  type_keys('s')\n  child.expect_screenshot()\n\n  type_keys('<BS>')\n  child.expect_screenshot()\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nlocal validate_common_split = function(init_lines, modifier_key)\n  set_lines(init_lines)\n  set_cursor(1, 0)\n  type_keys('VG', 'gA')\n\n  child.expect_screenshot()\n  type_keys(modifier_key)\n  child.expect_screenshot()\nend\n\nT['Modifiers']['<equal sign>'] = function() validate_common_split({ 'a=b', 'aaa=bbb' }, '=') end\n\nT['Modifiers']['<comma>'] = function() validate_common_split({ 'a,b', 'aaa,bbb' }, ',') end\n\nT['Modifiers']['<bar>'] = function() validate_common_split({ '|a|b|', '|aaa|bbb|' }, '|') end\n\nT['Modifiers']['<space bar>'] = function() validate_common_split({ '  a  b', '    aaa    bbb', 'a b' }, ' ') end\n\nT['Documented examples'] = new_set()\n\nT['Documented examples']['trim with highest indentation'] = function()\n  local lines = { ' a _ b', '   aaa _ bbb' }\n  local keys = { 'Vj', 'ga', 't', '_' }\n\n  validate_keys(lines, keys, { ' a    _b', '   aaa_bbb' })\n\n  unload_module()\n  child.lua([[require('mini.align').setup({\n    modifiers = {\n      t = function(steps, _) table.insert(steps.pre_justify, MiniAlign.gen_step.trim('both', 'high')) end\n    },\n  })]])\n\n  validate_keys(lines, keys, { '   a  _b', '   aaa_bbb' })\nend\n\nT['Documented examples']['use \"j\" to cycle through justify values'] = function()\n  unload_module()\n  child.lua([[require('mini.align').setup({\n    modifiers = {\n      j = function(_, opts)\n        local next_option = ({\n          left = 'center', center = 'right', right = 'none', none = 'left'\n        })[opts.justify_side]\n        opts.justify_side = next_option or 'left'\n      end\n    },\n  })]])\n\n  set_lines({ 'a_b', 'aaa_b' })\n  set_cursor(1, 0)\n  type_keys('Vip', 'gA', '_')\n  eq(get_lines(), { 'a  _b', 'aaa_b' })\n\n  type_keys('j')\n  eq(get_lines(), { ' a _b', 'aaa_b' })\n\n  type_keys('j')\n  eq(get_lines(), { '  a_b', 'aaa_b' })\n\n  type_keys('j')\n  eq(get_lines(), { 'a_b', 'aaa_b' })\n\n  type_keys('j')\n  eq(get_lines(), { 'a  _b', 'aaa_b' })\nend\n\nT['Documented examples']['align by default only by first pair of columns'] = function()\n  local lines = { 'a_b_c', 'aa_bb_cc' }\n  local keys = { 'Vip', 'ga', '_' }\n\n  validate_keys(lines, keys, { 'a _b _c', 'aa_bb_cc' })\n\n  unload_module()\n  child.lua([[\n  local align = require('mini.align')\n  align.setup({\n    steps = {\n      pre_justify = { align.gen_step.filter('n == 1') }\n    },\n  })]])\n\n  validate_keys(lines, keys, { 'a _b_c', 'aa_bb_cc' })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_animate.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('animate', config) end\nlocal unload_module = function() child.mini_unload('animate') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\n--stylua: ignore end\n\nlocal get_virt_cursor = function()\n  local pos = child.fn.getcurpos()\n  return { pos[2], pos[3] + pos[4] - 1 }\nend\n\nlocal validate_topline = function(x) eq(child.fn.line('w0'), x) end\n\nlocal validate_floats = function(configs)\n  for win_id, ref_config in pairs(configs) do\n    -- Value `false` is used to test absence of floating window\n    if ref_config == false then\n      eq(child.api.nvim_win_is_valid(win_id), false)\n      return\n    end\n\n    local config = child.api.nvim_win_get_config(win_id)\n    for key, val in pairs(ref_config) do\n      if key ~= 'winblend' then\n        eq({ win_id = win_id, key = key, value = val }, { win_id = win_id, key = key, value = config[key] })\n      end\n    end\n\n    if ref_config.winblend ~= nil then eq(child.api.nvim_win_get_option(win_id, 'winblend'), ref_config.winblend) end\n  end\nend\n\nlocal list_wins = function()\n  local res = child.api.nvim_list_wins()\n  table.sort(res)\n  return res\nend\n\nlocal create_openclose_test_winconfig = function()\n  child.lua([[_G.openclose_test_winconfig = function(win_id)\n    local pos = vim.fn.win_screenpos(win_id)\n    local width, height = vim.api.nvim_win_get_width(win_id), vim.api.nvim_win_get_height(win_id)\n    local res = {}\n    -- Full coverage\n    res[1] = {\n      relative  = 'editor',\n      anchor    = 'NW',\n      row       = pos[1] - 1,\n      col       = pos[2] - 1,\n      width     = width,\n      height    = height,\n      focusable = false,\n      zindex    = 1,\n      style     = 'minimal',\n    }\n    -- Quarter coverage\n    res[2] = {\n      relative  = 'editor',\n      anchor    = 'NW',\n      row       = pos[1] - 1,\n      col       = pos[2] - 1,\n      width     = math.ceil(0.5 * width),\n      height    = math.ceil(0.5 * height),\n      focusable = false,\n      zindex    = 1,\n      style     = 'minimal',\n    }\n    return res\n  end]])\nend\n\n-- Data =======================================================================\n--stylua: ignore\nlocal example_scroll_lines = {\n  'aaaa', 'bbbb', 'cccc', 'dddd', 'eeee',\n  'ffff', 'gggg', 'hhhh', 'iiii', 'jjjj',\n  'kkkk', 'llll', 'mmmm', 'nnnn', 'oooo',\n}\n\n--stylua: ignore\nlocal example_scroll_lines_2 = {\n  'AAAA', 'BBBB', 'CCCC', 'DDDD', 'EEEE',\n  'FFFF', 'GGGG', 'HHHH', 'IIII', 'JJJJ',\n  'KKKK', 'LLLL', 'MMMM', 'NNNN', 'OOOO',\n}\n\n-- Time constants\nlocal default_total_time = 250\nlocal step_time = helpers.get_time_const(40)\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n\n      child.lua('_G.step_time, _G.small_time = ' .. step_time .. ', ' .. small_time)\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniAnimate)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniAnimate'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniAnimateCursor'), 'gui=reverse,nocombine')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniAnimate.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniAnimate.config.' .. field), value) end\n  local expect_config_function = function(field)\n    eq(child.lua_get('type(MiniAnimate.config.' .. field .. ')'), 'function')\n  end\n\n  expect_config('cursor.enable', true)\n  expect_config_function('cursor.timing')\n  expect_config_function('cursor.path')\n\n  expect_config('scroll.enable', true)\n  expect_config_function('scroll.timing')\n  expect_config_function('scroll.subscroll')\n\n  expect_config('resize.enable', true)\n  expect_config_function('resize.timing')\n  expect_config_function('resize.subresize')\n\n  expect_config('open.enable', true)\n  expect_config_function('open.timing')\n  expect_config_function('open.winconfig')\n  expect_config_function('open.winblend')\n\n  expect_config('close.enable', true)\n  expect_config_function('close.timing')\n  expect_config_function('close.winconfig')\n  expect_config_function('close.winblend')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ cursor = { enable = false } })\n  eq(child.lua_get('MiniAnimate.config.cursor.enable'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n\n  expect_config_error({ cursor = 'a' }, 'cursor', 'table')\n  expect_config_error({ cursor = { enable = 'a' } }, 'cursor.enable', 'boolean')\n  expect_config_error({ cursor = { timing = 'a' } }, 'cursor.timing', 'callable')\n  expect_config_error({ cursor = { path = 'a' } }, 'cursor.path', 'callable')\n\n  expect_config_error({ scroll = 'a' }, 'scroll', 'table')\n  expect_config_error({ scroll = { enable = 'a' } }, 'scroll.enable', 'boolean')\n  expect_config_error({ scroll = { timing = 'a' } }, 'scroll.timing', 'callable')\n  expect_config_error({ scroll = { subscroll = 'a' } }, 'scroll.subscroll', 'callable')\n\n  expect_config_error({ resize = 'a' }, 'resize', 'table')\n  expect_config_error({ resize = { enable = 'a' } }, 'resize.enable', 'boolean')\n  expect_config_error({ resize = { timing = 'a' } }, 'resize.timing', 'callable')\n  expect_config_error({ resize = { subresize = 'a' } }, 'resize.subresize', 'callable')\n\n  expect_config_error({ open = 'a' }, 'open', 'table')\n  expect_config_error({ open = { enable = 'a' } }, 'open.enable', 'boolean')\n  expect_config_error({ open = { timing = 'a' } }, 'open.timing', 'callable')\n  expect_config_error({ open = { winconfig = 'a' } }, 'open.winconfig', 'callable')\n  expect_config_error({ open = { winblend = 'a' } }, 'open.winblend', 'callable')\n\n  expect_config_error({ close = 'a' }, 'close', 'table')\n  expect_config_error({ close = { enable = 'a' } }, 'close.enable', 'boolean')\n  expect_config_error({ close = { timing = 'a' } }, 'close.timing', 'callable')\n  expect_config_error({ close = { winconfig = 'a' } }, 'close.winconfig', 'callable')\n  expect_config_error({ close = { winblend = 'a' } }, 'close.winblend', 'callable')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniAnimateCursor'), 'gui=reverse,nocombine')\nend\n\nT['is_active()'] = new_set()\n\nlocal is_active = function(action_type) return child.lua_get('MiniAnimate.is_active(...)', { action_type }) end\n\nT['is_active()']['works for `cursor`'] = function()\n  eq(is_active('cursor'), false)\n\n  set_lines({ 'aa', 'aa', 'aa' })\n  set_cursor(1, 0)\n  type_keys('2j')\n  eq(is_active('cursor'), true)\n  sleep(default_total_time - small_time)\n  eq(is_active('cursor'), true)\n  sleep(small_time + 3 * small_time)\n  eq(is_active('cursor'), false)\nend\n\nT['is_active()']['works for `scroll`'] = function()\n  eq(is_active('scroll'), false)\n\n  set_lines({ 'aa', 'aa', 'aa' })\n  set_cursor(1, 0)\n  type_keys('<C-f>')\n  eq(is_active('scroll'), true)\n  sleep(default_total_time - small_time)\n  eq(is_active('scroll'), true)\n  sleep(small_time + 3 * small_time)\n  eq(is_active('scroll'), false)\nend\n\nT['is_active()']['works for `resize`'] = function()\n  eq(is_active('resize'), false)\n\n  type_keys('<C-w>v', '<C-w>|')\n  eq(is_active('resize'), true)\n  sleep(default_total_time - small_time)\n  eq(is_active('resize'), true)\n  sleep(small_time + 3 * small_time)\n  eq(is_active('resize'), false)\nend\n\nT['is_active()']['works for `open`/`close`'] = function()\n  eq(is_active('open'), false)\n  eq(is_active('close'), false)\n\n  type_keys('<C-w>v')\n  eq(is_active('open'), true)\n  eq(is_active('close'), false)\n  sleep(default_total_time - small_time)\n  eq(is_active('open'), true)\n  eq(is_active('close'), false)\n  sleep(small_time + 3 * small_time)\n  eq(is_active('open'), false)\n  eq(is_active('close'), false)\n\n  child.cmd('quit')\n  eq(is_active('open'), false)\n  eq(is_active('close'), true)\n  sleep(default_total_time - small_time)\n  eq(is_active('open'), false)\n  eq(is_active('close'), true)\n  sleep(small_time + 3 * small_time)\n  eq(is_active('open'), false)\n  eq(is_active('close'), false)\nend\n\nT['execute_after()'] = new_set()\n\nT['execute_after()']['works immediately'] = function()\n  child.lua([[MiniAnimate.execute_after('cursor', 'let g:been_here = v:true')]])\n  eq(child.g.been_here, true)\nend\n\nT['execute_after()']['works after animation is done'] = function()\n  child.set_size(5, 80)\n  child.api.nvim_set_keymap(\n    'n',\n    'n',\n    [[<Cmd>lua vim.cmd('normal! n'); MiniAnimate.execute_after('scroll', 'let g:been_here = v:true')<CR>]],\n    { noremap = true }\n  )\n\n  set_lines({ 'aa', 'bb', 'aa', 'aa', 'aa', 'aa', 'aa', 'aa', 'bb' })\n  set_cursor(1, 0)\n  type_keys('/', 'bb', '<CR>')\n\n  type_keys('n')\n  eq(child.g.been_here, vim.NIL)\n  sleep(default_total_time - small_time)\n  eq(child.g.been_here, vim.NIL)\n  sleep(small_time + small_time)\n  eq(child.g.been_here, true)\nend\n\nT['execute_after()']['validates input'] = function()\n  expect.error(function() child.lua([[MiniAnimate.execute_after('a', function() end)]]) end, 'Wrong `animation_type`')\n  expect.error(function() child.lua([[MiniAnimate.execute_after('cursor', 1)]]) end, '`action`.*string or callable')\nend\n\nT['execute_after()']['allows callable action'] = function()\n  child.lua([[MiniAnimate.execute_after('cursor', function() _G.been_here = true end)]])\n  eq(child.lua_get('_G.been_here'), true)\nend\n\nT['animate()'] = new_set()\n\nT['animate()']['works'] = function()\n  child.lua('_G.action_history = {}')\n  child.lua('_G.step_action = function(step) table.insert(_G.action_history, step); return step < 3 end')\n  child.lua('_G.step_timing = function(step) return _G.step_time * step end')\n\n  child.lua([[MiniAnimate.animate(_G.step_action, _G.step_timing)]])\n  -- It should execute the following order:\n  -- Action (step 0) - wait (step 1) - action (step 1) - ...\n  -- So here it should be (with `step_time = 25`):\n  -- 0 ms - `action(0)`\n  -- 25(=`timing(1)`) ms - `action(1)`\n  -- 75 ms - `action(2)`\n  -- 150 ms - `action(3)` and stop\n  eq(child.lua_get('_G.action_history'), { 0 })\n  sleep(step_time - small_time)\n  eq(child.lua_get('_G.action_history'), { 0 })\n  sleep(small_time)\n  eq(child.lua_get('_G.action_history'), { 0, 1 })\n\n  sleep(2 * step_time - small_time)\n  eq(child.lua_get('_G.action_history'), { 0, 1 })\n  sleep(small_time)\n  eq(child.lua_get('_G.action_history'), { 0, 1, 2 })\n\n  sleep(3 * step_time - small_time)\n  eq(child.lua_get('_G.action_history'), { 0, 1, 2 })\n  sleep(small_time)\n  eq(child.lua_get('_G.action_history'), { 0, 1, 2, 3 })\nend\n\nT['animate()']['respects `opts.max_steps`'] = function()\n  child.lua('_G.step_action = function(step) _G.latest_step = step; return step < 1000 end')\n  child.lua('MiniAnimate.animate(_G.step_action, function() return _G.step_time end, { max_steps = 2 })')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.latest_step'), 2)\nend\n\nT['animate()']['handles step times less than 1 ms'] = function()\n  child.lua('_G.step_action = function(step) _G.latest_step = step; return step < 3 end')\n  child.lua('MiniAnimate.animate(_G.step_action, function() return 0.1 end)')\n\n  -- All steps should be executed almost immediately (respectnig `libuv` loops)\n  child.poke_eventloop()\n  child.poke_eventloop()\n  child.poke_eventloop()\n  eq(child.lua_get('_G.latest_step'), 3)\nend\n\nT['animate()']['handles non-integer step times'] = function()\n  local new_step_time = 0.91 * step_time\n  child.lua('_G.new_step_time = ' .. new_step_time)\n  -- It should accumulate fractional parts, not discard them\n  child.lua('_G.step_action = function(step) _G.latest_step = step; return step < 10 end')\n  child.lua('MiniAnimate.animate(_G.step_action, function() return _G.new_step_time end)')\n\n  sleep(10 * new_step_time - small_time)\n  eq(child.lua_get('_G.latest_step') < 10, true)\n\n  sleep(small_time + small_time)\n  eq(child.lua_get('_G.latest_step'), 10)\nend\n\nT['gen_timing'] = new_set()\n\nlocal validate_timing = function(family, target, opts, tolerance)\n  opts = opts or {}\n  tolerance = tolerance or 0.1\n  local lua_cmd = string.format('_G.f = MiniAnimate.gen_timing.%s(...)', family)\n  child.lua(lua_cmd, { opts })\n\n  local f = function(...) return child.lua_get('_G.f(...)', { ... }) end\n  for i, _ in ipairs(target) do\n    -- Expect approximate equality\n    eq(math.abs(f(i, #target) - target[i]) <= tolerance, true)\n  end\n\n  child.lua('_G.f = nil')\nend\n\n--stylua: ignore\nT['gen_timing']['respects `opts.easing` argument'] = function()\n  validate_timing('none',        { 0,    0,    0,    0,    0 })\n  validate_timing('linear',      { 20,   20,   20,   20,   20 })\n  validate_timing('quadratic',   { 33.3, 26.7, 20,   13.3, 6.7 },  { easing = 'in' })\n  validate_timing('quadratic',   { 6.7,  13.3, 20,   26.7, 33.3 }, { easing = 'out' })\n  validate_timing('quadratic',   { 27.3, 18.2, 9,    18.2, 27.3 }, { easing = 'in-out' })\n  validate_timing('cubic',       { 45.5, 29.1, 16.4, 7.2,  1.8 },  { easing = 'in' })\n  validate_timing('cubic',       { 1.8,  7.2,  16.4, 29.1, 45.5 }, { easing = 'out' })\n  validate_timing('cubic',       { 33.3, 14.8, 3.8,  14.8, 33.3 }, { easing = 'in-out' })\n  validate_timing('quartic',     { 55.5, 28.5, 12,   3.5,  0.5 },  { easing = 'in' })\n  validate_timing('quartic',     { 0.5,  3.5,  12,   28.5, 55.5 }, { easing = 'out' })\n  validate_timing('quartic',     { 38,   11.3, 1.4,  11.3, 38 },   { easing = 'in-out' })\n  validate_timing('exponential', { 60.9, 24.2, 9.6,  3.8,  1.5 },  { easing = 'in' })\n  validate_timing('exponential', { 1.5,  3.8,  9.6,  24.2, 60.9 }, { easing = 'out' })\n  validate_timing('exponential', { 38.4, 10.2, 2.8,  10.2, 38.4 }, { easing = 'in-out' })\n\n  -- 'in-out' variants should be always symmetrical\n  validate_timing('quadratic',   { 30,   20,   10,  10,  20,   30 },   { easing = 'in-out' })\n  validate_timing('cubic',       { 38.6, 17.1, 4.3, 4.3, 17.1, 38.6 }, { easing = 'in-out' })\n  validate_timing('quartic',     { 45,   13.3, 1.7, 1.7, 13.3, 45 },   { easing = 'in-out' })\n  validate_timing('exponential', { 45.5, 11.6, 2.9, 2.9, 11.6, 45.5 }, { easing = 'in-out' })\nend\n\nT['gen_timing']['respects `opts` other arguments'] = function()\n  validate_timing('linear', { 10, 10 }, { unit = 'total' })\n  validate_timing('linear', { 100, 100 }, { duration = 100 })\n  validate_timing('linear', { 50, 50 }, { unit = 'total', duration = 100 })\nend\n\nT['gen_timing']['validates `opts` values'] = function()\n  local validate = function(opts, err_pattern)\n    expect.error(function() child.lua('MiniAnimate.gen_timing.linear(...)', { opts }) end, err_pattern)\n  end\n\n  validate({ easing = 'a' }, 'one of')\n  validate({ duration = 'a' }, 'number')\n  validate({ duration = -1 }, 'positive')\n  validate({ unit = 'a' }, 'one of')\nend\n\n--stylua: ignore\nT['gen_timing']['handles `n_steps=1` for all progression families and `opts.easing`'] = function()\n  validate_timing('none',        { 0 })\n  validate_timing('linear',      { 20 })\n  validate_timing('quadratic',   { 20 }, { easing = 'in' })\n  validate_timing('quadratic',   { 20 }, { easing = 'out' })\n  validate_timing('quadratic',   { 20 }, { easing = 'in-out' })\n  validate_timing('cubic',       { 20 }, { easing = 'in' })\n  validate_timing('cubic',       { 20 }, { easing = 'out' })\n  validate_timing('cubic',       { 20 }, { easing = 'in-out' })\n  validate_timing('quartic',     { 20 }, { easing = 'in' })\n  validate_timing('quartic',     { 20 }, { easing = 'out' })\n  validate_timing('quartic',     { 20 }, { easing = 'in-out' })\n  validate_timing('exponential', { 20 }, { easing = 'in' })\n  validate_timing('exponential', { 20 }, { easing = 'out' })\n  validate_timing('exponential', { 20 }, { easing = 'in-out' })\nend\n\nT['gen_path'] = new_set()\n\nT['gen_path']['line()'] = new_set()\n\nlocal validate_path = function(destination, output) eq(child.lua_get('_G.test_path(...)', { destination }), output) end\n\nlocal validate_default_path_predicate = function()\n  -- Default predicate should ignore nearby lines\n  validate_path({ 0, 0 }, {})\n\n  validate_path({ 1, 0 }, {})\n  validate_path({ 1, 100 }, {})\n  validate_path({ 1, -100 }, {})\n\n  validate_path({ -1, 0 }, {})\n  validate_path({ -1, 100 }, {})\n  validate_path({ -1, -100 }, {})\nend\n\n--stylua: ignore\nT['gen_path']['line()']['works'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.line()')\n\n  -- Basic checks\n  validate_path({  3,  3 }, { { 0, 0 }, {  1,  1 }, {  2,  2 } })\n  validate_path({ -3,  3 }, { { 0, 0 }, { -1,  1 }, { -2,  2 } })\n  validate_path({  3, -3 }, { { 0, 0 }, {  1, -1 }, {  2, -2 } })\n  validate_path({ -3, -3 }, { { 0, 0 }, { -1, -1 }, { -2, -2 } })\n\n  -- Default predicate\n  validate_default_path_predicate()\n\n  -- Walks along dimension with further distance\n  validate_path({ 3, 5 }, { { 0, 0 }, { 1, 1 }, { 1, 2 }, { 2, 3 }, { 2, 4 } })\n  validate_path({ 5, 3 }, { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 2 } })\n\n  validate_path({ 3, -5 }, { { 0, 0 }, {  1, -1 }, {  1, -2 }, {  2, -3 }, {  2, -4 } })\n  validate_path({ -5, 3 }, { { 0, 0 }, { -1,  1 }, { -2,  1 }, { -3,  2 }, { -4,  2 } })\n\n  validate_path({ -3, -5 }, { { 0, 0 }, { -1, -1 }, { -1, -2 }, { -2, -3 }, { -2, -4 } })\n  validate_path({ -5, -3 }, { { 0, 0 }, { -1, -1 }, { -2, -1 }, { -3, -2 }, { -4, -2 } })\nend\n\n--stylua: ignore\nT['gen_path']['line()']['respects `opts.predicate`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.line({ predicate = function() return true end })')\n\n  -- Should allow all non-trivial `destination`\n  validate_path({ 0, 0 }, {})\n  validate_path({  1, 3 }, { { 0, 0 }, { 0, 1 }, {  1, 2 } })\n  validate_path({ -1, 3 }, { { 0, 0 }, { 0, 1 }, { -1, 2 } })\n\n  validate_path({ 3, 3 }, { { 0, 0 }, { 1, 1 }, { 2, 2 } })\nend\n\n--stylua: ignore\nT['gen_path']['line()']['respects `opts.max_output_steps`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.line({ max_output_steps = 4 })')\n  validate_path({ 0, 0 }, {})\n  validate_path({ 2, 3 }, { { 0, 0 }, { 1, 1 }, {  1, 2 } })\n\n  validate_path({  2,  5 }, { { 0, 0 }, { 1,  1 }, {  1,  3 }, {  2,  4 } })\n  validate_path({ -2,  5 }, { { 0, 0 }, { 0,  1 }, { -1,  3 }, { -1,  4 } })\n  validate_path({  2, -5 }, { { 0, 0 }, { 1, -1 }, {  1, -2 }, {  2, -4 } })\n  validate_path({ -2, -5 }, { { 0, 0 }, { 0, -1 }, { -1, -2 }, { -1, -4 } })\nend\n\nT['gen_path']['angle()'] = new_set()\n\n--stylua: ignore\nT['gen_path']['angle()']['works'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.angle()')\n\n  -- Basic checks\n  validate_path({  3,  3 }, { { 0, 0 }, { 0,  1 }, { 0,  2 }, { 0,  3 }, {  1,  3 }, {  2,  3 }})\n  validate_path({ -3,  3 }, { { 0, 0 }, { 0,  1 }, { 0,  2 }, { 0,  3 }, { -1,  3 }, { -2,  3 }})\n  validate_path({  3, -3 }, { { 0, 0 }, { 0, -1 }, { 0, -2 }, { 0, -3 }, {  1, -3 }, {  2, -3 }})\n  validate_path({ -3, -3 }, { { 0, 0 }, { 0, -1 }, { 0, -2 }, { 0, -3 }, { -1, -3 }, { -2, -3 }})\n\n  -- Default predicate (should ignore nearby lines)\n  validate_default_path_predicate()\n\n  -- Walks along line (horizontal) first\n  validate_path({ 2, 3 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 3 } })\n  validate_path({ 3, 2 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 2 }, { 2, 2 } })\nend\n\n--stylua: ignore\nT['gen_path']['angle()']['respects `opts.predicate`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.angle({ predicate = function() return true end })')\n\n  -- Should allow all non-trivial `destination`\n  validate_path({ 0, 0 }, {})\n  validate_path({  1, 3 }, { { 0, 0 }, { 0, 1 }, {  0, 2 }, { 0, 3 } })\n  validate_path({ -1, 3 }, { { 0, 0 }, { 0, 1 }, {  0, 2 }, { 0, 3 } })\n\n  validate_path({  3,  3 }, { { 0, 0 }, { 0,  1 }, { 0,  2 }, { 0,  3 }, {  1,  3 }, {  2,  3 }})\nend\n\n--stylua: ignore\nT['gen_path']['angle()']['respects `opts.max_output_steps`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.angle({ max_output_steps = 3 })')\n  validate_path({ 0, 0 }, {})\n  validate_path({ 2, 3 }, { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 3 } })\n\n  validate_path({  2,  4 }, { { 0, 0 }, { 0,  1 }, { 0,  3 }, { 0,  4 }, {  1,  4 } })\n  validate_path({ -2,  4 }, { { 0, 0 }, { 0,  1 }, { 0,  3 }, { 0,  4 }, { -1,  4 } })\n  validate_path({  2, -4 }, { { 0, 0 }, { 0, -1 }, { 0, -3 }, { 0, -4 }, {  1, -4 } })\n  validate_path({ -2, -4 }, { { 0, 0 }, { 0, -1 }, { 0, -3 }, { 0, -4 }, { -1, -4 } })\nend\n\n--stylua: ignore\nT['gen_path']['angle()']['respects `opts.first_direction`'] = function()\n  child.lua([[_G.test_path = MiniAnimate.gen_path.angle({ first_direction = 'vertical' })]])\n\n  -- Should walk along column (vertical) first\n  validate_path({ 2, 3 }, { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 2, 1 }, { 2, 2 } })\n  validate_path({ 3, 2 }, { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 }, { 3, 1 } })\nend\n\nT['gen_path']['walls()'] = new_set()\n\n--stylua: ignore\nT['gen_path']['walls()']['works'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.walls()')\n\n  -- Basic checks\n  validate_path(\n  { 3, 3 },\n  {\n    { 3, 3 + 10 }, { 3, 3 - 10 },\n    { 3, 3 +  9 }, { 3, 3 -  9 },\n    { 3, 3 +  8 }, { 3, 3 -  8 },\n    { 3, 3 +  7 }, { 3, 3 -  7 },\n    { 3, 3 +  6 }, { 3, 3 -  6 },\n    { 3, 3 +  5 }, { 3, 3 -  5 },\n    { 3, 3 +  4 }, { 3, 3 -  4 },\n    { 3, 3 +  3 }, { 3, 3 -  3 },\n    { 3, 3 +  2 }, { 3, 3 -  2 },\n    { 3, 3 +  1 }, { 3, 3 -  1 }\n  })\n\n  validate_path(\n  { -3, -3 },\n  {\n    { -3, -3 + 10 }, { -3, -3 - 10 },\n    { -3, -3 +  9 }, { -3, -3 -  9 },\n    { -3, -3 +  8 }, { -3, -3 -  8 },\n    { -3, -3 +  7 }, { -3, -3 -  7 },\n    { -3, -3 +  6 }, { -3, -3 -  6 },\n    { -3, -3 +  5 }, { -3, -3 -  5 },\n    { -3, -3 +  4 }, { -3, -3 -  4 },\n    { -3, -3 +  3 }, { -3, -3 -  3 },\n    { -3, -3 +  2 }, { -3, -3 -  2 },\n    { -3, -3 +  1 }, { -3, -3 -  1 }\n  })\n\n  -- Default predicate (should ignore nearby lines)\n  validate_default_path_predicate()\nend\n\n--stylua: ignore\nT['gen_path']['walls()']['respects `opts.predicate`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.walls({ predicate = function() return true end })')\n\n  -- Should allow all non-trivial `destination`\n  validate_path({ 0, 0 }, {})\n\n  validate_path(\n  { 1, 3 },\n  {\n    { 1, 3 + 10 }, { 1, 3 - 10 },\n    { 1, 3 +  9 }, { 1, 3 -  9 },\n    { 1, 3 +  8 }, { 1, 3 -  8 },\n    { 1, 3 +  7 }, { 1, 3 -  7 },\n    { 1, 3 +  6 }, { 1, 3 -  6 },\n    { 1, 3 +  5 }, { 1, 3 -  5 },\n    { 1, 3 +  4 }, { 1, 3 -  4 },\n    { 1, 3 +  3 }, { 1, 3 -  3 },\n    { 1, 3 +  2 }, { 1, 3 -  2 },\n    { 1, 3 +  1 }, { 1, 3 -  1 }\n  })\n  validate_path(\n  { -1, 3 },\n  {\n    { -1, 3 + 10 }, { -1, 3 - 10 },\n    { -1, 3 +  9 }, { -1, 3 -  9 },\n    { -1, 3 +  8 }, { -1, 3 -  8 },\n    { -1, 3 +  7 }, { -1, 3 -  7 },\n    { -1, 3 +  6 }, { -1, 3 -  6 },\n    { -1, 3 +  5 }, { -1, 3 -  5 },\n    { -1, 3 +  4 }, { -1, 3 -  4 },\n    { -1, 3 +  3 }, { -1, 3 -  3 },\n    { -1, 3 +  2 }, { -1, 3 -  2 },\n    { -1, 3 +  1 }, { -1, 3 -  1 }\n  })\nend\n\n--stylua: ignore\nT['gen_path']['walls()']['respects `opts.width`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.walls({ width = 2 })')\n  validate_path(\n  { 3, 3 },\n  {\n    { 3, 3 + 2 }, { 3, 3 - 2 },\n    { 3, 3 + 1 }, { 3, 3 - 1 }\n  })\n\n  child.lua('_G.test_path = MiniAnimate.gen_path.walls({ width = 1 })')\n  validate_path({ 3, 3 }, { { 3, 3 + 1 }, { 3, 3 - 1 } })\n\n  child.lua('_G.test_path = MiniAnimate.gen_path.walls({ width = 0 })')\n  validate_path({ 3, 3 }, {})\nend\n\nT['gen_path']['spiral()'] = new_set()\n\n--stylua: ignore\nT['gen_path']['spiral()']['works'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.spiral()')\n\n  -- Basic checks\n  validate_path(\n  { 3, 3 },\n  -- Should go in narrowing spiral\n  {\n    -- Top (width 2)\n    { 3 - 2, 3 - 2 }, { 3 - 2, 3 - 1 }, { 3 - 2, 3 + 0 }, { 3 - 2, 3 + 1 },\n    -- Right (width 2)\n    { 3 - 2, 3 + 2 }, { 3 - 1, 3 + 2 }, { 3 + 0, 3 + 2 }, { 3 + 1, 3 + 2 },\n    -- Bottom (width 2)\n    { 3 + 2, 3 + 2 }, { 3 + 2, 3 + 1 }, { 3 + 2, 3 + 0 }, { 3 + 2, 3 - 1 },\n    -- Left (width 2)\n    { 3 + 2, 3 - 2 }, { 3 + 1, 3 - 2 }, { 3 + 0, 3 - 2 }, { 3 - 1, 3 - 2 },\n    -- Top (width 1)\n    { 3 - 1, 3 - 1 }, { 3 - 1, 3 + 0 },\n    -- Right (width 1)\n    { 3 - 1, 3 + 1 }, { 3 + 0, 3 + 1 },\n    -- Bottom (width 1)\n    { 3 + 1, 3 + 1 }, { 3 + 1, 3 + 0 },\n    -- Left (width 1)\n    { 3 + 1, 3 - 1 }, { 3 + 0, 3 - 1 },\n  })\n\n  -- Default predicate (should ignore nearby lines)\n  validate_default_path_predicate()\n end\n\nT['gen_path']['spiral()']['respects `opts.predicate`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.spiral({ predicate = function() return true end })')\n\n  -- Should allow all non-trivial `destination`\n  validate_path({ 0, 0 }, {})\n\n  eq(#child.lua_get('_G.test_path({ 1, 3 })') > 0, true)\n  eq(#child.lua_get('_G.test_path({ 3, 1 })') > 0, true)\nend\n\n--stylua: ignore\nT['gen_path']['spiral()']['respects `opts.width`'] = function()\n  child.lua('_G.test_path = MiniAnimate.gen_path.spiral({ width = 1 })')\n  validate_path(\n  { 3, 3 },\n  {\n    { 3 - 1, 3 - 1 }, { 3 - 1, 3 + 0 },\n    { 3 - 1, 3 + 1 }, { 3 + 0, 3 + 1 },\n    { 3 + 1, 3 + 1 }, { 3 + 1, 3 + 0 },\n    { 3 + 1, 3 - 1 }, { 3 + 0, 3 - 1 },\n  })\n\n  child.lua('_G.test_path = MiniAnimate.gen_path.spiral({ width = 0 })')\n  validate_path({ 3, 3 }, {})\nend\n\nT['gen_subscroll'] = new_set()\n\nlocal validate_subscroll = function(total_scroll, output)\n  eq(child.lua_get('_G.test_subscroll(...)', { total_scroll }), output)\nend\n\nT['gen_subscroll']['equal()'] = new_set()\n\n--stylua: ignore\nT['gen_subscroll']['equal()']['works'] = function()\n  child.lua('_G.test_subscroll = MiniAnimate.gen_subscroll.equal()')\n\n  -- Basic checks\n  validate_subscroll(2, { 1, 1 })\n  validate_subscroll(5, { 1, 1, 1, 1, 1 })\n\n  -- Default predicate (should subscroll only for more than 1)\n  validate_subscroll(1, {})\n  validate_subscroll(0, {})\n\n  -- Divides equally between steps if total scroll is more than default maximum\n  -- allowed number of steps\n  validate_subscroll(\n    60,\n    {\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    }\n  )\n  validate_subscroll(\n    63,\n    {\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n    }\n  )\n  validate_subscroll(\n    66,\n    {\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n      1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n    }\n  )\n  validate_subscroll(\n    72,\n    {\n      1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,\n      1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,\n      1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,\n    }\n  )\n  validate_subscroll(\n    120 - 3,\n    {\n      1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n      1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n      1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n    }\n  )\nend\n\nT['gen_subscroll']['equal()']['respects `opts.predicate`'] = function()\n  child.lua('_G.test_subscroll = MiniAnimate.gen_subscroll.equal({ predicate = function() return true end })')\n\n  -- Should allow all non-trivial `destination`\n  validate_subscroll(0, {})\n  validate_subscroll(1, { 1 })\nend\n\nT['gen_subscroll']['equal()']['respects `opts.max_output_steps`'] = function()\n  child.lua('_G.test_subscroll = MiniAnimate.gen_subscroll.equal({ max_output_steps = 10 })')\n\n  validate_subscroll(11, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 2 })\nend\n\nT['gen_subresize'] = new_set()\n\nlocal validate_subresize = function(sizes_from, sizes_to, output)\n  -- Overcome Neovim's \"Cannot convert given lua table\" for tables with\n  -- window sizes structure (keys like `[1000]`, etc.)\n  local lua_cmd =\n    string.format('vim.inspect(_G.test_subresize(%s, %s))', vim.inspect(sizes_from), vim.inspect(sizes_to))\n  local output_str = child.lua_get(lua_cmd)\n\n  eq(loadstring('return ' .. output_str)(), output)\nend\n\nT['gen_subresize']['equal()'] = new_set()\n\n--stylua: ignore\nT['gen_subresize']['equal()']['works'] = function()\n  child.lua('_G.test_subresize = MiniAnimate.gen_subresize.equal()')\n\n  -- Basic checks\n  validate_subresize(\n  {\n    [1000] = { width = 5, height = 5 },\n    [1001] = { width = 5, height = 7 }\n  },\n  {\n    [1000] = { width = 5, height = 2 },\n    [1001] = { width = 5, height = 10 }\n  },\n  {\n    {\n      [1000] = { width = 5, height = 4 },\n      [1001] = { width = 5, height = 8 }\n    },\n    {\n      [1000] = { width = 5, height = 3 },\n      [1001] = { width = 5, height = 9 }\n    },\n    {\n      [1000] = { width = 5, height = 2 },\n      [1001] = { width = 5, height = 10 }\n    },\n  })\n\n  validate_subresize(\n  {\n    [1000] = { width = 5, height = 5 },\n    [1001] = { width = 5, height = 7 }\n  },\n  {\n    [1000] = { width = 2, height = 5 },\n    [1001] = { width = 8, height = 7 }\n  },\n  {\n    {\n      [1000] = { width = 4, height = 5 },\n      [1001] = { width = 6, height = 7 }\n    },\n    {\n      [1000] = { width = 3, height = 5 },\n      [1001] = { width = 7, height = 7 }\n    },\n    {\n      [1000] = { width = 2, height = 5 },\n      [1001] = { width = 8, height = 7 }\n    },\n  })\n\n  -- Should compute number of steps based on maximum absolute difference\n  validate_subresize(\n  {\n    [1000] = { width = 5, height = 5 },\n    [1001] = { width = 5, height = 5 }\n  },\n  {\n    [1000] = { width = 2, height = 4 },\n    [1001] = { width = 8, height = 6 }\n  },\n  {\n    {\n      [1000] = { width = 4, height = 5 },\n      [1001] = { width = 6, height = 5 }\n    },\n    {\n      [1000] = { width = 3, height = 4 },\n      [1001] = { width = 7, height = 6 }\n    },\n    {\n      [1000] = { width = 2, height = 4 },\n      [1001] = { width = 8, height = 6 }\n    },\n  })\n\n  -- Works for single window\n  validate_subresize({ [1000] = { width = 5, height = 5 } }, { [1000] = { width = 7, height = 10 } }, {})\nend\n\nT['gen_subresize']['equal()']['respects `opts.predicate`'] = function()\n  child.lua([[_G.test_subresize = MiniAnimate.gen_subresize.equal({\n    predicate = function(sizes_from, sizes_to) return #vim.tbl_keys(sizes_from) > 2 end\n  })]])\n\n  -- Should allow all non-trivial `destination`\n  validate_subresize({\n    [1000] = { width = 5, height = 5 },\n    [1001] = { width = 5, height = 5 },\n  }, {\n    [1000] = { width = 2, height = 4 },\n    [1001] = { width = 8, height = 6 },\n  }, {})\nend\n\nT['gen_winconfig'] = new_set()\n\nlocal validate_winconfig = function(win_id, ref_position_data)\n  local output = child.lua_get('_G.test_winconfig(...)', { win_id })\n  eq(#output, #ref_position_data)\n\n  for step = 1, #output do\n      --stylua: ignore\n      eq(output[step], {\n        relative  = 'editor',\n        anchor    = 'NW',\n        row       = ref_position_data[step].row,\n        col       = ref_position_data[step].col,\n        width     = ref_position_data[step].width,\n        height    = ref_position_data[step].height,\n        focusable = false,\n        zindex    = 1,\n        border    = 'none',\n        style     = 'minimal',\n      })\n  end\nend\n\nlocal validate_same_border = function(ref_border)\n  local output = child.lua_get('_G.test_winconfig(0)')\n  for _, step in ipairs(output) do\n    eq(step.border, ref_border)\n  end\nend\n\nT['gen_winconfig']['static()'] = new_set()\n\nT['gen_winconfig']['static()']['works'] = function()\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.static()')\n  local validate = function(win_id)\n    local pos = child.fn.win_screenpos(win_id)\n    local width, height = child.api.nvim_win_get_width(win_id), child.api.nvim_win_get_height(win_id)\n    local ref_output = {}\n    for i = 1, 25 do\n        --stylua: ignore\n        ref_output[i] = {\n          row       = pos[1] - 1,\n          col       = pos[2] - 1,\n          width     = width,\n          height    = height,\n        }\n    end\n    validate_winconfig(win_id, ref_output)\n  end\n\n  -- Basic checks\n  child.cmd('wincmd v')\n  validate(child.api.nvim_get_current_win())\n\n  -- Default predicate (always `true`)\n  child.cmd('only')\n  validate(child.api.nvim_get_current_win())\nend\n\nT['gen_winconfig']['static()']['respects `opts.predicate`'] = function()\n  child.lua([[\n    _G.is_not_single_window = function(win_id)\n      local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n      return #vim.api.nvim_tabpage_list_wins(tabpage_id) > 1\n    end\n  ]])\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.static({ predicate = is_not_single_window })')\n\n  validate_winconfig(child.api.nvim_get_current_win(), {})\nend\n\nT['gen_winconfig']['static()']['respects `opts.n_steps`'] = function()\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.static({ n_steps = 1 })')\n\n  validate_winconfig(child.api.nvim_get_current_win(), {\n    {\n      row = 0,\n      col = 0,\n      width = 80,\n      height = 22,\n    },\n  })\nend\n\nT['gen_winconfig']['static()'][\"should not respect 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.o.winborder = 'rounded'\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.static()')\n  validate_same_border('none')\nend\n\nT['gen_winconfig']['center()'] = new_set()\n\nT['gen_winconfig']['center()']['works'] = function()\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.center()')\n\n  child.o.winwidth, child.o.winheight = 1, 1\n  child.set_size(5, 12)\n\n  child.cmd('wincmd v')\n  --stylua: ignore\n  validate_winconfig(\n    child.api.nvim_get_current_win(),\n    {\n      { col = 0, row = 0, width = 6, height = 3 },\n      { col = 1, row = 0, width = 5, height = 3 },\n      { col = 1, row = 1, width = 4, height = 2 },\n      { col = 2, row = 1, width = 3, height = 2 },\n      { col = 2, row = 1, width = 2, height = 1 },\n      { col = 3, row = 1, width = 1, height = 1 },\n    }\n  )\nend\n\nT['gen_winconfig']['center()']['respects `opts.predicate`'] = function()\n  child.lua([[\n    _G.is_not_single_window = function(win_id)\n      local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n      return #vim.api.nvim_tabpage_list_wins(tabpage_id) > 1\n    end\n  ]])\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.center({ predicate = is_not_single_window })')\n\n  validate_winconfig(child.api.nvim_get_current_win(), {})\nend\n\nT['gen_winconfig']['center()']['respects `opts.direction`'] = function()\n  child.lua([[_G.test_winconfig = MiniAnimate.gen_winconfig.center({ direction = 'from_center' })]])\n\n  child.o.winwidth, child.o.winheight = 1, 1\n  child.set_size(5, 12)\n\n  child.cmd('wincmd v')\n  --stylua: ignore\n  validate_winconfig(\n    child.api.nvim_get_current_win(),\n    {\n      { col = 3, row = 1, width = 1, height = 1 },\n      { col = 2, row = 1, width = 2, height = 1 },\n      { col = 2, row = 1, width = 3, height = 2 },\n      { col = 1, row = 1, width = 4, height = 2 },\n      { col = 1, row = 0, width = 5, height = 3 },\n      { col = 0, row = 0, width = 6, height = 3 },\n    }\n  )\nend\n\nT['gen_winconfig']['center()'][\"should not respect 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.o.winborder = 'rounded'\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.center()')\n  validate_same_border('none')\nend\n\nT['gen_winconfig']['wipe()'] = new_set()\n\nT['gen_winconfig']['wipe()']['works'] = function()\n  child.lua([[_G.test_winconfig = MiniAnimate.gen_winconfig.wipe()]])\n  local validate = function(command, ref_position_data)\n    child.cmd(command)\n    validate_winconfig(child.api.nvim_get_current_win(), ref_position_data)\n    child.cmd('only')\n  end\n\n  child.o.winwidth, child.o.winheight = 1, 1\n  child.set_size(10, 12)\n\n  -- Left\n  validate('topleft wincmd v', {\n    { col = 0, row = 0, width = 6, height = 8 },\n    { col = 0, row = 0, width = 5, height = 8 },\n    { col = 0, row = 0, width = 4, height = 8 },\n    { col = 0, row = 0, width = 3, height = 8 },\n    { col = 0, row = 0, width = 2, height = 8 },\n    { col = 0, row = 0, width = 1, height = 8 },\n  })\n\n  -- Top\n  validate('topleft wincmd s', {\n    { col = 0, row = 0, width = 12, height = 4 },\n    { col = 0, row = 0, width = 12, height = 3 },\n    { col = 0, row = 0, width = 12, height = 2 },\n    { col = 0, row = 0, width = 12, height = 1 },\n  })\n\n  -- Right\n  validate('botright wincmd v', {\n    { col = 6, row = 0, width = 6, height = 8 },\n    { col = 7, row = 0, width = 5, height = 8 },\n    { col = 8, row = 0, width = 4, height = 8 },\n    { col = 9, row = 0, width = 3, height = 8 },\n    { col = 10, row = 0, width = 2, height = 8 },\n    { col = 11, row = 0, width = 1, height = 8 },\n  })\n\n  -- Bottom\n  validate('botright wincmd s', {\n    { col = 0, row = 4, width = 12, height = 4 },\n    { col = 0, row = 5, width = 12, height = 3 },\n    { col = 0, row = 6, width = 12, height = 2 },\n    { col = 0, row = 7, width = 12, height = 1 },\n  })\nend\n\nT['gen_winconfig']['wipe()']['respects `opts.predicate`'] = function()\n  child.lua([[\n    _G.is_not_single_window = function(win_id)\n      local tabpage_id = vim.api.nvim_win_get_tabpage(win_id)\n      return #vim.api.nvim_tabpage_list_wins(tabpage_id) > 1\n    end\n  ]])\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.wipe({ predicate = is_not_single_window })')\n\n  validate_winconfig(child.api.nvim_get_current_win(), {})\nend\n\nT['gen_winconfig']['wipe()']['respects `opts.direction`'] = function()\n  child.lua([[_G.test_winconfig = MiniAnimate.gen_winconfig.wipe({ direction = 'from_edge' })]])\n  local validate = function(command, ref_position_data)\n    child.cmd(command)\n    validate_winconfig(child.api.nvim_get_current_win(), ref_position_data)\n    child.cmd('only')\n  end\n\n  child.o.winwidth, child.o.winheight = 1, 1\n  child.set_size(10, 12)\n\n  -- Left\n  validate('topleft wincmd v', {\n    { col = 0, row = 0, width = 1, height = 8 },\n    { col = 0, row = 0, width = 2, height = 8 },\n    { col = 0, row = 0, width = 3, height = 8 },\n    { col = 0, row = 0, width = 4, height = 8 },\n    { col = 0, row = 0, width = 5, height = 8 },\n    { col = 0, row = 0, width = 6, height = 8 },\n  })\n\n  -- Top\n  validate('topleft wincmd s', {\n    { col = 0, row = 0, width = 12, height = 1 },\n    { col = 0, row = 0, width = 12, height = 2 },\n    { col = 0, row = 0, width = 12, height = 3 },\n    { col = 0, row = 0, width = 12, height = 4 },\n  })\n\n  -- Right\n  validate('botright wincmd v', {\n    { col = 11, row = 0, width = 1, height = 8 },\n    { col = 10, row = 0, width = 2, height = 8 },\n    { col = 9, row = 0, width = 3, height = 8 },\n    { col = 8, row = 0, width = 4, height = 8 },\n    { col = 7, row = 0, width = 5, height = 8 },\n    { col = 6, row = 0, width = 6, height = 8 },\n  })\n\n  -- Bottom\n  validate('botright wincmd s', {\n    { col = 0, row = 7, width = 12, height = 1 },\n    { col = 0, row = 6, width = 12, height = 2 },\n    { col = 0, row = 5, width = 12, height = 3 },\n    { col = 0, row = 4, width = 12, height = 4 },\n  })\nend\n\nT['gen_winconfig']['wipe()'][\"should not respect 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.o.winborder = 'rounded'\n  child.lua('_G.test_winconfig = MiniAnimate.gen_winconfig.wipe()')\n  validate_same_border('none')\nend\n\nT['gen_winblend'] = new_set()\n\nT['gen_winblend']['linear()'] = new_set()\n\nT['gen_winblend']['linear()']['works'] = function()\n  child.lua('_G.f = MiniAnimate.gen_winblend.linear()')\n  eq(child.lua_get('{ _G.f(1, 10), _G.f(5, 10), _G.f(10, 10) }'), { 82, 90, 100 })\nend\n\nT['gen_winblend']['linear()']['respects `opts`'] = function()\n  child.lua('_G.f = MiniAnimate.gen_winblend.linear({ from = 50, to = 60 })')\n  eq(child.lua_get('{ _G.f(1, 10), _G.f(5, 10), _G.f(10, 10) }'), { 51, 55, 60 })\nend\n\n-- Integration tests ==========================================================\nT['Cursor'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Disable other animations for cleaner tests\n      child.lua('MiniAnimate.config.scroll.enable = false')\n      child.lua('MiniAnimate.config.resize.enable = false')\n      child.lua('MiniAnimate.config.open.enable = false')\n      child.lua('MiniAnimate.config.close.enable = false')\n\n      child.set_size(8, 12)\n\n      -- Use quicker timing for convenience\n      local lua_cmd = string.format('MiniAnimate.config.cursor.timing = function() return %d end', step_time)\n      child.lua(lua_cmd)\n\n      set_lines({ 'aaaaaaaaaa', 'aaa', '', 'aaa', 'aaaaaaaaaa' })\n      set_cursor(1, 0)\n    end,\n  },\n})\n\nT['Cursor']['works'] = function()\n  type_keys('G')\n  -- Cursor is set immediately\n  eq(get_cursor(), { 5, 0 })\n\n  -- First mark is shown immediately\n  child.expect_screenshot()\n\n  -- Every step is done properly\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n\n  -- Last one should remove mark\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Cursor']['works when movement is triggered by outside command'] = function()\n  set_cursor(5, 0)\n  child.expect_screenshot()\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Cursor']['works when cursor and/or marks are outside of line'] = function()\n  child.o.virtualedit = 'all'\n  set_cursor(4, 8)\n  child.expect_screenshot()\n  -- Introduce lag for test stability\n  sleep(small_time)\n  for _ = 1, 8 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Cursor']['works with tabs'] = function()\n  child.o.tabstop = 4\n  set_lines({ '\\taa', '\\tbb', 'cc' })\n  set_cursor(1, 4)\n\n  set_cursor(3, 0)\n  child.expect_screenshot()\n  -- Introduce lag for test stability\n  sleep(small_time)\n  for _ = 1, 5 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Cursor']['works with horizontally scrolled window view'] = function()\n  child.o.wrap = false\n  type_keys('2zl')\n  set_cursor(5, 5)\n  child.expect_screenshot()\n  -- Introduce lag for test stability\n  sleep(small_time)\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Cursor']['does not stop if mark should be placed outside of range'] = function()\n  child.lua([[MiniAnimate.config.cursor.path = function(destination)\n    local l, c = destination[1], destination[2]\n    return { { l, c }, { l, c - 10 }, { l, c }, { l + 10, c }, { l, c } }\n  end]])\n  set_cursor(5, 0)\n  child.expect_screenshot()\n  -- Introduce lag for test stability\n  sleep(small_time)\n  for _ = 1, 5 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Cursor']['stops on buffer change'] = function()\n  child.set_size(12, 24)\n  child.o.winwidth = 1\n  child.cmd('vertical botright new')\n  local second_window = child.api.nvim_get_current_win()\n  child.cmd('wincmd h')\n\n  set_cursor(5, 0)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_win(second_window)\n  -- Change doesn't happen right away, but inside next animation step\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Cursor']['can have only one animation active'] = function()\n  set_cursor(5, 0)\n\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  child.expect_screenshot()\n\n  set_cursor(1, 9)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Cursor']['works with multibyte characters'] = function()\n  set_lines({ 'ыыы', '🬗🬗🬗', '', 'ы', 'ыыыыыыыы' })\n  set_cursor(1, 0)\n  set_cursor(5, 14)\n  child.expect_screenshot()\n  -- Introduce lag for test stability\n  sleep(small_time)\n  for _ = 1, 7 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Cursor']['respects `enable` config setting'] = function()\n  child.lua('MiniAnimate.config.cursor.enable = false')\n  set_cursor(5, 0)\n  sleep(step_time + small_time)\n  -- Should show no marks\n  child.expect_screenshot()\nend\n\nT['Cursor']['correctly calls `timing`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.cursor.timing = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return _G.step_time\n  end]])\n  set_cursor(5, 0)\n  sleep(step_time * 5 + small_time)\n  eq(child.lua_get('_G.args_history'), { { s = 1, n = 4 }, { s = 2, n = 4 }, { s = 3, n = 4 }, { s = 4, n = 4 } })\nend\n\nT['Cursor']['correctly calls `path`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.cursor.path = function(destination)\n    table.insert(_G.args_history, destination)\n    return { { destination[1] - 1, destination[2] }, { destination[1], destination[2] } }\n  end]])\n\n  set_cursor(5, 9)\n  set_cursor(1, 0)\n  eq(child.lua_get('_G.args_history'), { { 4, 9 }, { -4, -9 } })\nend\n\nT['Cursor']['is not animated if `path` output is empty or `nil`'] = function()\n  child.lua('MiniAnimate.config.cursor.path = function() return {} end')\n  set_cursor(5, 0)\n  -- Should show now marks\n  child.expect_screenshot()\n\n  child.lua('MiniAnimate.config.cursor.path = function() return nil end')\n  set_cursor(1, 0)\n  -- Should show now marks\n  child.expect_screenshot()\nend\n\nT['Cursor']['ignores folds when computing path'] = function()\n  child.lua('MiniAnimate.config.cursor.path = function(destination) _G.destination = destination; return {} end')\n\n  -- Create text with folds\n  set_lines({ 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' })\n  set_cursor(2, 0)\n  type_keys('zf5j')\n  eq(\n    child.lua('_G.folds = {}; for i = 1, 9 do _G.folds[i] = vim.fn.foldclosed(i) end; return _G.folds'),\n    { -1, 2, 2, 2, 2, 2, 2, -1, -1 }\n  )\n  set_cursor(1, 0)\n  set_cursor(9, 0)\n  -- If folds were not ignored, this number would have been lower\n  eq(child.lua_get('_G.destination'), { 8, 0 })\nend\n\nT['Cursor']['triggers done event'] = function()\n  child.cmd('au User MiniAnimateDoneCursor lua _G.inside_done_event = true')\n  set_cursor(5, 0)\n  sleep(step_time * 5)\n  eq(child.lua_get('_G.inside_done_event'), true)\nend\n\nT['Cursor']['respects `vim.{g,b}.minianimate_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minianimate_disable = true\n    set_cursor(5, 0)\n    -- Should show now marks\n    child.expect_screenshot()\n\n    child[var_type].minianimate_disable = false\n    -- Needs two cursor movements in order to restore cache\n    set_cursor(1, 0)\n    set_cursor(5, 0)\n    -- Should show initial mark\n    child.expect_screenshot()\n  end,\n})\n\nT['Cursor']['respects buffer-local config'] = function()\n  child.lua('vim.b.minianimate_config = { cursor = { enable = false } }')\n\n  set_cursor(5, 0)\n  -- Should show now marks\n  child.expect_screenshot()\nend\n\nT['Scroll'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Disable other animations for cleaner tests\n      child.lua('MiniAnimate.config.cursor.enable = false')\n      child.lua('MiniAnimate.config.resize.enable = false')\n      child.lua('MiniAnimate.config.open.enable = false')\n      child.lua('MiniAnimate.config.close.enable = false')\n\n      child.set_size(8, 12)\n\n      -- Use quicker timing for convenience\n      local lua_cmd = string.format('MiniAnimate.config.scroll.timing = function() return %d end', step_time)\n      child.lua(lua_cmd)\n\n      set_lines(example_scroll_lines)\n      set_cursor(1, 0)\n    end,\n  },\n})\n\nT['Scroll']['works'] = function()\n  type_keys('3<C-e>')\n\n  -- Shouldn't start right away\n  child.expect_screenshot()\n\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  -- Nothing should happen after final view is reached\n  sleep(step_time)\n  child.expect_screenshot()\n\n  -- Should work in both directions\n  type_keys('3<C-y>')\n  child.expect_screenshot()\n\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Scroll']['works when movement is triggered by outside command'] = function()\n  set_cursor(9, 3)\n  child.expect_screenshot()\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Scroll']['allows immediate another scroll animation'] = function()\n  -- This should also properly restore some temporary set options\n  child.o.scrolloff, child.o.virtualedit = 1, 'block'\n\n  type_keys('10<C-e>')\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n\n  -- Should have intermediate options set\n  eq({ child.o.scrolloff, child.o.virtualedit }, { 0, 'all' })\n\n  -- Should start from the current window view and cursor (and not final)\n  type_keys('2<C-y>')\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n\n  -- Should properly restore options\n  eq({ child.o.scrolloff, child.o.virtualedit }, { 1, 'block' })\nend\n\nT['Scroll']['respects folds'] = function()\n  -- Create folds\n  set_cursor(2, 0)\n  type_keys('zf5j')\n\n  -- Should respect folds\n  set_cursor(1, 0)\n  type_keys('3<C-e>')\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Scroll'][\"respects global 'scrolloff'\"] = function()\n  child.o.scrolloff = 1\n  type_keys('L')\n\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\n  eq(child.o.scrolloff, 1)\nend\n\nT['Scroll'][\"respects window-local 'scrolloff'\"] = function()\n  child.wo.scrolloff = 1\n  type_keys('L')\n\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\n  eq(child.wo.scrolloff, 1)\nend\n\nT['Scroll'][\"respects 'virtualedit'\"] = function()\n  -- Global option\n  child.o.virtualedit = 'block'\n\n  type_keys('<C-d>')\n  sleep(3 * step_time + small_time)\n\n  validate_topline(4)\n  eq(child.o.virtualedit, 'block')\n\n  -- Window-local\n  child.wo.virtualedit = 'onemore'\n\n  type_keys('<C-u>')\n  sleep(3 * step_time + small_time)\n\n  validate_topline(1)\n  eq(child.o.virtualedit, 'onemore')\nend\n\nT['Scroll'][\"respects 'scrolloff' in presence of folds\"] = function()\n  set_cursor(6, 0)\n  type_keys('zf5j')\n  set_cursor(1, 0)\n\n  child.o.scrolloff = 1\n  type_keys('L')\n\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot({ ignore_text = { 7 } })\n  end\nend\n\nT['Scroll']['places cursor proportionally to scroll step'] = function()\n  set_cursor(9, 3)\n\n  -- Works forward\n  eq(get_cursor(), { 1, 0 })\n  sleep(step_time)\n  eq(get_cursor(), { 4, 1 })\n  sleep(step_time)\n  eq(get_cursor(), { 6, 2 })\n  sleep(step_time)\n  eq(get_cursor(), { 9, 3 })\n\n  -- Should work both ways\n  set_cursor(1, 2)\n  eq(get_cursor(), { 9, 3 })\n  sleep(step_time)\n  eq(get_cursor(), { 6, 3 })\n  sleep(step_time)\n  eq(get_cursor(), { 4, 2 })\n  sleep(step_time)\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['Scroll']['correctly places cursor in presence of multibyte characters'] = function()\n  local validate = function(topline_ref, cursor_ref)\n    eq(child.fn.line('w0'), topline_ref)\n    eq(get_cursor(), cursor_ref)\n  end\n\n  --stylua: ignore\n  set_lines({ 'аааа', '🬗🬗🬗🬗', 'ббб', '🬗🬗🬗', 'вввв', 'гггг', 'дддд', 'ееее' })\n  set_cursor(1, 6)\n\n  type_keys('3<C-e>')\n\n  validate(1, { 1, 6 })\n  -- Introduce lag for test stability\n  sleep(small_time)\n\n  sleep(step_time)\n  validate(2, { 2, 12 })\n\n  sleep(step_time)\n  validate(3, { 3, 4 })\n\n  sleep(step_time)\n  validate(4, { 4, 8 })\n\n  sleep(step_time)\n  validate(4, { 4, 8 })\nend\n\nT['Scroll']['correctly places cursor in presence of tabs'] = function()\n  local validate = function(topline_ref, cursor_ref)\n    eq(child.fn.line('w0'), topline_ref)\n    eq(get_cursor(), cursor_ref)\n  end\n\n  set_lines({ '\\t\\ta', '\\t\\tb', '\\t\\tc', '\\t\\td', 'e' })\n  set_cursor(1, 2)\n\n  type_keys('4<C-e>')\n\n  validate(1, { 1, 2 })\n  -- Introduce lag for test stability\n  sleep(small_time)\n\n  sleep(step_time)\n  validate(2, { 2, 1 })\n\n  sleep(step_time)\n  validate(3, { 3, 1 })\n\n  sleep(step_time)\n  validate(4, { 4, 0 })\n\n  sleep(step_time)\n  validate(5, { 5, 0 })\n\n  sleep(step_time)\n  validate(5, { 5, 0 })\nend\n\nT['Scroll']['can place intermediate cursor outside of line'] = function()\n  set_lines({ 'aaaa', 'a', '', '', '', '', '', 'a', 'aaaa' })\n  set_cursor(1, 3)\n\n  set_cursor(9, 3)\n\n  eq(get_virt_cursor(), { 1, 3 })\n  sleep(step_time)\n  eq(get_virt_cursor(), { 4, 3 })\n  sleep(step_time)\n  eq(get_virt_cursor(), { 6, 3 })\n  sleep(step_time)\n  eq(get_virt_cursor(), { 9, 3 })\nend\n\nT['Scroll']['places cursor on edge lines if intermediate target is not visible'] = function()\n  child.lua('MiniAnimate.config.scroll.subscroll = function(total_scroll) return { 1, total_scroll - 1 } end')\n\n  local many_lines = { 'aaaa' }\n  for _ = 1, 20 do\n    table.insert(many_lines, 'a')\n  end\n  table.insert(many_lines, 'aaaa')\n\n  set_lines(many_lines)\n  set_cursor(1, 3)\n\n  -- Cursor should be placed on visible window top/bottom at target column\n  -- (even if outside of line)\n  set_cursor(22, 3)\n  eq(get_virt_cursor(), { 1, 3 })\n  validate_topline(1)\n\n  sleep(step_time)\n  eq(get_virt_cursor(), { 7, 3 })\n  validate_topline(2)\n\n  sleep(step_time)\n  eq(get_virt_cursor(), { 22, 3 })\n  validate_topline(17)\n\n  -- Should work in both directions\n  set_cursor(1, 3)\n  eq(get_virt_cursor(), { 22, 3 })\n  validate_topline(17)\n\n  sleep(step_time)\n  eq(get_virt_cursor(), { 16, 3 })\n  validate_topline(16)\n\n  sleep(step_time)\n  eq(get_virt_cursor(), { 1, 3 })\n  validate_topline(1)\nend\n\nT['Scroll']['stops on buffer change'] = function()\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, true, { 'AAAA', 'BBBB', 'CCCC', 'DDDD' })\n\n  type_keys('10<C-e>')\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_buf(buf_id)\n  -- Should not scroll\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Scroll']['stops on window change'] = function()\n  child.o.winwidth = 1\n  child.cmd('vertical botright new')\n  local second_window = child.api.nvim_get_current_win()\n  set_lines({ 'AAAA', 'BBBB', 'CCCC', 'DDDD' })\n  child.cmd('wincmd h')\n\n  type_keys('10<C-e>')\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_win(second_window)\n  -- Should not scroll\n  child.expect_screenshot()\n  sleep(step_time)\n  child.expect_screenshot()\nend\n\nT['Scroll']['works properly just after buffer change'] = function()\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, true, example_scroll_lines_2)\n\n  child.api.nvim_set_current_buf(buf_id)\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  -- Should start animation\n  child.expect_screenshot()\nend\n\nT['Scroll']['works properly just after window change'] = function()\n  child.o.winwidth = 1\n  child.cmd('botright vertical split')\n  child.cmd('wincmd h')\n\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  -- Should start animation\n  child.expect_screenshot()\nend\n\nT['Scroll']['works properly inside terminal'] = function()\n  -- Start functioning terminal buffer\n  child.cmd('enew')\n  local job_id = child.fn.termopen('env -i bash --norc --noprofile')\n  child.fn.jobwait({ job_id }, 1000)\n\n  -- Echo many lines of text so that window view is completely different\n  -- compared with what was at Terminal mode start\n  local many_lines = string.rep([[a\\n]], 20)\n  type_keys(10, 'i', 'echo -e \"' .. many_lines .. '\"', '<CR>')\n  sleep(step_time)\n\n  -- There should not be any scroll animation after exiting Terminal mode\n  local init_line = child.fn.line('w0')\n  type_keys([[<C-\\>]], '<C-n>')\n  sleep(2 * step_time)\n  eq(child.fn.line('w0'), init_line)\nend\n\nT['Scroll']['does not automatically animate after buffer change'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  set_cursor(5, 0)\n\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_id)\n  child.api.nvim_set_current_buf(init_buf_id)\n\n  -- Should immediately show centered cursor line without animating it\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  child.expect_screenshot()\nend\n\nT['Scroll'][\"does not automatically animate result of 'incsearch'\"] = function()\n  child.o.incsearch = true\n\n  child.set_size(10, 25)\n\n  -- Should work for search with `/`\n  type_keys('/', 'oo', '<CR>')\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  -- Should be the same\n  child.expect_screenshot()\n\n  -- Should work for search with `?`\n  type_keys('?', 'aa', '<CR>')\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  -- Should be the same\n  child.expect_screenshot()\nend\n\nT['Scroll']['does not animate in Select mode'] = function()\n  child.set_size(5, 15)\n  child.cmd('smap <M-m> <Cmd>call winrestview({ \"topline\": 3 })<CR>')\n\n  set_cursor(4, 0)\n  type_keys('v<C-g>')\n  eq(child.fn.mode(), 's')\n\n  type_keys('<M-m>')\n  child.expect_screenshot()\n  eq(child.fn.mode(), 's')\nend\n\nT['Scroll']['handles mappings with <Cmd><CR>'] = function()\n  child.api.nvim_set_keymap('n', 'G', 'G<Cmd>lua _G.n = 0<CR>', {})\n\n  type_keys('G')\n  child.expect_screenshot()\n  sleep(step_time + small_time)\n  child.expect_screenshot()\nend\n\nT['Scroll']['works with different keys'] = new_set()\n\nT['Scroll']['works with different keys']['zz'] = function()\n  set_cursor(6, 0)\n  validate_topline(1)\n\n  type_keys('zz')\n  validate_topline(1)\n  sleep(step_time)\n  validate_topline(2)\n  sleep(step_time)\n  validate_topline(3)\n  sleep(step_time)\n  validate_topline(4)\n  sleep(step_time)\n  validate_topline(4)\n\n  eq(get_cursor(), { 6, 0 })\nend\n\nT['Scroll']['works with different keys']['zb'] = function()\n  type_keys('2<C-e>')\n  sleep(step_time * 2 + small_time)\n  set_cursor(6, 0)\n  validate_topline(3)\n\n  type_keys('zb')\n  validate_topline(3)\n  sleep(step_time)\n  validate_topline(2)\n  sleep(step_time)\n  validate_topline(1)\n  sleep(step_time)\n  validate_topline(1)\n\n  eq(get_cursor(), { 6, 0 })\nend\n\nT['Scroll']['works with different keys']['zt'] = function()\n  set_cursor(3, 0)\n  validate_topline(1)\n\n  type_keys('zt')\n  validate_topline(1)\n  sleep(step_time)\n  validate_topline(2)\n  sleep(step_time)\n  validate_topline(3)\n  sleep(step_time)\n  validate_topline(3)\n\n  eq(get_cursor(), { 3, 0 })\nend\n\nT['Scroll']['works with different keys']['gg'] = function()\n  type_keys('3<C-e>')\n  sleep(step_time * 3 + small_time)\n  validate_topline(4)\n\n  type_keys('gg')\n  validate_topline(4)\n  sleep(step_time)\n  validate_topline(3)\n  sleep(step_time)\n  validate_topline(2)\n  sleep(step_time)\n  validate_topline(1)\n  sleep(step_time)\n  validate_topline(1)\n\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Scroll']['works with different keys']['G'] = function()\n  validate_topline(1)\n  type_keys('G')\n  validate_topline(1)\n  sleep(step_time)\n  validate_topline(2)\n  sleep(step_time)\n  validate_topline(3)\n\n  sleep(small_time)\n  sleep(step_time * 6)\n  validate_topline(9)\n  sleep(step_time)\n  validate_topline(10)\n  sleep(step_time)\n  validate_topline(10)\n\n  eq(get_cursor(), { 15, 0 })\nend\n\nT['Scroll']['respects `enable` config setting'] = function()\n  child.lua('MiniAnimate.config.scroll.enable = false')\n  type_keys('3<C-e>')\n  -- Should move immediately\n  validate_topline(4)\nend\n\nT['Scroll']['correctly calls `timing`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.scroll.timing = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return _G.step_time\n  end]])\n\n  type_keys('4<C-e>')\n  sleep(step_time * 4 + small_time)\n  eq(child.lua_get('_G.args_history'), { { s = 1, n = 4 }, { s = 2, n = 4 }, { s = 3, n = 4 }, { s = 4, n = 4 } })\nend\n\nT['Scroll']['correctly calls `subscroll`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.scroll.subscroll = function(total_scroll)\n    table.insert(_G.args_history, total_scroll)\n    return { 1, 1, 1, 1 }\n  end]])\n\n  type_keys('4<C-e>')\n  sleep(step_time * 4 + small_time)\n  eq(child.lua_get('_G.args_history'), { 4 })\nend\n\nT['Scroll']['is not animated if `subscroll` output is empty or `nil`'] = function()\n  child.lua('MiniAnimate.config.scroll.subscroll = function() return {} end')\n  type_keys('10<C-e>')\n  -- Should scroll immediately\n  validate_topline(11)\n\n  child.lua('MiniAnimate.config.scroll.subscroll = function() return nil end')\n  type_keys('10<C-y>')\n  -- Should scroll immediately\n  validate_topline(1)\nend\n\nT['Scroll']['triggers done event'] = function()\n  child.cmd('au User MiniAnimateDoneScroll lua _G.inside_done_event = true')\n  type_keys('3<C-e>')\n  sleep(step_time * 3 + small_time)\n  eq(child.lua_get('_G.inside_done_event'), true)\nend\n\nT['Scroll']['respects `vim.{g,b}.minianimate_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minianimate_disable = true\n    type_keys('3<C-e>')\n    -- Should scroll immediately\n    validate_topline(4)\n\n    child[var_type].minianimate_disable = false\n    -- Needs two scrolls in order to restore cache\n    type_keys('3<C-y>')\n    type_keys('3<C-e>')\n    -- Should not scroll immediately\n    validate_topline(1)\n    sleep(step_time)\n    validate_topline(2)\n  end,\n})\n\nT['Scroll']['respects buffer-local config'] = function()\n  child.lua('vim.b.minianimate_config = { scroll = { enable = false } }')\n\n  type_keys('3<C-e>')\n  -- Should scroll immediately\n  validate_topline(4)\nend\n\nT['Resize'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Disable other animations for cleaner tests\n      child.lua('MiniAnimate.config.cursor.enable = false')\n      child.lua('MiniAnimate.config.scroll.enable = false')\n      child.lua('MiniAnimate.config.open.enable = false')\n      child.lua('MiniAnimate.config.close.enable = false')\n\n      child.lua('MiniAnimate.config.resize.enable = false')\n      child.set_size(8, 12)\n      child.lua('MiniAnimate.config.resize.enable = true')\n\n      -- Use quicker timing for convenience\n      local lua_cmd = string.format('MiniAnimate.config.resize.timing = function() return %d end', step_time)\n      child.lua(lua_cmd)\n\n      -- Prepare layout\n      child.o.winheight, child.o.winwidth = 1, 1\n      local init_win_id = child.api.nvim_get_current_win()\n      set_lines({ 'aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff' })\n      child.o.wrap = false\n\n      child.cmd('botright vertical new')\n      set_lines({ 'AAAA', 'BBBB', 'CCCC', 'DDDD', 'EEEE', 'FFFF' })\n      child.o.wrap = false\n\n      child.cmd('botright new')\n      set_lines({ '1111', '2222', '3333', '4444', '5555', '6666' })\n      child.o.wrap = false\n\n      child.api.nvim_set_current_win(init_win_id)\n      set_cursor(1, 0)\n    end,\n  },\n})\n\nT['Resize']['works'] = function()\n  -- Vertical resizing (in horizontal container)\n  type_keys('<C-w>|')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 6 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\n\n  -- Horizontal resizing (in horizontal container)\n  type_keys('<C-w>_')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 3 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\n\n  -- Both vertical and horizontal resizing\n  type_keys('<C-w>=')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 5 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Resize']['works when resize is triggered by outside command'] = function()\n  child.cmd('vertical resize +2')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 3 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Resize']['allows immediate another resize animation'] = function()\n  type_keys('<C-w>|')\n  child.expect_screenshot()\n  sleep(step_time + 2)\n  child.expect_screenshot()\n\n  type_keys('<C-w>l', '<C-w>|')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 6 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Resize']['animates only for equal layouts'] = function()\n  -- Should immediately close and go to final sizes\n  child.cmd('close')\n  child.expect_screenshot()\n\n  -- Should immediately open and go to final sizes\n  child.cmd('wincmd v')\n  child.expect_screenshot()\nend\n\nT['Resize']['does not flicker due to high cursor column'] = function()\n  set_lines({ 'aaaaaaaaaaaa' })\n  set_cursor(1, 11)\n\n  type_keys('<C-w>l', '<C-w>|')\n  sleep(step_time * 6)\n\n  type_keys('<C-w>=')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 5 do\n    sleep(step_time)\n    child.expect_screenshot({ ignore_text = { 4 } })\n  end\nend\n\nT['Resize']['does not flicker due to high cursor column in current window'] = function()\n  -- This is mostly the case if resize is happened due to high `winwidth`\n  set_lines({ 'aaaaaaaaaaaa' })\n  set_cursor(1, 11)\n  child.cmd('wincmd l')\n  child.o.winwidth = 12\n  sleep(step_time * 6 + small_time)\n\n  child.cmd('wincmd h')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 10 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Resize']['works with `winheight`/`winwidth`'] = function()\n  child.o.winwidth, child.o.winheight = 8, 4\n  sleep(step_time * 4)\n\n  child.cmd('wincmd l')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 6 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\n\n  -- Should work again\n  child.cmd('wincmd h')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 6 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\n\n  -- And again (for height resize)\n  child.cmd('wincmd j')\n  child.expect_screenshot()\n  sleep(small_time)\n  for _ = 1, 4 do\n    sleep(step_time)\n    child.expect_screenshot()\n  end\nend\n\nT['Resize']['respects `enable` config setting'] = function()\n  child.lua('MiniAnimate.config.resize.enable = false')\n  type_keys('<C-w>|')\n  -- Should resize immediately\n  child.expect_screenshot()\nend\n\nT['Resize']['correctly calls `timing`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.resize.timing = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return _G.step_time\n  end]])\n\n  type_keys('<C-w>|')\n  sleep(step_time * 5 + small_time)\n  eq(\n    child.lua_get('_G.args_history'),\n    { { s = 1, n = 5 }, { s = 2, n = 5 }, { s = 3, n = 5 }, { s = 4, n = 5 }, { s = 5, n = 5 } }\n  )\nend\n\nT['Resize']['correctly calls `subresize`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.resize.subresize = function(sizes_from, sizes_to)\n    table.insert(_G.args_history, { from = sizes_from, to = sizes_to })\n    return { sizes_to }\n  end]])\n\n  type_keys('<C-w>|')\n  sleep(step_time)\n  local args_history_string = child.lua_get('vim.inspect(_G.args_history)')\n  local args_history = loadstring('return ' .. args_history_string)()\n  eq(args_history, {\n    {\n      from = {\n        [1000] = { height = 2, width = 5 },\n        [1001] = { height = 2, width = 6 },\n        [1002] = { height = 3, width = 12 },\n      },\n      to = {\n        [1000] = { height = 2, width = 10 },\n        [1001] = { height = 2, width = 1 },\n        [1002] = { height = 3, width = 12 },\n      },\n    },\n  })\nend\n\nT['Resize']['is not animated if `subresize` output is empty or `nil`'] = function()\n  child.lua('MiniAnimate.config.resize.subresize = function() return {} end')\n  type_keys('<C-w>|')\n  -- Should resize immediately\n  child.expect_screenshot()\n\n  child.lua('MiniAnimate.config.resize.subresize = function() return nil end')\n  type_keys('<C-w>=')\n  -- Should resize immediately\n  child.expect_screenshot()\nend\n\nT['Resize']['triggers done event'] = function()\n  child.cmd('au User MiniAnimateDoneResize lua _G.inside_done_event = true')\n  type_keys('<C-w>|')\n  sleep(step_time * 5 + small_time)\n  eq(child.lua_get('_G.inside_done_event'), true)\nend\n\nT['Resize']['respects `vim.{g,b}.minianimate_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minianimate_disable = true\n    type_keys('<C-w>|')\n    -- Should resize immediately\n    child.expect_screenshot()\n\n    child[var_type].minianimate_disable = false\n    -- Needs two resizes in order to restore cache\n    type_keys('<C-w>=')\n    type_keys('<C-w>|')\n    -- Should not resize immediately\n    child.expect_screenshot()\n    sleep(step_time)\n    child.expect_screenshot()\n  end,\n})\n\nT['Resize']['respects buffer-local config'] = function()\n  child.lua('vim.b.minianimate_config = { resize = { enable = false } }')\n\n  type_keys('<C-w>|')\n  -- Should resize immediately\n  child.expect_screenshot()\nend\n\nT['Open'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Disable other animations for cleaner tests\n      child.lua('MiniAnimate.config.cursor.enable = false')\n      child.lua('MiniAnimate.config.scroll.enable = false')\n      child.lua('MiniAnimate.config.resize.enable = false')\n      child.lua('MiniAnimate.config.close.enable = false')\n\n      child.set_size(8, 12)\n\n      -- Use quicker timing for convenience\n      local lua_cmd = string.format('MiniAnimate.config.open.timing = function() return %d end', step_time)\n      child.lua(lua_cmd)\n\n      -- Use more testable `winconfig`\n      create_openclose_test_winconfig()\n      child.lua('MiniAnimate.config.open.winconfig = _G.openclose_test_winconfig')\n\n      child.o.winheight, child.o.winwidth = 1, 1\n      set_lines({ 'aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff' })\n      set_cursor(1, 0)\n    end,\n  },\n})\n\n--stylua: ignore\nT['Open']['works'] = function()\n  child.cmd('topleft vertical new')\n  sleep(small_time)\n  validate_floats({\n    [1003] = {\n      anchor = 'NW', external = false, focusable = false, relative = 'editor', zindex = 1,\n      row = 0, col = 0, width = 6, height = 6, winblend = 80,\n    },\n  })\n  eq(child.api.nvim_win_get_option(1003, 'winhighlight'), 'Normal:MiniAnimateNormalFloat')\n  local win_buf = child.api.nvim_win_get_buf(1003)\n  eq(child.api.nvim_buf_get_name(win_buf), 'minianimate://' .. win_buf .. '/open-close-scratch')\n\n  sleep(step_time)\n  validate_floats({ [1003] = { row = 0, col = 0, width = 3, height = 3, winblend = 90 } })\n\n  sleep(step_time)\n  validate_floats({ [1003] = false })\nend\n\nT['Open']['works for a new tabpage'] = function()\n  child.cmd('tabedit')\n  sleep(small_time)\n  validate_floats({\n    [1003] = { relative = 'editor', row = 1, col = 0, width = 12, height = 5, winblend = 80 },\n  })\n  sleep(2 * small_time)\n  child.cmd('tabclose')\n\n  -- Should also work second time (testing correct usage of tabpage number)\n  child.cmd('tabedit')\n  validate_floats({\n    [1005] = { relative = 'editor', row = 1, col = 0, width = 12, height = 5, winblend = 80 },\n  })\nend\n\nT['Open']['allows only one active animation'] = function()\n  child.cmd('topleft vertical new')\n  sleep(small_time)\n  validate_floats({\n    [1003] = { relative = 'editor', row = 0, col = 0, width = 6, height = 6, winblend = 80 },\n  })\n\n  child.cmd('botright new')\n  sleep(step_time + small_time)\n  --stylua: ignore\n  validate_floats({\n    [1003] = false,\n    [1005] = {\n      -- It is already a second step with quarter coverage\n      relative = 'editor', row = 3, col = 0, width = 6, height = 2, winblend = 90,\n    },\n  })\nend\n\nT['Open']['reopens floating window if it was closed manually'] = function()\n  child.cmd('topleft vertical new')\n  sleep(small_time)\n  validate_floats({\n    [1003] = { relative = 'editor', row = 0, col = 0, width = 6, height = 6, winblend = 80 },\n  })\n  child.cmd('only')\n  eq(child.api.nvim_list_wins(), { 1001 })\n\n  sleep(step_time)\n  validate_floats({\n    -- It is already a second step with quarter coverage\n    [1004] = { relative = 'editor', row = 0, col = 0, width = 3, height = 3, winblend = 90 },\n  })\nend\n\nT['Open']['respects `enable` config setting'] = function()\n  child.lua('MiniAnimate.config.open.enable = false')\n  child.cmd('topleft vertical new')\n  -- Should not animate\n  eq(list_wins(), { 1000, 1001 })\nend\n\nT['Open']['correctly calls `timing`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.open.timing = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return _G.step_time\n  end]])\n\n  child.cmd('wincmd v')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.args_history'), { { s = 1, n = 2 }, { s = 2, n = 2 } })\nend\n\nT['Open']['correctly calls `winconfig`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.open.winconfig = function(win_id)\n    table.insert(_G.args_history, win_id)\n    return _G.openclose_test_winconfig(win_id)\n  end]])\n\n  child.cmd('wincmd v')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.args_history'), { 1001 })\nend\n\nT['Open'][\"does not respect 'winborder' option by default\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  -- Reset to default `config.open.winconfig`\n  unload_module()\n  load_module()\n\n  child.o.winborder = 'rounded'\n  local default_winconfig_steps = child.lua_get('MiniAnimate.config.open.winconfig(0)')\n  for _, step in ipairs(default_winconfig_steps) do\n    eq(step.border, 'none')\n  end\nend\n\nT['Open']['correctly calls `winblend`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.open.winblend = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return 10\n  end]])\n\n  child.cmd('wincmd v')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.args_history'), { { s = 0, n = 2 }, { s = 1, n = 2 } })\nend\n\nT['Open']['is not animated if `winconfig` output is empty or `nil`'] = function()\n  child.lua('MiniAnimate.config.open.winconfig = function() return {} end')\n  child.cmd('wincmd v')\n  -- Should not animate\n  eq(list_wins(), { 1000, 1001 })\n\n  child.lua('MiniAnimate.config.open.winconfig = function() return nil end')\n  child.cmd('wincmd v')\n  -- Should not animate\n  eq(list_wins(), { 1000, 1001, 1002 })\nend\n\nT['Open']['triggers done event'] = function()\n  child.cmd('au User MiniAnimateDoneOpen lua _G.inside_done_event = true')\n  child.cmd('wincmd v')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.inside_done_event'), true)\nend\n\nT['Open']['respects `vim.{g,b}.minianimate_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minianimate_disable = true\n    child.cmd('wincmd v')\n    -- Should open without animation\n    eq(list_wins(), { 1000, 1001 })\n\n    child[var_type].minianimate_disable = false\n    child.cmd('wincmd v')\n    -- Should open with animation\n    sleep(small_time)\n    validate_floats({ [1004] = { relative = 'editor' } })\n  end,\n})\n\nT['Open']['respects buffer-local config'] = function()\n  child.lua('vim.b.minianimate_config = { open = { enable = false } }')\n  child.cmd('wincmd v')\n  -- Should open without animation\n  eq(list_wins(), { 1000, 1001 })\nend\n\n-- `close` is tested less thoroughly in hope that it shares implementation with `open`\nT['Close'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Disable other animations for cleaner tests\n      child.lua('MiniAnimate.config.cursor.enable = false')\n      child.lua('MiniAnimate.config.scroll.enable = false')\n      child.lua('MiniAnimate.config.resize.enable = false')\n      child.lua('MiniAnimate.config.open.enable = false')\n\n      child.set_size(8, 12)\n\n      -- Use quicker timing for convenience\n      local lua_cmd = string.format('MiniAnimate.config.close.timing = function() return %d end', step_time)\n      child.lua(lua_cmd)\n\n      -- Use more testable `winconfig`\n      create_openclose_test_winconfig()\n      child.lua('MiniAnimate.config.close.winconfig = _G.openclose_test_winconfig')\n\n      child.o.winheight, child.o.winwidth = 1, 1\n      set_lines({ 'aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff' })\n      set_cursor(1, 0)\n    end,\n  },\n})\n\n--stylua: ignore\nT['Close']['works'] = function()\n  child.cmd('topleft vertical new')\n  child.cmd('close')\n  sleep(small_time)\n  validate_floats({\n    [1003] = {\n      anchor = 'NW', external = false, focusable = false, relative = 'editor', zindex = 1,\n      row = 0, col = 0, width = 6, height = 6, winblend = 80,\n    },\n  })\n  eq(child.api.nvim_win_get_option(1003, 'winhighlight'), 'Normal:MiniAnimateNormalFloat')\n  local win_buf = child.api.nvim_win_get_buf(1003)\n  eq(child.api.nvim_buf_get_name(win_buf), 'minianimate://' .. win_buf .. '/open-close-scratch')\n\n  sleep(step_time)\n  validate_floats({ [1003] = { row = 0, col = 0, width = 3, height = 3, winblend = 90 } })\n\n  sleep(step_time)\n  validate_floats({ [1003] = false })\nend\n\nT['Close']['respects `enable` config setting'] = function()\n  child.lua('MiniAnimate.config.close.enable = false')\n  child.cmd('topleft vertical new')\n  child.cmd('close')\n  -- Should not animate\n  eq(list_wins(), { 1000 })\nend\n\nT['Close']['correctly calls `timing`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.close.timing = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return _G.step_time\n  end]])\n\n  child.cmd('wincmd v')\n  child.cmd('close')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.args_history'), { { s = 1, n = 2 }, { s = 2, n = 2 } })\nend\n\nT['Close']['correctly calls `winconfig`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.close.winconfig = function(win_id)\n    table.insert(_G.args_history, win_id)\n    return _G.openclose_test_winconfig(win_id)\n  end]])\n\n  child.cmd('wincmd v')\n  child.cmd('close')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.args_history'), { 1001 })\nend\n\nT['Close'][\"does not respect 'winborder' option by default\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  -- Reset to default `config.open.winconfig`\n  unload_module()\n  load_module()\n\n  child.o.winborder = 'rounded'\n  local default_winconfig_steps = child.lua_get('MiniAnimate.config.close.winconfig(0)')\n  for _, step in ipairs(default_winconfig_steps) do\n    eq(step.border, 'none')\n  end\nend\n\nT['Close']['correctly calls `winblend`'] = function()\n  child.lua('_G.args_history = {}')\n  child.lua([[MiniAnimate.config.close.winblend = function(s, n)\n    table.insert(_G.args_history, { s = s, n = n })\n    return 10\n  end]])\n\n  child.cmd('wincmd v')\n  child.cmd('close')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.args_history'), { { s = 0, n = 2 }, { s = 1, n = 2 } })\nend\n\nT['Close']['triggers done event'] = function()\n  child.cmd('au User MiniAnimateDoneClose lua _G.inside_done_event = true')\n  child.cmd('wincmd v')\n  child.cmd('close')\n  sleep(step_time * 2 + small_time)\n  eq(child.lua_get('_G.inside_done_event'), true)\nend\n\nT['Close']['respects buffer-local config'] = function()\n  child.lua('vim.b.minianimate_config = { close = { enable = false } }')\n  child.cmd('wincmd v')\n  child.cmd('close')\n  -- Should open without animation\n  eq(list_wins(), { 1000 })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_base16.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('base16', config) end\nlocal unload_module = function() child.mini_unload('base16') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\n--stylua: ignore end\n\nlocal validate_hl_group = function(group_name, target)\n  expect.match(\n    child.cmd_capture('highlight ' .. group_name):gsub(' +', ' '),\n    group_name .. ' xxx .*' .. vim.pesc(target)\n  )\nend\n\n-- Data =======================================================================\nlocal minischeme_palette = {\n  base00 = '#112641',\n  base01 = '#3a475e',\n  base02 = '#606b81',\n  base03 = '#8691a7',\n  base04 = '#d5dc81',\n  base05 = '#e2e98f',\n  base06 = '#eff69c',\n  base07 = '#fcffaa',\n  base08 = '#ffcfa0',\n  base09 = '#cc7e46',\n  base0A = '#46a436',\n  base0B = '#9ff895',\n  base0C = '#ca6ecf',\n  base0D = '#42f7ff',\n  base0E = '#ffc4ff',\n  base0F = '#00a5c5',\n}\n\nlocal minischeme_use_cterm = {\n  base00 = 235,\n  base01 = 238,\n  base02 = 60,\n  base03 = 103,\n  base04 = 186,\n  base05 = 186,\n  base06 = 229,\n  base07 = 229,\n  base08 = 223,\n  base09 = 173,\n  base0A = 71,\n  base0B = 156,\n  base0C = 170,\n  base0D = 87,\n  base0E = 225,\n  base0F = 38,\n}\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Undo the color scheme applied for all tests\n      child.cmd('hi clear')\n\n      load_module({ palette = minischeme_palette })\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniBase16)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniBase16.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniBase16.config.' .. field), value) end\n\n  expect_config('palette', minischeme_palette)\n  expect_config('use_cterm', vim.NIL)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ palette = minischeme_palette, use_cterm = true })\n  eq(child.lua_get('MiniBase16.config.use_cterm'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ palette = 'a' }, 'config.palette', 'table')\n  expect_config_error({ palette = { 'a' } }, 'config.palette', 'base00')\n  expect_config_error({ palette = { base00 = 1 } }, 'config.palette', 'HEX')\n  expect_config_error({ palette = { base00 = '000' } }, 'config.palette.base00', 'HEX')\n  expect_config_error({ palette = { base00 = '000000' } }, 'config.palette.base00', 'HEX')\n  expect_config_error({ palette = { base00 = '#GGGGGG' } }, 'config.palette.base00', 'HEX')\n  expect_config_error({ palette = minischeme_palette, use_cterm = 'a' }, 'use_cterm', 'boolean or table')\n  expect_config_error({ palette = minischeme_palette, use_cterm = { 'a' } }, 'use_cterm', 'base00')\n  expect_config_error({ palette = minischeme_palette, use_cterm = { base00 = 'a' } }, 'use_cterm.base00', 'cterm color')\n  expect_config_error({ palette = minischeme_palette, use_cterm = { base00 = -1 } }, 'use_cterm.base00', 'cterm color')\nend\n\nT['setup()']['defines builtin highlight groups'] = function()\n  local p = child.lua_get('MiniBase16.config.palette')\n  validate_hl_group('Normal', ('guifg=%s guibg=%s'):format(p.base05, p.base00))\n  validate_hl_group('Cursor', ('guifg=%s guibg=%s'):format(p.base00, p.base05))\n\n  validate_hl_group('Comment', ('guifg=%s'):format(p.base03))\n  validate_hl_group('Error', ('guifg=%s guibg=%s'):format(p.base00, p.base08))\n  validate_hl_group('Special', ('guifg=%s'):format(p.base0C))\n  validate_hl_group('Bold', 'gui=bold')\n\n  local diagnostic_hl_group = 'DiagnosticError'\n  validate_hl_group(diagnostic_hl_group, ('guifg=%s'):format(p.base08))\nend\n\nT['setup()']['defines highlight groups for terminal colors'] = function()\n  local p = child.lua_get('MiniBase16.config.palette')\n  vim.g.terminal_color_0 = p.base00\n  vim.g.terminal_color_background = vim.o.background == 'dark' and vim.g.terminal_color_0 or vim.g.terminal_color_7\n  vim.g.terminal_color_foreground = vim.o.background == 'dark' and vim.g.terminal_color_5 or vim.g.terminal_color_2\nend\n\nT['setup()']['clears previous colorscheme'] = function()\n  local p = child.lua_get('MiniBase16.config.palette')\n  child.cmd('colorscheme blue')\n  load_module({ palette = minischeme_palette })\n  validate_hl_group('Normal', ('guifg=%s guibg=%s'):format(p.base05, p.base00))\nend\n\nT['setup()']['respects `config.use_cterm`'] = function()\n  local p = child.lua_get('MiniBase16.config.palette')\n  local p_cterm = minischeme_use_cterm\n\n  reload_module({ palette = minischeme_palette, use_cterm = true })\n  validate_hl_group(\n    'Normal',\n    ('ctermfg=%s ctermbg=%s guifg=%s guibg=%s'):format(p_cterm.base05, p_cterm.base00, p.base05, p.base00)\n  )\n\n  reload_module({ palette = minischeme_palette, use_cterm = p_cterm })\n  validate_hl_group(\n    'Normal',\n    ('ctermfg=%s ctermbg=%s guifg=%s guibg=%s'):format(p_cterm.base05, p_cterm.base00, p.base05, p.base00)\n  )\nend\n\nT['setup()']['respects `config.plugins`'] = function()\n  local clear_highlight = function()\n    child.cmd('highlight clear')\n    expect.match(child.cmd_capture('hi MiniCursorword'), 'cleared')\n  end\n\n  -- By default it should load plugin integrations\n  clear_highlight()\n  reload_module({ palette = minischeme_palette })\n  validate_hl_group('MiniCursorword', 'gui=underline')\n\n  -- If supplied `false`, should not load plugin integration\n  clear_highlight()\n  reload_module({\n    palette = minischeme_palette,\n    plugins = { ['nvim-mini/mini.nvim'] = false, ['echasnovski/mini.nvim'] = false },\n  })\n  expect.match(child.cmd_capture('hi MiniCursorword'), 'cleared')\n\n  -- Should allow loading only chosen integrations\n  clear_highlight()\n  reload_module({ palette = minischeme_palette, plugins = { default = false, ['nvim-mini/mini.nvim'] = true } })\n  validate_hl_group('MiniCursorword', 'gui=underline')\n  expect.match(child.cmd_capture('hi GitSignsAdd'), 'cleared')\nend\n\nT['mini_palette()'] = new_set()\n\nT['mini_palette()']['validates arguments'] = function()\n  local validate = function(args, error_pattern)\n    expect.error(function() child.lua_get('MiniBase16.mini_palette(...)', args) end, error_pattern)\n  end\n\n  validate({ 1, '#000000' }, 'background.*HEX')\n  validate({ 'a', '#000000' }, 'background.*HEX')\n  validate({ '000000', '#000000' }, 'background.*HEX')\n  validate({ '#GGGGGG', '#000000' }, 'background.*HEX')\n\n  validate({ '#000000', 1 }, 'foreground.*HEX')\n  validate({ '#000000', 'a' }, 'foreground.*HEX')\n  validate({ '#000000', '000000' }, 'foreground.*HEX')\n  validate({ '#000000', '#GGGGGG' }, 'foreground.*HEX')\n\n  validate({ '#000000', '#FFFFFF', 'a' }, 'accent_chroma.*number')\n  validate({ '#000000', '#FFFFFF', -1 }, 'accent_chroma.*positive')\nend\n\nT['mini_palette()']['works'] = function()\n  eq(child.lua_get([[MiniBase16.mini_palette('#112641', '#e2e98f', 75)]]), minischeme_palette)\nend\n\nT['rgb_palette_to_cterm_palette()'] = new_set()\n\nT['rgb_palette_to_cterm_palette()']['validates arguments'] = function()\n  local validate = function(palette, error_pattern)\n    expect.error(\n      function() child.lua_get('MiniBase16.rgb_palette_to_cterm_palette(...)', { palette }) end,\n      error_pattern\n    )\n  end\n\n  validate('a', 'palette.*table')\n  validate({ 'a' }, 'palette.*base00')\n  validate({ base00 = 1 }, 'palette.*HEX')\n  validate({ base00 = '000' }, 'palette.base00.*HEX')\n  validate({ base00 = '000000' }, 'palette.base00.*HEX')\n  validate({ base00 = '#GGGGGG' }, 'palette.base00.*HEX')\nend\n\nT['rgb_palette_to_cterm_palette()']['works'] = function()\n  eq(child.lua_get('MiniBase16.rgb_palette_to_cterm_palette(...)', { minischeme_palette }), minischeme_use_cterm)\nend\n\nT['minischeme colorscheme'] = new_set()\n\nT['minischeme colorscheme']['works with dark background'] = function()\n  child.cmd('colorscheme minischeme')\n  child.o.background = 'dark'\n  validate_hl_group('Normal', 'ctermfg=186 ctermbg=235 guifg=#e2e98f guibg=#112641')\nend\n\nT['minischeme colorscheme']['works with light background'] = function()\n  child.cmd('colorscheme minischeme')\n  child.o.background = 'light'\n  validate_hl_group('Normal', 'ctermfg=18 ctermbg=254 guifg=#002a83 guibg=#e2e5ca')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_basics.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('basics', config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = child.setup,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniBasics)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n\n  eq(child.lua_get('type(_G.MiniBasics.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniBasics.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('options.basic', true)\n  expect_config('options.extra_ui', false)\n  expect_config('options.win_borders', 'auto')\n  expect_config('mappings.basic', true)\n  expect_config('mappings.option_toggle_prefix', [[\\]])\n  expect_config('mappings.windows', false)\n  expect_config('mappings.move_with_alt', false)\n  expect_config('autocommands.basic', true)\n  expect_config('autocommands.relnum_in_visual_mode', false)\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  load_module({ options = { basic = false } })\n  eq(child.lua_get('MiniBasics.config.options.basic'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { basic = 1 } }, 'options.basic', 'boolean')\n  expect_config_error({ options = { extra_ui = 1 } }, 'options.extra_ui', 'boolean')\n  expect_config_error({ options = { win_borders = 1 } }, 'options.win_borders', 'string')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { basic = 1 } }, 'mappings.basic', 'boolean')\n  expect_config_error({ mappings = { option_toggle_prefix = 1 } }, 'mappings.option_toggle_prefix', 'string')\n  expect_config_error({ mappings = { windows = 1 } }, 'mappings.windows', 'boolean')\n  expect_config_error({ mappings = { move_with_alt = 1 } }, 'mappings.move_with_alt', 'boolean')\n  expect_config_error({ autocommands = 'a' }, 'autocommands', 'table')\n  expect_config_error({ autocommands = { basic = 1 } }, 'autocommands.basic', 'boolean')\n  expect_config_error({ autocommands = { relnum_in_visual_mode = 1 } }, 'autocommands.relnum_in_visual_mode', 'boolean')\n  expect_config_error({ silent = 'a' }, 'silent', 'boolean')\nend\n\nT['toggle_diagnostic()'] = new_set()\n\nlocal toggle_diagnostic = function() return child.lua_get('MiniBasics.toggle_diagnostic()') end\n\nT['toggle_diagnostic()']['works'] = function()\n  if child.fn.has('nvim-0.10') == 1 then\n    child.lua('vim.diagnostic.enable = function(enable) vim.b.diag_status = enable and \"enabled\" or \"disabled\" end')\n    child.lua('vim.diagnostic.is_enabled = function(enable) return vim.b.diag_status ~= \"disabled\" end')\n  else\n    child.lua('vim.diagnostic.enable = function() vim.b.diag_status = \"enabled\" end')\n    child.lua('vim.diagnostic.disable = function() vim.b.diag_status = \"disabled\" end')\n    child.lua('vim.diagnostic.is_disabled = function() return vim.b.diag_status == \"disabled\" end')\n  end\n\n  load_module()\n\n  -- Should disable on per-buffer basis\n  local buf_id_one = child.api.nvim_get_current_buf()\n  local buf_id_two = child.api.nvim_create_buf(true, false)\n\n  child.api.nvim_set_current_buf(buf_id_one)\n  eq(child.b.diag_status, vim.NIL)\n  eq(toggle_diagnostic(), 'nodiagnostic')\n  eq(child.b.diag_status, 'disabled')\n\n  child.api.nvim_set_current_buf(buf_id_two)\n  eq(child.b.diag_status, vim.NIL)\n  eq(toggle_diagnostic(), 'nodiagnostic')\n  eq(child.b.diag_status, 'disabled')\n\n  child.api.nvim_set_current_buf(buf_id_one)\n  eq(child.b.diag_status, 'disabled')\n  eq(toggle_diagnostic(), '  diagnostic')\n  eq(child.b.diag_status, 'enabled')\n\n  child.api.nvim_set_current_buf(buf_id_two)\n  eq(child.b.diag_status, 'disabled')\n  eq(toggle_diagnostic(), '  diagnostic')\n  eq(child.b.diag_status, 'enabled')\nend\n\nT['toggle_diagnostic()']['works if initially disabled'] = function()\n  load_module()\n  local buf_id = child.api.nvim_get_current_buf()\n\n  local disable, is_disabled\n  if child.fn.has('nvim-0.10') == 1 then\n    disable = function() child.diagnostic.enable(false, { bufnr = buf_id }) end\n    is_disabled = function() return not child.diagnostic.is_enabled({ bufnr = buf_id }) end\n  else\n    disable = function() child.diagnostic.disable(buf_id) end\n    is_disabled = function() return child.diagnostic.is_disabled(buf_id) end\n  end\n\n  disable()\n  eq(is_disabled(), true)\n  toggle_diagnostic()\n  eq(is_disabled(), false)\n  toggle_diagnostic()\n  eq(is_disabled(), true)\nend\n\n-- Integration tests ==========================================================\nT['Options'] = new_set()\n\nT['Options']['work'] = function()\n  -- Basic options (should be set by default)\n  eq(child.g.mapleader, vim.NIL)\n  eq(child.o.number, false)\n  eq(child.o.signcolumn, 'auto')\n  eq(child.o.fillchars, '')\n\n  -- Extra options (should not be set by default)\n  eq(child.o.pumblend, 0)\n\n  load_module()\n\n  eq(child.g.mapleader, ' ')\n  eq(child.o.number, true)\n  eq(child.o.signcolumn, 'yes')\n  eq(child.o.fillchars, 'eob: ')\n\n  eq(child.o.pumblend, 0)\nend\n\nT['Options']['do not override manually set options'] = function()\n  -- Shouldn't modify options manually set to non-default value\n  child.g.mapleader = ';'\n  child.cmd('set signcolumn=no')\n  child.cmd('set pumblend=50')\n\n  -- Shouldn't modify option manually set to default value\n  child.cmd('set nonumber')\n  child.cmd('set nolist')\n\n  load_module({ options = { basic = true, extra_ui = true } })\n\n  eq(child.g.mapleader, ';')\n  eq(child.o.signcolumn, 'no')\n  eq(child.o.pumblend, 50)\n  eq(child.o.number, false)\n  eq(child.o.list, false)\nend\n\nT['Options']['respect `config.options.basic`'] = function()\n  eq(child.g.mapleader, vim.NIL)\n  local tgc = child.o.termguicolors\n  eq(child.o.number, false)\n  eq(child.o.signcolumn, 'auto')\n\n  load_module({ options = { basic = false } })\n\n  eq(child.g.mapleader, vim.NIL)\n  eq(child.o.termguicolors, tgc)\n  eq(child.o.number, false)\n  eq(child.o.signcolumn, 'auto')\nend\n\nT['Options']['respect `config.options.extra_ui`'] = function()\n  eq(child.o.pumblend, 0)\n  eq(child.o.list, false)\n\n  load_module({ options = { extra_ui = true } })\n\n  eq(child.o.pumblend, 10)\n  eq(child.o.list, true)\n\n  -- 'listchars' should have `tab` defined to not show `^I` instead of tab\n  expect.match(child.o.listchars, 'tab')\nend\n\nT['Options']['respect `config.options.win_borders`'] = function()\n  local validate = function(opt_value, ref_fillchars)\n    child.o.fillchars = ''\n    load_module({ options = { basic = false, win_borders = opt_value } })\n    eq(child.o.fillchars, ref_fillchars)\n  end\n\n  validate(nil, '')\n  validate('double', 'horiz:═,horizdown:╦,horizup:╩,msgsep:═,vert:║,verthoriz:╬,vertleft:╣,vertright:╠')\n  -- - Should not respect 'winborder' style names directly\n  validate('none', '')\n\n  if child.fn.has('nvim-0.11') == 0 then return end\n\n  -- With default 'auto' should infer from 'winborder' option\n  local validate_winborder = function(winborder_value, ref_fillchars)\n    child.o.winborder = winborder_value\n    validate(nil, ref_fillchars)\n    validate('auto', ref_fillchars)\n  end\n\n  validate_winborder('', '')\n\n  local single_fcs = 'horiz:─,horizdown:┬,horizup:┴,msgsep:─,vert:│,verthoriz:┼,vertleft:┤,vertright:├'\n  validate_winborder('single', single_fcs)\n  validate_winborder('rounded', single_fcs)\n\n  local solid_fcs = 'horiz: ,horizdown: ,horizup: ,msgsep: ,vert: ,verthoriz: ,vertleft: ,vertright: '\n  validate_winborder('solid', solid_fcs)\n  validate_winborder('none', solid_fcs)\n  validate_winborder('shadow', solid_fcs)\n\n  if child.fn.has('nvim-0.12') == 0 then return end\n\n  -- With custom list 'winborder' should do nothing\n  validate_winborder('+,-,+,|,+,-,+,|', '')\nend\n\nT['Mappings'] = new_set()\n\nT['Mappings']['work'] = function()\n  expect.match(child.cmd_capture('nmap go'), 'No mapping')\n\n  load_module()\n\n  expect.match(child.cmd_capture('nmap go'), 'MiniBasics')\nend\n\nT['Mappings']['do not override manually created mappings'] = function()\n  child.api.nvim_set_keymap('n', 'j', 'aaaaa', { noremap = true })\n  child.api.nvim_set_keymap('n', ',s', 'bbbbb', { noremap = true })\n  child.lua([[vim.keymap.set('n', '<C-l>', function() end, { desc = 'Test' })]])\n  child.api.nvim_set_keymap('i', '<M-h>', 'ddddd', { noremap = true })\n\n  load_module({ mappings = { basic = true, option_toggle_prefix = ',', windows = true, move_with_alt = true } })\n\n  expect.match(child.cmd_capture('nmap j'), 'aaaaa')\n  expect.match(child.cmd_capture('nmap ,s'), 'bbbbb')\n  expect.match(child.cmd_capture('nmap <C-l>'), 'Test')\n  expect.match(child.cmd_capture('imap <M-h>'), 'ddddd')\nend\n\nT['Mappings']['ignores buffer-local mappings when deciding whether to create one'] = function()\n  child.api.nvim_buf_set_keymap(0, 'n', 'j', 'aaaaa', { noremap = true })\n  child.api.nvim_buf_set_keymap(0, 'n', ',s', 'bbbbb', { noremap = true })\n  child.api.nvim_buf_set_keymap(0, 'n', '<C-h>', 'ccccc', { noremap = true })\n  child.api.nvim_buf_set_keymap(0, 'i', '<M-h>', 'ddddd', { noremap = true })\n\n  load_module({ mappings = { basic = true, option_toggle_prefix = ',', windows = true, move_with_alt = true } })\n\n  child.api.nvim_buf_del_keymap(0, 'n', 'j')\n  child.api.nvim_buf_del_keymap(0, 'n', ',s')\n  child.api.nvim_buf_del_keymap(0, 'n', '<C-h>')\n  child.api.nvim_buf_del_keymap(0, 'i', '<M-h>')\n\n  expect.match(child.cmd_capture('nmap j'), 'gj')\n  expect.match(child.cmd_capture('nmap ,s'), 'spell')\n  expect.match(child.cmd_capture('nmap <C-h>'), '<C%-W>')\n  expect.match(child.cmd_capture('imap <M-h>'), '<Left>')\nend\n\nT['Mappings']['Basic'] = new_set()\n\nT['Mappings']['Basic']['can be disabled'] = function()\n  expect.match(child.cmd_capture('nmap go'), 'No mapping')\n\n  load_module({ mappings = { basic = false } })\n\n  expect.match(child.cmd_capture('nmap go'), 'No mapping')\nend\n\nT['Mappings']['Basic']['j/k'] = function()\n  local validate = function()\n    -- Goes by visible lines without `[count]`\n    set_cursor(1, 0)\n    type_keys('jj')\n    eq(get_cursor(), { 1, 24 })\n    type_keys('k')\n    eq(get_cursor(), { 1, 12 })\n\n    -- Goes by usual lines with `[count]`\n    set_cursor(1, 0)\n    type_keys('1j')\n    eq(get_cursor(), { 2, 0 })\n    type_keys('1k')\n    eq(get_cursor(), { 1, 0 })\n  end\n\n  load_module()\n\n  child.o.number = false\n  child.o.signcolumn = 'no'\n  child.o.wrap = true\n  child.set_size(10, 12)\n  set_lines({ string.rep('a', 48), 'bbb' })\n\n  -- Normal mode\n  child.ensure_normal_mode()\n  validate()\n\n  -- Visual mode\n  set_cursor(1, 0)\n  type_keys('v')\n  eq(child.fn.mode(), 'v')\n  child.ensure_normal_mode()\nend\n\nT['Mappings']['Basic']['go'] = function()\n  load_module()\n\n  -- Should add empty line(s) below with cursor staying on line\n  set_lines({ 'aaa' })\n  set_cursor(1, 1)\n\n  type_keys('go')\n  eq(get_lines(), { 'aaa', '' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- Should respect `[count]`\n  type_keys('2go')\n  eq(get_lines(), { 'aaa', '', '', '' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- Should work with dot-repeat\n  type_keys('.')\n  eq(get_lines(), { 'aaa', '', '', '', '', '' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- Should allow different `v:count` in dot-repeat\n  type_keys('1.')\n  eq(get_lines(), { 'aaa', '', '', '', '', '', '' })\n  eq(get_cursor(), { 1, 1 })\nend\n\nT['Mappings']['Basic']['gO'] = function()\n  load_module()\n\n  -- Should add empty line(s) above with cursor staying on line\n  set_lines({ 'aaa' })\n  set_cursor(1, 1)\n\n  type_keys('gO')\n  eq(get_lines(), { '', 'aaa' })\n  eq(get_cursor(), { 2, 1 })\n\n  -- Should respect `[count]`\n  type_keys('2gO')\n  eq(get_lines(), { '', '', '', 'aaa' })\n  eq(get_cursor(), { 4, 1 })\n\n  -- Should work with dot-repeat\n  type_keys('.')\n  eq(get_lines(), { '', '', '', '', '', 'aaa' })\n  eq(get_cursor(), { 6, 1 })\n\n  -- Should allow different `v:count` in dot-repeat\n  type_keys('1.')\n  eq(get_lines(), { '', '', '', '', '', '', 'aaa' })\n  eq(get_cursor(), { 7, 1 })\nend\n\nT['Mappings']['Basic']['gy'] = function()\n  load_module()\n  eq(child.fn.maparg('gy', 'n'), '\"+y')\n  eq(child.fn.maparg('gy', 'x'), '\"+y')\nend\n\nT['Mappings']['Basic']['gp'] = function()\n  load_module()\n\n  -- Has problems with CI testing, so test mapping themselves. Should be enough\n  -- as they are quite basic.\n  local created_mappings = {}\n\n  local normal_keymaps = child.api.nvim_get_keymap('n')\n  for _, keymap in ipairs(normal_keymaps) do\n    if keymap.lhs == 'gy' then\n      table.insert(created_mappings, 'n_gy')\n      eq(keymap.rhs, '\"+y')\n    end\n    if keymap.lhs == 'gp' then\n      table.insert(created_mappings, 'n_gp')\n      eq(keymap.rhs, '\"+p')\n    end\n  end\n\n  local visual_keymaps = child.api.nvim_get_keymap('x')\n  for _, keymap in ipairs(visual_keymaps) do\n    if keymap.lhs == 'gy' then\n      table.insert(created_mappings, 'x_gy')\n      eq(keymap.rhs, '\"+y')\n    end\n    if keymap.lhs == 'gp' then\n      table.insert(created_mappings, 'x_gp')\n      -- Should use `P` to not cut visual selection in `\"\"` register\n      eq(keymap.rhs, '\"+P')\n    end\n  end\n\n  table.sort(created_mappings)\n  eq(created_mappings, { 'n_gp', 'n_gy', 'x_gp', 'x_gy' })\nend\n\nT['Mappings']['Basic']['gV'] = function()\n  local validate_cur_selection = function(ref_selection)\n    eq({ { child.fn.line('v'), child.fn.col('v') }, { child.fn.line('.'), child.fn.col('.') } }, ref_selection)\n  end\n  load_module()\n\n  -- Should reselect previously pasted or yanked text\n\n  -- Charwise mode\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_cursor(1, 0)\n  type_keys('yiw')\n  set_cursor(2, 0)\n  type_keys('P')\n\n  -- - Result selection should not depend on latest Visual selection type\n  set_cursor(1, 0)\n  type_keys('V', '<Esc>')\n\n  type_keys('gV')\n  validate_cur_selection({ { 2, 1 }, { 2, 3 } })\n  eq(child.fn.mode(), 'v')\n\n  child.ensure_normal_mode()\n\n  -- Linewise mode\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_cursor(1, 0)\n  type_keys('yy', 'p')\n  -- - Add location to the jumplist\n  type_keys('gg')\n\n  -- - Result selection should not depend on latest Visual selection type\n  set_cursor(1, 0)\n  type_keys('viw', '<Esc>')\n\n  type_keys('gV')\n  validate_cur_selection({ { 2, 1 }, { 2, 3 } })\n  eq(child.fn.mode(), 'V')\n\n  child.ensure_normal_mode()\n\n  -- - Selection should not have overwritten jumplist\n  type_keys('<C-o>')\n  eq(get_cursor(), { 1, 0 })\n\n  -- Blockwise mode\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_cursor(1, 0)\n  type_keys('<C-v>ly')\n  set_cursor(2, 0)\n  type_keys('P')\n\n  -- - Result selection should not depend on latest Visual selection type\n  set_cursor(1, 0)\n  type_keys('viw', '<Esc>')\n\n  type_keys('gV')\n  validate_cur_selection({ { 2, 1 }, { 2, 2 } })\n  eq(child.fn.mode(), '\\22')\nend\n\nT['Mappings']['Basic']['g/'] = function()\n  load_module()\n\n  -- Should search inside visual selection\n  set_lines({ 'abc', 'abc', 'abc' })\n  set_cursor(1, 0)\n  type_keys('Vj', 'g/', 'a<CR>')\n\n  eq(get_cursor(), { 1, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 2, 0 })\n  -- Should not recognize match outside visual selection\n  type_keys('n')\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Mappings']['Basic']['*/#'] = function()\n  load_module()\n\n  -- Should work just like in Normal mode but for visual selection and even\n  -- with bad characters present\n\n  -- *\n  set_lines({ [[aa?/\\bb]], 'aa', [[aa?/\\bb]], 'aa', [[aa?/\\bb]] })\n  set_cursor(1, 0)\n  type_keys('v$ho', '*')\n\n  eq(get_cursor(), { 3, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 5, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 1, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 3, 0 })\n\n  child.cmd('nohlsearch')\n  child.ensure_normal_mode()\n\n  -- #\n  set_lines({ [[aa?/\\bb]], 'aa', [[aa?/\\bb]], 'aa', [[aa?/\\bb]] })\n  set_cursor(1, 0)\n  type_keys('v$ho', '#')\n\n  eq(get_cursor(), { 5, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 3, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 1, 0 })\n  type_keys('n')\n  eq(get_cursor(), { 5, 0 })\nend\n\nT['Mappings']['Basic']['<C-s>'] = function()\n  local test_file_path = 'tests/ctrl-s.txt'\n  MiniTest.finally(function() child.fn.delete(test_file_path) end)\n\n  load_module()\n\n  child.cmd('write ' .. test_file_path)\n\n  -- Should save in Normal mode\n  eq(child.bo.modified, false)\n  set_lines({ 'aaa' })\n  eq(child.bo.modified, true)\n\n  type_keys('<C-s>')\n  eq(child.bo.modified, false)\n  eq(child.fn.mode(), 'n')\n\n  -- Should save in Insert mode and leave in Normal mode\n  eq(child.bo.modified, false)\n  set_lines({ 'aaa' })\n  set_cursor(1, 0)\n  child.cmd('startinsert')\n  eq(child.bo.modified, true)\n  eq(child.fn.mode(), 'i')\n\n  type_keys('<C-s>')\n  eq(child.bo.modified, false)\n  eq(child.fn.mode(), 'n')\n\n  -- Should save in Visual mode and leave in Normal mode\n  eq(child.bo.modified, false)\n  set_lines({ 'aaa' })\n  set_cursor(1, 0)\n  type_keys('v')\n  eq(child.bo.modified, true)\n  eq(child.fn.mode(), 'v')\n\n  type_keys('<C-s>')\n  eq(child.bo.modified, false)\n  eq(child.fn.mode(), 'n')\nend\n\nT['Mappings']['Toggle options'] = new_set()\n\nT['Mappings']['Toggle options']['work'] = function()\n  -- NOTE: these mappings should also give feedback about new option values.\n  -- But there doesn't seem to be a way of testing it without screenshots.\n  -- So later test only for 'spell'.\n  local validate = function(keys, option, before, after)\n    child.o[option] = before\n    type_keys(keys)\n    eq(child.o[option], after)\n    type_keys(keys)\n    eq(child.o[option], before)\n  end\n\n  child.g.mapleader = ' '\n  load_module({ options = { basic = false } })\n\n  validate([[\\b]], 'background', 'dark', 'light')\n  validate([[\\c]], 'cursorline', false, true)\n  validate([[\\C]], 'cursorcolumn', false, true)\n  -- \\d should toggle diagnostic\n  -- \\h should almost toggle 'hlsearch'\n  validate([[\\i]], 'ignorecase', false, true)\n  validate([[\\l]], 'list', false, true)\n  validate([[\\n]], 'number', false, true)\n  validate([[\\r]], 'relativenumber', false, true)\n  validate([[\\s]], 'spell', false, true)\n  validate([[\\w]], 'wrap', true, false)\nend\n\nT['Mappings']['Toggle options']['shows feedback about new value'] = function()\n  child.set_size(10, 20)\n  load_module()\n  type_keys([[\\s]])\n  child.expect_screenshot()\nend\n\nT['Mappings']['Toggle options']['works with diagnostic'] = function()\n  if child.fn.has('nvim-0.10') == 1 then\n    child.lua('vim.diagnostic.enable = function(enable) vim.b.diag_status = enable and \"enabled\" or \"disabled\" end')\n    child.lua('vim.diagnostic.is_enabled = function(enable) return vim.b.diag_status ~= \"disabled\" end')\n  else\n    child.lua('vim.diagnostic.enable = function() vim.b.diag_status = \"enabled\" end')\n    child.lua('vim.diagnostic.disable = function() vim.b.diag_status = \"disabled\" end')\n    child.lua('vim.diagnostic.is_disabled = function() return vim.b.diag_status == \"disabled\" end')\n  end\n\n  load_module()\n\n  -- Should disable on per-buffer basis\n  local buf_id_one = child.api.nvim_get_current_buf()\n  local buf_id_two = child.api.nvim_create_buf(true, false)\n\n  child.api.nvim_set_current_buf(buf_id_one)\n  eq(child.b.diag_status, vim.NIL)\n  type_keys([[\\d]])\n  eq(child.b.diag_status, 'disabled')\n\n  child.api.nvim_set_current_buf(buf_id_two)\n  eq(child.b.diag_status, vim.NIL)\n  type_keys([[\\d]])\n  eq(child.b.diag_status, 'disabled')\n\n  child.api.nvim_set_current_buf(buf_id_one)\n  eq(child.b.diag_status, 'disabled')\n  type_keys([[\\d]])\n  eq(child.b.diag_status, 'enabled')\n\n  child.api.nvim_set_current_buf(buf_id_two)\n  eq(child.b.diag_status, 'disabled')\n  type_keys([[\\d]])\n  eq(child.b.diag_status, 'enabled')\nend\n\nT['Mappings']['Toggle options'][\"does not disables 'hlsearch' directly\"] = function()\n  load_module()\n\n  set_lines({ 'abc', 'abc' })\n\n  eq(child.o.hlsearch, true)\n  type_keys('/', 'a', '<CR>')\n  eq(child.o.hlsearch, true)\n  type_keys([[\\h]])\n  eq(child.o.hlsearch, true)\n  eq(child.v.hlsearch, 0)\n\n  -- Typing `n` should still show matches\n  type_keys('n')\n  eq(child.o.hlsearch, true)\n  eq(child.v.hlsearch, 1)\nend\n\nT['Mappings']['Toggle options']['can be disabled'] = function()\n  expect.match(child.cmd_capture([[nmap \\w]]), 'No mapping')\n\n  load_module({ mappings = { option_toggle_prefix = '' } })\n\n  expect.match(child.cmd_capture([[nmap \\w]]), 'No mapping')\nend\n\nT['Mappings']['Toggle options']['can work with `<Leader>`'] = function()\n  vim.g.mapleader = ' '\n  load_module({ mappings = { option_toggle_prefix = '<Leader>t' } })\n\n  expect.match(child.cmd_capture([[nmap <Space>tw]]), 'wrap')\nend\n\nT['Mappings']['Toggle options']['respects `config.silent`'] = function()\n  child.set_size(10, 20)\n\n  load_module({ silent = true })\n  type_keys([[\\s]])\n  child.expect_screenshot()\nend\n\nT['Mappings']['Windows'] = new_set()\n\nT['Mappings']['Windows']['work for common navigation'] = function()\n  local validate_cur_win = function(x) eq(child.api.nvim_get_current_win(), x) end\n\n  load_module({ options = { basic = false }, mappings = { windows = true } })\n\n  child.cmd('wincmd v | wincmd s | wincmd s')\n\n  validate_cur_win(1003)\n  type_keys('<C-l>')\n  validate_cur_win(1000)\n  type_keys('<C-h>')\n  validate_cur_win(1003)\n  type_keys('<C-j>')\n  validate_cur_win(1002)\n  type_keys('<C-k>')\n  validate_cur_win(1003)\n\n  -- Works with `[count]`\n  type_keys('2<C-j>')\n  validate_cur_win(1001)\nend\n\nT['Mappings']['Windows']['work for resizing'] = function()\n  local validate = function(dims) eq({ child.fn.winheight(0), child.fn.winwidth(0) }, dims) end\n\n  load_module({ options = { basic = false }, mappings = { windows = true } })\n\n  child.cmd('wincmd v | wincmd s')\n\n  -- Should change correct dimension and respect `[count]`\n  local start_height, start_width = child.fn.winheight(0), child.fn.winwidth(0)\n\n  type_keys('<C-left>')\n  validate({ start_height, start_width - 1 })\n  type_keys('2<C-left>')\n  validate({ start_height, start_width - 3 })\n\n  type_keys('<C-right>')\n  validate({ start_height, start_width - 2 })\n  type_keys('2<C-right>')\n  validate({ start_height, start_width })\n\n  type_keys('<C-down>')\n  validate({ start_height - 1, start_width })\n  type_keys('2<C-down>')\n  validate({ start_height - 3, start_width })\n\n  type_keys('<C-up>')\n  validate({ start_height - 2, start_width })\n  type_keys('2<C-up>')\n  validate({ start_height, start_width })\nend\n\nT['Mappings']['Move with alt'] = new_set()\n\nT['Mappings']['Move with alt']['works in Insert mode'] = function()\n  load_module({ mappings = { move_with_alt = true } })\n\n  set_lines({ 'aaa', 'bbb' })\n  set_cursor(1, 1)\n  type_keys('a')\n\n  eq(get_cursor(), { 1, 2 })\n  type_keys('<M-h>')\n  eq(get_cursor(), { 1, 1 })\n  type_keys('<M-l>')\n  eq(get_cursor(), { 1, 2 })\n  type_keys('<M-j>')\n  eq(get_cursor(), { 2, 2 })\n  type_keys('<M-k>')\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['Mappings']['Move with alt']['works in Terminal mode'] = function()\n  load_module({ mappings = { move_with_alt = true } })\n\n  -- Too unstable to actually verify in Terminal mode\n  expect.match(child.cmd_capture('tmap <M-h>'), '<Left>')\n  expect.match(child.cmd_capture('tmap <M-j>'), '<Down>')\n  expect.match(child.cmd_capture('tmap <M-k>'), '<Up>')\n  expect.match(child.cmd_capture('tmap <M-l>'), '<Right>')\nend\n\nT['Mappings']['Move with alt']['works in Insert mode'] = function()\n  load_module({ mappings = { move_with_alt = true } })\n\n  type_keys(':hello')\n\n  eq(child.fn.getcmdpos(), 6)\n  type_keys('<M-h>')\n  eq(child.fn.getcmdpos(), 5)\n  type_keys('<M-l>')\n  eq(child.fn.getcmdpos(), 6)\nend\n\nT['Autocommands'] = new_set()\n\nT['Autocommands']['work'] = function()\n  child.lua([[\n    local on_yank = function() _G.been_here = true end\n    local module = vim.fn.has('nvim-0.11') == 1 and vim.hl or vim.highlight\n    module.on_yank = on_yank\n  ]])\n  load_module()\n\n  -- Highlight on yank\n  set_lines({ 'aaa' })\n  type_keys('yiw')\n  eq(child.lua_get('_G.been_here'), true)\n\n  -- Start terminal in Insert mode\n  child.cmd('terminal')\n  eq(child.fn.mode(), 't')\nend\n\nT['Autocommands']['starts Terminal mode only in proper terminals'] = function()\n  load_module()\n  child.api.nvim_open_term(0, {})\n  eq(child.fn.mode(), 'n')\nend\n\nT['Autocommands']['start Terminal mode only if target terminal is current'] = function()\n  load_module()\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n  child.lua([[vim.api.nvim_buf_call(vim.api.nvim_create_buf(true, false), function() vim.cmd('terminal') end)]])\n\n  eq(child.api.nvim_get_current_buf(), init_buf_id)\n  eq(child.fn.mode(), 'n')\nend\n\nT['Autocommands']['can be disabled'] = function()\n  load_module({ autocommands = { basic = false } })\n  child.cmd('terminal')\n  eq(child.fn.mode(), 'n')\nend\n\nT['Autocommands']['respects `config.autocommands.relnum_in_visual_mode`'] = function()\n  eq(child.o.relativenumber, false)\n  type_keys('V')\n  eq(child.o.relativenumber, false)\n  type_keys('<C-v>')\n  eq(child.o.relativenumber, false)\n  type_keys('<Esc>')\n  eq(child.o.relativenumber, false)\n\n  load_module({ autocommands = { relnum_in_visual_mode = true } })\n\n  eq(child.o.relativenumber, false)\n  type_keys('V')\n  eq(child.o.relativenumber, true)\n  type_keys('<C-v>')\n  eq(child.o.relativenumber, true)\n  type_keys('<Esc>')\n  eq(child.o.relativenumber, false)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_bracketed.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\nlocal path_sep = package.config:sub(1, 1)\nlocal project_root = vim.fn.fnamemodify(vim.fn.getcwd(), ':p')\nlocal dir_bracketed_path = project_root .. 'tests' .. path_sep .. 'dir-bracketed'\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('bracketed', config) end\nlocal unload_module = function() child.mini_unload('bracketed') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal make_path = function(...) return table.concat({...}, path_sep):gsub(path_sep .. path_sep, path_sep) end\nlocal make_testpath = function(...) return make_path(dir_bracketed_path, ...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\nlocal edit_test_file = function(rel_path) child.cmd('edit ' .. make_testpath(rel_path)) end\nlocal get_bufname = function(buf_id) return child.api.nvim_buf_get_name(buf_id or 0) end\nlocal validate_test_file = function(rel_path) eq(get_bufname(), make_testpath(rel_path)) end\n\n-- Helper wrappers for iteration directions\nlocal forward = function(target, ...)\n  local command = string.format('MiniBracketed.%s(\"forward\", ...)', target)\n  child.lua(command, { ... })\nend\n\nlocal backward = function(target, ...)\n  local command = string.format('MiniBracketed.%s(\"backward\", ...)', target)\n  child.lua(command, { ... })\nend\n\nlocal first = function(target, ...)\n  local command = string.format('MiniBracketed.%s(\"first\", ...)', target)\n  child.lua(command, { ... })\nend\n\nlocal last = function(target, ...)\n  local command = string.format('MiniBracketed.%s(\"last\", ...)', target)\n  child.lua(command, { ... })\nend\n\n-- Validators for common test cases\nlocal validate_works = function(validate, n_items)\n  -- Forward\n  for i = 1, n_items do\n    -- Increase by one wrapping around edge\n    validate(i, 'forward', i % n_items + 1)\n  end\n\n  -- Backward\n  for i = n_items, 1, -1 do\n    -- Decrease by one wrapping around edge\n    validate(i, 'backward', (i - 2) % n_items + 1)\n  end\n\n  -- First\n  for i = 1, n_items do\n    -- Always go to first item\n    validate(i, 'first', 1)\n  end\n\n  -- Last\n  for i = 1, n_items do\n    -- Always go to last item\n    validate(i, 'last', n_items)\n  end\nend\n\nlocal validate_n_times = function(validate, n_items)\n  -- Forward\n  for i = 1, n_items do\n    -- Increase by two wrapping around edge\n    validate(i, 'forward', (i + 1) % n_items + 1, { n_times = 2 })\n  end\n\n  -- Backward\n  for i = n_items, 1, -1 do\n    -- Decrease by two wrapping around edge\n    validate(i, 'backward', (i - 3) % n_items + 1, { n_times = 2 })\n  end\n\n  -- First\n  for i = 1, n_items do\n    -- Always go to second item\n    validate(i, 'first', 2, { n_times = 2 })\n  end\n\n  -- Last\n  for i = 1, n_items do\n    -- Always go to second to last item\n    validate(i, 'last', n_items - 1, { n_times = 2 })\n  end\nend\n\nlocal validate_wrap = function(validate, n_items)\n  -- Forward\n  validate(n_items, 'forward', n_items, { wrap = false })\n  validate(n_items - 1, 'forward', n_items, { n_times = 1000, wrap = false })\n\n  -- Backward\n  validate(1, 'backward', 1, { wrap = false })\n  validate(2, 'backward', 1, { n_times = 1000, wrap = false })\n\n  -- First\n  validate(1, 'first', n_items, { n_times = 1000, wrap = false })\n  validate(n_items, 'first', n_items, { n_times = 1000, wrap = false })\n\n  -- Last\n  validate(n_items, 'last', 1, { n_times = 1000, wrap = false })\n  validate(1, 'last', 1, { n_times = 1000, wrap = false })\nend\n\n-- More general validators\nlocal validate_edit = function(lines_before, cursor_before, keys, lines_after, cursor_after)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n  child.ensure_normal_mode()\nend\n\nlocal validate_move = function(cursor_before, keys, cursor_after)\n  child.ensure_normal_mode()\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_cursor(), cursor_after)\n  child.ensure_normal_mode()\nend\n\n-- Data =======================================================================\nlocal test_files = { 'file-a', 'file-b', 'file-c', 'file-d', 'file-e' }\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniBracketed)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniBracketed'), 1)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniBracketed.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniBracketed.config.' .. field), value) end\n\n  expect_config('buffer.suffix', 'b')\n  expect_config('buffer.options', {})\n\n  expect_config('comment.suffix', 'c')\n  expect_config('comment.options', {})\n\n  expect_config('conflict.suffix', 'x')\n  expect_config('conflict.options', {})\n\n  expect_config('diagnostic.suffix', 'd')\n  expect_config('diagnostic.options', {})\n\n  expect_config('file.suffix', 'f')\n  expect_config('file.options', {})\n\n  expect_config('indent.suffix', 'i')\n  expect_config('indent.options', {})\n\n  expect_config('jump.suffix', 'j')\n  expect_config('jump.options', {})\n\n  expect_config('location.suffix', 'l')\n  expect_config('location.options', {})\n\n  expect_config('oldfile.suffix', 'o')\n  expect_config('oldfile.options', {})\n\n  expect_config('quickfix.suffix', 'q')\n  expect_config('quickfix.options', {})\n\n  expect_config('undo.suffix', 'u')\n  expect_config('undo.options', {})\n\n  expect_config('window.suffix', 'w')\n  expect_config('window.options', {})\n\n  expect_config('yank.suffix', 'y')\n  expect_config('yank.options', {})\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ buffer = { suffix = '' } })\n  eq(child.lua_get('MiniBracketed.config.buffer.suffix'), '')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n\n  expect_config_error({ buffer = 'a' }, 'buffer', 'table')\n  expect_config_error({ buffer = { suffix = 1 } }, 'buffer.suffix', 'string')\n  expect_config_error({ buffer = { options = 'a' } }, 'buffer.options', 'table')\n\n  expect_config_error({ comment = 'a' }, 'comment', 'table')\n  expect_config_error({ comment = { suffix = 1 } }, 'comment.suffix', 'string')\n  expect_config_error({ comment = { options = 'a' } }, 'comment.options', 'table')\n\n  expect_config_error({ conflict = 'a' }, 'conflict', 'table')\n  expect_config_error({ conflict = { suffix = 1 } }, 'conflict.suffix', 'string')\n  expect_config_error({ conflict = { options = 'a' } }, 'conflict.options', 'table')\n\n  expect_config_error({ diagnostic = 'a' }, 'diagnostic', 'table')\n  expect_config_error({ diagnostic = { suffix = 1 } }, 'diagnostic.suffix', 'string')\n  expect_config_error({ diagnostic = { options = 'a' } }, 'diagnostic.options', 'table')\n\n  expect_config_error({ file = 'a' }, 'file', 'table')\n  expect_config_error({ file = { suffix = 1 } }, 'file.suffix', 'string')\n  expect_config_error({ file = { options = 'a' } }, 'file.options', 'table')\n\n  expect_config_error({ indent = 'a' }, 'indent', 'table')\n  expect_config_error({ indent = { suffix = 1 } }, 'indent.suffix', 'string')\n  expect_config_error({ indent = { options = 'a' } }, 'indent.options', 'table')\n\n  expect_config_error({ jump = 'a' }, 'jump', 'table')\n  expect_config_error({ jump = { suffix = 1 } }, 'jump.suffix', 'string')\n  expect_config_error({ jump = { options = 'a' } }, 'jump.options', 'table')\n\n  expect_config_error({ location = 'a' }, 'location', 'table')\n  expect_config_error({ location = { suffix = 1 } }, 'location.suffix', 'string')\n  expect_config_error({ location = { options = 'a' } }, 'location.options', 'table')\n\n  expect_config_error({ oldfile = 'a' }, 'oldfile', 'table')\n  expect_config_error({ oldfile = { suffix = 1 } }, 'oldfile.suffix', 'string')\n  expect_config_error({ oldfile = { options = 'a' } }, 'oldfile.options', 'table')\n\n  expect_config_error({ quickfix = 'a' }, 'quickfix', 'table')\n  expect_config_error({ quickfix = { suffix = 1 } }, 'quickfix.suffix', 'string')\n  expect_config_error({ quickfix = { options = 'a' } }, 'quickfix.options', 'table')\n\n  expect_config_error({ undo = 'a' }, 'undo', 'table')\n  expect_config_error({ undo = { suffix = 1 } }, 'undo.suffix', 'string')\n  expect_config_error({ undo = { options = 'a' } }, 'undo.options', 'table')\n\n  expect_config_error({ window = 'a' }, 'window', 'table')\n  expect_config_error({ window = { suffix = 1 } }, 'window.suffix', 'string')\n  expect_config_error({ window = { options = 'a' } }, 'window.options', 'table')\n\n  expect_config_error({ yank = 'a' }, 'yank', 'table')\n  expect_config_error({ yank = { suffix = 1 } }, 'yank.suffix', 'string')\n  expect_config_error({ yank = { options = 'a' } }, 'yank.options', 'table')\nend\n\nT['setup()']['properly creates mappings'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('nmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('[B', 'first'), true)\n  eq(has_map('[b', 'backward'), true)\n  eq(has_map(']b', 'forward'), true)\n  eq(has_map(']B', 'last'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('n', '[B')\n  child.api.nvim_del_keymap('n', '[b')\n  child.api.nvim_del_keymap('n', ']b')\n  child.api.nvim_del_keymap('n', ']B')\n\n  -- Supplying empty string as suffix should mean \"don't create keymaps\"\n  load_module({ buffer = { suffix = '' } })\n  eq(has_map('[B', 'first'), false)\n  eq(has_map('[b', 'backward'), false)\n  eq(has_map(']b', 'forward'), false)\n  eq(has_map(']B', 'last'), false)\nend\n\nT['buffer()'] = new_set()\n\nlocal get_buf = function() return child.api.nvim_get_current_buf() end\nlocal set_buf = function(x) return child.api.nvim_set_current_buf(x) end\n\nlocal setup_buffers = function()\n  local init_buf = child.api.nvim_get_current_buf()\n\n  local buf_1 = child.api.nvim_create_buf(true, false)\n\n  -- Test when target buffers are not consecutive\n  child.api.nvim_create_buf(false, false)\n\n  local buf_2 = child.api.nvim_create_buf(true, false)\n  local buf_3 = child.api.nvim_create_buf(true, false)\n\n  -- Should work even in not \"normal\" buffers\n  local buf_4 = child.api.nvim_create_buf(true, false)\n  child.bo[buf_4].buftype = 'help'\n\n  local buf_5 = child.api.nvim_create_buf(true, false)\n\n  -- Test if initial buffer is not 1\n  child.cmd('bwipeout ' .. init_buf)\n\n  local buf_list = { buf_1, buf_2, buf_3, buf_4, buf_5 }\n  local validate = function(id_start, direction, id_ref, opts)\n    set_buf(buf_list[id_start])\n    child.lua('MiniBracketed.buffer(...)', { direction, opts })\n    eq(get_buf(), buf_list[id_ref])\n  end\n\n  return buf_list, validate\nend\n\nT['buffer()']['works'] = function()\n  local buf_list, validate = setup_buffers()\n  validate_works(validate, #buf_list)\nend\n\nT['buffer()']['works when started in not listed buffer'] = function()\n  local buf_list = setup_buffers()\n  local buf_nolisted = child.api.nvim_create_buf(false, true)\n\n  -- Forward\n  set_buf(buf_nolisted)\n  forward('buffer')\n  eq(get_buf(), buf_list[1])\n\n  -- Backward\n  set_buf(buf_nolisted)\n  backward('buffer')\n  eq(get_buf(), buf_list[#buf_list])\nend\n\nT['buffer()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.buffer(1)') end, 'buffer%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.buffer('next')]]) end, 'buffer%(%).*direction.*one of')\nend\n\nT['buffer()']['adds to jumplist'] = function()\n  setup_buffers()\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n  child.lua([[MiniBracketed.buffer('forward')]])\n  eq(child.api.nvim_get_current_buf() == init_buf_id, false)\n\n  type_keys('<C-o>')\n  eq(child.api.nvim_get_current_buf() == init_buf_id, true)\nend\n\nT['buffer()']['respects `opts.n_times`'] = function()\n  local buf_list, validate = setup_buffers()\n  validate_n_times(validate, #buf_list)\nend\n\nT['buffer()']['respects `opts.wrap`'] = function()\n  local buf_list, validate = setup_buffers()\n  validate_wrap(validate, #buf_list)\nend\n\nT['buffer()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local buf_list = setup_buffers()\n    set_buf(buf_list[1])\n\n    child[var_type].minibracketed_disable = true\n    forward('buffer')\n    eq(get_buf(), buf_list[1])\n  end,\n})\n\nT['buffer()']['respects `vim.b.minibracketed_config`'] = function()\n  local buf_list = setup_buffers()\n  set_buf(buf_list[1])\n\n  child.b.minibracketed_config = { buffer = { options = { wrap = false } } }\n  backward('buffer')\n  eq(get_buf(), buf_list[1])\nend\n\nT['comment()'] = new_set()\n\nlocal validate_comment = function(line_start, direction, line_ref, opts)\n  set_cursor(line_start, 0)\n  child.lua('MiniBracketed.comment(...)', { direction, opts })\n  eq(get_cursor(), { line_ref, 0 })\nend\n\nT['comment()']['works'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '3', '## 4', '5', '## 6', '7', '## 8', '9', '## 10', '11' }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward\n  line_ref = { 2, 4, 4, 6, 6, 8, 8, 10, 10, 2, 2 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i])\n  end\n\n  -- Backward\n  line_ref = { 10, 10, 2, 2, 4, 4, 6, 6, 8, 8, 10 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i])\n  end\n\n  -- First\n  line_ref = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }\n  for i = 1, #lines do\n    validate_comment(i, 'first', line_ref[i])\n  end\n\n  -- Last\n  line_ref = { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }\n  for i = 1, #lines do\n    validate_comment(i, 'last', line_ref[i])\n  end\nend\n\nT['comment()']['works on first/last lines comments'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '## 1', '2', '## 3', '4', '## 5' }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward\n  line_ref = { 3, 3, 5, 5, 1 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i])\n  end\n\n  -- Backward\n  line_ref = { 5, 1, 1, 3, 3 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i])\n  end\n\n  -- First\n  line_ref = { 1, 1, 1, 1, 1 }\n  for i = 1, #lines do\n    validate_comment(i, 'first', line_ref[i])\n  end\n\n  -- Last\n  line_ref = { 5, 5, 5, 5, 5 }\n  for i = 1, #lines do\n    validate_comment(i, 'last', line_ref[i])\n  end\nend\n\nT['comment()']['works with one comment or less'] = function()\n  child.o.commentstring = '## %s'\n  local lines\n\n  -- One comment\n  lines = { '1', '## 2', '3' }\n  set_lines(lines)\n\n  for i = 1, #lines do\n    validate_comment(i, 'forward', 2)\n    validate_comment(i, 'backward', 2)\n    validate_comment(i, 'first', 2)\n    validate_comment(i, 'last', 2)\n  end\n\n  -- No comments. Should not move cursor at all\n  set_lines({ '11', '22' })\n\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    set_cursor(1, 1)\n    dir('comment')\n    eq(get_cursor(), { 1, 1 })\n  end\nend\n\nT['comment()']['works when jumping to current line'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '3', '## 4', '5' }\n  set_lines(lines)\n\n  local validate = function(cursor, direction, opts)\n    set_cursor(cursor[1], cursor[2])\n    child.lua('MiniBracketed.comment(...)', { direction, opts })\n    -- Should not move cursor at all\n    eq(get_cursor(), cursor)\n  end\n\n  validate({ 2, 1 }, 'forward', { n_times = 2 })\n  validate({ 2, 1 }, 'backward', { n_times = 2 })\n  validate({ 2, 1 }, 'first', { n_times = 3 })\n  validate({ 2, 1 }, 'last', { n_times = 2 })\nend\n\nT['comment()']['opens just enough folds'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '## 3', '4', '## 5', '## 6', '7' }\n  set_lines(lines)\n  set_cursor(1, 0)\n\n  child.cmd('2,3 fold')\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n  child.cmd('5,6 fold')\n  eq({ child.fn.foldclosed(5), child.fn.foldclosed(6) }, { 5, 5 })\n\n  forward('comment')\n  eq(get_cursor(), { 2, 0 })\n\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { -1, -1 })\n  eq({ child.fn.foldclosed(5), child.fn.foldclosed(6) }, { 5, 5 })\nend\n\nT['comment()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.comment(1)') end, 'comment%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.comment('next')]]) end, 'comment%(%).*direction.*one of')\nend\n\nT['comment()']['respects `opts.add_to_jumplist`'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '222', '3', '## 4' }\n  set_lines(lines)\n  set_cursor(2, 2)\n\n  child.lua([[MiniBracketed.comment('forward', { add_to_jumplist = true })]])\n  eq(get_cursor(), { 4, 0 })\n\n  type_keys('<C-o>')\n  eq(get_cursor(), { 2, 2 })\nend\n\nT['comment()']['respects `opts.block_side`'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '## 3', '## 4', '5', '6', '7', '## 8', '## 9', '## 10', '11' }\n  set_lines(lines)\n  local line_ref\n\n  -- Default ('near')\n  line_ref = { 2, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i])\n    validate_comment(i, 'forward', line_ref[i], { block_side = 'near' })\n  end\n\n  line_ref = { 10, 10, 10, 10, 4, 4, 4, 4, 4, 4, 10 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i])\n    validate_comment(i, 'backward', line_ref[i], { block_side = 'near' })\n  end\n\n  -- Start\n  line_ref = { 2, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i], { block_side = 'start' })\n  end\n\n  line_ref = { 8, 8, 2, 2, 2, 2, 2, 2, 8, 8, 8 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i], { block_side = 'start' })\n  end\n\n  -- End\n  line_ref = { 4, 4, 4, 10, 10, 10, 10, 10, 10, 4, 4 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i], { block_side = 'end' })\n  end\n\n  line_ref = { 10, 10, 10, 10, 4, 4, 4, 4, 4, 4, 10 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i], { block_side = 'end' })\n  end\n\n  -- Both\n  line_ref = { 2, 4, 4, 8, 8, 8, 8, 10, 10, 2, 2 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i], { block_side = 'both' })\n  end\n\n  line_ref = { 10, 10, 2, 2, 4, 4, 4, 4, 8, 8, 10 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i], { block_side = 'both' })\n  end\nend\n\nT['comment()']['respects `opts.n_times`'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '3', '## 4', '5', '## 6', '7', '## 8', '9' }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward\n  line_ref = { 4, 6, 6, 8, 8, 2, 2, 4, 4 }\n  for i = 1, #lines do\n    validate_comment(i, 'forward', line_ref[i], { n_times = 2 })\n  end\n\n  -- Backward\n  line_ref = { 6, 6, 8, 8, 2, 2, 4, 4, 6 }\n  for i = 1, #lines do\n    validate_comment(i, 'backward', line_ref[i], { n_times = 2 })\n  end\n\n  -- First\n  line_ref = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }\n  for i = 1, #lines do\n    validate_comment(i, 'first', line_ref[i], { n_times = 2 })\n  end\n\n  -- Last\n  line_ref = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }\n  for i = 1, #lines do\n    validate_comment(i, 'last', line_ref[i], { n_times = 2 })\n  end\nend\n\nT['comment()']['respects `opts.wrap`'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '3', '## 4', '5', '## 6', '7', '## 8', '9' }\n  set_lines(lines)\n\n  -- Forward\n  validate_comment(9, 'forward', 9, { wrap = false })\n  validate_comment(8, 'forward', 8, { wrap = false })\n  validate_comment(7, 'forward', 8, { n_times = 1000, wrap = false })\n\n  -- Backward\n  validate_comment(1, 'backward', 1, { wrap = false })\n  validate_comment(2, 'backward', 2, { wrap = false })\n  validate_comment(3, 'backward', 2, { n_times = 1000, wrap = false })\n\n  -- First\n  validate_comment(1, 'first', 8, { n_times = 1000, wrap = false })\n  validate_comment(2, 'first', 8, { n_times = 1000, wrap = false })\n  validate_comment(8, 'first', 8, { n_times = 1000, wrap = false })\n  validate_comment(9, 'first', 8, { n_times = 1000, wrap = false })\n\n  -- Backward\n  validate_comment(1, 'last', 2, { n_times = 1000, wrap = false })\n  validate_comment(2, 'last', 2, { n_times = 1000, wrap = false })\n  validate_comment(8, 'last', 2, { n_times = 1000, wrap = false })\n  validate_comment(9, 'last', 2, { n_times = 1000, wrap = false })\nend\n\nT['comment()']['correctly identifies comment'] = function()\n  -- -- Uses 'commentstring'\n  child.o.commentstring = '## %s //'\n  set_lines({ '1', '## 2', '## 3 //', '4 //' })\n  validate_comment(1, 'forward', 3)\n\n  -- Handles empty comment line\n  child.o.commentstring = '## %s //'\n  set_lines({ '1', '##//', '3', '## //' })\n  validate_comment(1, 'forward', 2)\n  validate_comment(2, 'forward', 4)\n\n  -- Trims whitespace form comment parts\n  child.o.commentstring = '## %s'\n  set_lines({ '1', '##2' })\n  validate_comment(1, 'forward', 2)\n\n  -- Escapes special characters in comment parts\n  child.o.commentstring = '%. %s'\n  set_lines({ '1', '%. 2' })\n  validate_comment(1, 'forward', 2)\nend\n\nT['comment()']['works for indented comments'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '  ## 2', '    ## 3', '    4', '    ## 5', '  ## 6', '7' }\n  set_lines(lines)\n\n  local validate = function(cur_start, direction, cur_ref, opts)\n    set_cursor(cur_start[1], cur_start[2])\n    child.lua('MiniBracketed.comment(...)', { direction, opts })\n    eq(get_cursor(), cur_ref)\n  end\n\n  -- Should put cursor on first non-whitespace character\n  validate({ 1, 0 }, 'forward', { 2, 2 })\n  validate({ 2, 5 }, 'forward', { 5, 4 })\n\n  validate({ 7, 0 }, 'backward', { 6, 2 })\n  validate({ 6, 5 }, 'backward', { 3, 4 })\nend\n\nT['comment()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child.o.commentstring = '## %s'\n    set_lines({ '1', '# 2' })\n    set_cursor(1, 0)\n\n    child[var_type].minibracketed_disable = true\n    forward('comment')\n    eq(get_cursor(), { 1, 0 })\n  end,\n})\n\nT['comment()']['respects `vim.b.minibracketed_config`'] = function()\n  child.o.commentstring = '## %s'\n  set_lines({ '1', '# 2', '3', '# 4', '5' })\n\n  child.b.minibracketed_config = { comment = { options = { wrap = false } } }\n  validate_comment(4, 'forward', 4)\nend\n\nT['conflict()'] = new_set()\n\nlocal validate_conflict = function(line_start, direction, line_ref, opts)\n  set_cursor(line_start, 0)\n  child.lua('MiniBracketed.conflict(...)', { direction, opts })\n  eq(get_cursor(), { line_ref, 0 })\nend\n\nlocal conflict_marks = { '<<<<<<< ', '=======', '>>>>>>> ' }\n\nT['conflict()']['works'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], m[2], m[3], '5', m[3], m[2], m[1], '9' }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward\n  line_ref = { 2, 3, 4, 6, 6, 7, 8, 2, 2 }\n  for i = 1, #lines do\n    validate_conflict(i, 'forward', line_ref[i])\n  end\n\n  -- Backward\n  line_ref = { 8, 8, 2, 3, 4, 4, 6, 7, 8 }\n  for i = 1, #lines do\n    validate_conflict(i, 'backward', line_ref[i])\n  end\n\n  -- First\n  line_ref = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }\n  for i = 1, #lines do\n    validate_conflict(i, 'first', line_ref[i])\n  end\n\n  -- Last\n  line_ref = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }\n  for i = 1, #lines do\n    validate_conflict(i, 'last', line_ref[i])\n  end\nend\n\nT['conflict()']['works on first/last lines conflicts'] = function()\n  local m = conflict_marks\n  local lines = { m[1], m[2], m[3] }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward\n  line_ref = { 2, 3, 1 }\n  for i = 1, #lines do\n    validate_conflict(i, 'forward', line_ref[i])\n  end\n\n  -- Backward\n  line_ref = { 3, 1, 2 }\n  for i = 1, #lines do\n    validate_conflict(i, 'backward', line_ref[i])\n  end\n\n  -- First\n  line_ref = { 1, 1, 1 }\n  for i = 1, #lines do\n    validate_conflict(i, 'first', line_ref[i])\n  end\n\n  -- Last\n  line_ref = { 3, 3, 3 }\n  for i = 1, #lines do\n    validate_conflict(i, 'last', line_ref[i])\n  end\nend\n\nT['conflict()']['works with one conflict or less'] = function()\n  local m = conflict_marks\n  local lines\n\n  -- One conflict\n  lines = { '1', m[1], '3' }\n  set_lines(lines)\n\n  for i = 1, #lines do\n    validate_conflict(i, 'forward', 2)\n    validate_conflict(i, 'backward', 2)\n    validate_conflict(i, 'first', 2)\n    validate_conflict(i, 'last', 2)\n  end\n\n  -- No conflicts. Should not move cursor at all\n  set_lines({ '11', '22' })\n\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    set_cursor(1, 1)\n    dir('conflict')\n    eq(get_cursor(), { 1, 1 })\n  end\nend\n\nT['conflict()']['works when jumping to current line'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], '3', m[2], '5' }\n  set_lines(lines)\n\n  local validate = function(cursor, direction, opts)\n    set_cursor(cursor[1], cursor[2])\n    child.lua('MiniBracketed.conflict(...)', { direction, opts })\n    -- Should not move cursor at all\n    eq(get_cursor(), cursor)\n  end\n\n  validate({ 2, 1 }, 'forward', { n_times = 2 })\n  validate({ 2, 1 }, 'backward', { n_times = 2 })\n  validate({ 2, 1 }, 'first', { n_times = 3 })\n  validate({ 2, 1 }, 'last', { n_times = 2 })\nend\n\nT['conflict()']['opens just enough folds'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], m[2], '4', m[3], m[1], '7' }\n  set_lines(lines)\n  set_cursor(1, 0)\n\n  child.cmd('2,3 fold')\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n  child.cmd('5,6 fold')\n  eq({ child.fn.foldclosed(5), child.fn.foldclosed(6) }, { 5, 5 })\n\n  forward('conflict')\n  eq(get_cursor(), { 2, 0 })\n\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { -1, -1 })\n  eq({ child.fn.foldclosed(5), child.fn.foldclosed(6) }, { 5, 5 })\nend\n\nT['conflict()']['does not recognize similar lines'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], m[2], '<<<', '===', '>>>', '<<<<<<<<', '========', '>>>>>>>>' }\n  set_lines(lines)\n  set_cursor(1, 0)\n\n  validate_conflict(1, 'forward', 2)\n  validate_conflict(2, 'forward', 3)\n  validate_conflict(3, 'forward', 2)\nend\n\nT['conflict()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.conflict(1)') end, 'conflict%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.conflict('next')]]) end, 'conflict%(%).*direction.*one of')\nend\n\nT['conflict()']['respects `opts.add_to_jumplist`'] = function()\n  local m = conflict_marks\n  local lines = { '1', '222', '3', m[1] }\n  set_lines(lines)\n  set_cursor(2, 2)\n\n  child.lua([[MiniBracketed.conflict('forward', { add_to_jumplist = true })]])\n  eq(get_cursor(), { 4, 0 })\n\n  type_keys('<C-o>')\n  eq(get_cursor(), { 2, 2 })\nend\n\nT['conflict()']['respects `opts.n_times`'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], '3', m[2], '5', m[3], '7', m[1], '9' }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward\n  line_ref = { 4, 6, 6, 8, 8, 2, 2, 4, 4 }\n  for i = 1, #lines do\n    validate_conflict(i, 'forward', line_ref[i], { n_times = 2 })\n  end\n\n  -- Backward\n  line_ref = { 6, 6, 8, 8, 2, 2, 4, 4, 6 }\n  for i = 1, #lines do\n    validate_conflict(i, 'backward', line_ref[i], { n_times = 2 })\n  end\n\n  -- First\n  line_ref = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }\n  for i = 1, #lines do\n    validate_conflict(i, 'first', line_ref[i], { n_times = 2 })\n  end\n\n  -- Last\n  line_ref = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }\n  for i = 1, #lines do\n    validate_conflict(i, 'last', line_ref[i], { n_times = 2 })\n  end\nend\n\nT['conflict()']['respects `opts.wrap`'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], '3', m[2], '5', m[3], '7', m[1], '9' }\n  set_lines(lines)\n\n  -- Forward\n  validate_conflict(9, 'forward', 9, { wrap = false })\n  validate_conflict(8, 'forward', 8, { wrap = false })\n  validate_conflict(7, 'forward', 8, { n_times = 1000, wrap = false })\n\n  -- Backward\n  validate_conflict(1, 'backward', 1, { wrap = false })\n  validate_conflict(2, 'backward', 2, { wrap = false })\n  validate_conflict(3, 'backward', 2, { n_times = 1000, wrap = false })\n\n  -- First\n  validate_conflict(1, 'first', 8, { n_times = 1000, wrap = false })\n  validate_conflict(2, 'first', 8, { n_times = 1000, wrap = false })\n  validate_conflict(8, 'first', 8, { n_times = 1000, wrap = false })\n  validate_conflict(9, 'first', 8, { n_times = 1000, wrap = false })\n\n  -- Backward\n  validate_conflict(1, 'last', 2, { n_times = 1000, wrap = false })\n  validate_conflict(2, 'last', 2, { n_times = 1000, wrap = false })\n  validate_conflict(8, 'last', 2, { n_times = 1000, wrap = false })\n  validate_conflict(9, 'last', 2, { n_times = 1000, wrap = false })\nend\n\nT['conflict()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    set_lines({ '1', conflict_marks[1] })\n    set_cursor(1, 0)\n\n    child[var_type].minibracketed_disable = true\n    forward('conflict')\n    eq(get_cursor(), { 1, 0 })\n  end,\n})\n\nT['conflict()']['respects `vim.b.minibracketed_config`'] = function()\n  local m = conflict_marks\n  set_lines({ '1', m[1], '3', m[2], '5' })\n\n  child.b.minibracketed_config = { conflict = { options = { wrap = false } } }\n  validate_conflict(4, 'forward', 4)\nend\n\nT['diagnostic()'] = new_set()\n\nlocal diagnostic = function(direction, opts)\n  opts = opts or {}\n  -- Force traversing of all diagnostics. It is needed on Neovim>=0.10.\n  opts.severity = opts.severity or { min = child.lua_get('vim.diagnostic.severity.HINT') }\n  return child.lua_get('MiniBracketed.diagnostic(...)', { direction, opts })\nend\n\nlocal setup_diagnostic = function()\n  local mock_data = dofile(make_testpath('mock/diagnostic.lua'))\n  set_lines(mock_data.lines)\n\n  local ns = child.api.nvim_create_namespace('mock-diagnostics')\n\n  child.diagnostic.set(ns, 0, mock_data.diagnostic_arr, {})\n\n  local cursor_position_tbl = mock_data.cursor_positions\n  local validate = function(pos_before, direction, pos_after, opts)\n    set_cursor(unpack(pos_before))\n    diagnostic(direction, opts)\n    eq(get_cursor(), pos_after)\n  end\n\n  return cursor_position_tbl, validate\nend\n\nT['diagnostic()']['works'] = function()\n  local cur_pos_tbl, validate = setup_diagnostic()\n  local all = cur_pos_tbl.all\n  local n = #all\n\n  -- Jumping from diagnostic itself\n  for i = 1, n do\n    validate(all[i], 'forward', all[i % n + 1])\n    validate(all[i], 'backward', all[(i - 2) % n + 1])\n    validate(all[i], 'first', all[1])\n    validate(all[i], 'last', all[n])\n  end\n\n  -- Jumping near diagnostic\n  local second_pos = all[2]\n  validate({ second_pos[1], second_pos[2] - 1 }, 'forward', all[2])\n  validate({ second_pos[1], second_pos[2] - 1 }, 'backward', all[1])\nend\n\nT['diagnostic()']['works on first/last diagnostic'] = function()\n  set_lines('E   E')\n\n  local sev_err = vim.diagnostic.severity.ERROR\n  local diagnostic_arr = {\n    { lnum = 0, end_lnum = 0, col = 0, end_col = 1, message = 'Error 1', severity = sev_err },\n    { lnum = 0, end_lnum = 0, col = 4, end_col = 5, message = 'Error 2', severity = sev_err },\n  }\n  local ns = child.api.nvim_create_namespace('mock-edge-diagnostics')\n  child.diagnostic.set(ns, 0, diagnostic_arr, {})\n\n  local positions = { { 1, 0 }, { 1, 4 } }\n\n  local validate = function(pos_before, direction, pos_after, opts)\n    set_cursor(unpack(pos_before))\n    diagnostic(direction, opts)\n    eq(get_cursor(), pos_after)\n  end\n\n  validate({ 1, 2 }, 'forward', positions[2])\n  validate({ 1, 2 }, 'forward', positions[1], { n_times = 2 })\n\n  validate({ 1, 2 }, 'backward', positions[1])\n  validate({ 1, 2 }, 'backward', positions[2], { n_times = 2 })\n\n  validate({ 1, 2 }, 'first', positions[1])\n  validate({ 1, 2 }, 'first', positions[2], { n_times = 2 })\n\n  validate({ 1, 2 }, 'last', positions[2])\n  validate({ 1, 2 }, 'last', positions[1], { n_times = 2 })\nend\n\nT['diagnostic()']['works with one diagnostic or less'] = function()\n  -- No diagnostic. Should not move cursor.\n  set_lines({ 'aaa', 'Error', 'aaa' })\n\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    set_cursor(1, 2)\n    dir('diagnostic')\n    eq(get_cursor(), { 1, 2 })\n  end\n\n  -- One diagnostic\n  local sev_err = vim.diagnostic.severity.ERROR\n  local diagnostic_arr = {\n    { lnum = 1, end_lnum = 1, col = 0, end_col = 5, message = 'Error 1', severity = sev_err },\n  }\n  local ns = child.api.nvim_create_namespace('mock-single-diagnostics')\n  child.diagnostic.set(ns, 0, diagnostic_arr, {})\n\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    set_cursor(1, 2)\n    dir('diagnostic')\n    eq(get_cursor(), { 2, 0 })\n  end\nend\n\nT['diagnostic()']['opens just enough folds'] = function()\n  local cur_pos_tbl = setup_diagnostic()\n  local all = cur_pos_tbl.all\n\n  set_cursor(3, 0)\n  child.cmd('1,2 fold')\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  child.cmd('5,6 fold')\n  eq({ child.fn.foldclosed(5), child.fn.foldclosed(6) }, { 5, 5 })\n\n  last('diagnostic')\n  eq(get_cursor(), all[#all])\n\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  eq({ child.fn.foldclosed(5), child.fn.foldclosed(6) }, { -1, -1 })\nend\n\nT['diagnostic()']['opens floating window'] = function()\n  local cur_pos_tbl = setup_diagnostic()\n  local all = cur_pos_tbl.all\n\n  -- From not diagnostic position and not showing floating window\n  set_cursor(1, 2)\n  diagnostic('forward')\n  eq(get_cursor(), all[2])\n\n  -- -- Actual testing of floating window fails for some unimagniable reason.\n  -- -- But everything seems to work fine in real life\n  -- local windows = child.api.nvim_list_wins()\n  -- eq(#windows, 2)\n\n  -- From diagnostic position and showing floating window\n  diagnostic('forward')\n  eq(get_cursor(), all[3])\n\n  -- -- Again, can't test, but seems to works fine.\n  -- local windows = child.api.nvim_list_wins()\n  -- eq(#windows, 2)\nend\n\nT['diagnostic()']['validates `direction`'] = function()\n  expect.error(function() diagnostic(1) end, 'diagnostic%(%).*direction.*one of')\n  expect.error(function() diagnostic('next') end, 'diagnostic%(%).*direction.*one of')\nend\n\nT['diagnostic()']['adds to jumplist'] = function()\n  local cur_pos_tbl, _ = setup_diagnostic()\n  local all = cur_pos_tbl.all\n\n  set_cursor(all[2][1], all[2][2])\n  diagnostic('forward', { n_times = 4 })\n\n  eq(get_cursor(), all[6])\n\n  type_keys('<C-o>')\n  eq(get_cursor(), all[2])\nend\n\nT['diagnostic()']['respects `opts.float`'] = function()\n  -- As actual testing of floating window fails for some unimagniable reason,\n  -- there is no way at the moment to test this. Would be **great** otherwise.\nend\n\nT['diagnostic()']['respects `opts.n_times`'] = function()\n  local cur_pos_tbl, _ = setup_diagnostic()\n  local all = cur_pos_tbl.all\n\n  local validate = function(id_before, direction, id_ref, opts)\n    set_cursor(unpack(all[id_before]))\n    diagnostic(direction, opts)\n    eq(get_cursor(), all[id_ref])\n  end\n\n  validate_n_times(validate, #all)\nend\n\nlocal severity_tbl = vim.diagnostic.severity\n\nT['diagnostic()']['respects `opts.severity`'] = new_set({\n  parametrize = {\n    { 'error', severity_tbl.ERROR },\n    { 'warning', severity_tbl.WARN },\n    { 'info', severity_tbl.INFO },\n    { 'hint', severity_tbl.HINT },\n    { 'error_warning', { min = severity_tbl.WARN } },\n  },\n}, {\n  test = function(position_key, severity)\n    local cur_pos_tbl, _ = setup_diagnostic()\n    local positions = cur_pos_tbl[position_key]\n\n    local validate = function(id_before, direction, id_ref)\n      set_cursor(unpack(positions[id_before]))\n      diagnostic(direction, { severity = severity })\n      eq(get_cursor(), positions[id_ref])\n    end\n\n    validate_works(validate, #positions)\n  end,\n})\n\nT['diagnostic()']['respects `opts.wrap`'] = function()\n  local cur_pos_tbl, _ = setup_diagnostic()\n  local all = cur_pos_tbl.all\n\n  local validate = function(id_before, direction, id_ref, opts)\n    set_cursor(unpack(all[id_before]))\n    diagnostic(direction, opts)\n    eq(get_cursor(), all[id_ref])\n  end\n\n  validate_wrap(validate, #all)\nend\n\nT['diagnostic()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    setup_diagnostic()\n    set_cursor(2, 0)\n\n    child[var_type].minibracketed_disable = true\n    forward('diagnostic')\n    eq(get_cursor(), { 2, 0 })\n  end,\n})\n\nT['diagnostic()']['respects `vim.b.minibracketed_config`'] = function()\n  setup_diagnostic()\n  set_cursor(1, 0)\n\n  child.b.minibracketed_config = { diagnostic = { options = { wrap = false } } }\n  backward('diagnostic')\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['file()'] = new_set()\n\nlocal validate_file = function(id_start, direction, id_ref, opts)\n  edit_test_file(test_files[id_start])\n  child.lua('MiniBracketed.file(...)', { direction, opts })\n  validate_test_file(test_files[id_ref])\nend\n\nT['file()']['works'] = function()\n  eq(child.fn.getcwd() .. path_sep, project_root)\n\n  -- Should traverse files alphabetically in directory of currently opened file\n  validate_works(validate_file, #test_files)\nend\n\nT['file()']['opens path in relative form'] = function()\n  edit_test_file('file-a')\n  child.lua('MiniBracketed.file(\"forward\")')\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]tests/dir%-bracketed/file%-b')\nend\n\nT['file()']['reuses buffer if file is already opened'] = function()\n  edit_test_file('file-a')\n  local buf_a = child.api.nvim_get_current_buf()\n  edit_test_file('file-b')\n  eq(#child.api.nvim_list_bufs(), 2)\n\n  backward('file')\n  validate_test_file('file-a')\n  eq(child.api.nvim_get_current_buf(), buf_a)\nend\n\nT['file()']['works with non-file current buffer'] = function()\n  -- Should select first (for 'forward') or last (for 'backward') file in\n  -- current working directory\n  child.fn.chdir(dir_bracketed_path)\n\n  local setup_nonfile_buf = function() child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false)) end\n\n  setup_nonfile_buf()\n  forward('file')\n  validate_test_file('file-a')\n\n  setup_nonfile_buf()\n  backward('file')\n  validate_test_file('file-e')\nend\n\nT['file()']['does not traverses subdirectories'] = function()\n  edit_test_file('file-a')\n  validate_test_file('file-a')\n\n  for _, f in ipairs({ 'file-b', 'file-c', 'file-d', 'file-e', 'file-a' }) do\n    forward('file')\n    validate_test_file(f)\n  end\nend\n\nT['file()']['works for empty directory'] = function()\n  local empty_dir_path = make_testpath('dir-empty')\n  child.fn.mkdir(empty_dir_path, 'p')\n  MiniTest.finally(function() child.fn.delete(empty_dir_path, 'rf') end)\n\n  child.fn.chdir(empty_dir_path)\n\n  local buf_id = child.api.nvim_get_current_buf()\n  eq(child.api.nvim_buf_get_name(buf_id), '')\n\n  forward('file')\n  eq(child.api.nvim_get_current_buf(), buf_id)\n  eq(child.api.nvim_buf_get_name(buf_id), '')\nend\n\nT['file()']['works when jumping to current file'] = function()\n  local n = #test_files\n\n  edit_test_file('file-a')\n  set_lines('This is unsaved change making buffer modified.')\n  eq(child.bo.modified, true)\n\n  -- Should not call `:edit`, as it causes flicker\n  forward('file', { n_times = n })\n  validate_test_file('file-a')\n  -- If it called `:edit`, there would be an error message\n  eq(child.cmd_capture('1messages'), '')\nend\n\nT['file()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.file(1)') end, 'file%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.file('next')]]) end, 'file%(%).*direction.*one of')\nend\n\nT['file()']['adds to jumplist'] = function()\n  edit_test_file(test_files[1])\n  local init_file = child.api.nvim_buf_get_name(0)\n\n  child.lua([[MiniBracketed.file('forward')]])\n  eq(get_bufname() == init_file, false)\n\n  type_keys('<C-o>')\n  eq(get_bufname() == init_file, true)\nend\n\nT['file()']['respects `opts.n_times`'] = function() validate_n_times(validate_file, #test_files) end\n\nT['file()']['respects `opts.wrap`'] = function() validate_wrap(validate_file, #test_files) end\n\nT['file()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    edit_test_file('file-a')\n\n    child[var_type].minibracketed_disable = true\n    forward('file')\n    validate_test_file('file-a')\n  end,\n})\n\nT['file()']['respects `vim.b.minibracketed_config`'] = function()\n  edit_test_file('file-a')\n\n  child.b.minibracketed_config = { file = { options = { wrap = false } } }\n  backward('file')\n  validate_test_file('file-a')\nend\n\nT['indent()'] = new_set()\n\nlocal validate_indent = function(line_start, direction, line_ref, opts)\n  local col_start = math.max(child.fn.getline(line_start):len() - 1, 0)\n  set_cursor(line_start, col_start)\n  child.lua('MiniBracketed.indent(...)', { direction, opts })\n\n  -- Should put cursor on first non-blank character\n  eq(get_cursor(), { line_ref, child.fn.indent(line_ref) })\nend\n\nT['indent()']['works'] = function()\n  local lines = { '1', ' 2', '3', ' 4', '  5', ' 6', '7', ' 8', '9' }\n  set_lines(lines)\n  local line_ref\n\n  -- Forward. By default moves to next line with strictly less indent.\n  line_ref = { 1, 3, 3, 7, 6, 7, 7, 9, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'forward', line_ref[i])\n  end\n\n  -- Backward. By default moves to previous line with strictly less indent.\n  line_ref = { 1, 1, 3, 3, 4, 3, 7, 7, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'backward', line_ref[i])\n  end\n\n  -- First. By default moves to a nearest line above with the smallest indent.\n  line_ref = { 1, 1, 3, 3, 3, 3, 7, 7, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'first', line_ref[i])\n  end\n\n  -- Last. By default moves to a nearest line below with the smallest indent.\n  line_ref = { 1, 3, 3, 7, 7, 7, 7, 9, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'last', line_ref[i])\n  end\nend\n\nT['indent()']['works with minimum indent more than 1'] = function()\n  set_lines({ ' 1', ' 2', '  3', '4' })\n  validate_indent(3, 'first', 2)\n\n  set_lines({ '1', '  2', ' 3', ' 4' })\n  validate_indent(2, 'last', 3)\nend\n\nT['indent()']['ignores blank/empty lines'] = function()\n  local lines = { '1', ' 2', '', ' ', '  5', ' ', '', ' 8', '9' }\n  set_lines(lines)\n\n  validate_indent(5, 'forward', 8)\n  validate_indent(5, 'backward', 2)\n  validate_indent(5, 'first', 1)\n  validate_indent(5, 'last', 9)\nend\n\nT['indent()']['works when no jump target found'] = function()\n  local lines = { '11', ' 22', '33', ' 44', '55' }\n  set_lines(lines)\n\n  local validate = function(cursor, direction, opts)\n    set_cursor(cursor[1], cursor[2])\n    child.lua('MiniBracketed.indent(...)', { direction, opts })\n    -- Should not move cursor at all\n    eq(get_cursor(), cursor)\n  end\n\n  validate({ 3, 1 }, 'forward')\n  validate({ 3, 1 }, 'backward')\n  validate({ 3, 1 }, 'first')\n  validate({ 3, 1 }, 'last')\n\n  validate({ 2, 2 }, 'forward', { change_type = 'more' })\n  validate({ 2, 2 }, 'backward', { change_type = 'more' })\n  validate({ 2, 2 }, 'first', { change_type = 'more' })\n  validate({ 2, 2 }, 'last', { change_type = 'more' })\n\n  validate({ 5, 1 }, 'forward', { change_type = 'diff' })\n  validate({ 1, 1 }, 'backward', { change_type = 'diff' })\n  validate({ 1, 1 }, 'first', { change_type = 'diff' })\n  validate({ 5, 1 }, 'last', { change_type = 'diff' })\nend\n\nT['indent()']['opens just enough folds'] = function()\n  local lines = { '1', ' 2', '3', '4', ' 5', '6', '7' }\n  set_lines(lines)\n  set_cursor(2, 0)\n\n  child.cmd('3,4 fold')\n  eq({ child.fn.foldclosed(3), child.fn.foldclosed(4) }, { 3, 3 })\n  child.cmd('6,7 fold')\n  eq({ child.fn.foldclosed(6), child.fn.foldclosed(7) }, { 6, 6 })\n\n  forward('indent')\n  eq(get_cursor(), { 3, 0 })\n\n  eq({ child.fn.foldclosed(3), child.fn.foldclosed(4) }, { -1, -1 })\n  eq({ child.fn.foldclosed(6), child.fn.foldclosed(7) }, { 6, 6 })\nend\n\nT['indent()']['works in edge cases'] = function()\n  -- All lines are empty/blank\n  set_lines({ '', ' ', '  ', '', '\\t\\t' })\n\n  local validate = function(cursor, direction, opts)\n    set_cursor(cursor[1], cursor[2])\n    child.lua('MiniBracketed.indent(...)', { direction, opts })\n    -- Should not move cursor at all\n    eq(get_cursor(), cursor)\n  end\n\n  validate({ 3, 1 }, 'forward')\n  validate({ 3, 1 }, 'backward')\n  validate({ 3, 1 }, 'first')\n  validate({ 3, 1 }, 'last')\nend\n\nT['indent()']['works when starting in empty/blank line'] = new_set({ parametrize = { { '' }, { ' ' } } }, {\n  test = function(init_line)\n    -- Should take indent from line in a search direction\n    set_lines({ ' 1', init_line, '   3', '  2', '5' })\n    validate_indent(3, 'forward', 4)\n\n    set_lines({ '1', '  2', '   3', init_line, ' 5' })\n    validate_indent(3, 'backward', 2)\n\n    set_lines({ '1', ' 2', init_line, ' 4', '5' })\n    validate_indent(3, 'first', 1)\n    validate_indent(3, 'last', 5)\n  end,\n})\n\nT['indent()']['does not depend on cursor position when computing indent'] = function()\n  local validate = function(pos_start, direction, pos_ref, opts)\n    set_cursor(pos_start[1], pos_start[2])\n    child.lua('MiniBracketed.indent(...)', { direction, opts })\n    eq(get_cursor(), pos_ref)\n  end\n\n  set_lines({ '1', ' 2', '  3', ' 4', '5' })\n\n  for col = 0, 2 do\n    validate({ 3, col }, 'forward', { 4, 1 })\n    validate({ 3, col }, 'backward', { 2, 1 })\n    validate({ 3, col }, 'first', { 1, 0 })\n    validate({ 3, col }, 'last', { 5, 0 })\n  end\nend\n\nT['indent()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.indent(1)') end, 'indent%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.indent('next')]]) end, 'indent%(%).*direction.*one of')\nend\n\nT['indent()']['respects `opts.add_to_jumplist`'] = function()\n  local lines = { '  1', '  2', '3' }\n  set_lines(lines)\n  set_cursor(1, 2)\n\n  child.lua([[MiniBracketed.indent('forward', { add_to_jumplist = true })]])\n  eq(get_cursor(), { 3, 0 })\n\n  type_keys('<C-o>')\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['indent()']['respects `opts.change_type`'] = function()\n  local lines, line_ref\n\n  -- 'more'\n  lines = { '1', ' 2', '3', ' 4', '  5', ' 6', '7', ' 8', '9' }\n  set_lines(lines)\n\n  -- - Forward\n  line_ref = { 2, 5, 4, 5, 5, 6, 8, 8, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'forward', line_ref[i], { change_type = 'more' })\n  end\n\n  -- - Backward\n  line_ref = { 1, 2, 2, 4, 5, 5, 6, 5, 8 }\n  for i = 1, #lines do\n    validate_indent(i, 'backward', line_ref[i], { change_type = 'more' })\n  end\n\n  -- - First (nearest biggest indent above)\n  line_ref = { 1, 2, 2, 4, 5, 5, 5, 5, 5 }\n  for i = 1, #lines do\n    validate_indent(i, 'first', line_ref[i], { change_type = 'more' })\n  end\n\n  -- - Last (nearest biggest indent below)\n  line_ref = { 5, 5, 5, 5, 5, 6, 8, 8, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'last', line_ref[i], { change_type = 'more' })\n  end\n\n  -- 'diff'\n  lines = { '1', '2', '3', ' 4', ' 5', ' 6', '  7', '8', '9' }\n  set_lines(lines)\n\n  -- - Forward\n  line_ref = { 4, 4, 4, 7, 7, 7, 8, 8, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'forward', line_ref[i], { change_type = 'diff' })\n  end\n\n  -- - Backward\n  line_ref = { 1, 2, 3, 3, 3, 3, 6, 7, 7 }\n  for i = 1, #lines do\n    validate_indent(i, 'backward', line_ref[i], { change_type = 'diff' })\n  end\n\n  -- - First (last change above)\n  line_ref = { 1, 2, 3, 3, 3, 3, 3, 3, 3 }\n  for i = 1, #lines do\n    validate_indent(i, 'first', line_ref[i], { change_type = 'diff' })\n  end\n\n  -- - Last (last change below)\n  line_ref = { 8, 8, 8, 8, 8, 8, 8, 8, 9 }\n  for i = 1, #lines do\n    validate_indent(i, 'last', line_ref[i], { change_type = 'diff' })\n  end\nend\n\nT['indent()']['respects `opts.n_times`'] = function()\n  set_lines({ '1', '2', ' 3', '  4', ' 5', '6', '7' })\n\n  -- Change type 'less' (default)\n  validate_indent(4, 'forward', 6, { n_times = 2 })\n  validate_indent(4, 'backward', 2, { n_times = 2 })\n  -- - Ideally, it should be 3 and 5 (as if counting from first forward and\n  --   last backward), but it would mean worse performance, because first and\n  --   last indents should have been precomputed.\n  validate_indent(4, 'first', 2, { n_times = 2 })\n  validate_indent(4, 'last', 6, { n_times = 2 })\n\n  -- Change type 'more'\n  validate_indent(2, 'forward', 4, { change_type = 'more', n_times = 2 })\n  validate_indent(6, 'backward', 4, { change_type = 'more', n_times = 2 })\n  -- - Again, should have been 5 and 3\n  validate_indent(6, 'first', 4, { change_type = 'more', n_times = 2 })\n  validate_indent(2, 'last', 4, { change_type = 'more', n_times = 2 })\n\n  -- Change type 'diff'\n  validate_indent(3, 'forward', 5, { change_type = 'diff', n_times = 2 })\n  validate_indent(5, 'backward', 3, { change_type = 'diff', n_times = 2 })\n  -- - Again, should have been 3 and 5\n  validate_indent(6, 'first', 2, { change_type = 'diff', n_times = 2 })\n  validate_indent(2, 'last', 6, { change_type = 'diff', n_times = 2 })\n\n  -- Allows \"early stop\" with very big `n_times`\n  validate_indent(4, 'forward', 6, { n_times = 100 })\n  validate_indent(4, 'backward', 2, { n_times = 100 })\n  validate_indent(4, 'first', 2, { n_times = 100 })\n  validate_indent(4, 'last', 6, { n_times = 100 })\nend\n\nT['indent()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    set_lines({ '1', ' 2', '3' })\n    set_cursor(2, 1)\n\n    child[var_type].minibracketed_disable = true\n    forward('indent')\n    eq(get_cursor(), { 2, 1 })\n  end,\n})\n\nT['indent()']['respects `vim.b.minibracketed_config`'] = function()\n  set_lines({ ' 1', '  2', '3' })\n  set_cursor(1, 1)\n\n  child.b.minibracketed_config = { indent = { options = { change_type = 'more' } } }\n  forward('indent')\n  eq(get_cursor(), { 2, 2 })\nend\n\nT['jump()'] = new_set()\n\nlocal get_jump_num = function() return child.fn.getjumplist()[2] + 1 end\nlocal set_jump_num = function(x)\n  local jump_list, cur_jump_num = unpack(child.fn.getjumplist())\n  cur_jump_num = cur_jump_num + 1\n\n  local num_diff = x - cur_jump_num\n  if num_diff == 0 then\n    local jump_entry = jump_list[x]\n    pcall(child.fn.cursor, { jump_entry.lnum, jump_entry.col + 1, jump_entry.coladd })\n  else\n    -- Use builtin mappings to also update current jump entry\n    local key = num_diff > 0 and '<C-i>' or '<C-o>'\n    type_keys(math.abs(num_diff) .. key)\n  end\nend\n\nlocal setup_jumplist = function()\n  -- Set up buffers with text\n  local buf_1 = child.api.nvim_get_current_buf()\n  child.api.nvim_buf_set_lines(buf_1, 0, -1, true, { 'aa', '1aa', 'a2a', 'aa3', 'a4a', '5aa' })\n\n  local buf_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_2, 0, -1, true, { 'aa', '1aa', 'a2a' })\n\n  -- Creat jump list for two buffers\n  child.cmd('clearjumps')\n  child.fn.setreg('/', [[\\d\\+]])\n  -- - Start with last wanted jump location. It will be added as first jumplist\n  --   entry. At the end, put cursor on it again, move back in jumplist in\n  --   order to add it to end of jump list (thus removing from first entry).\n  set_cursor(6, 0)\n  type_keys('n', 'n', 'n')\n\n  child.api.nvim_set_current_buf(buf_2)\n  type_keys('n')\n\n  child.api.nvim_set_current_buf(buf_1)\n  type_keys('n')\n\n  child.api.nvim_set_current_buf(buf_2)\n  type_keys('n')\n\n  child.api.nvim_set_current_buf(buf_1)\n  type_keys('n')\n\n  -- - Add current cursor position to the end of jumplist\n  eq(get_cursor(), { 6, 0 })\n  type_keys('<C-o>')\n  type_keys('<C-i>')\n\n  -- Create separate reference jumplist indexes for two buffers\n  local jump_list = child.fn.getjumplist()[1]\n  local buffer_jump_numbers = {}\n  for i, entry in ipairs(jump_list) do\n    if entry.bufnr == buf_1 then table.insert(buffer_jump_numbers, i) end\n  end\n\n  -- Should jump only inside current buffer. This is checked with by using jump\n  -- numbers referring only to current buffer.\n  local validate = function(id_start, direction, id_ref, opts)\n    local s, e = buffer_jump_numbers[id_start], buffer_jump_numbers[id_ref]\n\n    set_jump_num(s)\n    child.lua('MiniBracketed.jump(...)', { direction, opts })\n    eq(get_jump_num(), e)\n    eq(get_cursor(), { jump_list[e].lnum, jump_list[e].col })\n  end\n\n  return buffer_jump_numbers, validate, jump_list\nend\n\nT['jump()']['works'] = function()\n  local cur_jump_inds, validate = setup_jumplist()\n  validate_works(validate, #cur_jump_inds)\nend\n\nT['jump()']['works in a buffers without jumplist entries'] = function()\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n  local validate = function(direction, opts)\n    local cur_pos = get_cursor()\n    child.lua('MiniBracketed.jump(...)', { direction, opts })\n    eq(get_cursor(), cur_pos)\n  end\n\n  validate('first', { n_times = 1 })\n  validate('first', { n_times = 2 })\n  validate('backward', { n_times = 1 })\n  validate('backward', { n_times = 2 })\n  validate('forward', { n_times = 1 })\n  validate('forward', { n_times = 2 })\n  validate('last', { n_times = 1 })\n  validate('last', { n_times = 2 })\nend\n\nT['jump()']['works when currently moved after latest jump'] = function()\n  local cur_jump_inds, _, jump_list = setup_jumplist()\n  local n = #cur_jump_inds\n\n  set_cursor(1, 0)\n  last('jump')\n  eq(get_jump_num(), cur_jump_inds[n])\n  local last_entry = jump_list[cur_jump_inds[n]]\n  eq(get_cursor(), { last_entry.lnum, last_entry.col })\nend\n\nT['jump()']['works when current jump number is outside of jumplist'] = function()\n  local cur_jump_inds, _, jump_list = setup_jumplist()\n  local n = #cur_jump_inds\n\n  -- This should increase current jump number by one but not affect jumplist\n  -- yet (empty line with `>` when execute `:jumps`). After next jump or\n  -- `<C-o>`/`<C-i>` current position will be added to the end. Because it is\n  -- not yet in jumplist, the rest of jumplist should not be affected.\n  -- See `:h jumplist`.\n  type_keys('gg')\n  backward('jump')\n  eq(get_jump_num(), cur_jump_inds[n])\n  local last_entry = jump_list[cur_jump_inds[n]]\n  eq(get_cursor(), { last_entry.lnum, last_entry.col })\nend\n\nT['jump()']['can jump to current entry'] = function()\n  local cur_jump_inds, _, jump_list = setup_jumplist()\n  local n = #cur_jump_inds\n\n  set_cursor(1, 0)\n  forward('jump', { n_times = n })\n  eq(get_jump_num(), cur_jump_inds[n])\n  local last_entry = jump_list[cur_jump_inds[n]]\n  eq(get_cursor(), { last_entry.lnum, last_entry.col })\nend\n\nT['jump()']['opens just enough folds'] = function()\n  setup_jumplist()\n\n  child.cmd('1,2 fold')\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  child.cmd('4,5 fold')\n  eq({ child.fn.foldclosed(4), child.fn.foldclosed(5) }, { 4, 4 })\n\n  backward('jump')\n  eq(get_cursor(), { 5, 1 })\n\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  eq({ child.fn.foldclosed(4), child.fn.foldclosed(5) }, { -1, -1 })\nend\n\nT['jump()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.jump(1)') end, 'jump%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.jump('next')]]) end, 'jump%(%).*direction.*one of')\nend\n\n-- No test for adding to jumplist because it is moving along jumplist\n\nT['jump()']['respects `opts.n_times`'] = function()\n  local cur_jump_inds, validate = setup_jumplist()\n  validate_n_times(validate, #cur_jump_inds)\nend\n\nT['jump()']['respects `opts.wrap`'] = function()\n  local cur_jump_inds, validate = setup_jumplist()\n  validate_wrap(validate, #cur_jump_inds)\nend\n\nT['jump()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    setup_jumplist()\n\n    child[var_type].minibracketed_disable = true\n    local cur_pos = get_cursor()\n    backward('jump')\n    eq(get_cursor(), cur_pos)\n  end,\n})\n\nT['jump()']['respects `vim.b.minibracketed_config`'] = function()\n  setup_jumplist()\n\n  child.b.minibracketed_config = { jump = { options = { wrap = false } } }\n  local cur_pos = get_cursor()\n  forward('jump')\n  eq(get_cursor(), cur_pos)\nend\n\nT['location()'] = new_set()\n\nlocal get_location = function() return child.fn.getloclist(0, { idx = 0 }).idx end\nlocal set_location = function(x) child.cmd('silent ll ' .. x) end\n\nlocal setup_location = function()\n  set_lines({ 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })\n  local buf_id = child.api.nvim_get_current_buf()\n\n  child.fn.setloclist(0, {\n    { bufnr = buf_id, lnum = 1, col = 1 },\n    { bufnr = buf_id, lnum = 2, col = 2 },\n    { bufnr = buf_id, lnum = 3, col = 3 },\n    { bufnr = buf_id, lnum = 4, col = 4 },\n    { bufnr = buf_id, lnum = 5, col = 5 },\n  })\n\n  local loc_list = child.fn.getloclist(0)\n  local validate = function(id_start, direction, id_ref, opts)\n    set_location(id_start)\n    child.lua('MiniBracketed.location(...)', { direction, opts })\n    eq(get_location(), id_ref)\n    eq(get_cursor(), { loc_list[id_ref].lnum, loc_list[id_ref].col - 1 })\n  end\n\n  return loc_list, validate\nend\n\nT['location()']['works'] = function()\n  local loc_list, validate = setup_location()\n  validate_works(validate, #loc_list)\nend\n\nT['location()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.location(1)') end, 'location%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.location('next')]]) end, 'location%(%).*direction.*one of')\nend\n\nT['location()']['adds to jumplist'] = function()\n  setup_location()\n\n  set_location(2)\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local init_cursor = get_cursor()\n  local is_at_init_position = function()\n    return child.api.nvim_get_current_buf() == init_buf_id and vim.deep_equal(get_cursor(), init_cursor)\n  end\n\n  child.lua([[MiniBracketed.location('forward')]])\n  eq(get_location(), 3)\n  eq(is_at_init_position(), false)\n\n  type_keys('<C-o>')\n  eq(is_at_init_position(), true)\nend\n\nT['location()']['respects `opts.n_times`'] = function()\n  local loc_list, validate = setup_location()\n  validate_n_times(validate, #loc_list)\nend\n\nT['location()']['respects `opts.wrap`'] = function()\n  local loc_list, validate = setup_location()\n  validate_wrap(validate, #loc_list)\nend\n\nT['location()']['opens just enough folds and centers window'] = function()\n  local loc_list = setup_location()\n  set_location(3)\n\n  child.set_size(5, 12)\n  set_cursor(1, 0)\n  type_keys('zt')\n\n  eq(child.fn.line('w0'), 1)\n  child.cmd('1,2 fold')\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  child.cmd('4,5 fold')\n  eq({ child.fn.foldclosed(4), child.fn.foldclosed(5) }, { 4, 4 })\n\n  child.cmd([[silent lua MiniBracketed.location('forward')]])\n  eq(get_location(), 4)\n  eq(get_cursor(), { loc_list[4].lnum, loc_list[4].col - 1 })\n\n  eq(child.fn.line('w0'), 3)\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  eq({ child.fn.foldclosed(4), child.fn.foldclosed(5) }, { -1, -1 })\nend\n\nT['location()']['can jump to current entry'] = function()\n  local loc_list = setup_location()\n  set_location(3)\n  set_cursor(1, 0)\n\n  forward('location', { n_times = #loc_list })\n  eq(get_location(), 3)\n  eq(get_cursor(), { loc_list[3].lnum, loc_list[3].col - 1 })\nend\n\nT['location()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    setup_location()\n    set_location(1)\n    local cur_pos = get_cursor()\n\n    child[var_type].minibracketed_disable = true\n    forward('location')\n    eq(get_location(), 1)\n    eq(get_cursor(), cur_pos)\n  end,\n})\n\nT['location()']['respects `vim.b.minibracketed_config`'] = function()\n  setup_location()\n  set_location(1)\n  local cur_pos = get_cursor()\n\n  child.b.minibracketed_config = { location = { options = { wrap = false } } }\n  backward('location')\n  eq(get_location(), 1)\n  eq(get_cursor(), cur_pos)\nend\n\nT['oldfile()'] = new_set()\n\nlocal setup_oldfile = function()\n  local file_arr = { 'file-a', 'file-e', 'file-b', 'file-d', 'file-c' }\n  for _, file in ipairs(file_arr) do\n    edit_test_file(file)\n  end\n  local validate = function(direction, id_ref, opts)\n    child.lua('MiniBracketed.oldfile(...)', { direction, opts })\n    validate_test_file(file_arr[id_ref])\n  end\n  -- Make sure that shada is not written before qutting child process as it\n  -- affects the same shada file that user uses\n  child.o.shadafile = 'NONE'\n  return file_arr, validate\nend\n\nT['oldfile()']['works'] = function()\n  local files, validate = setup_oldfile()\n  local n = #files\n\n  -- Forward\n  for i = 1, n do\n    validate('forward', i)\n  end\n\n  -- Backward\n  for i = n - 1, 1, -1 do\n    validate('backward', i)\n  end\n  validate('backward', n)\n\n  -- First\n  validate('first', 1)\n\n  -- Last\n  validate('last', n)\nend\n\nT['oldfile()']['opens path in relative form'] = function()\n  setup_oldfile()\n  child.cmd('%bwipeout')\n  local n_bufs = #child.api.nvim_list_bufs()\n  child.lua('MiniBracketed.oldfile(\"backward\")')\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]tests/dir%-bracketed/file%-c')\n  -- Should mimic `:h buffer-reuse` similar to how `:edit` does it\n  eq(#child.api.nvim_list_bufs(), n_bufs)\nend\n\nT['oldfile()']['works in not appropriate buffers'] = function()\n  local files = setup_oldfile()\n  local n = #files\n\n  -- When in buffer without name should still go recent buffers\n  local setup_nonfile_buf = function() child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false)) end\n\n  setup_nonfile_buf()\n  backward('oldfile')\n  validate_test_file(files[n])\n\n  setup_nonfile_buf()\n  forward('oldfile')\n  validate_test_file(files[1])\n\n  -- Same with non-normal buffers with name\n  local buf_id_nonnormal = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(buf_id_nonnormal)\n  child.api.nvim_buf_set_name(buf_id_nonnormal, 'tmp')\n  eq(vim.fn.fnamemodify(get_bufname(), ':t'), 'tmp')\n  eq(child.bo.buftype, 'nofile')\n\n  backward('oldfile')\n  validate_test_file(files[n])\n\n  child.api.nvim_set_current_buf(buf_id_nonnormal)\n  forward('oldfile')\n  validate_test_file(files[1])\nend\n\nT['oldfile()']['is initialized with `v:oldfiles`'] = function()\n  -- Enable shada\n  local shada_path = make_testpath('oldfile.shada')\n  MiniTest.finally(function() child.fn.delete(shada_path) end)\n\n  -- Set up `v:oldfiles`\n  setup_oldfile()\n  child.o.shadafile = shada_path\n  child.cmd('wshada! ' .. shada_path)\n\n  child.restart()\n  load_module()\n  child.o.shadafile = shada_path\n  child.cmd('rshada! ' .. shada_path)\n\n  -- Notes:\n  -- - It is ordered from most recent to oldest.\n  -- - It doesn't seem to preserve order from `setup_oldfile()` in this test.\n  local files = {}\n  for _, f in ipairs(child.v.oldfiles) do\n    table.insert(files, 1, f)\n  end\n  local n = #files\n\n  child.cmd('edit ' .. files[n])\n\n  forward('oldfile')\n  eq(get_bufname(), files[1])\n\n  backward('oldfile', { n_times = 2 })\n  eq(get_bufname(), files[n - 1])\n\n  child.o.shadafile = 'NONE'\nend\n\nT['oldfile()']['traverses only readable files'] = function()\n  child.lua([[\n    vim.fn.filereadable = function(path) return vim.endswith(path, 'file-a') and 0 or 1 end\n  ]])\n  setup_oldfile()\n\n  child.cmd('enew')\n\n  child.lua('MiniBracketed.oldfile(\"forward\")')\n  -- Choose next file after the (first) 'file-a' as it is nor readable\n  validate_test_file('file-e')\nend\n\nT['oldfile()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.oldfile(1)') end, 'oldfile%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.oldfile('next')]]) end, 'oldfile%(%).*direction.*one of')\nend\n\nT['oldfile()']['adds to jumplist'] = function()\n  setup_oldfile()\n  local init_file = child.api.nvim_buf_get_name(0)\n\n  child.lua([[MiniBracketed.oldfile('forward')]])\n  eq(get_bufname() == init_file, false)\n\n  type_keys('<C-o>')\n  eq(get_bufname() == init_file, true)\nend\n\nT['oldfile()']['respects `opts.n_times`'] = function()\n  local files, validate = setup_oldfile()\n  local n = #files\n\n  -- Forward\n  validate_test_file(files[n])\n  for i = 1, n do\n    validate('forward', (2 * i - 1) % n + 1, { n_times = 2 })\n  end\n\n  -- Backward\n  validate_test_file(files[n])\n  for i = 1, n do\n    validate('backward', (n - 2 * i - 1) % n + 1, { n_times = 2 })\n  end\n\n  -- First\n  validate('first', 2, { n_times = 2 })\n\n  -- Last\n  validate('last', n - 1, { n_times = 2 })\nend\n\nT['oldfile()']['respects `opts.wrap`'] = function()\n  local files, validate = setup_oldfile()\n  local n = #files\n\n  -- Forward\n  validate_test_file(files[n])\n  validate('forward', n, { wrap = false })\n\n  backward('oldfile')\n  validate_test_file(files[n - 1])\n  validate('forward', n, { n_times = 1000, wrap = false })\n\n  -- Backward\n  first('oldfile')\n  validate_test_file(files[1])\n  validate('backward', 1, { wrap = false })\n\n  forward('oldfile')\n  validate_test_file(files[2])\n  validate('backward', 1, { n_times = 1000, wrap = false })\n\n  -- First\n  first('oldfile')\n  validate_test_file(files[1])\n  validate('first', n, { n_times = 1000, wrap = false })\n\n  last('oldfile')\n  validate_test_file(files[n])\n  validate('first', n, { n_times = 1000, wrap = false })\n\n  -- Last\n  last('oldfile')\n  validate_test_file(files[n])\n  validate('last', 1, { n_times = 1000, wrap = false })\n\n  first('oldfile')\n  validate_test_file(files[1])\n  validate('last', 1, { n_times = 1000, wrap = false })\nend\n\nT['oldfile()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local files = setup_oldfile()\n    local n = #files\n\n    -- `oldfile()` itself shouldn't work\n    child[var_type].minibracketed_disable = true\n    backward('oldfile')\n    validate_test_file(files[n])\n\n    -- Tracking recent files shouldn't work\n    edit_test_file(files[2])\n    edit_test_file(files[n])\n    child[var_type].minibracketed_disable = false\n    backward('oldfile')\n    validate_test_file(files[n - 1])\n  end,\n})\n\nT['oldfile()']['respects `vim.b.minibracketed_config`'] = function()\n  local files = setup_oldfile()\n\n  local cur_bufname = files[#files]\n  child.b.minibracketed_config = { oldfile = { options = { wrap = false } } }\n  forward('oldfile')\n  validate_test_file(cur_bufname)\nend\n\nT['quickfix()'] = new_set()\n\nlocal get_quickfix = function() return child.fn.getqflist({ idx = 0 }).idx end\nlocal set_quickfix = function(x) child.cmd('silent cc ' .. x) end\n\nlocal setup_quickfix = function()\n  set_lines({ 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })\n  local buf_id = child.api.nvim_get_current_buf()\n\n  child.fn.setqflist({\n    { bufnr = buf_id, lnum = 1, col = 1 },\n    { bufnr = buf_id, lnum = 2, col = 2 },\n    { bufnr = buf_id, lnum = 3, col = 3 },\n    { bufnr = buf_id, lnum = 4, col = 4 },\n    { bufnr = buf_id, lnum = 5, col = 5 },\n  })\n\n  local qf_list = child.fn.getqflist()\n  local validate = function(id_start, direction, id_ref, opts)\n    set_quickfix(id_start)\n    child.lua('MiniBracketed.quickfix(...)', { direction, opts })\n    eq(get_quickfix(), id_ref)\n    eq(get_cursor(), { qf_list[id_ref].lnum, qf_list[id_ref].col - 1 })\n  end\n\n  return qf_list, validate\nend\n\nT['quickfix()']['works'] = function()\n  local qf_list, validate = setup_quickfix()\n  validate_works(validate, #qf_list)\nend\n\nT['quickfix()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.quickfix(1)') end, 'quickfix%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.quickfix('next')]]) end, 'quickfix%(%).*direction.*one of')\nend\n\nT['quickfix()']['adds to jumplist'] = function()\n  setup_quickfix()\n\n  set_quickfix(2)\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local init_cursor = get_cursor()\n  local is_at_init_position = function()\n    return child.api.nvim_get_current_buf() == init_buf_id and vim.deep_equal(get_cursor(), init_cursor)\n  end\n\n  child.lua([[MiniBracketed.quickfix('forward')]])\n  eq(get_quickfix(), 3)\n  eq(is_at_init_position(), false)\n\n  type_keys('<C-o>')\n  eq(is_at_init_position(), true)\nend\n\nT['quickfix()']['respects `opts.n_times`'] = function()\n  local qf_list, validate = setup_quickfix()\n  validate_n_times(validate, #qf_list)\nend\n\nT['quickfix()']['respects `opts.wrap`'] = function()\n  local qf_list, validate = setup_quickfix()\n  validate_wrap(validate, #qf_list)\nend\n\nT['quickfix()']['opens just enough folds and centers window'] = function()\n  local qf_list = setup_quickfix()\n  set_quickfix(3)\n\n  child.set_size(5, 12)\n  set_cursor(1, 0)\n  type_keys('zt')\n\n  eq(child.fn.line('w0'), 1)\n  child.cmd('1,2 fold')\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  child.cmd('4,5 fold')\n  eq({ child.fn.foldclosed(4), child.fn.foldclosed(5) }, { 4, 4 })\n\n  child.cmd([[silent lua MiniBracketed.quickfix('forward')]])\n  eq(get_quickfix(), 4)\n  eq(get_cursor(), { qf_list[4].lnum, qf_list[4].col - 1 })\n\n  eq(child.fn.line('w0'), 3)\n  eq({ child.fn.foldclosed(1), child.fn.foldclosed(2) }, { 1, 1 })\n  eq({ child.fn.foldclosed(4), child.fn.foldclosed(5) }, { -1, -1 })\nend\n\nT['quickfix()']['can jump to current entry'] = function()\n  local qf_list = setup_quickfix()\n  set_quickfix(3)\n  set_cursor(1, 0)\n\n  forward('quickfix', { n_times = #qf_list })\n  eq(get_quickfix(), 3)\n  eq(get_cursor(), { qf_list[3].lnum, qf_list[3].col - 1 })\nend\n\nT['quickfix()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    setup_quickfix()\n    set_quickfix(1)\n    local cur_pos = get_cursor()\n\n    child[var_type].minibracketed_disable = true\n    forward('quickfix')\n    eq(get_quickfix(), 1)\n    eq(get_cursor(), cur_pos)\n  end,\n})\n\nT['quickfix()']['respects `vim.b.minibracketed_config`'] = function()\n  setup_quickfix()\n  set_quickfix(1)\n  local cur_pos = get_cursor()\n\n  child.b.minibracketed_config = { quickfix = { options = { wrap = false } } }\n  backward('quickfix')\n  eq(get_quickfix(), 1)\n  eq(get_cursor(), cur_pos)\nend\n\nT['treesitter()'] = new_set()\n\nlocal setup_treesitter = function()\n  -- Make `vim.treesitter.get_node_at_pos()` return mock of tree-sitter node\n  -- based on balanced `{}`\n  child.cmd('source ' .. make_testpath('mock/treesitter.lua'))\n\n  -- Reference:\n  -- { root\n  -- { 1\n  -- { 2\n  -- { 3 { 4 { 5 } 4 } 3 }\n  --   2 }\n  --   1 }\n  --   root }\n  local lines = { '{ root', '{ 1', '{ 2', '{ 3 { 4 { 5 } 4 } 3 }', '  2 }', '  1 }', '  root }' }\n  set_lines(lines)\n\n  -- Rows one-indexed, columns - zero-indexed (like cursor)\n  local nodes = {\n    { from = { 2, 0 }, to = { 6, 4 } },\n    { from = { 3, 0 }, to = { 5, 4 } },\n    { from = { 4, 0 }, to = { 4, 20 } },\n    { from = { 4, 4 }, to = { 4, 16 } },\n    { from = { 4, 8 }, to = { 4, 12 } },\n  }\n  local inside_nodes = { { 2, 2 }, { 3, 2 }, { 4, 2 }, { 4, 6 }, { 4, 10 } }\n\n  local validate = function(pos_before, direction, pos_ref, opts)\n    set_cursor(pos_before[1], pos_before[2])\n    child.lua('MiniBracketed.treesitter(...)', { direction, opts })\n    eq(get_cursor(), pos_ref)\n  end\n\n  return nodes, validate, inside_nodes\nend\n\nT['treesitter()']['works'] = function()\n  local nodes, validate, inside_nodes = setup_treesitter()\n  local n = #nodes\n\n  for i = 1, n do\n    -- Forward. Move to end of current node\n    validate(inside_nodes[i], 'forward', nodes[i].to)\n\n    -- Backward. Move to start of current node\n    validate(inside_nodes[i], 'backward', nodes[i].from)\n\n    -- First. Move to start of latest non-root parent.\n    validate(inside_nodes[i], 'first', nodes[1].from)\n\n    -- Last. Move to end of latest non-root parent.\n    validate(inside_nodes[i], 'last', nodes[1].to)\n  end\nend\n\nT['treesitter()']['sets cursor safely'] = function()\n  child.lua('vim.treesitter.get_node = function() return _G.node end')\n  set_lines({ 'aaa' })\n\n  -- Before start\n  child.lua([[_G.node = {\n    start = function() return -1, 0 end,\n    end_ = function() return 1, 0 end,\n    range = function() return -1, 0, 1, 0 end,\n    parent = function() return _G.node end,\n  }]])\n\n  set_cursor(1, 1)\n  backward('treesitter')\n  eq(get_cursor(), { 1, 0 })\n\n  set_cursor(1, 1)\n  forward('treesitter')\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['treesitter()']['moves to other edge of current node'] = function()\n  local nodes, validate, _ = setup_treesitter()\n  local n = #nodes\n\n  for i = 1, n do\n    -- Forward. When on start, move to end of current node\n    validate(nodes[i].from, 'forward', nodes[i].to)\n\n    -- Backward. When on end, move to start of current node\n    validate(nodes[i].to, 'backward', nodes[i].from)\n  end\nend\n\nT['treesitter()']['moves to parent when on corresponding edge of current node'] = function()\n  local nodes, validate = setup_treesitter()\n  local n = #nodes\n\n  for i = 2, n do\n    -- Forward. Move to end of parent node\n    validate(nodes[i].to, 'forward', nodes[i - 1].to)\n\n    -- Backward. Move to start of parent node\n    validate(nodes[i].from, 'backward', nodes[i - 1].from)\n  end\nend\n\nT['treesitter()']['does nothing when in root node'] = function()\n  local _, validate = setup_treesitter()\n\n  for _, direction in ipairs({ 'forward', 'backward', 'first', 'last' }) do\n    validate({ 1, 1 }, direction, { 1, 1 })\n  end\nend\n\nT['treesitter()']['does nothing if no node at cursor'] = function()\n  child.lua('vim.treesitter.get_node_at_pos = function() return nil end')\n  child.lua('vim.treesitter.get_node = function() return nil end')\n\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    set_lines({ '{ aaa }' })\n    set_cursor(1, 2)\n    dir('treesitter')\n    eq(get_cursor(), { 1, 2 })\n  end\nend\n\nT['treesitter()']['handles error when finding node at cursor'] = function()\n  child.lua('vim.treesitter.get_node_at_pos = function() error(\"No tree-sitter\") end')\n  child.lua('vim.treesitter.get_node = function() error(\"No tree-sitter\") end')\n  expect.error(function() forward('treesitter') end, 'can not find tree%-sitter node')\nend\n\nT['treesitter()']['validates `direction`'] = function()\n  setup_treesitter()\n\n  expect.error(function() child.lua('MiniBracketed.treesitter(1)') end, 'treesitter%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.treesitter('next')]]) end, 'treesitter%(%).*direction.*one of')\nend\n\nT['treesitter()']['respects `opts.add_to_jumplist`'] = function()\n  local nodes, _, inside_nodes = setup_treesitter()\n\n  set_cursor(inside_nodes[1][1], inside_nodes[1][2])\n  child.lua([[MiniBracketed.treesitter('forward', { add_to_jumplist = true })]])\n  eq(get_cursor(), nodes[1].to)\n\n  type_keys('<C-o>')\n  eq(get_cursor(), inside_nodes[1])\nend\n\nT['treesitter()']['respects `opts.n_times`'] = function()\n  local nodes, validate, inside_nodes = setup_treesitter()\n  local n = #nodes\n\n  for i = 2, n do\n    -- Forward. Move to end of parent node from inside of current.\n    validate(inside_nodes[i], 'forward', nodes[i - 1].to, { n_times = 2 })\n\n    -- Backward. Move to start of parent node from inside of current.\n    validate(inside_nodes[i], 'backward', nodes[i - 1].from, { n_times = 2 })\n  end\nend\n\nT['treesitter()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local nodes, validate, inside_nodes = setup_treesitter()\n    local n = #nodes\n\n    child[var_type].minibracketed_disable = true\n    validate(inside_nodes[n], 'forward', inside_nodes[n])\n  end,\n})\n\nT['treesitter()']['respects `vim.b.minibracketed_config`'] = function()\n  local nodes, validate, inside_nodes = setup_treesitter()\n  local n = #nodes\n\n  child.b.minibracketed_config = { treesitter = { options = { n_times = 2 } } }\n  validate(inside_nodes[n], 'forward', nodes[n - 1].to)\nend\n\nT['undo()'] = new_set()\n\nlocal get_undo_state = function() return child.fn.undotree().seq_cur end\n\nlocal validate_undo = function(lines, state)\n  eq(get_lines(), lines)\n  eq(get_undo_state(), state)\nend\n\nlocal validate_undo_history = function(states)\n  first('undo')\n  eq(get_undo_state(), states[1])\n  for i = 2, #states do\n    forward('undo')\n    eq(get_undo_state(), states[i])\n  end\n  forward('undo')\n  eq(get_undo_state(), states[1])\nend\n\nlocal setup_undo = function(...)\n  local undos = {}\n  undos[1] = { lines = get_lines(), state = get_undo_state() }\n\n  for _, keys in ipairs({ ... }) do\n    type_keys(keys)\n    table.insert(undos, { lines = get_lines(), state = child.fn.undotree().seq_cur })\n  end\n\n  local validate = function(direction, id_ref, opts)\n    child.lua('MiniBracketed.undo(...)', { direction, opts })\n    validate_undo(undos[id_ref].lines, undos[id_ref].state)\n  end\n\n  return undos, validate\nend\n\nT['undo()']['works'] = function()\n  --stylua: ignore\n  local undos, validate = setup_undo(\n    { 'i', 'one', '<Esc>' },    -- one\n    { 'i', ' two', '<Esc>' },   -- one two\n    { '0', 'daw' },             -- two\n    'u',                        -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    'u',                        -- one two\n    '<C-R>'                     -- one two three\n  )\n  local n = #undos\n\n  -- Forward\n  for i = 1, n do\n    validate('forward', i)\n  end\n\n  -- Backward\n  for i = n - 1, 1, -1 do\n    validate('backward', i)\n  end\n  validate('backward', n)\n\n  -- First\n  validate('first', 1)\n\n  -- Last\n  validate('last', n)\nend\n\nT['undo()']['works with pending new undo states'] = function()\n  --stylua: ignore\n  local undos, validate = setup_undo(\n    { 'i', 'one two', '<Esc>' }, -- one two\n    'x',                         -- one tw\n    'x'                          -- one t\n  )\n  local n = #undos\n\n  for i = 1, n do\n    validate('forward', i)\n  end\nend\n\nT['undo()']['correctly tracks state 0'] = function()\n  --stylua: ignore\n  local undos, validate = setup_undo(\n    { 'i', 'one', '<Esc>' }, -- one\n    'u',                     -- <empty>\n    { 'i', 'two', '<Esc>' }, -- two\n    'u'                      -- <empty>\n  )\n  local n = #undos\n\n  for i = 1, n do\n    validate('forward', i)\n  end\nend\n\nT['undo()'][\"works with low 'undolevels'\"] = function()\n  child.o.undolevels = 1\n\n  local undos, _ = setup_undo(\n    { 'i', 'one two three', '<Esc>' }, -- one two three\n    'x', -- one two thre\n    'x', -- one two thr\n    'x', -- one two th\n    'x' -- one two t\n  )\n  local n = #undos\n\n  -- First tracked state is 0. In this case restores before last allowed state.\n  first('undo')\n  validate_undo(undos[n - 2].lines, 0)\n\n  forward('undo')\n  validate_undo(undos[n - 1].lines, undos[n - 1].state)\n\n  forward('undo')\n  validate_undo(undos[n].lines, undos[n].state)\nend\n\nT['undo()']['works with `:undo!` when not advancing'] = function()\n  --stylua: ignore\n  setup_undo(\n    { 'i', 'one',    '<Esc>' }, -- one\n    { 'A', ' two',   '<Esc>' }, -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    ':undo! 1<CR>',             -- one (deletes 2 and 3 from allowed states)\n    { 'A', ' four',  '<Esc>' }, -- one four\n    { 'A', ' five',  '<Esc>' }  -- one four five\n  )\n\n  backward('undo')\n  validate_undo({ 'one four' }, 4)\n\n  backward('undo')\n  validate_undo({ 'one' }, 1)\n\n  backward('undo')\n  validate_undo({ '' }, 0)\n\n  backward('undo')\n  validate_undo({ 'one four five' }, 5)\nend\n\nT['undo()']['works with `:undo!` advancing'] = function()\n  -- NOTE: Be careful with executing `:undo!` when not in latest undo state\n  -- See: https://github.com/neovim/neovim/issues/22298\n\n  --stylua: ignore\n  setup_undo(\n    { 'i', 'one',    '<Esc>' }, -- one\n    { 'A', ' two',   '<Esc>' }, -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    'u',                        -- one two\n    '<C-R>',                    -- one two three\n    'u',                        -- one two\n    'u',                        -- one\n    '<C-R>',                    -- one two\n    '<C-R>',                    -- one two three\n    'u',                        -- one two\n    'u'                         -- one\n  )\n\n  for _ = 1, 6 do\n    backward('undo')\n  end\n  validate_undo({ 'one two three' }, 3)\n\n  -- Before this call undo history is { 0, 1, 2, 3, 2, 3, 2, 1, 2, 3, 2, 1 }\n  -- with current id being 6 (second state number 3).\n  -- After `:undo! 2`, state 3 is not allowed.\n  --\n  -- At the next synchronization:\n  -- - State 3 should be removed while not allowing same consecutive states.\n  -- - Advancing should stop because there were some not allowed states.\n  --   This also means that current undo state (2) should be registered.\n  --\n  -- This leads to history being { 0, 1, 2, 1, 2, 1, 2 } and current id\n  -- pointing to last history state.\n  child.cmd('undo! 2')\n\n  validate_undo_history({ 0, 1, 2, 1, 2, 1, 2 })\n\n  -- Should proper register next undo state\n  type_keys('A', ' three again', '<Esc>')\n  eq(get_undo_state(), 3)\n  backward('undo')\n  validate_undo({ 'one two' }, 2)\nend\n\nT['undo()']['does not register undo actions without `register_undo_state()`'] = function()\n  -- It would be **great** to implement that, but seems impossible\n  type_keys('i', 'one', '<Esc>')\n  type_keys('A', ' two', '<Esc>')\n  type_keys('A', ' three', '<Esc>')\n\n  type_keys('g-')\n  type_keys('g+')\n  child.cmd('earlier')\n  child.cmd('later')\n\n  -- Ideally, history should be { 0, 1, 2, 3, 2, 3, 2, 3 }, but in reality it\n  -- is { 0, 1, 2, 3 }\n  validate_undo_history({ 0, 1, 2, 3 })\nend\n\nT['undo()']['registers states after `register_undo_state()`'] = function()\n  local register_undo_state = function() child.lua('MiniBracketed.register_undo_state()') end\n  type_keys('i', 'one', '<Esc>')\n  type_keys('A', ' two', '<Esc>')\n  type_keys('A', ' three', '<Esc>')\n\n  type_keys('g-')\n  register_undo_state()\n  type_keys('g+')\n  register_undo_state()\n  child.cmd('earlier')\n  register_undo_state()\n  child.cmd('later')\n  register_undo_state()\n\n  validate_undo_history({ 0, 1, 2, 3, 2, 3, 2, 3 })\nend\n\nT['undo()']['respects [count] in `u` and `<C-R>`'] = function()\n  --stylua: ignore\n  setup_undo(\n    { 'i', 'one',    '<Esc>' }, -- one\n    { 'A', ' two',   '<Esc>' }, -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    '2u',                       -- one\n    '2<C-R>'                    -- one two three\n  )\n\n  validate_undo_history({ 0, 1, 2, 3, 1, 3 })\nend\n\nT['undo()']['tracks advance per buffer'] = function()\n  local buf_init = child.api.nvim_get_current_buf()\n  type_keys('i', 'one', '<Esc>')\n  type_keys('A', ' two', '<Esc>')\n  type_keys('A', ' three', '<Esc>')\n  backward('undo')\n  backward('undo')\n  validate_undo({ 'one' }, 1)\n\n  local buf_new = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_new)\n  type_keys('i', 'one', '<Esc>')\n  type_keys('A', ' two', '<Esc>')\n  backward('undo')\n  validate_undo({ 'one' }, 1)\n\n  -- Changing buffer should not reset advance\n  child.api.nvim_set_current_buf(buf_init)\n  backward('undo')\n  validate_undo({ '' }, 0)\nend\n\nT['undo()']['does not append currently advanced state if same as last one'] = function()\n  --stylua: ignore\n  setup_undo(\n    { 'i', 'one',  '<Esc>' }, -- state 1\n    { 'A', ' two', '<Esc>' }, -- state 2\n    'u'                       -- state 1\n  )\n\n  validate_undo({ 'one' }, 1)\n  backward('undo')\n  validate_undo({ 'one two' }, 2)\n  backward('undo')\n  validate_undo({ 'one' }, 1)\n\n  type_keys('A', ' three', '<Esc>')\n  validate_undo({ 'one three' }, 3)\n\n  backward('undo')\n  validate_undo({ 'one' }, 1)\n\n  -- If currently advanced state was appended, this would repeat state 1\n  backward('undo')\n  validate_undo({ 'one two' }, 2)\nend\n\nT['undo()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.undo(1)') end, 'undo%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.undo('next')]]) end, 'undo%(%).*direction.*one of')\nend\n\n-- No test for adding to jumplist because it is not designed to move cursor\n\nT['undo()']['respects `opts.n_times`'] = function()\n  --stylua: ignore\n  local undos, validate = setup_undo(\n    { 'i', 'one', '<Esc>' },    -- one\n    { 'i', ' two', '<Esc>' },   -- one two\n    { '0', 'daw' },             -- two\n    'u',                        -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    'u',                        -- one two\n    '<C-R>'                     -- one two three\n  )\n  local n = #undos\n\n  -- Forward\n  validate_undo(undos[n].lines, undos[n].state)\n  for i = 1, n do\n    validate('forward', (2 * i - 1) % n + 1, { n_times = 2 })\n  end\n\n  -- Backward\n  validate_undo(undos[n].lines, undos[n].state)\n  for i = 1, n do\n    validate('backward', (n - 2 * i - 1) % n + 1, { n_times = 2 })\n  end\n\n  -- First\n  validate('first', 2, { n_times = 2 })\n\n  -- Last\n  validate('last', n - 1, { n_times = 2 })\nend\n\nT['undo()']['respects `opts.wrap`'] = function()\n  --stylua: ignore\n  local undos, validate = setup_undo(\n    { 'i', 'one', '<Esc>' },    -- one\n    { 'i', ' two', '<Esc>' },   -- one two\n    { '0', 'daw' },             -- two\n    'u',                        -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    'u',                        -- one two\n    '<C-R>'                     -- one two three\n  )\n  local n = #undos\n\n  -- Forward\n  validate_undo(undos[n].lines, undos[n].state)\n  validate('forward', n, { wrap = false })\n\n  backward('undo')\n  validate_undo(undos[n - 1].lines, undos[n - 1].state)\n  validate('forward', n, { n_times = 1000, wrap = false })\n\n  -- Backward\n  first('undo')\n  validate_undo(undos[1].lines, undos[1].state)\n  validate('backward', 1, { wrap = false })\n\n  forward('undo')\n  validate_undo(undos[2].lines, undos[2].state)\n  validate('backward', 1, { n_times = 1000, wrap = false })\n\n  -- First\n  first('undo')\n  validate_undo(undos[1].lines, undos[1].state)\n  validate('first', n, { n_times = 1000, wrap = false })\n\n  last('undo')\n  validate_undo(undos[n].lines, undos[n].state)\n  validate('first', n, { n_times = 1000, wrap = false })\n\n  -- Last\n  last('undo')\n  validate_undo(undos[n].lines, undos[n].state)\n  validate('last', 1, { n_times = 1000, wrap = false })\n\n  first('undo')\n  validate_undo(undos[1].lines, undos[1].state)\n  validate('last', 1, { n_times = 1000, wrap = false })\nend\n\nT['undo()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    type_keys('i', 'one', '<Esc>')\n    type_keys('A', ' two', '<Esc>')\n\n    child[var_type].minibracketed_disable = true\n    backward('undo')\n    validate_undo({ 'one two' }, 2)\n  end,\n})\n\nT['undo()']['respects `vim.b.minibracketed_config`'] = function()\n  type_keys('i', 'one', '<Esc>')\n  type_keys('A', ' two', '<Esc>')\n\n  child.b.minibracketed_config = { undo = { options = { wrap = false } } }\n  forward('undo')\n  validate_undo({ 'one two' }, 2)\nend\n\n-- Most tests are done in `undo()`\nT['register_undo_state()'] = new_set()\n\nT['register_undo_state()']['is present'] = function()\n  eq(child.lua_get('type(MiniBracketed.register_undo_state)'), 'function')\nend\n\nT['window()'] = new_set()\n\nlocal get_winnr = function() return child.fn.winnr() end\nlocal set_winnr = function(x) return child.api.nvim_set_current_win(child.fn.win_getid(x)) end\n\nlocal setup_windows = function()\n  child.cmd('rightbelow vertical split')\n  child.cmd('rightbelow split')\n  child.cmd('rightbelow vertical split')\n  child.cmd('rightbelow split')\n  child.cmd('rightbelow split')\n\n  -- Should traverse windows in order of their number (which is position\n  -- specific, unlike id)\n  local winnr_list = {}\n  for i = 1, child.fn.winnr('$') do\n    table.insert(winnr_list, i)\n  end\n\n  -- Should not matter what buffer is shown in window\n  local win_2 = child.fn.win_getid(2)\n  local buf_scratch = child.api.nvim_create_buf(false, true)\n  child.api.nvim_win_set_buf(win_2, buf_scratch)\n\n  -- Should ignore floating windows\n  local buf_float = child.api.nvim_create_buf(true, false)\n  child.api.nvim_open_win(buf_float, false, { relative = 'editor', width = 2, height = 2, row = 2, col = 2 })\n\n  local validate = function(id_start, direction, id_ref, opts)\n    set_winnr(winnr_list[id_start])\n    child.lua('MiniBracketed.window(...)', { direction, opts })\n    eq(get_winnr(), winnr_list[id_ref])\n  end\n\n  return winnr_list, validate\nend\n\nT['window()']['works'] = function()\n  local winnr_list, validate = setup_windows()\n  validate_works(validate, #winnr_list)\nend\n\nT['window()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.window(1)') end, 'window%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.window('next')]]) end, 'window%(%).*direction.*one of')\nend\n\n-- No test for adding to jumplist because it is not designed to move cursor\n\nT['window()']['respects `opts.n_times`'] = function()\n  local winnr_list, validate = setup_windows()\n  validate_n_times(validate, #winnr_list)\nend\n\nT['window()']['respects `opts.wrap`'] = function()\n  local winnr_list, validate = setup_windows()\n  validate_wrap(validate, #winnr_list)\nend\n\nT['window()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local winnr_list = setup_windows()\n\n    set_winnr(winnr_list[1])\n    child[var_type].minibracketed_disable = true\n    forward('window')\n    eq(get_winnr(), winnr_list[1])\n  end,\n})\n\nT['window()']['respects `vim.b.minibracketed_config`'] = function()\n  local winnr_list = setup_windows()\n\n  set_winnr(winnr_list[1])\n  child.b.minibracketed_config = { window = { options = { wrap = false } } }\n  backward('window')\n  eq(get_winnr(), winnr_list[1])\nend\n\nT['yank()'] = new_set()\n\n-- local get_yank = function() return end\n-- local set_yank = function(x) end\n\n---@param ... any Yank entries to populate yank history.\n---   Each element is one of:\n---   - String. Will be yanked in charwise mode.\n---   - Table. First element is array of lines, second - keys used to yank them\n---     (assuming Normal mode and cursor being {1, 0}).\n---@return ... Array of arrays with yank history lines and its validator.\n---@private\nlocal setup_yank = function(...)\n  local yank_entries = vim.tbl_map(function(x)\n    -- If entry is string, yank it whole in charwise mode\n    if type(x) == 'string' then return { { x }, '0v$hy' } end\n    return x\n  end, { ... })\n\n  for _, entry in ipairs(yank_entries) do\n    child.ensure_normal_mode()\n    set_lines(entry[1])\n    set_cursor(1, 0)\n    type_keys(entry[2])\n  end\n\n  child.ensure_normal_mode()\n  set_lines({})\n  local yanks = vim.tbl_map(function(x) return x[1] end, yank_entries)\n\n  local validate = function(direction, id_ref, opts)\n    child.lua('MiniBracketed.yank(...)', { direction, opts })\n    eq(get_lines(), yanks[id_ref])\n  end\n\n  return yanks, validate\nend\n\nT['yank()']['works'] = function()\n  local yanks, validate = setup_yank('one', 'two', 'three', 'four', 'five')\n  local n = #yanks\n  type_keys('p')\n  eq(get_lines(), yanks[n])\n\n  -- Forward\n  for i = 1, n do\n    validate('forward', i)\n  end\n\n  -- Backward\n  for i = n - 1, 1, -1 do\n    validate('backward', i)\n  end\n  validate('backward', n)\n\n  -- First\n  validate('first', 1)\n\n  -- Last\n  validate('last', n)\nend\n\nT['yank()']['works advancing charwise<->charwise'] = function()\n  setup_yank('one', 'two')\n\n  set_lines({ '____' })\n  set_cursor(1, 2)\n  type_keys('yl', 'P')\n  eq(get_lines(), { '_____' })\n\n  backward('yank')\n  eq(get_lines(), { '__two__' })\n\n  backward('yank')\n  eq(get_lines(), { '__one__' })\n\n  last('yank')\n  eq(get_lines(), { '_____' })\nend\n\nT['yank()']['works advancing charwise<->linewise'] = function()\n  setup_yank({ { 'line' }, 'yy' })\n\n  set_lines({ '_', '____', '_' })\n  set_cursor(2, 2)\n  type_keys('yl', 'P')\n  eq(get_lines(), { '_', '_____', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', 'line', '____', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '_____', '_' })\nend\n\nT['yank()']['works advancing charwise<->blockwise'] = function()\n  setup_yank({ { 'bl', 'ock' }, '<C-v>j2ly' })\n\n  set_lines({ '_', '____', '_' })\n  set_cursor(2, 2)\n  type_keys('yl', 'P')\n  eq(get_lines(), { '_', '_____', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '__bl __', '_ ock' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '_____', '_ ' })\nend\n\nT['yank()']['works with multiline charwise yank entry'] = function()\n  setup_yank({ { 'one', 'aaaa' }, 'v$jy' })\n\n  set_lines({ '_', '____', '_' })\n  set_cursor(2, 2)\n  type_keys('yl', 'P')\n  eq(get_lines(), { '_', '_____', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '__one', 'aaaa__', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '_____', '_' })\nend\n\nT['yank()']['works pasting charwise on last column'] = function()\n  setup_yank('one')\n\n  -- Past last column\n  set_lines({ 'xyz' })\n  set_cursor(1, 1)\n  type_keys('vy', '$', 'p')\n  eq(get_lines(), { 'xyzy' })\n\n  backward('yank')\n  eq(get_lines(), { 'xyzone' })\n\n  backward('yank')\n  eq(get_lines(), { 'xyzy' })\n\n  -- Just before last column\n  set_lines({ 'xyz' })\n  set_cursor(1, 2)\n  type_keys('P')\n  eq(get_lines(), { 'xyyz' })\n\n  backward('yank')\n  eq(get_lines(), { 'xyonez' })\n\n  backward('yank')\n  eq(get_lines(), { 'xyyz' })\n\n  -- Replacing linewise region on last line\n  type_keys('yy', 'p')\n  eq(get_lines(), { 'xyyz', 'xyyz' })\n\n  backward('yank')\n  eq(get_lines(), { 'yxyyz' })\nend\n\nT['yank()']['works advancing linewise<->linewise'] = function()\n  setup_yank({ { 'line1' }, 'yy' }, { { 'line2' }, 'yy' })\n\n  set_lines({ '_', '_' })\n  set_cursor(1, 0)\n  type_keys('yy', 'p')\n  eq(get_lines(), { '_', '_', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', 'line2', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', 'line1', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '_', '_' })\nend\n\nT['yank()']['works advancing linewise<->blockwise'] = function()\n  setup_yank({ { 'bl', 'ock' }, '<C-v>j2ly' })\n\n  set_lines({ '_', '_' })\n  set_cursor(1, 0)\n  type_keys('yy', 'p')\n  eq(get_lines(), { '_', '_', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', 'bl _', 'ock' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '_', '_', '' })\nend\n\nT['yank()']['works with multiline linewise yank entry'] = function()\n  setup_yank({ { 'line1', 'line2' }, 'y2_' })\n\n  set_lines({ '_', '_' })\n  set_cursor(1, 0)\n  type_keys('yy', 'p')\n  eq(get_lines(), { '_', '_', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', 'line1', 'line2', '_' })\n\n  backward('yank')\n  eq(get_lines(), { '_', '_', '_' })\nend\n\nT['yank()']['works pasting linewise on last line'] = function()\n  setup_yank({ { 'line' }, 'yy' })\n\n  -- Past last line\n  set_lines({ 'xxx', '___' })\n  set_cursor(1, 0)\n  type_keys('yy', 'j', 'p')\n  eq(get_lines(), { 'xxx', '___', 'xxx' })\n\n  backward('yank')\n  eq(get_lines(), { 'xxx', '___', 'line' })\n\n  backward('yank')\n  eq(get_lines(), { 'xxx', '___', 'xxx' })\n\n  -- Just before of last line\n  set_lines({ 'yyy', '___' })\n  set_cursor(2, 0)\n  type_keys('P')\n  eq(get_lines(), { 'yyy', 'xxx', '___' })\n\n  backward('yank')\n  eq(get_lines(), { 'yyy', 'line', '___' })\n\n  backward('yank')\n  eq(get_lines(), { 'yyy', 'xxx', '___' })\n\n  -- Replacing non-linewise region on last column\n  set_lines({ 'yyy', '___' })\n  set_cursor(1, 2)\n  type_keys('yl', 'p')\n  eq(get_lines(), { 'yyyy', '___' })\n\n  backward('yank')\n  eq(get_lines(), { 'xxx', 'yyy', '___' })\nend\n\nT['yank()']['works advancing blockwise<->blockwise'] = function()\n  setup_yank({ { 'bl', 'ock1' }, '<C-v>j3ly' }, { { 'block2' }, '<C-v>5ly' })\n\n  set_lines({ '___', '___' })\n  set_cursor(1, 1)\n  type_keys('<C-v>y', 'P')\n  eq(get_lines(), { '____', '___' })\n\n  backward('yank')\n  eq(get_lines(), { '_block2__', '___' })\n\n  backward('yank')\n  eq(get_lines(), { '_bl  __', '_ock1__' })\n\n  backward('yank')\n  eq(get_lines(), { '____', '___' })\nend\n\nT['yank()']['works pasting blockwise on last column'] = function()\n  setup_yank({ { 'bl', 'ock' }, '<C-v>j2ly' })\n\n  -- Past last column\n  set_lines({ 'x__', 'x__' })\n  set_cursor(1, 0)\n  type_keys('<C-v>jy', '$', 'p')\n  eq(get_lines(), { 'x__x', 'x__x' })\n\n  backward('yank')\n  eq(get_lines(), { 'x__bl', 'x__ock' })\n\n  backward('yank')\n  eq(get_lines(), { 'x__x', 'x__x' })\n\n  -- Just before last column\n  set_lines({ '___', '___' })\n  set_cursor(1, 2)\n  type_keys('P')\n  eq(get_lines(), { '__x_', '__x_' })\n\n  backward('yank')\n  eq(get_lines(), { '__bl _', '__ock_' })\n\n  backward('yank')\n  eq(get_lines(), { '__x_', '__x_' })\n\n  -- Replacing linewise region on last line\n  set_lines({ 'aaa' })\n  type_keys('yy', 'p')\n  eq(get_lines(), { 'aaa', 'aaa' })\n\n  backward('yank')\n  eq(get_lines(), { 'xaaa', 'x' })\nend\n\nT['yank()']['works with one yank entry or less'] = function()\n  -- No yank history\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    set_lines({ 'aaa' })\n    set_cursor(1, 0)\n    dir('yank')\n    eq(get_lines(), { 'aaa' })\n    eq(get_cursor(), { 1, 0 })\n  end\n\n  -- Single-entry yank history\n  set_lines({ 'x__' })\n  set_cursor(1, 0)\n  type_keys('ylp')\n  eq(get_lines(), { 'xx__' })\n  eq(get_cursor(), { 1, 1 })\n\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    dir('yank')\n    eq(get_lines(), { 'xx__' })\n    eq(get_cursor(), { 1, 1 })\n  end\n\n  -- No yank entry with proper operator\n  for _, dir in ipairs({ forward, backward, first, last }) do\n    dir('yank', { operators = { 'c' } })\n    eq(get_lines(), { 'xx__' })\n    eq(get_cursor(), { 1, 1 })\n  end\nend\n\nT['yank()']['does not depend on cursor position'] = function()\n  setup_yank('one')\n\n  set_lines({ '___', '___' })\n  set_cursor(1, 0)\n  type_keys('yl', 'p')\n  eq(get_lines(), { '____', '___' })\n\n  set_cursor(2, 2)\n  backward('yank')\n  eq(get_lines(), { '_one__', '___' })\n  eq(get_cursor(), { 1, 3 })\nend\n\nT['yank()']['places cursor at region start during replacement'] = function()\n  setup_yank('x', { { 'xxx' }, 'yy' })\n\n  set_lines({ '___' })\n  type_keys('p')\n  eq(get_lines(), { '___', 'xxx' })\n\n  set_cursor(2, 2)\n  backward('yank')\n  eq(get_lines(), { 'x___' })\nend\n\nT['yank()']['tracks all `TextYankPost` events'] = function()\n  setup_yank({ { 'one' }, '\"ayiw' }, { { 'two' }, 'diw' }, { { 'three' }, 'ciw<Esc>' })\n\n  set_lines({ '___' })\n  set_cursor(1, 0)\n  type_keys('yl', 'p')\n  eq(get_lines(), { '____' })\n\n  backward('yank')\n  eq(get_lines(), { '_three__' })\n\n  backward('yank')\n  eq(get_lines(), { '_two__' })\n\n  backward('yank')\n  eq(get_lines(), { '_one__' })\n\n  backward('yank')\n  eq(get_lines(), { '____' })\nend\n\nT['yank()']['tracks yanking right after advancing'] = function()\n  setup_yank('one', 'two')\n\n  set_lines({ '', 'three' })\n  set_cursor(1, 0)\n  type_keys('p')\n  eq(get_lines(), { 'two', 'three' })\n\n  backward('yank')\n  eq(get_lines(), { 'one', 'three' })\n\n  -- It should reset advancing after adding another entry to yank history\n  set_cursor(2, 0)\n  type_keys('yiw', 'P')\n  eq(get_lines(), { 'one', 'threethree' })\n\n  backward('yank')\n  eq(get_lines(), { 'one', 'twothree' })\nend\n\nT['yank()']['does not detect correct region mode when pasted with register'] = function()\n  -- It would be **great** to make it work but seems impossible right now\n  -- See https://github.com/vim/vim/issues/12003\n  setup_yank({ { 'a', 'b' }, '<C-v>j\"ay' }, { { 'aaa' }, 'yy' })\n\n  set_lines({ 'xxx', 'yyy' })\n  set_cursor(1, 0)\n  type_keys('\"aP')\n  eq(get_lines(), { 'axxx', 'byyy' })\n\n  backward('yank')\n  -- It thinks that region is linewise but it is not. Also at this point yank\n  -- history is { {'a', 'b'}, {'aaa'} } so backward chooses second to last.\n  eq(get_lines(), { 'a', 'b' })\n\n  backward('yank')\n  eq(get_lines(), { 'aaa', '', '' })\nend\n\nT['yank()']['does not have side effects'] = function()\n  setup_yank('one', 'two')\n\n  set_lines({ 'x__' })\n  set_cursor(1, 0)\n  type_keys('\"zyl', 'l', 'yl')\n  type_keys('P')\n  eq(get_lines(), { 'x___' })\n  eq(child.fn.getreg('z'), 'x')\n  eq(child.fn.getreg('\"'), '_')\n\n  backward('yank')\n  eq(get_lines(), { 'xx__' })\n\n  backward('yank')\n  eq(get_lines(), { 'xtwo__' })\n\n  eq(child.fn.getreg('z'), 'x')\n  eq(child.fn.getreg('\"'), '_')\nend\n\nT['yank()']['undos all advances at once'] = function()\n  setup_yank('one', 'two', 'three', 'four')\n\n  type_keys('p')\n  eq(get_lines(), { 'four' })\n\n  backward('yank')\n  eq(get_lines(), { 'three' })\n  backward('yank')\n  eq(get_lines(), { 'two' })\n  backward('yank')\n  eq(get_lines(), { 'one' })\n\n  type_keys('u')\n  eq(get_lines(), { 'four' })\n  type_keys('u')\n  eq(get_lines(), { '' })\nend\n\nT['yank()']['replaces region based on `[` marks `]`'] = function()\n  -- Should replace not only latest put region, but also yanked or changed\n  -- Region from change operation\n  setup_yank('one')\n\n  set_lines({ '____' })\n  set_cursor(1, 1)\n  type_keys('cl<Esc>')\n  eq(get_lines(), { '___' })\n\n  backward('yank')\n  -- - As `_` is now the last entry in history, going backward selects `two`\n  eq(get_lines(), { '_one_' })\n\n  -- Region from yank operation\n  setup_yank('two')\n\n  set_lines({ '____' })\n  set_cursor(1, 1)\n  type_keys('yl')\n\n  backward('yank')\n  -- Neovim>=0.11 has more correct behavior for setting `[`/`]` marks here\n  local ref = child.fn.has('nvim-0.11') == 1 and '_two__' or '_two_'\n  eq(get_lines(), { ref })\nend\n\nT['yank()']['respects `register_put_region()` to determine region boundaries'] = function()\n  -- Should take into account only regions coming from the helper; not from\n  -- yank or change operations.\n  set_lines({ 'xaa', 'bbb', 'ccc' })\n\n  set_cursor(1, 0)\n  type_keys('yl', '$', 'P')\n\n  child.lua('MiniBracketed.register_put_region()')\n\n  set_cursor(2, 0)\n  type_keys('ciw', '<Esc>')\n\n  set_cursor(3, 0)\n  type_keys('yiw')\n\n  eq(get_lines(), { 'xaxa', '', 'ccc' })\n  backward('yank')\n  -- - At this moment yank history is `{ 'x', 'bbb', 'ccc' }` with current\n  --   entry being the last one.\n  eq(get_lines(), { 'xabbba', '', 'ccc' })\nend\n\nT['yank()']['respects `register_put_region()` to determine region mode'] = function()\n  -- Currently this is only possible with remapping\n  child.api.nvim_set_keymap('n', 'P', 'v:lua.MiniBracketed.register_put_region(\"P\")', { expr = true })\n\n  setup_yank({ { 'a', 'b' }, '<C-v>j\"ay' }, { { 'aaa' }, 'yy' })\n\n  set_lines({ 'xxx', 'yyy' })\n  set_cursor(1, 0)\n  type_keys('\"aP')\n  eq(get_lines(), { 'axxx', 'byyy' })\n\n  backward('yank')\n  -- At this point yank history is { { 'a', 'b' }, { 'aaa' } } so backward\n  -- chooses second to last.\n  eq(get_lines(), { 'axxx', 'byyy' })\n  backward('yank')\n  eq(get_lines(), { 'aaa', 'xxx', 'yyy' })\nend\n\nT['yank()']['should reset advancing on buffer change'] = function()\n  local buf_id_new = child.api.nvim_create_buf(true, false)\n  setup_yank('one', 'two', 'three', 'four')\n\n  type_keys('P')\n  eq(get_lines(), { 'four' })\n\n  backward('yank')\n  eq(get_lines(), { 'three' })\n  backward('yank')\n  eq(get_lines(), { 'two' })\n\n  child.api.nvim_set_current_buf(buf_id_new)\n  type_keys('P')\n  eq(get_lines(), { 'four' })\n  backward('yank')\n  eq(get_lines(), { 'three' })\nend\n\nT['yank()']['validates `direction`'] = function()\n  expect.error(function() child.lua('MiniBracketed.yank(1)') end, 'yank%(%).*direction.*one of')\n  expect.error(function() child.lua([[MiniBracketed.yank('next')]]) end, 'yank%(%).*direction.*one of')\nend\n\n-- No test for adding to jumplist because it is not designed to move cursor\n\nT['yank()']['respects `opts.n_times`'] = function()\n  local yanks, validate = setup_yank('one', 'two', 'three', 'four', 'five')\n  local n = #yanks\n  type_keys('p')\n  eq(get_lines(), yanks[n])\n\n  -- Forward\n  eq(get_lines(), yanks[n])\n  for i = 1, n do\n    validate('forward', (2 * i - 1) % n + 1, { n_times = 2 })\n  end\n\n  -- Backward\n  eq(get_lines(), yanks[n])\n  for i = 1, n do\n    validate('backward', (n - 2 * i - 1) % n + 1, { n_times = 2 })\n  end\n\n  -- First\n  validate('first', 2, { n_times = 2 })\n\n  -- Last\n  validate('last', n - 1, { n_times = 2 })\nend\n\nT['yank()']['respects `opts.operators`'] = function()\n  setup_yank({ { 'one' }, '\"ayiw' }, { { 'two' }, 'diw' }, { { 'three' }, 'ciw<Esc>' })\n\n  set_lines({ '___' })\n  set_cursor(1, 0)\n  type_keys('yl', 'p')\n  eq(get_lines(), { '____' })\n\n  backward('yank', { operators = { 'y' } })\n  eq(get_lines(), { '_one__' })\n\n  backward('yank', { operators = { 'd' } })\n  eq(get_lines(), { '_two__' })\n\n  backward('yank', { operators = { 'c' } })\n  eq(get_lines(), { '_three__' })\n\n  backward('yank', { operators = { 'y', 'd' } })\n  eq(get_lines(), { '_two__' })\nend\n\nT['yank()']['respects `opts.wrap`'] = function()\n  local yanks, validate = setup_yank('one', 'two', 'three', 'four', 'five')\n  local n = #yanks\n  type_keys('p')\n  eq(get_lines(), yanks[n])\n\n  -- Forward\n  eq(get_lines(), yanks[n])\n  validate('forward', n, { wrap = false })\n\n  backward('yank')\n  eq(get_lines(), yanks[n - 1])\n  validate('forward', n, { n_times = 1000, wrap = false })\n\n  -- Backward\n  first('yank')\n  eq(get_lines(), yanks[1])\n  validate('backward', 1, { wrap = false })\n\n  forward('yank')\n  eq(get_lines(), yanks[2])\n  validate('backward', 1, { n_times = 1000, wrap = false })\n\n  -- First\n  first('yank')\n  eq(get_lines(), yanks[1])\n  validate('first', n, { n_times = 1000, wrap = false })\n\n  last('yank')\n  eq(get_lines(), yanks[n])\n  validate('first', n, { n_times = 1000, wrap = false })\n\n  -- Last\n  last('yank')\n  eq(get_lines(), yanks[n])\n  validate('last', 1, { n_times = 1000, wrap = false })\n\n  first('yank')\n  eq(get_lines(), yanks[1])\n  validate('last', 1, { n_times = 1000, wrap = false })\nend\n\nT['yank()']['respects `vim.{g,b}.minibracketed_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    setup_yank('one', 'two')\n    type_keys('p')\n    eq(get_lines(), { 'two' })\n\n    -- `yank()` itself shouldn't work\n    child[var_type].minibracketed_disable = true\n    backward('yank')\n    eq(get_lines(), { 'two' })\n\n    -- Tracking yank history shouldn't work\n    set_cursor(1, 0)\n    type_keys('yl')\n\n    set_cursor(1, 1)\n    type_keys('yl', 'P')\n    eq(get_lines(), { 'twwo' })\n\n    child[var_type].minibracketed_disable = false\n    -- Yank history should still be { 'one', 'two' } (without 't' and 'w').\n    -- Going backward select second to last entry.\n    backward('yank')\n    eq(get_lines(), { 'tonewo' })\n  end,\n})\n\nT['yank()']['respects `vim.b.minibracketed_config`'] = function()\n  setup_yank('one', 'two')\n  type_keys('p')\n  eq(get_lines(), { 'two' })\n\n  child.b.minibracketed_config = { yank = { options = { wrap = false } } }\n  forward('yank')\n  eq(get_lines(), { 'two' })\nend\n\n-- Main tests are in `yank()`\nT['register_put_region()'] = new_set()\n\nT['register_put_region()']['is present'] = function()\n  eq(child.lua_get('type(MiniBracketed.register_put_region)'), 'function')\nend\n\nT['register_put_region()']['uses `[` and `]` marks'] = function()\n  set_lines({ 'xaa', 'bbb', 'ccc' })\n\n  set_cursor(1, 0)\n  type_keys('yl', '$', 'P')\n\n  -- Should be possible to use it not only on region from put operation\n  -- - Change\n  set_cursor(2, 0)\n  type_keys('ciw', '<Esc>')\n  child.lua('MiniBracketed.register_put_region()')\n\n  eq(get_lines(), { 'xaxa', '', 'ccc' })\n  -- - Yank history at this point: { 'x', 'bbb' }\n  backward('yank')\n  eq(get_lines(), { 'xaxa', 'x', 'ccc' })\n\n  -- - Yank\n  set_cursor(3, 0)\n  type_keys('yiw')\n  child.lua('MiniBracketed.register_put_region()')\n\n  eq(get_lines(), { 'xaxa', 'x', 'ccc' })\n  -- - Yank history at this point: { 'x', 'bbb', 'ccc' }\n  backward('yank')\n  eq(get_lines(), { 'xaxa', 'x', 'bbb' })\nend\n\nT['advance()'] = new_set()\n\nlocal make_iterator = function(init_state)\n  child.lua([[\n    _G.iterator = {}\n\n    _G.iterator.next = function(id)\n      if id == nil then return -1 end\n      if 5 <= id then return end\n      return id + 1\n    end\n\n    _G.iterator.prev = function(id)\n      if id == nil then return -2 end\n      if id <= 1 then return end\n      return id - 1\n    end\n\n    _G.iterator.start_edge = 0\n    _G.iterator.end_edge = 6\n  ]])\n  child.lua('_G.iterator.state = ' .. tostring(init_state))\nend\n\nlocal advance = function(direction, opts)\n  return child.lua_get('MiniBracketed.advance(iterator, ...)', { direction, opts })\nend\n\nT['advance()']['works'] = function()\n  make_iterator(3)\n\n  -- Should only return new state without changing current one\n  local res_id = advance('forward')\n  eq(res_id, 4)\n  eq(child.lua_get('_G.iterator.state'), 3)\nend\n\nT['advance()']['respects `direction` argument'] = function()\n  local n = 5\n\n  for i = 1, n do\n    make_iterator(i)\n\n    eq(advance('forward'), i % n + 1)\n    eq(advance('backward'), (i - 2) % n + 1)\n    eq(advance('first'), 1)\n    eq(advance('last'), n)\n  end\nend\n\nT['advance()']['respects `opts.n_times`'] = function()\n  local n = 5\n\n  for i = 1, n do\n    make_iterator(i)\n\n    eq(advance('forward', { n_times = 2 }), (i + 1) % n + 1)\n    eq(advance('backward', { n_times = 2 }), (i - 3) % n + 1)\n    eq(advance('first', { n_times = 2 }), 2)\n    eq(advance('last', { n_times = 2 }), n - 1)\n  end\nend\n\nT['advance()']['respects `opts.wrap`'] = function()\n  local n = 5\n\n  local validate = function(id_before, direction, id_ref, opts)\n    make_iterator(id_before)\n    eq(advance(direction, opts), id_ref)\n  end\n\n  validate_wrap(validate, n)\nend\n\nT['advance()']['handles `nil` states'] = function()\n  local n = 5\n\n  -- `state = nil`\n  make_iterator(3)\n  child.lua('_G.iterator.state = nil')\n\n  eq(advance('forward'), -1)\n  eq(advance('backward'), -2)\n  eq(advance('first'), 1)\n  eq(advance('last'), n)\n\n  -- `start_edge = nil`\n  make_iterator(3)\n  child.lua('_G.iterator.start_edge = nil')\n\n  eq(advance('forward'), 4)\n  eq(advance('backward'), 2)\n  eq(advance('first'), -1)\n  eq(advance('last'), n)\n\n  -- `end_edge = nil`\n  make_iterator(3)\n  child.lua('_G.iterator.end_edge = nil')\n\n  eq(advance('forward'), 4)\n  eq(advance('backward'), 2)\n  eq(advance('first'), 1)\n  eq(advance('last'), -2)\nend\n\n-- Integration tests ==========================================================\nT['Mappings'] = new_set()\n\nT['Mappings']['buffer'] = new_set()\n\nlocal validate_map_buffer = function(buf_start, keys, buf_ref)\n  set_buf(buf_start)\n  type_keys(keys)\n  eq(get_buf(), buf_ref)\nend\n\nT['Mappings']['buffer']['works'] = function()\n  local buf_list = setup_buffers()\n  local n = #buf_list\n\n  validate_map_buffer(buf_list[n], '[B', buf_list[1])\n  validate_map_buffer(buf_list[2], '2[b', buf_list[n])\n  validate_map_buffer(buf_list[1], ']b', buf_list[2])\n  validate_map_buffer(buf_list[n], '2]B', buf_list[n - 1])\nend\n\nT['Mappings']['buffer']['allows non-letter suffix'] = function()\n  reload_module({ buffer = { suffix = ',' } })\n\n  local buf_list = setup_buffers()\n  local n = #buf_list\n\n  -- Only backward/forward should be mapped\n  validate_map_buffer(buf_list[1], '[,', buf_list[n])\n  validate_map_buffer(buf_list[1], '],', buf_list[2])\nend\n\nT['Mappings']['comment'] = new_set()\n\nT['Mappings']['comment']['works'] = function()\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '3', '## 4', '5', '## 6', '7', '## 8', '9', '## 10', '11' }\n  set_lines(lines)\n\n  -- Normal mode\n  validate_move({ 1, 0 }, '[C', { 2, 0 })\n  validate_move({ 9, 0 }, '2[c', { 6, 0 })\n  validate_move({ 2, 0 }, ']c', { 4, 0 })\n  validate_move({ 1, 0 }, '2]C', { 8, 0 })\n\n  -- Visual mode\n  validate_move({ 1, 0 }, 'v[C', { 2, 0 })\n  validate_move({ 9, 0 }, 'v2[c', { 6, 0 })\n  validate_move({ 2, 0 }, 'v]c', { 4, 0 })\n  validate_move({ 1, 0 }, 'v2]C', { 8, 0 })\n\n  -- Operator-pending mode\n  validate_edit({ '1', '2', '## 3', '4' }, { 2, 0 }, 'd[C', { '1', '4' }, { 2, 0 })\n  validate_edit({ '1', '2', '## 3', '4' }, { 2, 0 }, 'd[c', { '1', '4' }, { 2, 0 })\n  validate_edit({ '1', '2', '## 3', '4' }, { 2, 0 }, 'd]c', { '1', '4' }, { 2, 0 })\n  validate_edit({ '1', '2', '## 3', '4' }, { 2, 0 }, 'd]C', { '1', '4' }, { 2, 0 })\n\n  -- - Dot-repeat\n  validate_edit({ '1', '2', '## 3', '4', '## 5' }, { 2, 0 }, 'd]c.', { '1' }, { 1, 0 })\nend\n\nT['Mappings']['comment']['allows non-letter suffix'] = function()\n  reload_module({ comment = { suffix = ',' } })\n\n  child.o.commentstring = '## %s'\n  local lines = { '1', '## 2', '3', '## 4', '5', '## 6' }\n  set_lines(lines)\n\n  -- Only backward/forward should be mapped\n  validate_move({ 5, 0 }, '[,', { 4, 0 })\n  validate_move({ 3, 0 }, '],', { 4, 0 })\nend\n\nT['Mappings']['conflict'] = new_set()\n\nT['Mappings']['conflict']['works'] = function()\n  local m = conflict_marks\n  local lines = { '1', m[1], m[2], m[3], '5', m[3], m[2], m[1], '9' }\n  set_lines(lines)\n\n  -- Normal mode\n  validate_move({ 1, 0 }, '[X', { 2, 0 })\n  validate_move({ 9, 0 }, '2[x', { 7, 0 })\n  validate_move({ 2, 0 }, ']x', { 3, 0 })\n  validate_move({ 1, 0 }, '2]X', { 7, 0 })\n\n  -- Visual mode\n  validate_move({ 1, 0 }, 'v[X', { 2, 0 })\n  validate_move({ 9, 0 }, 'v2[x', { 7, 0 })\n  validate_move({ 2, 0 }, 'v]x', { 3, 0 })\n  validate_move({ 1, 0 }, 'v2]X', { 7, 0 })\n\n  -- Operator-pending mode\n  validate_edit({ m[1], '2', m[2], '4', m[3] }, { 4, 0 }, 'd[X', { m[3] }, { 1, 0 })\n  validate_edit({ m[1], '2', m[2], '4', m[3] }, { 3, 0 }, 'd[x', { '4', m[3] }, { 1, 0 })\n  validate_edit({ m[1], '2', m[2], '4', m[3] }, { 3, 0 }, 'd]x', { m[1], '2' }, { 2, 0 })\n  validate_edit({ m[1], '2', m[2], '4', m[3] }, { 2, 0 }, 'd]X', { m[1] }, { 1, 0 })\n\n  -- - Dot-repeat\n  validate_edit({ m[1], '2', m[2], '4', m[3] }, { 1, 0 }, 'd]x.', { '' }, { 1, 0 })\nend\n\nT['Mappings']['conflict']['allows non-letter suffix'] = function()\n  reload_module({ conflict = { suffix = ',' } })\n\n  local m = conflict_marks\n  local lines = { m[1], '2', m[2], '4', m[3] }\n  set_lines(lines)\n\n  -- Only backward/forward should be mapped\n  validate_move({ 4, 0 }, '[,', { 3, 0 })\n  validate_move({ 2, 0 }, '],', { 3, 0 })\nend\n\nT['Mappings']['diagnostic'] = new_set()\n\nT['Mappings']['diagnostic']['works'] = function()\n  local cur_pos_tbl = setup_diagnostic()\n  local all = cur_pos_tbl.all\n  local n = #all\n\n  child.lua('MiniBracketed.config.diagnostic.options = { severity = { min = vim.diagnostic.severity.HINT } }')\n\n  -- Normal mode\n  validate_move(all[3], '[D', all[1])\n  validate_move(all[2], '2[d', all[n])\n  validate_move(all[1], ']d', all[2])\n  validate_move(all[1], '2]D', all[n - 1])\n\n  -- Visual mode\n  validate_move(all[3], 'v[D', all[1])\n  validate_move(all[2], 'v2[d', all[n])\n  validate_move(all[1], 'v]d', all[2])\n  validate_move(all[1], 'v2]D', all[n - 1])\n\n  -- Operator-pending mode\n  child.diagnostic.reset()\n\n  local lines = { 'aa Error', 'aa Error2' }\n  local sev_err = vim.diagnostic.severity.ERROR\n  local diagnostic_arr = {\n    { lnum = 0, end_lnum = 0, col = 3, end_col = 8, message = 'Error 1', severity = sev_err },\n    { lnum = 1, end_lnum = 1, col = 3, end_col = 9, message = 'Error 2', severity = sev_err },\n  }\n  local ns = child.api.nvim_create_namespace('mock-single-diagnostics')\n\n  local validate_edit_with_diagnostic = function(lines_before, cursor_before, keys, lines_after, cursor_after)\n    set_lines(lines_before)\n    child.diagnostic.set(ns, 0, diagnostic_arr, {})\n    set_cursor(cursor_before[1], cursor_before[2])\n\n    type_keys(keys)\n\n    eq(get_lines(), lines_after)\n    eq(get_cursor(), cursor_after)\n  end\n\n  validate_edit_with_diagnostic(lines, { 1, 1 }, 'd[D', { 'arror', 'aa Error2' }, { 1, 1 })\n  validate_edit_with_diagnostic(lines, { 2, 0 }, 'd[d', { 'aa a Error2' }, { 1, 3 })\n  validate_edit_with_diagnostic(lines, { 2, 0 }, 'd]d', { 'aa Error', 'rror2' }, { 2, 0 })\n  validate_edit_with_diagnostic(lines, { 1, 0 }, 'd]D', { 'rror2' }, { 1, 0 })\n\n  -- - Dot-repeat. On Neovim>=0.12 diagnostic is done via extmarks, which get\n  --   deleted if its text range is deleted. So on dot-repeat it goes to the\n  --   second position. On Neovim<0.12 it deletes twice up to { 1, 3 }.\n  local ref_lines = child.fn.has('nvim-0.12') == 1 and { 'aarror2' } or { 'aaor', 'aa Error2' }\n  validate_edit_with_diagnostic(lines, { 1, 2 }, 'd]d.', ref_lines, { 1, 2 })\nend\n\nT['Mappings']['diagnostic']['allows non-letter suffix'] = function()\n  reload_module({ diagnostic = { suffix = ',', options = { severity = { min = vim.diagnostic.severity.HINT } } } })\n\n  local cur_pos_tbl = setup_diagnostic()\n  local all = cur_pos_tbl.all\n  local n = #all\n\n  -- Only backward/forward should be mapped\n  validate_move(all[1], '[,', all[n])\n  validate_move(all[1], '],', all[2])\nend\n\nT['Mappings']['file'] = new_set()\n\nlocal validate_map_file = function(file_start, keys, file_ref)\n  edit_test_file(file_start)\n  type_keys(keys)\n  validate_test_file(file_ref)\nend\n\nT['Mappings']['file']['works'] = function()\n  local n = #test_files\n\n  validate_map_file(test_files[n], '[F', test_files[1])\n  validate_map_file(test_files[2], '2[f', test_files[n])\n  validate_map_file(test_files[1], ']f', test_files[2])\n  validate_map_file(test_files[n], '2]F', test_files[n - 1])\nend\n\nT['Mappings']['file']['allows non-letter suffix'] = function()\n  reload_module({ file = { suffix = ',' } })\n\n  local n = #test_files\n\n  -- Only backward/forward should be mapped\n  validate_map_file(test_files[1], '[,', test_files[n])\n  validate_map_file(test_files[1], '],', test_files[2])\nend\n\nT['Mappings']['indent'] = new_set()\n\nT['Mappings']['indent']['works'] = function()\n  local lines = { '1', ' 2', '  3', '   4', '  5', ' 6', '7' }\n  set_lines(lines)\n\n  -- Normal mode\n  validate_move({ 4, 3 }, '[I', { 1, 0 })\n  validate_move({ 4, 3 }, '2[i', { 2, 1 })\n  validate_move({ 4, 3 }, ']i', { 5, 2 })\n  -- - This target doesn't respect `[count]` for 'first'/'last'\n  validate_move({ 4, 3 }, '2]I', { 7, 0 })\n\n  -- Visual mode\n  validate_move({ 4, 3 }, 'v[I', { 1, 0 })\n  validate_move({ 4, 3 }, 'v2[i', { 2, 1 })\n  validate_move({ 4, 3 }, 'v]i', { 5, 2 })\n  validate_move({ 4, 3 }, 'v2]I', { 7, 0 })\n\n  -- Operator-pending mode\n  validate_edit(lines, { 4, 3 }, 'd[I', { '  5', ' 6', '7' }, { 1, 2 })\n  validate_edit(lines, { 4, 3 }, 'd[i', { '1', ' 2', '  5', ' 6', '7' }, { 3, 2 })\n  validate_edit(lines, { 4, 3 }, 'd]i', { '1', ' 2', '  3', ' 6', '7' }, { 4, 1 })\n  validate_edit(lines, { 4, 3 }, 'd]I', { '1', ' 2', '  3' }, { 3, 2 })\n\n  -- - Dot-repeat\n  -- - Final position is {3, 1} and not {3, 1} because it inherited column from\n  --   previous state when cursor was on ' 6' line\n  validate_edit(lines, { 4, 3 }, 'd]i.', { '1', ' 2', '  3' }, { 3, 1 })\nend\n\nT['Mappings']['indent']['allows non-letter suffix'] = function()\n  reload_module({ indent = { suffix = ',' } })\n\n  local lines = { '1', ' 2', '  3', ' 4', '5' }\n  set_lines(lines)\n\n  -- Only backward/forward should be mapped\n  validate_move({ 3, 2 }, '],', { 4, 1 })\n  validate_move({ 3, 2 }, '[,', { 2, 1 })\nend\n\nT['Mappings']['jump'] = new_set()\n\nT['Mappings']['jump']['works'] = function()\n  local cur_jump_inds, _, jump_list = setup_jumplist()\n  local n = #cur_jump_inds\n\n  local validate_jump_move = function(id_start, keys, id_ref)\n    child.ensure_normal_mode()\n\n    local s, e = cur_jump_inds[id_start], cur_jump_inds[id_ref]\n\n    set_jump_num(s)\n    type_keys(keys)\n    eq(get_jump_num(), e)\n    eq(get_cursor(), { jump_list[e].lnum, jump_list[e].col })\n\n    child.ensure_normal_mode()\n  end\n\n  -- Normal mode\n  validate_jump_move(n, '[J', 1)\n  validate_jump_move(2, '2[j', n)\n  validate_jump_move(1, ']j', 2)\n  validate_jump_move(n, '2]J', n - 1)\n\n  -- No Visual mode mappings (due to implementation difficulties)\n\n  -- Operator-pending mode\n  local validate_yank_weak = function(pos_before, keys)\n    set_cursor(pos_before[1], pos_before[2])\n    local register_before = child.fn.getreg('\"')\n\n    type_keys('y' .. keys)\n    eq(child.fn.getreg('\"') ~= register_before, true)\n  end\n\n  validate_yank_weak({ 1, 0 }, '[J')\n  validate_yank_weak({ 2, 0 }, '[j')\n  validate_yank_weak({ 3, 0 }, ']j')\n  validate_yank_weak({ 4, 0 }, ']J')\nend\n\nT['Mappings']['jump']['allows non-letter suffix'] = function()\n  reload_module({ jump = { suffix = ',' } })\n\n  local cur_jump_inds, _, jump_list = setup_jumplist()\n  local n = #cur_jump_inds\n\n  local validate_jump_move = function(id_start, keys, id_ref)\n    child.ensure_normal_mode()\n\n    local s, e = cur_jump_inds[id_start], cur_jump_inds[id_ref]\n\n    set_jump_num(s)\n    type_keys(keys)\n    eq(get_jump_num(), e)\n    eq(get_cursor(), { jump_list[e].lnum, jump_list[e].col })\n\n    child.ensure_normal_mode()\n  end\n\n  -- Only backward/forward should be mapped\n  validate_jump_move(1, '[,', n)\n  validate_jump_move(1, '],', 2)\nend\n\nT['Mappings']['location'] = new_set()\n\nlocal validate_map_location = function(id_start, keys, id_ref)\n  set_location(id_start)\n  type_keys(keys)\n  eq(get_location(), id_ref)\nend\n\nT['Mappings']['location']['works'] = function()\n  local loc_list = setup_location()\n  local n = #loc_list\n\n  validate_map_location(n, '[L', 1)\n  validate_map_location(2, '2[l', n)\n  validate_map_location(1, ']l', 2)\n  validate_map_location(n, '2]L', n - 1)\nend\n\nT['Mappings']['location']['allows non-letter suffix'] = function()\n  reload_module({ location = { suffix = ',' } })\n\n  local loc_list = setup_location()\n  local n = #loc_list\n\n  -- Only backward/forward should be mapped\n  validate_map_location(1, '[,', n)\n  validate_map_location(1, '],', 2)\nend\n\nT['Mappings']['oldfile'] = new_set()\n\nT['Mappings']['oldfile']['works'] = function()\n  local files = setup_oldfile()\n  local n = #files\n\n  local validate = function(keys, id_ref)\n    type_keys(keys)\n    validate_test_file(files[id_ref])\n  end\n\n  edit_test_file(files[n])\n\n  validate('[O', 1)\n  validate('2[o', n - 1)\n  validate(']o', n)\n  validate('2]O', n - 1)\nend\n\nT['Mappings']['oldfile']['allows non-letter suffix'] = function()\n  reload_module({ oldfile = { suffix = ',' } })\n\n  local files = setup_oldfile()\n  local n = #files\n  edit_test_file(files[n])\n\n  -- Only backward/forward should be mapped\n  type_keys('[,')\n  validate_test_file(files[n - 1])\n\n  type_keys('],')\n  validate_test_file(files[n])\nend\n\nT['Mappings']['quickfix'] = new_set()\n\nlocal validate_map_quickfix = function(id_start, keys, id_ref)\n  set_quickfix(id_start)\n  type_keys(keys)\n  eq(get_quickfix(), id_ref)\nend\n\nT['Mappings']['quickfix']['works'] = function()\n  local qf_list = setup_quickfix()\n  local n = #qf_list\n\n  validate_map_quickfix(n, '[Q', 1)\n  validate_map_quickfix(2, '2[q', n)\n  validate_map_quickfix(1, ']q', 2)\n  validate_map_quickfix(n, '2]Q', n - 1)\nend\n\nT['Mappings']['quickfix']['allows non-letter suffix'] = function()\n  reload_module({ quickfix = { suffix = ',' } })\n\n  local qf_list = setup_quickfix()\n  local n = #qf_list\n\n  -- Only backward/forward should be mapped\n  validate_map_quickfix(1, '[,', n)\n  validate_map_quickfix(1, '],', 2)\nend\n\nT['Mappings']['treesitter'] = new_set()\n\nT['Mappings']['treesitter']['works'] = function()\n  local nodes, _, inside_nodes = setup_treesitter()\n  local n = #nodes\n\n  -- Normal mode\n  validate_move(inside_nodes[n], '[T', nodes[1].from)\n  validate_move(inside_nodes[n], '2[t', nodes[n - 1].from)\n  validate_move(inside_nodes[n], ']t', nodes[n].to)\n  -- - This target doesn't respect `[count]` for 'first'/'last'\n  validate_move(inside_nodes[n], '2]T', nodes[1].to)\n\n  -- Visual mode\n  validate_move(inside_nodes[n], 'v[T', nodes[1].from)\n  validate_move(inside_nodes[n], 'v2[t', nodes[n - 1].from)\n  validate_move(inside_nodes[n], 'v]t', nodes[n].to)\n  validate_move(inside_nodes[n], 'v2]T', nodes[1].to)\n\n  -- Operator-pending mode\n  local lines = { '{ r { 1 { 2 { 3 } 2 } 1 } r }' }\n  local pos = { 1, 14 }\n  validate_edit(lines, pos, 'd[T', { '{ r  } 2 } 1 } r }' }, { 1, 4 })\n  validate_edit(lines, pos, 'd[t', { '{ r { 1 { 2  } 2 } 1 } r }' }, { 1, 12 })\n  validate_edit(lines, pos, 'd]t', { '{ r { 1 { 2 {  2 } 1 } r }' }, { 1, 14 })\n  validate_edit(lines, pos, 'd]T', { '{ r { 1 { 2 {  r }' }, { 1, 14 })\n\n  -- - Dot-repeat\n  validate_edit(lines, pos, 'd]t.', { '{ r { 1 { 2 {  1 } r }' }, { 1, 14 })\nend\n\nT['Mappings']['treesitter']['allows non-letter suffix'] = function()\n  reload_module({ treesitter = { suffix = ',' } })\n\n  local nodes, _, inside_nodes = setup_treesitter()\n  local n = #nodes\n\n  -- Only backward/forward should be mapped\n  validate_move(inside_nodes[n], '[,', nodes[n].from)\n  validate_move(inside_nodes[n], '],', nodes[n].to)\nend\n\nT['Mappings']['undo'] = new_set()\n\nT['Mappings']['undo']['works'] = function()\n  --stylua: ignore\n  local undos = setup_undo(\n    { 'i', 'one', '<Esc>' },    -- one\n    { 'i', ' two', '<Esc>' },   -- one two\n    { '0', 'daw' },             -- two\n    'u',                        -- one two\n    { 'A', ' three', '<Esc>' }, -- one two three\n    'u',                        -- one two\n    '<C-R>'                     -- one two three\n  )\n  local n = #undos\n  local validate = function(keys, id_ref)\n    type_keys(keys)\n    validate_undo(undos[id_ref].lines, undos[id_ref].state)\n  end\n\n  validate('[U', 1)\n  validate('2[u', n - 1)\n  validate(']u', n)\n  validate('2]U', n - 1)\nend\n\nT['Mappings']['undo']['allows non-letter suffix'] = function()\n  reload_module({ undo = { suffix = ',' } })\n\n  --stylua: ignore\n  local undos = setup_undo(\n    { 'i', 'one', '<Esc>' },    -- one\n    { 'i', ' two', '<Esc>' },   -- one two\n    { '0', 'daw' },             -- two\n    'u'                         -- one two\n  )\n  local n = #undos\n\n  -- Only backward/forward should be mapped\n  type_keys('[,')\n  validate_undo(undos[n - 1].lines, undos[n - 1].state)\n\n  type_keys('],')\n  validate_undo(undos[n].lines, undos[n].state)\nend\n\nT['Mappings']['window'] = new_set()\n\nlocal validate_map_window = function(winnr_start, keys, winnr_ref)\n  set_winnr(winnr_start)\n  type_keys(keys)\n  eq(get_winnr(), winnr_ref)\nend\n\nT['Mappings']['window']['works'] = function()\n  local winnr_list = setup_windows()\n  local n = #winnr_list\n\n  validate_map_window(winnr_list[n], '[W', winnr_list[1])\n  validate_map_window(winnr_list[2], '2[w', winnr_list[n])\n  validate_map_window(winnr_list[1], ']w', winnr_list[2])\n  validate_map_window(winnr_list[n], '2]W', winnr_list[n - 1])\nend\n\nT['Mappings']['window']['allows non-letter suffix'] = function()\n  reload_module({ window = { suffix = ',' } })\n\n  local winnr_list = setup_windows()\n  local n = #winnr_list\n\n  -- Only backward/forward should be mapped\n  validate_map_window(winnr_list[1], '[,', winnr_list[n])\n  validate_map_window(winnr_list[1], '],', winnr_list[2])\nend\n\nT['Mappings']['yank'] = new_set()\n\nT['Mappings']['yank']['works'] = function()\n  local yanks = setup_yank('one', 'two', 'three', 'four', 'five')\n  local n = #yanks\n  type_keys('p')\n  eq(get_lines(), yanks[n])\n\n  local validate = function(keys, id_ref)\n    type_keys(keys)\n    eq(get_lines(), yanks[id_ref])\n  end\n\n  validate('[Y', 1)\n  validate('2[y', n - 1)\n  validate(']y', n)\n  validate('2]Y', n - 1)\nend\n\nT['Mappings']['yank']['allows non-letter suffix'] = function()\n  reload_module({ yank = { suffix = ',' } })\n\n  local yanks = setup_yank('one', 'two', 'three', 'four', 'five')\n  local n = #yanks\n  type_keys('p')\n  eq(get_lines(), yanks[n])\n\n  -- Only backward/forward should be mapped\n  type_keys('[y')\n  eq(get_lines(), yanks[n - 1])\n\n  type_keys(']y')\n  eq(get_lines(), yanks[n])\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_bufremove.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('bufremove', config) end\nlocal unload_module = function() child.mini_unload('bufremove') end\nlocal win_get_buf = function(...) return child.api.nvim_win_get_buf(...) end\nlocal buf_get_option = function(...) return child.api.nvim_buf_get_option(...) end\n--stylua: ignore end\n\n-- Make helpers\nlocal setup_layout = function()\n  local res = {}\n\n  child.cmd('silent %bwipeout!')\n\n  -- Create two vertical windows (with ids 'win_left' and 'win_right') with the\n  -- same active buffer ('buf') but different alternate buffers (with ids\n  -- 'buf_left' and 'buf_right' respectively)\n  child.cmd('edit buf')\n  res['buf'] = child.api.nvim_get_current_buf()\n\n  child.cmd('edit buf_right')\n  res['buf_right'], res['win_right'] = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n\n  child.cmd('edit # | vsplit | edit buf_left')\n  res['buf_left'], res['win_left'] = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n\n  child.cmd('edit #')\n\n  return res\nend\n\nlocal validate_unshow_alternate = function(fun_name, layout)\n  eq(child.lua_get(('MiniBufremove.%s()'):format(fun_name)), true)\n\n  eq(win_get_buf(layout['win_left']), layout['buf_left'])\n  eq(win_get_buf(layout['win_right']), layout['buf_right'])\nend\n\nlocal validate_unshow_bprevious = function(fun_name, layout)\n  child.cmd('bwipeout ' .. layout['buf_left'])\n  local bprevious_buf = child.api.nvim_create_buf(true, false)\n\n  eq(child.lua_get(('MiniBufremove.%s()'):format(fun_name)), true)\n\n  eq(win_get_buf(layout['win_left']), bprevious_buf)\n  eq(win_get_buf(layout['win_right']), layout['buf_right'])\nend\n\nlocal validate_unshow_normal_buf = function(fun_name, layout)\n  -- Wipeout all buffers except current\n  child.cmd('.+,$bwipeout')\n\n  eq(child.lua_get(('MiniBufremove.%s()'):format(fun_name)), true)\n\n  -- Verify that created buffer is a normal buffer\n  local new_buf = child.api.nvim_get_current_buf()\n  expect.no_equality(new_buf, layout['buf'])\n  eq(buf_get_option(new_buf, 'buflisted'), true)\n  eq(buf_get_option(new_buf, 'buftype'), '')\n  -- Should be unnamed to allow `:h buffer-reuse`\n  eq(child.api.nvim_buf_get_name(new_buf), '')\n\n  eq(win_get_buf(layout['win_left']), new_buf)\n  eq(win_get_buf(layout['win_right']), new_buf)\nend\n\nlocal validate_unshow_cmdwin = function(fun_name)\n  child.cmd('only')\n\n  child.type_keys('q:')\n  eq(child.fn.getcmdwintype(), ':')\n  eq(#child.api.nvim_list_wins(), 2)\n\n  local command = ('MiniBufremove.%s()'):format(fun_name)\n  local out = child.lua_get(command)\n  eq(out, true)\n\n  eq(child.fn.getcmdwintype(), '')\n  eq(#child.api.nvim_list_wins(), 1)\nend\n\nlocal validate_args_validation = function(fun_name, args)\n  if vim.tbl_contains(args, 'buf_id') then\n    local command = ('MiniBufremove.%s(100)'):format(fun_name)\n    eq(child.lua_get(command), false)\n    local last_message = child.cmd_capture('1messages')\n    eq(last_message, '(mini.bufremove) 100 is not a valid buffer id.')\n  end\n\n  if args['force'] then\n    local command = ('MiniBufremove.%s(nil, 1)'):format(fun_name)\n    eq(child.lua_get(command), false)\n    local last_message = child.cmd_capture('1messages')\n    eq(last_message, '(mini.bufremove) `force` should be boolean.')\n  end\nend\n\nlocal validate_unshow_with_buf_id = function(fun_name, layout)\n  local command = ('MiniBufremove.%s(...)'):format(fun_name)\n  eq(child.lua_get(command, { layout['buf'] }), true)\n\n  eq(win_get_buf(layout['win_left']), layout['buf_left'])\n  eq(win_get_buf(layout['win_right']), layout['buf_right'])\nend\n\nlocal mock_confirm = function(user_choice)\n  local lua_cmd = string.format('vim.fn.confirm = function(...) _G.confirm_args = { ... }; return %d end', user_choice)\n  child.lua(lua_cmd)\nend\n\nlocal validate_force_argument = function(fun_name, layout)\n  child.api.nvim_buf_set_lines(layout['buf'], 0, -1, true, { 'aaa' })\n  -- Avoid hit-enter prompt due to long message\n  child.o.cmdheight = 10\n\n  -- Should ask for confirmation for modified buffer and no `force`\n  mock_confirm(1)\n  eq(child.bo.modified, true)\n  local output = child.lua_get(('MiniBufremove.%s()'):format(fun_name))\n  eq(output, false)\n\n  local prompt =\n    string.format('Buffer %d has unsaved changes. Do you want to force %s?', child.api.nvim_get_current_buf(), fun_name)\n  -- - Default choice should be 'No'\n  eq(child.lua_get('_G.confirm_args'), { prompt, '&No\\n&Yes', 1, 'Question' })\n\n  eq(win_get_buf(layout['win_left']), layout['buf'])\n  eq(win_get_buf(layout['win_right']), layout['buf'])\n\n  -- Should properly remove modified buffer after confirmation\n  mock_confirm(2)\n  eq(child.bo.modified, true)\n  output = child.lua_get(('MiniBufremove.%s()'):format(fun_name))\n  eq(output, true)\n  eq(win_get_buf(layout['win_left']), layout['buf_left'])\n  eq(win_get_buf(layout['win_right']), layout['buf_right'])\n\n  -- Should properly remove buffer with `force`\n  output = child.lua_get(('MiniBufremove.%s(nil, true)'):format(fun_name))\n  eq(output, true)\n  eq(win_get_buf(layout['win_left']), layout['buf_right'])\n  eq(win_get_buf(layout['win_right']), layout['buf_right'])\nend\n\nlocal validate_disable = function(var_type, fun_name, layout)\n  child[var_type].minibufremove_disable = true\n  local output = child.lua_get(('MiniBufremove.%s()'):format(fun_name))\n  eq(output, vim.NIL)\n\n  -- Check that lyout didn't change\n  eq(win_get_buf(layout['win_left']), layout['buf'])\n  eq(win_get_buf(layout['win_right']), layout['buf'])\nend\n\nlocal validate_silent = function(fun_name)\n  child.lua('MiniBufremove.config.silent = true')\n\n  local command = ('MiniBufremove.%s(-1)'):format(fun_name)\n  eq(child.lua_get(command), false)\n\n  -- Should show no message\n  eq(child.cmd_capture('1messages'), '')\nend\n\nlocal validate_bufhidden_option = function(fun_name, bufhidden_value)\n  local layout = setup_layout()\n  child.api.nvim_buf_set_option(layout['buf'], 'bufhidden', bufhidden_value)\n\n  local command = ('MiniBufremove.%s(...)'):format(fun_name)\n  local output = child.lua_get(command, { layout['buf'] })\n  eq(output, true)\n\n  if fun_name == 'wipeout' or bufhidden_value == 'wipe' then\n    eq(child.api.nvim_buf_is_valid(layout['buf']), false)\n  else\n    eq(buf_get_option(layout['buf'], 'buflisted'), false)\n  end\nend\n\n-- Output test set ============================================================\nlocal layout\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      layout = setup_layout()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniBufremove)'), 'table')\n\n  -- Sets appropriate settings\n  eq(child.lua_get('vim.o.hidden'), true)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniBufremove.config)'), 'table')\n\n  -- Check default values\n  eq(child.lua_get('MiniBufremove.config.silent'), false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ silent = true })\n  eq(child.lua_get('MiniBufremove.config.silent'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ silent = 'a' }, 'silent', 'boolean')\nend\n\nT['unshow()'] = new_set()\n\nT['unshow()']['uses alternate buffer'] = function()\n  validate_unshow_alternate('unshow', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow()']['uses `bprevious`'] = function()\n  validate_unshow_bprevious('unshow', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow()']['creates a stand-in listed buffer'] = function()\n  validate_unshow_normal_buf('unshow', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow()']['validates arguments'] = function() validate_args_validation('unshow', { 'buf_id' }) end\n\nT['unshow()']['closes command-line window'] = function() validate_unshow_cmdwin('unshow') end\n\nT['unshow()']['respects `buf_id` argument'] = function()\n  validate_unshow_with_buf_id('unshow', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow()']['respects `vim.{g,b}.minibufremove_disable`'] = new_set(\n  { parametrize = { { 'g' }, { 'b' } } },\n  { test = function(var_type) validate_disable(var_type, 'unshow', layout) end }\n)\n\nT['unshow()']['respects `config.silent`'] = function() validate_silent('unshow') end\n\nT['unshow_in_window()'] = new_set()\n\nT['unshow_in_window()']['uses alternate buffer'] = function()\n  eq(child.lua_get('MiniBufremove.unshow_in_window()'), true)\n  eq(win_get_buf(layout['win_left']), layout['buf_left'])\n  eq(win_get_buf(layout['win_right']), layout['buf'])\n\n  -- Ensure that buffer is not deleted\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow_in_window()']['uses `bprevious`'] = function()\n  child.cmd('bwipeout ' .. layout['buf_left'])\n  local previous_buf = child.api.nvim_create_buf(true, false)\n\n  eq(child.lua_get('MiniBufremove.unshow_in_window()'), true)\n  eq(win_get_buf(layout['win_left']), previous_buf)\n  eq(win_get_buf(layout['win_right']), layout['buf'])\n\n  -- Ensure that buffer is not deleted\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow_in_window()']['creates a normal buffer'] = function()\n  child.cmd('.+,$bwipeout')\n  eq(child.lua_get('MiniBufremove.unshow_in_window()'), true)\n\n  -- Verify that created buffer is normal buffer\n  local new_buf = child.api.nvim_get_current_buf()\n  eq(buf_get_option(new_buf, 'buflisted'), true)\n  eq(buf_get_option(new_buf, 'buftype'), '')\n\n  eq(win_get_buf(layout['win_left']), new_buf)\n  eq(win_get_buf(layout['win_right']), layout['buf'])\n\n  -- Ensure that buffer is not deleted\n  eq(buf_get_option(layout['buf'], 'buflisted'), true)\nend\n\nT['unshow_in_window()']['validates arguments'] = function()\n  eq(child.lua_get('MiniBufremove.unshow_in_window(100)'), false)\n  local last_message = child.cmd_capture('1messages')\n  eq(last_message, '(mini.bufremove) 100 is not a valid window id.')\nend\n\nT['unshow_in_window()']['respects `win_id` argument'] = function()\n  local output = child.lua_get('MiniBufremove.unshow_in_window(...)', { layout['win_left'] })\n  eq(output, true)\n  eq(win_get_buf(layout['win_left']), layout['buf_left'])\n  eq(win_get_buf(layout['win_right']), layout['buf'])\nend\n\nT['unshow_in_window()']['closes command-line window'] = function() validate_unshow_cmdwin('unshow_in_window') end\n\nT['unshow_in_window()']['respects `vim.{g,b}.minibufremove_disable`'] = new_set(\n  { parametrize = { { 'g' }, { 'b' } } },\n  { test = function(var_type) validate_disable(var_type, 'unshow_in_window', layout) end }\n)\n\nT['unshow_in_window()']['respects `config.silent`'] = function() validate_silent('unshow_in_window') end\n\nT['delete()'] = new_set()\n\nT['delete()']['uses alternate buffer'] = function()\n  validate_unshow_alternate('delete', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), false)\nend\n\nT['delete()']['uses `bprevious`'] = function()\n  validate_unshow_bprevious('delete', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), false)\nend\n\nT['delete()']['creates a stand-in listed buffer'] = function()\n  validate_unshow_normal_buf('delete', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), false)\nend\n\nT['delete()']['validates arguments'] = function() validate_args_validation('delete', { 'buf_id', 'force' }) end\n\nT['delete()']['closes command-line window'] = function() validate_unshow_cmdwin('delete') end\n\nT['delete()']['respects `buf_id` argument'] = function()\n  validate_unshow_with_buf_id('delete', layout)\n  eq(buf_get_option(layout['buf'], 'buflisted'), false)\nend\n\nT['delete()']['respects `force` argument'] = function() validate_force_argument('delete', layout) end\n\nT['delete()']['respects `vim.{g,b}.minibufremove_disable`'] = new_set(\n  { parametrize = { { 'g' }, { 'b' } } },\n  { test = function(var_type) validate_disable(var_type, 'delete', layout) end }\n)\n\nT['delete()']['respects `config.silent`'] = function() validate_silent('delete') end\n\nT['delete()'][\"works with different 'bufhidden' options\"] = function()\n  validate_bufhidden_option('delete', 'delete')\n  validate_bufhidden_option('delete', 'wipe')\nend\n\nT['wipeout()'] = new_set()\n\nT['wipeout()']['uses alternate buffer'] = function()\n  validate_unshow_alternate('wipeout', layout)\n  eq(child.api.nvim_buf_is_valid(layout['buf']), false)\nend\n\nT['wipeout()']['uses `bprevious`'] = function()\n  validate_unshow_bprevious('wipeout', layout)\n  eq(child.api.nvim_buf_is_valid(layout['buf']), false)\nend\n\nT['wipeout()']['creates a stand-in listed buffer'] = function()\n  validate_unshow_normal_buf('wipeout', layout)\n  eq(child.api.nvim_buf_is_valid(layout['buf']), false)\nend\n\nT['wipeout()']['validates arguments'] = function() validate_args_validation('wipeout', { 'buf_id', 'force' }) end\n\nT['wipeout()']['closes command-line window'] = function() validate_unshow_cmdwin('wipeout') end\n\nT['wipeout()']['respects `buf_id` argument'] = function()\n  validate_unshow_with_buf_id('wipeout', layout)\n  eq(child.api.nvim_buf_is_valid(layout['buf']), false)\nend\n\nT['wipeout()']['respects `force` argument'] = function() validate_force_argument('wipeout', layout) end\n\nT['wipeout()']['respects `vim.{g,b}.minibufremove_disable`'] = new_set(\n  { parametrize = { { 'g' }, { 'b' } } },\n  { test = function(var_type) validate_disable(var_type, 'wipeout', layout) end }\n)\n\nT['wipeout()']['respects `config.silent`'] = function() validate_silent('wipeout') end\n\nT['wipeout()'][\"works with different 'bufhidden' options\"] = function()\n  validate_bufhidden_option('wipeout', 'delete')\n  validate_bufhidden_option('wipeout', 'wipe')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_clue.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('clue', config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\nlocal get_window = function() return child.api.nvim_get_current_win() end\nlocal set_window = function(win_id) return child.api.nvim_set_current_win(win_id) end\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\n-- Mapping helpers\nlocal replace_termcodes = function(x) return child.api.nvim_replace_termcodes(x, true, true, true) end\n\nlocal reset_test_map_count = function(mode, lhs)\n  lhs = vim.fn.escape(replace_termcodes(lhs), [[\\]])\n  local lua_cmd = string.format([[_G['test_map_%s_%s'] = 0]], mode, lhs)\n  child.lua(lua_cmd)\nend\n\nlocal get_test_map_count = function(mode, lhs)\n  lhs = vim.fn.escape(replace_termcodes(lhs), [[\\]])\n  local lua_cmd = string.format([=[_G['test_map_%s_%s']]=], mode, lhs)\n  return child.lua_get(lua_cmd)\nend\n\nlocal make_test_map = function(mode, lhs, opts)\n  lhs = vim.fn.escape(replace_termcodes(lhs), [[\\]])\n  opts = opts or {}\n  opts.desc = 'LHS: ' .. vim.inspect(lhs)\n\n  reset_test_map_count(mode, lhs)\n\n  --stylua: ignore\n  local lua_cmd = string.format(\n    [[vim.keymap.set('%s', '%s', function() _G['test_map_%s_%s'] = _G['test_map_%s_%s'] + 1 end, %s)]],\n    mode, lhs,\n    mode, lhs,\n    mode, lhs,\n    vim.inspect(opts)\n  )\n  child.lua(lua_cmd)\nend\n\n-- Custom validators\nlocal validate_trigger_keymap = function(mode, keys, buf_id)\n  buf_id = buf_id or child.api.nvim_get_current_buf()\n  local lua_cmd = string.format(\n    [[vim.api.nvim_buf_call(%s, function() return vim.fn.maparg(%s, %s, false, true).desc end)]],\n    buf_id,\n    vim.inspect(keys),\n    vim.inspect(mode)\n  )\n  local map_desc = child.lua_get(lua_cmd)\n  if map_desc == vim.NIL then error('No such trigger.') end\n\n  local desc_pattern = 'keys after.*\"' .. vim.pesc(keys) .. '\"'\n  expect.match(map_desc, desc_pattern)\nend\n\nlocal validate_no_trigger_keymap = function(mode, keys, buf_id)\n  expect.error(function() validate_trigger_keymap(mode, keys, buf_id) end, 'No such trigger')\nend\n\nlocal validate_edit = function(lines_before, cursor_before, keys, lines_after, cursor_after)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n\n  child.ensure_normal_mode()\nend\n\nlocal validate_edit1d = function(line_before, col_before, keys, line_after, col_after)\n  validate_edit({ line_before }, { 1, col_before }, keys, { line_after }, { 1, col_after })\nend\n\nlocal validate_move = function(lines, cursor_before, keys, cursor_after)\n  validate_edit(lines, cursor_before, keys, lines, cursor_after)\nend\n\nlocal validate_move1d = function(line, col_before, keys, col_after)\n  validate_edit1d(line, col_before, keys, line, col_after)\nend\n\nlocal validate_selection = function(lines, cursor, keys, selection_from, selection_to, visual_mode)\n  visual_mode = visual_mode or 'v'\n  child.ensure_normal_mode()\n  set_lines(lines)\n  set_cursor(cursor[1], cursor[2])\n\n  type_keys(keys)\n\n  eq(child.fn.mode(), visual_mode)\n\n  -- Compute two correctly ordered edges\n  local from = { child.fn.line('v'), child.fn.col('v') - 1 }\n  local to = { child.fn.line('.'), child.fn.col('.') - 1 }\n  if to[1] < from[1] or (to[1] == from[1] and to[2] < from[2]) then\n    from, to = to, from\n  end\n  eq(from, selection_from)\n  eq(to, selection_to)\n\n  child.ensure_normal_mode()\nend\n\nlocal validate_selection1d = function(line, col, keys, selection_col_from, selection_col_to, visual_mode)\n  validate_selection({ line }, { 1, col }, keys, { 1, selection_col_from }, { 1, selection_col_to }, visual_mode)\nend\n\n-- Custom mocks\nlocal mock_comment_operators = function()\n  -- Imitate Lua commenting\n  child.lua([[\n    _G.comment_operator = function()\n      vim.o.operatorfunc = 'v:lua.operatorfunc'\n      return 'g@'\n    end\n\n    _G.comment_line = function() return _G.comment_operator() .. '_' end\n\n    _G.operatorfunc = function()\n      local from, to = vim.fn.line(\"'[\"), vim.fn.line(\"']\")\n      local lines = vim.api.nvim_buf_get_lines(0, from - 1, to, false)\n      local new_lines = vim.tbl_map(function(x) return '-- ' .. x end, lines)\n      vim.api.nvim_buf_set_lines(0, from - 1, to, false, new_lines)\n    end\n\n    vim.keymap.set('n', 'gc', _G.comment_operator, { expr = true, replace_keycodes = false })\n    vim.keymap.set('n', 'gcc', _G.comment_line, { expr = true, replace_keycodes = false })\n  ]])\nend\n\n-- Time constants\nlocal default_delay, postkeys_check_delay, redraw_interval = 1000, 50, 50\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function() child.setup() end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniClue)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniClue'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local validate_hl_group = function(name, ref) expect.match(child.cmd_capture('hi ' .. name), ref) end\n\n  validate_hl_group('MiniClueBorder', 'links to FloatBorder')\n  validate_hl_group('MiniClueDescGroup', 'links to DiagnosticFloatingWarn')\n  validate_hl_group('MiniClueDescSingle', 'links to NormalFloat')\n  validate_hl_group('MiniClueNextKey', 'links to DiagnosticFloatingHint')\n  validate_hl_group('MiniClueNextKeyWithPostkeys', 'links to DiagnosticFloatingError')\n  validate_hl_group('MiniClueSeparator', 'links to DiagnosticFloatingInfo')\n  validate_hl_group('MiniClueTitle', 'links to FloatTitle')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n\n  eq(child.lua_get('type(_G.MiniClue.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniClue.config.' .. field), value) end\n\n  expect_config('clues', {})\n  expect_config('triggers', {})\n\n  expect_config('window.delay', 1000)\n  expect_config('window.config', {})\n  expect_config('window.scroll_down', '<C-d>')\n  expect_config('window.scroll_up', '<C-u>')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  load_module({ window = { delay = 10 } })\n  eq(child.lua_get('MiniClue.config.window.delay'), 10)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n\n  expect_config_error({ clues = 'a' }, 'clues', 'table')\n  expect_config_error({ triggers = 'a' }, 'triggers', 'table')\n\n  expect_config_error({ window = 'a' }, 'window', 'table')\n  expect_config_error({ window = { delay = 'a' } }, 'window.delay', 'number')\n  expect_config_error({ window = { config = 'a' } }, 'window.config', 'table or callable')\n  expect_config_error({ window = { scroll_down = 1 } }, 'window.scroll_down', 'string')\n  expect_config_error({ window = { scroll_up = 1 } }, 'window.scroll_up', 'string')\nend\n\nT['setup()']['ensures colors'] = function()\n  load_module()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniClueBorder'), 'links to FloatBorder')\nend\n\nT['setup()']['creates mappings for `@` and `Q`'] = function()\n  load_module()\n  expect.match(child.lua_get(\"vim.fn.maparg('@', 'n', false, true).desc\"), 'macro.*mini%.clue')\n  expect.match(child.lua_get(\"vim.fn.maparg('Q', 'n', false, true).desc\"), 'macro.*mini%.clue')\n\n  -- Mappings should respect [count]\n  type_keys('qq', 'ia<Esc>', 'q')\n\n  type_keys('2@q')\n  eq(get_lines(), { 'aaa' })\n\n  type_keys('2Q')\n  eq(get_lines(), { 'aaaaa' })\n\n  -- Should not create mapping if it is already taken\n  child.api.nvim_set_keymap('n', 'Q', '<Cmd>echo 1<CR>', { desc = 'My Q' })\n  child.api.nvim_set_keymap('n', '@', '<Cmd>echo 2<CR>', { desc = 'My @' })\n\n  load_module()\n  eq(child.lua_get(\"vim.fn.maparg('Q', 'n', false, true).desc\"), 'My Q')\n  eq(child.lua_get(\"vim.fn.maparg('@', 'n', false, true).desc\"), 'My @')\nend\n\nT['setup()']['respects \"human-readable\" key names'] = function()\n  child.g.mapleader = '_'\n  make_test_map('n', '<Space><Space>')\n  make_test_map('n', '<Space><C-x>')\n  make_test_map('n', '<Leader>a')\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space><Space>', postkeys = '<Space>' },\n      { mode = 'n', keys = '<Space><C-x>', postkeys = '<Space>' },\n      { mode = 'n', keys = '<Leader>a', postkeys = '<Leader>' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' }, { mode = 'n', keys = '<Leader>' } },\n  })\n  validate_trigger_keymap('n', '<Space>')\n  validate_trigger_keymap('n', '_')\n\n  type_keys(' ', ' ', '<C-x>')\n  eq(get_test_map_count('n', '  '), 1)\n  eq(get_test_map_count('n', ' <C-x>'), 1)\n\n  type_keys('<Esc>')\n\n  type_keys('_', 'a', 'a')\n  eq(get_test_map_count('n', '_a'), 2)\nend\n\nT['setup()']['respects \"raw\" key names'] = function()\n  local ctrl_x = replace_termcodes('<C-x>')\n  make_test_map('n', '<Space><Space>')\n  make_test_map('n', '<Space><C-x>')\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '  ', postkeys = ' ' },\n      { mode = 'n', keys = ' ' .. ctrl_x, postkeys = ' ' },\n    },\n    triggers = { { mode = 'n', keys = ' ' } },\n  })\n  validate_trigger_keymap('n', '<Space>')\n\n  type_keys(' ', ' ', '<C-x>')\n  eq(get_test_map_count('n', '  '), 1)\n  eq(get_test_map_count('n', replace_termcodes(' <C-x>')), 1)\nend\n\nT['setup()']['creates triggers for already created buffers'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n\n  load_module({ triggers = { { mode = 'n', keys = 'g' } } })\n  validate_trigger_keymap('n', 'g')\n\n  validate_trigger_keymap('n', 'g', init_buf_id)\n  validate_trigger_keymap('n', 'g', other_buf_id)\nend\n\nT['setup()']['does not affect buffer-local options'] = function()\n  --stylua: ignore\n  child.restart({\n    '--cmd', 'let &rtp.=\",\".getcwd()',\n    -- Executing `setup()` before `vim.o.expandtab=true` might lead to the new\n    -- option value not take effect for not current buffers. Originally because\n    -- enabling triggers force loaded buffers that were not yet loaded, which\n    -- \"finalized\" default value as buffer-local value.\n    '--cmd', 'lua require(\"mini.clue\").setup({ triggers = { { mode = \"n\", keys = \"<Space>\" } } })',\n    '--cmd', 'lua vim.o.expandtab = true',\n    '--', 'file-a', 'file-b',\n  })\n  local validate = function(ref_buf_name)\n    local buf_name = child.api.nvim_buf_get_name(0)\n    eq(vim.fn.fnamemodify(buf_name, ':t'), ref_buf_name)\n    eq(child.bo.expandtab, true)\n    validate_trigger_keymap('n', '<Space>')\n  end\n\n  validate('file-a')\n  child.cmd('bnext')\n  validate('file-b')\n\n  -- Should still enable triggers if buffer is unloaded and then reloaded\n  child.cmd('bunload file-a')\n  child.cmd('edit file-a')\n  validate('file-a')\nend\n\nT['setup()']['creates triggers for an array of modes'] = function()\n  load_module({ triggers = { { mode = { 'n', 'x' }, keys = 'g' } } })\n  validate_trigger_keymap('n', 'g')\n  validate_trigger_keymap('x', 'g')\n  validate_no_trigger_keymap('c', 'g')\nend\n\nT['setup()']['creates triggers only in listed buffers'] = function()\n  local buf_id_nolisted = child.api.nvim_create_buf(false, true)\n  make_test_map('n', '<Space>a')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n  validate_no_trigger_keymap('n', '<Space>', buf_id_nolisted)\n\n  local buf_id_nolisted_new = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(buf_id_nolisted_new)\n  validate_no_trigger_keymap('n', '<Space>', buf_id_nolisted_new)\nend\n\nT['setup()']['ensures valid triggers on `LspAttach` event'] = function()\n  child.set_size(10, 40)\n  child.cmd([[au LspAttach * lua vim.keymap.set('n', '<Space>a', ':echo 1<CR>', { buffer = true })]])\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  child.cmd('doautocmd LspAttach')\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['setup()']['ensures valid triggers on selected special buffers'] = function()\n  local make_ft_buf = function(ft)\n    local buf_id = child.api.nvim_create_buf(false, true)\n    child.api.nvim_set_option_value('filetype', ft, { buf = buf_id })\n    return buf_id\n  end\n\n  local validate_trigger = function(ft, buf_id_existing)\n    child.api.nvim_set_current_buf(child.api.nvim_create_buf(false, true))\n    child.bo.filetype = ft\n    validate_trigger_keymap('n', '<Space>', 0)\n    validate_trigger_keymap('n', '<Space>', buf_id_existing)\n  end\n\n  child.cmd('au FileType help,git nmap <buffer> <Space>a :echo 1<CR>')\n\n  local buf_id_help = make_ft_buf('help')\n  local buf_id_git = make_ft_buf('git')\n\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  validate_trigger('help', buf_id_help)\n  validate_trigger('git', buf_id_git)\nend\n\nT['setup()'][\"works with 'mini.starter'\"] = function()\n  child.lua('require(\"mini.starter\").open()')\n  local triggers = {\n    { mode = 'n', keys = '<Space>' },\n    { mode = 'n', keys = 'g' },\n  }\n  load_module({ triggers = triggers, window = { delay = 0 } })\n\n  -- Should not override query updaters (common for \"g\", \"s\", \"z\" triggers)\n  validate_trigger_keymap('n', '<Space>', 0)\n  validate_no_trigger_keymap('n', 'g', 0)\nend\n\nT['setup()']['respects `vim.b.miniclue_disable`'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_var(other_buf_id, 'miniclue_disable', true)\n\n  load_module({ triggers = { { mode = 'n', keys = 'g' } } })\n  validate_trigger_keymap('n', 'g')\n\n  validate_trigger_keymap('n', 'g', init_buf_id)\n  validate_no_trigger_keymap('n', 'g', other_buf_id)\n\n  -- Should allow setting `vim.b.miniclue_disable` inside autocommand\n  child.lua([[vim.api.nvim_create_autocmd(\n    'BufAdd',\n    { callback = function(data) vim.b[data.buf].miniclue_disable = true end }\n  )]])\n  local another_buf_id = child.api.nvim_create_buf(true, false)\n  validate_no_trigger_keymap('n', 'g', another_buf_id)\nend\n\nT['setup()']['respects `vim.b.miniclue_config`'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  child.lua([[\n    _G.miniclue_config = { triggers = { { mode = 'n', keys = '<Space>' } } }\n    vim.b.miniclue_config = _G.miniclue_config\n\n    vim.api.nvim_create_autocmd(\n      'BufAdd',\n      { callback = function(data) vim.b[data.buf].miniclue_config = _G.miniclue_config end }\n    )]])\n\n  load_module({ triggers = { { mode = 'n', keys = 'g' } } })\n  validate_trigger_keymap('n', 'g', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(other_buf_id)\n  validate_trigger_keymap('n', 'g', other_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\nend\n\nT['setup()']['respects `vim.b.miniclue_config` in \"natural\" `FileType` event'] = function()\n  child.lua([[\n    vim.api.nvim_create_autocmd(\n      'FileType',\n      {\n        callback = function(data)\n          vim.b[data.buf].miniclue_config = { triggers = { { mode = 'n', keys = '<Space>' } } }\n        end\n      }\n    )]])\n\n  load_module()\n  child.cmd('edit tmp.lua')\n  validate_trigger_keymap('n', '<Space>')\nend\n\nT['enable_all_triggers()'] = new_set()\n\nlocal enable_all_triggers = forward_lua('MiniClue.enable_all_triggers')\n\nT['enable_all_triggers()']['works'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n  local disabled_buf_id = child.api.nvim_create_buf(true, false)\n  child.g.miniclue_disable = true\n  -- Should respect `vim.b.miniclue_disable`\n  child.api.nvim_buf_set_var(disabled_buf_id, 'miniclue_disable', true)\n\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_no_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', other_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', disabled_buf_id)\n\n  child.g.miniclue_disable = false\n\n  enable_all_triggers()\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', disabled_buf_id)\nend\n\nT['enable_all_triggers()']['respects `vim.b.miniclue_config`'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n  child.g.miniclue_disable = true\n\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_no_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', other_buf_id)\n\n  child.g.miniclue_disable = false\n  child.b.miniclue_config = { triggers = { { mode = 'n', keys = 'g' } } }\n\n  enable_all_triggers()\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_trigger_keymap('n', 'g', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\n  validate_no_trigger_keymap('n', 'g', other_buf_id)\nend\n\nT['enable_buf_triggers()'] = new_set()\n\nlocal enable_buf_triggers = forward_lua('MiniClue.enable_buf_triggers')\n\nT['enable_buf_triggers()']['works'] = function()\n  child.g.miniclue_disable = true\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_no_trigger_keymap('n', '<Space>')\n\n  child.g.miniclue_disable = false\n\n  -- Uses current buffer by default\n  enable_buf_triggers()\n  validate_trigger_keymap('n', '<Space>')\nend\n\nT['enable_buf_triggers()']['allows 0 for current buffer'] = function()\n  child.g.miniclue_disable = true\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_no_trigger_keymap('n', '<Space>')\n\n  child.g.miniclue_disable = false\n\n  enable_buf_triggers(0)\n  validate_trigger_keymap('n', '<Space>')\nend\n\nT['enable_buf_triggers()']['respects `buf_id`'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n\n  child.g.miniclue_disable = true\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  validate_no_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', other_buf_id)\n\n  child.g.miniclue_disable = false\n  enable_buf_triggers(init_buf_id)\n\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', other_buf_id)\nend\n\nT['enable_buf_triggers()']['can be used in non-listed buffers'] = function()\n  child.g.miniclue_disable = true\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  -- Scratch\n  local buf_id_scratch = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(buf_id_scratch)\n  validate_no_trigger_keymap('n', '<Space>')\n\n  child.g.miniclue_disable = false\n\n  enable_buf_triggers()\n  validate_trigger_keymap('n', '<Space>')\n\n  -- Help\n  child.g.miniclue_disable = true\n  child.cmd('help')\n  validate_no_trigger_keymap('n', '<Space>')\n\n  child.g.miniclue_disable = false\n\n  enable_buf_triggers()\n  validate_trigger_keymap('n', '<Space>')\nend\n\nT['enable_buf_triggers()']['validates arguments'] = function()\n  load_module()\n  expect.error(function() enable_buf_triggers('a') end, '`buf_id`.*buffer identifier')\nend\n\nT['enable_buf_triggers()']['respects `vim.b.miniclue_config`'] = function()\n  child.g.miniclue_disable = true\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_no_trigger_keymap('n', '<Space>')\n\n  child.b.miniclue_config = { triggers = { { mode = 'n', keys = 'g' } } }\n  child.g.miniclue_disable = false\n\n  enable_buf_triggers(0)\n  validate_trigger_keymap('n', '<Space>')\n  validate_trigger_keymap('n', 'g')\nend\n\nT['disable_all_triggers()'] = new_set()\n\nlocal disable_all_triggers = forward_lua('MiniClue.disable_all_triggers')\n\nT['disable_all_triggers()']['works'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n  local disabled_buf_id = child.api.nvim_create_buf(true, false)\n\n  -- Should respect `vim.b.miniclue_disable` and do nothing in disabled buffers\n  child.api.nvim_buf_set_var(disabled_buf_id, 'miniclue_disable', true)\n  child.api.nvim_buf_set_keymap(disabled_buf_id, 'n', '<Space>', '<Cmd>echo 1<CR>', {})\n  local has_custom_mapping_in_disabled_buffer = function()\n    local lua_cmd =\n      string.format([[vim.api.nvim_buf_call(%d, function() return vim.fn.maparg(' ', 'n') end)]], disabled_buf_id)\n    local rhs = child.lua_get(lua_cmd)\n    return rhs:find('echo 1') ~= nil\n  end\n\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' }, { mode = 'i', keys = '<C-R>' } } })\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_trigger_keymap('i', '<C-R>', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\n  validate_trigger_keymap('i', '<C-R>', other_buf_id)\n  eq(has_custom_mapping_in_disabled_buffer(), true)\n\n  disable_all_triggers()\n  validate_no_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_no_trigger_keymap('i', '<C-R>', init_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', other_buf_id)\n  validate_no_trigger_keymap('i', '<C-R>', other_buf_id)\n  eq(has_custom_mapping_in_disabled_buffer(), true)\nend\n\nT['disable_all_triggers()']['respects `vim.b.miniclue_config`'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n\n  child.b.miniclue_config = { triggers = { { mode = 'n', keys = 'g' } } }\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_trigger_keymap('n', 'g', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\n\n  disable_all_triggers()\n  validate_no_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_no_trigger_keymap('n', 'g', init_buf_id)\n  validate_no_trigger_keymap('n', '<Space>', other_buf_id)\nend\n\nT['disable_buf_triggers()'] = new_set()\n\nlocal disable_buf_triggers = forward_lua('MiniClue.disable_buf_triggers')\n\nT['disable_buf_triggers()']['works'] = function()\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' }, { mode = 'i', keys = '<C-R>' } } })\n  validate_trigger_keymap('n', '<Space>')\n  validate_trigger_keymap('i', '<C-R>')\n\n  -- Uses current buffer by default\n  disable_buf_triggers()\n  validate_no_trigger_keymap('n', '<Space>')\n  validate_no_trigger_keymap('i', '<C-R>')\nend\n\nT['disable_buf_triggers()']['allows 0 for current buffer'] = function()\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n\n  disable_buf_triggers(0)\n  validate_no_trigger_keymap('n', '<Space>')\nend\n\nT['disable_buf_triggers()']['respects `buf_id`'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  validate_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\n\n  disable_buf_triggers(init_buf_id)\n\n  validate_no_trigger_keymap('n', '<Space>', init_buf_id)\n  validate_trigger_keymap('n', '<Space>', other_buf_id)\nend\n\nT['disable_buf_triggers()']['validates arguments'] = function()\n  load_module()\n  expect.error(function() disable_buf_triggers('a') end, '`buf_id`.*buffer identifier')\nend\n\nT['disable_buf_triggers()']['respects `vim.b.miniclue_config`'] = function()\n  child.b.miniclue_config = { triggers = { { mode = 'n', keys = 'g' } } }\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n  validate_trigger_keymap('n', 'g')\n\n  disable_buf_triggers(0)\n  validate_no_trigger_keymap('n', '<Space>')\n  validate_no_trigger_keymap('n', 'g')\nend\n\nT['ensure_all_triggers()'] = new_set()\n\nlocal ensure_all_triggers = forward_lua('MiniClue.ensure_all_triggers')\n\nT['ensure_all_triggers()']['works'] = function()\n  child.set_size(10, 40)\n  make_test_map('n', '<Space>a')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  -- Create buffer-local mappings **after** enabling triggers which disrupts\n  -- trigger mapping (although it is `<nowait>`). `ensure_all_triggers()`\n  -- should fix this for all buffers.\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>b', ':echo 1CR>', {})\n\n  local buf_id_new = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_keymap(buf_id_new, 'n', '<Space>c', ':echo 2CR>', {})\n\n  ensure_all_triggers()\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('<Esc>')\n\n  child.api.nvim_set_current_buf(buf_id_new)\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['ensure_buf_triggers()'] = new_set()\n\nlocal ensure_buf_triggers = forward_lua('MiniClue.ensure_buf_triggers')\n\nT['ensure_buf_triggers()']['works'] = function()\n  child.set_size(10, 40)\n  make_test_map('n', '<Space>a')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  -- Create a buffer-local mapping **after** enabling triggers which disrupts\n  -- trigger mapping (although it is `<nowait>`). `ensure_buf_triggers()`\n  -- should fix this.\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>b', ':echo 1CR>', {})\n\n  ensure_buf_triggers()\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['ensure_buf_triggers()']['validates arguments'] = function()\n  load_module()\n  expect.error(function() ensure_buf_triggers('a') end, '`buf_id`.*buffer identifier')\nend\n\nT['set_mapping_desc()'] = new_set()\n\nlocal set_mapping_desc = forward_lua('MiniClue.set_mapping_desc')\n\nlocal validate_mapping_desc = function(mode, lhs, ref_desc) eq(child.fn.maparg(lhs, mode, false, true).desc, ref_desc) end\n\nT['set_mapping_desc()']['adds new description'] = function()\n  child.api.nvim_set_keymap('n', '<Space>a', ':echo 1<CR>', {})\n\n  load_module()\n  set_mapping_desc('n', '<Space>a', 'New desc')\n  validate_mapping_desc('n', '<Space>a', 'New desc')\nend\n\nT['set_mapping_desc()']['updates existing description'] = function()\n  child.api.nvim_set_keymap('n', '<Space>a', ':echo 1<CR>', { desc = 'Old desc' })\n\n  load_module()\n  set_mapping_desc('n', '<Space>a', 'New desc')\n  validate_mapping_desc('n', '<Space>a', 'New desc')\nend\n\nT['set_mapping_desc()']['prefers buffer-local mapping'] = function()\n  child.api.nvim_set_keymap('n', '<Space>a', ':echo 1<CR>', {})\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>a', ':echo 2<CR>', {})\n\n  load_module()\n  set_mapping_desc('n', '<Space>a', 'New desc')\n  validate_mapping_desc('n', '<Space>a', 'New desc')\n\n  child.api.nvim_buf_del_keymap(0, 'n', '<Space>a')\n  child.lua([[_G.map_data = vim.fn.maparg('<Space>a', 'n', false, true)]])\n  eq(child.lua_get('_G.map_data.desc'), vim.NIL)\n  eq(child.lua_get('_G.map_data.buffer'), 0)\nend\n\nT['set_mapping_desc()']['works for mapping with callback'] = function()\n  child.lua([[vim.keymap.set('n', '<Space>a', function() _G.been_here = true end)]])\n\n  load_module()\n  set_mapping_desc('n', '<Space>a', 'New desc')\n  child.lua([[_G.map_data = vim.fn.maparg('<Space>a', 'n', false, true)]])\n  eq(child.lua_get('_G.map_data.desc'), 'New desc')\n  eq(child.lua_get('type(_G.map_data.callback)'), 'function')\nend\n\nT['set_mapping_desc()']['validates input'] = function()\n  load_module()\n  expect.error(function() set_mapping_desc(1, 'aaa', 'New') end, '`mode`.*string')\n  expect.error(function() set_mapping_desc('n', 1, 'New') end, '`lhs`.*string')\n  expect.error(function() set_mapping_desc('n', 'aaa', 1) end, '`desc`.*string')\nend\n\nT['set_mapping_desc()']['handles incorrect usage'] = function()\n  load_module()\n\n  -- When no mapping found\n  expect.error(function() set_mapping_desc('n', 'aaa', 'New') end, 'No mapping found for mode \"n\" and LHS \"aaa\"')\n\n  -- When input is not valid\n  make_test_map('n', 'aaa')\n  expect.error(function() set_mapping_desc('n', 'aaa', 'Improper desc\\0') end, 'not a valid desc')\nend\n\nT['gen_clues'] = new_set()\n\nT['gen_clues']['g()'] = new_set()\n\nT['gen_clues']['g()']['works'] = function()\n  -- Check this only on Neovim>=0.11, as there are many new built-in mappings\n  if child.fn.has('nvim-0.11') == 0 then return end\n\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.g() },\n      triggers = { { mode = 'n', keys = 'g' }, { mode = 'x', keys = 'g' } },\n      window = { delay = 0, config = { width = 50 } },\n    })\n  ]])\n  child.cmd('unmap g%')\n\n  child.set_size(67, 55)\n  type_keys('g')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  child.set_size(19, 55)\n  type_keys('v', 'g')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['square_brackets()'] = new_set()\n\nT['gen_clues']['square_brackets()']['works'] = function()\n  -- Check this only on Neovim>=0.11, as there are many new built-in mappings\n  if child.fn.has('nvim-0.11') == 0 then return end\n  child.set_size(43, 66)\n\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.square_brackets() },\n      triggers = { { mode = 'n', keys = '[' }, { mode = 'n', keys = ']' } },\n      window = { delay = 0, config = { width = 66 } },\n    })\n  ]])\n\n  type_keys('[')\n  local ignore_text = child.fn.has('nvim-0.12') == 0 and { 28 } or {}\n  child.expect_screenshot({ ignore_text = ignore_text })\n  type_keys('<Esc>')\n  type_keys(']')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['z()'] = new_set()\n\nT['gen_clues']['z()']['works'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.z() },\n      triggers = { { mode = 'n', keys = 'z' }, { mode = 'x', keys = 'z' } },\n      window = { delay = 0, config = { width = 52 } },\n    })\n  ]])\n\n  child.set_size(51, 55)\n  type_keys('z')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  child.set_size(10, 55)\n  type_keys('v', 'z')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['windows()'] = new_set()\n\nT['gen_clues']['windows()']['works'] = function()\n  -- Check this only on Neovim>=0.10, as there are many new built-in mappings\n  if child.fn.has('nvim-0.10') == 0 then return end\n\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.windows() },\n      triggers = { { mode = 'n', keys = '<C-w>' } },\n      window = { delay = 0, config = { width = 45 } },\n    })\n  ]])\n\n  child.set_size(47, 48)\n  type_keys('<C-w>')\n  child.expect_screenshot()\n\n  child.set_size(15, 48)\n  type_keys('g')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['windows()']['respects `opts.submode_move`'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.windows({ submode_move = true }) },\n      triggers = { { mode = 'n', keys = '<C-w>' } },\n    })\n  ]])\n\n  local win_init = get_window()\n  local validate = function(keys_layouts)\n    -- Set up\n    set_window(win_init)\n    type_keys('<C-w>')\n\n    -- Test\n    for _, v in ipairs(keys_layouts) do\n      type_keys(v[1])\n      eq(child.fn.winlayout(), v[2])\n    end\n\n    -- Clean up\n    type_keys('<Esc>')\n    set_window(win_init)\n    child.cmd('only')\n  end\n\n  -- Left-right\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  local win_right = get_window()\n\n  validate({\n    { 'L', { 'row', { { 'leaf', win_right }, { 'leaf', win_init } } } },\n    { 'H', { 'row', { { 'leaf', win_init }, { 'leaf', win_right } } } },\n    { 'L', { 'row', { { 'leaf', win_right }, { 'leaf', win_init } } } },\n  })\n\n  -- Top-bottom\n  set_window(win_init)\n  child.cmd('rightbelow split')\n  local win_bottom = get_window()\n\n  validate({\n    { 'J', { 'col', { { 'leaf', win_bottom }, { 'leaf', win_init } } } },\n    { 'K', { 'col', { { 'leaf', win_init }, { 'leaf', win_bottom } } } },\n    { 'J', { 'col', { { 'leaf', win_bottom }, { 'leaf', win_init } } } },\n  })\n\n  -- Rotate up/left\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  local win_row_two = get_window()\n  child.cmd('rightbelow vertical split')\n  local win_row_three = get_window()\n\n  validate({\n    { 'R', { 'row', { { 'leaf', win_row_two }, { 'leaf', win_row_three }, { 'leaf', win_init } } } },\n    { 'R', { 'row', { { 'leaf', win_row_three }, { 'leaf', win_init }, { 'leaf', win_row_two } } } },\n  })\n\n  -- Rotate down/right\n  set_window(win_init)\n  child.cmd('rightbelow split')\n  local win_col_two = get_window()\n  child.cmd('rightbelow split')\n  local win_col_three = get_window()\n\n  validate({\n    { 'r', { 'col', { { 'leaf', win_col_three }, { 'leaf', win_init }, { 'leaf', win_col_two } } } },\n    { 'r', { 'col', { { 'leaf', win_col_two }, { 'leaf', win_col_three }, { 'leaf', win_init } } } },\n  })\n\n  -- Exchange\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  local win_two = get_window()\n  child.cmd('rightbelow vertical split')\n  local win_three = get_window()\n\n  validate({\n    { 'x', { 'row', { { 'leaf', win_two }, { 'leaf', win_init }, { 'leaf', win_three } } } },\n    { 'x', { 'row', { { 'leaf', win_init }, { 'leaf', win_two }, { 'leaf', win_three } } } },\n  })\nend\n\nT['gen_clues']['windows()']['respects `opts.submode_navigate`'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.windows({ submode_navigate = true }) },\n      triggers = { { mode = 'n', keys = '<C-w>' } },\n    })\n  ]])\n\n  local win_init = get_window()\n  local validate = function(keys_wins)\n    -- Set up\n    set_window(win_init)\n    type_keys('<C-w>')\n\n    -- Test\n    for _, v in ipairs(keys_wins) do\n      type_keys(v[1])\n      eq(get_window(), v[2])\n    end\n\n    -- Clean up\n    type_keys('<Esc>')\n    set_window(win_init)\n    child.cmd('only')\n  end\n\n  -- Left-right\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  local win_right = get_window()\n\n  validate({ { 'l', win_right }, { 'h', win_init }, { 'l', win_right } })\n\n  -- Next-previous\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  local win_next = get_window()\n\n  validate({ { 'w', win_next }, { 'W', win_init }, { 'w', win_next } })\n\n  -- Up-down\n  set_window(win_init)\n  child.cmd('rightbelow split')\n  local win_down = get_window()\n\n  validate({ { 'j', win_down }, { 'k', win_init }, { 'j', win_down } })\n\n  -- Top-bottom\n  set_window(win_init)\n  child.cmd('rightbelow split')\n  local win_bottom = get_window()\n\n  validate({ { 'b', win_bottom }, { 't', win_init }, { 'b', win_bottom } })\n\n  -- Last accessed\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  child.cmd('rightbelow vertical split')\n  local win_alt = get_window()\n\n  validate({ { 'p', win_alt }, { 'p', win_init }, { 'p', win_alt } })\n\n  -- Tabs\n  child.cmd('tabnew')\n  local win_tab = get_window()\n\n  validate({ { { 'g', 't' }, win_tab }, { { 'g', 'T' }, win_init }, { { 'g', '<Tab>' }, win_tab } })\nend\n\nT['gen_clues']['windows()']['respects `opts.submode_resize`'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.windows({ submode_resize = true }) },\n      triggers = { { mode = 'n', keys = '<C-w>' } },\n    })\n  ]])\n\n  local win_init = get_window()\n  local get_height = function() return child.api.nvim_win_get_height(0) end\n  local get_width = function() return child.api.nvim_win_get_width(0) end\n\n  -- Width\n  set_window(win_init)\n  child.cmd('rightbelow vertical split')\n  local init_width = get_width()\n\n  type_keys('<C-w>')\n\n  type_keys('>')\n  eq(get_width(), init_width + 1)\n  type_keys('>')\n  eq(get_width(), init_width + 2)\n\n  type_keys('<')\n  eq(get_width(), init_width + 1)\n  type_keys('<')\n  eq(get_width(), init_width)\n\n  type_keys('<Esc>')\n  set_window(win_init)\n  child.cmd('only')\n\n  -- Height\n  set_window(win_init)\n  child.cmd('rightbelow split')\n  local init_height = get_height()\n\n  type_keys('<C-w>')\n\n  type_keys('+')\n  eq(get_height(), init_height + 1)\n  type_keys('+')\n  eq(get_height(), init_height + 2)\n\n  type_keys('-')\n  eq(get_height(), init_height + 1)\n  type_keys('-')\n  eq(get_height(), init_height)\nend\n\nT['gen_clues']['builtin_completion()'] = new_set()\n\nT['gen_clues']['builtin_completion()']['works'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.builtin_completion() },\n      triggers = { { mode = 'i', keys = '<C-x>' } },\n      window = { delay = 0, config = { width = 40 } },\n    })\n  ]])\n  child.set_size(23, 45)\n\n  type_keys('i', '<C-x>')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['marks()'] = new_set()\n\nT['gen_clues']['marks()']['works'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.marks() },\n      triggers = {\n        { mode = 'n', keys = '`' },\n        { mode = 'n', keys = 'g`' },\n        { mode = 'n', keys = \"'\" },\n        { mode = 'n', keys = \"g'\" },\n        { mode = 'x', keys = '`' },\n        { mode = 'x', keys = 'g`' },\n        { mode = 'x', keys = \"'\" },\n        { mode = 'x', keys = \"g'\" },\n      },\n      window = { delay = 0, config = { width = 45 } },\n    })\n  ]])\n  child.set_size(20, 48)\n\n  -- Normal mode\n  type_keys(\"'\")\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  type_keys(\"g'\")\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  type_keys('`')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  type_keys('g`')\n  child.expect_screenshot()\n\n  -- Visual mode\n  type_keys('<Esc>')\n  type_keys('v', \"'\")\n  child.expect_screenshot()\n\n  type_keys('<Esc>', '<Esc>')\n  type_keys('v', \"g'\")\n  child.expect_screenshot()\n\n  type_keys('<Esc>', '<Esc>')\n  type_keys('v', '`')\n  child.expect_screenshot()\n\n  type_keys('<Esc>', '<Esc>')\n  type_keys('v', 'g`')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['registers()'] = new_set()\n\nT['gen_clues']['registers()']['works'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.registers() },\n      triggers = {\n        { mode = 'n', keys = '\"' },\n        { mode = 'x', keys = '\"' },\n        { mode = 'i', keys = '<C-r>' },\n        { mode = 'c', keys = '<C-r>' },\n      },\n      window = { delay = 0, config = { width = 45 } },\n    })\n  ]])\n  child.set_size(25, 48)\n\n  type_keys('\"')\n  child.expect_screenshot()\n\n  type_keys('<Esc>', 'v', '\"')\n  child.expect_screenshot()\n\n  type_keys('<Esc>', '<Esc>', 'i', '<C-r>')\n  child.expect_screenshot()\n  type_keys('<C-o>')\n  child.expect_screenshot()\n  type_keys('<BS>', '<C-p>')\n  child.expect_screenshot()\n  type_keys('<BS>', '<C-r>')\n  child.expect_screenshot()\n\n  type_keys('<Esc>', '<Esc>', ':', '<C-r>')\n  child.expect_screenshot()\n  type_keys('<C-o>')\n  child.expect_screenshot()\n  type_keys('<BS>', '<C-r>')\n  child.expect_screenshot()\nend\n\nT['gen_clues']['registers()']['respects `opts.show_contents`'] = function()\n  child.lua([[\n    local miniclue = require('mini.clue')\n    miniclue.setup({\n      clues = { miniclue.gen_clues.registers({ show_contents = true }) },\n      triggers = {\n        { mode = 'n', keys = '\"' },\n        { mode = 'x', keys = '\"' },\n        { mode = 'i', keys = '<C-r>' },\n        { mode = 'c', keys = '<C-r>' },\n      },\n      window = { delay = 0, config = { width = 30 } },\n    })\n  ]])\n  child.set_size(52, 35)\n\n  -- Mock constant clipboard for better reproducibility of system registers\n  -- (mostly on CI). As `setreg('+', '')` is not guaranteed to be working for\n  -- system clipboard, use `g:clipboard` which copies/pastes nothing.\n  child.lua([[\n    local empty = function() return '' end\n    vim.g.clipboard = {\n      name  = 'myClipboard',\n      copy  = { ['+'] = empty, ['*'] = empty },\n      paste = { ['+'] = empty, ['*'] = empty },\n    }\n  ]])\n\n  -- Populate registers\n  set_lines({ 'aaa', 'bbb' })\n  type_keys('\"ayiw')\n  type_keys('\"xyip')\n  type_keys('G', 'yiw')\n  type_keys('gg', 'diw')\n\n  type_keys('\"')\n  child.expect_screenshot()\n\n  -- Assume all other triggers also show contents\nend\n\n-- Integration tests ==========================================================\nT['Showing keys'] = new_set({ hooks = { pre_case = function() child.set_size(10, 40) end } })\n\nT['Showing keys']['works'] = function()\n  helpers.skip_if_slow()\n\n  make_test_map('n', '<Space>aa')\n  make_test_map('n', '<Space>ab')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  -- Window should be shown after debounced delay\n  type_keys(' ')\n  sleep(default_delay - small_time)\n  child.expect_screenshot()\n\n  type_keys('a')\n  sleep(default_delay - small_time)\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  -- Should use proper buffer name\n  local buf_id = child.api.nvim_win_get_buf(1002)\n  eq(child.api.nvim_buf_get_name(buf_id), 'miniclue://' .. buf_id .. '/content')\nend\n\nT['Showing keys']['respects `config.window.delay`'] = function()\n  helpers.skip_if_slow()\n\n  make_test_map('n', '<Space>aa')\n  make_test_map('n', '<Space>ab')\n  load_module({\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0.5 * default_delay },\n  })\n\n  type_keys(' ')\n  sleep(0.5 * default_delay - small_time)\n  child.expect_screenshot()\n\n  type_keys('a')\n  sleep(0.5 * default_delay - small_time)\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n  child.expect_screenshot()\nend\n\nT['Showing keys']['allows zero delay'] = function()\n  make_test_map('n', '<Space>a')\n  load_module({\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  -- Window should be shown immediately\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['respects `config.window.config`'] = function()\n  make_test_map('n', '<Space>a')\n  load_module({\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0, config = { border = 'double', title = 'Custom title to check truncation' } },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('<Esc>')\n\n  -- Should properly truncate title\n  child.lua([[\n    local title = string.sub('abcdefgijklmnopqrstuvwxyzabcdefgijklmnopqrstuvwxyz', -vim.o.columns)\n    MiniClue.config.window.config = { width = vim.o.columns, title = title }\n  ]])\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  make_test_map('n', '<Space>a')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  local validate = function(winborder)\n    child.o.winborder = winborder\n    type_keys(' ')\n    child.expect_screenshot()\n    type_keys('<Esc>')\n  end\n\n  validate('rounded')\n\n  -- Should prefer explicitly configured value over 'winborder'\n  child.lua('MiniClue.config.window.config.border = \"double\"')\n  validate('rounded')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.lua('MiniClue.config.window.config.border = nil')\n  validate('+,-,+,|,+,-,+,|')\nend\n\nT['Showing keys']['can have `config.window.config.width=\"auto\"`'] = function()\n  make_test_map('n', '<Space>a')\n  load_module({\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0, config = { width = 'auto' } },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['can have callable `config.window.config`'] = function()\n  make_test_map('n', '<Space>a')\n  make_test_map('n', '<Space>b')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  -- Should be called with buffer identifier with already set lines\n  child.lua([[MiniClue.config.window.config = function(buf_id)\n    -- Should also allow special non-built-in values\n    return { height = vim.api.nvim_buf_line_count(buf_id) + 2, width = 'auto' }\n  end]])\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['can have \"auto\" for `row` and `col` in window config'] = function()\n  make_test_map('n', '<Space>a')\n  load_module({\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0, config = { row = 'auto', col = 'auto' } },\n  })\n\n  -- Should \"stick\" to anchor ('SE' by default)\n  type_keys(' ')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  child.lua('MiniClue.config.window.config.anchor = \"SW\"')\n  type_keys(' ')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  child.lua('MiniClue.config.window.config.anchor = \"NW\"')\n  type_keys(' ')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  child.lua('MiniClue.config.window.config.anchor = \"NE\"')\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['can work with small instance dimensions'] = function()\n  --Stylua: ignore\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a' },\n      { mode = 'n', keys = '<Space>b' },\n      { mode = 'n', keys = '<Space>c' },\n      { mode = 'n', keys = '<Space>d' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  child.set_size(5, 12)\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['indicates that description is truncated'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'A very long description' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0, config = { width = 15 } },\n  })\n\n  child.set_size(5, 20)\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['uses query clue as title'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'Group a' },\n      { mode = 'n', keys = '<Space>aa', desc = 'Subgroup aa' },\n      { mode = 'n', keys = '<Space>ba', desc = 'Subgroup ba' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0, config = { width = 20 } },\n  })\n\n  child.api.nvim_set_keymap('n', '<Space>aaa', '<Nop>', { desc = 'Do aaa' })\n  child.api.nvim_set_keymap('n', '<Space>aab', '<Nop>', { desc = 'Do aab' })\n  child.api.nvim_set_keymap('n', '<Space>baa', '<Nop>', { desc = 'Do baa' })\n  child.api.nvim_set_keymap('n', '<Space>bab', '<Nop>', { desc = 'Do bab' })\n  child.api.nvim_set_keymap('n', '<Space>caa', '<Nop>', { desc = 'Do caa' })\n\n  child.set_size(10, 30)\n  local validate = function(keys)\n    type_keys(keys)\n    child.expect_screenshot()\n  end\n\n  -- Should show trigger keys (not description/clue)\n  validate(' ')\n  -- Should show `<Space>a` clue\n  validate('a')\n  -- Should show `<Space>aa` clue, even if is a subgroup\n  validate('a')\n  -- Should work after `<BS>`\n  validate('<BS>')\n  -- Should fall back to showing keys if they have no clue\n  type_keys('<BS>')\n  validate('b')\n  -- Should try using only current subgroup (even if there is no parent clue)\n  validate('a')\n  -- Should work for a group with 1 key\n  type_keys('<BS>', '<BS>')\n  validate('c')\n  validate('a')\nend\n\nT['Showing keys']['respects `scroll_down` and `scroll_up` in `config.window`'] = function()\n  child.set_size(8, 40)\n\n  --stylua: ignore\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a' }, { mode = 'n', keys = '<Space>b' },\n      { mode = 'n', keys = '<Space>c' }, { mode = 'n', keys = '<Space>d' },\n      { mode = 'n', keys = '<Space>e' }, { mode = 'n', keys = '<Space>f' },\n      { mode = 'n', keys = '<Space>g' }\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  -- With default key\n  type_keys(' ')\n  child.expect_screenshot()\n\n  -- Should not change `'scroll'` window option\n  child.lua('_G.clue_win_id = math.max(unpack(vim.api.nvim_list_wins()))')\n  local clue_win_scroll_value = child.lua_get('vim.wo[_G.clue_win_id].scroll')\n  local validate_scroll_opt = function() eq(child.lua_get('vim.wo[_G.clue_win_id].scroll'), clue_win_scroll_value) end\n\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  -- - Should not be able to scroll past edge\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  validate_scroll_opt()\n\n  type_keys('<C-u>')\n  child.expect_screenshot()\n  -- - Should not be able to scroll past edge\n  type_keys('<C-u>')\n  child.expect_screenshot()\n  validate_scroll_opt()\n\n  type_keys('<Esc>')\n\n  -- With different keys\n  child.lua([[MiniClue.config.window.scroll_down = '<C-f>']])\n  child.lua([[MiniClue.config.window.scroll_up = '<C-b>']])\n\n  type_keys(' ')\n  child.expect_screenshot()\n\n  type_keys('<C-f>')\n  child.expect_screenshot()\n\n  type_keys('<C-b>')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n\n  -- With empty string (should disable special treatment)\n  child.lua([[MiniClue.config.window.scroll_down = '']])\n  child.lua([[MiniClue.config.window.scroll_up = '']])\n\n  type_keys('<Space>', '<C-d>')\n  child.expect_screenshot()\n\n  type_keys('<Space>', '<C-u>')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['highlights group descriptions differently'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'Single #1' },\n      { mode = 'n', keys = '<Space>b', desc = '+Group' },\n      { mode = 'n', keys = '<Space>c', desc = 'Single #2' },\n      { mode = 'n', keys = '<Space>ba' },\n      { mode = 'n', keys = '<Space>bb' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['highlights next key with postkeys differently'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'Without postkeys #1' },\n      { mode = 'n', keys = '<Space>b', desc = 'With postkey', postkeys = '<Space>' },\n      { mode = 'n', keys = '<Space>c', desc = 'Without postkeys #2' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['scroll is not persistent'] = function()\n  child.set_size(7, 40)\n  --stylua: ignore\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a' }, { mode = 'n', keys = '<Space>b' },\n      { mode = 'n', keys = '<Space>c' }, { mode = 'n', keys = '<Space>d' },\n      { mode = 'n', keys = '<Space>e' }, { mode = 'n', keys = '<Space>f' },\n\n      { mode = 'n', keys = '<Space>ga' }, { mode = 'n', keys = '<Space>gb' },\n      { mode = 'n', keys = '<Space>gc' }, { mode = 'n', keys = '<Space>gd' },\n      { mode = 'n', keys = '<Space>ge' }, { mode = 'n', keys = '<Space>gf' },\n\n      { mode = 'n', keys = '_a' }, { mode = 'n', keys = '_b' },\n      { mode = 'n', keys = '_c' }, { mode = 'n', keys = '_d' },\n      { mode = 'n', keys = '_e' }, { mode = 'n', keys = '_f' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' }, { mode = 'n', keys = '_' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ', '<C-d>', '<C-d>', '<C-d>', '<C-d>')\n  child.expect_screenshot()\n\n  type_keys('g')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  type_keys('_')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['properly translates special keys'] = function()\n  make_test_map('n', '<Space><Space><<f')\n  make_test_map('n', '<Space><Space><<g')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('<')\n  child.expect_screenshot()\n  type_keys('<')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['respects tabline, statusline, cmdheight'] = function()\n  child.set_size(7, 40)\n\n  --stylua: ignore\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a' }, { mode = 'n', keys = '<Space>b' },\n      { mode = 'n', keys = '<Space>c' }, { mode = 'n', keys = '<Space>d' },\n      { mode = 'n', keys = '<Space>e' }, { mode = 'n', keys = '<Space>f' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  local validate = function(screenshot_opts)\n    type_keys(' ')\n    child.expect_screenshot(screenshot_opts)\n    type_keys('<Esc>')\n  end\n\n  -- Tabline\n  child.o.showtabline = 2\n  validate({ ignore_text = { 1 }, ignore_attr = { 1 } })\n  child.o.showtabline = 0\n\n  -- Statusline\n  child.o.laststatus = 0\n  validate()\n  child.o.laststatus = 2\n\n  -- Command line height\n  child.o.cmdheight = 2\n  validate({ ignore_text = { 6, 7 }, ignore_attr = { 6, 7 } })\n\n  -- - Zero command line height\n  child.o.cmdheight = 0\n  validate()\nend\n\nT['Showing keys']['works with small available dimensions'] = function()\n  -- Check this only on Neovim>=0.12, as there is a slight change in\n  -- highlighting command line area\n  if child.fn.has('nvim-0.12') == 0 then return end\n\n  child.set_size(5, 40)\n  child.o.showtabline, child.o.laststatus = 0, 0\n  child.o.cmdheight = 4\n\n  load_module({\n    clues = { { mode = 'n', keys = '<Space>a' }, { mode = 'n', keys = '<Space>b' } },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['reacts to `VimResized`'] = function()\n  child.set_size(7, 20)\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a' },\n      { mode = 'n', keys = '<Space>b' },\n      { mode = 'n', keys = '<Space>c' },\n      { mode = 'n', keys = '<Space>d' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n\n  child.set_size(10, 40)\n  child.expect_screenshot()\nend\n\nT['Showing keys']['works with multibyte characters'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>f', desc = 'Single-byte #1' },\n      { mode = 'n', keys = '<Space>y', desc = 'Single-byte #2' },\n      { mode = 'n', keys = '<Space>ф', desc = 'Не англомовний опис' },\n      { mode = 'n', keys = '<Space>ы', desc = 'Тест на коректну ширину' },\n      { mode = 'n', keys = '<Space>э', desc = 'Многобайтовая группа' },\n      { mode = 'n', keys = '<Space>эю', desc = 'фыва' },\n      { mode = 'n', keys = '<Space>эя', desc = 'йцукен' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0, config = { width = 'auto' } },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n  helpers.skip_on_windows('Windows has different collation order')\n  type_keys('э')\n  child.expect_screenshot()\nend\n\nT['Showing keys']['works in Command-line window'] = function()\n  make_test_map('n', '<Space>f')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n  child.o.timeoutlen = small_time\n\n  type_keys('q:')\n  type_keys(' ')\n\n  child.expect_screenshot()\n\n  sleep(small_time + small_time)\n  type_keys('f')\n\n  -- Closing floating window is allowed only on Neovim>=0.10.\n  -- See https://github.com/neovim/neovim/issues/24452 .\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  eq(get_test_map_count('n', '<Space>f'), 1)\n\n  type_keys(':q<CR>')\nend\n\nT['Showing keys']['does not trigger unnecessary events'] = function()\n  make_test_map('n', '<Space>aa')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  -- Window should be shown after debounced delay\n  child.cmd('au BufEnter,BufWinEnter,BufLeave * lua _G.n_events = (_G.n_events or 0) + 1')\n  type_keys(' ')\n  child.expect_screenshot()\n\n  type_keys('a', 'a')\n  eq(get_test_map_count('n', ' aa'), 1)\n  eq(child.lua_get('_G.n_events'), vim.NIL)\nend\n\nT['Showing keys']['respects `vim.b.miniclue_config`'] = function()\n  make_test_map('n', '<Space>a')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n  child.b.miniclue_config = { window = { config = { width = 20 } } }\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues'] = new_set({ hooks = { pre_case = function() child.set_size(10, 40) end } })\n\nT['Clues']['can be configured after load'] = function()\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n  child.lua([[MiniClue.config.clues = { { mode = 'n', keys = '<Space>a' } }]])\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['uses human-readable names for special keys'] = function()\n  child.set_size(20, 40)\n  child.cmd('nmap <Space><Space> :echo 1<CR>')\n  child.cmd('nmap <Space><Tab> :echo 2<CR>')\n  child.cmd('nmap <Space><End> :echo 3<CR>')\n  child.cmd('nmap <Space><PageUp> :echo 4<CR>')\n  child.cmd('nmap <Space><C-x> :echo 5<CR>')\n  child.cmd('nmap <Space><C-j> :echo 6<CR>')\n  child.cmd('nmap <Space><C-S-j> :echo 6.1<CR>')\n  child.cmd('nmap <Space><C-M-j> :echo 6.2<CR>')\n  child.cmd('nmap <Space><Right> :echo 7<CR>')\n  child.cmd('nmap <Space><C-Right> :echo 8<CR>')\n  child.cmd('nmap <Space><S-Right> :echo 9<CR>')\n  child.cmd('nmap <Space><kRight> :echo 10<CR>')\n  child.cmd('nmap <Space>< :echo 11<CR>')\n  child.cmd('nmap <Space><F1> :echo 12<CR>')\n  child.cmd('nmap <Space><S-F1> :echo 13<CR>')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['are properly sorted'] = function()\n  child.set_size(15, 40)\n  --stylua: ignore\n  local lhs_arr = {\n    '<Space>0',     '<Space>9',     '<Space>a', '<Space>A', '<Space>x', '<Space>X',\n    '<Space><C-a>', '<Space><C-x>', '<Space>:', '<Space>/'\n  }\n  vim.tbl_map(function(lhs) make_test_map('n', lhs) end, lhs_arr)\n\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['has proper precedence'] = function()\n  -- config.clue < global mapping desc < buffer mapping desc.\n  -- If mapping doesn't have description, clue should use empty string because\n  -- it shows the most accurate information.\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>a', '<Nop>', { desc = 'Buffer-local <Space>a' })\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>b', '<Nop>', {})\n  child.api.nvim_set_keymap('n', '<Space>a', '<Nop>', { desc = 'Global <Space>a' })\n  child.api.nvim_set_keymap('n', '<Space>b', '<Nop>', { desc = 'Global <Space>b' })\n  child.api.nvim_set_keymap('n', '<Space>c', '<Nop>', { desc = 'Global <Space>c' })\n  child.api.nvim_set_keymap('n', '<Space>d', '<Nop>', {})\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'Clue <Space>a' },\n      { mode = 'n', keys = '<Space>b', desc = 'Clue <Space>b' },\n      { mode = 'n', keys = '<Space>c', desc = 'Clue <Space>c' },\n      { mode = 'n', keys = '<Space>d', desc = 'Clue <Space>d' },\n      { mode = 'n', keys = '<Space>e', desc = 'Clue <Space>e' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['handles no description'] = function()\n  child.api.nvim_set_keymap('n', '<Space>a', '<Nop>', {})\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>b' },\n      { mode = 'n', keys = '<Space>ca' },\n      { mode = 'n', keys = '<Space>cb' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['handles an array of modes'] = function()\n  load_module({\n    clues = { { mode = { 'n', 'x' }, keys = '<Space>a', desc = 'Clue <Space>a' } },\n    triggers = { { mode = { 'n', 'x' }, keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  type_keys('v', ' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['shows as group a single non-exact clue'] = function()\n  load_module({\n    clues = { { mode = 'n', keys = '<Space>aaa', desc = 'Clue <Space>a' } },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\nend\n\nT['Clues']['can have nested subarrays'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a' },\n      { { mode = 'n', keys = '<Space>b' } },\n      { { { mode = 'n', keys = '<Space>c' } } },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['can have callables'] = function()\n  child.lua([[\n    _G.callable_clue_direct = function() return { mode = 'n', keys = '<Space>a' } end\n    _G.callable_clue_direct_with_callable_desc = function()\n      return { mode = 'n', keys = '<Space>b', desc = function() return 'From <Space>b callable' end }\n    end\n    _G.callable_clue_array = function()\n      return {\n        { mode = 'n', keys = '<Space>c' },\n        { mode = 'n', keys = '<Space>d', desc = function() return 'From <Space>d callable' end },\n      }\n    end\n  ]])\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } }, window = { delay = 0 } })\n\n  local validate = function()\n    type_keys(' ')\n    child.expect_screenshot()\n    type_keys('<Esc>')\n  end\n\n  -- Direct\n  child.lua([[MiniClue.config.clues = { _G.callable_clue_direct }]])\n  validate()\n\n  -- Nested in subarray\n  child.lua([[MiniClue.config.clues = { { _G.callable_clue_direct } }]])\n  validate()\n\n  -- With callable description\n  child.lua([[MiniClue.config.clues = { _G.callable_clue_direct_with_callable_desc }]])\n  validate()\n\n  -- Returns array of clues with normal and callable descriptions\n  child.lua([[MiniClue.config.clues = { _G.callable_clue_array }]])\n  validate()\nend\n\nT['Clues']['can have callable description'] = function()\n  child.lua([[\n    require('mini.clue').setup({\n      clues = { { mode = 'n', keys = '<Space>a', desc = function() return 'From callable desc' end } },\n      triggers = { { mode = 'n', keys = '<Space>' } },\n      window = { delay = 0 },\n    })\n  ]])\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['silently ignores non-valid clues'] = function()\n  load_module({\n    clues = {\n      -- Valid\n      { mode = 'n', keys = '<Space>a' },\n\n      -- Non-valid\n      '<Space>b',\n      { mode = 1, keys = '<Space>c' },\n      { mode = 'n', keys = 1 },\n      { mode = 'n', keys = '<Space>e', desc = 1 },\n      { mode = 'n', keys = '<Space>f', postkeys = 1 },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['can be overridden in later entries'] = function()\n  -- Like if there is table entry which later is partially overridden in\n  -- user-supplied one\n  load_module({\n    clues = {\n      { { mode = 'n', keys = '<Space>a', desc = 'First <Space>a' } },\n      { mode = 'n', keys = '<Space>a', desc = 'Second <Space>a' },\n\n      { mode = 'n', keys = '<Space>b', desc = 'First <Space>b' },\n      { mode = 'n', keys = '<Space>b', postkeys = '<Space>' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Clues']['handles showing group clues after executing key with postkeys'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>ga')\n  make_test_map('n', '<Space>gb')\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>f', desc = 'With postkeys', postkeys = '<Space>' },\n      { mode = 'n', keys = '<Space>g', desc = 'Group' },\n      { mode = 'n', keys = '<Space>ga', desc = 'Key a' },\n      { mode = 'n', keys = '<Space>gb', desc = 'Key b' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ', 'f')\n  child.expect_screenshot()\n  type_keys('g')\n  child.expect_screenshot()\nend\n\nT['Clues']['respects `vim.b.miniclue_config`'] = function()\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'From global config' },\n      { mode = 'n', keys = '<Space>b' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n  child.b.miniclue_config = {\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'From buffer-local config' },\n      { mode = 'n', keys = '<Space>c' },\n    },\n  }\n\n  type_keys(' ')\n  child.expect_screenshot()\nend\n\nT['Postkeys'] = new_set({ hooks = { pre_case = function() child.set_size(10, 40) end } })\n\nT['Postkeys']['works'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>x')\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>f', postkeys = '<Space>' },\n      { mode = 'n', keys = '<Space>x', postkeys = '<Space>' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('f')\n  child.expect_screenshot()\n  type_keys('x')\n  child.expect_screenshot()\n\n  type_keys('f', '<Esc>')\n\n  eq(get_test_map_count('n', ' f'), 2)\n  eq(get_test_map_count('n', ' x'), 1)\nend\n\nT['Postkeys']['works in edge cases'] = function()\n  -- With \"looped\" submodes\n  make_test_map('n', '<Space>a')\n  make_test_map('n', '_b')\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', postkeys = '_' },\n      { mode = 'n', keys = '_b', postkeys = '<Space>' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' }, { mode = 'n', keys = '_' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\n  type_keys('b')\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n\n  eq(get_test_map_count('n', ' a'), 1)\n  eq(get_test_map_count('n', '_b'), 1)\nend\n\nT['Postkeys']['shows window immediately'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>x')\n\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>f', postkeys = '<Space>' },\n      { mode = 'n', keys = '<Space>x', postkeys = '<Space>' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 10 },\n  })\n\n  type_keys(' ', 'f')\n  child.expect_screenshot()\nend\n\nT['Postkeys']['closes window if postkeys do not end up key querying'] = function()\n  load_module({\n    clues = { { mode = 'n', keys = '<Space>a', desc = 'Desc', postkeys = 'G' } },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n\n  type_keys(' ', 'a')\n  sleep(postkeys_check_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Postkeys']['persists window if action changes tabpage'] = function()\n  -- Check this only on Neovim>=0.10, as there are many new built-in mappings\n  if child.fn.has('nvim-0.10') == 0 then return end\n\n  load_module({\n    clues = { { mode = 'n', keys = '<C-w>T', desc = 'Move to new tabpage', postkeys = '<C-w>' } },\n    triggers = { { mode = 'n', keys = '<C-w>' } },\n    window = { delay = 0 },\n  })\n\n  child.cmd('wincmd v')\n\n  type_keys('<C-w>')\n  child.expect_screenshot()\n  type_keys('T')\n  child.expect_screenshot({ ignore_text = { 1 }, ignore_attr = { 1 } })\nend\n\nT['Querying keys'] = new_set()\n\nT['Querying keys']['works'] = function()\n  make_test_map('n', '<Space>f')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n\n  type_keys(' ', 'f')\n  eq(get_test_map_count('n', ' f'), 1)\n\n  type_keys(10, ' ', 'f')\n  eq(get_test_map_count('n', ' f'), 2)\nend\n\nT['Querying keys']['does not entirely block redraws'] = function()\n  child.set_size(10, 40)\n  set_lines({ 'aaaa' })\n  child.lua([[\n    local ns_id = vim.api.nvim_create_namespace('test')\n    local n = 0\n    _G.add_hl = function()\n      local col = n\n      local vim_hl = vim.fn.has('nvim-0.11') == 1 and vim.hl or vim.highlight\n      vim.defer_fn(function()\n        vim_hl.range(0, ns_id, 'Comment', { 0, col }, { 0, col + 1 }, {})\n      end, 5)\n      n = n + 1\n    end\n    vim.keymap.set('n', '<Space>f', _G.add_hl, { desc = 'Add hl' })]])\n\n  load_module({\n    clues = { { mode = 'n', keys = '<Space>f', postkeys = '<Space>' } },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n  })\n\n  type_keys('<Space>', 'f')\n  -- - Redraws don't happen immediately but inside a repeating timer\n  sleep(redraw_interval + small_time)\n  child.expect_screenshot()\n\n  type_keys('f')\n  sleep(redraw_interval + small_time)\n  child.expect_screenshot()\nend\n\nT['Querying keys']['allows trigger with more than one character'] = function()\n  make_test_map('n', '<Space>aa')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>a' } } })\n  validate_trigger_keymap('n', '<Space>a')\n\n  type_keys(' ', 'a', 'a')\n  eq(get_test_map_count('n', ' aa'), 1)\n\n  type_keys(10, ' ', 'a', 'a')\n  eq(get_test_map_count('n', ' aa'), 2)\nend\n\nT['Querying keys'][\"does not time out after 'timeoutlen'\"] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>ff')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  -- Should wait for next key as there are still multiple clues available\n  child.o.timeoutlen = small_time\n  type_keys(' ', 'f')\n  sleep(2 * small_time)\n  eq(get_test_map_count('n', ' f'), 0)\nend\n\nT['Querying keys']['takes into account user-supplied clues'] = function()\n  child.set_size(10, 40)\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>a', desc = 'My space a' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { delay = 0 },\n  })\n  validate_trigger_keymap('n', '<Space>')\n\n  type_keys(' ')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\nend\n\nT['Querying keys']['respects `<CR>`'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>ff')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n\n  -- `<CR>` should execute current query\n  child.o.timeoutlen = small_time\n  type_keys(' ', 'f', '<CR>')\n  sleep(small_time + small_time)\n  eq(get_test_map_count('n', ' f'), 1)\nend\n\nT['Querying keys']['respects `<Esc>`/`<C-c>`'] = function()\n  make_test_map('n', '<Space>f')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n\n  -- `<Esc>` and `<C-c>` should stop current query\n  local validate = function(key)\n    type_keys(' ', key, 'f')\n    child.ensure_normal_mode()\n    eq(get_test_map_count('n', ' f'), 0)\n  end\n\n  validate('<Esc>')\n  validate('<C-c>')\nend\n\nT['Querying keys']['respects `<BS>`'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>ff')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n\n  -- `<BS>` should remove latest key\n  type_keys(' ', 'f', '<BS>', 'f', 'f')\n  eq(get_test_map_count('n', ' f'), 0)\n  eq(get_test_map_count('n', ' ff'), 1)\nend\n\nT['Querying keys']['can `<BS>` on first element'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', ',gg')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' }, { mode = 'n', keys = ',g' } } })\n  validate_trigger_keymap('n', '<Space>')\n  validate_trigger_keymap('n', ',g')\n\n  type_keys(' ', '<BS>', ' ', 'f')\n  eq(get_test_map_count('n', ' f'), 1)\n\n  -- Removes first trigger element at once, not by characters\n  type_keys(',g', '<BS>', ',g', 'g')\n  eq(get_test_map_count('n', ',gg'), 1)\nend\n\nT['Querying keys']['can use scroll keys when window is not shown'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space><C-f>')\n  make_test_map('n', '<Space><C-b>')\n  load_module({\n    triggers = { { mode = 'n', keys = '<Space>' } },\n    window = { scroll_down = '<C-f>', scroll_up = '<C-b>' },\n  })\n  validate_trigger_keymap('n', '<Space>')\n\n  type_keys(' ', '<C-f>')\n  eq(get_test_map_count('n', ' <C-f>'), 1)\n\n  type_keys(' ', '<C-b>')\n  eq(get_test_map_count('n', ' <C-b>'), 1)\nend\n\nT['Querying keys']['allows reaching longest keymap'] = function()\n  make_test_map('n', '<Space>f')\n  make_test_map('n', '<Space>fff')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  validate_trigger_keymap('n', '<Space>')\n\n  child.o.timeoutlen = small_time\n  type_keys(' ', 'f', 'f')\n  sleep(small_time + small_time)\n  type_keys('f')\n  eq(get_test_map_count('n', ' f'), 0)\n  eq(get_test_map_count('n', ' fff'), 1)\nend\n\nT['Querying keys']['executes even if no extra clues is set'] = function()\n  load_module({ triggers = { { mode = 'c', keys = 'g' }, { mode = 'i', keys = 'g' } } })\n  validate_trigger_keymap('c', 'g')\n  validate_trigger_keymap('i', 'g')\n\n  type_keys(':', 'g')\n  eq(child.fn.getcmdline(), 'g')\n\n  child.ensure_normal_mode()\n  type_keys('i', 'g')\n  eq(get_lines(), { 'g' })\nend\n\nT['Querying keys']['works with multibyte characters'] = function()\n  make_test_map('n', '<Space>фф')\n  make_test_map('n', '<Space>фы')\n  load_module({\n    clues = {\n      { mode = 'n', keys = '<Space>фф', postkeys = '<Space>ф' },\n      { mode = 'n', keys = '<Space>фы', postkeys = '<Space>ф' },\n    },\n    triggers = { { mode = 'n', keys = '<Space>ф' } },\n  })\n  validate_trigger_keymap('n', '<Space>ф')\n\n  type_keys(' ф', 'ф', 'ы', 'ф', '<Esc>')\n  eq(get_test_map_count('n', '<Space>фф'), 2)\n  eq(get_test_map_count('n', '<Space>фы'), 1)\nend\n\nT['Querying keys']['works with special keys'] = function()\n  child.cmd('nmap <Space><Space>  <Cmd>lua _G.space_space  = true<CR>')\n  child.cmd('nmap <Space><Tab>    <Cmd>lua _G.space_tab    = true<CR>')\n  child.cmd('nmap <Space><End>    <Cmd>lua _G.space_end    = true<CR>')\n  child.cmd('nmap <Space><PageUp> <Cmd>lua _G.space_pageup = true<CR>')\n  child.cmd('nmap <Space><C-x>    <Cmd>lua _G.space_ctrlx  = true<CR>')\n  child.cmd('nmap <Space><        <Cmd>lua _G.space_lt     = true<CR>')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  local validate = function(key, suffix)\n    type_keys(' ', key)\n    eq(child.lua_get('_G.space_' .. suffix), true)\n  end\n\n  validate(' ', 'space')\n  validate('<Tab>', 'tab')\n  validate('<End>', 'end')\n  validate('<PageUp>', 'pageup')\n  validate('<C-x>', 'ctrlx')\n  validate('<', 'lt')\nend\n\nT['Querying keys'][\"respects 'langmap'\"] = function()\n  make_test_map('n', '<Space>a')\n  make_test_map('n', '<Space>A')\n  make_test_map('n', '<Space>s')\n  make_test_map('n', '<Space>S')\n  make_test_map('n', '<Space>d')\n  make_test_map('n', '<Space>D')\n\n  child.o.langmap = [[фФ;aA,ыs,ЫS,вdВD]]\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  local validate_key = function(from, to)\n    local init_count = get_test_map_count('n', ' ' .. to)\n    type_keys(' ', from)\n    eq(get_test_map_count('n', ' ' .. to), init_count + 1)\n  end\n\n  validate_key('ф', 'a')\n  validate_key('Ф', 'A')\n  validate_key('ы', 's')\n  validate_key('Ы', 'S')\n  validate_key('в', 'd')\n  validate_key('В', 'D')\n\n  -- Special cases of 'langmap' currently don't work because later key\n  -- reproducing with `nvim_feedkeys(keys, 'mit')` will inverse meaning second\n  -- time.\n  --\n  -- make_test_map('n', '<Space>;')\n  -- make_test_map('n', '<Space>:')\n  -- child.o.langmap = [[:\\;;\\;:]]\n  -- child.o.langmap = [[:\\;\\;:]]\n  --\n  -- make_test_map('n', '<Space>/')\n  -- make_test_map('n', [[<Space>\\]])\n  -- child.o.langmap = [[\\\\/;/\\\\]]\n  -- child.o.langmap = [[\\\\//\\\\]]\nend\n\nT['Reproducing keys'] = new_set()\n\nT['Reproducing keys']['works for builtin keymaps in Normal mode'] = function()\n  load_module({ triggers = { { mode = 'n', keys = 'g' } } })\n  validate_trigger_keymap('n', 'g')\n\n  -- `ge` (basic test)\n  validate_move1d('aa bb', 3, { 'g', 'e' }, 1)\n\n  -- `gg` (should avoid infinite recursion)\n  validate_move({ 'aa', 'bb' }, { 2, 0 }, { 'g', 'g' }, { 1, 0 })\n\n  -- `g~` (should work with operators)\n  validate_edit1d('aa bb', 0, { 'g', '~', 'iw' }, 'AA bb', 0)\n\n  -- `g'a` (should work with more than one character ahead)\n  set_lines({ 'aa', 'bb' })\n  set_cursor(2, 0)\n  type_keys('ma')\n  set_cursor(1, 0)\n  type_keys(\"g'\", 'a')\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['Reproducing keys']['works for user keymaps in Normal mode'] = function()\n  -- Should work for both keymap created before and after making trigger\n  make_test_map('n', '<Space>f')\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n  make_test_map('n', '<Space>g')\n\n  validate_trigger_keymap('n', '<Space>')\n\n  type_keys(' ', 'f')\n  eq(get_test_map_count('n', ' f'), 1)\n  eq(get_test_map_count('n', ' g'), 0)\n\n  type_keys(' ', 'g')\n  eq(get_test_map_count('n', ' f'), 1)\n  eq(get_test_map_count('n', ' g'), 1)\nend\n\nT['Reproducing keys']['respects `[count]` in Normal mode'] = function()\n  load_module({ triggers = { { mode = 'n', keys = 'g' } } })\n  validate_trigger_keymap('n', 'g')\n\n  validate_move1d('aa bb cc', 6, { '2', 'g', 'e' }, 1)\nend\n\nT['Reproducing keys']['respects `[register]` in Normal mode'] = function()\n  child.lua([[\n    _G.track_register = function()\n      _G.register = vim.v.register\n      vim.cmd('normal! g~iw')\n    end\n    vim.keymap.set('n', 'ge', _G.track_register)\n\n    _G.track_register_expr = function()\n      _G.register_expr = vim.v.register\n      return 'g~iw'\n    end\n    vim.keymap.set('n', 'gE', _G.track_register_expr, { expr = true })\n  ]])\n  load_module({ triggers = { { mode = 'n', keys = 'g' } } })\n  validate_trigger_keymap('n', 'g')\n\n  validate_edit1d('AaA', 0, { '\"x', 'g', 'e' }, 'aAa', 0)\n  eq(child.lua_get('_G.register'), 'x')\n\n  validate_edit1d('AaA', 0, { '\"y', 'g', 'E' }, 'aAa', 0)\n  eq(child.lua_get('_G.register_expr'), 'y')\n\n  -- Works with special expression register \"=\"\n  child.lua([[\n    vim.keymap.set('n', 'gd', function() return 'P' end, { expr = true })\n  ]])\n  validate_edit1d('xxx', 0, { '\"=', '1+1<CR>', 'g', 'd' }, '2xxx', 0)\n  eq(child.fn.mode(1), 'n')\nend\n\nT['Reproducing keys']['works in temporary Normal mode'] = function()\n  load_module({\n    triggers = { { mode = 'n', keys = 'g' }, { mode = 'o', keys = 'i' } },\n  })\n  validate_trigger_keymap('n', 'g')\n  validate_trigger_keymap('o', 'i')\n\n  -- One step keymap\n  set_lines({ 'aa bb' })\n  child.cmd('startinsert')\n  type_keys('<C-o>', 'g', '~', 'tb')\n  eq(child.fn.mode(), 'i')\n  eq(get_lines(), { 'AA bb' })\n\n  -- Currently doesn't work when there is trigger in Operator-pending mode\n  -- Would be great if it could\n  -- child.ensure_normal_mode()\n  --\n  -- set_lines({ 'aa bb' })\n  -- child.cmd('startinsert')\n  -- type_keys('<C-o>', 'g', '~', 'i', 'w')\n  -- eq(child.fn.mode(), 'i')\n  -- eq(get_lines(), { 'AA bb' })\nend\n\nT['Reproducing keys']['works for builtin keymaps in Insert mode'] = function()\n  load_module({ triggers = { { mode = 'i', keys = '<C-x>' } } })\n  validate_trigger_keymap('i', '<C-X>')\n\n  set_lines({ 'aa aa', 'bb bb', '' })\n  set_cursor(3, 0)\n  type_keys('i', '<C-x>', '<C-l>')\n\n  eq(child.fn.mode(), 'i')\n  local complete_words = vim.tbl_map(function(x) return x.word end, child.fn.complete_info().items)\n  eq(vim.tbl_contains(complete_words, 'aa aa'), true)\n  eq(vim.tbl_contains(complete_words, 'bb bb'), true)\nend\n\nT['Reproducing keys']['works for user keymaps in Insert mode'] = function()\n  -- Should work for both keymap created before and after making trigger\n  make_test_map('i', '<Space>f')\n  load_module({ triggers = { { mode = 'i', keys = '<Space>' } } })\n  make_test_map('i', '<Space>g')\n\n  validate_trigger_keymap('i', '<Space>')\n\n  child.cmd('startinsert')\n\n  type_keys(' ', 'f')\n  eq(child.fn.mode(), 'i')\n  eq(get_test_map_count('i', ' f'), 1)\n  eq(get_test_map_count('i', ' g'), 0)\n\n  type_keys(' ', 'g')\n  eq(child.fn.mode(), 'i')\n  eq(get_test_map_count('i', ' f'), 1)\n  eq(get_test_map_count('i', ' g'), 1)\nend\n\nT['Reproducing keys']['does not reproduce register in Insert mode'] = function()\n  child.api.nvim_buf_set_keymap(0, 'n', 'i', '\"_cc', { noremap = true })\n  load_module({ triggers = { { mode = 'i', keys = '<C-x>' } } })\n\n  set_lines({ 'aa', '' })\n  set_cursor(2, 0)\n  type_keys('i', '<C-x>', '<C-v>')\n  eq(get_lines()[2] ~= '\"_', true)\nend\n\nT['Reproducing keys']['works for builtin keymaps in Visual mode'] = function()\n  load_module({ triggers = { { mode = 'x', keys = 'g' }, { mode = 'x', keys = 'a' } } })\n  validate_trigger_keymap('x', 'g')\n  validate_trigger_keymap('x', 'a')\n\n  -- `a'` (should work to update selection)\n  validate_selection1d(\"'aa'\", 1, { 'v', 'a', \"'\" }, 0, 3)\n\n  -- Should preserve Visual submode\n  validate_selection({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'V', 'a', 'p' }, { 1, 0 }, { 3, 0 }, 'V')\n  validate_selection1d(\"'aa'\", 1, \"<C-v>a'\", 0, 3, replace_termcodes('<C-v>'))\n\n  -- `g?` (should work to manipulation selection)\n  validate_edit1d('aa bb', 0, { 'v', 'iw', 'g', '?' }, 'nn bb', 0)\nend\n\nT['Reproducing keys']['works for user keymaps in Visual mode'] = function()\n  -- Should work for both keymap created before and after making trigger\n  make_test_map('x', '<Space>f')\n  load_module({ triggers = { { mode = 'x', keys = '<Space>' } } })\n  make_test_map('x', '<Space>g')\n\n  validate_trigger_keymap('x', '<Space>')\n\n  type_keys('v')\n\n  type_keys(' ', 'f')\n  eq(child.fn.mode(), 'v')\n  eq(get_test_map_count('x', ' f'), 1)\n  eq(get_test_map_count('x', ' g'), 0)\n\n  type_keys(' ', 'g')\n  eq(child.fn.mode(), 'v')\n  eq(get_test_map_count('x', ' f'), 1)\n  eq(get_test_map_count('x', ' g'), 1)\n\n  -- Should preserve Visual submode\n  child.ensure_normal_mode()\n  type_keys('V')\n  type_keys(' ', 'f')\n  eq(child.fn.mode(), 'V')\n  eq(get_test_map_count('x', ' f'), 2)\n\n  child.ensure_normal_mode()\n  type_keys('<C-v>')\n  type_keys(' ', 'f')\n  eq(child.fn.mode(), replace_termcodes('<C-v>'))\n  eq(get_test_map_count('x', ' f'), 3)\nend\n\nT['Reproducing keys']['respects `[count]` in Visual mode'] = function()\n  load_module({ triggers = { { mode = 'x', keys = 'a' } } })\n  validate_trigger_keymap('x', 'a')\n\n  validate_selection1d('aa bb cc', 0, { 'v', '2', 'a', 'w' }, 0, 5)\nend\n\nT['Reproducing keys']['respects `[register]` in Visual mode'] = function()\n  child.lua([[\n    _G.track_register = function()\n      _G.register = vim.v.register\n      vim.fn.feedkeys('g~', 'nx')\n    end\n    vim.keymap.set('x', 'ge', _G.track_register)\n\n    _G.track_register_expr = function()\n      _G.register_expr = vim.v.register\n      return 'g~'\n    end\n    vim.keymap.set('x', 'gE', _G.track_register_expr, { expr = true })\n  ]])\n  load_module({ triggers = { { mode = 'x', keys = 'g' } } })\n  validate_trigger_keymap('x', 'g')\n\n  validate_edit1d('AaA', 0, { 'viw', '\"x', 'g', 'e' }, 'aAa', 0)\n  eq(child.lua_get('_G.register'), 'x')\n\n  validate_edit1d('AaA', 0, { 'viw', '\"y', 'g', 'E' }, 'aAa', 0)\n  eq(child.lua_get('_G.register_expr'), 'y')\nend\n\nT['Reproducing keys']['works in Select mode'] = function()\n  -- Should work for both keymap created before and after making trigger\n  make_test_map('s', '<Space>f')\n  load_module({ triggers = { { mode = 's', keys = '<Space>' } } })\n  validate_trigger_keymap('s', '<Space>')\n\n  type_keys('v', '<C-g>')\n  eq(child.fn.mode(), 's')\n  type_keys(' ', 'f')\n  eq(get_test_map_count('s', ' f'), 1)\nend\n\nT['Reproducing keys']['Operator-pending mode'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Make user keymap\n      child.api.nvim_set_keymap('o', 'if', 'iw', {})\n      child.api.nvim_set_keymap('o', 'iF', 'ip', {})\n\n      -- Register trigger. Use zero delay in window to account for possible\n      -- clearance of `v:count` and `v:register` inside window update.\n      load_module({ triggers = { { mode = 'o', keys = 'i' } }, window = { delay = 0 } })\n      validate_trigger_keymap('o', 'i')\n    end,\n  },\n})\n\nT['Reproducing keys']['Operator-pending mode']['c'] = function()\n  validate_edit1d('aa bb cc', 3, { 'c', 'i', 'w', 'dd' }, 'aa dd cc', 5)\n\n  -- Dot-repeat\n  validate_edit1d('aa bb', 0, { 'c', 'i', 'w', 'dd', '<Esc>w.' }, 'dd dd', 4)\n\n  -- Should respect register\n  validate_edit1d('aaa', 0, { '\"ac', 'i', 'w', 'xxx' }, 'xxx', 3)\n  eq(child.fn.getreg('a'), 'aaa')\n\n  -- User keymap\n  validate_edit1d('aa bb cc', 3, { 'c', 'i', 'f', 'dd' }, 'aa dd cc', 5)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'c2', 'i', 'w', 'dd' }, 'ddbb cc', 2)\nend\n\nT['Reproducing keys']['Operator-pending mode']['d'] = function()\n  validate_edit1d('aa bb cc', 3, { 'd', 'i', 'w' }, 'aa  cc', 3)\n\n  -- Dot-rpeat\n  validate_edit1d('aa bb cc', 0, { 'd', 'i', 'w', 'w.' }, '  cc', 1)\n\n  -- Should respect register\n  validate_edit1d('aaa', 0, { '\"ad', 'i', 'w' }, '', 0)\n  eq(child.fn.getreg('a'), 'aaa')\n\n  -- User keymap\n  validate_edit1d('aa bb cc', 3, { 'd', 'i', 'f' }, 'aa  cc', 3)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'd2', 'i', 'w' }, 'bb cc', 0)\nend\n\nT['Reproducing keys']['Operator-pending mode']['y'] = function()\n  validate_edit1d('aa bb cc', 3, { 'y', 'i', 'w', 'P' }, 'aa bbbb cc', 4)\n\n  -- Should respect register\n  validate_edit1d('aaa', 0, { '\"ay', 'i', 'w' }, 'aaa', 0)\n  eq(child.fn.getreg('a'), 'aaa')\n\n  -- User keymap\n  validate_edit1d('aa bb cc', 3, { 'y', 'i', 'f', 'P' }, 'aa bbbb cc', 4)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'y2', 'i', 'w', 'P' }, 'aa aa bb cc', 2)\nend\n\nT['Reproducing keys']['Operator-pending mode']['~'] = function()\n  child.o.tildeop = true\n\n  validate_edit1d('aa bb', 0, { '~', 'i', 'w' }, 'AA bb', 0)\n  validate_edit1d('aa bb', 1, { '~', 'i', 'w' }, 'AA bb', 0)\n  validate_edit1d('aa bb', 3, { '~', 'i', 'w' }, 'aa BB', 3)\n\n  -- Dot-repeat\n  validate_edit1d('aa bb', 0, { '~', 'i', 'w', 'w.' }, 'AA BB', 3)\n\n  -- User keymap\n  validate_edit1d('aa bb', 0, { '~', 'i', 'f' }, 'AA bb', 0)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { '~3', 'i', 'w' }, 'AA BB cc', 0)\nend\n\nT['Reproducing keys']['Operator-pending mode']['g~'] = function()\n  validate_edit1d('aa bb', 0, { 'g~', 'i', 'w' }, 'AA bb', 0)\n  validate_edit1d('aa bb', 1, { 'g~', 'i', 'w' }, 'AA bb', 0)\n  validate_edit1d('aa bb', 3, { 'g~', 'i', 'w' }, 'aa BB', 3)\n\n  -- Dot-repeat\n  validate_edit1d('aa bb', 0, { 'g~', 'i', 'w', 'w.' }, 'AA BB', 3)\n\n  -- User keymap\n  validate_edit1d('aa bb', 0, { 'g~', 'i', 'f' }, 'AA bb', 0)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'g~3', 'i', 'w' }, 'AA BB cc', 0)\nend\n\nT['Reproducing keys']['Operator-pending mode']['gu'] = function()\n  validate_edit1d('AA BB', 0, { 'gu', 'i', 'w' }, 'aa BB', 0)\n  validate_edit1d('AA BB', 1, { 'gu', 'i', 'w' }, 'aa BB', 0)\n  validate_edit1d('AA BB', 3, { 'gu', 'i', 'w' }, 'AA bb', 3)\n\n  -- Dot-repeat\n  validate_edit1d('AA BB', 0, { 'gu', 'i', 'w', 'w.' }, 'aa bb', 3)\n\n  -- User keymap\n  validate_edit1d('AA BB', 0, { 'gu', 'i', 'f' }, 'aa BB', 0)\n\n  -- Should respect `[count]`\n  validate_edit1d('AA BB CC', 0, { 'gu3', 'i', 'w' }, 'aa bb CC', 0)\nend\n\nT['Reproducing keys']['Operator-pending mode']['gU'] = function()\n  validate_edit1d('aa bb', 0, { 'gU', 'i', 'w' }, 'AA bb', 0)\n  validate_edit1d('aa bb', 1, { 'gU', 'i', 'w' }, 'AA bb', 0)\n  validate_edit1d('aa bb', 3, { 'gU', 'i', 'w' }, 'aa BB', 3)\n\n  -- Dot-repeat\n  validate_edit1d('aa bb', 0, { 'gU', 'i', 'w', 'w.' }, 'AA BB', 3)\n\n  -- User keymap\n  validate_edit1d('aa bb', 0, { 'gU', 'i', 'f' }, 'AA bb', 0)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'gU3', 'i', 'w' }, 'AA BB cc', 0)\nend\n\nT['Reproducing keys']['Operator-pending mode']['gq'] = function()\n  child.lua([[_G.formatexpr = function()\n    local from, to = vim.v.lnum, vim.v.lnum + vim.v.count - 1\n    local new_lines = {}\n    for _ = 1, vim.v.count do table.insert(new_lines, 'xxx') end\n    vim.api.nvim_buf_set_lines(0, from - 1, to, false, new_lines)\n  end]])\n  child.bo.formatexpr = 'v:lua.formatexpr()'\n\n  validate_edit({ 'aa', 'aa', '', 'bb' }, { 1, 0 }, { 'gq', 'i', 'p' }, { 'xxx', 'xxx', '', 'bb' }, { 1, 0 })\n\n  -- Dot-repeat\n  validate_edit(\n    { 'aa', 'aa', '', 'bb', 'bb' },\n    { 1, 0 },\n    { 'gq', 'i', 'p', 'G.' },\n    { 'xxx', 'xxx', '', 'xxx', 'xxx' },\n    { 4, 0 }\n  )\n\n  -- User keymap\n  validate_edit({ 'aa', 'aa', '', 'bb' }, { 1, 0 }, { 'gq', 'i', 'F' }, { 'xxx', 'xxx', '', 'bb' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit(\n    { 'aa', '', 'bb', '', 'cc' },\n    { 1, 0 },\n    { 'gq3', 'i', 'p' },\n    { 'xxx', 'xxx', 'xxx', '', 'cc' },\n    { 1, 0 }\n  )\nend\n\nT['Reproducing keys']['Operator-pending mode']['gw'] = function()\n  child.o.textwidth = 5\n\n  validate_edit({ 'aaa aaa', '', 'bb' }, { 1, 0 }, { 'gw', 'i', 'p' }, { 'aaa', 'aaa', '', 'bb' }, { 1, 0 })\n\n  -- Dot-repeat\n  validate_edit(\n    { 'aaa aaa', '', 'bbb bbb' },\n    { 1, 0 },\n    { 'gw', 'i', 'p', 'G.' },\n    { 'aaa', 'aaa', '', 'bbb', 'bbb' },\n    { 4, 0 }\n  )\n\n  -- User keymap\n  validate_edit({ 'aaa aaa', '', 'bb' }, { 1, 0 }, { 'gw', 'i', 'F' }, { 'aaa', 'aaa', '', 'bb' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit(\n    { 'aaa aaa', '', 'bbb bbb', '', 'cc' },\n    { 1, 0 },\n    { 'gw3i', 'p', '' },\n    { 'aaa', 'aaa', '', 'bbb', 'bbb', '', 'cc' },\n    { 1, 0 }\n  )\nend\n\nT['Reproducing keys']['Operator-pending mode']['g?'] = function()\n  validate_edit1d('aa bb', 0, { 'g?', 'i', 'w' }, 'nn bb', 0)\n  validate_edit1d('aa bb', 1, { 'g?', 'i', 'w' }, 'nn bb', 0)\n  validate_edit1d('aa bb', 3, { 'g?', 'i', 'w' }, 'aa oo', 3)\n\n  -- Dot-repeat\n  validate_edit1d('aa bb', 0, { 'g?', 'i', 'w', 'w.' }, 'nn oo', 3)\n\n  -- User keymap\n  validate_edit1d('aa bb', 0, { 'g?', 'i', 'f' }, 'nn bb', 0)\n\n  -- Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'g?3', 'i', 'w' }, 'nn oo cc', 0)\nend\n\nT['Reproducing keys']['Operator-pending mode']['!'] = function()\n  validate_edit({ 'cc', 'bb', '', 'aa' }, { 1, 0 }, { '!', 'i', 'p', 'sort<CR>' }, { 'bb', 'cc', '', 'aa' }, { 1, 0 })\n\n  -- Dot-repeat\n  validate_edit(\n    { 'cc', 'bb', '', 'dd', 'aa' },\n    { 1, 0 },\n    { '!', 'i', 'p', 'sort<CR>G.' },\n    { 'bb', 'cc', '', 'aa', 'dd' },\n    { 4, 0 }\n  )\n\n  -- User keymap\n  validate_edit({ 'cc', 'bb', '', 'aa' }, { 1, 0 }, { '!', 'i', 'F', 'sort<CR>' }, { 'bb', 'cc', '', 'aa' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit(\n    { 'cc', 'bb', '', 'ee', 'dd', '', 'aa' },\n    { 1, 0 },\n    { '!3', 'i', 'p', 'sort<CR>' },\n    { '', 'bb', 'cc', 'dd', 'ee', '', 'aa' },\n    { 1, 0 }\n  )\nend\n\nT['Reproducing keys']['Operator-pending mode']['='] = function()\n  validate_edit({ 'aa', '\\taa', '', 'bb' }, { 1, 0 }, { '=', 'i', 'p' }, { 'aa', 'aa', '', 'bb' }, { 1, 0 })\n\n  -- Dot-repeat\n  validate_edit(\n    { 'aa', '\\taa', '', 'bb', '\\tbb' },\n    { 1, 0 },\n    { '=', 'i', 'p', 'G.' },\n    { 'aa', 'aa', '', 'bb', 'bb' },\n    { 4, 0 }\n  )\n\n  -- User keymap\n  validate_edit({ 'aa', '\\taa', '', 'bb' }, { 1, 0 }, { '=', 'i', 'F' }, { 'aa', 'aa', '', 'bb' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit(\n    { 'aa', '\\taa', '', 'bb', '\\tbb', '', 'cc' },\n    { 1, 0 },\n    { '=3', 'i', 'p' },\n    { 'aa', 'aa', '', 'bb', 'bb', '', 'cc' },\n    { 1, 0 }\n  )\nend\n\nT['Reproducing keys']['Operator-pending mode']['>'] = function()\n  validate_edit({ 'aa', '', 'bb' }, { 1, 0 }, { '>', 'i', 'p' }, { '\\taa', '', 'bb' }, { 1, 0 })\n\n  -- Dot-repeat\n  validate_edit({ 'aa', '', 'bb' }, { 1, 0 }, { '>', 'i', 'p', '.2j.' }, { '\\t\\taa', '', '\\tbb' }, { 3, 0 })\n\n  -- User keymap\n  validate_edit({ 'aa', '', 'bb' }, { 1, 0 }, { '>', 'i', 'F' }, { '\\taa', '', 'bb' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit({ 'aa', '', 'bb', '', 'cc' }, { 1, 0 }, { '>3', 'i', 'p' }, { '\\taa', '', '\\tbb', '', 'cc' }, { 1, 0 })\nend\n\nT['Reproducing keys']['Operator-pending mode']['<'] = function()\n  validate_edit({ '\\t\\taa', '', 'bb' }, { 1, 0 }, { '<', 'i', 'p' }, { '\\taa', '', 'bb' }, { 1, 0 })\n\n  -- Dot-repeat\n  validate_edit({ '\\t\\t\\taa', '', '\\tbb' }, { 1, 0 }, { '<', 'i', 'p', '.2j.' }, { '\\taa', '', 'bb' }, { 3, 1 })\n\n  -- User keymap\n  validate_edit({ '\\t\\taa', '', 'bb' }, { 1, 0 }, { '<', 'i', 'F' }, { '\\taa', '', 'bb' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit(\n    { '\\t\\taa', '', '\\t\\tbb', '', 'cc' },\n    { 1, 0 },\n    { '<', '3', 'i', 'p' },\n    { '\\taa', '', '\\tbb', '', 'cc' },\n    { 1, 0 }\n  )\nend\n\nT['Reproducing keys']['Operator-pending mode']['zf'] = function()\n  local validate = function(keys, ref_last_folded_line)\n    local lines = { 'aa', 'aa', '', 'bb', '', 'cc' }\n    set_lines(lines)\n    set_cursor(1, 0)\n\n    type_keys(keys)\n\n    for i = 1, ref_last_folded_line do\n      eq(child.fn.foldclosed(i), 1)\n    end\n\n    for i = ref_last_folded_line + 1, #lines do\n      eq(child.fn.foldclosed(i), -1)\n    end\n  end\n\n  validate({ 'zf', 'i', 'p' }, 2)\n  validate({ 'zf', 'i', 'F' }, 2)\n\n  -- Should respect `[count]`\n  validate({ 'zf3', 'i', 'p' }, 4)\nend\n\nT['Reproducing keys']['Operator-pending mode']['g@'] = function()\n  child.o.operatorfunc = 'v:lua.operatorfunc'\n\n  -- Charwise\n  child.lua([[_G.operatorfunc = function()\n    local from, to = vim.fn.col(\"'[\"), vim.fn.col(\"']\")\n    local line = vim.fn.line('.')\n\n    vim.api.nvim_buf_set_text(0, line - 1, from - 1, line - 1, to, { 'xx' })\n  end]])\n\n  validate_edit1d('aa bb cc', 3, { 'g@', 'i', 'w' }, 'aa xx cc', 3)\n\n  -- - Dot-repeat\n  validate_edit1d('aa bb cc', 3, { 'g@', 'i', 'w', 'w.' }, 'aa xx xx', 6)\n\n  -- - User keymap\n  validate_edit1d('aa bb cc', 3, { 'g@', 'i', 'f' }, 'aa xx cc', 3)\n\n  -- - Should respect `[count]`\n  validate_edit1d('aa bb cc', 0, { 'g@3', 'i', 'w' }, 'xx cc', 0)\n\n  -- Linewise\n  child.lua([[_G.operatorfunc = function() vim.cmd(\"'[,']sort\") end]])\n\n  validate_edit({ 'cc', 'bb', '', 'aa' }, { 1, 0 }, { 'g@', 'i', 'p' }, { 'bb', 'cc', '', 'aa' }, { 1, 0 })\n\n  -- - Dot-repeat\n  validate_edit(\n    { 'cc', 'bb', '', 'dd', 'aa' },\n    { 1, 0 },\n    { 'g@', 'i', 'p', 'G.' },\n    { 'bb', 'cc', '', 'aa', 'dd' },\n    { 4, 0 }\n  )\n\n  -- - User keymap\n  validate_edit({ 'cc', 'bb', '', 'aa' }, { 1, 0 }, { 'g@', 'i', 'F' }, { 'bb', 'cc', '', 'aa' }, { 1, 0 })\n\n  -- Should respect `[count]`\n  validate_edit(\n    { 'cc', 'bb', '', 'ee', 'dd', '', 'aa' },\n    { 1, 0 },\n    { 'g@3', 'i', 'p' },\n    { '', 'bb', 'cc', 'dd', 'ee', '', 'aa' },\n    { 1, 0 }\n  )\nend\n\nT['Reproducing keys']['Operator-pending mode']['works with operator and textobject from triggers'] = function()\n  load_module({ triggers = { { mode = 'n', keys = 'g' }, { mode = 'o', keys = 'i' } } })\n  validate_trigger_keymap('n', 'g')\n  validate_trigger_keymap('o', 'i')\n\n  -- `g~`\n  validate_edit1d('aa bb', 0, { 'g~', 'i', 'w' }, 'AA bb', 0)\n\n  -- `g@`\n  child.lua([[_G.operatorfunc = function() vim.cmd(\"'[,']sort\") end]])\n  child.o.operatorfunc = 'v:lua.operatorfunc'\n\n  validate_edit({ 'cc', 'bb', '', 'aa' }, { 1, 0 }, { 'g@', 'i', 'p' }, { 'bb', 'cc', '', 'aa' }, { 1, 0 })\nend\n\nT['Reproducing keys']['Operator-pending mode']['respects forced submode'] = function()\n  load_module({ triggers = { { mode = 'o', keys = '`' } } })\n  validate_trigger_keymap('o', '`')\n\n  -- Linewise\n  set_lines({ 'aa', 'bbbb', 'cc' })\n  set_cursor(2, 1)\n  type_keys('mb')\n  set_cursor(1, 0)\n  type_keys('dV', '`', 'b')\n  eq(get_lines(), { 'cc' })\n\n  -- Blockwise\n  set_lines({ 'aa', 'bbbb', 'cc' })\n  set_cursor(3, 1)\n  type_keys('mc')\n  set_cursor(1, 0)\n  type_keys('d\\22', '`', 'c')\n  eq(get_lines(), { '', 'bb', '' })\nend\n\nT['Reproducing keys']['works for builtin keymaps in Terminal mode'] = function()\n  load_module({ triggers = { { mode = 't', keys = [[<C-\\>]] } } })\n  validate_trigger_keymap('t', [[<C-\\>]])\n\n  child.cmd('wincmd v')\n  child.cmd('terminal')\n  -- Wait for terminal to load\n  vim.loop.sleep(6 * small_time)\n  child.cmd('startinsert')\n  eq(child.fn.mode(), 't')\n\n  type_keys([[<C-\\>]], '<C-n>')\n  eq(child.fn.mode(), 'n')\nend\n\nT['Reproducing keys']['works for user keymaps in Terminal mode'] = function()\n  -- Should work for both keymap created before and after making trigger\n  make_test_map('t', '<Space>f')\n  load_module({ triggers = { { mode = 't', keys = '<Space>' } } })\n  make_test_map('t', '<Space>g')\n\n  validate_trigger_keymap('t', '<Space>')\n\n  child.cmd('wincmd v')\n  child.cmd('terminal')\n  -- Wait for terminal to load\n  vim.loop.sleep(6 * small_time)\n  child.cmd('startinsert')\n  eq(child.fn.mode(), 't')\n\n  type_keys(' ', 'f')\n  eq(child.fn.mode(), 't')\n  eq(get_test_map_count('t', ' f'), 1)\n  eq(get_test_map_count('t', ' g'), 0)\n\n  type_keys(' ', 'g')\n  eq(child.fn.mode(), 't')\n  eq(get_test_map_count('t', ' f'), 1)\n  eq(get_test_map_count('t', ' g'), 1)\nend\n\nT['Reproducing keys']['works for builtin keymaps in Command-line mode'] = function()\n  load_module({ triggers = { { mode = 'c', keys = '<C-r>' } } })\n  validate_trigger_keymap('c', '<C-R>')\n\n  set_lines({ 'aaa' })\n  set_cursor(1, 0)\n  type_keys(':', '<C-r>', '<C-w>')\n  eq(child.fn.getcmdline(), 'aaa')\nend\n\nT['Reproducing keys']['works for user keymaps in Command-line mode'] = function()\n  -- Should work for both keymap created before and after making trigger\n  make_test_map('c', '<Space>f')\n  load_module({ triggers = { { mode = 'c', keys = '<Space>' } } })\n  make_test_map('c', '<Space>g')\n\n  validate_trigger_keymap('c', '<Space>')\n\n  type_keys(':')\n\n  type_keys(' ', 'f')\n  eq(child.fn.mode(), 'c')\n  eq(get_test_map_count('c', ' f'), 1)\n  eq(get_test_map_count('c', ' g'), 0)\n\n  type_keys(' ', 'g')\n  eq(child.fn.mode(), 'c')\n  eq(get_test_map_count('c', ' f'), 1)\n  eq(get_test_map_count('c', ' g'), 1)\nend\n\nT['Reproducing keys']['works for registers'] = function()\n  load_module({ triggers = { { mode = 'n', keys = '\"' }, { mode = 'x', keys = '\"' } } })\n  validate_trigger_keymap('n', '\"')\n  validate_trigger_keymap('x', '\"')\n\n  -- Normal mode\n  set_lines({ 'aa' })\n  set_cursor(1, 0)\n  type_keys('\"', 'a', 'yiw')\n  eq(child.fn.getreg('\"a'), 'aa')\n\n  -- Visual mode\n  set_lines({ 'bb' })\n  set_cursor(1, 0)\n  type_keys('viw', '\"', 'b', 'y')\n  eq(child.fn.getreg('\"b'), 'bb')\nend\n\nT['Reproducing keys']['works for marks'] = function()\n  load_module({ triggers = { { mode = 'n', keys = \"'\" }, { mode = 'n', keys = '`' } } })\n  validate_trigger_keymap('n', \"'\")\n  validate_trigger_keymap('n', '`')\n\n  set_lines({ 'aa', 'bb' })\n  set_cursor(1, 1)\n  type_keys('ma')\n\n  -- Line jump\n  set_cursor(2, 0)\n  type_keys(\"'\", 'a')\n  eq(get_cursor(), { 1, 0 })\n\n  -- Exact jump\n  set_cursor(2, 0)\n  type_keys('`', 'a')\n  eq(get_cursor(), { 1, 1 })\nend\n\nT['Reproducing keys']['works with macros'] = function()\n  mock_comment_operators()\n  load_module({ triggers = { { mode = 'n', keys = 'g' }, { mode = 'o', keys = 'i' }, { mode = 'i', keys = '<C-r>' } } })\n  validate_trigger_keymap('n', 'g')\n  validate_trigger_keymap('o', 'i')\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local new_buf_id = child.api.nvim_create_buf(true, false)\n\n  local setup = function()\n    child.api.nvim_buf_set_lines(init_buf_id, 0, -1, false, { 'aa', 'bb' })\n    child.api.nvim_buf_set_lines(new_buf_id, 0, -1, false, { 'cc', 'dd' })\n\n    child.api.nvim_set_current_buf(init_buf_id)\n    set_cursor(1, 0)\n  end\n\n  local validate = function()\n    eq(child.api.nvim_buf_get_lines(init_buf_id, 0, -1, false), { '-- AA', '-- bb' })\n    eq(child.api.nvim_buf_get_lines(new_buf_id, 0, -1, false), { '-- CC', '-- dd' })\n\n    -- Make sure that triggers persist because they are temporarily disabled\n    -- for the duration of macro execution\n    validate_trigger_keymap('n', 'g')\n    validate_trigger_keymap('o', 'i')\n  end\n\n  setup()\n\n  type_keys('qq', 'g~', 'i', 'w', 'gc', 'i', 'p')\n  type_keys(':bnext<CR>', 'g~', 'i', 'w', 'gc', 'i', 'p')\n  type_keys('q')\n\n  validate()\n\n  eq(child.fn.getreg('q', 1, 1), { 'g~iwgcip:bnext\\rg~iwgcip' })\n\n  -- Should work reproducing multiple times with different keys\n  setup()\n  type_keys('@q')\n  validate()\n\n  setup()\n  type_keys('@@')\n  validate()\n\n  setup()\n  type_keys('Q')\n  validate()\n\n  -- Should not throw error if user aborted with `<C-c>`\n  setup()\n  type_keys('@', '<C-c>')\n  child.api.nvim_buf_set_lines(init_buf_id, 0, -1, false, { 'aa', 'bb' })\n  child.api.nvim_buf_set_lines(new_buf_id, 0, -1, false, { 'cc', 'dd' })\n  validate_trigger_keymap('n', 'g')\n  validate_trigger_keymap('o', 'i')\n\n  -- Should work when creating new buffer inside macro (i.e. auto-creating\n  -- triggers should not intefere)\n  child.fn.setreg('a', 'word')\n  type_keys('qw', ':enew<CR>', 'i', '<C-r>', 'a', '<Esc>', 'q')\n  eq(child.fn.getreg('w'), ':enew\\ri\\18a\\27')\nend\n\nT['Reproducing keys'][\"works with macros and 'mini.jump'\"] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('The solution works only on Neovim>=0.10') end\n  child.lua(\"require('mini.jump').setup()\")\n  load_module()\n  set_lines({ '  [aaa][bbb][ccc]' })\n\n  type_keys(small_time, 'qq', '0f', '[', 'r(f', ']', 'r)', 'q')\n  eq(get_lines(), { '  (aaa)[bbb][ccc]' })\n\n  type_keys('Q')\n  eq(get_lines(), { '  (aaa)(bbb)[ccc]' })\n\n  type_keys('@q')\n  eq(get_lines(), { '  (aaa)(bbb)(ccc)' })\nend\n\nT['Reproducing keys']['works when key query is executed in presence of longer keymaps'] = function()\n  mock_comment_operators()\n  load_module({ triggers = { { mode = 'n', keys = 'g' }, { mode = 'o', keys = 'i' } } })\n  validate_trigger_keymap('n', 'g')\n  validate_trigger_keymap('o', 'i')\n\n  validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'g', 'c', 'i', 'p' }, { '-- aa', '-- bb', '', 'cc' }, { 1, 0 })\nend\n\nT['Reproducing keys']['works with `<Cmd>` mappings'] = function()\n  child.api.nvim_set_keymap('n', '<Space>f', '<Cmd>lua _G.been_here = true<CR>', {})\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  type_keys(' ', 'f')\n  eq(child.lua_get('_G.been_here'), true)\nend\n\nT['Reproducing keys']['works with buffer-local mappings'] = function()\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>f', '<Cmd>lua _G.been_here = true<CR>', {})\n  load_module({ triggers = { { mode = 'n', keys = '<Space>' } } })\n\n  type_keys(' ', 'f')\n  eq(child.lua_get('_G.been_here'), true)\nend\n\nT['Reproducing keys']['does not register new triggers'] = function()\n  load_module({ triggers = { { mode = 'o', keys = 'i' } } })\n  validate_trigger_keymap('o', 'i')\n\n  set_lines('aaa')\n  type_keys('\"adiw')\n\n  validate_trigger_keymap('o', 'i')\nend\n\nT['Reproducing keys'][\"respects 'clipboard'\"] = function()\n  -- Mock constant clipboard for better reproducibility of system registers\n  -- (mostly on CI).\n  child.lua([[\n    local empty = function() return '' end\n    vim.g.clipboard = {\n      name  = 'myClipboard',\n      copy  = { ['+'] = empty, ['*'] = empty },\n      paste = { ['+'] = empty, ['*'] = empty },\n    }\n  ]])\n\n  load_module({ triggers = { { mode = 'c', keys = 'g' }, { mode = 'i', keys = 'g' } } })\n  validate_trigger_keymap('c', 'g')\n  validate_trigger_keymap('i', 'g')\n\n  local validate_clipboard = function(clipboard_value)\n    child.ensure_normal_mode()\n    set_lines({})\n\n    child.o.clipboard = clipboard_value\n\n    child.ensure_normal_mode()\n    type_keys('i', 'g')\n    eq(get_lines(), { 'g' })\n  end\n\n  validate_clipboard('unnamed')\n  validate_clipboard('unnamedplus')\n  validate_clipboard('unnamed,unnamedplus')\n  validate_clipboard('unnamedplus,unnamed')\nend\n\nT['Reproducing keys']['works with <F*> keys'] = function()\n  child.lua([[vim.g.mapleader = vim.api.nvim_replace_termcodes('<F2>', true, true, true)]])\n  child.cmd('nnoremap <Leader>a <Cmd>lua _G.n = (_G.n or 0) + 1<CR>')\n  child.cmd('nnoremap <F3>b <Cmd>lua _G.m = (_G.m or 0) + 1<CR>')\n\n  load_module({\n    clues = { { mode = 'n', keys = '<Leader>a', postkeys = '<Leader>' } },\n    triggers = { { mode = 'n', keys = '<Leader>' }, { mode = 'n', keys = '<F3>' } },\n  })\n\n  type_keys('<F2>', 'a', 'a', '<Esc>')\n  eq(child.lua_get('_G.n'), 2)\n\n  type_keys('<F3>', 'b')\n  eq(child.lua_get('_G.m'), 1)\nend\n\nT[\"'mini.nvim' compatibility\"] = new_set()\n\nT[\"'mini.nvim' compatibility\"]['mini.ai'] = function()\n  child.lua('require(\"mini.ai\").setup()')\n\n  load_module({ triggers = { { mode = 'o', keys = 'i' }, { mode = 'o', keys = 'a' } }, window = { delay = 0 } })\n  validate_trigger_keymap('o', 'i')\n  validate_trigger_keymap('o', 'a')\n\n  -- `i` in Visual mode\n  validate_selection1d('aa(bb)', 0, 'vi)', 3, 4)\n  validate_selection1d('aa ff(bb)', 0, 'vif', 6, 7)\n\n  validate_selection1d('(a(b(cc)b)a)', 5, 'v2i)', 3, 8)\n  validate_selection1d('(a(b(cc)b)a)', 5, 'vi)i)', 3, 8)\n\n  validate_selection1d('(aa) (bb) (cc)', 6, 'vil)', 1, 2)\n  validate_selection1d('(aa) (bb) (cc)', 11, 'v2il)', 1, 2)\n\n  validate_selection1d('(aa) (bb) (cc)', 6, 'vin)', 11, 12)\n  validate_selection1d('(aa) (bb) (cc)', 1, 'v2in)', 11, 12)\n\n  -- `a` in Visual mode\n  validate_selection1d('aa(bb)', 0, 'va)', 2, 5)\n  validate_selection1d('aa ff(bb)', 0, 'vaf', 3, 8)\n\n  validate_selection1d('(a(b(cc)b)a)', 5, 'v2a)', 2, 9)\n  validate_selection1d('(a(b(cc)b)a)', 5, 'va)a)', 2, 9)\n\n  validate_selection1d('(aa) (bb) (cc)', 6, 'val)', 0, 3)\n  validate_selection1d('(aa) (bb) (cc)', 11, 'v2al)', 0, 3)\n\n  validate_selection1d('(aa) (bb) (cc)', 6, 'van)', 10, 13)\n  validate_selection1d('(aa) (bb) (cc)', 1, 'v2an)', 10, 13)\n\n  -- `i` in Operator-pending mode\n  validate_edit1d('aa(bb)', 0, 'di)', 'aa()', 3)\n  validate_edit1d('aa(bb)', 0, 'ci)cc', 'aa(cc)', 5)\n  validate_edit1d('aa(bb)', 0, 'yi)P', 'aa(bbbb)', 4)\n  validate_edit1d('aa ff(bb)', 0, 'dif', 'aa ff()', 6)\n\n  validate_edit1d('(a(b(cc)b)a)', 5, 'd2i)', '(a()a)', 3)\n\n  validate_edit1d('(a(b(cc)b)a)', 5, 'di).', '(a()a)', 3)\n  validate_edit1d('(aa) (bb)', 1, 'ci)cc<Esc>W.', '(cc) (cc)', 7)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'dil)', '() (bb) (cc)', 1)\n  validate_edit1d('(aa) (bb) (cc)', 11, 'd2il)', '() (bb) (cc)', 1)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'din)', '(aa) (bb) ()', 11)\n  validate_edit1d('(aa) (bb) (cc)', 1, 'd2in)', '(aa) (bb) ()', 11)\n\n  -- `a` in Operator-pending mode\n  validate_edit1d('aa(bb)', 0, 'da)', 'aa', 1)\n  validate_edit1d('aa(bb)', 0, 'ca)cc', 'aacc', 4)\n  validate_edit1d('aa(bb)', 0, 'ya)P', 'aa(bb)(bb)', 5)\n  validate_edit1d('aa ff(bb)', 0, 'daf', 'aa ', 2)\n\n  validate_edit1d('(a(b(cc)b)a)', 5, 'd2a)', '(aa)', 2)\n\n  validate_edit1d('(a(b(cc)b)a)', 5, 'da).', '(aa)', 2)\n  validate_edit1d('(aa) (bb)', 1, 'ca)cc<Esc>W.', 'cc cc', 4)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'dal)', ' (bb) (cc)', 0)\n  validate_edit1d('(aa) (bb) (cc)', 11, 'd2al)', ' (bb) (cc)', 0)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'dan)', '(aa) (bb) ', 9)\n  validate_edit1d('(aa) (bb) (cc)', 1, 'd2an)', '(aa) (bb) ', 9)\nend\n\nT[\"'mini.nvim' compatibility\"]['mini.align'] = function()\n  child.set_size(10, 30)\n  child.o.cmdheight = 5\n\n  child.lua('require(\"mini.align\").setup()')\n\n  -- Works together with 'mini.ai' without `g` as trigger\n  child.lua('require(\"mini.ai\").setup()')\n  load_module({ triggers = { { mode = 'o', keys = 'i' } } })\n  validate_edit({ 'f(', 'a_b', 'aa_b', ')' }, { 2, 0 }, { 'ga', 'if', '_' }, { 'f(', 'a _b', 'aa_b', ')' }, { 1, 1 })\n\n  -- Works with `g` as trigger\n  load_module({ triggers = { { mode = 'n', keys = 'g' }, { mode = 'o', keys = 'i' } }, window = { delay = 0 } })\n  validate_trigger_keymap('n', 'g')\n\n  -- - No preview\n  validate_edit({ 'a_b', 'aa_b' }, { 1, 0 }, 'vapga_', { 'a _b', 'aa_b' }, { 2, 0 })\n  validate_edit({ 'a_b', 'aa_b' }, { 1, 0 }, 'gaap_', { 'a _b', 'aa_b' }, { 1, 0 })\n\n  validate_edit(\n    { 'a_b', 'aa_b', '', 'c_d', 'cc_d' },\n    { 1, 0 },\n    'gaap_G.',\n    { 'a _b', 'aa_b', '', 'c _d', 'cc_d' },\n    { 3, 0 }\n  )\n\n  -- - With preview\n  local validate_preview = function(keys)\n    set_lines({ 'a_b', 'aa_b' })\n    set_cursor(1, 0)\n    type_keys(keys)\n    child.expect_screenshot({ redraw = false })\n    type_keys('_<CR>')\n    eq(get_lines(), { 'a _b', 'aa_b' })\n  end\n\n  validate_preview('vapgA')\n  validate_preview('gAap')\n\n  -- Works together with 'mini.ai' with `g` as trigger\n  if has_ai then\n    validate_edit({ 'f(', 'a_b', 'aa_b', ')' }, { 2, 0 }, { 'ga', 'if', '_' }, { 'f(', 'a _b', 'aa_b', ')' }, { 1, 1 })\n  end\nend\n\nT[\"'mini.nvim' compatibility\"]['mini.basics'] = function()\n  child.lua('require(\"mini.basics\").setup()')\n\n  load_module({ triggers = { { mode = 'n', keys = 'g' } }, window = { delay = 0 } })\n  validate_trigger_keymap('n', 'g')\n\n  set_lines({ 'aa' })\n\n  type_keys('g', 'O', '.')\n  eq(get_lines(), { '', '', 'aa' })\n  eq(get_cursor(), { 3, 0 })\n\n  type_keys('g', 'o', '.')\n  eq(get_lines(), { '', '', 'aa', '', '' })\n  eq(get_cursor(), { 3, 0 })\nend\n\nT[\"'mini.nvim' compatibility\"]['mini.bracketed'] = function()\n  child.lua('require(\"mini.bracketed\").setup()')\n\n  load_module({\n    triggers = {\n      { mode = 'n', keys = '[' },\n      { mode = 'x', keys = '[' },\n      { mode = 'o', keys = '[' },\n      { mode = 'n', keys = ']' },\n      { mode = 'x', keys = ']' },\n      { mode = 'o', keys = ']' },\n    },\n    window = { delay = 0 },\n  })\n  validate_trigger_keymap('n', '[')\n  validate_trigger_keymap('x', '[')\n  validate_trigger_keymap('o', '[')\n  validate_trigger_keymap('n', ']')\n  validate_trigger_keymap('x', ']')\n  validate_trigger_keymap('o', ']')\n\n  -- Normal mode\n  -- - Not same buffer\n  local get_buf = child.api.nvim_get_current_buf\n  local init_buf_id = get_buf()\n  local new_buf_id = child.api.nvim_create_buf(true, false)\n\n  type_keys(']b')\n  eq(get_buf(), new_buf_id)\n\n  type_keys('[b')\n  eq(get_buf(), init_buf_id)\n\n  type_keys(']B')\n  eq(get_buf(), new_buf_id)\n\n  type_keys('[B')\n  eq(get_buf(), init_buf_id)\n\n  type_keys('2[b')\n  eq(get_buf(), init_buf_id)\n\n  -- - Same buffer\n  local indent_lines = { 'aa', '\\tbb', '\\t\\tcc', '\\tdd', 'ee' }\n  validate_move(indent_lines, { 3, 2 }, '[i', { 2, 1 })\n  validate_move(indent_lines, { 3, 2 }, ']i', { 4, 1 })\n  validate_move(indent_lines, { 3, 2 }, '2[i', { 1, 0 })\n\n  -- Visual mode\n  validate_selection(indent_lines, { 3, 2 }, 'v[i', { 2, 1 }, { 3, 2 })\n  validate_selection(indent_lines, { 3, 2 }, 'v]i', { 3, 2 }, { 4, 1 })\n  validate_selection(indent_lines, { 3, 2 }, 'v2[i', { 1, 0 }, { 3, 2 })\n\n  validate_selection(indent_lines, { 3, 2 }, 'V[i', { 2, 1 }, { 3, 2 }, 'V')\n\n  -- Operator-pending mode\n  validate_edit(indent_lines, { 3, 2 }, 'd[i', { 'aa', '\\tdd', 'ee' }, { 2, 2 })\n  validate_edit(indent_lines, { 3, 2 }, 'd]i', { 'aa', '\\tbb', 'ee' }, { 3, 1 })\n  validate_edit(indent_lines, { 3, 2 }, 'd2[i', { '\\tdd', 'ee' }, { 1, 2 })\nend\n\nT[\"'mini.nvim' compatibility\"]['mini.comment'] = function()\n  child.o.commentstring = '## %s'\n\n  child.lua('require(\"mini.comment\").setup()')\n\n  -- Works together with 'mini.ai' without `g` as trigger\n  child.lua('require(\"mini.ai\").setup()')\n  load_module({ triggers = { { mode = 'o', keys = 'i' } }, window = { delay = 0 } })\n  validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'gc', 'ip' }, { '## aa', '## bb', '', 'cc' }, { 1, 0 })\n\n  -- Works with `g` as trigger\n  load_module({\n    triggers = {\n      { mode = 'n', keys = 'g' },\n      { mode = 'x', keys = 'g' },\n      { mode = 'o', keys = 'g' },\n\n      { mode = 'o', keys = 'i' },\n    },\n    window = { delay = 0 },\n  })\n  validate_trigger_keymap('n', 'g')\n\n  -- Normal mode\n  validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'gc', 'ap' }, { '## aa', '## bb', '##', 'cc' }, { 1, 0 })\n  validate_edit(\n    { 'aa', '', 'bb', '', 'cc' },\n    { 1, 0 },\n    { '2gc', 'ap' },\n    { '## aa', '##', '## bb', '##', 'cc' },\n    { 1, 0 }\n  )\n  validate_edit(\n    { 'aa', '', 'bb', '', 'cc' },\n    { 1, 0 },\n    { 'gc', 'ap', '.' },\n    { '## ## aa', '## ##', '## bb', '##', 'cc' },\n    { 1, 0 }\n  )\n\n  validate_edit({ 'aa', 'bb', '' }, { 1, 0 }, { 'gcc' }, { '## aa', 'bb', '' }, { 1, 0 })\n  validate_edit({ 'aa', 'bb', '' }, { 1, 0 }, { '2gcc' }, { '## aa', '## bb', '' }, { 1, 0 })\n  validate_edit({ 'aa', 'bb', '' }, { 1, 0 }, { 'gcc', 'j', '.' }, { '## aa', '## bb', '' }, { 2, 0 })\n\n  -- Visual mode\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'V', 'gc' }, { '## aa', 'bb' }, { 1, 0 })\n\n  -- Operator-pending mode\n  validate_edit({ '## aa', 'bb' }, { 1, 0 }, { 'dgc' }, { 'bb' }, { 1, 0 })\n  validate_edit({ '## aa', 'bb', '## cc' }, { 1, 0 }, { 'dgc', 'j', '.' }, { 'bb' }, { 1, 0 })\n\n  -- Works together with 'mini.ai' when `g` is trigger\n  if has_ai then\n    validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'gc', 'ip' }, { '## aa', '## bb', '', 'cc' }, { 1, 0 })\n  end\nend\n\nT[\"'mini.nvim' compatibility\"]['mini.indentscope'] = function()\n  child.lua('require(\"mini.indentscope\").setup()')\n\n  load_module({\n    triggers = {\n      { mode = 'n', keys = '[' },\n      { mode = 'n', keys = ']' },\n\n      { mode = 'x', keys = '[' },\n      { mode = 'x', keys = ']' },\n      { mode = 'x', keys = 'a' },\n      { mode = 'x', keys = 'i' },\n\n      { mode = 'o', keys = '[' },\n      { mode = 'o', keys = ']' },\n      { mode = 'o', keys = 'a' },\n      { mode = 'o', keys = 'i' },\n    },\n    window = { delay = 0 },\n  })\n  validate_trigger_keymap('n', '[')\n  validate_trigger_keymap('n', ']')\n  validate_trigger_keymap('x', '[')\n  validate_trigger_keymap('x', ']')\n  validate_trigger_keymap('x', 'a')\n  validate_trigger_keymap('x', 'i')\n  validate_trigger_keymap('o', '[')\n  validate_trigger_keymap('o', ']')\n  validate_trigger_keymap('o', 'a')\n  validate_trigger_keymap('o', 'i')\n\n  local lines = { 'aa', '\\tbb', '\\t\\tcc', '\\tdd', 'ee' }\n  local cursor = { 3, 2 }\n\n  -- Normal mode\n  validate_move(lines, cursor, '[i', { 2, 1 })\n  validate_move(lines, cursor, '2[i', { 1, 0 })\n\n  validate_move(lines, cursor, ']i', { 4, 1 })\n  validate_move(lines, cursor, '2]i', { 5, 0 })\n\n  -- Visual mode\n  validate_selection(lines, cursor, 'v[i', { 2, 1 }, { 3, 2 })\n  validate_selection(lines, cursor, 'v2[i', { 1, 0 }, { 3, 2 })\n\n  validate_selection(lines, cursor, 'v]i', { 3, 2 }, { 4, 1 })\n  validate_selection(lines, cursor, 'v2]i', { 3, 2 }, { 5, 0 })\n\n  validate_selection(lines, cursor, 'vai', { 2, 1 }, { 4, 1 }, 'V')\n  validate_selection(lines, cursor, 'v2ai', { 1, 0 }, { 5, 0 }, 'V')\n\n  validate_selection(lines, cursor, 'vii', { 3, 2 }, { 3, 2 }, 'V')\n  validate_selection(lines, cursor, 'v2ii', { 3, 2 }, { 3, 2 }, 'V')\n\n  -- Operator-pending mode\n  validate_edit(lines, cursor, 'd[i', { 'aa', '\\tcc', '\\tdd', 'ee' }, { 2, 1 })\n  validate_edit(lines, cursor, 'd2[i', { 'cc', '\\tdd', 'ee' }, { 1, 0 })\n  validate_edit(lines, cursor, 'd[i.', { 'cc', '\\tdd', 'ee' }, { 1, 0 })\n\n  validate_edit(lines, cursor, 'd]i', { 'aa', '\\tbb', '\\t\\tdd', 'ee' }, { 3, 2 })\n  validate_edit(lines, cursor, 'd2]i', { 'aa', '\\tbb', 'ee' }, { 3, 0 })\n  validate_edit(lines, cursor, 'd]i.', { 'aa', '\\tbb', 'ee' }, { 3, 0 })\n\n  validate_edit(lines, cursor, 'dai', { 'aa', 'ee' }, { 2, 1 })\n  validate_edit(lines, cursor, 'd2ai', { '' }, { 1, 0 })\n  validate_edit(lines, cursor, 'dai.', { 'aa', 'ee' }, { 2, 1 })\n\n  validate_edit(lines, cursor, 'dii', { 'aa', '\\tbb', '\\tdd', 'ee' }, { 3, 2 })\n  validate_edit(lines, cursor, 'd2ii', { 'aa', '\\tbb', '\\tdd', 'ee' }, { 3, 2 })\n  validate_edit(lines, cursor, 'dii.', { 'aa', 'ee' }, { 2, 1 })\nend\n\nT[\"'mini.nvim' compatibility\"]['mini.surround'] = function()\n  -- `saiw` works as expected when `s` and `i` are triggers: doesn't move cursor, no messages.\n\n  child.lua('require(\"mini.surround\").setup()')\n\n  -- Works together with 'mini.ai' without `s` as trigger\n  child.lua('require(\"mini.ai\").setup()')\n  load_module({ triggers = { { mode = 'o', keys = 'i' } }, window = { delay = 0 } })\n  validate_edit1d('aa bb', 0, { 'sa', 'iw', ')' }, '(aa) bb', 1)\n  validate_edit1d('aa ff(bb)', 0, { 'sa', 'if', ']' }, 'aa ff([bb])', 7)\n\n  -- Works with `s` as trigger\n  load_module({ triggers = { { mode = 'n', keys = 's' }, { mode = 'o', keys = 'i' } }, window = { delay = 0 } })\n  validate_trigger_keymap('n', 's')\n  validate_trigger_keymap('o', 'i')\n\n  -- Add\n  validate_edit1d('aa bb', 0, { 'sa', 'iw', ')' }, '(aa) bb', 1)\n  validate_edit1d('aa bb', 0, { '2sa', 'iw', ')' }, '((aa)) bb', 2)\n  validate_edit1d('aa bb', 0, { 'sa', '3iw', ')' }, '(aa bb)', 1)\n  validate_edit1d('aa bb', 0, { '2sa', '3iw', ')' }, '((aa bb))', 2)\n\n  validate_edit1d('aa bb', 0, { 'viw', 'sa', ')' }, '(aa) bb', 1)\n  validate_edit1d('aa bb', 0, { 'viw', '2sa', ')' }, '((aa)) bb', 2)\n\n  validate_edit1d('aa bb', 0, { 'sa', 'iw', ')', 'W', '.' }, '(aa) (bb)', 6)\n\n  -- Delete\n  validate_edit1d('(a(b(cc)b)a)', 5, 'sd)', '(a(bccb)a)', 4)\n  validate_edit1d('(a(b(cc)b)a)', 5, '2sd)', '(ab(cc)ba)', 2)\n\n  validate_edit1d('(a(b(cc)b)a)', 5, 'sd).', '(abccba)', 2)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'sdl)', 'aa (bb) (cc)', 0)\n  validate_edit1d('(aa) (bb) (cc)', 11, '2sdl)', 'aa (bb) (cc)', 0)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'sdn)', '(aa) (bb) cc', 10)\n  validate_edit1d('(aa) (bb) (cc)', 1, '2sdn)', '(aa) (bb) cc', 10)\n\n  -- Replace\n  validate_edit1d('(a(b(cc)b)a)', 5, 'sr)>', '(a(b<cc>b)a)', 5)\n  validate_edit1d('(a(b(cc)b)a)', 5, '2sr)>', '(a<b(cc)b>a)', 3)\n\n  validate_edit1d('(a(b(cc)b)a)', 5, 'sr)>.', '(a<b<cc>b>a)', 3)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'srl)>', '<aa> (bb) (cc)', 1)\n  validate_edit1d('(aa) (bb) (cc)', 11, '2srl)>', '<aa> (bb) (cc)', 1)\n\n  validate_edit1d('(aa) (bb) (cc)', 6, 'srn)>', '(aa) (bb) <cc>', 11)\n  validate_edit1d('(aa) (bb) (cc)', 1, '2srn)>', '(aa) (bb) <cc>', 11)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_cmdline.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('cmdline', config) end\nlocal unload_module = function(config) child.mini_unload('cmdline', config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Create a helper for mock-typing every key separately because state tracking\n-- can depend on emulating one-by-one key presses (mostly for autocorrect).\nlocal tbl_flatten = vim.fn.has('nvim-0.10') == 1 and function(x) return vim.iter(x):flatten(math.huge):totable() end\n  or vim.tbl_flatten\n\nlocal slice_keys = function(keys)\n  local res, cur_key = {}, ''\n  for i = 1, vim.fn.strchars(keys) do\n    cur_key = cur_key .. vim.fn.strcharpart(keys, i - 1, 1)\n    if cur_key:sub(1, 1) ~= '<' or cur_key:sub(-1) == '>' then\n      table.insert(res, cur_key)\n      cur_key = ''\n    end\n  end\n  return res\nend\n\nlocal type_every_key = function(...)\n  local wait, keys = nil, tbl_flatten({ ... })\n  if type(keys[1]) == 'number' then\n    wait, keys = keys[1], vim.list_slice(keys, 2)\n  end\n  local args = slice_keys(table.concat(keys, ''))\n  if wait ~= nil then table.insert(args, 1, wait) end\n\n  -- Always type keys one-by-one as this is needed to mock actual typing.\n  -- Otherwise state tracking is not emulated properly\n  child.type_keys(unpack(args))\nend\n\nlocal test_dir = 'tests/dir-cmdline'\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal validate_cmdline = function(line, pos)\n  eq(child.fn.mode(), 'c')\n  eq(child.fn.getcmdline(), line)\n  eq(child.fn.getcmdpos(), pos or line:len() + 1)\nend\n\nlocal expect_screenshot_after_keys = function(keys)\n  type_keys(keys)\n  child.expect_screenshot()\nend\n\n-- Data =======================================================================\nlocal lines_101 = {}\nfor i = 1, 101 do\n  lines_101[i] = 'Line ' .. i\nend\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      -- Use `--noplugin` flag for easier testing without built-in plugins\n      child.restart({ '--noplugin', '-u', 'scripts/minimal_init.lua' })\n      child.bo.readonly = false\n    end,\n    post_once = child.stop,\n    n_retry = helpers.get_n_retry(2),\n  },\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniCmdline)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniCmdline'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniCmdlinePeekBorder', 'links to FloatBorder')\n  has_highlight('MiniCmdlinePeekLineNr', 'links to DiagnosticSignWarn')\n  has_highlight('MiniCmdlinePeekNormal', 'links to NormalFloat')\n  has_highlight('MiniCmdlinePeekSign', 'links to DiagnosticSignHint')\n  has_highlight('MiniCmdlinePeekSep', 'links to SignColumn')\n  has_highlight('MiniCmdlinePeekTitle', 'links to FloatTitle')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n  eq(child.lua_get('type(_G.MiniCmdline.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniCmdline.config.' .. field), value) end\n\n  expect_config('autocomplete.enable', true)\n  expect_config('autocomplete.delay', 0)\n  expect_config('autocomplete.predicate', vim.NIL)\n  expect_config('autocomplete.map_arrows', true)\n  expect_config('autocorrect.enable', true)\n  expect_config('autocorrect.func', vim.NIL)\n  expect_config('autopeek.enable', true)\n  expect_config('autopeek.n_context', 1)\n  expect_config('autopeek.predicate', vim.NIL)\n  expect_config('autopeek.window.config', {})\n  expect_config('autopeek.window.statuscolumn', vim.NIL)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ autocomplete = 1 }, 'autocomplete', 'table')\n  expect_config_error({ autocomplete = { enable = 1 } }, 'autocomplete.enable', 'boolean')\n  expect_config_error({ autocomplete = { predicate = 1 } }, 'autocomplete.predicate', 'function')\n  expect_config_error({ autocomplete = { map_arrows = 1 } }, 'autocomplete.map_arrows', 'boolean')\n  expect_config_error({ autocorrect = 1 }, 'autocorrect', 'table')\n  expect_config_error({ autocorrect = { enable = 1 } }, 'autocorrect.enable', 'boolean')\n  expect_config_error({ autocorrect = { func = 1 } }, 'autocorrect.func', 'function')\n  expect_config_error({ autopeek = 1 }, 'autopeek', 'table')\n  expect_config_error({ autopeek = { enable = 1 } }, 'autopeek.enable', 'boolean')\n  expect_config_error({ autopeek = { window = 1 } }, 'autopeek.window', 'table')\n  expect_config_error({ autopeek = { n_context = 'a' } }, 'autopeek.n_context', 'number')\n  expect_config_error({ autopeek = { predicate = 1 } }, 'autopeek.predicate', 'callable')\n  expect_config_error({ autopeek = { window = { config = 1 } } }, 'autopeek.window.config', 'table or callab')\n  expect_config_error({ autopeek = { window = { statuscolumn = 1 } } }, 'autopeek.window.statuscolumn', 'callable')\nend\n\nT['setup()']['ensures colors'] = function()\n  load_module()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniCmdlinePeekBorder'), 'links to FloatBorder')\nend\n\nT['setup()']['sets recommended option values'] = function()\n  local check_wildmode = child.fn.has('nvim-0.11') == 1\n  load_module()\n  eq(child.o.wildoptions, 'pum,fuzzy')\n  if check_wildmode then eq(child.o.wildmode, 'noselect,full') end\n\n  -- Should not set if was previously set\n  child.o.wildoptions = 'pum'\n  if check_wildmode then child.o.wildmode = 'full' end\n  load_module()\n  eq(child.o.wildoptions, 'pum')\n  if check_wildmode then eq(child.o.wildmode, 'full') end\n\n  -- Should only set 'wildmode' if autocomplete is enabled\n  if check_wildmode then\n    child.restart({ '--noplugin', '-u', 'scripts/minimal_init.lua' })\n    load_module({ autocomplete = { enable = false } })\n    eq(child.o.wildmode, 'full')\n  end\nend\n\nT['default_autocomplete_predicate()'] = new_set()\n\nlocal default_autocomplete_predicate = forward_lua('MiniCmdline.default_autocomplete_predicate')\n\nT['default_autocomplete_predicate()']['works'] = function()\n  load_module({ autocorrect = { enable = false }, autopeek = { enable = false } })\n\n  local line, pos, line_prev, pos_prev = '', 1, '', 1\n  eq(default_autocomplete_predicate({ line = line, pos = pos, line_prev = line_prev, pos_prev = pos_prev }), false)\n\n  type_keys(':')\n\n  local validate = function(key, ref)\n    type_keys(key)\n    line_prev, pos_prev = line, pos\n    line, pos = child.fn.getcmdline(), child.fn.getcmdpos()\n    eq(default_autocomplete_predicate({ line = line, pos = pos, line_prev = line_prev, pos_prev = pos_prev }), ref)\n  end\n\n  -- Should return `true` only if there is alphabetic character\n  validate('1', false)\n  validate(',', false)\n  validate('2', false)\n  validate(' ', false)\n  validate('h', true)\n  validate(' ', true)\n  validate(\"'\", true)\n  type_keys('<Esc>')\n\n  line, pos, line_prev, pos_prev = '', 1, '', 1\n  type_keys(':')\n  validate(' ', false)\n  validate('h', true)\n  validate(' ', true)\n  validate(\"'\", true)\n  type_keys('<Esc>')\nend\n\nT['default_autocorrect_func()'] = new_set({ hooks = { pre_case = load_module } })\n\nlocal default_autocorrect_func = forward_lua('MiniCmdline.default_autocorrect_func')\n\nT['default_autocorrect_func()']['works'] = function()\n  -- Most of the testing is done in 'Autocorrect' test case\n  local validate = function(data, ref) eq(default_autocorrect_func(data), ref) end\n\n  -- General\n  validate({ word = 'ste', type = 'command' }, 'set')\n  validate({ word = 'set', type = 'command' }, 'set')\n\n  -- Strict type\n  validate({ word = 'rndomhue', type = 'color' }, 'randomhue')\n\n  -- Not strict type\n  validate({ word = 'MniCmdline', type = 'augroup' }, 'MniCmdline')\n\n  -- Empty string\n  validate({ word = 'xxx', type = '' }, 'xxx')\n  validate({ word = '', type = 'command' }, '')\n  validate({ word = '', type = '' }, '')\nend\n\nT['default_autocorrect_func()']['respects `opts.strict_type`'] = function()\n  local validate = function(data, ref) eq(default_autocorrect_func(data, { strict_type = false }), ref) end\n  validate({ word = 'MniCmdline', type = 'augroup' }, 'MiniCmdline')\n  validate({ word = 'Nrmal', type = 'highlight' }, 'Normal')\nend\n\nT['default_autocorrect_func()']['respects `opts.get_candidates`'] = function()\n  local out = child.lua([[\n    _G.log = {}\n    local get_cand = function(...) table.insert(_G.log, { ... }); return { 'xxx' } end\n    return MiniCmdline.default_autocorrect_func({ word = 'ste', type = 'color' }, { get_candidates = get_cand })\n  ]])\n  eq(out, 'xxx')\n  eq(child.lua_get('_G.log'), { { { type = 'color', word = 'ste' } } })\nend\n\nT['default_autocorrect_func()']['validates arguments'] = function()\n  expect.error(function() default_autocorrect_func(1) end, '`data`.*table')\n  expect.error(function() default_autocorrect_func({ word = 1, type = 'command' }) end, '`data.word`.*string')\n  expect.error(function() default_autocorrect_func({ word = 'ste', type = 1 }) end, '`data.type`.*string')\nend\n\nT['default_autopeek_predicate()'] = new_set()\n\nlocal default_autopeek_predicate = forward_lua('MiniCmdline.default_autopeek_predicate')\n\nT['default_autopeek_predicate()']['works'] = function()\n  load_module()\n  local validate = function(data, ref) eq(default_autopeek_predicate(data), ref) end\n\n  -- Should mostly return `true`\n  validate({ left = 1, right = 1, cmd = '' }, true)\n  validate({ left = 10, right = 1, cmd = '' }, true)\n  validate({ left = 1, right = 1, cmd = 'delete' }, true)\n  validate({ left = 1, right = 1, cmd = 'sort' }, true)\n\n  -- Should return `false` for (full) name of a command with preview\n  -- - Built-in commands\n  validate({ left = 1, right = 1, cmd = 'substitute' }, false)\n  validate({ left = 1, right = 1, cmd = 'smagic' }, false)\n  validate({ left = 1, right = 1, cmd = 'snomagic' }, false)\n\n  -- - User commands\n  child.lua([[\n    local opts = { preview = function() end, addr = 'lines', range = true }\n    vim.api.nvim_create_user_command('WithPreview', function()  end, opts)\n    vim.api.nvim_buf_create_user_command(0, 'BufWithPreview', function()  end, opts)\n  ]])\n\n  validate({ left = 1, right = 1, cmd = 'WithPreview' }, false)\n  validate({ left = 1, right = 1, cmd = 'BufWithPreview' }, false)\nend\n\nT['default_autopeek_statuscolumn()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(7, 15)\n      set_lines(lines_101)\n\n      load_module()\n\n      child.o.showtabline, child.o.laststatus = 0, 0\n      child.o.ruler = false\n    end,\n  },\n})\n\nlocal setup_statuscolumn = function(data, opts)\n  child.lua('_G.data = ' .. vim.inspect(data))\n  child.lua('_G.opts = ' .. vim.inspect(opts))\n  child.lua([[\n    _G.test_statuscolumn = function()\n      _G.res = MiniCmdline.default_autopeek_statuscolumn(_G.data, _G.opts)\n      return _G.res\n    end\n    vim.wo.statuscolumn = '%{%v:lua.test_statuscolumn()%}'\n    vim.cmd('redraw')\n  ]])\n\n  -- Ensure more informative screenshots\n  child.cmd('hi MiniCmdlinePeekLineNr guibg=Red ctermbg=Red')\n  child.cmd('hi MiniCmdlinePeekSign guibg=Green ctermbg=Green')\n  child.cmd('hi MiniCmdlinePeekSep guibg=Yellow ctermbg=Yellow')\nend\n\nlocal validate_statuscolumn = function(data, opts)\n  setup_statuscolumn(data, opts)\n  local last_line = child.o.lines\n  child.expect_screenshot({ ignore_text = { last_line }, ignore_attr = { last_line } })\nend\n\nT['default_autopeek_statuscolumn()']['works'] = function()\n  -- Different type of ranges\n  validate_statuscolumn({ left = 2, right = 5 })\n  validate_statuscolumn({ left = 4, right = 5 })\n  validate_statuscolumn({ left = 4, right = 4 })\n  validate_statuscolumn({ left = 5, right = 4 })\n  validate_statuscolumn({ left = 5, right = 2 })\n\n  -- Actually uses expected highlight groups\n  local ref_pat = '^%%#MiniCmdlinePeekSign#.*%%#MiniCmdlinePeekLineNr#.*%%#MiniCmdlinePeekSep#│$'\n  expect.match(child.lua_get('_G.res'), ref_pat)\n\n  -- Line numbers should be aligned to the right, but their highlighting should\n  -- start right after the sign (matters if different background).\n  set_cursor(7, 0)\n  child.cmd('normal! zt')\n  validate_statuscolumn({ left = 8, right = 10 })\nend\n\nT['default_autopeek_statuscolumn()']['works with wrapped and virtual lines'] = function()\n  child.set_size(10, 15)\n  set_lines({ '', 'Very big line number one', 'Very big line number two', '' })\n  local ns_id = child.api.nvim_create_namespace('Test')\n  child.api.nvim_buf_set_extmark(0, ns_id, 1, 0, { virt_lines = { { { 'Virt' } } } })\n  child.api.nvim_buf_set_extmark(0, ns_id, 3, 0, { virt_lines = { { { 'Virt above' } } }, virt_lines_above = true })\n\n  validate_statuscolumn({ left = 2, right = 3 })\nend\n\nT['default_autopeek_statuscolumn()']['respects `opts`'] = function()\n  local opts = {\n    signs = { same = '=', left = '<', mid = '-', right = '>', out = '*', virt = '$', wrap = '!' },\n    sep = '#',\n  }\n  -- All usages of `%` should be escaped as `%%`\n  local opts_percent = {\n    signs = { same = '%%', left = '%%', mid = '%%', right = '%%', out = '%%', virt = '%%', wrap = '%%' },\n    sep = '%%',\n  }\n\n  validate_statuscolumn({ left = 2, right = 5 }, opts)\n  validate_statuscolumn({ left = 2, right = 5 }, opts_percent)\n\n  set_lines({ '', 'Very big line number one', 'Very big line number two', '' })\n  local ns_id = child.api.nvim_create_namespace('Test')\n  child.api.nvim_buf_set_extmark(0, ns_id, 1, 0, { virt_lines = { { { 'Virt' } } } })\n  validate_statuscolumn({ left = 2, right = 2 }, opts)\n  validate_statuscolumn({ left = 2, right = 2 }, opts_percent)\nend\n\n-- Integration tests ==========================================================\nT['Autocomplete'] = new_set({\n  hooks = {\n    pre_case = function()\n      if child.fn.has('nvim-0.11') == 0 then MiniTest.skip('Autocompletion is available only on Neovim>=0.11') end\n\n      load_module({ autocorrect = { enable = false }, autopeek = { enable = false } })\n      child.set_size(10, 20)\n      child.o.pumheight, child.o.pumwidth = 5, 16\n      child.o.showtabline, child.o.laststatus = 0, 0\n    end,\n  },\n})\n\nlocal has_pum = function() return child.fn.wildmenumode() == 1 end\n\nT['Autocomplete']['works'] = function()\n  type_keys(':')\n\n  -- Should be no completion at the start\n  child.expect_screenshot()\n\n  -- Should trigger after the first character\n  expect_screenshot_after_keys('b')\n\n  -- Should respect `wildmenu=pum,fuzzy`, which is set by default\n  expect_screenshot_after_keys('f')\n\n  -- Should react to text deletion\n  expect_screenshot_after_keys('<BS>')\n  expect_screenshot_after_keys('<C-u>')\nend\n\nT['Autocomplete'][\"works with different 'wildchar'\"] = function()\n  child.cmd('set wildchar=<Down>')\n  type_keys(':', 'b')\n  eq(has_pum(), true)\n  validate_cmdline('b')\nend\n\nT['Autocomplete']['works with different completion types'] = function()\n  child.set_size(10, 30)\n  child.fn.chdir(test_dir)\n  child.o.wildoptions = 'pum'\n\n  type_keys(':', 'set ig')\n  child.expect_screenshot()\n  type_keys('<Esc>')\n\n  type_keys(':', 'edit ', 'f')\n  child.expect_screenshot()\n  type_keys('<Esc>')\n\n  type_keys(':', 'grep ', 'f')\n  child.expect_screenshot()\n  type_keys('<Esc>')\nend\n\nT['Autocomplete']['respects mappings'] = function()\n  -- Should not work if Command-line mode is both entered and exited\n  child.cmd('nnoremap <C-x> :sort<CR>')\n  type_keys('<C-x>')\n  eq(has_pum(), false)\n  eq(get_lines(), { '' })\nend\n\nT['Autocomplete']['works in edge cases'] = function()\n  -- After \"!\"\n  type_keys(':', 'q', '!')\n  validate_cmdline('q!')\n  eq(has_pum(), false)\n  type_keys('<Esc>')\n\n  -- With special commands\n  local validate_special_cmd = function(key)\n    set_lines({ 'Line 1', 'Line 2' })\n    type_keys(':', key)\n    child.api.nvim_input('/')\n    child.api.nvim_input('L')\n    -- Completion in thiese special cases is available only on Neovim>=0.12\n    if child.fn.has('nvim-0.12') == 1 then\n      child.expect_screenshot()\n    else\n      eq(has_pum(), false)\n    end\n    type_keys('<Esc>')\n  end\n\n  -- :substitute\n  validate_special_cmd('s')\n  -- :global\n  validate_special_cmd('g')\n  -- :vimgrep\n  validate_special_cmd('v')\nend\n\nT['Autocomplete']['does not throw completion related errors'] = function()\n  type_keys(':tag')\n  -- NOTE: Use `nvim_input` instead of `type_keys()` because the latter checks\n  -- `v:errmsg` to propagate the error. However, here on Neovim>=0.12 usage of\n  -- `vim.fn.wildtrigger()` *does* set `errmsg` but no error is actuall shown.\n  child.api.nvim_input(' ')\n  -- What actually should be tested is that there is no errors *shown*, but it\n  -- doesn't look easy, as behavior in child process and manual testing differ.\n  eq(child.cmd('messages'), '')\n  expect.no_match(child.v.errmsg, 'cmdline%.lua')\nend\n\nT['Autocomplete']['is not triggered when wildmenu is visible'] = function()\n  type_keys(':', 'b')\n  eq(has_pum(), true)\n  expect_screenshot_after_keys('<Tab>')\n  type_keys('<Esc>')\n\n  -- In combination with autocorrection\n  child.lua('MiniCmdline.config.autocorrect.enable = true')\n  child.fn.chdir(test_dir)\n  child.cmd('argadd fileA fileB')\n  type_keys(':', 'argdel fla', ' ')\n  validate_cmdline('argdel fileA ')\n  eq(has_pum(), true)\nend\n\nT['Autocomplete']['works in different command types'] = function()\n  set_lines({ 'aa', 'aaa', 'aaaa' })\n\n  local validate = function(keys)\n    eq(child.fn.mode(), 'n')\n    type_every_key(keys)\n    if child.fn.has('nvim-0.12') == 1 then\n      child.expect_screenshot({ ignore_attr = true })\n    else\n      eq(has_pum(), false)\n    end\n    type_keys('<Esc>', '<Esc>')\n  end\n\n  -- `/` and `?` can complete on Neovim>=0.12\n  validate({ '/', 'a' })\n  validate({ '?', 'a' })\n\n  -- Others command types - no completion\n  validate({ 'i', '<C-r>=', 'a' })\n  validate({ ':call input(\"\")<CR>', 'a' })\nend\n\nT['Autocomplete']['works with default predicate'] = function()\n  type_keys(':', '1')\n  eq(has_pum(), false)\n\n  type_keys('s')\n  eq(has_pum(), true)\n\n  type_keys('<BS>')\n  eq(has_pum(), false)\nend\n\nT['Autocomplete']['respects `config.autocomplete.delay`'] = function()\n  local delay = 10 * small_time\n  child.lua('MiniCmdline.config.autocomplete.delay = ' .. delay)\n\n  type_keys(':', 'b')\n  eq(has_pum(), false)\n  sleep(delay - 2 * small_time)\n  eq(has_pum(), false)\n\n  -- Should implement debounce-style delay\n  type_keys('u')\n  sleep(delay - 2 * small_time)\n  eq(has_pum(), false)\n  sleep(4 * small_time)\n  eq(has_pum(), true)\n\n  -- Should work when pum is visible\n  type_keys('f')\n  sleep(delay - 2 * small_time)\n  -- NOTE: Although no pum is present, on Neovim>=0.12 it is still drawn since\n  -- that is how `wildtrigger()` works. This results in less flickering.\n  eq(has_pum(), false)\n  sleep(4 * small_time)\n  eq(has_pum(), true)\n\n  -- Should work when deleting text\n  type_keys('<BS>')\n  sleep(delay - 2 * small_time)\n  eq(has_pum(), false)\n  sleep(4 * small_time)\n  eq(has_pum(), true)\nend\n\nT['Autocomplete']['should be triggered only during Command-line mode'] = function()\n  local delay = 10 * small_time\n  child.lua('MiniCmdline.config.autocomplete.delay = ' .. delay)\n\n  set_lines({ 'Line 1', 'Line 2' })\n  set_cursor(1, 0)\n  child.cmd('set wildchar=<Down>')\n\n  type_keys(':', 'b')\n  sleep(small_time)\n  type_keys('<Esc>')\n  sleep(delay + small_time)\n\n  eq(get_lines(), { 'Line 1', 'Line 2' })\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Autocomplete']['respects `config.autocomplete.predicate`'] = function()\n  child.lua([[\n    _G.res = true\n    _G.predicate_log = {}\n    MiniCmdline.config.autocomplete.predicate = function(...)\n      table.insert(_G.predicate_log, { ... })\n      return _G.res\n    end\n  ]])\n\n  local validate_log = function(ref)\n    eq(child.lua_get('_G.predicate_log'), ref)\n    child.lua('_G.predicate_log = {}')\n  end\n\n  local has_012 = child.fn.has('nvim-0.12') == 1\n\n  -- Should be called with proper data\n  type_keys(':')\n  eq(has_pum(), false)\n  validate_log({})\n\n  type_keys('1')\n  validate_log({ { { line = '1', pos = 2, line_prev = '', pos_prev = 1 } } })\n  eq(has_pum(), not has_012)\n\n  type_keys('s')\n  validate_log({ { { line = '1s', pos = 3, line_prev = '1', pos_prev = 2 } } })\n  eq(has_pum(), true)\n\n  type_keys('<C-u>')\n  validate_log({ { { line = '', pos = 1, line_prev = '1s', pos_prev = 3 } } })\n  eq(has_pum(), not has_012)\n  type_keys('<Esc>')\n\n  -- Should not show if `false`\n  child.lua('_G.res = false')\n  type_keys(':')\n  type_keys('s')\n  eq(has_pum(), false)\nend\n\nT['Autocomplete']['respects `vim.{g,b}.minicmdline_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicmdline_disable = true\n    type_keys(':', 'b')\n    eq(has_pum(), false)\n    type_keys('<Esc>')\n\n    child[var_type].minicmdline_disable = false\n    type_keys(':', 'b')\n    eq(has_pum(), true)\n  end,\n})\n\nT['Autocorrect'] = new_set({\n  hooks = {\n    pre_case = function() load_module({ autocomplete = { enable = false }, autopeek = { enable = false } }) end,\n  },\n})\n\nT['Autocorrect']['works for commands'] = function()\n  local validate = function(bad_word, ref_word)\n    type_every_key(':', bad_word, ' ')\n    validate_cmdline(ref_word .. ' ')\n    type_keys('<Esc>')\n  end\n\n  child.cmd('command MyCommand echo \"Hello\"')\n  child.cmd('command Git echo \"World\"')\n\n  -- Should correct for common edit types\n  validate('bbuffer', 'buffer') -- Deletion\n  validate('uffer', 'buffer') -- Insertion\n  validate('xuffer', 'buffer') -- Substitution\n  validate('ste', 'set') -- Transposition\n\n  -- Should respect abbreviations, even for user commands\n  validate('nmor', 'nnor')\n  validate('nmore', 'nnore')\n\n  validate('MxC', 'MyC')\n\n  validate('W', 'w')\n  validate('Q', 'q')\n\n  -- Should respect \"ignore case\" matches\n  validate('WrItE', 'write')\n  validate('W', 'w')\n  validate('NNO', 'nno')\n\n  validate('myc', 'MyC')\n\n  -- Should prefer \"respect case\" abbreviation over \"ignore case\"\n  validate('%g', '%g')\n\n  -- Should prefer transposition\n  validate('ua', 'au')\n\n  -- Should work with bang\n  type_keys(':', 'Q', '!')\n  validate_cmdline('q!')\n  type_keys('<Esc>')\n\n  -- Should work with range\n  type_keys(':', \"'a\")\n  validate_cmdline(\"'a\")\n  type_keys(',')\n  validate_cmdline(\"'a,\")\n  type_keys(\"'b\")\n  validate_cmdline(\"'a,'b\")\n  type_keys('<Esc>')\n\n  -- Should work with command modifiers\n  validate('abvelfet', 'aboveleft')\n\n  -- Should not correct `:=` command\n  -- validate('=123', '=123')\n  validate('=_G', '=_G')\nend\n\nT['Autocorrect']['works for options'] = function()\n  local validate_option = function(input, ref)\n    -- In progress\n    type_every_key(':', input, ' ')\n    validate_cmdline(ref .. ' ')\n    type_keys('<Esc>')\n\n    -- Final\n    type_every_key(':', input, '<CR>')\n    eq(child.fn.histget('cmd', -1), ref)\n  end\n\n  validate_option('set expndtb', 'set expandtab')\n  validate_option('set noexpndtb', 'set noexpandtab')\n  validate_option('set invexpndtb', 'set invexpandtab')\n  validate_option('set ET', 'set et')\n  validate_option('set noET', 'set noet')\n  validate_option('set invET', 'set invet')\n\n  validate_option('setlocal expndtb', 'setlocal expandtab')\n\n  -- Should work multiple times\n  type_every_key(':set ET inorecase nowrp invmgic ')\n  validate_cmdline('set et ignorecase nowrap invmagic ')\n  type_keys('<Esc>')\n\n  -- Correction when option is followed by not space\n  local validate_option_char = function(char)\n    type_every_key(':', 'set lstchars', char)\n    validate_cmdline('set listchars' .. char)\n    type_keys('<Esc>')\n\n    type_every_key(':', 'set LCS', char)\n    validate_cmdline('set lcs' .. char)\n    type_keys('<Esc>')\n  end\n\n  validate_option_char('=')\n  validate_option_char('?')\n  validate_option_char('!')\n  validate_option_char('&')\n  validate_option_char('^')\n  validate_option_char('+')\n  validate_option_char('-')\nend\n\nT['Autocorrect']['works for other types'] = function()\n  local validate_inprogress = function(input, ref)\n    type_every_key(':', input, ' ')\n    validate_cmdline(ref .. ' ')\n    type_keys('<Esc>')\n  end\n  local validate_final = function(input, ref)\n    type_every_key(':', input, '<CR>')\n    eq(child.fn.histget('cmd', -1), ref)\n  end\n\n  child.fn.chdir(test_dir)\n  child.cmd([[let &runtimepath.=','.getcwd()]])\n  child.cmd([[let &packpath.=','.getcwd()]])\n\n  -- arglist\n  child.cmd('argadd fileA fileB')\n  validate_inprogress('argdel fla', 'argdel fileA')\n  validate_final('argdel flb', 'argdel fileB')\n\n  -- color\n  -- - No in-progress check since `:colorscheme` expects single argument\n  validate_final('colorscheme dfault', 'colorscheme default')\n\n  -- compiler\n  -- - No in-progress check since `:compiler` expects single argument\n  validate_final('compiler tstcompiler', 'compiler testcompiler')\n\n  -- diff_buffer\n  child.cmd('edit fileA')\n  child.cmd('diffsplit fileB')\n  -- - No in-progress check since `:diffput` expects single argument\n  validate_final('diffput flA', 'diffput fileA')\n\n  child.cmd('%bwipeout')\n  child.cmd('only')\n\n  -- event\n  validate_inprogress('au Cmdlinelve', 'au CmdlineLeave')\n  validate_final('au BfEnter', 'au BufEnter')\n  type_keys('<C-c>')\n\n  -- filetype\n  -- - No in-progress check since `:setfiletype` expects single argument\n  validate_final('setfiletype pthon', 'setfiletype python')\n\n  -- history\n  -- - No in-progress check since `:history` expects single argument\n  validate_final('history srch', 'history search')\n\n  -- keymap\n  -- Neovim<0.10 has no 'keymap' `:h :command-complete` value\n  if child.fn.has('nvim-0.10') == 1 then\n    validate_inprogress('set keymap=tstkeymap', 'set keymap=testkeymap')\n    validate_final('set keymap=tstkeymap', 'set keymap=testkeymap')\n  end\n\n  -- locale\n  -- - No in-progress check since `:language time` expects single argument\n  -- No easy way to test locales on non-Linux\n  if child.fn.has('linux') == 1 then validate_final('language time PSX', 'language time POSIX') end\n\n  -- mapclear\n  -- Neovim<0.11 has wrong `complpat` computation in this case\n  if child.fn.has('nvim-0.11') == 1 then\n    -- - No in-progress check since `:mapclear` expects single argument\n    validate_final('mapclear <LT>bfr>', 'mapclear <buffer>')\n  end\n\n  -- messages\n  -- - No in-progress check since `:messages` expects single argument\n  validate_final('messages clr', 'messages clear')\n\n  -- packadd\n  -- - No in-progress check since `:packadd` expects single argument\n  validate_final('packadd tstplugin', 'packadd testplugin')\n\n  -- sign\n  validate_inprogress('sign dfine', 'sign define')\n  validate_final('sign lst', 'sign list')\n\n  -- syntax\n  -- Neovim<0.10 does not set `compltype=syntax` in this case\n  if child.fn.has('nvim-0.10') == 1 then\n    validate_inprogress('set syntax=LUA', 'set syntax=lua')\n    validate_final('set syntax=LUA', 'set syntax=lua')\n  end\n\n  -- syntime\n  -- - No in-progress check since `:syntime` expects single argument\n  validate_final('syntime clr', 'syntime clear')\nend\n\nT['Autocorrect']['works multiple times'] = function()\n  type_every_key(':', 'srot', ' ')\n  validate_cmdline('sort ')\n\n  -- After delete\n  type_every_key('<C-u>', 'abvoelfet', ' ')\n  validate_cmdline('aboveleft ')\n\n  -- After another typed autocorrection\n  type_every_key('noutocmd', ' ')\n  validate_cmdline('aboveleft noautocmd ')\n\n  type_every_key('sort', ' ')\n  validate_cmdline('aboveleft noautocmd sort ')\nend\n\nT['Autocorrect']['works only in `:` command type'] = function()\n  local validate = function(keys, ref)\n    eq(child.fn.mode(), 'n')\n    type_every_key(keys)\n    validate_cmdline(ref)\n    type_keys('<Esc>', '<Esc>')\n  end\n  validate('/srot ', 'srot ')\n  validate('?srot ', 'srot ')\n  validate('i<C-r>=srot ', 'srot ')\nend\n\nT['Autocorrect']['respects mappings'] = function()\n  -- Should not work if Command-line mode is both entered and exited\n  child.cmd('nnoremap <C-x> :ehco<CR>')\n  local ok, err = pcall(type_keys, '<C-x>')\n  eq(ok, false)\n  eq(err, 'E492: Not an editor command: ehco')\n\n  -- Should act if text increases latest word by a single character\n  child.cmd('cnoremap <C-x> w')\n  type_keys(':', 'XX', '<C-x>')\n  validate_cmdline('XXw')\n  type_keys(' ')\n  validate_cmdline('bw ')\n  type_keys('<Esc>')\n\n  -- Should act if text finishes the last word\n  child.cmd('cnoremap <C-y> <Space>')\n  type_keys(':', 'XX', '<C-y>')\n  validate_cmdline('ex ')\n  type_keys('<Esc>')\nend\n\nT['Autocorrect']['respects abbreviations'] = function()\n  child.lua([[\n    _G.log = {}\n    local orig = MiniCmdline.default_autocorrect_func\n    MiniCmdline.default_autocorrect_func = function(...)\n      table.insert(_G.log, vim.deepcopy({ ... }))\n      return orig(...)\n    end\n  ]])\n\n  child.cmd('cabbrev Y wincmd')\n  child.cmd('cnoreabbrev <buffer> D bwipeout')\n\n  type_keys(':', 'Y', ' ')\n  validate_cmdline('wincmd ')\n  type_keys('<Esc>')\n\n  type_keys(':', 'D', '<CR>')\n  eq(child.fn.histget('cmd', -1), 'bwipeout')\n\n  -- Should not call `config.autocorrect.func` for abbreviations\n  eq(child.lua_get('_G.log'), {})\nend\n\nT['Autocorrect']['ignores editing previous text'] = function()\n  type_keys(':', 'set ', '<Left>')\n  type_keys('<BS>')\n  validate_cmdline('se ', 3)\n  type_keys('T')\n  validate_cmdline('seT ', 4)\n  type_keys(' ')\n  validate_cmdline('seT  ', 5)\n  type_keys('<Esc>')\n\n  -- Appending after editing\n  MiniTest.skip('Make it work or declare out of scope. Problematic because complpat and pos_prev are not relevant')\n  type_keys(':', 'rot', '<Home>', 's', '<End>', ' ')\n  validate_cmdline('sort ')\nend\n\nT['Autocorrect']['ignores navigating through history'] = function()\n  child.cmd('command Icommand echo \"Hello\"')\n  type_keys(':', 'Icommand ', '<Esc>')\n  -- Should not autocorrect `I` to `i` (as it happens in case of `:I<Space>`)\n  type_keys(':', 'I', '<Up>')\n  validate_cmdline('Icommand ')\nend\n\nT['Autocorrect']['correctly computes word to autocorrect'] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip('Requires `getcmdcomplpat()`, present in Neovim>=0.11') end\n\n  local validate = function(text, final_key, ref)\n    type_keys(':', text, final_key)\n    validate_cmdline(ref)\n    type_keys('<Esc>')\n  end\n\n  validate(\"'a,'bsrot\", ' ', \"'a,'bsort \")\n  validate(\"'a,'bsrot\", '!', \"'a,'bsort!\")\n  validate(\"'a,''srot\", ' ', \"'a,''sort \")\nend\n\nT['Autocorrect']['does not correct valid words'] = function()\n  child.cmd('au CmdlineChanged * lua _G.n = (_G.n or 0) + 1')\n\n  local validate = function(word)\n    type_keys(':', word)\n    child.lua('_G.n = 0')\n    type_keys(' ')\n    validate_cmdline(word .. ' ')\n    eq(child.lua_get('_G.n'), 1)\n\n    type_keys('<Esc>')\n  end\n\n  validate('cnoremap')\n  validate('cnor')\n\n  child.cmd('command MyCommand echo \"Hello\"')\n  validate('MyCommand')\n  validate('MyC')\n\n  child.cmd('vsplit')\n  local win_id = child.api.nvim_get_current_win()\n  type_keys(':', 'q', '!', '<CR>')\n  eq(child.api.nvim_win_is_valid(win_id), false)\nend\n\nT['Autocorrect']['suggests only valid abbreviations'] = function()\n  -- Should uniquely identify user commands\n  child.cmd('command MyCommandA echo \"Hello\"')\n  child.cmd('command MyCommandB echo \"World\"')\n\n  type_keys(':', 'MyComman', ' ')\n  validate_cmdline('MyCommandA ')\n  type_keys('<Esc>')\n\n  -- `:def` is not a valid abbreviation\n  type_keys(':', 'def', ' ')\n  validate_cmdline('de ')\n  type_keys('<Esc>')\nend\n\nT['Autocorrect']['respects `config.autocorrect.func`'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniCmdline.config.autocorrect.func = function(data)\n      table.insert(_G.log, vim.deepcopy(data))\n      return _G.correction\n    end\n  ]])\n\n  child.lua('_G.correction = \"xxxx\"')\n  type_keys(':', 'srot')\n  eq(child.lua_get('_G.log'), {})\n  type_keys(' ')\n  -- NOTE: Should not autocorrect output\n  validate_cmdline('xxxx ')\n  eq(child.lua_get('_G.log'), { { word = 'srot', type = 'command' } })\n  child.lua('_G.log = {}')\n  type_keys('<Esc>')\n\n  -- Should not change command line if output is same word or `nil`\n  child.cmd('au CmdlineChanged * lua _G.n = (_G.n or 0) + 1')\n  local validate_no_change = function(correction)\n    child.lua('_G.correction = ' .. vim.inspect(correction))\n    type_keys(':', 'srot')\n    child.lua('_G.n = 0')\n\n    type_keys(' ')\n    validate_cmdline('srot ')\n    eq(child.lua_get('_G.n'), 1)\n\n    type_keys('<Esc>')\n  end\n\n  validate_no_change('srot')\n  validate_no_change(nil)\n\n  -- Handles improper output\n  child.lua([[\n    _G.notify_log = {}\n    vim.notify = function(...) table.insert(_G.notify_log, { ... }) end\n    MiniCmdline.config.autocorrect.func = function() return 1 end\n  ]])\n  type_keys(':', 'srot', ' ')\n  validate_cmdline('srot ')\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n  eq(child.lua_get('_G.notify_log'), { { '(mini.cmdline) Can not autocorrect for \"srot\"', warn_level } })\nend\n\nT['Autocorrect']['works just before final <CR>'] = function()\n  local validate = function(bad_word, ref_word)\n    type_every_key(':', bad_word, '<CR>')\n    eq(child.fn.histget('cmd', -1), ref_word)\n    eq(child.fn.mode(), 'n')\n  end\n\n  local buf_id_other = child.api.nvim_create_buf(true, false)\n  validate('bnxxt', 'bnext')\n  eq(child.api.nvim_get_current_buf(), buf_id_other)\n  type_keys('<Esc>')\n\n  -- Should work with `!`\n  child.cmd('vsplit')\n  local win_id = child.api.nvim_get_current_win()\n  validate({ 'Q', '!' }, 'q!')\n  eq(child.api.nvim_win_is_valid(win_id), false)\nend\n\nT['Autocorrect']['is not applied when abandoning command line'] = function()\n  local validate = function(key)\n    type_keys(':', 'xxxx', key)\n    eq(child.fn.histget('cmd', -1), 'xxxx')\n  end\n  validate('<Esc>')\n  validate('<C-c>')\nend\n\nT['Autocorrect']['uses correct state before final <CR>'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniCmdline.config.autocorrect.func = function(data)\n      table.insert(_G.log, vim.deepcopy(data))\n      return data.word\n    end\n  ]])\n\n  -- Changing `type` just before `<CR>`\n  type_every_key(':', 'cnoremap <LT>C-x> www', '<CR>')\n  type_every_key(':', 'cnoremap <LT>C-x> ww', '<Up>')\n  validate_cmdline('cnoremap <C-x> www')\n  child.lua('_G.log = {}')\n  type_keys('<CR>')\n  local ref_word = child.fn.has('nvim-0.11') == 1 and '<C-x> www' or 'www'\n  eq(child.lua_get('_G.log'), { { word = ref_word, type = 'mapping' } })\n\n  -- Should include `!` in the word (when using `vim.fn.getcmdcomplpat()`)\n  if child.fn.has('nvim-0.11') == 0 then return end\n  child.cmd('split')\n  child.lua('_G.log = {}')\n  type_every_key(':', 'q!', '<CR>')\n  eq(child.lua_get('_G.log'), { { word = 'q!', type = '' } })\nend\n\nT['Autocorrect']['respects `vim.{g,b}.minicmdline_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicmdline_disable = true\n    type_keys(':', 'seT', ' ')\n    validate_cmdline('seT ')\n  end,\n})\n\nT['Autopeek'] = new_set({\n  hooks = {\n    pre_case = function()\n      load_module({ autocomplete = { enable = false }, autocorrect = { enable = false } })\n\n      child.set_size(11, 20)\n      set_lines(lines_101)\n\n      child.o.tabline, child.o.statusline = 'My tabline', 'My statusline'\n      child.o.showtabline, child.o.laststatus = 2, 2\n\n      -- Ensure more informative screenshots\n      child.cmd('hi MiniCmdlinePeekLineNr guibg=Red ctermbg=Red')\n      child.cmd('hi MiniCmdlinePeekSign guibg=Green ctermbg=Green')\n      child.cmd('hi MiniCmdlinePeekSep guibg=Yellow ctermbg=Yellow')\n    end,\n  },\n})\n\nlocal get_peek_win_id = function()\n  local buf_id = child.api.nvim_get_current_buf()\n  for _, win_id in ipairs(child.api.nvim_list_wins()) do\n    local is_float = child.api.nvim_win_get_config(win_id).relative ~= ''\n    if is_float and child.api.nvim_win_get_buf(win_id) == buf_id then return win_id end\n  end\nend\n\nlocal get_peek_winheight = function()\n  local peek_win_id = get_peek_win_id()\n  return peek_win_id == nil and 0 or child.api.nvim_win_get_height(peek_win_id)\nend\n\nlocal validate_no_peek = function() eq(get_peek_winheight() == 0, true) end\nlocal validate_peek = function() eq(get_peek_winheight() > 0, true) end\n\nT['Autopeek']['works'] = function()\n  type_keys(':')\n  expect_screenshot_after_keys('2')\n\n  -- Empty range end means cursor line\n  expect_screenshot_after_keys(',')\n\n  -- Explicit same line range should be the same as one number range\n  expect_screenshot_after_keys('2')\n\n  expect_screenshot_after_keys('0')\n\n  -- Should truncate to last available line\n  expect_screenshot_after_keys('0')\n\n  -- Should update after deleting text\n  expect_screenshot_after_keys('<BS>')\n  expect_screenshot_after_keys('<C-w>')\n  expect_screenshot_after_keys('<C-u>')\n\n  -- Should work with blank line\n  expect_screenshot_after_keys(' ')\n\n  -- Exiting Command-line mode should hide peek window\n  type_keys('<Esc>')\n  validate_no_peek()\nend\n\nT['Autopeek']['persists for the entirety of command typing'] = function()\n  type_keys(':')\n  expect_screenshot_after_keys('2')\n  expect_screenshot_after_keys('delete ')\n  expect_screenshot_after_keys('_ 3')\n  type_keys('<CR>')\n  eq(child.api.nvim_buf_get_lines(0, 0, 2, false), { 'Line 1', 'Line 5' })\nend\n\nT['Autopeek']['correctly computes lines to show'] = function()\n  type_keys(':')\n\n  -- Apart, near edges\n  expect_screenshot_after_keys('<C-u>1,101')\n  expect_screenshot_after_keys('<C-u>2,101')\n  expect_screenshot_after_keys('<C-u>1,100')\n  expect_screenshot_after_keys('<C-u>2,100')\n\n  -- Apart, away from edges\n  expect_screenshot_after_keys('<C-u>3,99')\n\n  -- One line in between contexts (no fold should be visible)\n  expect_screenshot_after_keys('<C-u>3,7')\n\n  -- Touching contexts\n  expect_screenshot_after_keys('<C-u>3,6')\n\n  -- Intersecting contexts\n  expect_screenshot_after_keys('<C-u>3,5')\n\n  -- Touching range lines\n  expect_screenshot_after_keys('<C-u>3,4')\nend\n\nT['Autopeek']['works with inverted range'] = function()\n  type_keys(':')\n\n  expect_screenshot_after_keys('<C-u>101,1')\n  expect_screenshot_after_keys('<C-u>101,2')\n  expect_screenshot_after_keys('<C-u>100,1')\n  expect_screenshot_after_keys('<C-u>100,2')\n  expect_screenshot_after_keys('<C-u>99,3')\n  expect_screenshot_after_keys('<C-u>7,3')\n  expect_screenshot_after_keys('<C-u>6,3')\n  expect_screenshot_after_keys('<C-u>5,3')\n  expect_screenshot_after_keys('<C-u>4,3')\nend\n\nT['Autopeek']['can be hidden and opened within same session'] = function()\n  type_keys(':')\n\n  validate_no_peek()\n  type_keys('2')\n  validate_peek()\n  type_keys(',')\n  validate_peek()\n  type_keys('<C-u>')\n  validate_no_peek()\n\n  type_keys('1')\n  validate_peek()\n  type_keys('<BS>')\n  validate_no_peek()\nend\n\nT['Autopeek'][\"works with 'inccommand'\"] = function()\n  -- Explicitly enable autopeek, as by default it is not shown for commands\n  -- with preview\n  child.lua('MiniCmdline.config.autopeek.predicate = function() return true end')\n\n  type_keys(':')\n  local validate = function(keys)\n    child.api.nvim_input(keys)\n    child.expect_screenshot()\n  end\n  validate('2s')\n  validate('/')\n  validate('Li')\n  validate('/')\n  validate('XX')\n\n  validate('/<CR>')\n  validate_no_peek()\n  eq(child.api.nvim_buf_get_lines(0, 0, 2, false), { 'Line 1', 'XXne 2' })\nend\n\nT['Autopeek']['respects mappings'] = function()\n  -- Should not work if Command-line mode is both entered and exited\n  child.cmd('nnoremap <C-x> :2,3sort<CR>')\n  type_keys('<C-x>')\n  validate_no_peek()\n\n  -- Should work if Command-line mode is only entered\n  child.cmd('nnoremap <C-y> :3,4')\n  expect_screenshot_after_keys('<C-y>')\nend\n\nT['Autopeek']['uses correct highlight groups'] = function()\n  type_keys(':', '2')\n  local win_id = get_peek_win_id()\n  local peek_winhl = child.api.nvim_get_option_value('winhighlight', { scope = 'local', win = win_id })\n  expect.match(peek_winhl, 'NormalFloat:MiniCmdlinePeekNormal')\n  expect.match(peek_winhl, 'FloatBorder:MiniCmdlinePeekBorder')\n  expect.match(peek_winhl, 'FloatTitle:MiniCmdlinePeekTitle')\nend\n\nT['Autopeek'][\"ignores 'wrap'\"] = function()\n  set_lines({ 'Very big line number one', '', '', 'Very big line number two' })\n  child.o.wrap = true\n\n  type_keys(':')\n  expect_screenshot_after_keys('<C-u>2')\n  expect_screenshot_after_keys('<C-u>2,3')\n  expect_screenshot_after_keys('<C-u>1,4')\n  type_keys('<Esc>')\n\n  -- Should also respect global 'list' and 'listchars'\n  type_keys(':')\n  child.o.list = true\n  child.o.listchars = 'precedes:<,extends:>'\n  expect_screenshot_after_keys('<C-u>2,3')\nend\n\nT['Autopeek']['works with virtual lines'] = function()\n  local ns_id = child.api.nvim_create_namespace('Test')\n  child.api.nvim_buf_set_extmark(0, ns_id, 1, 0, { virt_lines = { { { 'Virt' } } } })\n  child.api.nvim_buf_set_extmark(0, ns_id, 3, 0, { virt_lines = { { { 'Virt above' } } }, virt_lines_above = true })\n\n  -- Currently context computation doesn't take virtual lines into account.\n  -- Ideally their extmarks should not be shown, but doing that is difficult.\n  -- It is much easier to show buffer as is and document issue with virtual\n  -- lines as a known limitation.\n  type_keys(':')\n  expect_screenshot_after_keys('<C-u>2')\n  expect_screenshot_after_keys('<C-u>4')\n  expect_screenshot_after_keys('<C-u>2,4')\n  type_keys('<Esc>')\n\n  -- Zero context should work better\n  child.lua('MiniCmdline.config.autopeek.n_context = 0')\n  type_keys(':')\n  expect_screenshot_after_keys('<C-u>2')\n  expect_screenshot_after_keys('<C-u>4')\n  expect_screenshot_after_keys('<C-u>2,4')\nend\n\nT['Autopeek']['hides visual selection'] = function()\n  child.set_size(15, 20)\n\n  -- The range preview is already a preview of Visual selection\n  set_cursor(2, 1)\n  type_keys('v', '2j', ':')\n  child.expect_screenshot()\n  eq(get_cursor(), { 2, 1 })\n  type_keys('<Esc>')\n\n  -- Should be overridable via autocommand before `require('mini.cmdline')`\n  unload_module()\n  child.lua([[\n    local disable = vim.schedule_wrap(function()\n      local is_from_visual = vim.startswith(vim.fn.getcmdline(), \"'<,'>\")\n      MiniCmdline.config.autopeek.enable = not is_from_visual\n    end)\n    local reenable = function() MiniCmdline.config.autopeek.enable = true end\n\n    vim.api.nvim_create_autocmd('CmdlineEnter', { callback = disable })\n    vim.api.nvim_create_autocmd('CmdlineLeave', { callback = reenable })\n  ]])\n  load_module()\n\n  type_keys('v', '2j', ':')\n  child.expect_screenshot({ redraw = false })\n  type_keys('<Esc>')\n\n  type_keys(':', '5')\n  validate_peek()\nend\n\nT['Autopeek']['works with every kind of line range'] = function()\n  set_cursor(3, 0)\n  type_keys('Vj', '<Esc>')\n\n  set_cursor(10, 1)\n  type_keys('ma')\n  set_cursor(12, 0)\n  type_keys('mb')\n\n  set_cursor(2, 0)\n  type_keys(':')\n\n  -- `:h :range`\n  expect_screenshot_after_keys('<C-u>.,$')\n  expect_screenshot_after_keys('<C-u>%')\n  expect_screenshot_after_keys('<C-u>*')\n  expect_screenshot_after_keys(\"<C-u>'<LT>,'>\")\n  expect_screenshot_after_keys(\"<C-u>'a,'b\")\n  expect_screenshot_after_keys(\"<C-u>'b,'a\")\n  expect_screenshot_after_keys('<C-u>/Line 5/,/Line 4/')\n  expect_screenshot_after_keys('<C-u>/Line 5/;/Line 4/')\n  expect_screenshot_after_keys('<C-u>?Line 5?,?Line 6?')\n  expect_screenshot_after_keys('<C-u>?Line 5?;?Line 6?')\n\n  -- `:h range-offset`\n  expect_screenshot_after_keys('<C-u>++,-')\n  expect_screenshot_after_keys(\"<C-u>'<LT>+2,'a--\")\n  expect_screenshot_after_keys('<C-u>/5/+100,/4/-100')\nend\n\nT['Autopeek']['is shown only for line range'] = function()\n  type_keys(':')\n\n  -- Should assume line range by default\n  type_keys('%')\n  validate_peek()\n\n  -- `:bwipeout` doesn't treat range as lines, see `:h :command-addr`\n  type_keys('bw')\n  validate_no_peek()\n\n  type_keys('<C-w>')\n  validate_peek()\nend\n\nT['Autopeek']['is not shown for commands with preview'] = function()\n  local validate = function(command_keys)\n    type_keys(':', '2')\n    type_keys(command_keys)\n    validate_no_peek()\n    type_keys('<Esc>')\n  end\n\n  -- Built-in commands\n  validate('substitute')\n  validate('s')\n  validate('smagic')\n  validate('sm')\n  validate('snomagic')\n  validate('sno')\n\n  -- User commands\n  child.lua([[\n    local opts = { preview = function() end, addr = 'lines', range = true }\n    vim.api.nvim_create_user_command('WithPreview', function()  end, opts)\n    vim.api.nvim_buf_create_user_command(0, 'BufWithPreview', function()  end, opts)\n  ]])\n\n  validate('WithPreview')\n  validate('WithP')\n  validate('BufWithPreview')\n  validate('BufWithP')\nend\n\nT['Autopeek']['works when regular command line parsing fails'] = function()\n  type_keys('/', 'Line 10', '<CR>')\n  child.cmd('nohlsearch')\n\n  type_keys(':')\n\n  -- Line with only range\n  expect_screenshot_after_keys('<C-u>%')\n\n  -- Unfinished `/xxx/` range\n  expect_screenshot_after_keys('<C-u>/')\n  expect_screenshot_after_keys('Li')\n  expect_screenshot_after_keys('ne 4')\n  expect_screenshot_after_keys('/,')\n  expect_screenshot_after_keys('/Line 6')\n\n  -- Unrecognized command\n  expect_screenshot_after_keys('<C-u>1xxx')\n  expect_screenshot_after_keys('<C-u>1,2xxx')\n  expect_screenshot_after_keys('<C-u>%xxx')\nend\n\nT['Autopeek']['reacts to command line height change during typing'] = function()\n  child.set_size(10, 15)\n\n  local long_line = string.rep('a', 16)\n  type_keys(':', '2,5')\n\n  -- Should reposition on top of new command line height\n  expect_screenshot_after_keys(long_line)\n\n  -- Should adjust height if not enough space\n  expect_screenshot_after_keys(long_line)\n  expect_screenshot_after_keys(long_line)\nend\n\nT['Autopeek']['reacts to `VimResized`'] = function()\n  child.set_size(10, 20)\n  type_keys(':')\n  expect_screenshot_after_keys('2,5')\n\n  child.set_size(10, 25)\n  child.expect_screenshot()\n\n  child.set_size(15, 15)\n  child.expect_screenshot()\n\n  child.set_size(6, 20)\n  child.expect_screenshot()\nend\n\nT['Autopeek'][\"works with different 'cmdheight'\"] = function()\n  child.o.cmdheight = 0\n  expect_screenshot_after_keys(':2,5')\n  type_keys('<Esc>')\n\n  child.o.cmdheight = 2\n  expect_screenshot_after_keys(':2,5')\n  type_keys('<Esc>')\nend\n\nT['Autopeek']['works only in `:` command type'] = function()\n  local validate = function(keys)\n    eq(child.fn.mode(), 'n')\n    type_keys(keys)\n    validate_no_peek()\n    type_keys('<Esc>', '<Esc>')\n  end\n  validate({ '/', '2' })\n  validate({ '?', '2' })\n  validate({ 'i', '<C-r>=', '2' })\n  validate({ 'call input(\"\")<CR>', '2' })\nend\n\nT['Autopeek']['is shown below pmenu and <C-d> output'] = function()\n  type_keys(':', '1,2sor')\n  expect_screenshot_after_keys('<Tab>')\n\n  -- Testing via screenshot requires `{ redraw = false }`, but it displays peek\n  -- window in wrong place (not like when testing interactively).\n  -- So test indirectly via verifying `zindex` (should be below 200).\n  local peek_win_id = get_peek_win_id()\n  eq(child.api.nvim_win_get_config(peek_win_id).zindex, 199)\nend\n\nT['Autopeek']['respects `config.autopeek.window.config`'] = function()\n  -- As table\n  child.lua([[MiniCmdline.config.autopeek.window.config = { border = 'none', width = 15 }]])\n  expect_screenshot_after_keys({ ':', '2' })\n  type_keys('<Esc>')\n\n  -- As callable\n  child.lua([[MiniCmdline.config.autopeek.window.config = function()\n    return { border = 'double', width = 0.25 * vim.o.columns, height = 5, title = 'Custom title to check truncation' }\n  end]])\n  expect_screenshot_after_keys({ ':', '2' })\n  type_keys('<Esc>')\n\n  -- Should properly truncate title\n  child.lua([[\n    local title = string.sub('abcdefgijklmnopqrstuvwxyz', -vim.o.columns)\n    MiniCmdline.config.autopeek.window.config = { width = vim.o.columns, title = title }\n  ]])\n  expect_screenshot_after_keys({ ':', '2' })\nend\n\nT['Autopeek']['respects `config.autopeek.window.statuscolumn`'] = function()\n  child.lua([[\n    MiniCmdline.config.autopeek.window.statuscolumn = function(...)\n      _G.args = { ... }\n      return '!' .. vim.v.lnum\n    end\n  ]])\n\n  set_cursor(3, 0)\n  type_keys(':')\n\n  local validate = function(key, ref_args)\n    type_keys(key)\n    eq(child.lua_get('_G.args'), ref_args)\n    child.lua('_G.args = nil')\n  end\n\n  validate('2', { { left = 2, right = 2, cmd = '' } })\n  child.expect_screenshot()\n\n  validate(',', { { left = 2, right = 3, cmd = '' } })\n  validate('4', { { left = 2, right = 4, cmd = '' } })\n  validate('d', { { left = 2, right = 4, cmd = 'delete' } })\n  validate('<BS>', { { left = 2, right = 4, cmd = '' } })\nend\n\nT['Autopeek'][\"respects 'winborder'\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  local validate = function(winborder)\n    child.o.winborder = winborder\n    type_keys(':')\n    expect_screenshot_after_keys(':2,100')\n    type_keys('<Esc>')\n  end\n\n  validate('rounded')\n\n  -- Should prefer explicitly configured value over 'winborder'\n  child.lua('MiniCmdline.config.autopeek.window.config = { border = \"double\" }')\n  validate('rounded')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.lua('MiniCmdline.config.autopeek.window.config.border = nil')\n  validate('+,-,+,|,+,-,+,|')\nend\n\nT['Autopeek']['correctly shows window without border'] = function()\n  child.lua('MiniCmdline.config.autopeek.window.config = { border = \"none\" }')\n\n  local validate = function(screen_lines, range)\n    child.set_size(screen_lines, 20)\n    type_keys(':')\n    expect_screenshot_after_keys(range)\n    type_keys('<Esc>')\n  end\n\n  validate(10, '1,101')\n  validate(10, '2,100')\n  validate(10, '2,5')\n  validate(10, '2,2')\n\n  -- No context\n  child.lua('MiniCmdline.config.autopeek.n_context = 0')\n  validate(10, '2,101')\n\n  -- Extreme available height\n  validate(4, '2,4')\nend\n\nT['Autopeek']['respects `config.autopeek.n_context`'] = function()\n  child.lua('MiniCmdline.config.autopeek.n_context = 0')\n\n  type_keys(':')\n  expect_screenshot_after_keys('<C-u>1,101')\n  expect_screenshot_after_keys('<C-u>2,101')\n  expect_screenshot_after_keys('<C-u>1,100')\n  expect_screenshot_after_keys('<C-u>2,100')\n  expect_screenshot_after_keys('<C-u>2,4')\n  expect_screenshot_after_keys('<C-u>2,3')\n  expect_screenshot_after_keys('<C-u>2,2')\nend\n\nT['Autopeek']['respects `config.autopeek.predicate`'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`:cbuffer` has addr=? on Neovim<0.10') end\n\n  child.lua([[\n    _G.log = {}\n    MiniCmdline.config.autopeek.predicate = function(data)\n      table.insert(_G.log, vim.deepcopy(data))\n      return data.left > 9 and data.right > 9 and (data.cmd == '' or data.cmd == 'change')\n    end\n  ]])\n\n  local validate = function(key, is_shown, ref_log)\n    child.lua('_G.log = {}')\n    type_keys(key)\n    if is_shown then return validate_peek() end\n    if not is_shown then validate_no_peek() end\n    eq(child.lua_get('_G.log'), ref_log)\n  end\n\n  set_cursor(9, 0)\n\n  type_keys(':')\n  validate('1', false, { { left = 1, right = 1, cmd = '' } })\n  validate('0', true, { { left = 10, right = 10, cmd = '' } })\n\n  validate(',', false, { { left = 10, right = 9, cmd = '' } })\n  validate('1', false, { { left = 10, right = 1, cmd = '' } })\n  validate('0', true, { { left = 10, right = 10, cmd = '' } })\n\n  validate('c', true, { { left = 10, right = 10, cmd = 'change' } })\n  validate('b', false, { { left = 10, right = 10, cmd = 'cbuffer' } })\n\n  -- Should be called when deleting text\n  type_keys('<Home><Right><Right>')\n  validate('<BS>', false, { { left = 1, right = 10, cmd = 'cbuffer' } })\n\n  type_keys('<Esc>')\n\n  -- Should be called only for valid buffer lines range\n  type_keys(':')\n  validate('1', false, { { left = 1, right = 1, cmd = '' } })\n  validate('d', false, { { left = 1, right = 1, cmd = 'delete' } })\n  validate('x', false, { { left = 1, right = 1, cmd = '' } })\n  type_keys('<Esc>')\n\n  type_keys(':')\n  validate('%', false, { { left = 1, right = 101, cmd = '' } })\n  validate('b', false, {})\n  validate('w', false, {})\n  type_keys('<Esc>')\nend\n\nT['Autopeek']['fits into available height'] = function()\n  child.lua('MiniCmdline.config.autopeek.n_context = 2')\n\n  local validate = function(screen_lines, range)\n    child.set_size(screen_lines, 20)\n    type_keys(':')\n    expect_screenshot_after_keys(range)\n    type_keys('<Esc>')\n  end\n\n  validate(14, '3,10')\n\n  -- Should first hide outer context equally from top and bottom\n  validate(13, '3,10')\n  validate(12, '3,10')\n  validate(11, '3,10')\n  validate(10, '3,10')\n\n  -- Should then hide excsess under the fold\n  validate(9, '3,10')\n  validate(8, '3,10')\n  validate(7, '3,10')\n  validate(6, '3,10')\n\n  -- Should work with extreme available height\n  validate(5, '3,10')\n  validate(4, '3,10')\n\n  -- Should work with different kinds of context overlap\n  -- - Touching\n  validate(13, '3,8')\n  validate(12, '3,8')\n  validate(11, '3,8')\n  validate(10, '3,8')\n  validate(9, '3,8')\n  validate(8, '3,8')\n  validate(7, '3,8')\n  validate(6, '3,8')\n  validate(5, '3,8')\n\n  -- - Inner intersecting\n  validate(11, '3,6')\n  validate(10, '3,6')\n  validate(9, '3,6')\n  validate(8, '3,6')\n  validate(7, '3,6')\n  validate(6, '3,6')\n  validate(5, '3,6')\n\n  -- - Outer intersecting\n  validate(9, '3,4')\n  validate(8, '3,4')\n  validate(7, '3,4')\n  validate(6, '3,4')\n  validate(5, '3,4')\n\n  -- Inverted range (only selective basic sanity checks)\n  validate(12, '10,3')\n  validate(9, '10,3')\n  validate(12, '8,3')\n  validate(8, '8,3')\n  validate(8, '4,3')\n  validate(5, '4,3')\nend\n\nT['Autopeek']['updates when navigating through history'] = function()\n  type_keys(':', '2,5sort', '<CR>')\n  type_keys(':', 'echo', '<CR>')\n\n  type_keys(':')\n  expect_screenshot_after_keys('10')\n  expect_screenshot_after_keys('<C-u><Up>')\n  expect_screenshot_after_keys('<C-u><Up>')\n  expect_screenshot_after_keys('<C-u><Down>')\nend\n\nT['Autopeek']['works with command window'] = function()\n  -- Command window seems to block child process, so use a workaround to test\n  -- if autopeek was shown\n  child.lua([[\n    _G.statuscolumn_was_used = false\n    MiniCmdline.config.autopeek.window.statuscolumn = function(...)\n      _G.statuscolumn_was_used = true\n      return MiniCmdline.default_autopeek_statuscolumn(...)\n    end\n  ]])\n\n  -- Should not be shown if command is typed inside command window\n  -- NOTE: It would be good to also show it, but it would require much more\n  -- explicit work (`CmdlineChanged` is not triggered in cmdwin)\n  type_keys('q:', '2', ',5', '<CR>')\n  eq(child.lua_get('_G.statuscolumn_was_used'), false)\n\n  -- NOTE: Neovim<0.10 can not detect if buffer belongs to command window\n  if child.fn.has('nvim-0.10') == 0 then\n    MiniTest.skip('Neovim<0.10 does not have enough capabilities to work with command window')\n  end\n\n  -- Should not be shown for command window buffer.\n  type_keys('q:')\n  type_keys(':', '1', '<CR>')\n  type_keys('<CR>')\n  eq(child.lua_get('_G.statuscolumn_was_used'), false)\n\n  -- Should hide already visible peek when entering command window\n  type_keys(':', '2')\n  validate_peek()\n  child.lua('_G.statuscolumn_was_used = false')\n  type_keys('<C-f>')\n  type_keys(',5', '<CR>')\n  eq(child.lua_get('_G.statuscolumn_was_used'), false)\nend\n\nT['Autopeek']['works when using command-line expression register'] = function()\n  type_keys(':', '2,', '<C-r>=', '10+10')\n  -- Should not react to \"range like\" content when entering register\n  eq(get_peek_winheight(), 3)\n\n  type_keys('<CR>')\n  child.expect_screenshot()\n\n  -- Should keep working as if the number was typed manually\n  type_keys('+')\n  child.expect_screenshot()\n  type_keys('<Esc>')\n  validate_no_peek()\nend\n\nT['Autopeek']['respects `vim.{g,b}.minicmdline_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicmdline_disable = true\n    type_keys(':', '2')\n    validate_no_peek()\n    type_keys('<Esc>')\n\n    child[var_type].minicmdline_disable = false\n    type_keys(':', '2')\n    validate_peek()\n  end,\n})\n\nT['Arrow mappings'] = new_set()\n\nT['Arrow mappings']['work horizontally'] = function()\n  load_module({ autocomplete = { enable = false } })\n\n  -- Left/Right - always move cursor regardless of pum\n  type_keys(':', 'so', '<Tab>')\n  eq(has_pum(), true)\n  type_keys('<Left>')\n  validate_cmdline('sort', 4)\n  eq(has_pum(), false)\n\n  type_keys('<Tab>')\n  eq(has_pum(), true)\n  type_keys('<Right>')\n  validate_cmdline('sortt', 6)\n  eq(has_pum(), false)\nend\n\nT['Arrow mappings']['work vertically'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Works only on Neovim>=0.10') end\n\n  load_module({ autocomplete = { enable = false } })\n\n  -- Disable fuzzy matching for easier testing\n  child.o.wildoptions = 'pum'\n\n  -- Up/Down - navigate history regardless of pum\n  type_keys(':', 'setglobal expandtab', '<CR>')\n  type_keys(':', 'setglobal ignorecase', '<CR>')\n\n  type_keys(':', 'set', '<Tab>')\n  eq(has_pum(), true)\n\n  type_keys('<Up>')\n  validate_cmdline('setglobal ignorecase')\n  eq(has_pum(), false)\n  type_keys('<Up>')\n  validate_cmdline('setglobal expandtab')\n  eq(has_pum(), false)\n\n  type_keys('<C-u>set', '<Tab>')\n  eq(has_pum(), true)\n\n  type_keys('<Down>')\n  validate_cmdline('setglobal ignorecase')\n  eq(has_pum(), false)\n  type_keys('<Down>')\n  validate_cmdline('set')\n  eq(has_pum(), false)\nend\n\nT['Arrow mappings']['respect `config.autocomplete.map_arrows`'] = function()\n  load_module({ autocomplete = { map_arrows = false } })\n  local validate = function(key) expect.match(child.cmd_capture('cnoremap ' .. key), 'No mapping found') end\n  validate('<Left>')\n  validate('<Right>')\n  validate('<Up>')\n  validate('<Down>')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_colors.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq, eq_approx = helpers.expect, helpers.expect.equality, helpers.expect.equality_approx\nlocal new_set = MiniTest.new_set\n\nlocal dir_path = vim.fn.fnamemodify('tests/dir-colors/', ':p')\nlocal colors_path = dir_path .. '/colors/'\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('colors', config) end\nlocal unload_module = function(config) child.mini_unload('colors', config) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Mock test color scheme\nlocal mock_cs = function() child.cmd('set rtp+=' .. dir_path .. 'mock_cs/') end\n\n-- Time constants\nlocal default_transition_duration, default_show_duration = 1000, 1000\nlocal default_transition_steps = 25\nlocal small_transition_time = 0.5 * (default_transition_duration / default_transition_steps)\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniColors)'), 'table')\n\n  -- `Colorscheme` command\n  eq(child.fn.exists(':Colorscheme'), 2)\nend\n\nT['setup()']['creates `config` field'] = function() eq(child.lua_get('type(_G.MiniColors.config)'), 'table') end\n\nT['as_colorscheme()'] = new_set()\n\nT['as_colorscheme()']['works'] = function()\n  child.lua([[_G.cs_data = {\n    name = 'my_test_cs',\n    groups = { Normal = { fg = '#ffffff', bg = '#000000' } },\n    terminal = { [0] = '#111111' }\n  }]])\n  child.lua('_G.cs = MiniColors.as_colorscheme(_G.cs_data)')\n\n  -- Fields\n  local validate_field = function(field, value) eq(child.lua_get('_G.cs.' .. field), value) end\n\n  validate_field('name', 'my_test_cs')\n\n  validate_field('groups.Normal', { fg = '#ffffff', bg = '#000000' })\n\n  validate_field('terminal[0]', '#111111')\n\n  -- Methods\n  local validate_method = function(method)\n    local lua_cmd = string.format('type(_G.cs.%s)', method)\n    eq(child.lua_get(lua_cmd), 'function')\n  end\n\n  validate_method('apply')\n  validate_method('add_cterm_attributes')\n  validate_method('add_terminal_colors')\n  validate_method('add_transparency')\n  validate_method('chan_add')\n  validate_method('chan_invert')\n  validate_method('chan_modify')\n  validate_method('chan_multiply')\n  validate_method('chan_repel')\n  validate_method('chan_set')\n  validate_method('color_modify')\n  validate_method('compress')\n  validate_method('get_palette')\n  validate_method('resolve_links')\n  validate_method('simulate_cvd')\n  validate_method('write')\n\n  -- Should not modify input table\n  eq(child.lua_get('type(_G.cs_data.apply)'), 'nil')\n\n  -- Should not require any input data\n  expect.no_error(function() child.lua('MiniColors.as_colorscheme({})') end)\nend\n\nT['as_colorscheme()']['validates arguments'] = function()\n  expect.error(function() child.lua('MiniColors.as_colorscheme(1)') end, '%(mini%.colors%).*table')\n\n  expect.error(\n    function() child.lua('MiniColors.as_colorscheme({groups = 1})') end,\n    '%(mini%.colors%).*groups.*table or nil'\n  )\n  expect.error(\n    function() child.lua('MiniColors.as_colorscheme({groups = { 1 }})') end,\n    '%(mini%.colors%).*All elements.*groups.*tables'\n  )\n\n  expect.error(\n    function() child.lua('MiniColors.as_colorscheme({terminal = 1})') end,\n    '%(mini%.colors%).*terminal.*table or nil'\n  )\n  expect.error(\n    function() child.lua('MiniColors.as_colorscheme({terminal = { 1 }})') end,\n    '%(mini%.colors%).*All elements.*terminal.*strings'\n  )\nend\n\nT['as_colorscheme()']['ensures independence of groups'] = function()\n  child.lua([[_G.hl_group = { fg = '#012345' }]])\n  child.lua([[_G.cs = MiniColors.as_colorscheme({ groups = { Normal = hl_group, NormalNC = hl_group }})]])\n\n  eq(child.lua_get('_G.cs.groups.Normal == _G.cs.groups.NormalNC'), false)\nend\n\nT['as_colorscheme() methods'] = new_set()\n\nT['as_colorscheme() methods']['add_cterm_attributes()'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal          = { fg = '#5f87af', bg = '#080808' },\n      TestForce       = { fg = '#5f87af', ctermfg = 0 },\n      TestApprox      = { fg = '#5f87aa' },\n      TestNormalCterm = { ctermfg = 67,   ctermbg = 232 },\n      TestSpecial     = { sp = '#00ff00', underline = true },\n    }\n  })]])\n\n  -- Default\n  eq(child.lua_get('_G.cs:add_cterm_attributes().groups'), {\n    -- Updates both `guifg` and `guibg`. Works with chromatics and grays.\n    Normal = { fg = '#5f87af', ctermfg = 67, bg = '#080808', ctermbg = 232 },\n    -- Updates already present `cterm` (`force = true` by default)\n    TestForce = { fg = '#5f87af', ctermfg = 67 },\n    -- Should be able to approximate\n    TestApprox = { fg = '#5f87aa', ctermfg = 67 },\n    -- Doesn't change `cterm` if no corresponding `gui`\n    TestNormalCterm = { ctermbg = 232, ctermfg = 67 },\n    -- Doesn't touch `sp`\n    TestSpecial = { sp = '#00ff00', underline = true },\n  })\n\n  -- - Should return copy without modifying original\n  eq(child.lua_get('_G.cs.groups.Normal.ctermfg'), vim.NIL)\n\n  -- With `force = false`\n  eq(child.lua_get('_G.cs:add_cterm_attributes({ force = false }).groups.TestForce'), { fg = '#5f87af', ctermfg = 0 })\nend\n\nT['as_colorscheme() methods']['add_terminal_colors()'] = new_set()\n\nT['as_colorscheme() methods']['add_terminal_colors()']['works'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      Test1  = { fg = '#ffaea0', bg = '#e0c479' },\n      Test2  = { fg = '#97d9a4', bg = '#70d9eb' },\n      Test3  = { fg = '#aec4ff', sp = '#ecafe6' },\n    }\n  })]])\n\n  eq(\n    child.lua_get([[vim.deep_equal(_G.cs:add_terminal_colors().terminal, {\n    [0] = '#2e2e2e', [8] = '#2e2e2e',\n    [1] = '#ffaea0', [9] = '#ffaea0',\n    [2] = '#97d9a4', [10] = '#97d9a4',\n    [3] = '#e0c479', [11] = '#e0c479',\n    [4] = '#aec4ff', [12] = '#aec4ff',\n    [5] = '#ecafe6', [13] = '#ecafe6',\n    [6] = '#70d9eb', [14] = '#70d9eb',\n    [7] = '#c7c7c7', [15] = '#c7c7c7',\n  })]]),\n    true\n  )\nend\n\nT['as_colorscheme() methods']['add_terminal_colors()']['uses present terminal colors'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n    },\n    terminal = {\n    [0] = '#ffaea0', [8] = '#97d9a4',\n    [1] = '#2e2e2e', [9] = '#e0c479',\n    [2] = '#e0c479', [10] = '#2e2e2e',\n    [3] = '#97d9a4', [11] = '#ffaea0',\n    [4] = '#ecafe6', [12] = '#70d9eb',\n    [5] = '#aec4ff', [13] = '#c7c7c7',\n    [6] = '#c7c7c7', [14] = '#aec4ff',\n    [7] = '#70d9eb', [15] = '#ecafe6',\n  }\n  })]])\n\n  eq(\n    child.lua_get([[vim.deep_equal(_G.cs:add_terminal_colors().terminal, {\n    [0] = '#2e2e2e', [8] = '#2e2e2e',\n    [1] = '#ffaea0', [9] = '#ffaea0',\n    [2] = '#97d9a4', [10] = '#97d9a4',\n    [3] = '#e0c479', [11] = '#e0c479',\n    [4] = '#aec4ff', [12] = '#aec4ff',\n    [5] = '#ecafe6', [13] = '#ecafe6',\n    [6] = '#70d9eb', [14] = '#70d9eb',\n    [7] = '#c7c7c7', [15] = '#c7c7c7',\n  })]]),\n    true\n  )\nend\n\nT['as_colorscheme() methods']['add_terminal_colors()']['properly approximates'] = function()\n  local validate_red = function(hex) eq(child.lua_get('_G.cs:add_terminal_colors().terminal[1]'), hex) end\n\n  -- Picks proper red if it exists in palette\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      -- Reference lightness should be taken from `Normal.fg` (80 in this case)\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      -- Proper red with `l = 80, h = 30`\n      Test   = { fg = '#ffaea0' },\n      -- Different lightness\n      TestDiffL = { fg = '#f2a193', bg = '#ffbfb2' },\n      -- Different hue\n      TestDiffH = { fg = '#ffada6', bg = '#ffaf9b' },\n    }\n  })]])\n  validate_red('#ffaea0')\n\n  -- Properly picks closest lightness in absence of perfect hue\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      -- All have hue 40, but lightness 70, 79, 90\n      TestDiffL = { fg = '#e2967b', bg = '#f1a388', sp = '#ffd7c6' },\n    }\n  })]])\n  validate_red('#f1a388')\n\n  -- Properly picks closest hue in absence of perfect lightness\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      -- All have lightness 80, but hue 20, 29, 40\n      TestDiffH = { fg = '#ffadac', bg = '#ffaea1', sp = '#ffb195' },\n    }\n  })]])\n  validate_red('#ffaea1')\n\n  -- Doesn't take chroma into account\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      -- The `fg` has correct lightness and hue but chroma is only 1\n      -- The `bg` has more vivid colors, but lightness is 74\n      -- So, `fg` should be picked as correct one\n      Test = { fg = '#cdc4c3', bg = '#fe9584' },\n    }\n  })]])\n  validate_red('#cdc4c3')\nend\n\nT['as_colorscheme() methods']['add_terminal_colors()']['respects `opts.force`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      Test   = { fg = '#ffaea0' },\n    },\n    terminal = { [1] = '#012345' }\n  })]])\n\n  eq(child.lua_get('_G.cs:add_terminal_colors({ force = false }).terminal[1]'), '#012345')\nend\n\nT['as_colorscheme() methods']['add_terminal_colors()']['respects `opts.palette_args`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      Test   = { fg = '#012345', bg = '#012345', sp = '#012345' },\n      -- Although this `fg` is a perfect match, it won't be used due to not\n      -- being frequent enough\n      Test2  = { fg = '#ffaea0', bg = '#012345' }\n    }\n  })]])\n\n  eq(child.lua_get('_G.cs:add_terminal_colors({ palette_args = { threshold = 0.5 } }).terminal[1]'), '#012345')\nend\n\nT['as_colorscheme() methods']['add_terminal_colors()']['handles not proper `Normal` highlight group'] = function()\n  -- Absent (should fall back on lightness depending on background)\n  child.cmd('hi clear Normal')\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      -- The `fg` has fallback lightness for light background, `bg` - for dark\n      Test   = { fg = '#470301', bg = '#ffbfb2' },\n    }\n  })]])\n\n  child.o.background = 'dark'\n  eq(child.lua_get('_G.cs:add_terminal_colors().terminal[1]'), '#ffbfb2')\n\n  child.o.background = 'light'\n  eq(child.lua_get('_G.cs:add_terminal_colors().terminal[1]'), '#470301')\n\n  -- Linked\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      NormalLink = { fg = '#c7c7c7', bg = '#2e2e2e' },\n      Normal = { link = 'NormalLink' },\n      -- The `fg` has perfect fit while `bg` uses fallback lightness\n      Test   = { fg = '#ffaea0', bg = '#ffbfb2' },\n    }\n  })]])\n  eq(child.lua_get('_G.cs:add_terminal_colors().terminal[1]'), '#ffaea0')\nend\n\nT['as_colorscheme() methods']['add_transparency()'] = new_set()\n\nT['as_colorscheme() methods']['add_transparency()']['works'] = function()\n  child.lua([[_G.hl_group = { fg = '#aaaaaa', ctermfg = 255, bg = '#111111', ctermbg = 232, }]])\n  local hl_group = child.lua_get('_G.hl_group')\n  local hl_transparent = { fg = '#aaaaaa', ctermfg = 255, blend = 0 }\n\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      -- General (should be made transparent)\n      Normal = hl_group,\n      NormalNC = { bg = '#111111' },\n      EndOfBuffer = { ctermbg = 232 },\n      MsgArea = { blend = 50 },\n      ErrorMsg = { bg = '#000000' },\n      MsgSeparator = hl_group,\n      VertSplit = hl_group,\n      WinSeparator = hl_group,\n\n      -- Other (should be left as is)\n      NormalFloat = hl_group,\n      SignColumn = hl_group,\n      StatusLine = hl_group,\n      TabLine = hl_group,\n      WinBar = hl_group,\n    }\n  })]])\n\n  child.lua('_G.cs_trans = _G.cs:add_transparency()')\n\n  eq(child.lua_get('_G.cs_trans.groups'), {\n    Normal = hl_transparent,\n    NormalNC = { blend = 0 },\n    EndOfBuffer = { blend = 0 },\n    MsgArea = { blend = 0 },\n    ErrorMsg = { blend = 0 },\n    MsgSeparator = hl_transparent,\n    VertSplit = hl_transparent,\n    WinSeparator = hl_transparent,\n\n    NormalFloat = hl_group,\n    SignColumn = hl_group,\n    StatusLine = hl_group,\n    TabLine = hl_group,\n    WinBar = hl_group,\n  })\n\n  -- Should return copy without modifying original\n  eq(child.lua_get('_G.cs.groups.Normal.bg'), '#111111')\nend\n\nT['as_colorscheme() methods']['add_transparency()']['works with not all groups present'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({ groups = { Normal = { bg = '#012345' } } })]])\n  eq(child.lua_get('_G.cs:add_transparency().groups'), { Normal = { blend = 0 } })\nend\n\nT['as_colorscheme() methods']['add_transparency()']['respects `opts`'] = function()\n  child.lua([[_G.hl_group = { fg = '#aaaaaa', ctermfg = 255, bg = '#111111', ctermbg = 232, }]])\n  local hl_group = child.lua_get('_G.hl_group')\n  local hl_transparent = { fg = '#aaaaaa', ctermfg = 255, blend = 0 }\n\n  local validate_groups_become_transparent = function(opts, groups)\n    -- Create colorscheme object\n    local group_fields = vim.tbl_map(function(x) return x .. ' = hl_group' end, groups)\n    local lua_cmd =\n      string.format('_G.cs = MiniColors.as_colorscheme({ groups = { %s } })', table.concat(group_fields, ', '))\n    child.lua(lua_cmd)\n\n    -- Validate\n    local ref_groups = {}\n    for _, gr in ipairs(groups) do\n      ref_groups[gr] = hl_transparent\n    end\n\n    local lua_get_cmd = string.format('_G.cs:add_transparency(%s).groups', vim.inspect(opts))\n    eq(child.lua_get(lua_get_cmd), ref_groups)\n  end\n\n  -- opts.general\n  child.lua([[_G.cs = MiniColors.as_colorscheme({ groups = { Normal = hl_group } })]])\n  eq(child.lua_get('_G.cs:add_transparency({ general = false }).groups.Normal'), hl_group)\n\n  -- Other\n  validate_groups_become_transparent({ float = true }, { 'FloatBorder', 'FloatTitle', 'NormalFloat' })\n  --stylua: ignore\n  validate_groups_become_transparent(\n    { statuscolumn = true },\n    {\n      'FoldColumn', 'LineNr', 'LineNrAbove', 'LineNrBelow', 'SignColumn',\n      'DiagnosticSignError', 'DiagnosticSignWarn', 'DiagnosticSignInfo', 'DiagnosticSignHint', 'DiagnosticSignOk',\n    }\n  )\n  validate_groups_become_transparent(\n    { statusline = true },\n    { 'StatusLine', 'StatusLineNC', 'StatusLineTerm', 'StatusLineTermNC' }\n  )\n  validate_groups_become_transparent({ tabline = true }, { 'TabLine', 'TabLineFill', 'TabLineSel' })\n  validate_groups_become_transparent({ winbar = true }, { 'WinBar', 'WinBarNC' })\nend\n\nT['as_colorscheme() methods']['add_transparency()']['respects sign highlight groups'] = function()\n  child.fn.sign_define('Sign1', { texthl = 'Texthl', numhl = 'Numhl' })\n\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Texthl = { bg = '#111111' },\n      Numhl = { bg = '#111111' },\n    }\n  })]])\n\n  eq(child.lua_get('_G.cs:add_transparency({ statuscolumn = true }).groups'), {\n    Texthl = { blend = 0 },\n    Numhl = { blend = 0 },\n  })\n\n  eq(child.lua_get('_G.cs:add_transparency().groups'), {\n    Texthl = { bg = '#111111' },\n    Numhl = { bg = '#111111' },\n  })\nend\n\nT['as_colorscheme() methods']['apply()'] = new_set()\n\nT['as_colorscheme() methods']['apply()']['works'] = function()\n  -- Define current color scheme data\n  child.g.colors_name = 'prior_cs'\n  child.api.nvim_set_hl(0, 'Normal', { fg = '#aaaaaa', bg = '#111111' })\n  child.api.nvim_set_hl(0, 'TestPartial', { fg = '#aaaaaa', bg = '#111111' })\n  child.api.nvim_set_hl(0, 'TestSingle', { fg = '#aaaaaa' })\n  child.g.terminal_color_1 = '#aa0000'\n\n  -- Create and apply some color scheme\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'new_cs',\n    groups = {\n      Normal = { fg = '#ffffff', bg = '#000000' },\n      TestPartial = { fg = '#ffffff' },\n      TestNew = { bg = '#000000' }\n    },\n    terminal = { [0] = '#000000' }\n  })]])\n  child.lua('_G.cs:apply()')\n\n  -- Validate\n  eq(child.g.colors_name, 'new_cs')\n\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#ffffff%s+guibg=#000000')\n  -- - Should override completely without inheriting `bg`\n  expect.match(child.cmd_capture('hi TestPartial'), 'guifg=#ffffff$')\n  -- - Should clear all highlight groups by default\n  expect.match(child.cmd_capture('hi TestSingle'), 'cleared')\n  -- - Should be able to create new highlight groups\n  expect.match(child.cmd_capture('hi TestNew'), 'guibg=#000000$')\n\n  -- - Should remove all previous terminal colors\n  eq(child.g.terminal_color_0, '#000000')\n  eq(child.g.terminal_color_1, vim.NIL)\nend\n\nT['as_colorscheme() methods']['apply()']['respects `opts.clear`'] = function()\n  child.api.nvim_set_hl(0, 'TestSingle', { fg = '#aaaaaa' })\n\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = { Normal = { fg = '#ffffff' } }\n  })]])\n  child.lua('_G.cs:apply({ clear = false })')\n  expect.match(child.cmd_capture('hi TestSingle'), 'guifg=#aaaaaa$')\nend\n\nlocal create_basic_cs = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    -- Oklch ~ { l = 50, c = 15, h = 0 }\n    -- Oklab ~ { l = 50, a = 14.96, b = 0.056 }\n    -- Saturation ~ 65\n    -- Temperature = 90\n    -- Pressure = 180\n    -- RGB = { r = 186, g = 74, b = 115 }\n    groups = { Normal = { fg = '#ba4a73' } }\n  })]])\nend\n\nlocal validate_chan_method = function(method, channel, args, ref_normal_fg)\n  local lua_cmd = string.format([[_G.cs_modified = _G.cs:%s('%s', %s)]], method, channel, args)\n  child.lua(lua_cmd)\n\n  eq(child.lua_get('_G.cs_modified.groups.Normal.fg'), ref_normal_fg)\nend\n\nlocal validate_self_copy = function(method, value_string)\n  local lua_cmd = string.format([[_G.cs_modified = _G.cs:%s('hue', %s)]], method, value_string)\n  child.lua(lua_cmd)\n\n  eq(child.lua_get('vim.deep_equal(_G.cs, _G.cs_modified)'), true)\n  eq(child.lua_get('_G.cs ~= _G.cs_modified'), true)\nend\n\n-- Only basic testing here. More thorough tests are in `chan_modify()`.\nT['as_colorscheme() methods']['chan_add()'] = new_set({ hooks = { pre_case = create_basic_cs } })\n\nT['as_colorscheme() methods']['chan_add()']['works'] = function()\n  local validate = function(channel, value, ref_normal_fg, opts_string)\n    local args = string.format('%s, %s', value, opts_string or '{}')\n    validate_chan_method('chan_add', channel, args, ref_normal_fg)\n  end\n\n  --stylua: ignore start\n  validate('lightness',   10,  '#d8658d')\n  validate('chroma',      -10, '#906b76')\n  validate('saturation',  10,  '#c33f72')\n  validate('hue',         10,  '#bd4a62')\n  validate('temperature', 10,  '#bd4a62')\n  validate('pressure',    -10, '#bd4a62')\n  validate('a',           -10, '#906b75')\n  validate('b',           10,  '#cb4021')\n  validate('red',         16,  '#ca4a73')\n  validate('green',       16,  '#ba5a73')\n  validate('blue',        16,  '#ba4a83')\n  --stylua: ignore end\n\n  -- Should respect `opts`\n  validate('chroma', 20, '#e30078', [[{ gamut_clip = 'cusp' }]])\n\n  -- With value 0 should return copy of input\n  validate_self_copy('chan_add', '0')\nend\n\nT['as_colorscheme() methods']['chan_add()']['validates arguments'] = function()\n  expect.error(function() child.lua('_G.cs:chan_add(1, 10)') end, 'Channel.*one of')\n  expect.error(function() child.lua([[_G.cs:chan_add('aaa', 10)]]) end, 'Channel.*one of')\n\n  expect.error(function() child.lua([[_G.cs:chan_add('hue', 'a')]]) end, '`value`.*number')\nend\n\n-- Only basic testing here. More thorough tests are in `chan_modify()`.\nT['as_colorscheme() methods']['chan_invert()'] = new_set({ hooks = { pre_case = create_basic_cs } })\n\nT['as_colorscheme() methods']['chan_invert()']['works'] = function()\n  -- Use different color with off-center channel values\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = { Normal = { fg = '#432618' } }\n  })]])\n\n  local validate = function(channel, ref_normal_fg, opts_string)\n    validate_chan_method('chan_invert', channel, opts_string or '{}', ref_normal_fg)\n  end\n\n  --stylua: ignore start\n  validate('lightness',   '#e3bdac')\n  -- - Chroma is same as saturation due to lack of good reference point\n  validate('chroma',      '#3d291f')\n  validate('saturation',  '#3d291f')\n  validate('hue',         '#382740')\n  validate('temperature', '#382740')\n  validate('pressure',    '#243419')\n  validate('a',           '#243419')\n  validate('b',           '#382740')\n  validate('red',         '#bc2618')\n  validate('green',       '#43d918')\n  validate('blue',        '#4326e7')\n  --stylua: ignore end\n\n  -- Should respect `opts`\n  child.lua([[_G.cs.groups.Normal.fg = '#fef0cb']])\n  validate('lightness', '#221900', [[{ gamut_clip = 'cusp' }]])\nend\n\nT['as_colorscheme() methods']['chan_invert()']['validates arguments'] = function()\n  expect.error(function() child.lua('_G.cs:chan_invert(1)') end, 'Channel.*one of')\n  expect.error(function() child.lua([[_G.cs:chan_invert('aaa')]]) end, 'Channel.*one of')\nend\n\nT['as_colorscheme() methods']['chan_modify()'] = new_set({ hooks = { pre_case = create_basic_cs } })\n\nlocal validate_chan_modify = function(channel, function_body, ref_normal_fg, opts_string)\n  opts_string = opts_string or '{}'\n  local lua_cmd = string.format('_G.f = function(x) %s end', function_body)\n  child.lua(lua_cmd)\n\n  local lua_get_cmd = string.format([[_G.cs:chan_modify('%s', _G.f, %s).groups.Normal.fg]], channel, opts_string)\n  eq(child.lua_get(lua_get_cmd), ref_normal_fg)\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"lightness\"'] = function()\n  local validate = function(...) validate_chan_modify('lightness', ...) end\n\n  validate('return x - 10', '#9c2e5a')\n\n  -- Should normalize to [0; 100]\n  validate('return 110', '#ffffff')\n  validate('return -10', '#000000')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return 80', '#ff9bbe', [[{ gamut_clip = 'cusp' }]])\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"chroma\"'] = function()\n  local validate = function(...) validate_chan_modify('chroma', ...) end\n\n  validate('return x - 10', '#906b76')\n\n  -- Should normalize to positive number\n  validate('return -10', '#777777')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return 25', '#da0072', [[{ gamut_clip = 'cusp' }]])\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"saturation\"'] = function()\n  local validate = function(...) validate_chan_modify('saturation', ...) end\n\n  validate('return x - 10', '#b15374')\n\n  -- Should normalize to [0; 100]\n  validate('return 110', '#d70071')\n  validate('return -10', '#777777')\n\n  -- In theory, 'gamut_clip' is unnecessary as it always stays inside gamut\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"hue\"'] = function()\n  local validate = function(...) validate_chan_modify('hue', ...) end\n\n  validate('return x + 10', '#bd4a62')\n\n  -- Should periodically normalize to be inside [0; 360)\n  validate('return x + 370', '#bd4a62')\n  validate('return x - 350', '#bd4a62')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return 90', '#a28000', [[{ gamut_clip = 'cusp' }]])\n\n  -- Doesn't have effect on grays (as they have no defined hue)\n  child.lua([[_G.cs.groups.Normal.fg = '#aaaaaa']])\n  validate('return 90', '#aaaaaa')\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"temperature\"'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    -- Test on both hue half-planes ([-90; 90] and [90; 270])\n    -- Both colors have temperature 90\n    groups = { Normal = { fg = '#ba4a73', bg = '#68cebb' } }\n  })]])\n\n  local validate = function(function_body, ref_fg_hex, ref_bg_hex, opts_string)\n    opts_string = opts_string or '{}'\n\n    local lua_cmd = string.format('_G.f = function(x) %s end', function_body)\n    child.lua(lua_cmd)\n\n    local lua_get_cmd = string.format([[_G.cs:chan_modify('temperature', _G.f, %s).groups.Normal]], opts_string)\n    eq(child.lua_get(lua_get_cmd), { fg = ref_fg_hex, bg = ref_bg_hex })\n  end\n\n  -- \"Temperature\" is a circular distance to hue 270\n  validate('return x + 10', '#bd4a62', '#71ceaf')\n\n  -- Should normalize to [0; 180]\n  validate('return 270', '#927300', '#d2b66b')\n  validate('return -90', '#556fce', '#a0b6fa')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return 180', '#a28000', '#d2b66b', [[{ gamut_clip = 'cusp' }]])\n\n  -- Doesn't have effect on grays (as they have no defined hue)\n  child.lua([[_G.cs.groups.Normal.fg = '#aaaaaa']])\n  child.lua([[_G.cs.groups.Normal.bg = '#777777']])\n  validate('return 180', '#aaaaaa', '#777777')\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"pressure\"'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    -- Test on both hue half-planes ([0; 180] and [180, 360))\n    -- Both colors have pressure 90\n    groups = { Normal = { fg = '#556fce', bg = '#d2b66b' } }\n  })]])\n\n  local validate = function(function_body, ref_fg_hex, ref_bg_hex, opts_string)\n    opts_string = opts_string or '{}'\n\n    local lua_cmd = string.format('_G.f = function(x) %s end', function_body)\n    child.lua(lua_cmd)\n\n    local lua_get_cmd = string.format([[_G.cs:chan_modify('pressure', _G.f, %s).groups.Normal]], opts_string)\n    eq(child.lua_get(lua_get_cmd), { fg = ref_fg_hex, bg = ref_bg_hex })\n  end\n\n  -- \"Pressure\" is a circular distance to hue 180\n  validate('return x + 10', '#6769cc', '#dbb26c')\n\n  -- Should normalize to [0; 180]\n  validate('return 270', '#ba4a73', '#ee9eb6')\n  validate('return -90', '#018a79', '#68cebb')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return 0', '#01a38f', '#68cebb', [[{ gamut_clip = 'cusp' }]])\n\n  -- Doesn't have effect on grays (as they have no defined hue)\n  child.lua([[_G.cs.groups.Normal.fg = '#aaaaaa']])\n  child.lua([[_G.cs.groups.Normal.bg = '#777777']])\n  validate('return 180', '#aaaaaa', '#777777')\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"a\"'] = function()\n  local validate = function(...) validate_chan_modify('a', ...) end\n\n  validate('return x - 20', '#568178')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return -20', '#00b49e', [[{ gamut_clip = 'cusp' }]])\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"b\"'] = function()\n  local validate = function(...) validate_chan_modify('b', ...) end\n\n  validate('return x - 10', '#ab48ae')\n\n  -- Should respect `opts.gamut_clip`\n  validate('return 40', '#dd8c00', [[{ gamut_clip = 'cusp' }]])\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"red\"'] = function()\n  local validate = function(...) validate_chan_modify('red', ...) end\n\n  validate('return x - 16', '#aa4a73')\n\n  -- Should normalize to [0; 255]\n  validate('return 300', '#ff4a73')\n  validate('return -50', '#004a73')\n\n  -- In theory, 'gamut_clip' is unnecessary as it always stays inside gamut\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"green\"'] = function()\n  local validate = function(...) validate_chan_modify('green', ...) end\n\n  validate('return x - 16', '#ba3a73')\n\n  -- Should normalize to [0; 255]\n  validate('return 300', '#baff73')\n  validate('return -50', '#ba0073')\n\n  -- In theory, 'gamut_clip' is unnecessary as it always stays inside gamut\nend\n\nT['as_colorscheme() methods']['chan_modify()']['works with \"blue\"'] = function()\n  local validate = function(...) validate_chan_modify('blue', ...) end\n\n  validate('return x - 16', '#ba4a63')\n\n  -- Should normalize to [0; 255]\n  validate('return 300', '#ba4aff')\n  validate('return -50', '#ba4a00')\n\n  -- In theory, 'gamut_clip' is unnecessary as it always stays inside gamut\nend\n\nT['as_colorscheme() methods']['chan_modify()']['validates arguments'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({ groups = { Normal = { fg = '#ffffff' } } })]])\n  child.lua('_G.f = function(x) return x + 1 end')\n\n  expect.error(function() child.lua('_G.cs:chan_modify(1, _G.f)') end, 'Channel.*one of')\n  expect.error(function() child.lua([[_G.cs:chan_modify('aaa', _G.f)]]) end, 'Channel.*one of')\n\n  expect.error(function() child.lua([[_G.cs:chan_modify('hue', 1)]]) end, '`f`.*callable')\n\n  expect.error(function() child.lua([[_G.cs:chan_modify('hue', _G.f, { filter = 1 })]]) end, '`opts%.filter`.*callable')\n  expect.error(\n    function() child.lua([[_G.cs:chan_modify('hue', _G.f, { filter = 'a' })]]) end,\n    '`opts%.filter`.*proper attribute'\n  )\n\n  expect.error(\n    function() child.lua([[_G.cs:chan_modify('hue', _G.f, { gamut_clip = 'a' })]]) end,\n    '`opts%.gamut_clip`.*one of'\n  )\nend\n\nT['as_colorscheme() methods']['chan_modify()']['respects `opts.filter`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = { Normal = { fg = '#000000', bg = '#000000', sp = '#000000' } },\n    terminal = { [0] = '#000000' },\n  })]])\n  child.lua([[_G.f = function(x) return x + 2 end]])\n\n  -- Allowed attribute strings\n  local validate_attr = function(attr)\n    local lua_cmd = string.format([[_G.cs_modified = _G.cs:chan_modify('lightness', _G.f, { filter = '%s' })]], attr)\n    child.lua(lua_cmd)\n\n    local ref_normal = { fg = '#000000', bg = '#000000', sp = '#000000' }\n    if attr ~= 'term' then ref_normal[attr] = '#020202' end\n    eq(child.lua_get('_G.cs_modified.groups.Normal'), ref_normal)\n\n    local ref_terminal = attr == 'term' and '#020202' or '#000000'\n    eq(child.lua_get('_G.cs_modified.terminal[0]'), ref_terminal)\n  end\n\n  validate_attr('fg')\n  validate_attr('bg')\n  validate_attr('sp')\n  validate_attr('term')\n\n  -- Callable filter\n  child.lua('_G.args_history = {}')\n  child.lua([[_G.filter = function(...)\n    table.insert(_G.args_history, { ... })\n    return false\n  end]])\n\n  eq(child.lua_get([[vim.deep_equal(_G.cs, _G.cs:chan_modify('lightness', _G.f, { filter = _G.filter }))]]), true)\n  -- Ensure consistent order in history as there is no order guarantee in how\n  -- filter is applied\n  child.lua('table.sort(_G.args_history, function(a, b) return a[2].attr < b[2].attr end)')\n  eq(child.lua_get('_G.args_history'), {\n    { '#000000', { attr = 'bg', name = 'Normal' } },\n    { '#000000', { attr = 'fg', name = 'Normal' } },\n    { '#000000', { attr = 'sp', name = 'Normal' } },\n    { '#000000', { attr = 'term', name = 'terminal_color_0' } },\n  })\nend\n\nT['as_colorscheme() methods']['chan_modify()']['respects `opts.gamut_clip`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    -- This is approximately { l = 75, c = 5, h = 0 } in Oklch\n    groups = { Normal = { fg = '#d5acb8' } }\n  })]])\n  child.lua([[_G.f = function(_) return 20 end]])\n\n  eq(child.lua_get([[_G.cs:chan_modify('chroma', _G.f).groups.Normal.fg]]), '#ff88b7')\n  eq(child.lua_get([[_G.cs:chan_modify('chroma', _G.f, { gamut_clip = 'chroma' }).groups.Normal.fg]]), '#ff88b7')\n  eq(child.lua_get([[_G.cs:chan_modify('chroma', _G.f, { gamut_clip = 'cusp' }).groups.Normal.fg]]), '#ff7eb1')\n  eq(child.lua_get([[_G.cs:chan_modify('chroma', _G.f, { gamut_clip = 'lightness' }).groups.Normal.fg]]), '#ff68a7')\nend\n\n-- Only basic testing here. More thorough tests are in `chan_modify()`.\nT['as_colorscheme() methods']['chan_multiply()'] = new_set({ hooks = { pre_case = create_basic_cs } })\n\nT['as_colorscheme() methods']['chan_multiply()']['works'] = function()\n  local validate = function(channel, coef, ref_normal_fg, opts_string)\n    local args = string.format('%s, %s', coef, opts_string or '{}')\n    validate_chan_method('chan_multiply', channel, args, ref_normal_fg)\n  end\n\n  --stylua: ignore start\n  validate('lightness',   0.5, '#6e0037')\n  validate('chroma',      0.5, '#9c6475')\n  validate('saturation',  1.5, '#d51071')\n  validate('hue',         100, '#bf4b4e')\n  validate('temperature', 2,   '#927300')\n  validate('pressure',    0.5, '#927300')\n  validate('a',           -1,  '#008b79')\n  validate('b',           -1,  '#ba4a74')\n  validate('red',         0.5, '#5d4a73')\n  validate('green',       0.5, '#ba2573')\n  validate('blue',        0.5, '#ba4a3a')\n  --stylua: ignore end\n\n  -- Should respect `opts`\n  validate('chroma', 20, '#f50081', [[{ gamut_clip = 'cusp' }]])\n\n  -- With coefficient 1 should return copy of input\n  validate_self_copy('chan_multiply', '1')\nend\n\nT['as_colorscheme() methods']['chan_multiply()']['validates arguments'] = function()\n  expect.error(function() child.lua('_G.cs:chan_multiply(1, 10)') end, 'Channel.*one of')\n  expect.error(function() child.lua([[_G.cs:chan_multiply('aaa', 10)]]) end, 'Channel.*one of')\n\n  expect.error(function() child.lua([[_G.cs:chan_multiply('hue', 'a')]]) end, '`coef`.*number')\nend\n\n-- Only basic testing here. More thorough tests are in `chan_modify()`.\nT['as_colorscheme() methods']['chan_repel()'] = new_set({ hooks = { pre_case = create_basic_cs } })\n\nT['as_colorscheme() methods']['chan_repel()']['works with linear channels'] = function()\n  -- Tested only with `lightness` as linear scale in hope that all others\n  -- (except hue) are implemented the same\n  local ref_lch = child.lua_get([[MiniColors.convert(_G.cs.groups.Normal.fg, 'oklch')]])\n  local ref_l = ref_lch.l\n\n  local validate = function(sources, coef, ref_normal_fg, opts_string)\n    local args = string.format('%s, %s, %s', vim.inspect(sources), coef, opts_string or '{}')\n    validate_chan_method('chan_repel', 'lightness', args, ref_normal_fg)\n  end\n\n  local ref_color = function(nudge, opts_string)\n    --stylua: ignore\n    local lua_get_cmd = string.format(\n      [[MiniColors.convert({ l = %s, c = %s, h = %s }, 'hex', %s)]],\n      ref_lch.l + nudge, ref_lch.c, ref_lch.h, opts_string or '{}'\n    )\n    return child.lua_get(lua_get_cmd)\n  end\n\n  -- Should be repelled away from source\n  validate({ ref_l + 15 }, 10, ref_color(-2.23))\n  validate({ ref_l - 15 }, 10, ref_color(2.23))\n\n  -- If repelled number is inside [src - coef; src + coef], it should be\n  -- repelled outside of it but close to nearest edge\n  validate({ ref_l + 1 }, 10, ref_color(-9.05))\n  validate({ ref_l - 1 }, 10, ref_color(9.05))\n\n  -- If repelled from distant source, effect should be very small\n  validate({ ref_l + 40 }, 10, ref_color(-0.183))\n  validate({ ref_l - 40 }, 10, ref_color(0.183))\n\n  -- Should attract with negative coefficient\n  validate({ ref_l + 15 }, -10, ref_color(6.0653))\n  validate({ ref_l - 15 }, -10, ref_color(-6.0653))\n\n  -- If attracted number is inside [src - coef; src + coef], it should be\n  -- attracted directly towards source\n  validate({ ref_l - 9 }, -10, ref_color(-9))\n  validate({ ref_l - 1 }, -10, ref_color(-1))\n  validate({ ref_l + 1 }, -10, ref_color(1))\n  validate({ ref_l + 9 }, -10, ref_color(9))\n\n  -- Should allow multiple sources with additive nudges\n  validate({ ref_l - 1, ref_l + 1 }, 10, ref_color(0))\n  validate({ ref_l - 1, ref_l + 2 }, 10, ref_color(0.861))\n  validate({ ref_l - 2, ref_l + 1 }, 10, ref_color(-0.861))\n\n  validate({ ref_l - 1, ref_l + 1 }, -10, ref_color(0))\n  validate({ ref_l - 1, ref_l + 2 }, -10, ref_color(1))\n  validate({ ref_l - 2, ref_l + 1 }, -10, ref_color(-1))\n\n  -- Should allow single number source\n  validate(ref_l + 15, 10, ref_color(-2.23))\n\n  -- Should respect `opts`\n  local ref_cusp = ref_color(-39.0123, [[{ gamut_clip = 'cusp' }]])\n  validate({ ref_l + 1 }, 40, ref_cusp, [[{ gamut_clip = 'cusp' }]])\n\n  -- With no sources or coefficient 0 should return copy of input\n  validate_self_copy('chan_repel', '{}, 1')\n  validate_self_copy('chan_repel', '{ 0 }, 0')\nend\n\nT['as_colorscheme() methods']['chan_repel()']['works with \"hue\"'] = function()\n  -- Use color more appropriate for this test\n  local ref_hex = '#a95d69'\n  child.lua('_G.cs.groups.Normal.fg = ' .. vim.inspect(ref_hex))\n  local ref_lch = child.lua_get([[MiniColors.convert(_G.cs.groups.Normal.fg, 'oklch')]])\n  -- Approximately 10.5\n  local ref_h = ref_lch.h\n\n  local validate = function(sources, coef, ref_normal_fg)\n    local args = string.format('%s, %s', vim.inspect(sources), coef)\n    validate_chan_method('chan_repel', 'hue', args, ref_normal_fg)\n  end\n\n  local ref_color = function(nudge)\n    --stylua: ignore\n    local lua_get_cmd = string.format(\n      [[MiniColors.convert({ l = %s, c = %s, h = %s }, 'hex')]],\n      -- Having `% 360` is crucial to test periodic nature\n      ref_lch.l, ref_lch.c, (ref_lch.h + nudge) % 360\n    )\n    return child.lua_get(lua_get_cmd)\n  end\n\n  -- This mostly tests periodic nature of \"hue\" channel\n\n  -- Should be repelled away from source\n  validate({ ref_h + 5 }, 4, ref_color(-1.146))\n  validate({ ref_h - 5 }, 4, ref_color(1.146))\n\n  -- Should be attracted with negative coefficient\n  validate({ ref_h + 5 }, -4, ref_color(3.115))\n  validate({ ref_h - 5 }, -4, ref_color(-3.115))\n\n  -- Should be repelled on circle\n  validate({ ref_h + 5 }, 20, ref_color(-15.576))\n  validate({ ref_h - 5 }, 20, ref_color(15.576))\n\n  -- Should account for periodic nature. Here 355 is actually close (~15.5\n  -- instead of ~344.5), so it should be repelled in positive direction\n  validate({ 355 }, 20, ref_color(9.214))\n\n  -- Points away from 180 degrees should be almost unaffected\n  validate({ ref_h + 180 }, 20, ref_color(0))\nend\n\nT['as_colorscheme() methods']['chan_repel()']['properly repels when close to source'] = function()\n  local create_cs = function(fg, bg)\n    local lua_cmd =\n      string.format([[_G.cs = MiniColors.as_colorscheme({ groups = { Normal = { fg = '%s', bg = '%s' } } })]], fg, bg)\n    child.lua(lua_cmd)\n  end\n\n  local validate = function(channel, sources, coef, ref_normal_group)\n    local lua_get_cmd =\n      string.format([[_G.cs:chan_repel('%s', %s, %s).groups.Normal]], channel, vim.inspect(sources), coef)\n    eq(child.lua_get(lua_get_cmd), ref_normal_group)\n  end\n\n  -- Lightness\n  create_cs('#ffffff', '#000000')\n  validate('lightness', { 0 }, 10, { fg = '#ffffff', bg = '#161616' })\n  validate('lightness', { 100 }, 10, { fg = '#e2e2e2', bg = '#000000' })\n\n  -- Chroma (grays will remain grays as they don't have hue to go along)\n  create_cs('#ba4a73', '#eeeeee')\n  validate('chroma', { 14.96798 }, 5, { fg = '#cc2d72', bg = '#eeeeee' })\n\n  -- Saturation (grays sill remain the same)\n  create_cs('#d70071', '#eeeeee')\n  validate('saturation', { 0 }, 10, { fg = '#d70071', bg = '#eeeeee' })\n  validate('saturation', { 100 }, 10, { fg = '#cf2772', bg = '#eeeeee' })\n\n  -- Hue\n  create_cs('#837655', '#6b7695')\n  validate('hue', { 89.0081 }, 10, { fg = '#7e7856', bg = '#6b7695' })\n  validate('hue', { 269.5389 }, 10, { fg = '#837655', bg = '#667895' })\n\n  -- Temperature\n  create_cs('#567e8d', '#bc5419')\n  validate('temperature', { 43.3911 }, 10, { fg = '#547f8a', bg = '#bc5419' })\n  validate('temperature', { 135.3044 }, 10, { fg = '#567e8d', bg = '#bf4f33' })\n\n  -- Pressure\n  create_cs('#567e8d', '#bc5419')\n  validate('pressure', { 43.3911 }, 10, { fg = '#597d90', bg = '#bc5419' })\n  validate('pressure', { 135.3044 }, 10, { fg = '#567e8d', bg = '#b55b00' })\n\n  -- a\n  create_cs('#018a79', '#a65d75')\n  validate('a', { -10.2764 }, 2, { fg = '#348779', bg = '#a65d75' })\n  validate('a', { 9.9023 }, 2, { fg = '#018a79', bg = '#9e6375' })\n\n  -- b\n  create_cs('#6073b2', '#8e7426')\n  validate('b', { -10.0310 }, 2, { fg = '#6474a7', bg = '#8e7426' })\n  validate('b', { 9.9888 }, 2, { fg = '#6073b2', bg = '#89753c' })\n\n  -- Red\n  create_cs('#ff0000', '#000000')\n  validate('red', { 0 }, 16, { fg = '#ff0000', bg = '#100000' })\n  validate('red', { 255 }, 16, { fg = '#ef0000', bg = '#000000' })\n\n  -- Green\n  create_cs('#00ff00', '#000000')\n  validate('green', { 0 }, 16, { fg = '#00ff00', bg = '#001000' })\n  validate('green', { 255 }, 16, { fg = '#00ef00', bg = '#000000' })\n\n  -- Blue\n  create_cs('#0000ff', '#000000')\n  validate('blue', { 0 }, 16, { fg = '#0000ff', bg = '#000010' })\n  validate('blue', { 255 }, 16, { fg = '#0000ef', bg = '#000000' })\nend\n\nT['as_colorscheme() methods']['chan_repel()']['validates arguments'] = function()\n  expect.error(function() child.lua('_G.cs:chan_repel(1, 10, 1)') end, 'Channel.*one of')\n  expect.error(function() child.lua([[_G.cs:chan_repel('aaa', 10, 1)]]) end, 'Channel.*one of')\n\n  expect.error(function() child.lua([[_G.cs:chan_repel('hue', 'a', 1)]]) end, '`sources`.*array of numbers')\n  expect.error(function() child.lua([[_G.cs:chan_repel('hue', { 'a' }, 1)]]) end, '`sources`.*array of numbers')\n\n  expect.error(function() child.lua([[_G.cs:chan_repel('hue', 10, 'a')]]) end, '`coef`.*number')\nend\n\n-- Only basic testing here. More thorough tests are in `chan_modify()`.\nT['as_colorscheme() methods']['chan_set()'] = new_set({ hooks = { pre_case = create_basic_cs } })\n\nT['as_colorscheme() methods']['chan_set()']['works with linear channels'] = function()\n  -- Add second color to test multiple `values`\n  -- Oklch ~ { l = 70, c = 5, h = 100 }\n  -- Oklab ~ { l = 70, a = -1, b = 5 }\n  -- Saturation ~ 32\n  -- Temperature = 170\n  -- Pressure = 80\n  -- RGB = { r = 178 g = 173, b = 137 }\n  child.lua([[_G.cs.groups.Normal.bg = '#b2ad89']])\n\n  local validate = function(channel, values, ref_normal, opts_string)\n    local lua_get_cmd =\n      string.format([[_G.cs:chan_set('%s', %s, %s).groups.Normal]], channel, vim.inspect(values), opts_string or '{}')\n    eq(child.lua_get(lua_get_cmd), ref_normal)\n  end\n\n  --stylua: ignore start\n  validate('lightness',   { 60 },  { fg = '#d8658d', bg = '#97926f' })\n  validate('chroma',      { 10 },  { fg = '#a65d74', bg = '#b9ae60' })\n  validate('saturation',  { 50 },  { fg = '#ad5774', bg = '#b6ad74' })\n  validate('hue',         { 45 },  { fg = '#bc541a', bg = '#c7a292' })\n  validate('temperature', { 45 },  { fg = '#9757b3', bg = '#8ab3c3' })\n  validate('pressure',    { 45 },  { fg = '#4d891f', bg = '#9eb394' })\n  validate('a',           { 0 },   { fg = '#777777', bg = '#b7ab89' })\n  validate('b',           { 0 },   { fg = '#ba4a73', bg = '#a6aeac' })\n  validate('red',         { 128 }, { fg = '#804a73', bg = '#80ad89' })\n  validate('green',       { 128 }, { fg = '#ba8073', bg = '#b28089' })\n  validate('blue',        { 128 }, { fg = '#ba4a80', bg = '#b2ad80' })\n\n  -- Should allow multiple values while setting to closest one\n  validate('lightness',   { 60,  65 },  { fg = '#d8658d', bg = '#a49f7c' })\n  validate('chroma',      { 7,   10 },  { fg = '#a65d74', bg = '#b5ad7a' })\n  validate('saturation',  { 50,  40 },  { fg = '#ad5774', bg = '#b4ad80' })\n  -- - \"Hue\" should use circlar distance\n  validate('hue',         { 45,  355 }, { fg = '#b84b7b', bg = '#c7a292' })\n  validate('temperature', { 45,  150 }, { fg = '#9757b3', bg = '#a7b18e' })\n  validate('pressure',    { 45,  150 }, { fg = '#bf4d3e', bg = '#9eb394' })\n  validate('a',           { 0,   10 },  { fg = '#a65d74', bg = '#b7ab89' })\n  validate('b',           { 0,   4 },   { fg = '#ba4a73', bg = '#b0ad90' })\n  validate('red',         { 128, 237 }, { fg = '#ed4a73', bg = '#80ad89' })\n  validate('green',       { 128, 192 }, { fg = '#ba8073', bg = '#b2c089' })\n  validate('blue',        { 128, 140 }, { fg = '#ba4a80', bg = '#b2ad8c' })\n  --stylua: ignore end\n\n  -- Should allow single number as `values`\n  validate('lightness', 60, { fg = '#d8658d', bg = '#97926f' })\n\n  -- Should respect `opts`\n  validate('lightness', { 10 }, { fg = '#560029', bg = '#221d00' }, [[{ gamut_clip = 'cusp' }]])\nend\n\nT['as_colorscheme() methods']['chan_set()']['validates arguments'] = function()\n  expect.error(function() child.lua('_G.cs:chan_set(1, 10)') end, 'Channel.*one of')\n  expect.error(function() child.lua([[_G.cs:chan_set('aaa', 10)]]) end, 'Channel.*one of')\n\n  expect.error(function() child.lua([[_G.cs:chan_set('hue', 'a')]]) end, '`values`.*array of numbers')\n  expect.error(function() child.lua([[_G.cs:chan_set('hue', { 'a' })]]) end, '`values`.*array of numbers')\n  expect.error(function() child.lua([[_G.cs:chan_set('hue', {})]]) end, '`values`.*should not be empty')\nend\n\nT['as_colorscheme() methods']['color_modify()'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#ffffff', bg = '#ffffff' },\n      TestNotAllAttrs = { sp = '#ffffff' },\n    },\n    terminal = { [0] = '#ffffff' }\n  })]])\n  child.lua('_G.args_history = {}')\n  child.lua([[_G.f = function(...)\n    table.insert(_G.args_history, { ... })\n    return '#000000'\n  end]])\n\n  child.lua('_G.cs_modified = _G.cs:color_modify(_G.f)')\n  eq(child.lua_get('_G.cs_modified.groups.Normal'), { fg = '#000000', bg = '#000000' })\n  eq(child.lua_get('_G.cs_modified.groups.TestNotAllAttrs'), { sp = '#000000' })\n  eq(child.lua_get('_G.cs_modified.terminal[0]'), '#000000')\n\n  child.lua('table.sort(_G.args_history, function(a, b) return a[2].attr < b[2].attr end)')\n  eq(child.lua_get('_G.args_history'), {\n    { '#ffffff', { attr = 'bg', name = 'Normal' } },\n    { '#ffffff', { attr = 'fg', name = 'Normal' } },\n    { '#ffffff', { attr = 'sp', name = 'TestNotAllAttrs' } },\n    { '#ffffff', { attr = 'term', name = 'terminal_color_0' } },\n  })\nend\n\nT['as_colorscheme() methods']['compress()'] = new_set()\n\nT['as_colorscheme() methods']['compress()']['works'] = function()\n  -- Compressing should be like removing all highlight groups similar to ones\n  -- that come after `:hi clear`\n  child.cmd('hi clear')\n  child.lua('_G.cs = MiniColors.get_colorscheme()')\n  eq(child.lua_get('vim.tbl_count(_G.cs.groups) == 0'), false)\n  eq(child.lua_get('vim.tbl_count(_G.cs:compress().groups) == 0'), true)\n\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      -- This link is the same as after `:hi clear` so should be removed\n      SpecialChar = { link = 'Special' },\n\n      -- Should preserve manually created highlight groups\n      Test = { fg = '#ffffff' },\n\n      -- By default should exclude groups from some pre-defined plugins\n      DevIconMine = { fg = '#ffffff' },\n      colorizer_mine = { fg = '#ffffff' },\n    },\n    -- Terminal colors should be untouched\n    terminal = { [1] = '#ff0000' }\n  })]])\n  child.lua('_G.cs_compressed = _G.cs:compress()')\n\n  eq(child.lua_get('_G.cs_compressed.groups'), { Test = { fg = '#ffffff' } })\n  eq(child.lua_get('_G.cs_compressed.terminal'), { [1] = '#ff0000' })\n\n  -- Should return full copy of group data\n  child.lua([[_G.cs.groups.Test.bg = '#000000']])\n  child.lua([[_G.cs.terminal[1] = '#000000']])\n\n  eq(child.lua_get('_G.cs_compressed.groups.Test.bg'), vim.NIL)\n  eq(child.lua_get('_G.cs_compressed.terminal[1]'), '#ff0000')\nend\n\nT['as_colorscheme() methods']['compress()']['respects `opts.plugins`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      DevIconMine = { fg = '#ffffff' },\n      colorizer_mine = { fg = '#ffffff' },\n    }\n  })]])\n\n  eq(child.lua_get('_G.cs:compress({ plugins = false }).groups'), {\n    DevIconMine = { fg = '#ffffff' },\n    colorizer_mine = { fg = '#ffffff' },\n  })\nend\n\nT['as_colorscheme() methods']['compress()']['does not have side effects'] = function()\n  -- As checking equivalence to result of `:hi clear` needs to execute it,\n  -- there should be proper cache and restore of current color scheme\n  child.cmd('hi TestRestore guifg=#ffffff')\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = { Test = { bg = '#000000' } }\n  })]])\n\n  child.lua('_G.cs:compress()')\n  expect.match(child.cmd_capture('hi TestRestore'), 'guifg=#ffffff$')\nend\n\nT['as_colorscheme() methods']['get_palette()'] = new_set()\n\nT['as_colorscheme() methods']['get_palette()']['works'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { fg = '#ffffff', bg = '#000000' },\n      Test = { fg = '#fcb48c', bg = '#ffadac', sp = '#e9c07a' },\n    },\n    terminal = { [0] = '#222222', [1] = '#777777', [15] = '#d4d4d4' },\n  })]])\n\n  -- Should return colors in increasing order of lightness\n  eq(\n    child.lua_get('_G.cs:get_palette()'),\n    { '#000000', '#222222', '#777777', '#ffadac', '#fcb48c', '#e9c07a', '#d4d4d4', '#ffffff' }\n  )\n\n  -- By default returns only colors above small threshold\n  child.lua([[\n    local cs_groups = {}\n    for i = 0, 100 do\n      cs_groups['Test' .. i] = { fg = '#012345' }\n    end\n    cs_groups.TestRare = { fg = '#543210' }\n    _G.cs = MiniColors.as_colorscheme({ groups = cs_groups })\n  ]])\n  eq(child.lua_get('_G.cs:get_palette()'), { '#012345' })\nend\n\nT['as_colorscheme() methods']['get_palette()']['respects `opts.threshold`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = { Test = { fg = '#012345', bg = '#012345', sp = '#543210' } }\n  })]])\n  eq(child.lua_get('_G.cs:get_palette({ threshold = 0.5 })'), { '#012345' })\nend\n\nT['as_colorscheme() methods']['resolve_links()'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = {\n      Normal = { link = 'Test1' },\n      Test1 = { link = 'Test2' },\n      Test2 = { fg = '#ffffff' },\n      TestImpossible = { link = 'TestMissing' },\n    }\n  })]])\n  child.lua('_G.cs_resolved = _G.cs:resolve_links()')\n\n  eq(child.lua_get('_G.cs_resolved.groups'), {\n    -- Should resolve all nested links\n    Normal = { fg = '#ffffff' },\n    Test1 = { fg = '#ffffff' },\n    Test2 = { fg = '#ffffff' },\n    -- Can't resolve link to a group not defined within color scheme\n    TestImpossible = { link = 'TestMissing' },\n  })\n\n  -- Should return copy without modifying original\n  eq(child.lua_get('_G.cs.groups.Test1.fg'), vim.NIL)\n\n  -- Resolved data should be independent of original link\n  child.lua([[_G.cs_resolved.groups.Test2.fg = '#000000']])\n  eq(child.lua_get('_G.cs_resolved.groups.Test1.fg'), '#ffffff')\nend\n\nT['as_colorscheme() methods']['simulate_cvd()'] = function()\n  -- Test only basics. More thorough ones are in `MiniColors.simulate_cvd()`.\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    groups = { Normal = { fg = '#00ff00', bg = '#00ff00', sp = '#00ff00' } },\n    terminal = { [1] = '#ff0000' },\n  })]])\n\n  child.lua([[_G.cs_cvd = _G.cs:simulate_cvd('protan', 1)]])\n  eq(child.lua_get('_G.cs_cvd.groups'), { Normal = { fg = '#ffc900', bg = '#ffc900', sp = '#ffc900' } })\n  eq(child.lua_get('_G.cs_cvd.terminal[1]'), '#271d00')\nend\n\nT['as_colorscheme() methods']['write()'] = new_set({\n  hooks = {\n    pre_case = function()\n      local lua_cmd = string.format([[vim.fn.stdpath = function() return %s end]], vim.inspect(dir_path))\n      child.lua(lua_cmd)\n\n      -- Add to `rtp` to be able to discrove color schemes\n      child.cmd('set rtp+=' .. dir_path)\n    end,\n    post_case = function() vim.fn.delete(colors_path, 'rf') end,\n  },\n})\n\nlocal make_validate_file_lines = function(path)\n  local lines = vim.fn.readfile(path)\n  local lines_string = table.concat(lines, '\\n')\n  return function(pat) expect.match(lines_string, pat) end, function(pat) expect.no_match(lines_string, pat) end\nend\n\nT['as_colorscheme() methods']['write()']['works'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'my_cs',\n    groups = {\n      Normal = { fg = '#ffffff', bg = '#000000' },\n      -- This should be dropped during compression\n      SpecialChar = { link = 'Special' },\n    },\n    terminal = { [1] = '#ff0000' },\n  })]])\n\n  -- Calling `write()` should result into discroverable color scheme\n  child.lua('_G.cs:write()')\n\n  -- Validate\n  child.cmd('colorscheme my_cs')\n\n  eq(child.g.colors_name, 'my_cs')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#ffffff')\n  eq(child.g.terminal_color_1, '#ff0000')\n\n  -- Make basic checks for file content\n  local validate_match, validate_no_match = make_validate_file_lines(colors_path .. '/my_cs.lua')\n\n  -- - Description comments\n  validate_match([[^%-%- Made with 'mini%.colors']])\n  validate_match([[%-%- Highlight groups]])\n  validate_match([[%-%- Terminal colors]])\n\n  -- - Basic code\n  validate_match([[vim.cmd%('highlight clear'%)]])\n  validate_match([[vim%.g%.colors_name = \"my_cs\"]])\n  validate_match([[\"Normal\", { bg = \"#000000\", fg = \"#ffffff\" }]])\n  validate_match([[g.terminal_color_1 = \"#ff0000\"]])\n\n  -- - Should compress by default and not include redundant groups\n  validate_no_match('SpecialChar')\nend\n\nT['as_colorscheme() methods']['write()']['makes unique color scheme name'] = function()\n  mock_cs()\n\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    -- This color scheme should already be present\n    name = 'mock_cs',\n    groups = { Normal = { fg = '#ffffff', bg = '#000000' } },\n    terminal = { [1] = '#ff0000' },\n  })]])\n  child.lua('_G.cs:write()')\n\n  local files = child.fn.readdir(colors_path)\n  eq(#files, 1)\n  -- File name should add timestamp suffix in case of duplicated name, but\n  -- doesn't work on Windows\n  helpers.skip_on_windows('`vim.fn.strftime()` does not work on Windows')\n  expect.match(files[1], 'mock_cs_%d%d%d%d%d%d%d%d_%d%d%d%d%d%d%.lua')\nend\n\nT['as_colorscheme() methods']['write()']['handles empty fields'] = function()\n  child.lua('_G.cs = MiniColors.as_colorscheme({})')\n  child.lua('_G.cs:write()')\n\n  -- File name should be inferred as 'mini_colors'\n  local validate_match = make_validate_file_lines(colors_path .. 'mini_colors.lua')\n\n  validate_match('g%.colors_name = nil')\n  validate_match('%-%- No highlight groups defined')\n  validate_match('%-%- No terminal colors defined')\nend\n\nT['as_colorscheme() methods']['write()']['handles metatables'] = function()\n  child.lua([[\n    local mt = { __tostring = function(x) return vim.inspect(x) end }\n    _G.cs = MiniColors.as_colorscheme({\n      name = 'my_cs',\n      groups = {\n        Normal = setmetatable({ fg = '#ffffff', bg = '#000000' }, mt),\n        -- This should be dropped during compression\n        SpecialChar = vim.empty_dict(),\n      },\n      terminal = setmetatable({ [1] = '#ff0000' }, mt),\n    })]])\n\n  child.lua('_G.cs:write()')\n  local _, validate_no_match = make_validate_file_lines(colors_path .. '/my_cs.lua')\n  validate_no_match('metatable')\n  validate_no_match('vim%.empty_dict%(%)')\nend\n\nT['as_colorscheme() methods']['write()']['respects `opts.compress`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'my_cs',\n    groups = {\n      -- This should be dropped during compression\n      SpecialChar = { link = 'Special' },\n      Normal = { fg = '#ffffff' },\n    }\n  })]])\n  child.lua('_G.cs:write({ compress = false })')\n\n  local validate_match = make_validate_file_lines(colors_path .. 'my_cs.lua')\n  -- It should be present as no compression should have been done\n  validate_match('SpecialChar')\nend\n\nT['as_colorscheme() methods']['write()']['respects `opts.name`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'blue',\n    groups = { Normal = { fg = '#ffffff' } }\n  })]])\n  child.lua([[_G.cs:write({ name = 'my_cs_from_name' })]])\n\n  eq(child.fn.filereadable(colors_path .. 'my_cs_from_name.lua'), 1)\nend\n\nT['as_colorscheme() methods']['write()']['respects `opts.directory`'] = function()\n  local inner_dir = dir_path .. 'inner_dir/'\n  MiniTest.finally(function() vim.fn.delete(inner_dir, 'rf') end)\n\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'my_cs',\n    groups = { Normal = { fg = '#ffffff' } }\n  })]])\n\n  local write_cmd = '_G.cs:write({ directory = ' .. vim.inspect(inner_dir) .. ' })'\n  child.lua(write_cmd)\n\n  eq(child.fn.filereadable(inner_dir .. 'my_cs.lua'), 1)\nend\n\nT['get_colorscheme()'] = new_set()\n\nlocal validate_mock_cs = function(cs_var)\n  -- Fields\n  local validate_field = function(field, value) eq(child.lua_get(cs_var .. '.' .. field), value) end\n\n  validate_field('groups.Normal', { fg = '#5f87af', bg = '#080808' })\n  validate_field('groups.TestNormalCterm', { ctermfg = 67, ctermbg = 232 })\n  validate_field('groups.TestComment', { fg = '#5f87af', bg = '#080808' })\n  validate_field('groups.TestSpecial', { sp = '#00ff00', underline = true })\n  validate_field('groups.TestBlend', { bg = '#121212', blend = 0 })\n\n  validate_field('name', 'mock_cs')\n\n  validate_field('terminal[0]', '#010101')\n  validate_field('terminal[7]', '#fefefe')\n\n  -- Methods\n  local validate_method = function(method)\n    local lua_cmd = string.format('type(%s.%s)', cs_var, method)\n    eq(child.lua_get(lua_cmd), 'function')\n  end\n\n  validate_method('apply')\n  validate_method('add_cterm_attributes')\n  validate_method('add_terminal_colors')\n  validate_method('add_transparency')\n  validate_method('chan_add')\n  validate_method('chan_invert')\n  validate_method('chan_modify')\n  validate_method('chan_multiply')\n  validate_method('chan_repel')\n  validate_method('chan_set')\n  validate_method('color_modify')\n  validate_method('compress')\n  validate_method('get_palette')\n  validate_method('resolve_links')\n  validate_method('simulate_cvd')\n  validate_method('write')\nend\n\nT['get_colorscheme()']['works for current color scheme'] = function()\n  mock_cs()\n  child.cmd('colorscheme mock_cs')\n\n  child.lua('_G.cs = MiniColors.get_colorscheme()')\n  validate_mock_cs('_G.cs')\nend\n\nT['get_colorscheme()']['works for some color scheme'] = function()\n  mock_cs()\n  child.lua([[_G.cs = MiniColors.get_colorscheme('mock_cs')]])\n  validate_mock_cs('_G.cs')\nend\n\nT['get_colorscheme()']['works when color is defined by name'] = function()\n  child.cmd('hi Normal guifg=Red guibg=Black')\n  child.g.terminal_color_1 = 'Red'\n\n  child.lua('_G.cs = MiniColors.get_colorscheme()')\n  eq(child.lua_get('_G.cs.groups.Normal'), { fg = '#ff0000', bg = '#000000' })\n  eq(child.lua_get('_G.cs.terminal[1]'), '#ff0000')\nend\n\nT['get_colorscheme()']['works with cleared groups'] = function()\n  child.cmd('hi clear MsgArea')\n  child.cmd('hi clear AAA')\n\n  local validate_hl = function(name, ref)\n    eq(child.lua_get('_G.cs.groups.' .. name), ref)\n    -- Should not include metatable (from being equal to `vim.empty_dict()`),\n    -- as this results in incorrect lines after `write()`\n    eq(child.lua_get('getmetatable(_G.cs.groups.' .. name .. ')'), vim.NIL)\n  end\n\n  -- Cleared groups should still be present\n  child.lua('_G.cs = MiniColors.get_colorscheme()')\n  validate_hl('MsgArea', {})\n  validate_hl('AAA', {})\n\n  -- Should work after `add_transparency()` (still no metatable)\n  child.lua('_G.cs = _G.cs:add_transparency()')\n  validate_hl('MsgArea', { blend = 0 })\n  validate_hl('AAA', {})\nend\n\nT['get_colorscheme()']['validates arguments'] = function()\n  expect.error(function() child.lua_get('MiniColors.get_colorscheme(111)') end, '`name`.*string')\n  expect.error(function() child.lua_get([[MiniColors.get_colorscheme('aaa')]]) end, 'No color scheme')\nend\n\nT['get_colorscheme()']['has no side effects'] = function()\n  -- Update current color scheme\n  child.g.color_name = 'aaa'\n  child.cmd('hi AAA guifg=#aaaaaa')\n\n  mock_cs()\n  child.lua([[_G.cs = MiniColors.get_colorscheme('mock_cs')]])\n\n  eq(child.g.color_name, 'aaa')\n  expect.match(child.cmd_capture('hi AAA'), 'AAA.*guifg=#aaaaaa')\nend\n\nT['get_colorscheme()']['respects `opts.new_name`'] = function()\n  -- Current color scheme\n  child.g.colors_name = 'aaa'\n  eq(child.lua_get([[MiniColors.get_colorscheme(nil, { new_name = 'bbb' }).name]]), 'bbb')\n\n  -- Some other color scheme\n  mock_cs()\n  eq(child.lua_get([[MiniColors.get_colorscheme('mock_cs', { new_name = 'ccc' }).name]]), 'ccc')\nend\n\nT['animate()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Create two color scheme objects\n      child.lua([[_G.cs_1 = MiniColors.as_colorscheme({\n        name = 'cs_1',\n        groups = {\n          Normal      = { fg = '#190000', bg = '#001900' },\n          TestSpecial = { sp = '#000019', blend = 0 },\n          TestLink    = { link = 'Title' },\n          TestSingle  = { fg = '#ffffff', bg = '#000000', sp = '#aaaaaa', underline = true },\n\n          TestBold          = { fg = '#000000', bold          = true },\n          TestItalic        = { fg = '#000000', italic        = true },\n          TestNocombine     = { fg = '#000000', nocombine     = true },\n          TestReverse       = { fg = '#000000', reverse       = true },\n          TestStandout      = { fg = '#000000', standout      = true },\n          TestStrikethrough = { fg = '#000000', strikethrough = true },\n          TestUndercurl     = { fg = '#000000', undercurl     = true },\n          TestUnderdashed   = { fg = '#000000', underdashed   = true },\n          TestUnderdotted   = { fg = '#000000', underdotted   = true },\n          TestUnderdouble   = { fg = '#000000', underdouble   = true },\n          TestUnderline     = { fg = '#000000', underline     = true },\n        },\n        terminal = { [0] = '#190000', [7] = '#001900' }\n      })]])\n\n      child.lua([[_G.cs_2 = MiniColors.as_colorscheme({\n        name = 'cs_2',\n        groups = {\n          Normal      = { fg = '#000000', bg = '#000000' },\n          TestSpecial = { sp = '#000000', blend = 25 },\n          TestLink    = { link = 'Comment' },\n          TestSingle  = {},\n\n          TestBold          = { fg = '#000000', bold          = nil },\n          TestItalic        = { fg = '#000000', italic        = nil },\n          TestNocombine     = { fg = '#000000', nocombine     = nil },\n          TestReverse       = { fg = '#000000', reverse       = nil },\n          TestStandout      = { fg = '#000000', standout      = nil },\n          TestStrikethrough = { fg = '#000000', strikethrough = nil },\n          TestUndercurl     = { fg = '#000000', undercurl     = nil },\n          TestUnderdashed   = { fg = '#000000', underdashed   = nil },\n          TestUnderdotted   = { fg = '#000000', underdotted   = nil },\n          TestUnderdouble   = { fg = '#000000', underdouble   = nil },\n          TestUnderline     = { fg = '#000000', underline     = nil },\n        },\n        terminal = { [7] = '#000000', [15] = '#000000' }\n      })]])\n\n      -- Create function to get relevant data\n      child.lua([[_G.get_relevant_cs_data = function(cs)\n        cs = cs or MiniColors.get_colorscheme()\n\n        return {\n          name = cs.name,\n          groups = {\n            Normal            = cs.groups.Normal,\n            TestSpecial       = cs.groups.TestSpecial,\n            TestLink          = cs.groups.TestLink,\n            TestSingle        = cs.groups.TestSingle,\n            TestBold          = cs.groups.TestBold,\n            TestItalic        = cs.groups.TestItalic,\n            TestNocombine     = cs.groups.TestNocombine,\n            TestReverse       = cs.groups.TestReverse,\n            TestStandout      = cs.groups.TestStandout,\n            TestStrikethrough = cs.groups.TestStrikethrough,\n            TestUndercurl     = cs.groups.TestUndercurl,\n            TestUnderdashed   = cs.groups.TestUnderdashed,\n            TestUnderdotted   = cs.groups.TestUnderdotted,\n            TestUnderdouble   = cs.groups.TestUnderdouble,\n            TestUnderline     = cs.groups.TestUnderline,\n          },\n          terminal = {\n            { 0, vim.g.terminal_color_0},\n            { 7, vim.g.terminal_color_7},\n            { 15, vim.g.terminal_color_15},\n          }\n        }\n      end]])\n    end,\n  },\n  n_retry = helpers.get_n_retry(4),\n})\n\nlocal validate_cs_1 = function()\n  local cur_cs_data = child.lua_get('_G.get_relevant_cs_data()')\n  local cs_1_data = child.lua_get('_G.get_relevant_cs_data(_G.cs_1)')\n  eq(cur_cs_data, cs_1_data)\nend\n\nlocal validate_cs_2 = function()\n  local cur_cs_data = child.lua_get('_G.get_relevant_cs_data()')\n  local cs_2_data = child.lua_get('_G.get_relevant_cs_data(_G.cs_2)')\n  eq(cur_cs_data, cs_2_data)\nend\n\n--stylua: ignore\nT['animate()']['works'] = function()\n  local validate_intermediate = function()\n    eq(\n      child.lua_get('_G.get_relevant_cs_data()'),\n      {\n        name = 'transition_step',\n        groups = {\n          Normal      = { fg = '#0c0100', bg = '#040f00' },\n          TestSpecial = { sp = '#00010b', blend = 8 },\n          TestLink    = { link = 'Title' },\n          TestSingle  = { bg = '#000000', fg = '#ffffff', sp = '#aaaaaa', underline = true },\n\n          TestBold          = { fg = '#000000', bold          = true },\n          TestItalic        = { fg = '#000000', italic        = true },\n          TestNocombine     = { fg = '#000000', nocombine     = true },\n          TestReverse       = { fg = '#000000', reverse       = true },\n          TestStandout      = { fg = '#000000', standout      = true },\n          TestStrikethrough = { fg = '#000000', strikethrough = true },\n          TestUndercurl     = { fg = '#000000', undercurl     = true },\n          TestUnderdashed   = { fg = '#000000', underdashed   = true },\n          TestUnderdotted   = { fg = '#000000', underdotted   = true },\n          TestUnderdouble   = { fg = '#000000', underdouble   = true },\n          TestUnderline     = { fg = '#000000', underline     = true },\n        },\n        terminal = { { 0, '#190000' }, { 7, '#040f00' }, { 15 } }\n      }\n    )\n  end\n\n  -- Start with first color scheme\n  child.lua('_G.cs_1:apply()')\n  validate_cs_1()\n\n  -- It should animate transition from current color scheme to first in array,\n  -- then to second, and so on\n  local test_transition_duration, test_show_duration = 15 * small_time, 10 * small_time\n  child.lua('_G.test_transition_duration = ' .. test_transition_duration)\n  child.lua('_G.test_show_duration = ' .. test_show_duration)\n  child.lua([[\n    MiniColors.animate(\n      { _G.cs_2, _G.cs_1 },\n      {\n        -- Test with manual options for more robust testing. Sadly, no default\n        -- option values are tested as times can be too fast for running in CI.\n        -- There are indirect tests in `:Colorscheme`, though.\n        transition_steps = 3,\n        transition_duration = _G.test_transition_duration,\n        show_duration = _G.test_show_duration,\n      }\n    )\n  ]])\n\n  -- Should actually perform transform\n  sleep(0.5 * test_transition_duration)\n  validate_intermediate()\n\n  sleep(0.5 * test_transition_duration + small_time)\n  validate_cs_2()\n\n  -- After first transition end it should show color scheme 2 for specified\n  -- \"show\" duration\n  sleep(test_show_duration - 2 * small_time)\n  validate_cs_2()\n\n  -- After showing period it should start transition back to first one (as it\n  -- was specially designed command)\n  sleep(0.5 * test_transition_duration + 3 * small_time)\n  validate_intermediate()\n\n  sleep(0.5 * test_transition_duration)\n  validate_cs_1()\nend\n\nT['animate()']['validates arguments'] = function()\n  expect.error(function() child.lua('MiniColors.animate(_G.cs_2)') end, 'array of color schemes')\nend\n\nT['convert()'] = new_set()\n\nlocal convert = function(...) return child.lua_get('MiniColors.convert(...)', { ... }) end\n\nT['convert()']['converts to 8-bit'] = function()\n  local validate = function(x, ref) eq(convert(x, '8-bit'), ref) end\n\n  local bit_ref = 67\n  validate(bit_ref, bit_ref)\n  validate('#5f87af', bit_ref)\n  validate({ r = 95, g = 135, b = 175 }, bit_ref)\n  validate({ l = 54.729, a = -2.692, b = -7.072 }, bit_ref)\n  validate({ l = 54.729, c = 7.567, h = 249.16 }, bit_ref)\n  validate({ l = 54.729, s = 44.01, h = 249.16 }, bit_ref)\n\n  -- Handles grays\n  local gray_ref = 240\n  validate({ r = 88, g = 88, b = 88 }, gray_ref)\n  validate({ l = 37.6, a = 0, b = 0 }, gray_ref)\n  validate({ l = 37.6, c = 0 }, gray_ref)\n  validate({ l = 37.6, c = 0, h = 180 }, gray_ref)\n  validate({ l = 37.6, s = 0 }, gray_ref)\n  validate({ l = 37.6, s = 0, h = 180 }, gray_ref)\nend\n\nT['convert()']['converts to HEX'] = function()\n  local validate = function(x, ref) eq(convert(x, 'hex'), ref) end\n\n  local hex_ref = '#5f87af'\n  validate(67, hex_ref)\n  validate(hex_ref, hex_ref)\n  validate({ r = 95, g = 135, b = 175 }, hex_ref)\n  validate({ l = 54.729, a = -2.692, b = -7.072 }, hex_ref)\n  validate({ l = 54.729, c = 7.567, h = 249.16 }, hex_ref)\n  validate({ l = 54.729, s = 44.01, h = 249.16 }, hex_ref)\n\n  -- Handles grays\n  local gray_ref = '#111111'\n  validate({ r = 17, g = 17, b = 17 }, gray_ref)\n  validate({ l = 8, a = 0, b = 0 }, gray_ref)\n  validate({ l = 8, c = 0 }, gray_ref)\n  validate({ l = 8, c = 0, h = 180 }, gray_ref)\n  validate({ l = 8, s = 0 }, gray_ref)\n  validate({ l = 8, s = 0, h = 180 }, gray_ref)\n\n  -- Performs correct gamut clipping\n  -- NOTE: this uses approximate linear model and not entirely correct\n  -- Clipping should be correct below and above cusp lightness.\n  -- Cusp for hue=0 is at c=26.23 and l=59.05\n  eq(convert({ l = 15, c = 13, h = 0 }, 'hex'), convert({ l = 15, c = 10.266, h = 0 }, 'hex'))\n  eq(convert({ l = 85, c = 13, h = 0 }, 'hex'), convert({ l = 85, c = 9.5856, h = 0 }, 'hex'))\n\n  -- Clipping with 'chroma' method should clip chroma channel\n  eq(\n    convert({ l = 15, c = 13, h = 0 }, 'hex', { gamut_clip = 'chroma' }),\n    convert({ l = 15, c = 10.266, h = 0 }, 'hex')\n  )\n  eq(\n    convert({ l = 85, c = 13, h = 0 }, 'hex', { gamut_clip = 'chroma' }),\n    convert({ l = 85, c = 9.5856, h = 0 }, 'hex')\n  )\n\n  -- Clipping with 'lightness' method should clip lightness channel\n  eq(\n    convert({ l = 15, c = 13, h = 0 }, 'hex', { gamut_clip = 'lightness' }),\n    convert({ l = 22.07, c = 13, h = 0 }, 'hex')\n  )\n  eq(\n    convert({ l = 85, c = 13, h = 0 }, 'hex', { gamut_clip = 'lightness' }),\n    convert({ l = 79.66, c = 13, h = 0 }, 'hex')\n  )\n\n  -- Clipping with 'cusp' method should draw line towards c=c_cusp, l=0 in\n  -- (c, l) coordinates (with **not corrected** `l`)\n  eq(\n    convert({ l = 15, c = 13, h = 0 }, 'hex', { gamut_clip = 'cusp' }),\n    convert({ l = 18.84, c = 11.77, h = 0 }, 'hex')\n  )\n  eq(convert({ l = 85, c = 13, h = 0 }, 'hex', { gamut_clip = 'cusp' }), convert({ l = 82, c = 11.5, h = 0 }, 'hex'))\nend\n\nT['convert()']['converts to RGB'] = function()\n  local validate = function(x, ref, tol) eq_approx(convert(x, 'rgb'), ref, tol or 0) end\n\n  local rgb_ref = { r = 95, g = 135, b = 175 }\n  validate(67, rgb_ref)\n  validate('#5f87af', rgb_ref)\n  validate(rgb_ref, rgb_ref)\n  validate({ l = 54.729, a = -2.692, b = -7.072 }, rgb_ref, 0.01)\n  validate({ l = 54.729, c = 7.567, h = 249.16 }, rgb_ref, 0.01)\n  validate({ l = 54.729, s = 44.01, h = 249.16 }, rgb_ref, 0.01)\n\n  -- Handles grays\n  local gray_ref = { r = 17, g = 17, b = 17 }\n  validate({ l = 8, a = 0, b = 0 }, gray_ref, 0.02)\n  validate({ l = 8, c = 0 }, gray_ref, 0.02)\n  validate({ l = 8, c = 0, h = 180 }, gray_ref, 0.02)\n  validate({ l = 8, s = 0 }, gray_ref, 0.02)\n  validate({ l = 8, s = 0, h = 180 }, gray_ref, 0.02)\n\n  -- Normalization\n  validate({ r = 300, g = -10, b = 127 }, { r = 255, g = 0, b = 127 })\n\n  -- Performs correct gamut clipping\n  -- NOTE: this uses approximate linear model and not entirely correct\n  -- Clipping should be correct below and above cusp lightness.\n  -- Cusp for hue=0 is at c=26.23 and l=59.05\n  eq_approx(convert({ l = 15, c = 13, h = 0 }, 'rgb'), convert({ l = 15, c = 10.266, h = 0 }, 'rgb'), 1e-4)\n  eq_approx(convert({ l = 85, c = 13, h = 0 }, 'rgb'), convert({ l = 85, c = 9.5856, h = 0 }, 'rgb'), 1e-4)\n\n  -- Clipping with 'chroma' method should clip chroma channel\n  eq_approx(\n    convert({ l = 15, c = 13, h = 0 }, 'rgb', { gamut_clip = 'chroma' }),\n    convert({ l = 15, c = 10.266, h = 0 }, 'rgb'),\n    0.02\n  )\n  eq_approx(\n    convert({ l = 85, c = 13, h = 0 }, 'rgb', { gamut_clip = 'chroma' }),\n    convert({ l = 85, c = 9.5856, h = 0 }, 'rgb'),\n    0.02\n  )\n\n  -- Clipping with 'lightness' method should clip lightness channel\n  eq_approx(\n    convert({ l = 15, c = 13, h = 0 }, 'rgb', { gamut_clip = 'lightness' }),\n    convert({ l = 22.07, c = 13, h = 0 }, 'rgb'),\n    0.02\n  )\n  eq_approx(\n    convert({ l = 85, c = 13, h = 0 }, 'rgb', { gamut_clip = 'lightness' }),\n    convert({ l = 79.66, c = 13, h = 0 }, 'rgb'),\n    0.02\n  )\n\n  -- Clipping with 'cusp' method should draw line towards c=c_cusp, l=0 in\n  -- (c, l) coordinates (with **not corrected** `l`)\n  eq_approx(\n    convert({ l = 15, c = 13, h = 0 }, 'rgb', { gamut_clip = 'cusp' }),\n    convert({ l = 18.8397, c = 11.7727, h = 0 }, 'rgb'),\n    0.02\n  )\n  eq_approx(\n    convert({ l = 85, c = 13, h = 0 }, 'rgb', { gamut_clip = 'cusp' }),\n    convert({ l = 82.003, c = 11.5003, h = 0 }, 'rgb'),\n    0.02\n  )\nend\n\nT['convert()']['converts to Oklab'] = function()\n  local validate = function(x, ref, tol) eq_approx(convert(x, 'oklab'), ref, tol or 0) end\n\n  local oklab_ref = { l = 54.7293, a = -2.6923, b = -7.0722 }\n  validate(67, oklab_ref, 1e-3)\n  validate('#5f87af', oklab_ref, 1e-3)\n  validate({ r = 95, g = 135, b = 175 }, oklab_ref, 1e-3)\n  validate(oklab_ref, oklab_ref, 1e-6)\n  validate({ l = 54.7293, c = 7.5673, h = 249.1588 }, oklab_ref, 1e-3)\n  validate({ l = 54.7293, s = 44.0189, h = 249.1588 }, oklab_ref, 1e-3)\n\n  -- Handles grays\n  local gray_ref = { l = 8, a = 0, b = 0 }\n  validate(gray_ref, gray_ref)\n  validate({ l = 8, c = 0 }, gray_ref)\n  validate({ l = 8, c = 0, h = 180 }, gray_ref)\n  validate({ l = 8, s = 0 }, gray_ref)\n  validate({ l = 8, s = 0, h = 180 }, gray_ref)\n\n  -- Normalization\n  validate({ l = 110, a = 1, b = 1 }, { l = 100, a = 1, b = 1 }, 1e-6)\n  validate({ l = -10, a = 1, b = 1 }, { l = 0, a = 1, b = 1 }, 1e-6)\nend\n\nT['convert()']['converts to Oklch'] = function()\n  local validate = function(x, ref, tol) eq_approx(convert(x, 'oklch'), ref, tol or 0) end\n\n  local oklch_ref = { l = 54.7293, c = 7.5673, h = 249.1588 }\n  validate(67, oklch_ref, 1e-3)\n  validate('#5f87af', oklch_ref, 1e-3)\n  validate({ r = 95, g = 135, b = 175 }, oklch_ref, 1e-3)\n  validate({ l = 54.7293, a = -2.6923, b = -7.0722 }, oklch_ref, 1e-3)\n  validate(oklch_ref, oklch_ref, 1e-6)\n  validate({ l = 54.7293, s = 44.0189, h = 249.1588 }, oklch_ref, 1e-3)\n\n  -- Handles grays\n  local gray_ref = { l = 8, c = 0 }\n  validate({ l = 8, a = 0, b = 0 }, gray_ref)\n  validate(gray_ref, gray_ref)\n  validate({ l = 8, c = 0, h = 180 }, gray_ref)\n  validate({ l = 8, s = 0 }, gray_ref)\n  validate({ l = 8, s = 0, h = 180 }, gray_ref)\n\n  -- Normalization\n  validate({ l = 110, c = 10, h = 0 }, { l = 100, c = 10, h = 0 }, 1e-6)\n  validate({ l = -10, c = 10, h = 0 }, { l = 0, c = 10, h = 0 }, 1e-6)\n\n  validate({ l = 50, c = -10, h = 0 }, { l = 50, c = 0 }, 1e-6)\n\n  validate({ l = 50, c = 10, h = -90 }, { l = 50, c = 10, h = 270 }, 1e-6)\n  validate({ l = 50, c = 10, h = 450 }, { l = 50, c = 10, h = 90 }, 1e-6)\n  validate({ l = 50, c = 10, h = 360 }, { l = 50, c = 10, h = 0 }, 1e-6)\nend\n\nT['convert()']['converts to okhsl'] = function()\n  local validate = function(x, ref, tol) eq_approx(convert(x, 'okhsl'), ref, tol or 0) end\n\n  local okhsl_ref = { l = 54.7293, s = 44.0189, h = 249.1588 }\n  validate(67, okhsl_ref, 1e-3)\n  validate('#5f87af', okhsl_ref, 1e-3)\n  validate({ r = 95, g = 135, b = 175 }, okhsl_ref, 1e-3)\n  validate({ l = 54.7293, a = -2.6923, b = -7.0722 }, okhsl_ref, 1e-3)\n  validate({ l = 54.7293, c = 7.5673, h = 249.1588 }, okhsl_ref, 1e-3)\n  validate(okhsl_ref, okhsl_ref, 1e-6)\n\n  -- Handles grays\n  local gray_ref = { l = 8, s = 0 }\n  validate({ l = 8, a = 0, b = 0 }, gray_ref)\n  validate({ l = 8, c = 0 }, gray_ref)\n  validate({ l = 8, c = 0, h = 180 }, gray_ref)\n  validate(gray_ref, gray_ref)\n  validate({ l = 8, s = 0, h = 180 }, gray_ref)\n\n  -- Normalization\n  validate({ l = 110, s = 10, h = 0 }, { l = 100, s = 0 }, 1e-6)\n  validate({ l = -10, s = 10, h = 0 }, { l = 0, s = 0 }, 1e-6)\n\n  validate({ l = 50, s = -10, h = 0 }, { l = 50, s = 0 }, 1e-6)\n\n  validate({ l = 50, s = 10, h = -90 }, { l = 50, s = 10, h = 270 }, 1e-6)\n  validate({ l = 50, s = 10, h = 450 }, { l = 50, s = 10, h = 90 }, 1e-6)\n  validate({ l = 50, s = 10, h = 360 }, { l = 50, s = 10, h = 0 }, 1e-6)\nend\n\nT['convert()']['respects `opts.adjust_lightness`'] = function()\n  -- Should return correct lightness estimate\n  local validate = function(input, space, ref_output)\n    eq(convert(input, space, { adjust_lightness = false }), ref_output)\n  end\n  validate({ l = 20, a = 2, b = 0 }, 'hex', '#1e1216')\n  validate({ l = 20, c = 2, h = 0 }, 'hex', '#1e1216')\n  validate({ l = 20, s = 26, h = 357 }, 'hex', '#1e1216')\n\n  local validate_approx = function(input, space, ref_output, tol)\n    eq_approx(convert(input, space, { adjust_lightness = false }), ref_output, tol)\n  end\n  validate_approx({ l = 20, a = 2, b = 0 }, 'rgb', { r = 30, g = 18, b = 22 }, 0.5)\n  validate_approx({ l = 20, c = 2, h = 0 }, 'rgb', { r = 30, g = 18, b = 22 }, 0.5)\n  validate_approx({ l = 20, s = 26, h = 357 }, 'rgb', { r = 30, g = 18, b = 22 }, 0.5)\n\n  local validate_l = function(input, space, ref_l)\n    eq_approx(convert(input, space, { adjust_lightness = false }).l, ref_l, 0.05)\n  end\n  validate_l('#1e1216', 'oklab', 20)\n  validate_l('#1e1216', 'oklch', 20)\n  validate_l('#1e1216', 'okhsl', 20)\n\n  local validate_same_l = function(input, space) eq(convert(input, space, { adjust_lightness = false }).l, input.l) end\n  validate_same_l({ l = 20, a = 2, b = 0 }, 'oklch')\n  validate_same_l({ l = 20, a = 2, b = 0 }, 'okhsl')\n  validate_same_l({ l = 20, c = 2, h = 0 }, 'oklab')\n  validate_same_l({ l = 20, c = 2, h = 0 }, 'okhsl')\n  validate_same_l({ l = 20, s = 26, h = 357 }, 'oklab')\n  validate_same_l({ l = 20, s = 26, h = 357 }, 'oklch')\n\n  -- Should compute correct gamut clipping\n  eq(convert({ l = 20, c = 20, h = 0 }, 'hex', { adjust_lightness = false, gamut_clip = 'lightness' }), '#b2005d')\n  eq(convert({ l = 20, c = 20, h = 0 }, 'hex', { adjust_lightness = false, gamut_clip = 'cusp' }), '#6a0035')\nend\n\nT['convert()']['validates arguments'] = function()\n  -- Input\n  expect.error(function() convert('aaaaaa', 'rgb') end, 'Can not infer color space of \"aaaaaa\"')\n  expect.error(function() convert('##aaaaaa', 'rgb') end, 'Can not infer')\n  expect.error(function() convert({}, 'rgb') end, 'Can not infer color space of {}')\n  expect.error(function() convert({ l = 50, a = 1 }, 'rgb') end, 'Can not infer color space of')\n\n  -- - `nil` is allowed as input\n  eq(child.lua_get([[MiniColors.convert(nil, 'hex')]]), vim.NIL)\n\n  -- `to_space`\n  expect.error(function() convert('#aaaaaa', 'AAA') end, 'one of')\nend\n\n-- Only basic testing here. More thorough tests are in `chan_modify()`\n-- Assumes they both are implemented similarly\nT['modify_channel()'] = new_set()\n\nT['modify_channel()']['works'] = function()\n  child.lua('_G.f = function(x) return x + 10 end')\n  local validate = function(channel, ref)\n    local lua_get_cmd = string.format([[MiniColors.modify_channel('#ba4a73', '%s', _G.f)]], channel)\n    eq(child.lua_get(lua_get_cmd), ref)\n  end\n\n  validate('lightness', '#d8658d')\n  validate('chroma', '#d70071')\n  validate('saturation', '#c33f72')\n  validate('hue', '#bd4a62')\n  validate('temperature', '#bd4a62')\n  validate('pressure', '#ba4a73')\n  validate('a', '#d70071')\n  validate('b', '#cb4021')\n  validate('red', '#c44a73')\n  validate('green', '#ba5473')\n  validate('blue', '#ba4a7d')\nend\n\nT['modify_channel()']['accepts input in any color space'] = function()\n  local validate = function(input)\n    child.lua('_G.f = function(x) return x end')\n    local lua_get_cmd = string.format([[MiniColors.modify_channel(%s, 'lightness', _G.f)]], vim.inspect(input))\n    eq(child.lua_get(lua_get_cmd), '#5f87af')\n  end\n\n  validate(67)\n  validate('#5f87af')\n  validate({ r = 95, g = 135, b = 175 })\n  validate({ l = 54.729, a = -2.692, b = -7.072 })\n  validate({ l = 54.729, c = 7.567, h = 249.16 })\n  validate({ l = 54.729, s = 44.01, h = 249.16 })\nend\n\nT['modify_channel()']['validates arguments'] = function()\n  child.lua('_G.f = function(x) return x + 1 end')\n\n  expect.error(function() child.lua([[MiniColors.modify_channel(1, 'hue', _G.f)]]) end, 'color space')\n  expect.error(function() child.lua([[MiniColors.modify_channel('111111', 'hue', _G.f)]]) end, 'color space')\n\n  expect.error(function() child.lua([[MiniColors.modify_channel('#000000', 1, _G.f)]]) end, 'Channel.*one of')\n  expect.error(function() child.lua([[MiniColors.modify_channel('#000000', 'aaa', _G.f)]]) end, 'Channel.*one of')\n\n  expect.error(function() child.lua([[MiniColors.modify_channel('#000000', 'hue', 1)]]) end, '`f`.*callable')\nend\n\nT['modify_channel()']['respects `opts.gamut_clip`'] = function()\n  eq(\n    child.lua_get(\n      [[MiniColors.modify_channel('#ba4a73', 'chroma', function() return 100 end, { gamut_clip = 'cusp' })]]\n    ),\n    '#f50081'\n  )\nend\n\nT['simulate_cvd()'] = new_set()\n\nlocal simulate_cvd = function(...) return child.lua_get('MiniColors.simulate_cvd(...)', { ... }) end\n\nT['simulate_cvd()']['works for \"protan\"'] = function()\n  local validate = function(x, severity, ref) eq(simulate_cvd(x, 'protan', severity), ref) end\n\n  local hex = '#00ff00'\n  validate(hex, 0.0, '#00ff00')\n  validate(hex, 0.1, '#2ef400')\n  validate(hex, 0.2, '#55ea00')\n  validate(hex, 0.3, '#77e300')\n  validate(hex, 0.4, '#94dd00')\n  validate(hex, 0.5, '#add800')\n  validate(hex, 0.6, '#c4d400')\n  validate(hex, 0.7, '#d9d000')\n  validate(hex, 0.8, '#ebcd00')\n  validate(hex, 0.9, '#fdcb00')\n  validate(hex, 1.0, '#ffc900')\n\n  -- Works for non-hex input\n  validate({ r = 0, g = 255, b = 0 }, 1, '#ffc900')\nend\n\nT['simulate_cvd()']['works for \"deutan\"'] = function()\n  local validate = function(x, severity, ref) eq(simulate_cvd(x, 'deutan', severity), ref) end\n\n  local hex = '#00ff00'\n  validate(hex, 0.0, '#00ff00')\n  validate(hex, 0.1, '#2def02')\n  validate(hex, 0.2, '#51e303')\n  validate(hex, 0.3, '#6fd805')\n  validate(hex, 0.4, '#87cf06')\n  validate(hex, 0.5, '#9bc707')\n  validate(hex, 0.6, '#acc008')\n  validate(hex, 0.7, '#bbba09')\n  validate(hex, 0.8, '#c7b50a')\n  validate(hex, 0.9, '#d2b00a')\n  validate(hex, 1.0, '#dbab0b')\n\n  -- Works for non-hex input\n  validate({ r = 0, g = 255, b = 0 }, 1, '#dbab0b')\nend\n\nT['simulate_cvd()']['works for \"tritan\"'] = function()\n  local validate = function(x, severity, ref) eq(simulate_cvd(x, 'tritan', severity), ref) end\n\n  local hex = '#00ff00'\n  validate(hex, 0.0, '#00ff00')\n  validate(hex, 0.1, '#18f60e')\n  validate(hex, 0.2, '#22f11b')\n  validate(hex, 0.3, '#21f026')\n  validate(hex, 0.4, '#17f131')\n  validate(hex, 0.5, '#07f43f')\n  validate(hex, 0.6, '#00f851')\n  validate(hex, 0.7, '#00fa67')\n  validate(hex, 0.8, '#00f980')\n  validate(hex, 0.9, '#00f499')\n  validate(hex, 1.0, '#00edb0')\n\n  -- Works for non-hex input\n  validate({ r = 0, g = 255, b = 0 }, 1, '#00edb0')\nend\n\nT['simulate_cvd()']['works for \"mono\"'] = function()\n  local validate = function(lightness)\n    local hex = convert({ l = lightness, c = 4, h = 0 }, 'hex')\n    local ref_gray = convert({ l = convert(hex, 'oklch').l, c = 0 }, 'hex')\n    eq(simulate_cvd(hex, 'mono'), ref_gray)\n  end\n\n  for i = 0, 10 do\n    validate(10 * i)\n  end\n\n  -- Works for non-hex input\n  eq(simulate_cvd({ r = 0, g = 255, b = 0 }, 'mono'), '#d3d3d3')\nend\n\nT['simulate_cvd()']['allows all values of `severity`'] = function()\n  local validate = function(severity_1, severity_2)\n    eq(simulate_cvd('#00ff00', 'protan', severity_1), simulate_cvd('#00ff00', 'protan', severity_2))\n  end\n\n  -- Not one of 0, 0.1, ..., 0.9, 1 is rounded towards closest one\n  validate(0.54, 0.5)\n  validate(0.56, 0.6)\n\n  -- `nil` is allowed\n  validate(nil, 1)\n\n  -- Out of bounds values\n  validate(100, 1)\n  validate(-100, 0)\nend\n\nT['simulate_cvd()']['validates arguments'] = function()\n  -- Input\n  expect.error(function() simulate_cvd('aaaaaa', 'protan', 1) end, 'Can not infer color space of \"aaaaaa\"')\n  expect.error(function() simulate_cvd({}, 'protan', 1) end, 'Can not infer color space of {}')\n\n  -- - `nil` is allowed as input\n  eq(child.lua_get([[MiniColors.simulate_cvd(nil, 'protan', 1)]]), vim.NIL)\n\n  -- `cvd_type`\n  expect.error(function() simulate_cvd('#aaaaaa', 'AAA', 1) end, 'one of')\n\n  -- `severity`\n  expect.error(function() simulate_cvd('#aaaaaa', 'protan', 'a') end, '`severity`.*number')\nend\n\n-- Integration tests ==========================================================\nT[':Colorscheme'] = new_set({ n_retry = helpers.get_n_retry(4) })\n\nT[':Colorscheme']['works'] = function()\n  mock_cs()\n\n  child.cmd('hi Normal guifg=#ffffff')\n  type_keys(':Colorscheme mock_cs<CR>')\n  sleep(default_transition_duration + 3 * small_time)\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#5f87af')\nend\n\nT[':Colorscheme']['accepts several arguments'] = function()\n  helpers.skip_if_slow()\n\n  child.cmd('colorscheme blue')\n  mock_cs()\n  type_keys(':Colorscheme mock_cs blue<CR>')\n\n  sleep(default_transition_duration + small_time)\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#5f87af')\n\n  sleep(default_show_duration - 2 * small_transition_time)\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#5f87af')\n\n  sleep(default_transition_duration + 3 * small_time)\n  local blue_normal_fg = '#ffd700'\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=' .. blue_normal_fg)\nend\n\nT[':Colorscheme']['provides proper completion'] = function()\n  mock_cs()\n  type_keys(':Colorscheme mock_<Tab> blu<Tab>')\n  eq(child.fn.getcmdline(), 'Colorscheme mock_cs blue')\n  type_keys('<Esc>')\nend\n\nT['interactive()'] = new_set()\n\nT['interactive()']['works'] = function()\n  -- - Mock '~/.config/nvim'\n  local lua_cmd = 'vim.fn.stdpath = function() return ' .. vim.inspect(dir_path) .. ' end'\n  child.lua(lua_cmd)\n  child.cmd('set rtp+=' .. dir_path)\n  MiniTest.finally(function() vim.fn.delete(colors_path, 'rf') end)\n\n  -- Check screenshots only on Neovim>=0.11 as there are slight differences in\n  -- highlighting\n  local expect_screenshot = function()\n    if child.fn.has('nvim-0.11') == 1 then child.expect_screenshot() end\n  end\n\n  child.set_size(30, 60)\n  child.o.cmdheight = 3\n\n  child.g.colors_name = 'test_interactive'\n  child.cmd('hi Normal guifg=#ffffff guibg=#000000')\n\n  child.lua('MiniColors.interactive()')\n\n  -- General data\n  expect_screenshot()\n\n  eq(child.api.nvim_buf_get_name(0), 'minicolors://' .. child.api.nvim_get_current_buf() .. '/interactive')\n  eq(child.bo.filetype, 'lua')\n  eq(child.get_cursor(), { 22, 0 })\n  eq(child.api.nvim_get_mode().mode, 'n')\n\n  -- Applying transformations using direct calls to methods\n  type_keys('i', [[chan_invert('lightness')]], '<Esc>')\n  type_keys('<M-a>')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#000000 guibg=#ffffff')\n\n  -- Writing\n  -- - Write\n  type_keys('<A-w>')\n  expect_screenshot()\n  type_keys('<C-w>new_cs<CR>')\n\n  -- - Verify\n  child.cmd('hi Normal guifg=#ffffff guibg=#000000')\n  child.cmd('colorscheme new_cs')\n  eq(child.g.colors_name, 'new_cs')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#000000 guibg=#ffffff')\n\n  -- Resetting\n  type_keys('<M-r>')\n  eq(child.g.colors_name, 'test_interactive')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#ffffff guibg=#000000')\n\n  -- Quitting\n  local cur_buf_id = child.api.nvim_get_current_buf()\n  type_keys('<M-q>')\n  eq(child.api.nvim_get_current_buf() ~= cur_buf_id, true)\nend\n\nT['interactive()']['works without prior `setup()`'] = function()\n  unload_module()\n  expect.no_error(function() child.lua([[require('mini.colors').interactive()]]) end)\n\n  expect.match(child.cmd_capture('nmap <M-a>'), 'Apply')\nend\n\nT['interactive()']['can have side effects'] = function()\n  child.lua('MiniColors.interactive()')\n  type_keys('i', '_G.a = 1', '<Esc>')\n  type_keys('<M-a>')\n  eq(child.lua_get('_G.a'), 1)\nend\n\nT['interactive()']['has no internal side effects'] = function()\n  child.lua('MiniColors.interactive()')\n  type_keys('<M-a>')\n\n  -- Temporary values are not kept global\n  local validate_nil = function(var_name) eq(child.lua_get('type(' .. var_name .. ')'), 'nil') end\n\n  validate_nil('_G._interactive_cs')\n  validate_nil('self')\n\n  -- Direct methods should not be global\n  validate_nil('apply')\n  validate_nil('add_cterm_attributes')\n  validate_nil('add_terminal_colors')\n  validate_nil('add_transparency')\n  validate_nil('chan_add')\n  validate_nil('chan_invert')\n  validate_nil('chan_modify')\n  validate_nil('chan_multiply')\n  validate_nil('chan_repel')\n  validate_nil('chan_set')\n  validate_nil('color_modify')\n  validate_nil('compress')\n  validate_nil('get_palette')\n  validate_nil('resolve_links')\n  validate_nil('simulate_cvd')\n  validate_nil('write')\nend\n\nT['interactive()']['exposes relevant variables'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'input_cs',\n    groups = { Normal = { fg = '#ffffff' } }\n  })]])\n  child.lua('MiniColors.interactive({ colorscheme = _G.cs })')\n\n  local validate_code = function(value_code, ref_output)\n    type_keys('cc', '_G.output = ', value_code, '<Esc>')\n    type_keys('<M-a>')\n    eq(child.lua_get('_G.output'), ref_output)\n  end\n\n  -- Methods should be exposed (hope they are correct ones)\n  --stylua: ignore\n  local methods = {\n    'apply', 'add_cterm_attributes', 'add_terminal_colors', 'add_transparency',\n    'chan_add', 'chan_invert', 'chan_modify', 'chan_multiply', 'chan_repel', 'chan_set',\n    'color_modify', 'compress', 'get_palette', 'resolve_links', 'simulate_cvd', 'write',\n  }\n  for _, meth in ipairs(methods) do\n    validate_code('type(' .. meth .. ')', 'function')\n  end\n\n  -- `self` should be exposed with initial updatable colorscheme\n  type_keys('cc', [[chan_invert('lightness'); _G.self = self]], '<Esc>')\n  type_keys('<M-a>')\n  eq(child.lua_get('_G.self.name'), 'input_cs')\n  eq(child.lua_get('_G.self.groups.Normal.fg'), '#000000')\nend\n\nT['interactive()']['handles errors'] = function()\n  child.o.cmdheight = 10\n\n  child.lua('MiniColors.interactive()')\n  type_keys('i', 'a = 1 + true', '<Esc>')\n\n  expect.error(function() type_keys('<M-a>') end, 'attempt.*arithmetic.*boolean')\nend\n\nT['interactive()']['respects `opts.colorscheme`'] = function()\n  child.lua([[_G.cs = MiniColors.as_colorscheme({\n    name = 'input_cs',\n    groups = { Normal = { fg = '#ffffff' } },\n  })]])\n  child.g.colors_name = 'current_cs'\n  child.cmd('hi Normal guifg=#000000')\n\n  child.lua('MiniColors.interactive({ colorscheme = _G.cs })')\n\n  -- Apply\n  type_keys('<M-a>')\n  eq(child.g.colors_name, 'input_cs')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#ffffff')\n\n  -- Reset\n  child.cmd('hi Normal guifg=#000000')\n  type_keys('<M-a>')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#ffffff')\nend\n\nT['interactive()']['respects `opts.mappings`'] = function()\n  child.lua([[MiniColors.interactive({\n    mappings = { Apply = '<C-a>', Reset = '<C-r>', Quit = '<C-q>', Write = '<C-w>' },\n  })]])\n\n  local n = 0\n  local validate_desc = function(desc, ref_desc)\n    eq(desc, ref_desc)\n    n = n + 1\n  end\n\n  local buf_maps = child.api.nvim_buf_get_keymap(0, 'n')\n  for _, m in ipairs(buf_maps) do\n    if m.lhs == '<C-A>' then validate_desc(m.desc, 'Apply') end\n    if m.lhs == '<C-R>' then validate_desc(m.desc, 'Reset') end\n    if m.lhs == '<C-Q>' then validate_desc(m.desc, 'Quit') end\n    if m.lhs == '<C-W>' then validate_desc(m.desc, 'Write') end\n  end\n  -- Validate that all maps are created\n  eq(n, 4)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_comment.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('comment', config) end\nlocal unload_module = function() child.mini_unload('comment') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Common helpers\nlocal reload_with_hooks = function()\n  unload_module()\n  child.lua([[\n    _G.hook_args = {}\n    require('mini.comment').setup({\n      hooks = {\n        pre = function(...)\n          table.insert(_G.hook_args, { 'pre', vim.deepcopy({ ... }) })\n          -- Allow this to successfully change 'commentstring' option\n          vim.bo.commentstring = vim.bo.commentstring == '# %s' and '// %s' or '# %s'\n        end,\n        post = function(...) table.insert(_G.hook_args, { 'post', vim.deepcopy({ ... }) }) end,\n      },\n    })]])\nend\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\n-- Data =======================================================================\n-- Reference text\n-- aa\n--  aa\n--   aa\n--\n--   aa\n--  aa\n-- aa\nlocal example_lines = { 'aa', ' aa', '  aa', '', '  aa', ' aa', 'aa' }\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n      set_lines(example_lines)\n      child.bo.commentstring = '# %s'\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniComment)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniComment.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniComment.config.' .. field), value) end\n\n  expect_config('options.custom_commentstring', vim.NIL)\n  expect_config('options.ignore_blank_line', false)\n  expect_config('options.start_of_line', false)\n  expect_config('options.pad_comment_parts', true)\n  expect_config('mappings.comment', 'gc')\n  expect_config('mappings.comment_line', 'gcc')\n  expect_config('mappings.comment_visual', 'gc')\n  expect_config('mappings.textobject', 'gc')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ mappings = { comment = 'gC' } })\n  eq(child.lua_get('MiniComment.config.mappings.comment'), 'gC')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { custom_commentstring = 1 } }, 'options.custom_commentstring', 'function')\n  expect_config_error({ options = { ignore_blank_line = 1 } }, 'options.ignore_blank_line', 'boolean')\n  expect_config_error({ options = { start_of_line = 1 } }, 'options.start_of_line', 'boolean')\n  expect_config_error({ options = { pad_comment_parts = 1 } }, 'options.pad_comment_parts', 'boolean')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { comment = 1 } }, 'mappings.comment', 'string')\n  expect_config_error({ mappings = { comment_line = 1 } }, 'mappings.comment_line', 'string')\n  expect_config_error({ mappings = { comment_visual = 1 } }, 'mappings.comment_visual', 'string')\n  expect_config_error({ mappings = { textobject = 1 } }, 'mappings.textobject', 'string')\n  expect_config_error({ hooks = 'a' }, 'hooks', 'table')\n  expect_config_error({ hooks = { pre = 1 } }, 'hooks.pre', 'function')\n  expect_config_error({ hooks = { post = 1 } }, 'hooks.post', 'function')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('omap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('gc', 'Comment'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('o', 'gc')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { textobject = '' } })\n  eq(has_map('gc', 'Comment'), false)\nend\n\nT['toggle_lines()'] = new_set()\n\nlocal toggle_lines = forward_lua('MiniComment.toggle_lines')\n\nT['toggle_lines()']['works'] = function()\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  # aa', '  #', '  # aa' })\n\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  aa', '', '  aa' })\nend\n\nT['toggle_lines()']['validates arguments'] = function()\n  set_lines({ 'aa', 'aa', 'aa' })\n\n  --stylua: ignore start\n  expect.error(function() toggle_lines(-1, 1)    end, 'line_start.*1')\n  expect.error(function() toggle_lines(100, 101) end, 'line_start.*3')\n  expect.error(function() toggle_lines(1, -1)    end, 'line_end.*1')\n  expect.error(function() toggle_lines(1, 100)   end, 'line_end.*3')\n  expect.error(function() toggle_lines(2, 1)     end, 'line_start.*less than or equal.*line_end')\n  --stylua: ignore end\nend\n\nT['toggle_lines()'][\"works with different 'commentstring' options\"] = function()\n  -- Two-sided\n  set_lines(example_lines)\n  child.bo.commentstring = '/* %s */'\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  /* aa */', '  /**/', '  /* aa */' })\n\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  aa', '', '  aa' })\n\n  -- Right-sided\n  set_lines(example_lines)\n  child.bo.commentstring = '%s #'\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  aa #', '  #', '  aa #' })\n\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  aa', '', '  aa' })\n\n  -- Latex (#25)\n  set_lines(example_lines)\n  child.bo.commentstring = '% %s'\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  % aa', '  %', '  % aa' })\n\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  aa', '', '  aa' })\nend\n\nT['toggle_lines()']['respects tree-sitter injections'] = function()\n  -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers\n  local lines = {\n    'set background=dark',\n    'lua << EOF',\n    'print(1)',\n    'vim.api.nvim_exec2([[',\n    '    set background=light',\n    ']])',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  -- Single line comments\n  local validate = function(line, ref_output)\n    toggle_lines(line, line)\n    eq(get_lines()[line], ref_output)\n    -- Cleanup\n    set_lines(lines)\n  end\n\n  validate(1, '\" set background=dark')\n  validate(2, '\" lua << EOF')\n  validate(3, '-- print(1)')\n  validate(4, '-- vim.api.nvim_exec2([[')\n  validate(5, '    \" set background=light')\n  validate(6, '-- ]])')\n  validate(7, '\" EOF')\n\n  -- Multiline comments should be computed based on first line 'commentstring'\n  set_lines(lines)\n  toggle_lines(1, 3)\n  local out_lines = get_lines()\n  eq(out_lines[1], '\" set background=dark')\n  eq(out_lines[2], '\" lua << EOF')\n  eq(out_lines[3], '\" print(1)')\nend\n\nT['toggle_lines()']['respects `opts.ref_position`'] = function()\n  -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers\n  local lines = {\n    'lua << EOF',\n    '  print(1)',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  toggle_lines(2, 2, { ref_position = { 1, 0 } })\n  eq(get_lines()[2], '  \" print(1)')\n\n  set_lines(lines)\n  toggle_lines(2, 2, { ref_position = { 2, 3 } })\n  eq(get_lines()[2], '  -- print(1)')\nend\n\nT['toggle_lines()']['correctly computes indent'] = function()\n  toggle_lines(2, 4)\n  eq(get_lines(1, 4), { ' # aa', ' #  aa', ' #' })\nend\n\n--stylua: ignore\nT['toggle_lines()']['correctly detects comment/uncomment'] = function()\n  local validate = function(from, to, ref_lines)\n    set_lines({ '', 'aa', '# aa', '# aa', 'aa', '' })\n    toggle_lines(from, to)\n    eq(get_lines(), ref_lines)\n  end\n\n  -- It should uncomment only if all lines are comments\n  validate(3, 4, { '',  'aa',   'aa',     'aa',     'aa',   '' })\n  validate(2, 4, { '',  '# aa', '# # aa', '# # aa', 'aa',   '' })\n  validate(3, 5, { '',  'aa',   '# # aa', '# # aa', '# aa', '' })\n  validate(1, 6, { '#', '# aa', '# # aa', '# # aa', '# aa', '#' })\n\n  -- Blank lines should be ignored when making a decision\n  set_lines({ '# aa', '', '  ', '\\t', '# aa' })\n  toggle_lines(1, 5)\n  eq(get_lines(), { 'aa', '', '  ', '\\t', 'aa' })\nend\n\nT['toggle_lines()']['matches comment parts strictly when detecting comment/uncomment'] = function()\n  local validate = function(from, to, ref_lines)\n    set_lines({ '/*aa*/', '/* aa */', '/*  aa  */' })\n    toggle_lines(from, to)\n    eq(get_lines(), ref_lines)\n  end\n\n  -- Should first try to match 'commentstring' parts exactly with their\n  -- whitespace, with fallback on trimmed parts\n  child.bo.commentstring = '/* %s */'\n  validate(1, 3, { 'aa', 'aa', ' aa ' })\n  validate(2, 3, { '/*aa*/', 'aa', ' aa ' })\n  validate(3, 3, { '/*aa*/', '/* aa */', ' aa ' })\n\n  -- With `pad_comment_parts = false` should treat parts as is\n  child.lua('MiniComment.config.options.pad_comment_parts = false')\n\n  child.bo.commentstring = '/*%s*/'\n  validate(1, 3, { 'aa', ' aa ', '  aa  ' })\n  validate(2, 3, { '/*aa*/', ' aa ', '  aa  ' })\n  validate(3, 3, { '/*aa*/', '/* aa */', '  aa  ' })\n\n  child.bo.commentstring = '/*  %s  */'\n  validate(1, 3, { 'aa', ' aa ', 'aa' })\n  validate(2, 3, { '/*aa*/', ' aa ', 'aa' })\n  validate(3, 3, { '/*aa*/', '/* aa */', 'aa' })\n\n  child.bo.commentstring = ' /*%s*/ '\n  validate(1, 3, { 'aa', ' aa ', '  aa  ' })\n  validate(2, 3, { '/*aa*/', ' aa ', '  aa  ' })\n  validate(3, 3, { '/*aa*/', '/* aa */', '  aa  ' })\nend\n\nT['toggle_lines()']['respects `config.options.custom_commentstring`'] = function()\n  local lines = { 'aa', '  aa' }\n\n  -- Works correctly and called with proper arguments\n  child.lua([[MiniComment.config.options.custom_commentstring = function(...)\n    _G.args = { ... }\n    return '++ %s'\n  end]])\n\n  set_lines(lines)\n  toggle_lines(1, 2, { ref_position = { 2, 3 } })\n  eq(get_lines(), { '++ aa', '++   aa' })\n  eq(child.lua_get('_G.args'), { { 2, 3 } })\n\n  -- Allows `nil` output to indicate usage of default rules\n  child.lua('MiniComment.config.options.custom_commentstring = function() return nil end')\n  set_lines(lines)\n  toggle_lines(1, 2)\n  eq(get_lines(), { '# aa', '#   aa' })\n\n  -- Validates output\n  child.lua('MiniComment.config.options.custom_commentstring = function() return 2 end')\n  expect.error(function() toggle_lines(1, 2) end, \"2.*valid 'commentstring'\")\n\n  child.lua('MiniComment.config.options.custom_commentstring = function() return \"ab %c\" end')\n  expect.error(function() toggle_lines(1, 2) end, [[\"ab %%c\".*valid 'commentstring']])\nend\n\nT['toggle_lines()']['respects `config.options.start_of_line`'] = function()\n  child.lua('MiniComment.config.options.start_of_line = true')\n  local lines = { ' # aa', '  # aa', '# aa', '#  aa' }\n\n  -- Should recognize as commented only lines with zero indent\n  set_lines(lines)\n  toggle_lines(1, 3)\n  eq(get_lines(), { '#  # aa', '#   # aa', '# # aa', '#  aa' })\n  toggle_lines(1, 3)\n  eq(get_lines(), lines)\n\n  set_lines(lines)\n  toggle_lines(3, 4)\n  eq(get_lines(), { ' # aa', '  # aa', 'aa', ' aa' })\n  toggle_lines(3, 4)\n  eq(get_lines(), { ' # aa', '  # aa', '# aa', '#  aa' })\nend\n\nT['toggle_lines()']['respects `config.options.ignore_blank_line`'] = function()\n  child.lua('MiniComment.config.options.ignore_blank_line = true')\n  local lines = { '  aa', '', '  aa', '  ', '  aa' }\n\n  -- Should not add comment to blank (empty or with only whitespace) lines\n  set_lines(lines)\n  toggle_lines(1, 5)\n  eq(get_lines(), { '  # aa', '', '  # aa', '  ', '  # aa' })\n\n  -- Should ignore blank lines when deciding comment/uncomment action\n  toggle_lines(1, 5)\n  eq(get_lines(), lines)\nend\n\nT['toggle_lines()']['respects `config.options.pad_comment_parts`'] = function()\n  child.lua('MiniComment.config.options.pad_comment_parts = false')\n\n  local validate = function(lines_before, lines_after, lines_again)\n    set_lines(lines_before)\n    toggle_lines(1, #lines_before)\n    eq(get_lines(), lines_after)\n    toggle_lines(1, #lines_before)\n    eq(get_lines(), lines_again or lines_before)\n  end\n\n  -- No whitespace in parts\n  child.bo.commentstring = '#%s#'\n  -- - General case\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { '#aa#', '#  aa#', '#aa  #', '#  aa  #' })\n  -- - Tabs\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { '#aa#', '#\\taa#', '#aa\\t#', '#\\taa\\t#' })\n  -- - With indent\n  validate({ ' aa', '  aa' }, { ' #aa#', ' # aa#' })\n  -- - With blank/empty lines\n  validate({ '  aa', '', '  ', '\\t' }, { '  #aa#', '  ##', '  ##', '  ##' }, { '  aa', '', '', '' })\n\n  child.bo.commentstring = '#%s'\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { '#aa', '#  aa', '#aa  ', '#  aa  ' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { '#aa', '#\\taa', '#aa\\t', '#\\taa\\t' })\n  validate({ ' aa', '  aa' }, { ' #aa', ' # aa' })\n  validate({ '  aa', '', '  ', '\\t' }, { '  #aa', '  #', '  #', '  #' }, { '  aa', '', '', '' })\n\n  child.bo.commentstring = '%s#'\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { 'aa#', '  aa#', 'aa  #', '  aa  #' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { 'aa#', '\\taa#', 'aa\\t#', '\\taa\\t#' })\n  validate({ ' aa', '  aa' }, { ' aa#', '  aa#' })\n  validate({ '  aa', '', '  ', '\\t' }, { '  aa#', '  #', '  #', '  #' }, { '  aa', '', '', '' })\n\n  -- Whitespace inside comment parts\n  child.bo.commentstring = '#  %s  #'\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { '#  aa  #', '#    aa  #', '#  aa    #', '#    aa    #' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { '#  aa  #', '#  \\taa  #', '#  aa\\t  #', '#  \\taa\\t  #' })\n  validate({ ' aa', '  aa' }, { ' #  aa  #', ' #   aa  #' })\n  validate({ '  aa', '', '  ', '\\t' }, { '  #  aa  #', '  ##', '  ##', '  ##' }, { '  aa', '', '', '' })\n\n  child.bo.commentstring = '#  %s'\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { '#  aa', '#    aa', '#  aa  ', '#    aa  ' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { '#  aa', '#  \\taa', '#  aa\\t', '#  \\taa\\t' })\n  validate({ ' aa', '  aa' }, { ' #  aa', ' #   aa' })\n  validate({ '  aa', '', '  ', '\\t' }, { '  #  aa', '  #', '  #', '  #' }, { '  aa', '', '', '' })\n\n  child.bo.commentstring = '%s  #'\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { 'aa  #', '  aa  #', 'aa    #', '  aa    #' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { 'aa  #', '\\taa  #', 'aa\\t  #', '\\taa\\t  #' })\n  validate({ ' aa', '  aa' }, { ' aa  #', '  aa  #' })\n  validate({ '  aa', '', '  ', '\\t' }, { '  aa  #', '  #', '  #', '  #' }, { '  aa', '', '', '' })\n\n  -- Whitespace outside of comment parts\n  child.bo.commentstring = ' # %s # '\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { ' # aa # ', ' #   aa # ', ' # aa   # ', ' #   aa   # ' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { ' # aa # ', ' # \\taa # ', ' # aa\\t # ', ' # \\taa\\t # ' })\n  validate({ ' aa', '  aa' }, { '  # aa # ', '  #  aa # ' })\n  validate({ '  aa', '', '  ', '\\t' }, { '   # aa # ', '  ##', '  ##', '  ##' }, { '  aa', '', '', '' })\n\n  child.bo.commentstring = ' # %s '\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { ' # aa ', ' #   aa ', ' # aa   ', ' #   aa   ' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { ' # aa ', ' # \\taa ', ' # aa\\t ', ' # \\taa\\t ' })\n  validate({ ' aa', '  aa' }, { '  # aa ', '  #  aa ' })\n  validate({ '  aa', '', '  ', '\\t' }, { '   # aa ', '  #', '  #', '  #' }, { '  aa', '', '', '' })\n\n  child.bo.commentstring = ' %s # '\n  validate({ 'aa', '  aa', 'aa  ', '  aa  ' }, { ' aa # ', '   aa # ', ' aa   # ', '   aa   # ' })\n  validate({ 'aa', '\\taa', 'aa\\t', '\\taa\\t' }, { ' aa # ', ' \\taa # ', ' aa\\t # ', ' \\taa\\t # ' })\n  validate({ ' aa', '  aa' }, { '  aa # ', '   aa # ' })\n  validate({ '  aa', '', '  ', '\\t' }, { '   aa # ', '  #', '  #', '  #' }, { '  aa', '', '', '' })\nend\n\nT['toggle_lines()']['uncomments on inconsistent indent levels'] = function()\n  set_lines({ '# aa', ' # aa', '  # aa' })\n  toggle_lines(1, 3)\n  eq(get_lines(), { 'aa', ' aa', '  aa' })\nend\n\nT['toggle_lines()']['respects tabs (#20)'] = function()\n  child.bo.expandtab = false\n  set_lines({ '\\t\\taa', '\\t\\taa' })\n\n  toggle_lines(1, 2)\n  eq(get_lines(), { '\\t\\t# aa', '\\t\\t# aa' })\n\n  toggle_lines(1, 2)\n  eq(get_lines(), { '\\t\\taa', '\\t\\taa' })\nend\n\nT['toggle_lines()']['adds spaces inside non-empty lines'] = function()\n  -- Two-sided\n  set_lines(example_lines)\n  child.bo.commentstring = '/*%s*/'\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  /* aa */', '  /**/', '  /* aa */' })\n\n  -- Right-sided\n  set_lines(example_lines)\n  child.bo.commentstring = '%s#'\n  toggle_lines(3, 5)\n  eq(get_lines(2, 5), { '  aa #', '  #', '  aa #' })\nend\n\nT['toggle_lines()']['works with trailing whitespace'] = function()\n  -- Without right-hand side\n  child.bo.commentstring = '# %s'\n  set_lines({ ' aa', ' aa  ', '  ' })\n  toggle_lines(1, 3)\n  eq(get_lines(), { ' # aa', ' # aa  ', ' #' })\n  toggle_lines(1, 3)\n  eq(get_lines(), { ' aa', ' aa  ', '' })\n\n  -- With right-hand side\n  child.bo.commentstring = '%s #'\n  set_lines({ ' aa', ' aa  ', '  ' })\n  toggle_lines(1, 3)\n  eq(get_lines(), { ' aa #', ' aa   #', ' #' })\n  toggle_lines(1, 3)\n  eq(get_lines(), { ' aa', ' aa  ', '' })\n\n  -- Trailing whitespace after right side should be preserved for non-blanks\n  child.bo.commentstring = '%s #'\n  set_lines({ ' aa #  ', ' aa #\\t', ' #  ', ' #\\t' })\n  toggle_lines(1, 4)\n  eq(get_lines(), { ' aa  ', ' aa\\t', '', '' })\nend\n\nT['toggle_lines()']['applies hooks'] = function()\n  reload_with_hooks()\n  eq(child.bo.commentstring, '# %s')\n\n  set_lines({ 'aa', 'aa' })\n  toggle_lines(1, 2)\n  -- It should allow change of `commentstring` in `pre` hook\n  eq(get_lines(), { '// aa', '// aa' })\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'pre',  { { line_start = 1, line_end = 2, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post', { { line_start = 1, line_end = 2, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\n\n  -- Should correctly identify `action`\n  child.lua('_G.hook_args = {}')\n  set_lines({ '// aa', '// aa' })\n  child.bo.commentstring = '# %s'\n  toggle_lines(1, 1)\n  eq(get_lines(), { 'aa', '// aa' })\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'pre',  { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post', { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'uncomment' } } },\n  })\nend\n\nT['toggle_lines()']['stops when hook returns `false`'] = function()\n  local lines = { 'aa', 'aa' }\n  set_lines(lines)\n\n  child.lua('MiniComment.config.hooks.pre = function() return false end')\n  toggle_lines(1, 2)\n  eq(get_lines(), lines)\n\n  -- Currently can't really check for `hooks.post`\nend\n\nT['toggle_lines()']['respects `vim.b.minicomment_config`'] = function()\n  child.lua('vim.b.minicomment_config = { options = { start_of_line = true } }')\n  set_lines({ '  # aa', '  # aa' })\n\n  toggle_lines(1, 2)\n  eq(get_lines(), { '#   # aa', '#   # aa' })\nend\n\nT['get_commentstring()'] = new_set()\n\nlocal get_commentstring = function(...) return child.lua_get('MiniComment.get_commentstring(...)', { ... }) end\n\nT['get_commentstring()']['works'] = function()\n  -- Uses buffer's 'commentstring'\n  child.bo.commentstring = '# %s'\n\n  eq(get_commentstring(), '# %s')\n\n  local lines = {\n    'lua << EOF',\n    '  print(1)',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  eq(get_commentstring({ 1, 1 }), '\"%s')\n  eq(get_commentstring({ 2, 3 }), '-- %s')\n  eq(get_commentstring({ 3, 1 }), '\"%s')\nend\n\n-- Integration tests ==========================================================\nT['Operator'] = new_set()\n\nT['Operator']['works in Normal mode'] = function()\n  set_cursor(2, 2)\n  type_keys('gc', 'ap')\n  eq(get_lines(), { '# aa', '#  aa', '#   aa', '#', '  aa', ' aa', 'aa' })\n  -- Cursor moves to start line\n  eq(get_cursor(), { 1, 0 })\n\n  -- Supports `v:count`\n  set_lines(example_lines)\n  set_cursor(2, 0)\n  type_keys('2gc', 'ap')\n  eq(get_lines(), { '# aa', '#  aa', '#   aa', '#', '#   aa', '#  aa', '# aa' })\nend\n\nT['Operator']['allows dot-repeat in Normal mode'] = function()\n  local doubly_commented = { '# # aa', '# #  aa', '# #   aa', '# #', '#   aa', '#  aa', '# aa' }\n\n  set_lines(example_lines)\n  set_cursor(2, 2)\n  type_keys('gc', 'ap')\n  type_keys('.')\n  eq(get_lines(), doubly_commented)\n\n  -- Not immediate dot-repeat\n  set_lines(example_lines)\n  set_cursor(2, 2)\n  type_keys('gc', 'ap')\n  set_cursor(7, 0)\n  type_keys('.')\n  eq(get_lines(), doubly_commented)\nend\n\nT['Operator']['works in Visual mode'] = function()\n  set_cursor(2, 2)\n  type_keys('v', 'ap', 'gc')\n  eq(get_lines(), { '# aa', '#  aa', '#   aa', '#', '  aa', ' aa', 'aa' })\n\n  -- Cursor moves to start line\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Operator']['allows dot-repeat after initial Visual mode'] = function()\n  -- local example_lines = { 'aa', ' aa', '  aa', '', '  aa', ' aa', 'aa' }\n\n  set_lines(example_lines)\n  set_cursor(2, 2)\n  type_keys('vip', 'gc')\n  eq(get_lines(), { '# aa', '#  aa', '#   aa', '', '  aa', ' aa', 'aa' })\n  eq(get_cursor(), { 1, 0 })\n\n  -- Dot-repeat after first application in Visual mode should apply to the same\n  -- relative region\n  type_keys('.')\n  eq(get_lines(), example_lines)\n\n  set_cursor(3, 0)\n  type_keys('.')\n  eq(get_lines(), { 'aa', ' aa', '  # aa', '  #', '  # aa', ' aa', 'aa' })\nend\n\nT['Operator']['works with different mapping'] = function()\n  reload_module({ mappings = { comment = 'gC', comment_visual = 'C' } })\n\n  -- Normal mode\n  set_cursor(2, 2)\n  type_keys('gC', 'ap')\n  eq(get_lines(), { '# aa', '#  aa', '#   aa', '#', '  aa', ' aa', 'aa' })\n\n  -- Visual mode\n  set_lines(example_lines)\n  set_cursor(2, 2)\n  type_keys('v', 'ap', 'C')\n  eq(get_lines(), { '# aa', '#  aa', '#   aa', '#', '  aa', ' aa', 'aa' })\nend\n\nT['Operator'][\"respects 'commentstring'\"] = function()\n  child.bo.commentstring = '/*%s*/'\n  set_cursor(2, 2)\n  type_keys('gc', 'ap')\n  eq(get_lines(), { '/* aa */', '/*  aa */', '/*   aa */', '/**/', '  aa', ' aa', 'aa' })\nend\n\nT['Operator'][\"works with empty 'commentstring'\"] = function()\n  child.bo.commentstring = ''\n  set_cursor(2, 2)\n  type_keys('gc', 'ap')\n  eq(get_lines(), example_lines)\n  eq(child.cmd_capture('1messages'), [[(mini.comment) Option 'commentstring' is empty.]])\nend\n\nT['Operator']['respects tree-sitter injections'] = function()\n  -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers\n  local lines = {\n    'set background=dark',\n    'lua << EOF',\n    'print(1)',\n    'vim.api.nvim_exec2([[',\n    '    set background=light',\n    ']])',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  -- Single line comments\n  local validate = function(line, ref_output)\n    set_cursor(line, 0)\n    type_keys('gc_')\n    eq(get_lines()[line], ref_output)\n    -- Cleanup\n    set_lines(lines)\n  end\n\n  validate(1, '\" set background=dark')\n  validate(2, '\" lua << EOF')\n  validate(3, '-- print(1)')\n  validate(4, '-- vim.api.nvim_exec2([[')\n  validate(5, '    \" set background=light')\n  validate(6, '-- ]])')\n  validate(7, '\" EOF')\n\n  -- Has proper dot-repeat which recomputes 'commentstring'\n  set_lines(lines)\n\n  set_cursor(1, 0)\n  type_keys('gc_')\n  eq(get_lines()[1], '\" set background=dark')\n\n  set_cursor(3, 0)\n  type_keys('.')\n  eq(get_lines()[3], '-- print(1)')\n\n  -- Multiline comments should be computed based on cursor position\n  -- which in case of Visual selection means its left part\n  set_lines(lines)\n  set_cursor(1, 0)\n  type_keys('v2j', 'gc')\n  local out_lines = get_lines()\n  eq(out_lines[1], '\" set background=dark')\n  eq(out_lines[2], '\" lua << EOF')\n  eq(out_lines[3], '\" print(1)')\nend\n\nT['Operator']['respects `options.custom_commentstring`'] = function()\n  local lines = { 'aa', '  aa' }\n\n  -- Works correctly and called with proper arguments\n  child.lua([[MiniComment.config.options.custom_commentstring = function(...)\n    _G.args = { ... }\n    return '++ %s'\n  end]])\n\n  set_lines(lines)\n  set_cursor(2, 2)\n  type_keys('gc', '_')\n  eq(get_lines(), { 'aa', '  ++ aa' })\n  eq(child.lua_get('_G.args'), { { 2, 3 } })\nend\n\nT['Operator']['does not break with loaded tree-sitter'] = function()\n  set_lines({ 'set background=dark' })\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  type_keys('gcip')\n  eq(get_lines(), { '\" set background=dark' })\nend\n\nT['Operator']['preserves marks'] = function()\n  set_cursor(2, 0)\n  -- Set '`<' and '`>' marks\n  type_keys('VV')\n  type_keys('gc', 'ip')\n  child.expect_visual_marks(2, 2)\nend\n\nT['Operator']['respects `vim.{g,b}.minicomment_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicomment_disable = true\n    set_cursor(2, 2)\n    local lines = get_lines()\n    type_keys('gc', 'j')\n    eq(get_lines(), lines)\n  end,\n})\n\nT['Operator']['applies hooks'] = function()\n  reload_with_hooks()\n  eq(child.bo.commentstring, '# %s')\n\n  set_lines({ 'aa', 'aa' })\n  set_cursor(1, 0)\n  type_keys('gc', 'ip')\n  -- It should allow change of `commentstring` in `pre` hook\n  eq(get_lines(), { '// aa', '// aa' })\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'pre',  { { line_start = 1, line_end = 2, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post', { { line_start = 1, line_end = 2, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\n\n  -- It should work with dot-repeat\n  child.lua('_G.hook_args = {}')\n  set_lines({ '// aa', '// aa', '// aa' })\n  set_cursor(1, 0)\n  type_keys('.')\n  eq(get_lines(), { '# // aa', '# // aa', '# // aa' })\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'pre',  { { line_start = 1, line_end = 3, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post', { { line_start = 1, line_end = 3, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\nend\n\nT['Operator']['stops when hook returns `false`'] = function()\n  local lines = { 'aa', 'aa' }\n  set_lines(lines)\n  set_cursor(1, 0)\n\n  child.lua('MiniComment.config.hooks.pre = function() return false end')\n  type_keys('gc', 'ip')\n  eq(get_lines(), lines)\n\n  -- Currently can't really check for `hooks.post`\nend\n\nT['Operator']['respects `vim.b.minicomment_config`'] = function()\n  set_lines({ 'aa', 'aa' })\n  set_cursor(1, 0)\n  reload_with_hooks()\n  child.lua('vim.b.minicomment_config = { hooks = { pre = function() _G.pre_n = _G.pre_n + 10 end } }')\n\n  child.lua([[vim.b.minicomment_config = {\n    hooks = {\n      pre = function(...) table.insert(_G.hook_args, { 'buf_pre', vim.deepcopy({ ... }) }) end,\n    },\n  }]])\n\n  type_keys('gc', 'ip')\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'buf_pre', { { line_start = 1, line_end = 2, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post',    { { line_start = 1, line_end = 2, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\nend\n\nT['Current line'] = new_set()\n\nT['Current line']['works'] = function()\n  set_lines(example_lines)\n  set_cursor(1, 1)\n  type_keys('gcc')\n  eq(get_lines(0, 2), { '# aa', ' aa' })\n\n  -- Does not comment empty line\n  set_lines(example_lines)\n  set_cursor(4, 0)\n  type_keys('gcc')\n  eq(get_lines(2, 5), { '  aa', '', '  aa' })\n\n  -- Supports `v:count`\n  set_lines(example_lines)\n  set_cursor(2, 0)\n  type_keys('2gcc')\n  eq(get_lines(0, 3), { 'aa', ' # aa', ' #  aa' })\nend\n\nT['Current line']['works with different mapping'] = function()\n  reload_module({ mappings = { comment_line = 'gCC' } })\n\n  set_cursor(1, 0)\n  type_keys('gCC')\n  eq(get_lines(0, 1), { '# aa' })\nend\n\nT['Current line']['respects tree-sitter injections'] = function()\n  -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers\n  local lines = {\n    'set background=dark',\n    'lua << EOF',\n    'print(1)',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  set_cursor(1, 0)\n  type_keys('gcc')\n  eq(get_lines(), { '\" set background=dark', 'lua << EOF', 'print(1)', 'EOF' })\n\n  -- Should work with dot-repeat\n  set_cursor(3, 0)\n  type_keys('.')\n  eq(get_lines(), { '\" set background=dark', 'lua << EOF', '-- print(1)', 'EOF' })\nend\n\nT['Current line'][\"computes local 'commentstring' based on cursor position\"] = function()\n  local lines = {\n    'lua << EOF',\n    '  print(1)',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  set_cursor(1, 0)\n  type_keys('gcc')\n  eq(get_lines()[1], '\" lua << EOF')\n\n  set_lines(lines)\n  set_cursor(2, 2)\n  type_keys('gcc')\n  eq(get_lines()[2], '  -- print(1)')\nend\n\nT['Current line']['allows dot-repeat'] = function()\n  set_lines(example_lines)\n  set_cursor(1, 1)\n  type_keys('gcc')\n  type_keys('.')\n  eq(get_lines(), example_lines)\n\n  -- Not immediate dot-repeat\n  set_lines(example_lines)\n  set_cursor(1, 1)\n  type_keys('gcc')\n  set_cursor(7, 0)\n  type_keys('.')\n  eq(get_lines(6, 7), { '# aa' })\nend\n\nT['Current line']['applies hooks'] = function()\n  reload_with_hooks()\n  eq(child.bo.commentstring, '# %s')\n\n  set_lines({ 'aa', 'aa' })\n  set_cursor(1, 0)\n  type_keys('gcc')\n  -- It should allow change of `commentstring` in `pre` hook\n  eq(get_lines(), { '// aa', 'aa' })\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'pre',  { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post', { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\n\n  -- It should work with dot-repeat\n  child.lua('_G.hook_args = {}')\n  set_lines({ '// aa', 'aa' })\n  set_cursor(1, 0)\n  type_keys('.')\n  eq(get_lines(), { '# // aa', 'aa' })\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'pre',  { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post', { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\nend\n\nT['Current line']['respects `vim.b.minicomment_config`'] = function()\n  set_lines({ 'aa', 'aa' })\n  set_cursor(1, 0)\n  reload_with_hooks()\n  child.lua([[vim.b.minicomment_config = {\n    hooks = {\n      pre = function(...) table.insert(_G.hook_args, { 'buf_pre', vim.deepcopy({ ... }) }) end,\n    },\n  }]])\n\n  type_keys('gcc')\n  --stylua: ignore\n  eq(child.lua_get('_G.hook_args'), {\n    { 'buf_pre', { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'toggle' } } },\n    { 'post',    { { line_start = 1, line_end = 1, ref_position = { 1, 1 }, action = 'comment' } } },\n  })\nend\n\nT['Textobject'] = new_set()\n\nT['Textobject']['works'] = function()\n  set_lines({ 'aa', '# aa', '# aa', 'aa' })\n  set_cursor(2, 0)\n  type_keys('d', 'gc')\n  eq(get_lines(), { 'aa', 'aa' })\nend\n\nT['Textobject']['does nothing when not inside textobject'] = function()\n  -- Builtin operators\n  type_keys('d', 'gc')\n  eq(get_lines(), example_lines)\n\n  -- Comment operator\n  -- Main problem here at time of writing happened while calling `gc` on\n  -- comment textobject when not on comment line. This sets `]` mark right to\n  -- the left of `[` (but not when cursor in (1, 0)).\n  local validate_no_action = function(line, col)\n    set_lines(example_lines)\n    set_cursor(line, col)\n    type_keys('gc', 'gc')\n    eq(get_lines(), example_lines)\n  end\n\n  validate_no_action(1, 1)\n  validate_no_action(2, 2)\n\n  -- Doesn't work (but should) because both `[` and `]` are set to (1, 0)\n  -- (instead of more reasonable (1, -1) or (0, 2147483647)).\n  -- validate_no_action(1, 0)\nend\n\nT['Textobject']['works with different mapping'] = function()\n  reload_module({ mappings = { textobject = 'gC' } })\n\n  set_lines({ 'aa', '# aa', '# aa', 'aa' })\n  set_cursor(2, 0)\n  type_keys('d', 'gC')\n  eq(get_lines(), { 'aa', 'aa' })\n\n  -- Should work in Visual mode as it differs from `comment_visual` mapping\n  set_lines({ 'aa', '# bb', '# cc', '# dd', 'ee' })\n  set_cursor(3, 0)\n  type_keys('v', 'gC', 'd')\n  eq(get_lines(), { 'aa', 'ee' })\nend\n\nT['Textobject']['respects tree-sitter injections'] = function()\n  -- NOTE: This leverages bundled Vimscript and Lua tree-sitter parsers\n  local lines = {\n    '\" set background=dark',\n    '\" set termguicolors',\n    'lua << EOF',\n    '-- print(1)',\n    '-- print(2)',\n    'EOF',\n  }\n  set_lines(lines)\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n\n  set_cursor(1, 0)\n  type_keys('dgc')\n  eq(get_lines(), { 'lua << EOF', '-- print(1)', '-- print(2)', 'EOF' })\n\n  -- Should work with dot-repeat\n  set_cursor(2, 0)\n  type_keys('.')\n  eq(get_lines(), { 'lua << EOF', 'EOF' })\nend\n\nT['Textobject']['allows dot-repeat'] = function()\n  set_lines({ 'aa', '# aa', '# aa', 'aa', '# aa' })\n  set_cursor(2, 0)\n  type_keys('d', 'gc')\n  set_cursor(3, 0)\n  type_keys('.')\n  eq(get_lines(), { 'aa', 'aa' })\nend\n\nT['Textobject']['respects `config.options.start_of_line`'] = function()\n  child.lua('MiniComment.config.options.start_of_line = true')\n\n  local lines = { ' # aa', '  # aa', '# aa', '#  aa' }\n  set_lines(lines)\n\n  set_cursor(1, 0)\n  type_keys('d', 'gc')\n  eq(get_lines(), lines)\n\n  set_cursor(3, 0)\n  type_keys('d', 'gc')\n  eq(get_lines(), { ' # aa', '  # aa' })\nend\n\nT['Textobject']['respects `config.options.ignore_blank_line`'] = function()\n  child.lua('MiniComment.config.options.ignore_blank_line = true')\n\n  local validate = function(lines_before, cursor_line, lines_after)\n    set_lines(lines_before)\n    set_cursor(cursor_line, 0)\n    type_keys('d', 'gc')\n    eq(get_lines(), lines_after)\n  end\n\n  local lines = { 'aa', '# bb', '', ' ', '# dd', '# ee', '\\t', '# gg', 'hh' }\n  local lines_without_comment = { 'aa', 'hh' }\n  validate(lines, 1, lines)\n  validate(lines, 2, lines_without_comment)\n  validate(lines, 3, lines_without_comment)\n  validate(lines, 4, lines_without_comment)\n  validate(lines, 5, lines_without_comment)\n  validate(lines, 6, lines_without_comment)\n  validate(lines, 7, lines_without_comment)\n  validate(lines, 8, lines_without_comment)\n  validate(lines, 9, lines)\n\n  lines = { '# aa', '', ' ', 'dd', '', '\\t', '# gg' }\n  validate(lines, 1, { '', ' ', 'dd', '', '\\t', '# gg' })\n  validate(lines, 2, lines)\n  validate(lines, 3, lines)\n  validate(lines, 4, lines)\n  validate(lines, 5, lines)\n  validate(lines, 6, lines)\n  validate(lines, 7, { '# aa', '', ' ', 'dd', '', '\\t' })\n\n  lines = { '# aa', '', ' ', '\\t', '# ee' }\n  lines_without_comment = { '' }\n  validate(lines, 1, lines_without_comment)\n  validate(lines, 2, lines_without_comment)\n  validate(lines, 3, lines_without_comment)\n  validate(lines, 4, lines_without_comment)\n  validate(lines, 5, lines_without_comment)\n\n  -- Should not recognize blank lines before/after as textobject\n  lines = { 'aa', '', ' ', '# dd', '', ' ', '# gg', '', '\\t', 'jj' }\n  lines_without_comment = { 'aa', '', ' ', '', '\\t', 'jj' }\n  validate(lines, 2, lines)\n  validate(lines, 3, lines)\n  validate(lines, 4, lines_without_comment)\n  validate(lines, 5, lines_without_comment)\n  validate(lines, 6, lines_without_comment)\n  validate(lines, 7, lines_without_comment)\n  validate(lines, 8, lines)\n  validate(lines, 9, lines)\n\n  lines = { '', ' ', '# dd', '', '\\t' }\n  lines_without_comment = { '', ' ', '', '\\t' }\n  validate(lines, 1, lines)\n  validate(lines, 2, lines)\n  validate(lines, 3, lines_without_comment)\n  validate(lines, 4, lines)\n  validate(lines, 5, lines)\n\n  -- Should work in buffer with only blank lines\n  reload_with_hooks()\n  child.lua('MiniComment.config.options.ignore_blank_line = true')\n  lines = { '', ' ', '\\t', '' }\n  validate(lines, 2, lines)\n  eq(\n    child.lua_get('_G.hook_args'),\n    { { 'pre', { { action = 'textobject' } } }, { 'post', { { action = 'textobject' } } } }\n  )\nend\n\nT['Textobject']['respects `vim.{g,b}.minicomment_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicomment_disable = true\n    local lines = { 'aa', '# aa', '# aa', 'aa' }\n    set_lines(lines)\n    set_cursor(2, 0)\n    type_keys('d', 'gc')\n    eq(get_lines(), lines)\n  end,\n})\n\nT['Textobject']['applies hooks'] = function()\n  -- It should allow change of `commentstring` in `pre` hook\n  reload_with_hooks()\n  eq(child.bo.commentstring, '# %s')\n\n  local validate = function(lines_before, keys, lines_after, ref_hook_args)\n    child.lua('_G.hook_args = {}')\n    set_lines(lines_before)\n    set_cursor(1, 0)\n    type_keys(keys)\n    eq(get_lines(), lines_after)\n    eq(child.lua_get('_G.hook_args'), ref_hook_args)\n  end\n\n  local ref_args = {\n    { 'pre', { { action = 'textobject' } } },\n    { 'post', { { line_start = 1, line_end = 1, action = 'textobject' } } },\n  }\n  validate({ '// aa', 'bb' }, { 'd', 'gc' }, { 'bb' }, ref_args)\n\n  -- It should work with dot-repeat\n  validate({ '# aa', 'bb' }, { '.' }, { 'bb' }, ref_args)\n\n  -- Correctly not detecting absence of comment textobject should still be\n  -- considered a successful usage of a textobject\n  ref_args = { { 'pre', { { action = 'textobject' } } }, { 'post', { { action = 'textobject' } } } }\n  validate({ 'aa', 'bb' }, { 'd', 'gc' }, { 'aa', 'bb' }, ref_args)\nend\n\nT['Textobject']['respects `vim.b.minicomment_config`'] = function()\n  reload_with_hooks()\n  child.lua([[vim.b.minicomment_config = {\n    hooks = {\n      pre = function(...) table.insert(_G.hook_args, { 'buf_pre', vim.deepcopy({ ... }) }) end,\n    },\n  }]])\n\n  set_lines({ '// aa', 'aa' })\n  set_cursor(1, 0)\n  type_keys('d', 'gc')\n  eq(\n    child.lua_get('_G.hook_args'),\n    { { 'buf_pre', { { action = 'textobject' } } }, { 'post', { { action = 'textobject' } } } }\n  )\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_completion.lua",
    "content": "-- NOTE: These are basic tests which cover basic functionliaty. A lot of\n-- nuances are not tested to meet \"complexity-necessity\" trade-off.\nlocal helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal eq_partial_tbl = helpers.expect.equality_partial_tbl\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('completion', config) end\nlocal unload_module = function() child.mini_unload('completion') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\nlocal mock_lsp = function() child.cmd('luafile tests/mock-lsp/months.lua') end\nlocal new_buffer = function() child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false)) end\n--stylua: ignore end\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal mock_miniicons = function()\n  child.lua([[\n    require('mini.icons').setup()\n    local _, hl_text = MiniIcons.get('lsp', 'Text')\n    local _, hl_function = MiniIcons.get('lsp', 'Function')\n    _G.ref_hlgroup = { text = hl_text, func = hl_function}\n  ]])\nend\n\nlocal mock_completefunc_lsp_tracking = function()\n  child.lua([[\n    local completefunc_lsp_orig = MiniCompletion.completefunc_lsp\n    MiniCompletion.completefunc_lsp = function(...)\n      _G.n_completfunc_lsp = (_G.n_completfunc_lsp or 0) + 1\n      return completefunc_lsp_orig(...)\n    end\n  ]])\nend\n\nlocal mock_lsp_items = function(items, client_id)\n  child.lua('_G.input_items = ' .. vim.inspect(items))\n  child.lua('_G.client_id = ' .. (client_id or 1))\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(_, base)\n      local items = vim.deepcopy(_G.input_items)\n      -- Ensure same order\n      for i, _ in ipairs(items) do\n        items[i].sortText = string.format('%03d', i)\n        items[i].client_id = _G.client_id\n      end\n      return MiniCompletion.default_process_items(items, base)\n    end\n  ]])\nend\n\nlocal mock_event_log = function()\n  child.lua([[\n    _G.log = {}\n    local events = { 'MiniCompletionWindowOpen', 'MiniCompletionWindowUpdate' }\n    local log_event = function(ev)\n      table.insert(_G.log, { event = ev.match, data = ev.data })\n    end\n    vim.api.nvim_create_autocmd('User', { pattern = events, callback = log_event })\n  ]])\nend\n\nlocal mock_custom_window_config = function()\n  child.lua([[\n    vim.api.nvim_create_autocmd('User', {\n      pattern = { 'MiniCompletionWindowOpen', 'MiniCompletionWindowUpdate' },\n      callback = function(ev)\n        local config = vim.api.nvim_win_get_config(ev.data.win_id)\n        config.title, config.title_pos = 'Custom', 'right'\n        vim.api.nvim_win_set_config(ev.data.win_id, config)\n      end,\n    })\n  ]])\nend\n\n-- NOTE: this can't show \"what filtered text is actually shown in window\".\n-- Seems to be because information for `complete_info()`\n--- is updated in the very last minute (probably, by UI). This means that the\n--- idea of \"Type <C-n> -> get selected item\" loop doesn't work (because\n--- \"selected item\" is not updated). Can't find a way to force its update.\n---\n--- Using screen tests to get information about actually shown filtered items.\n---\n--- More info: https://github.com/vim/vim/issues/10007\nlocal get_completion = function(what)\n  what = what or 'word'\n  return vim.tbl_map(function(x) return x[what] end, child.fn.complete_info().items)\nend\n\nlocal get_floating_windows = function()\n  return vim.tbl_filter(\n    function(x) return child.api.nvim_win_get_config(x).relative ~= '' end,\n    child.api.nvim_list_wins()\n  )\nend\n\nlocal validate_single_floating_win = function(opts)\n  opts = opts or {}\n  local wins = get_floating_windows()\n  eq(#wins, 1)\n\n  local win_id = wins[1]\n  if opts.lines ~= nil then\n    local buf_id = child.api.nvim_win_get_buf(win_id)\n    local lines = child.api.nvim_buf_get_lines(buf_id, 0, -1, true)\n    eq(lines, opts.lines)\n  end\n  if opts.config ~= nil then\n    local true_config = child.api.nvim_win_get_config(win_id)\n    local compare_config = {}\n    for key, _ in pairs(opts.config) do\n      compare_config[key] = true_config[key]\n    end\n    eq(compare_config, opts.config)\n  end\nend\n\n-- Time constants\nlocal default_completion_delay, default_info_delay, default_signature_delay = 100, 100, 50\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniCompletion)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniCompletion'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniCompletionActiveParameter'), 'links to LspSignatureActiveParameter')\n  expect.match(child.cmd_capture('hi MiniCompletionDeprecated'), 'links to DiagnosticDeprecated')\n  expect.match(child.cmd_capture('hi MiniCompletionInfoBorderOutdated'), 'links to DiagnosticFloatingWarn')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniCompletion.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniCompletion.config.' .. field), value) end\n\n  expect_config('delay.completion', 100)\n  expect_config('delay.info', 100)\n  expect_config('delay.signature', 50)\n  expect_config('window.info.height', 25)\n  expect_config('window.info.width', 80)\n  expect_config('window.info.border', vim.NIL)\n  expect_config('window.signature.height', 25)\n  expect_config('window.signature.width', 80)\n  expect_config('window.signature.border', vim.NIL)\n  expect_config('lsp_completion.source_func', 'completefunc')\n  expect_config('lsp_completion.auto_setup', true)\n  expect_config('lsp_completion.process_items', vim.NIL)\n  expect_config('lsp_completion.snippet_insert', vim.NIL)\n  expect_config('fallback_action', '<C-n>')\n  expect_config('mappings.force_twostep', '<C-Space>')\n  expect_config('mappings.force_fallback', '<A-Space>')\n  expect_config('mappings.scroll_down', '<C-f>')\n  expect_config('mappings.scroll_up', '<C-b>')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  -- Check setting `MiniCompletion.config` fields\n  reload_module({ delay = { completion = 300 } })\n  eq(child.lua_get('MiniCompletion.config.delay.completion'), 300)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ delay = 'a' }, 'delay', 'table')\n  expect_config_error({ delay = { completion = 'a' } }, 'delay.completion', 'number')\n  expect_config_error({ delay = { info = 'a' } }, 'delay.info', 'number')\n  expect_config_error({ delay = { signature = 'a' } }, 'delay.signature', 'number')\n  expect_config_error({ window = 'a' }, 'window', 'table')\n  expect_config_error({ window = { info = 'a' } }, 'window.info', 'table')\n  expect_config_error({ window = { info = { height = 'a' } } }, 'window.info.height', 'number')\n  expect_config_error({ window = { info = { width = 'a' } } }, 'window.info.width', 'number')\n  expect_config_error({ window = { info = { border = 1 } } }, 'window.info.border', 'string or array')\n  expect_config_error({ window = { signature = 'a' } }, 'window.signature', 'table')\n  expect_config_error({ window = { signature = { height = 'a' } } }, 'window.signature.height', 'number')\n  expect_config_error({ window = { signature = { width = 'a' } } }, 'window.signature.width', 'number')\n  expect_config_error({ window = { signature = { border = 1 } } }, 'window.signature.border', 'string or array')\n  expect_config_error({ lsp_completion = 'a' }, 'lsp_completion', 'table')\n  expect_config_error(\n    { lsp_completion = { source_func = 'a' } },\n    'lsp_completion.source_func',\n    '\"completefunc\" or \"omnifunc\"'\n  )\n  expect_config_error({ lsp_completion = { auto_setup = 'a' } }, 'lsp_completion.auto_setup', 'boolean')\n  expect_config_error({ lsp_completion = { process_items = 'a' } }, 'lsp_completion.process_items', 'callable')\n  expect_config_error({ lsp_completion = { snippet_insert = 'a' } }, 'lsp_completion.snippet_insert', 'callable')\n  expect_config_error({ fallback_action = 1 }, 'fallback_action', 'function or string')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { force_twostep = 1 } }, 'mappings.force_twostep', 'string')\n  expect_config_error({ mappings = { force_fallback = 1 } }, 'mappings.force_fallback', 'string')\n  expect_config_error({ mappings = { scroll_down = 1 } }, 'mappings.scroll_down', 'string')\n  expect_config_error({ mappings = { scroll_up = 1 } }, 'mappings.scroll_up', 'string')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniCompletionActiveParameter'), 'links to LspSignatureActiveParameter')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('imap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('<C-Space>', 'Complete'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('i', '<C-Space>')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { force_twostep = '' } })\n  eq(has_map('<C-Space>', 'Complete'), false)\nend\n\nT['setup()']['uses `config.lsp_completion`'] = function()\n  local validate = function(auto_setup, source_func)\n    reload_module({ lsp_completion = { auto_setup = auto_setup, source_func = source_func } })\n    local buf_id = child.api.nvim_create_buf(true, false)\n    child.api.nvim_set_current_buf(buf_id)\n\n    local omnifunc, completefunc\n    if auto_setup == false then\n      omnifunc, completefunc = '', ''\n    else\n      local val = 'v:lua.MiniCompletion.completefunc_lsp'\n      omnifunc = source_func == 'omnifunc' and val or ''\n      completefunc = source_func == 'completefunc' and val or ''\n    end\n\n    eq(child.bo.omnifunc, omnifunc)\n    eq(child.bo.completefunc, completefunc)\n  end\n\n  validate(false)\n  validate(true, 'omnifunc')\n  validate(true, 'completefunc')\nend\n\nT['setup()']['sets recommended option values'] = function()\n  expect.match(child.o.shortmess, 'c')\n  expect.match(child.o.shortmess, 'C')\n  eq(child.o.completeopt, 'menuone,noselect')\n  eq(child.o.complete:find('t'), nil)\n\n  -- Should not set if was previously set\n  child.o.shortmess = 'ltToO'\n  child.o.completeopt = 'menu,noinsert'\n  child.o.complete = '.,w,b,u,t'\n  reload_module()\n  eq(child.o.shortmess, 'ltToO')\n  eq(child.o.completeopt, 'menu,noinsert')\n  eq(child.o.complete, '.,w,b,u,t')\nend\n\nT['default_process_items()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Mock LSP items\n      child.lua([[\n        _G.items = {\n          { kind = 1,   label = \"January\",  sortText = \"001\" },\n          { kind = 2,   label = \"May\",      sortText = \"005\" },\n          { kind = 2,   label = \"March\",    sortText = \"003\" },\n          { kind = 2,   label = \"April\",    sortText = \"004\" },\n          { kind = 1,   label = \"February\", sortText = \"002\" },\n          -- Unknown kind\n          { kind = 100, label = \"July\",     sortText = \"007\" },\n          { kind = 3,   label = \"June\",     sortText = \"006\" },\n        }\n      ]])\n    end,\n  },\n})\n\nlocal default_process_items = forward_lua('MiniCompletion.default_process_items')\n\nlocal ref_prefix_items = {\n  { kind = 2, label = 'March', sortText = '003' },\n  { kind = 2, label = 'May', sortText = '005' },\n}\n\nlocal ref_fuzzy_items = {\n  { kind = 100, label = 'July', sortText = '007' },\n  { kind = 2, label = 'April', sortText = '004' },\n}\n\nT['default_process_items()']['works'] = function()\n  -- Should use 'prefix' filtersort if no 'fuzzy' in 'completeopt'\n  eq(child.lua_get('MiniCompletion.default_process_items(_G.items, \"M\")'), ref_prefix_items)\n\n  -- Should use 'fuzzy' filtersort if there is 'fuzzy' in 'completeopt'\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"Only Neovim>=0.11 has 'fuzzy' flag in 'completeopt'\") end\n  child.o.completeopt = 'menuone,noselect,fuzzy'\n  eq(child.lua_get('MiniCompletion.default_process_items(_G.items, \"l\")'), ref_fuzzy_items)\nend\n\nT['default_process_items()']['highlights deprecated items'] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'abbr_hlgroup' field is present on Neovim>=0.11\") end\n\n  child.lua([[\n    _G.items[1].deprecated = true\n    _G.items[6].tags = { vim.lsp.protocol.CompletionTag.Deprecated }\n    -- Should not override already set `abbr_hlgroup`\n    _G.items[7].abbr_hlgroup = 'String'\n  ]])\n  local tags = child.lua_get('{ vim.lsp.protocol.CompletionTag.Deprecated }')\n\n  local ref_processed_items = {\n    { abbr_hlgroup = 'MiniCompletionDeprecated', deprecated = true, kind = 1, label = 'January', sortText = '001' },\n    { abbr_hlgroup = 'String', kind = 3, label = 'June', sortText = '006' },\n    { abbr_hlgroup = 'MiniCompletionDeprecated', tags = tags, kind = 100, label = 'July', sortText = '007' },\n  }\n  eq(child.lua_get('MiniCompletion.default_process_items(_G.items, \"J\")'), ref_processed_items)\n\n  -- Should not modify original items\n  eq(child.lua_get('_G.items[1].abbr_hlgroup'), vim.NIL)\nend\n\nT['default_process_items()'][\"highlights LSP kind if 'mini.icons' is enabled\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'kind_hlgroup' field is present on Neovim>=0.11\") end\n\n  mock_miniicons()\n  local ref_hlgroup = child.lua_get('_G.ref_hlgroup')\n  local ref_processed_items = {\n    { kind_hlgroup = ref_hlgroup.text, kind = 1, label = 'January', sortText = '001' },\n    { kind_hlgroup = ref_hlgroup.func, kind = 3, label = 'June', sortText = '006' },\n    -- Unknown kind should not get highlighted\n    { kind_hlgroup = nil, kind = 100, label = 'July', sortText = '007' },\n  }\n  eq(child.lua_get('MiniCompletion.default_process_items(_G.items, \"J\")'), ref_processed_items)\n\n  -- Should not modify original items\n  eq(child.lua_get('_G.items[1].kind_hlgroup'), vim.NIL)\n\n  -- Should not override already set `kind_hlgroup`\n  local out = child.lua([[\n    _G.items[5].kind_hlgroup = 'Comment'\n    return MiniCompletion.default_process_items(_G.items, 'F')\n  ]])\n  eq(out, { { kind_hlgroup = 'Comment', kind = 1, label = 'February', sortText = '002' } })\nend\n\nT['default_process_items()']['works after `MiniIcons.tweak_lsp_kind()`'] = function()\n  mock_miniicons()\n  child.lua('MiniIcons.tweak_lsp_kind()')\n\n  local ref_hlgroup = child.lua_get('_G.ref_hlgroup')\n  local ref_processed_items = {\n    { kind = 1, kind_hlgroup = ref_hlgroup.text, label = 'January', sortText = '001' },\n    { kind = 3, kind_hlgroup = ref_hlgroup.func, label = 'June', sortText = '006' },\n    -- Unknown kind should not get highlighted\n    { kind = 100, kind_hlgroup = nil, label = 'July', sortText = '007' },\n  }\n  eq(child.lua_get('MiniCompletion.default_process_items(_G.items, \"J\")'), ref_processed_items)\nend\n\nT['default_process_items()']['respects `opts.filtersort`'] = function()\n  local all_items = child.lua_get('_G.items')\n  local validate = function(method, base, ref)\n    child.lua('_G.method = ' .. vim.inspect(method))\n    child.lua('_G.base = ' .. vim.inspect(base))\n    local out = child.lua([[\n      local copy_items = vim.deepcopy(_G.items)\n      local processed = MiniCompletion.default_process_items(_G.items, _G.base, { filtersort = _G.method })\n      local res = vim.deepcopy(processed)\n      if processed[1] ~= nil then processed[1].new_field = 'hello' end\n      return { processed = res, returns_copy = _G.items[1].new_field == nil}\n    ]])\n    eq(out.processed, ref)\n    eq(out.returns_copy, true)\n  end\n\n  validate(nil, 'l', {})\n  validate('fuzzy', 'l', ref_fuzzy_items)\n  validate('none', 'l', all_items)\n\n  -- Should return all items with empty string base\n  local all_items_sorted = vim.deepcopy(all_items)\n  table.sort(all_items_sorted, function(a, b) return (a.sortText or a.label) < (b.sortText or b.label) end)\n\n  validate(nil, '', all_items_sorted)\n  validate('fuzzy', '', all_items)\n  validate('none', '', all_items)\n\n  -- Should allow callable `filtersort`\n  child.lua([[\n    _G.args = {}\n    local filtersort = function(...)\n      table.insert(_G.args, { ... })\n      return { { label = 'New item' } }\n    end\n    _G.processed = MiniCompletion.default_process_items(_G.items, \"l\", { filtersort = filtersort })\n  ]])\n  eq(child.lua_get('_G.processed'), { { label = 'New item' } })\n  eq(child.lua_get('_G.args'), { { all_items, 'l' } })\nend\n\nT['default_process_items()']['prefers match at start instead of camel case at end'] = function()\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip('Only Neovim>=0.12 has improved fuzzy matching support') end\n\n  local items = {\n    { kind = 1, label = 'MyClass' },\n    { kind = 1, label = 'Class' },\n    { kind = 1, label = 'MyOtherClass' },\n  }\n  child.lua('_G.items = ' .. vim.inspect(items))\n  local out = child.lua_get('MiniCompletion.default_process_items(_G.items, \"Cl\", { filtersort = \"fuzzy\" })')\n  eq(out, { items[2], items[1], items[3] })\nend\n\nT['default_process_items()']['respects `opts.kind_priority`'] = function()\n  local kind_map = child.lua([[\n    _G.kind_map = {}\n    for k, v in pairs(vim.lsp.protocol.CompletionItemKind) do\n      if type(k) == 'string' then _G.kind_map[k] = v end\n    end\n    return _G.kind_map\n  ]])\n\n  -- Should work even if `vim.lsp.protocol.CompletionItemKind` is tweaked\n  mock_miniicons()\n  child.lua('MiniIcons.tweak_lsp_kind()')\n\n  local items = {\n    { label = 'a', kind = kind_map.Function },\n    { label = 'b', kind = kind_map.Snippet },\n    { label = 'c', kind = kind_map.Text },\n    { label = 'd', kind = kind_map.Function },\n    { label = 'e', kind = kind_map.Variable },\n    { label = 'f', kind = kind_map.Text },\n    { label = 'g', kind = kind_map.Variable },\n    -- Should work with unknown/missing kind (with default priority of 100)\n    { label = 'h', kind = -13 },\n    { label = 'i', kind = 3.14 },\n    { label = 'j', kind = nil },\n  }\n  local opts = { kind_priority = { Variable = 101, Snippet = 99, Text = -1 } }\n  --stylua: ignore\n  local ref_items = {\n    items[5], items[7], -- priority 101\n    items[1], items[4], items[8], items[9], items[10], -- priority 100\n    items[2], -- priority 99\n    -- No items for negative priority\n  }\n  eq_partial_tbl(default_process_items(items, '', opts), ref_items)\n\n  -- Should apply after `filtersort` and preserve its order within priority\n  items = {\n    { label = 'ba', kind = kind_map.Snippet },\n    { label = 'ca', kind = kind_map.Variable },\n    { label = 'ea', kind = kind_map.Text },\n    { label = 'da', kind = kind_map.Function },\n\n    { label = 'ac', kind = kind_map.Variable },\n    { label = 'ab', kind = kind_map.Snippet },\n    { label = 'ad', kind = kind_map.Function },\n    { label = 'ae', kind = kind_map.Text },\n\n    { label = 'xx', kind = kind_map.Variable },\n\n    { label = 'cca', kind = kind_map.Variable },\n  }\n  opts = { filtersort = 'fuzzy', kind_priority = { Variable = 101, Snippet = 99, Text = -1 } }\n  --stylua: ignore\n  ref_items = {\n    items[5], items[2], items[10], -- priority 101\n    items[7], items[4],            -- priority 100\n    items[6], items[1],            -- priority 99\n  }\n  eq_partial_tbl(default_process_items(items, 'a', opts), ref_items)\nend\n\nT['default_process_items()']['validates input'] = function()\n  expect.error(\n    function() child.lua('MiniCompletion.default_process_items({}, \"\", { filtersort = 1 })') end,\n    '`filtersort`.*callable or one of'\n  )\n  expect.error(\n    function() child.lua('MiniCompletion.default_process_items({}, \"\", { kind_priority = 1 })') end,\n    '`kind_priority`.*table'\n  )\nend\n\nT['get_lsp_capabilities()'] = new_set()\n\nT['get_lsp_capabilities()']['works'] = function()\n  local validate_keys = function(x, ref_keys)\n    local keys = vim.tbl_keys(x)\n    table.sort(keys)\n    eq(keys, ref_keys)\n  end\n\n  local out = child.lua_get('MiniCompletion.get_lsp_capabilities()')\n  validate_keys(out, { 'textDocument' })\n  validate_keys(out.textDocument, { 'completion', 'signatureHelp' })\n  --stylua: ignore\n  local completion_keys = {\n    'completionItem', 'completionItemKind', 'completionList',\n    'contextSupport', 'dynamicRegistration', 'insertTextMode',\n  }\n  validate_keys(out.textDocument.completion, completion_keys)\n  validate_keys(out.textDocument.signatureHelp, { 'contextSupport', 'dynamicRegistration', 'signatureInformation' })\n\n  local ref_resolve_properties = { 'additionalTextEdits', 'detail', 'documentation' }\n  eq(out.textDocument.completion.completionItem.resolveSupport.properties, ref_resolve_properties)\nend\n\nT['get_lsp_capabilities()']['respects `opts.resolve_additional_text_edits`'] = function()\n  local validate = function(out, ref_resolve_properties)\n    eq(out.textDocument.completion.completionItem.resolveSupport.properties, ref_resolve_properties)\n  end\n  local out_false = child.lua_get('MiniCompletion.get_lsp_capabilities({ resolve_additional_text_edits = false })')\n  validate(out_false, { 'detail', 'documentation' })\n  local out_true = child.lua_get('MiniCompletion.get_lsp_capabilities({ resolve_additional_text_edits = true })')\n  validate(out_true, { 'additionalTextEdits', 'detail', 'documentation' })\nend\n\n-- Integration tests ==========================================================\nT['Autocompletion'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Create new buffer to set buffer-local `completefunc` or `omnifunc`\n      new_buffer()\n      -- For details see 'mock-lsp/months.lua'\n      mock_lsp()\n    end,\n  },\n})\n\nT['Autocompletion']['works with LSP client'] = function()\n  type_keys('i', 'J')\n  eq(get_completion(), {})\n\n  -- Shows completion only after delay\n  sleep(default_completion_delay - small_time)\n  eq(get_completion(), {})\n  sleep(small_time + small_time)\n  -- Both completion word and kind are shown\n  eq(get_completion(), { 'January', 'June', 'July' })\n  eq(get_completion('kind'), { 'Text', 'Function', 'Function' })\n\n  -- Completion menu is filtered after entering characters\n  type_keys('u')\n  child.set_size(10, 20)\n  child.expect_screenshot()\nend\n\nT['Autocompletion']['works without LSP clients'] = function()\n  child.lsp.buf_detach_client(0, child.lua_get('_G.months_lsp_client_id'))\n\n  type_keys('i', 'aab aac aba a')\n  eq(get_completion(), {})\n  sleep(default_completion_delay - small_time)\n  eq(get_completion(), {})\n  sleep(small_time + small_time)\n  eq(get_completion(), { 'aab', 'aac', 'aba' })\n\n  -- Completion menu is filtered after entering characters\n  type_keys('a')\n  child.set_size(10, 30)\n  child.expect_screenshot()\nend\n\nT['Autocompletion']['implements debounce-style delay'] = function()\n  type_keys('i', 'J')\n\n  sleep(default_completion_delay - small_time)\n  eq(get_completion(), {})\n  type_keys('u')\n  sleep(default_completion_delay - small_time)\n  eq(get_completion(), {})\n  sleep(small_time + small_time)\n  eq(get_completion(), { 'June', 'July' })\nend\n\nT['Autocompletion']['uses fallback'] = function()\n  set_lines({ 'Jackpot', '' })\n  set_cursor(2, 0)\n\n  type_keys('i', 'Ja')\n  sleep(default_completion_delay + small_time)\n  eq(get_completion(), { 'January' })\n\n  -- Due to how 'completefunc' and 'omnifunc' currently work, fallback won't\n  -- trigger after the first character which lead to empty completion list.\n  -- The reason seems to be that at that point Neovim's internal filtering of\n  -- completion items is still \"in charge\" (backspace leads to previous\n  -- completion item list without reevaluating completion function). It is\n  -- only after the next character completion function gets reevaluated\n  -- leading to zero items from LSP which triggers fallback action.\n  type_keys('c')\n  eq(child.fn.pumvisible(), 0)\n  type_keys('k')\n  eq(get_completion(), { 'Jackpot' })\nend\n\nT['Autocompletion']['forces new LSP completion at LSP trigger'] = new_set(\n  -- Test with different source functions because they (may) differ slightly on\n  -- how certain completion events (`CompleteDonePre`) are triggered, which\n  -- affects whether autocompletion is done in certain cases (for example, when\n  -- completion candidate is fully typed).\n  -- See https://github.com/nvim-mini/mini.nvim/issues/813\n  { parametrize = { { 'completefunc' }, { 'omnifunc' } } },\n  {\n    test = function(source_func)\n      reload_module({ lsp_completion = { source_func = source_func } })\n      mock_completefunc_lsp_tracking()\n      child.set_size(16, 30)\n      child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n      --stylua: ignore\n      local all_months = {\n        'January', 'February', 'March', 'April', 'May', 'June',\n        'July', 'August', 'September', 'October', 'November', 'December',\n      }\n      type_keys('i', '<C-Space>')\n      eq(get_completion(), all_months)\n      -- - Should only call two times, as per `:h complete-functions`, i.e. not\n      --   use it to actually make request (which would have made it 3 times).\n      eq(child.lua_get('_G.n_completfunc_lsp'), 2)\n\n      type_keys('May.')\n      eq(child.lua_get('_G.n_completfunc_lsp'), 2)\n      eq(child.fn.pumvisible(), 0)\n      sleep(default_completion_delay - small_time)\n      eq(child.fn.pumvisible(), 0)\n      sleep(small_time + small_time)\n      eq(get_completion(), all_months)\n      eq(child.lua_get('_G.n_completfunc_lsp'), 4)\n      child.expect_screenshot()\n\n      -- Should show only LSP without fallback, i.e. typing LSP trigger should\n      -- show no completion if there is no LSP completion (as is imitated\n      -- inside commented lines).\n      type_keys('<Esc>o', '# .')\n      sleep(default_completion_delay + small_time)\n      child.expect_screenshot()\n    end,\n  }\n)\n\nT['Autocompletion']['works with `<BS>`'] = function()\n  mock_completefunc_lsp_tracking()\n  child.set_size(10, 20)\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n  type_keys('i', 'J', 'u', '<C-Space>')\n  -- - Should only call two times, as per `:h complete-functions`: first to\n  --   find the start column, second to return completion suggestions.\n  eq(child.lua_get('_G.n_completfunc_lsp'), 2)\n\n  type_keys('n')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.n_completfunc_lsp'), 2)\n\n  -- Should keep completion menu and adjust items without extra 'completefunc'\n  -- calls (as it is still at or after initial start column)\n  type_keys('<BS>')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.n_completfunc_lsp'), 2)\n\n  -- Should reevaluate completion list as it is past initial start column\n  type_keys('<BS>')\n  child.expect_screenshot()\n  -- - Should call three times: first to make a request, second and third to\n  --   act as a regular 'completefunc'/'omnifunc'\n  eq(child.lua_get('_G.n_completfunc_lsp'), 5)\nend\n\nT['Autocompletion']['forces new LSP completion in case of `isIncomplete`'] = function()\n  child.lua('_G.lines_at_request = {}')\n  mock_completefunc_lsp_tracking()\n  child.set_size(10, 20)\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n  -- Mock incomplete completion list which contains only months 1-6\n  child.lua('_G.mock_isincomplete = true')\n  type_keys('i', 'J', '<C-Space>')\n  -- - Should not contain `July` as it is not in the response\n  child.expect_screenshot()\n  eq(child.lua_get('_G.n_textdocument_completion'), 1)\n  -- - Should only call two times, as per `:h complete-functions`: first to\n  --   find the start column, second to return completion suggestions.\n  eq(child.lua_get('_G.n_completfunc_lsp'), 2)\n  eq(child.lua_get('_G.lines_at_request'), { 'J' })\n\n  -- Should force new request which this time will be complete\n  child.lua('_G.mock_isincomplete = false')\n  type_keys('u')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.n_textdocument_completion'), 2)\n  -- - NOTE: not using completefunc to make an LSP request is a key to reduce\n  --   flickering in this use case (as executing `<C-x>...` forces popup hide).\n  eq(child.lua_get('_G.n_completfunc_lsp'), 4)\n  -- - Should request when line is up to date (i.e. not *exactly* inside\n  --   `InsertCharPre`).\n  eq(child.lua_get('_G.lines_at_request'), { 'J', 'Ju' })\n\n  -- Shouldn't force new requests or call 'completefunc' for complete responses\n  type_keys('n')\n  eq(child.lua_get('_G.n_textdocument_completion'), 2)\n  eq(child.lua_get('_G.n_completfunc_lsp'), 4)\n  eq(child.lua_get('_G.lines_at_request'), { 'J', 'Ju' })\n  type_keys('<BS>')\n  eq(child.lua_get('_G.n_textdocument_completion'), 2)\n  eq(child.lua_get('_G.n_completfunc_lsp'), 4)\n  eq(child.lua_get('_G.lines_at_request'), { 'J', 'Ju' })\n\n  -- Should force new request if deleting past the start of previous request.\n  -- This time response will be complete.\n  type_keys('<BS>')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.n_textdocument_completion'), 3)\n  -- - Should call three times: first to make a request, second and third to\n  --   act as a regular 'completefunc'/'omnifunc'\n  eq(child.lua_get('_G.n_completfunc_lsp'), 7)\n  eq(child.lua_get('_G.lines_at_request'), { 'J', 'Ju', 'J' })\nend\n\nT['Autocompletion']['forces new LSP completion for `isIncomplete` even if canceled'] = function()\n  child.lua('_G.lines_at_request = {}')\n  child.set_size(10, 20)\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n  child.lua('_G.mock_request_delay = ' .. small_time)\n\n  -- Mock incomplete completion list which contains only months 1-6\n  child.lua('_G.mock_isincomplete = true')\n  type_keys('i', 'J', '<C-Space>')\n  sleep(small_time + small_time)\n  eq(child.lua_get('_G.lines_at_request'), { 'J' })\n\n  -- Should force two requests even though the first one was canceled due to\n  -- fast typing\n  child.lua('_G.mock_isincomplete = false')\n  type_keys('u', 'l')\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n  eq(child.lua_get('_G.lines_at_request'), { 'J', 'Ju', 'Jul' })\nend\n\nT['Autocompletion']['sends proper context in request'] = function()\n  child.lua('MiniCompletion.config.delay.completion = ' .. small_time)\n  -- Make sure that `CompleteDonePre` event is not triggered after typing `.`\n  child.o.iskeyword = '@,48-57,_,192-255,.'\n\n  local trigger_kinds = child.lua([[\n    local res = {}\n    for k, v in pairs(vim.lsp.protocol.CompletionTriggerKind) do\n      if type(k) == 'string' then res[k] = v end\n    end\n    return res\n  ]])\n  local validate_latest_request_context = function(ref_context)\n    local latest_params = child.lua_get('_G.params_log[#_G.params_log]')\n    eq(latest_params.method, 'textDocument/completion')\n    eq(latest_params.params.context, ref_context)\n  end\n\n  -- First request is done after typing non-trigger character\n  child.lua('_G.mock_isincomplete = true')\n  type_keys('i', 'J')\n  sleep(small_time + small_time)\n  validate_latest_request_context({ triggerKind = trigger_kinds.Invoked })\n\n  -- Second request is done automatically due to `isIncomplete`\n  type_keys('u')\n  sleep(small_time + small_time)\n  validate_latest_request_context({ triggerKind = trigger_kinds.TriggerForIncompleteCompletions })\n\n  -- Third request is done after typing trigger character, although there is\n  -- still `isIncomplete` after previous request\n  type_keys('.')\n  sleep(small_time + small_time)\n  validate_latest_request_context({ triggerKind = trigger_kinds.TriggerCharacter, triggerCharacter = '.' })\nend\n\nT['Autocompletion']['respects `config.delay.completion`'] = function()\n  child.lua('MiniCompletion.config.delay.completion = ' .. (2 * default_completion_delay))\n\n  type_keys('i', 'J')\n  sleep(2 * default_completion_delay - small_time)\n  eq(get_completion(), {})\n  sleep(small_time + small_time)\n  eq(get_completion(), { 'January', 'June', 'July' })\n\n  -- Should also use buffer local config\n  child.ensure_normal_mode()\n  set_lines({ '' })\n  set_cursor(1, 0)\n  child.b.minicompletion_config = { delay = { completion = default_completion_delay } }\n  type_keys('i', 'J')\n  sleep(default_completion_delay - small_time)\n  eq(get_completion(), {})\n  sleep(small_time + small_time)\n  eq(get_completion(), { 'January', 'June', 'July' })\nend\n\nT['Autocompletion']['respects `config.lsp_completion.process_items`'] = function()\n  child.lua('_G.process_items = function(items, base) return { items[2], items[3] } end')\n  child.lua('MiniCompletion.config.lsp_completion.process_items = _G.process_items')\n\n  type_keys('i', 'J')\n  sleep(default_completion_delay + small_time)\n  eq(get_completion(), { 'February', 'March' })\n\n  child.ensure_normal_mode()\n  set_lines({ '' })\n  set_cursor(1, 0)\n  child.lua('_G.process_items_2 = function(items, base) return { items[4], items[5] } end')\n  child.lua('vim.b.minicompletion_config = { lsp_completion = { process_items = _G.process_items_2 } }')\n\n  type_keys('i', 'J')\n  sleep(default_completion_delay + small_time)\n  eq(get_completion(), { 'April', 'May' })\nend\n\nT['Autocompletion']['calls `config.lsp_completion.process_items` once for several servers'] = function()\n  child.lua([[\n    require('mini.snippets').setup({ snippets = { { prefix = 'Jav', body = 'Java snippet' } } })\n    MiniSnippets.start_lsp_server()\n\n    _G.log = {}\n    MiniCompletion.config.lsp_completion.process_items = function(items, base)\n      table.insert(_G.log, items)\n      return MiniCompletion.default_process_items(items, base)\n    end\n  ]])\n\n  type_keys('i', 'J')\n  sleep(default_completion_delay + small_time)\n  eq(get_completion(), { 'January', 'June', 'July', 'Java snippet' })\n\n  local log = child.lua_get('_G.log')\n  eq(#log, 1)\n  eq(log[1][1].label, 'January')\n  eq(log[1][#log[1]].label, 'Jav')\nend\n\nT['Autocompletion']['respects string `config.fallback_action`'] = function()\n  child.set_size(10, 25)\n  child.lua([[MiniCompletion.config.fallback_action = '<C-x><C-l>']])\n\n  set_lines({ 'Line number 1', '' })\n  set_cursor(2, 0)\n  type_keys('i', 'L')\n  sleep(default_completion_delay + small_time)\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  child.ensure_normal_mode()\n  child.b.minicompletion_config = { fallback_action = '<C-p>' }\n  set_lines({ 'Line number 1', '' })\n  set_cursor(2, 0)\n  type_keys('i', 'L')\n  sleep(default_completion_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Autocompletion']['respects function `config.fallback_action`'] = function()\n  child.lua([[MiniCompletion.config.fallback_action = function() _G.inside_fallback = true end]])\n  type_keys('i', 'a')\n  sleep(default_completion_delay + small_time)\n  eq(child.lua_get('_G.inside_fallback'), true)\n\n  child.ensure_normal_mode()\n  child.lua('vim.b.minicompletion_config = { fallback_action = function() _G.inside_local_fallback = true end }')\n  type_keys('i', 'a')\n  sleep(default_completion_delay + small_time)\n  eq(child.lua_get('_G.inside_local_fallback'), true)\nend\n\nT['Autocompletion']['respects `vim.{g,b}.minicompletion_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicompletion_disable = true\n    type_keys('i', 'J')\n    sleep(default_completion_delay + small_time)\n    eq(get_completion(), {})\n  end,\n})\n\nT['Manual completion'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Virtually disable auto-completion\n      child.lua('MiniCompletion.config.delay.completion = 100000')\n      -- Create new buffer to set buffer-local `completefunc` or `omnifunc`\n      new_buffer()\n      -- For details see 'mock-lsp/months.lua'\n      mock_lsp()\n\n      set_lines({ 'Jackpot', '' })\n      set_cursor(2, 0)\n    end,\n  },\n})\n\nT['Manual completion']['works with two-step completion'] = function()\n  type_keys('i', 'J', '<C-Space>')\n  eq(get_completion(), { 'January', 'June', 'July' })\n\n  type_keys('ac')\n  eq(child.fn.pumvisible(), 0)\n\n  type_keys('<C-Space>')\n  eq(get_completion(), { 'Jackpot' })\nend\n\nT['Manual completion']['handles request errors'] = function()\n  child.lua('_G.mock_error = { [\"textDocument/completion\"] = \"Error\" }')\n  type_keys('i', 'J', '<C-Space>')\n  eq(get_completion(), { 'Jackpot' })\nend\n\nT['Manual completion']['uses `vim.lsp.protocol.CompletionItemKind` in LSP step'] = function()\n  child.set_size(17, 30)\n  child.lua([[vim.lsp.protocol.CompletionItemKind = {\n    [1] = 'Text',         Text = 1,\n    [2] = 'Method',       Method = 2,\n    [3] = 'S Something',  ['S Something'] = 3,\n    [4] = 'Fallback',     Fallback = 4,\n  }]])\n  type_keys('i', '<C-Space>')\n  child.expect_screenshot()\nend\n\nT['Manual completion']['sends proper context in request'] = function()\n  local trigger_kind_invoked = child.lua_get('vim.lsp.protocol.CompletionTriggerKind.Invoked')\n  local validate_latest_request_context = function(ref_context)\n    local latest_params = child.lua_get('_G.params_log[#_G.params_log]')\n    eq(latest_params.method, 'textDocument/completion')\n    eq(latest_params.params.context, ref_context)\n  end\n\n  -- First request is done after manual completion invocation\n  type_keys('i', 'J', '<C-Space>')\n  validate_latest_request_context({ triggerKind = trigger_kind_invoked })\n\n  -- Second request is done via API\n  child.lua('MiniCompletion.complete_twostage()')\n  eq(child.lua_get('#_G.params_log'), 2)\n  validate_latest_request_context({ triggerKind = trigger_kind_invoked })\nend\n\nT['Manual completion']['works with fallback action'] = function()\n  type_keys('i', 'J', '<M-Space>')\n  eq(get_completion(), { 'Jackpot' })\nend\n\nT['Manual completion']['works with explicit `<C-x>...`'] = new_set(\n  { parametrize = { { 'completefunc' }, { 'omnifunc' } } },\n  {\n    test = function(source_func)\n      reload_module({ lsp_completion = { source_func = source_func } })\n      mock_completefunc_lsp_tracking()\n      child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n      local source_keys = '<C-x>' .. (source_func == 'completefunc' and '<C-u>' or '<C-o>')\n      type_keys('i', 'J', source_keys)\n      eq(get_completion(), { 'January', 'June', 'July' })\n      -- Should call three times: first to initiate request, second/third to\n      -- perform its actions (as per `:h complete-functions`)\n      eq(child.lua_get('_G.n_completfunc_lsp'), 3)\n    end,\n  }\n)\nT['Manual completion']['respects `config.mappings'] = function()\n  reload_module({ mappings = { force_twostep = '<C-z>', force_fallback = '<C-x>' } })\n  type_keys('i', 'J', '<C-z>')\n  eq(get_completion(), { 'January', 'June', 'July' })\n  type_keys('<C-x>')\n  eq(get_completion(), { 'Jackpot' })\nend\n\nT['Manual completion']['applies `additionalTextEdits` from \"textDocument/completion\"'] = function()\n  local validate = function(confirm_key)\n    child.ensure_normal_mode()\n    set_lines({})\n    type_keys('i', 'Se', '<C-space>')\n    child.poke_eventloop()\n    type_keys('<C-n>', confirm_key)\n\n    eq(child.fn.mode(), 'i')\n    local is_explicit_confirm = confirm_key == '<C-y>'\n    eq(\n      get_lines(),\n      { 'from months.completion import September', 'September' .. (is_explicit_confirm and '' or confirm_key) }\n    )\n    -- Text edits shouldn't interfere with relative cursor position\n    eq(get_cursor(), { 2, 9 + (is_explicit_confirm and 0 or 1) })\n  end\n\n  -- 'Confirmation' should be either explicit ('<C-y>') or implicit\n  -- (continued typing)\n  validate('<C-y>')\n  validate(' ')\nend\n\nT['Manual completion']['applies `additionalTextEdits` from \"completionItem/resolve\"'] = function()\n  local validate = function(word_start, word)\n    child.ensure_normal_mode()\n    set_lines({})\n    type_keys('i', word_start, '<C-space>')\n    child.poke_eventloop()\n    type_keys('<C-n>')\n    -- Wait until `completionItem/resolve` request is sent\n    sleep(default_info_delay + small_time)\n    type_keys('<C-y>')\n\n    eq(child.fn.mode(), 'i')\n    eq(get_lines(), { 'from months.resolve import ' .. word, word })\n    -- Text edits shouldn't interfere with relative cursor position\n    eq(get_cursor(), { 2, word:len() })\n  end\n\n  -- Case when `textDocument/completion` doesn't have `additionalTextEdits`\n  validate('Oc', 'October')\n\n  -- Case when `textDocument/completion` does have `additionalTextEdits`\n  validate('No', 'November')\n\n  -- Should clear all possible cache for `additionalTextEdits`\n  child.ensure_normal_mode()\n  set_lines({})\n  type_keys('i', 'Ja', '<C-space>')\n  child.poke_eventloop()\n  type_keys('<C-n>', '<C-y>')\n  eq(get_lines(), { 'January' })\nend\n\nT['Manual completion']['prefers completion range from LSP response'] = function()\n  set_lines({})\n  type_keys('i', 'months.')\n  -- Mock `textEdit`+`filterText` as in `tsserver` when called after `.`\n  child.lua([[\n    _G.mock_textEdit = {\n      pos = vim.api.nvim_win_get_cursor(0),\n      new_text = function(name) return '.' .. name end,\n    }\n    _G.mock_filterText = function(name) return '.' .. name end\n  ]])\n  type_keys('<C-space>')\n\n  eq(get_completion('abbr'), { 'April', 'August' })\n  eq(get_completion('word'), { '.April', '.August' })\n  type_keys('<C-n>', '<C-y>')\n  eq(get_lines(), { 'months.April' })\n  eq(get_cursor(), { 1, 12 })\n\n  type_keys('<C-e>', '<Esc>')\n  set_lines({})\n\n  -- Should recognize edit range from `itemDefaults` (as in `tailwindcss`)\n  type_keys('i', 'months.A')\n  child.lua([[_G.mock_itemdefaults = {\n    editRange = { start = { line = 0, character = 5 }, ['end'] = { line = 0, character = 7 } },\n  }\n  _G.mock_filterText = function(name) return 's.' .. name end\n  ]])\n  type_keys('<C-space>')\n  type_keys('<C-n>', '<C-y>')\n  eq(get_lines(), { 'month.April' })\nend\n\nT['Manual completion']['respects `filterText` from LSP response'] = function()\n  set_lines({})\n  type_keys('i', 'months.')\n  -- Mock `textEdit` and `filterText` as in `tsserver` when called after `.`\n  -- (see https://github.com/nvim-mini/mini.nvim/issues/306#issuecomment-1602245446)\n  child.lua([[\n    _G.mock_textEdit = {\n      pos = vim.api.nvim_win_get_cursor(0),\n      new_text = function(name) return '[' .. name .. ']' end,\n    }\n    _G.mock_filterText = function(name) return '.' .. name end\n  ]])\n  type_keys('<C-space>')\n\n  eq(get_completion('abbr'), { 'April', 'August' })\n  eq(get_completion('word'), { '[April]', '[August]' })\n  type_keys('<C-n>', '<C-y>')\n  eq(get_lines(), { 'months[April]' })\n  eq(get_cursor(), { 1, 13 })\nend\n\nT['Manual completion']['respects `filterText` during built-in filtering'] = function()\n  set_lines({})\n  child.set_size(10, 20)\n  local format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n  mock_lsp_items({\n    { label = 'ab', filterText = 'ba' },\n    { label = 'cba', filterText = 'abc' },\n    -- Snippets should still be filtered according to 'filterText' and\n    -- not what snippet will be inserted later\n    { label = 'dcba', filterText = 'ab$1cd', insertTextFormat = format_snippet },\n    { label = 'edcba', filterText = 'abcde', insertText = 'snip$1pet', insertTextFormat = format_snippet },\n  })\n\n  type_keys('i', '<C-Space>')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\nend\n\nT['Manual completion']['respects `labelDetails` from LSP response'] = function()\n  child.set_size(16, 32)\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(items, base)\n      for _, it in ipairs(items) do\n        if it.label == 'January' then it.labelDetails = { detail = 'jan' } end\n        if it.label == 'February' then it.labelDetails = { description = 'FEB' } end\n        -- Should use both `detail` and `description`\n        if it.label == 'March' then it.labelDetails = { detail = 'mar', description = 'MAR' } end\n      end\n      return MiniCompletion.default_process_items(items, base)\n    end\n  ]])\n\n  set_lines({})\n  type_keys('i', '<C-Space>')\n  child.expect_screenshot()\nend\n\nT['Manual completion']['respects `itemDefaults` from LSP response'] = function()\n  local format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(items, _)\n      _G.latest_items = vim.deepcopy(items)\n      return items\n    end\n  ]])\n\n  child.lua([[\n    _G.mock_textEdit = { new_text = function(x) return 'Hello ' .. x end, pos = { 1, 1 } }\n    _G.mock_itemdefaults = {\n      commitCharacters = { ')' },\n      data = { hello = 'world' },\n      insertTextFormat = vim.lsp.protocol.InsertTextFormat.Snippet,\n      insertTextMode = 1,\n    }\n  ]])\n\n  -- Mock with `editRange` as regular `Range`\n  local edit_range = { start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 1 } }\n  child.lua('_G.mock_itemdefaults.editRange = ' .. vim.inspect(edit_range))\n\n  set_lines({})\n  type_keys('i', '<C-Space>')\n\n  local items = child.lua_get('_G.latest_items')\n  for _, item in ipairs(items) do\n    eq(item.commitCharacters, { ')' })\n    eq(item.data, { hello = 'world' })\n    eq(item.insertTextFormat, format_snippet)\n    eq(item.insertTextMode, 1)\n\n    eq(item.textEdit.newText, item.textEdit.newText or item.textEditText or item.label)\n    eq(item.textEdit.range, item.textEdit.range or edit_range)\n    -- 'April' has mocked 'InsertReplaceEdit' type of `textEdit` in the item\n    if item.label ~= 'April' then\n      eq(item.textEdit.insert, nil)\n      eq(item.textEdit.replace, nil)\n    end\n  end\n  type_keys('<C-e>')\n  child.lua('_G.latest_items = nil')\n\n  -- Mock with `editRange` as isnert+replace ranges and partial default data\n  child.lua('_G.mock_itemdefaults.data = nil')\n  edit_range = {\n    replace = { start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 1 } },\n    insert = { start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 2 } },\n  }\n  child.lua('_G.mock_itemdefaults.editRange = ' .. vim.inspect(edit_range))\n\n  type_keys('<C-Space>')\n  items = child.lua_get('_G.latest_items')\n  for _, item in ipairs(items) do\n    eq(item.commitCharacters, { ')' })\n    eq(item.data, nil)\n    eq(item.insertTextFormat, format_snippet)\n    eq(item.insertTextMode, 1)\n\n    eq(item.textEdit.newText, item.textEdit.newText or item.textEditText or item.label)\n    -- 'August' has mocked 'Range' type of `textEdit` in the item\n    if item.label ~= 'August' then eq(item.textEdit.range, nil) end\n    eq(item.textEdit.insert, item.textEdit.insert or edit_range.insert)\n    eq(item.textEdit.replace, item.textEdit.replace or edit_range.replace)\n  end\nend\n\nT['Manual completion']['respects `abbr_hlgroup` as item field'] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip('Abbreviation highlighting is available on Neovim>=0.11') end\n  child.set_size(10, 40)\n  set_lines({})\n\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(items, base)\n      local res = vim.tbl_filter(function(x) return vim.startswith(x.label, base) end, items)\n      table.sort(res, function(a, b) return a.sortText < b.sortText end)\n      for _, item in ipairs(res) do\n        if item.label == 'January' then item.abbr_hlgroup = 'String' end\n        if item.label == 'June' then item.abbr_hlgroup = 'Comment' end\n      end\n      return res\n    end\n  ]])\n  type_keys('i', 'J', '<C-Space>')\n  child.expect_screenshot()\nend\n\nT['Manual completion']['respects `kind_hlgroup` as item field'] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip('Kind highlighting is available on Neovim>=0.11') end\n  child.set_size(10, 40)\n  set_lines({})\n\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(items, base)\n      local res = vim.tbl_filter(function(x) return vim.startswith(x.label, base) end, items)\n      table.sort(res, function(a, b) return a.sortText < b.sortText end)\n      for _, item in ipairs(res) do\n        if item.label == 'January' then item.kind_hlgroup = 'String' end\n        if item.label == 'June' then item.kind_hlgroup = 'Comment' end\n      end\n      return res\n    end\n  ]])\n  type_keys('i', 'J', '<C-Space>')\n  child.expect_screenshot()\nend\n\nT['Manual completion']['respects `vim.{g,b}.minicompletion_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicompletion_disable = true\n    type_keys('i', '<C-Space>')\n    child.poke_eventloop()\n    eq(get_completion(), {})\n\n    type_keys('i', '<M-Space>')\n    child.poke_eventloop()\n    eq(get_completion(), {})\n  end,\n})\n\nT['Information window'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Create new buffer to set buffer-local `completefunc` or `omnifunc`\n      new_buffer()\n      -- For details see 'mock-lsp/months.lua'\n      mock_lsp()\n    end,\n  },\n})\n\nlocal is_info_border_busy = function()\n  local win_id = get_floating_windows()[1]\n  local winhl = child.api.nvim_get_option_value('winhighlight', { win = win_id })\n  return winhl:find('FloatBorder:MiniCompletionInfoBorderOutdated') ~= nil\nend\n\nlocal validate_info_win = function(delay)\n  type_keys('i', 'J', '<C-Space>')\n  eq(get_completion(), { 'January', 'June', 'July' })\n\n  -- Should implement debounce-style delay\n  type_keys('<C-n>')\n  eq(get_floating_windows(), {})\n  sleep(delay - small_time)\n  eq(get_floating_windows(), {})\n\n  type_keys('<C-n>')\n  eq(get_floating_windows(), {})\n  sleep(delay - small_time)\n  eq(get_floating_windows(), {})\n\n  sleep(small_time + small_time)\n  validate_single_floating_win({ lines = { 'Month #06' } })\n  eq(is_info_border_busy(), false)\n\n  -- Should use properly named buffer\n  local info_buf_id = child.api.nvim_win_get_buf(get_floating_windows()[1])\n  eq(child.api.nvim_buf_get_name(info_buf_id), 'minicompletion://' .. info_buf_id .. '/item-info')\n\n  -- Should try to keep window opened while visualizing outdated state via\n  -- border highlighting\n  type_keys('<C-p>')\n  validate_single_floating_win({ lines = { 'Month #06' } })\n  eq(is_info_border_busy(), true)\n\n  sleep(delay + small_time)\n  validate_single_floating_win({ lines = { 'Month #01' } })\n  eq(is_info_border_busy(), false)\n\n  -- Should close window immediately if no candidate is selected\n  type_keys('<C-p>')\n  eq(get_floating_windows(), {})\nend\n\nT['Information window']['works'] = function()\n  child.set_size(10, 40)\n  validate_info_win(default_info_delay)\n\n  -- Should show relevant content without delay upon revisit\n  type_keys('<C-n>')\n  child.expect_screenshot()\nend\n\nT['Information window']['works without attached LSP server'] = function()\n  child.set_size(10, 40)\n  child.lsp.buf_detach_client(0, child.lua_get('_G.months_lsp_client_id'))\n  child.lua([[\n    local items = {\n      { word = 'aa', info = 'Word aa' },\n      { word = 'aaa', info = 'Word aaa' },\n    }\n    MiniCompletion.config.fallback_action = function() vim.fn.complete(vim.fn.col('.'), items) end\n  ]])\n\n  type_keys('i', '<C-Space>')\n  type_keys('<C-n>')\n  -- Should show info window immediately (as there is no LSP server to resolve\n  -- with) with regular border highlight\n  child.expect_screenshot()\n  eq(is_info_border_busy(), false)\n  type_keys('<C-n>')\n  child.expect_screenshot()\n  eq(is_info_border_busy(), false)\nend\n\nT['Information window']['has \"busy\" visualization until receiving resolve response'] = function()\n  local request_delay = 3 * small_time\n  child.lua('_G.mock_request_delay = ' .. request_delay)\n\n  type_keys('i', 'J', '<C-Space>')\n  sleep(request_delay + small_time)\n  eq(child.fn.pumvisible(), 1)\n\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  eq(get_floating_windows(), {})\n  sleep(request_delay)\n  validate_single_floating_win({ lines = { 'Month #01' } })\n  eq(is_info_border_busy(), false)\n\n  type_keys('<C-n>')\n  eq(is_info_border_busy(), true)\n  sleep(default_info_delay + request_delay - small_time)\n  validate_single_floating_win({ lines = { 'Month #01' } })\n  eq(is_info_border_busy(), true)\n  sleep(small_time + small_time)\n  validate_single_floating_win({ lines = { 'Month #06' } })\n  eq(is_info_border_busy(), false)\nend\n\nT['Information window']['handles no info in candidate'] = function()\n  type_keys('i', 'Ma', '<C-Space>', '<C-n>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  validate_single_floating_win({ lines = { '-No-info-' } })\nend\n\nT['Information window']['handles request errors'] = function()\n  child.lua('_G.mock_error = { [\"completionItem/resolve\"] = \"Error\" }')\n  type_keys('i', 'J', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  validate_single_floating_win({ lines = { '-No-info-' } })\nend\n\nT['Information window']['respects `config.delay.info`'] = function()\n  child.lua('MiniCompletion.config.delay.info = ' .. (2 * default_info_delay))\n  validate_info_win(2 * default_info_delay)\n\n  -- Should also use buffer local config\n  child.ensure_normal_mode()\n  set_lines({ '' })\n  child.b.minicompletion_config = { delay = { info = default_info_delay } }\n  validate_info_win(default_info_delay)\nend\n\nT['Information window']['caches info lines for visited candidates'] = function()\n  local info_delay = 2 * small_time\n  child.lua('MiniCompletion.config.delay.info = ' .. info_delay)\n  local validate_n_requests = function(ref) eq(child.lua_get('_G.n_completionitem_resolve'), ref) end\n  local validate_win = function(ref_lines, ref_is_border_busy)\n    if ref_lines == false then return eq(get_floating_windows(), {}) end\n    validate_single_floating_win({ lines = ref_lines })\n    eq(is_info_border_busy(), ref_is_border_busy)\n  end\n\n  -- Fully compute info lines on first candidate visit\n  type_keys('i', 'J', '<C-Space>', '<C-n>')\n  validate_win(false)\n  sleep(info_delay + small_time)\n  validate_win({ 'Month #01' }, false)\n\n  type_keys('<C-n>')\n  validate_win({ 'Month #01' }, true)\n  sleep(info_delay + small_time)\n  validate_win({ 'Month #06' }, false)\n\n  -- For already visited items do not make new LSP requests and show proper\n  -- content without delay\n  validate_n_requests(2)\n  type_keys('<C-p>')\n  validate_win({ 'Month #01' }, false)\n\n  type_keys('<C-n>')\n  validate_win({ 'Month #06' }, false)\n  validate_n_requests(2)\n\n  -- Cached info lines should still be preserved until current completion end\n  type_keys('<C-p>', '<C-p>')\n  validate_win(false)\n  type_keys('<C-n>')\n  validate_win({ 'Month #01' }, false)\n  validate_n_requests(2)\n\n  type_keys('<C-p>')\n  validate_win(false)\n  type_keys('u', '<C-n>')\n  validate_win({ 'Month #06' }, false)\n  validate_n_requests(2)\n\n  type_keys('<C-n>')\n  validate_win({ 'Month #06' }, true)\n  sleep(info_delay + small_time)\n  -- - NOTE: actual lines for \"July\" entry is too long, so not tested here\n  validate_win(nil, false)\n  validate_n_requests(3)\n\n  -- Cache for visited lines should be properly cleared after completion end\n  type_keys(' ', 'J', '<C-Space>', '<C-n>')\n  validate_win(false)\n  sleep(info_delay + small_time)\n  validate_win({ 'Month #01' }, false)\n  validate_n_requests(4)\nend\n\nT['Information window']['caches resolved data for visited candidates'] = function()\n  type_keys('i', '<C-space>', '<C-p>', '<C-p>', '<C-p>')\n  sleep(default_info_delay + small_time)\n  validate_single_floating_win({ lines = { 'Month #10' } })\n\n  type_keys('<C-n>', '<C-p>')\n  validate_single_floating_win({ lines = { 'Month #10' } })\n  type_keys('<C-y>')\n\n  eq(get_lines(), { 'from months.resolve import October', 'October' })\nend\n\nT['Information window']['caches data with multiple servers'] = function()\n  -- Start another LSP server\n  child.cmd('luafile tests/mock-lsp/fruits.lua')\n\n  local info_delay = 2 * small_time\n  child.lua('MiniCompletion.config.delay.info = ' .. info_delay)\n  local validate_n_requests = function(ref) eq(child.lua_get('_G.n_completionitem_resolve'), ref) end\n\n  local validate_info_content = function(sleep_delay)\n    local validate_step = function(lines)\n      type_keys('<C-n>')\n      if sleep_delay > 0 then sleep(sleep_delay) end\n      validate_single_floating_win({ lines = lines })\n    end\n\n    validate_step({ 'Month #01' })\n    validate_step({ 'Jackfruit is a fruit' })\n  end\n\n  type_keys('i', 'Ja', '<C-Space>')\n  validate_info_content(info_delay + small_time)\n\n  type_keys('<C-n>')\n  validate_n_requests(2)\n  validate_info_content(0)\n  validate_n_requests(2)\nend\n\nT['Information window']['handles caching for items with the same basic data'] = function()\n  local info_delay = 2 * small_time\n  child.lua('MiniCompletion.config.delay.info = ' .. info_delay)\n  local validate_n_requests = function(ref) eq(child.lua_get('_G.n_completionitem_resolve'), ref) end\n\n  mock_lsp_items({\n    { label = 'ab', sortText = '01', documentation = 'Item 1' },\n    { label = 'ab', sortText = '02', documentation = 'Item 2' },\n  })\n\n  type_keys('i', '<C-Space>', '<C-n>')\n  sleep(info_delay + small_time)\n  validate_single_floating_win({ lines = { 'Item 1' } })\n  type_keys('<C-n>')\n  sleep(info_delay + small_time)\n  validate_single_floating_win({ lines = { 'Item 2' } })\n\n  -- Should use caching mechanism that doesn't rely on fields that can be same\n  validate_n_requests(2)\n  type_keys('<C-p>')\n  validate_single_floating_win({ lines = { 'Item 1' } })\n  type_keys('<C-n>')\n  validate_single_floating_win({ lines = { 'Item 2' } })\n  validate_n_requests(2)\nend\n\nT['Information window']['works if server does not support `completionItem/resolve`'] = function()\n  child.lsp.buf_detach_client(0, child.lua_get('_G.months_lsp_client_id'))\n\n  -- Start another LSP server in a way that doesn't support resolve\n  child.lua('_G.mock_no_resolve = true')\n  child.cmd('luafile tests/mock-lsp/fruits.lua')\n\n  local info_delay = 2 * small_time\n  child.lua('MiniCompletion.config.delay.info = ' .. info_delay)\n\n  -- Should use data provided at the time of 'textDocument/completion' request\n  type_keys('i', '<C-Space>', '<C-n>')\n  sleep(info_delay + small_time)\n  validate_single_floating_win({ lines = { 'Apple fruit' } })\n\n  type_keys('<C-n>')\n  sleep(info_delay + small_time)\n  validate_single_floating_win({ lines = { '-No-info-' } })\n\n  -- Should still cache data as visited/resolved\n  type_keys('<C-p>')\n  validate_single_floating_win({ lines = { 'Apple fruit' } })\n  type_keys('<C-n>')\n  validate_single_floating_win({ lines = { '-No-info-' } })\n\n  -- Should not do 'completionItem/resolve' requests (as there is no support)\n  eq(child.lua_get('_G.n_completionitem_resolve'), vim.NIL)\nend\n\nlocal validate_info_window_config = function(keys, completion_items, win_config)\n  type_keys('i', keys, '<C-Space>')\n  eq(get_completion(), completion_items)\n\n  type_keys('<C-n>')\n  -- Some windows can take a while to process on slow machines. So add `10`\n  -- to ensure that processing is finished.\n  sleep(default_info_delay + small_time)\n  validate_single_floating_win({ config = win_config })\nend\n\nT['Information window']['respects `config.window.info`'] = function()\n  child.set_size(25, 60)\n  local win_config = { height = 20, width = 40, border = 'single' }\n  child.lua('MiniCompletion.config.window.info = ' .. vim.inspect(win_config))\n  validate_info_window_config('D', { 'December' }, {\n    height = 20,\n    width = 40,\n    border = { '┌', '─', '┐', '│', '┘', '─', '└', '│' },\n  })\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  child.ensure_normal_mode()\n  set_lines({ '' })\n  local test_border = { '1', '2', '3', '4', '5', '6', '7', '8' }\n  child.b.minicompletion_config = { window = { info = { height = 10, width = 20, border = test_border } } }\n  validate_info_window_config('D', { 'December' }, { height = 10, width = 20, border = test_border })\n  child.expect_screenshot()\nend\n\nT['Information window'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  local validate = function(ref_border)\n    validate_info_window_config('D', { 'December' }, { border = ref_border })\n    type_keys('<C-e>')\n    child.ensure_normal_mode()\n    set_lines({})\n  end\n\n  child.o.winborder = 'rounded'\n  validate({ '╭', '─', '╮', '│', '╯', '─', '╰', '│' })\n\n  -- Should prefer explicitly configured value over 'winborder'\n  child.lua('MiniCompletion.config.window.info.border = \"double\"')\n  validate({ '╔', '═', '╗', '║', '╝', '═', '╚', '║' })\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.lua('MiniCompletion.config.window.info.border = nil')\n  child.o.winborder = '+,-,+,|,+,-,+,|'\n  validate({ '+', '-', '+', '|', '+', '-', '+', '|' })\nend\n\nT['Information window'][\"respects 'pumborder' option\"] = function()\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"'pumborder' option is present on Neovim>=0.12\") end\n  child.set_size(15, 33)\n\n  local validate = function(offset, pumborder, keys)\n    keys = keys or { 'A', 'J', '<C-Space>' }\n    child.o.pumborder = pumborder\n    set_lines({ string.rep(' ', offset) })\n    type_keys(keys)\n    type_keys('<C-n>')\n    sleep(default_info_delay + small_time)\n    child.expect_screenshot()\n\n    type_keys('<C-e>')\n    child.ensure_normal_mode()\n    set_lines({})\n  end\n\n  -- Should properly adjust coordinates and pick side\n  validate(7, 'single')\n  validate(8, 'single')\n\n  -- Should respect no border in both windows\n  validate(0, 'none')\n\n  child.lua('MiniCompletion.config.window.info.border = \"none\"')\n  validate(0, 'single')\n  validate(0, 'none')\n  child.lua('MiniCompletion.config.window.info.border = nil')\n\n  -- Should work with present scrollbar\n  validate(0, 'single', { 'A', '<C-Space>' })\n  validate(0, 'none', { 'A', '<C-Space>' })\n  child.lua('MiniCompletion.config.window.info.border = \"none\"')\n  validate(0, 'single', { 'A', '<C-Space>' })\n  validate(0, 'none', { 'A', '<C-Space>' })\nend\n\nT['Information window']['triggers relevant events'] = function()\n  mock_event_log()\n  local validate_log = function(ref)\n    eq(child.lua_get('_G.log'), ref)\n    child.lua('_G.log = {}')\n  end\n\n  type_keys('i', 'J', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  local win_id = get_floating_windows()[1]\n  validate_log({ { event = 'MiniCompletionWindowOpen', data = { kind = 'info', win_id = win_id } } })\n\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  validate_log({ { event = 'MiniCompletionWindowUpdate', data = { kind = 'info', win_id = win_id } } })\nend\n\nT['Information window']['can be adjusted in event'] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip('\"title_pos\" window config field was added in Neovim=0.11') end\n\n  mock_custom_window_config()\n  child.set_size(10, 40)\n\n  type_keys('i', 'J', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['accounts for border when picking side'] = function()\n  child.set_size(10, 40)\n  child.lua([[MiniCompletion.config.window.info.border = 'single']])\n\n  set_lines({ 'aaaaaaaaaaaa ' })\n  type_keys('A', 'J', '<C-Space>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['has minimal dimensions for small text'] = function()\n  child.set_size(10, 40)\n  child.lua('MiniCompletion.config.window.info.height = 1')\n  child.lua('MiniCompletion.config.window.info.width = 9')\n  validate_info_window_config('J', { 'January', 'June', 'July' }, { height = 1, width = 9 })\n  child.expect_screenshot()\nend\n\nT['Information window']['adjusts window width'] = function()\n  child.set_size(10, 27)\n  child.lua([[MiniCompletion.config.window.info = { height = 15, width = 10, border = 'single' }]])\n\n  type_keys('i', 'J', '<C-Space>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['adjusts title'] = function()\n  child.set_size(20, 35)\n\n  type_keys('i', '<C-Space>', '<C-n>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\n  type_keys('<C-p>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['stylizes markdown with concealed characters'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Markdown highlighting is different on Neovim<0.10') end\n\n  child.set_size(15, 45)\n  type_keys('i', 'Jul', '<C-Space>')\n  type_keys('<C-n>')\n  eq(get_floating_windows(), {})\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['uses `detail` to construct content'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Markdown highlighting is different on Neovim<0.10') end\n  child.bo.filetype = 'lua'\n\n  child.set_size(15, 45)\n  type_keys('i', 'A', '<C-Space>')\n\n  -- Should show `detail` in language's code block if it is new information\n  -- Should also trim `detail` for a more compact view\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\n\n  -- Should omit `detail` if its content is already present in `documentation`\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['ignores data from first response if server can resolve completion item'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Markdown highlighting is different on Neovim<0.10') end\n\n  child.set_size(10, 45)\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(items, base)\n      for _, it in ipairs(items) do\n        if it.label == 'April' then\n          it.detail = 'Initial detail'\n          it.documentation = 'Initial documentation'\n        end\n      end\n      return MiniCompletion.default_process_items(items, base)\n    end\n  ]])\n\n  set_lines({})\n  type_keys('i', 'Apr', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  -- Should show resolved data and not initial in order to always prefer\n  -- resolved if possible. This is useful if initial response contains only\n  -- single `detail` or `documentation` but resolving gets them both (like in\n  -- `r-language-server`, for example).\n  child.expect_screenshot()\nend\n\nT['Information window']['adjusts for top/bottom code block delimiters'] = function()\n  child.set_size(10, 30)\n  type_keys('i', 'Sep', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  -- Should show floating window with height 1, i.e. both top and bottom code\n  -- block delimiters should be hidden\n  child.expect_screenshot()\nend\n\nT['Information window']['uses `info` field from not LSP source'] = function()\n  child.set_size(10, 30)\n  child.lua([[\n    MiniCompletion.config.fallback_action = function()\n      vim.fn.complete(1, { { word = 'Fall', abbr = 'Fall', info = 'back' } })\n    end\n  ]])\n\n  set_lines({})\n  type_keys('i', '<A-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Information window']['is closed when forced outside of Insert mode'] = new_set(\n  { parametrize = { { '<Esc>' }, { '<C-c>' } } },\n  {\n    test = function(key)\n      type_keys('i', 'J', '<C-Space>')\n      eq(get_completion(), { 'January', 'June', 'July' })\n\n      type_keys('<C-n>')\n      sleep(default_info_delay + small_time)\n      validate_single_floating_win({ lines = { 'Month #01' } })\n\n      type_keys(key)\n      eq(get_floating_windows(), {})\n    end,\n  }\n)\n\nT['Information window']['handles all buffer wipeout'] = function()\n  validate_info_win(default_info_delay)\n  child.ensure_normal_mode()\n\n  child.cmd('%bw!')\n  new_buffer()\n  mock_lsp()\n\n  validate_info_win(default_info_delay)\nend\n\nT['Information window']['handles outdated scheduled showing'] = function()\n  child.set_size(30, 40)\n  child.o.cmdheight = 20\n  child.o.completeopt = 'menuone,noinsert'\n\n  type_keys('i')\n  local text = 'aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az'\n  child.lua('_G.text = ' .. vim.inspect(text))\n  child.lua('_G.delay = ' .. small_time)\n  child.lua([[\n    MiniCompletion.config.delay.completion = _G.delay\n    MiniCompletion.config.delay.info = 0\n\n    local n_char = 0\n    local function type_text()\n      n_char = n_char + 1\n      local char = _G.text:sub(n_char, n_char)\n      if char == '' then return end\n      vim.api.nvim_input(char)\n      vim.defer_fn(type_text, _G.delay + 1)\n    end\n\n    type_text()\n  ]])\n\n  sleep(small_time * text:len() + small_time)\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['Information window']['respects `vim.{g,b}.minicompletion_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicompletion_disable = true\n\n    set_lines({ 'aa ab ', '' })\n    set_cursor(2, 0)\n    type_keys('i', '<C-n>', '<C-n>')\n    sleep(default_info_delay + small_time)\n    eq(#get_floating_windows(), 0)\n  end,\n})\n\nT['Signature help'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Create new buffer to set buffer-local `completefunc` or `omnifunc`\n      new_buffer()\n      -- For details see 'mock-lsp/months.lua'\n      mock_lsp()\n    end,\n  },\n})\n\nlocal validate_signature_win = function(delay)\n  type_keys('i', 'abc(')\n\n  eq(get_floating_windows(), {})\n  sleep(delay - small_time)\n  eq(get_floating_windows(), {})\n  sleep(small_time + small_time)\n  validate_single_floating_win({ lines = { 'abc(param1, param2)' } })\n\n  local signature_buf_id = child.api.nvim_win_get_buf(get_floating_windows()[1])\n  eq(child.api.nvim_buf_get_name(signature_buf_id), 'minicompletion://' .. signature_buf_id .. '/signature-help')\nend\n\nT['Signature help']['works'] = function()\n  child.set_size(7, 30)\n  validate_signature_win(default_signature_delay)\n  child.expect_screenshot()\nend\n\nT['Signature help']['handles request errors'] = function()\n  child.lua('_G.mock_error = { [\"textDocument/signatureHelp\"] = \"Error\" }')\n  type_keys('i', 'abc(')\n  sleep(default_signature_delay + small_time)\n  eq(get_floating_windows(), {})\nend\n\nT['Signature help']['respects `config.delay.signature`'] = function()\n  child.lua('MiniCompletion.config.delay.signature = ' .. (2 * default_signature_delay))\n  validate_signature_win(2 * default_signature_delay)\n\n  -- Should also use buffer local config\n  child.ensure_normal_mode()\n  set_lines({ '' })\n  child.b.minicompletion_config = { delay = { signature = default_signature_delay } }\n  validate_signature_win(default_signature_delay)\nend\n\nT['Signature help']['updates highlighting of active parameter'] = function()\n  child.set_size(7, 30)\n  child.cmd('startinsert')\n\n  type_keys('abc(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\n\n  -- Should update without configurable delay as window is already shown\n  type_keys('1,')\n  sleep(small_time)\n  child.expect_screenshot()\n\n  -- As there are only two parameters, nothing should be highlighted\n  type_keys('222,')\n  sleep(small_time)\n  child.expect_screenshot()\n\n  -- Should update if cursor is moved without typing (like during snippet jump)\n  set_cursor(1, 7)\n  sleep(small_time)\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  set_lines({ '' })\n\n  -- Should work when LSP server returns paramter label as string\n  type_keys('i', 'multiline(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\n  type_keys('3,')\n  sleep(small_time)\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  set_lines({ '' })\n\n  -- Should not error if parameters contain not correct label data\n  type_keys('i', 'bad_signature(')\n  sleep(default_signature_delay + small_time)\n  eq(child.cmd_capture('messages'):gsub('%s*$', ''), '')\nend\n\nT['Signature help']['updates without delay with different window'] = function()\n  child.set_size(8, 35)\n  set_lines({ 'multiline(', 'abc(111, 222)' })\n  child.cmd('startinsert')\n  set_cursor(1, 10)\n\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\n\n  set_cursor(2, 11)\n  sleep(small_time)\n  child.expect_screenshot()\nend\n\nlocal validate_signature_window_config = function(keys, win_config)\n  child.cmd('startinsert')\n  type_keys(keys)\n  sleep(default_signature_delay + small_time)\n  validate_single_floating_win({ config = win_config })\nend\n\nT['Signature help']['respects `config.window.signature`'] = function()\n  local keys = { 'l', 'o', 'n', 'g', '(' }\n  local win_config = { height = 15, width = 40, border = 'single' }\n  child.lua('MiniCompletion.config.window.signature = ' .. vim.inspect(win_config))\n  validate_signature_window_config(keys, {\n    height = 15,\n    width = 40,\n    border = { '┌', '─', '┐', '│', '┘', '─', '└', '│' },\n  })\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  child.ensure_normal_mode()\n  set_lines({ '' })\n  local test_border = { '1', '2', '3', '4', '5', '6', '7', '8' }\n  child.b.minicompletion_config = { window = { signature = { height = 10, width = 20, border = test_border } } }\n  validate_signature_window_config(keys, { height = 10, width = 20, border = test_border })\n  child.expect_screenshot()\nend\n\nT['Signature help'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  local validate = function(ref_border)\n    validate_signature_window_config('abc(', { border = ref_border })\n    type_keys('<C-e>')\n    child.ensure_normal_mode()\n    set_lines({})\n  end\n\n  child.o.winborder = 'rounded'\n  validate({ '╭', '─', '╮', '│', '╯', '─', '╰', '│' })\n\n  -- Should prefer explicitly configured value over 'winborder'\n  child.lua('MiniCompletion.config.window.signature.border = \"double\"')\n  validate({ '╔', '═', '╗', '║', '╝', '═', '╚', '║' })\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.lua('MiniCompletion.config.window.signature.border = nil')\n  child.o.winborder = '+,-,+,|,+,-,+,|'\n  validate({ '+', '-', '+', '|', '+', '-', '+', '|' })\nend\n\nT['Signature help']['triggers relevant events'] = function()\n  mock_event_log()\n  local validate_log = function(ref)\n    eq(child.lua_get('_G.log'), ref)\n    child.lua('_G.log = {}')\n  end\n\n  type_keys('i', 'abc(')\n  sleep(default_signature_delay + small_time)\n  local win_id = get_floating_windows()[1]\n  validate_log({ { event = 'MiniCompletionWindowOpen', data = { kind = 'signature', win_id = win_id } } })\n\n  -- Currently signature window is not updated after opened, so no\n  -- `MiniCompletionWindowUpdate` event is triggered\nend\n\nT['Signature help']['can be adjusted in event'] = function()\n  mock_custom_window_config()\n  child.set_size(7, 30)\n  type_keys('i', 'abc(')\n  sleep(default_signature_delay + small_time)\n  type_keys('x', ',')\n  sleep(small_time)\n  child.expect_screenshot()\nend\n\nT['Signature help']['accounts for border when picking side'] = function()\n  child.set_size(10, 40)\n  child.lua([[MiniCompletion.config.window.signature.border = 'single']])\n\n  type_keys('o<CR>', 'abc(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Signature help']['has minimal dimensions for small text'] = function()\n  child.set_size(7, 30)\n  local keys = { 'a', 'b', 'c', '(' }\n  child.lua('MiniCompletion.config.window.signature.height = 1')\n  child.lua('MiniCompletion.config.window.signature.width = 19')\n  validate_signature_window_config(keys, { height = 1, width = 19 })\n  child.expect_screenshot()\nend\n\nT['Signature help']['adjusts window height'] = function()\n  child.set_size(10, 25)\n  child.lua([[MiniCompletion.config.window.signature = { height = 15, width = 10, border = 'single' }]])\n\n  type_keys('i', 'long(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Signature help']['handles multiline text'] = function()\n  child.set_size(10, 35)\n\n  type_keys('i', 'multiline(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Signature help']['adjusts title'] = function()\n  child.set_size(10, 25)\n\n  type_keys('i', 'short(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\n  type_keys('aa,')\n  sleep(small_time)\n  child.expect_screenshot()\nend\n\nT['Signature help']['stylizes markdown with concealed characters'] = function()\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip('Lua highlighting is different on Neovim<0.12') end\n\n  child.set_size(10, 65)\n  child.bo.filetype = 'lua'\n  type_keys('i', 'string.format(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Signature help']['implements debounce-style delay'] = function()\n  child.cmd('startinsert')\n  type_keys('abc(')\n  sleep(default_signature_delay - small_time)\n  type_keys('d')\n  sleep(default_signature_delay + small_time)\n  eq(#get_floating_windows(), 0)\n\n  type_keys(',')\n  sleep(default_signature_delay + small_time)\n  validate_single_floating_win({ lines = { 'abc(param1, param2)' } })\nend\n\nT['Signature help']['is closed when forced outside of Insert mode'] = new_set(\n  { parametrize = { { '<Esc>' }, { '<C-c>' } } },\n  {\n    test = function(key)\n      type_keys('i', 'abc(')\n      sleep(default_signature_delay + small_time)\n      validate_single_floating_win({ lines = { 'abc(param1, param2)' } })\n\n      type_keys(key)\n      eq(get_floating_windows(), {})\n    end,\n  }\n)\n\nT['Signature help']['handles all buffer wipeout'] = function()\n  validate_signature_win(default_signature_delay)\n  child.ensure_normal_mode()\n\n  child.cmd('%bw!')\n  new_buffer()\n  mock_lsp()\n\n  validate_signature_win(default_signature_delay)\nend\n\nT['Signature help']['respects `vim.{g,b}.minicompletion_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minicompletion_disable = true\n\n    type_keys('i', 'abc(')\n    sleep(default_signature_delay + small_time)\n    eq(#get_floating_windows(), 0)\n  end,\n})\n\nT['Scroll'] = new_set({\n  hooks = {\n    pre_case = function()\n      new_buffer()\n      mock_lsp()\n      child.set_size(10, 25)\n    end,\n  },\n})\n\nT['Scroll']['can be done in info window'] = function()\n  child.lua('MiniCompletion.config.window.info.height = 4')\n\n  type_keys('i', 'F', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\n\n  type_keys('<C-f>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\n\n  type_keys('<C-b>')\n  child.expect_screenshot()\n  type_keys('<C-b>')\n  child.expect_screenshot()\n  type_keys('<C-b>')\n  child.expect_screenshot()\nend\n\nT['Scroll']['can be done in signature window'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip(\"'smoothscroll' requires Neovim>=0.10\") end\n\n  child.o.smoothscroll = true\n  child.lua('MiniCompletion.config.window.signature.height = 4')\n  child.lua('MiniCompletion.config.window.signature.width = 4')\n\n  type_keys('i', 'scroll(')\n  sleep(default_signature_delay + small_time)\n  child.expect_screenshot()\n\n  type_keys('<C-f>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\n\n  type_keys('<C-b>')\n  child.expect_screenshot()\n  type_keys('<C-b>')\n  child.expect_screenshot()\nend\n\nT['Scroll']['can be done in both windows'] = function()\n  child.o.smoothscroll = true\n  child.lua('MiniCompletion.config.window.info.height = 4')\n  child.lua('MiniCompletion.config.window.signature.height = 4')\n  child.lua('MiniCompletion.config.window.signature.width = 4')\n\n  type_keys('i', 'scroll(')\n  sleep(default_signature_delay + small_time)\n\n  type_keys('F', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\n\n  -- Should prefer scrolling in info window if both are visible\n  type_keys('<C-f>')\n  child.expect_screenshot()\n  type_keys('<C-b>')\n  child.expect_screenshot()\n\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip(\"'smoothscroll' requires Neovim>=0.10\") end\n  type_keys('<C-e>')\n  type_keys('<C-f>')\n  child.expect_screenshot()\nend\n\nT['Scroll']['respects `config.mappings`'] = function()\n  child.lua([[\n    vim.keymap.del('i', '<C-f>')\n    vim.keymap.del('i', '<C-b>')\n    MiniCompletion.setup({\n      lsp_completion = { source_func = 'omnifunc' },\n      mappings = { scroll_down = '<C-d>', scroll_up = '<C-u>' },\n      window = { info = { height = 4 } },\n    })\n  ]])\n\n  new_buffer()\n  mock_lsp()\n\n  type_keys('i', 'F', '<C-Space>')\n  type_keys('<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\n\n  type_keys('<C-d>')\n  child.expect_screenshot()\n  type_keys('<C-u>')\n  child.expect_screenshot()\n  type_keys('<C-e>')\n\n  -- Mapped keys can be used without active target window\n  set_lines({ '  Line' })\n  set_cursor(1, 6)\n  type_keys('<C-d>')\n  eq(get_lines(), { 'Line' })\n  type_keys('<C-u>')\n  eq(get_lines(), { '' })\nend\n\nlocal mock_lsp_snippets = function(snippets)\n  local kind_snippet = child.lua_get('vim.lsp.protocol.CompletionItemKind.Snippet')\n  mock_lsp_items(vim.tbl_map(function(x) return { label = x, kind = kind_snippet } end, snippets))\nend\n\nT['Snippets'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Test snippet insert primarily with 'mini.snippets'\n      child.lua('require(\"mini.snippets\").setup()')\n\n      new_buffer()\n      mock_lsp()\n      child.set_size(10, 25)\n    end,\n  },\n})\n\nT['Snippets']['work'] = function()\n  child.set_size(10, 40)\n\n  local kind_snippet = child.lua_get('vim.lsp.protocol.CompletionItemKind.Snippet')\n  local kind_function = child.lua_get('vim.lsp.protocol.CompletionItemKind.Function')\n  local format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n\n  local r = { start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 0 } }\n\n  local items = {\n    -- \"Regular\" snippet kind\n    { label = 'Snippet A $1', kind = kind_snippet },\n\n    -- Non-snippet kind, but with \"Snippet\" format of inserted text,\n    { label = 'Snippet B $1', kind = kind_function, insertTextFormat = format_snippet },\n\n    -- Should use `label` in popup and `insertText` after inserting\n    { label = 'Snip C', kind = kind_function, insertText = 'Snippet C $1', insertTextFormat = format_snippet },\n\n    -- Should use `label` in popup and `textEdit.newText` after inserting\n    {\n      label = 'Snip D',\n      kind = kind_function,\n      textEdit = { newText = 'Snippet D $1', range = vim.deepcopy(r) },\n      insertTextFormat = format_snippet,\n    },\n\n    -- Same, but `textEdit` is `InsertReplaceEdit`\n    {\n      label = 'Snip E',\n      kind = kind_function,\n      textEdit = { newText = 'Snippet E $1', insert = vim.deepcopy(r), replace = vim.deepcopy(r) },\n      insertTextFormat = format_snippet,\n    },\n\n    -- Multi-line snippets in label\n    { label = 'Snippet F\\nMulti\\nLine $1', kind = kind_snippet },\n    {\n      label = 'Snip G',\n      kind = kind_snippet,\n      textEdit = { newText = 'Snippet G\\nMulti\\nLine $1', range = vim.deepcopy(r) },\n    },\n  }\n\n  mock_lsp_items(items)\n  type_keys('i', '<C-Space>')\n  -- Should properly set abbreviation, kind, and \"S\" symbol\n  child.expect_screenshot()\n\n  -- Should show `label` when navigating with `<C-n>`\n  for i = 1, #items do\n    type_keys('<C-n>')\n    local ref_lines = vim.split(items[i].label, '\\n')\n    -- Built-in multi-line completion is present in Neovim>=0.11\n    if not (#ref_lines > 1 and child.fn.has('nvim-0.11') == 0) then eq(get_lines(), ref_lines) end\n  end\n\n  type_keys('<C-e>')\n  set_lines({ '' })\n\n  -- Should properly insert snippet and start snippet session\n  local validate = function(item, ref_lines, ref_cursor)\n    mock_lsp_items({ item })\n    type_keys('<C-Space>', '<C-n>', '<C-y>')\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n    eq(child.fn.mode(), 'i')\n    eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\n\n    type_keys('<C-c>')\n    set_lines({ '' })\n  end\n\n  validate(items[1], { 'Snippet A ' }, { 1, 10 })\n  validate(items[2], { 'Snippet B ' }, { 1, 10 })\n  validate(items[3], { 'Snippet C ' }, { 1, 10 })\n  validate(items[4], { 'Snippet D ' }, { 1, 10 })\n  validate(items[5], { 'Snippet E ' }, { 1, 10 })\n  validate(items[6], { 'Snippet F', 'Multi', 'Line ' }, { 3, 5 })\n  validate(items[7], { 'Snippet G', 'Multi', 'Line ' }, { 3, 5 })\nend\n\nT['Snippets']['are inserted after attempting to insert non-keyword charater'] = function()\n  mock_lsp_snippets({ 'Snippet A $1' })\n\n  local validate = function(non_keyword_char, ref_line, ref_cursor)\n    type_keys('i', '<C-Space>', '<C-n>', non_keyword_char)\n\n    eq(get_lines(), { ref_line })\n    eq(get_cursor(), ref_cursor)\n    eq(child.fn.pumvisible(), 0)\n    eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\n\n    type_keys('<C-c>', '<Esc>')\n    set_lines({ '' })\n  end\n\n  -- Should work with regular non-keyword character\n  validate(' ', 'Snippet A ', { 1, 10 })\n  validate('[', 'Snippet A ', { 1, 10 })\n  validate('<Tab>', 'Snippet A ', { 1, 10 })\n  validate('<S-Tab>', 'Snippet A ', { 1, 10 })\n\n  -- Should work with `<CR>` (with or without recommended remap)\n  validate('<CR>', 'Snippet A ', { 1, 10 })\n\n  child.lua([[\n    _G.cr_action = function()\n      -- '\\25' is <C-y> and '\\r' is <CR>\n      if vim.fn.pumvisible() ~= 0 then\n        local item_selected = vim.fn.complete_info()['selected'] ~= -1\n        return item_selected and '\\25' or '\\25\\r'\n      else\n        return '\\r'\n      end\n    end\n    vim.keymap.set('i', '<CR>', 'v:lua._G.cr_action()', { expr = true })\n  ]])\n  validate('<CR>', 'Snippet A ', { 1, 10 })\n\n  -- Should work when non-keyword char triggers Insert mode mapping that\n  -- inserts more characters (like in 'mini.pairs')\n  if child.fn.has('nvim-0.10') == 0 then\n    -- This is probably due to some fixed issue with extmarks\n    MiniTest.skip('Non-keyword character that inserts multiple characters can be used only on Neovim>=0.10 ')\n  end\n\n  child.cmd('inoremap ( (abc)<Left><Left><Left>')\n  set_lines({ 'Before cursor  text after cursor' })\n  set_cursor(1, 14)\n  -- - Should no part of `(abc)` be present\n  validate('(', 'Before cursor Snippet A  text after cursor', { 1, 24 })\nend\n\nT['Snippets']['can be stopped from inserting'] = function()\n  local kind_function = child.lua_get('vim.lsp.protocol.CompletionItemKind.Function')\n  local format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n  mock_lsp_items({\n    { label = 'Snip A', kind = kind_function, insertText = 'Snippet A $1', insertTextFormat = format_snippet },\n  })\n\n  local validate_stop = function(key, ref_line, ref_mode)\n    type_keys('i', '<C-Space>', '<C-n>')\n    type_keys(key)\n    eq(get_lines(), { ref_line })\n    eq(child.fn.mode(), ref_mode)\n\n    set_lines({ '' })\n    child.ensure_normal_mode()\n  end\n\n  -- Should do nothing after `<C-e>` (proper completion stop)\n  validate_stop('<C-e>', '', 'i')\n\n  -- Should not insert snippet after `<Esc>` / `<C-c>` (exit to Normal mode),\n  -- but inserted text\n  validate_stop('<Esc>', 'Snip A', 'n')\n  validate_stop('<C-c>', 'Snip A', 'n')\nend\n\nT['Snippets']['properly show special symbol in popup'] = function()\n  child.set_size(10, 35)\n  local kind_snippet = child.lua_get('vim.lsp.protocol.CompletionItemKind.Snippet')\n  local kind_function = child.lua_get('vim.lsp.protocol.CompletionItemKind.Function')\n\n  local items = {\n    -- Should correctly combine with label details\n    { label = 'Snippet A1 $1', kind = kind_snippet, labelDetails = { detail = 'Det' } },\n    { label = 'Snippet A2 $1', kind = kind_snippet, labelDetails = { description = 'Desc' } },\n    { label = 'Snippet A2 $1', kind = kind_snippet, labelDetails = { detail = 'Det', description = 'Desc' } },\n\n    -- No \"S\", as the text does not contain tabstop (although \"Snippet\" kind)\n    { label = 'OnlyText', kind = kind_snippet },\n\n    -- No \"S\", as not a snippet at all\n    { label = 'NotASnippet', kind = kind_function },\n  }\n\n  mock_lsp_items(items)\n  type_keys('i', '<C-Space>')\n  -- Should show \"S\" symbol only if item will actually insert snippet\n  child.expect_screenshot()\nend\n\nT['Snippets']['show full snippet text as info'] = function()\n  local kind_function = child.lua_get('vim.lsp.protocol.CompletionItemKind.Function')\n  local format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n  mock_lsp_items({\n    { label = 'January', kind = kind_function, insertText = 'January is $1', insertTextFormat = format_snippet },\n    { label = 'May', kind = kind_function, insertText = 'May the $1 be with you', insertTextFormat = format_snippet },\n  })\n\n  -- Should show full snippet text as info\n  type_keys('i', 'M', '<C-Space>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\n\n  type_keys('<C-e>', '<Esc>')\n  set_lines({ '' })\n\n  -- Should prefer server's documentation and/or detail if it provides one\n  type_keys('i', 'J', '<C-Space>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Snippets'][\"can fall back if no 'mini.snippets' is enabled\"] = function()\n  -- \"Unsetup\" 'mini.snippets'\n  child.lua('_G.MiniSnippets = nil')\n\n  mock_lsp_snippets({ 'Single line $1 snippet', 'Multi\\nline $1\\\\tnsnippet' })\n\n  -- On Neovim<0.10 should insert snippet text as is and set cursor at its end\n  if child.fn.has('nvim-0.10') == 0 then\n    local validate = function(snippet, ref_lines, ref_cursor)\n      mock_lsp_snippets({ snippet })\n\n      type_keys('i', '  Text before ')\n      type_keys('<C-Space>', '<C-n>', '<C-y>')\n      eq(get_lines(), ref_lines)\n      eq(get_cursor(), ref_cursor)\n      eq(child.fn.mode(), 'i')\n\n      child.ensure_normal_mode()\n      set_lines({ '' })\n    end\n\n    validate('Single line $1 snippet', { '  Text before Single line $1 snippet' }, { 1, 36 })\n    validate('Multi\\nline $1\\nsnippet', { '  Text before Multi', 'line $1', 'snippet' }, { 3, 7 })\n\n    return\n  end\n\n  -- On Neovim>=0.10 should use `vim.snippet.expand`\n  mock_lsp_snippets({ 'Multi\\nline $1\\nsnippet' })\n  type_keys('i', '  Text before ')\n  type_keys('<C-Space>', '<C-n>', '<C-y>')\n  eq(get_lines(), { '  Text before Multi', '  line ', '  snippet' })\n  eq(get_cursor(), { 2, 7 })\n  eq(child.fn.mode(), 'i')\n\n  child.lua('vim.snippet.jump(1)')\n  eq(get_cursor(), { 3, 9 })\n  eq(child.fn.mode(), 'i')\nend\n\nT['Snippets'][\"respect 'mini.snippets' config\"] = function()\n  child.lua([[\n    MiniSnippets.config.expand.insert = function(snippet)\n      MiniSnippets.default_insert(snippet, { empty_tabstop = '!', lookup = { VAR = 'Hello' } })\n    end\n    MiniSnippets.config.mappings.jump_next = '<Tab>'\n    MiniSnippets.config.mappings.jump_prev = '<S-Tab>'\n  ]])\n  mock_lsp_snippets({ 'Snippet_$1($0) $VAR' })\n  type_keys('i', '<C-Space>', '<C-n>', '<C-y>')\n  -- NOTE: inline virtual text is supported on Neovim>=0.10\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n  eq(get_cursor(), { 1, 8 })\n\n  type_keys('<Tab>')\n  eq(get_cursor(), { 1, 9 })\n  type_keys('<S-Tab>')\n  eq(get_cursor(), { 1, 8 })\nend\n\nT['Snippets']['can start nested sessions'] = function()\n  mock_lsp_snippets({ 'Snippet A $1', 'Snippet B $1' })\n  type_keys('i', '<C-Space>', '<C-n>', '<C-y>')\n  eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\n  type_keys('<C-Space>', '<C-n>', '<C-n>', '<C-y>')\n  eq(child.lua_get('#MiniSnippets.session.get(true)'), 2)\n\n  eq(get_lines(), { 'Snippet A Snippet B ' })\nend\n\nT['Snippets']['respect `lsp_completion.snippet_insert`'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniCompletion.config.lsp_completion.snippet_insert = function(...)\n      table.insert(_G.log, { ... })\n    end\n  ]])\n  mock_lsp_snippets({ 'Snippet $1' })\n  type_keys('i', '<C-Space>', '<C-n>', '<C-y>')\n  eq(child.fn.pumvisible(), 0)\n  eq(get_lines(), { '' })\n  eq(child.lua_get('_G.log'), { { 'Snippet $1' } })\nend\n\nT['Snippets']['are not inserted if have no tabstops or variables'] = function()\n  -- This allows inserting snippets \"implicitly\" after typing non-keyword\n  -- character. Without this, LSP servers which report any inserted text as\n  -- snippet will \"eat\" the next typed non-keyword charater.\n  -- Treating text as snippet if there is a variable is important for a snippet\n  -- insert method to expand them.\n\n  child.set_size(21, 52)\n  local snippets = {\n    -- - No insert:\n    'Just text',\n    [[Text with \\$1 escaped dollar]],\n    [[Text with \\$TM_FILENAME escaped dollar]],\n    [[Text with \\${1} escaped dollar]],\n    [[Text with \\${TM_FILENAME} escaped dollar]],\n    -- - Insert:\n    'Has $TM_FILENAME variable',\n    'Has $var variable',\n    'Has $1 tabstop',\n    '$1 has tabstop',\n    'Has ${1} tabstop',\n    '${1} has tabstop',\n    'Has ${1:aaa} tabstop',\n    'Has $0 tabstop',\n    'Has ${0} tabstop',\n    'Has tabstop$0',\n    'Has\\ttab',\n    'Has\\nnewline',\n  }\n  mock_lsp_snippets(snippets)\n\n  -- Should not show \"S\" symbol in popup for \"no insert\" items\n  type_keys('i', '<C-Space>')\n  child.expect_screenshot()\n  type_keys('<C-e>', '<Esc>')\n\n  child.lua([[\n    _G.log = {}\n    MiniCompletion.config.lsp_completion.snippet_insert = function(...)\n      table.insert(_G.log, { ... })\n    end\n  ]])\n  local validate = function(snip, accept_key, should_insert)\n    child.lua('_G.log = {}')\n    mock_lsp_snippets({ snip })\n\n    type_keys('i', '<C-Space>', '<C-n>', accept_key)\n    eq(child.lua_get('#_G.log > 0'), should_insert)\n\n    type_keys('<C-e>', '<Esc>')\n    set_lines({ '' })\n  end\n\n  for i = 1, 5 do\n    validate(snippets[i], '<C-y>', false)\n    validate(snippets[i], '<CR>', false)\n    validate(snippets[i], ' ', false)\n  end\n\n  for i = 6, #snippets do\n    validate(snippets[i], '<C-y>', true)\n    validate(snippets[i], '<CR>', true)\n    validate(snippets[i], ' ', true)\n  end\nend\n\nT['Snippets']['prefer snippet from resolved item'] = function()\n  -- Although it is not recommended by LSP spec to update/provide `insertText`\n  -- or `textEdti` in 'completionItem/resolve', this still can probably happen.\n  -- NOTE: There is no such test for regular inserted text because that is\n  -- pre-computed after 'textDocument/completion' inside complete-items (as\n  -- they are responsible for inserting text).\n\n  child.lua([[\n    MiniCompletion.config.lsp_completion.process_items = function(items, base)\n      for _, item in ipairs(items) do\n        if item.label == 'May' then\n          item.kind = vim.lsp.protocol.CompletionItemKind.Snippet\n          item.insertText = 'May $1 snippet'\n        end\n      end\n      return MiniCompletion.default_process_items(items, base)\n    end\n  ]])\n\n  local validate = function(ref_lines)\n    type_keys('i', 'May', '<C-Space>', '<C-n>')\n    -- - Wait for 'completionItem/resolve' request to be sent\n    sleep(default_info_delay + small_time)\n    type_keys('<C-y>')\n    eq(get_lines(), ref_lines)\n\n    type_keys('<C-c>')\n    set_lines({})\n    child.ensure_normal_mode()\n  end\n\n  -- mock_lsp_snippets({ 'Snippet $1 original' })\n  validate({ 'Resolved  May' })\n\n  -- Should handle error in 'completionItem/resolve' response\n  child.lua('_G.mock_error = { [\"completionItem/resolve\"] = \"Error\" }')\n  validate({ 'May  snippet' })\nend\n\nT['Snippets']['can be inserted together with additional text edits'] = function()\n  local kind_function = child.lua_get('vim.lsp.protocol.CompletionItemKind.Function')\n  local format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n\n  --stylua: ignore\n  local items = {\n    {\n      label = 'Snip A', kind = kind_function, insertText = 'Snippet A $1', insertTextFormat = format_snippet,\n      additionalTextEdits = {\n        {\n          newText = 'New text on first line',\n          range = { start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 0 } },\n        },\n      }\n    },\n  }\n  mock_lsp_items(items)\n\n  local validate = function(ref_lines, ref_cursor)\n    type_keys('i', '<C-Space>', '<C-n>', '<C-y>')\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n    eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\n\n    type_keys('<C-c>')\n    child.ensure_normal_mode()\n    set_lines({ '' })\n  end\n\n  -- A usual case of additional text edit not near completed item\n  set_lines({ '', '' })\n  set_cursor(2, 0)\n  validate({ 'New text on first line', 'Snippet A ' }, { 2, 10 })\n\n  -- An unusual case of additional text edit in the same line\n  set_lines({ '' })\n  set_cursor(1, 0)\n  validate({ 'New text on first lineSnippet A ' }, { 1, 32 })\n\n  -- Additional text edits should be applied after removing inserted\n  -- non-keyword characters used to accept completion item\n  if child.fn.has('nvim-0.10') == 0 then\n    -- This is probably due to some fixed issue with extmarks\n    MiniTest.skip('Non-keyword character that inserts multiple characters can be used only on Neovim>=0.10 ')\n  end\n  items[1].additionalTextEdits[1].range = { start = { line = 0, character = 6 }, ['end'] = { line = 0, character = 6 } }\n  mock_lsp_items(items)\n  child.cmd('inoremap ( (abc)<Left><Left><Left>')\n\n  type_keys('i', '<C-Space>', '<C-n>', '(')\n  eq(get_lines(), { 'New text on first lineSnippet A ' })\n  eq(get_cursor(), { 1, 32 })\n  eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\nend\n\nT['Snippets']['respect covering `textEdit` in candidate'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('This has problems on Neovim<0.10') end\n\n  child.set_size(10, 25)\n\n  local kind_snippet = child.lua_get('vim.lsp.protocol.CompletionItemKind.Snippet')\n  local items = {\n    {\n      label = 'Snip A',\n      kind = kind_snippet,\n      textEdit = {\n        newText = 'Snippet A $1',\n        -- Multi-line range to replace when inserting snippet\n        range = { start = { line = 0, character = 1 }, ['end'] = { line = 1, character = 1 } },\n      },\n    },\n    {\n      label = 'Snip B',\n      kind = kind_snippet,\n      textEdit = {\n        newText = 'Snippet B $1',\n        -- Should remove `insert` range when inserting snippet\n        insert = { start = { line = 0, character = 2 }, ['end'] = { line = 0, character = 4 } },\n        replace = { start = { line = 0, character = 2 }, ['end'] = { line = 0, character = 5 } },\n      },\n    },\n    {\n      label = 'Snip C',\n      kind = kind_snippet,\n      textEdit = {\n        newText = 'Snippet C $1',\n        range = { start = { line = 0, character = 3 }, ['end'] = { line = 0, character = 4 } },\n      },\n      -- Additional text edits both before and after candidate text edit\n      additionalTextEdits = {\n        {\n          newText = 'X',\n          range = { start = { line = 0, character = 0 }, ['end'] = { line = 0, character = 2 } },\n        },\n        {\n          newText = 'Y',\n          range = { start = { line = 0, character = 5 }, ['end'] = { line = 0, character = 6 } },\n        },\n      },\n    },\n    {\n      label = 'Snip D',\n      kind = kind_snippet,\n      textEdit = {\n        newText = 'Snippet D $1',\n        -- Bad range that does not cover starting position. Should not result\n        -- in side effects like \"extra `x` characters\".\n        range = { start = { line = 2, character = 1 }, ['end'] = { line = 2, character = 2 } },\n      },\n    },\n  }\n\n  mock_lsp_items(items)\n  local validate = function(item, ref_lines, ref_cursor)\n    mock_lsp_items({ item })\n    set_lines({ 'ab Sdef', 'gh' })\n    set_cursor(1, 4)\n    type_keys('i', '<C-Space>', '<C-n>', '<C-y>')\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n    eq(child.fn.mode(), 'i')\n    eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\n\n    type_keys('<C-c>', '<Esc>')\n  end\n\n  validate(items[1], { 'aSnippet A h' }, { 1, 11 })\n  validate(items[2], { 'abSnippet B def', 'gh' }, { 1, 12 })\n  validate(items[3], { 'X Snippet C dYf', 'gh' }, { 1, 12 })\n  validate(items[4], { 'ab def', 'gSnippet D ' }, { 2, 11 })\nend\n\nT['Snippets'][\"LSP server from 'mini.snippets'\"] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lsp.buf_detach_client(0, child.lua_get('_G.months_lsp_client_id'))\n\n      child.lua([[\n        MiniSnippets.config.snippets = {\n          { prefix = 'aa', body = 'Snippet $1 aa', desc = 'The aa snippet' },\n          { prefix = 'bb cc', body = 'Snippet $1 bb cc', desc = 'The bb cc snippet' },\n        }\n      ]])\n\n      child.set_size(10, 35)\n    end,\n  },\n})\n\nT['Snippets'][\"LSP server from 'mini.snippets'\"]['works'] = function()\n  child.lua('MiniSnippets.start_lsp_server()')\n\n  type_keys('i', '<C-Space>', '<C-n>')\n  sleep(default_info_delay + small_time)\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  type_keys(' ')\n  eq(get_lines(), { 'Snippet  aa' })\n  eq(get_cursor(), { 1, 8 })\n  eq(child.fn.mode(), 'i')\n  eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\nend\n\nT['Snippets'][\"LSP server from 'mini.snippets'\"]['works with in-server matching'] = function()\n  child.lua([[\n    local match = function(snippets)\n      local res = { snippets[2] }\n      res[1].region = { from = { line = 1, col = 1 }, to = { line = 1, col = vim.fn.col('.') - 1 } }\n      return res\n    end\n    MiniSnippets.start_lsp_server({ match = match })\n  ]])\n\n  type_keys('i', 'bb c', '<C-Space>')\n  child.expect_screenshot()\n  type_keys('<C-n>', '<C-y>')\n  eq(get_lines(), { 'Snippet  bb cc' })\n  eq(get_cursor(), { 1, 8 })\n  eq(child.lua_get('#MiniSnippets.session.get(true)'), 1)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_cursorword.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('cursorword', config) end\nlocal unload_module = function() child.mini_unload('cursorword') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\n--stylua: ignore end\n\n-- Make helpers\nlocal word_is_highlighted = function(word)\n  local general_n, current_n = 0, 0\n  local current_word_pattern = [[\\k*\\%#\\k*]]\n  local noncurrent_pattern = string.format([[\\(%s\\)\\@!\\&\\V\\<%s\\>]], current_word_pattern, word)\n\n  for _, m in ipairs(child.fn.getmatches()) do\n    if m.group == 'MiniCursorword' and m.pattern == noncurrent_pattern and m.priority == -1 then\n      general_n = general_n + 1\n    end\n    if m.group == 'MiniCursorwordCurrent' and m.pattern == current_word_pattern and m.priority == -1 then\n      current_n = current_n + 1\n    end\n  end\n  return general_n == 1 and current_n == 1\nend\n\nlocal get_match = function(hl_group)\n  return vim.tbl_filter(function(x) return x.group == hl_group end, child.fn.getmatches())\nend\n\n-- Data =======================================================================\nlocal example_lines = { 'aa', 'aa', 'aaa' }\n\n-- Time constants\nlocal default_delay = 100\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniCursorword)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniCursorword'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniCursorword'), 'gui=underline')\n  expect.match(child.cmd_capture('hi MiniCursorwordCurrent'), 'links to MiniCursorword')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniCursorword.config)'), 'table')\n\n  -- Check default values\n  eq(child.lua_get('MiniCursorword.config.delay'), 100)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ delay = 300 })\n  eq(child.lua_get('MiniCursorword.config.delay'), 300)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ delay = 'a' }, 'delay', 'number')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniCursorword'), 'gui=underline')\n  expect.match(child.cmd_capture('hi MiniCursorwordCurrent'), 'links to MiniCursorword')\nend\n\nT['setup()']['properly resets module highlighting'] = function()\n  child.lua('MiniCursorword.config.delay = 0')\n  set_lines({ 'aa a aaa aa a aaa', 'a aa aaa a aa aaa' })\n  set_cursor(1, 0)\n  eq(#child.fn.getmatches(), 2)\n\n  child.lua([[package.loaded['mini.cursorword'] = nil]])\n  load_module({ delay = 0 })\n  eq(#child.fn.getmatches(), 0)\n  set_cursor(2, 0)\n  eq(#child.fn.getmatches(), 2)\nend\n\n-- Integration tests ==========================================================\nT['Highlighting'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(5, 12)\n      child.lua('MiniCursorword.config.delay = 0')\n      set_lines({ 'a aa aaa', 'aa aaa a', 'aaa a aa' })\n      set_cursor(1, 0)\n    end,\n  },\n})\n\nT['Highlighting']['works'] = function() child.expect_screenshot() end\n\nT['Highlighting']['works on multibyte character'] = function()\n  set_lines({ 'ы ыы ыыы', 'ыы ыыы ы', 'ыыы ы ыы' })\n  set_cursor(1, 0)\n  child.expect_screenshot()\n\n  set_lines({ '  ', '  ', '  ' })\n  set_cursor(1, 0)\n  child.expect_screenshot()\nend\n\nT['Highlighting']['respects MiniCursorwordCurrent highlight group'] = function()\n  child.cmd('hi! MiniCursorwordCurrent gui=nocombine guifg=NONE guibg=NONE')\n  child.expect_screenshot()\nend\n\nT['Highlighting']['works with multiple windows'] = function()\n  child.set_size(5, 40)\n  child.cmd('vsplit | wincmd =')\n  set_cursor(2, 0)\n  child.expect_screenshot()\nend\n\nT['Highlighting']['can stop'] = function()\n  child.set_size(5, 15)\n  type_keys('i')\n  child.expect_screenshot()\nend\n\nT['Autohighlighting'] = new_set({\n  hooks = {\n    pre_case = function() set_lines(example_lines) end,\n  },\n})\n\nlocal validate_cursorword = function(delay)\n  set_cursor(2, 0)\n  eq(word_is_highlighted('aa'), false)\n  sleep(delay - small_time)\n  eq(word_is_highlighted('aa'), false)\n  sleep(small_time)\n  eq(word_is_highlighted('aa'), true)\nend\n\nT['Autohighlighting']['works'] = function() validate_cursorword(default_delay) end\n\nT['Autohighlighting']['respects `config.delay`'] = function()\n  child.lua('MiniCursorword.config.delay = ' .. (3 * default_delay))\n  validate_cursorword(3 * default_delay)\n\n  -- Should also use buffer local config\n  set_cursor(3, 0)\n  child.b.minicursorword_config = { delay = default_delay }\n  validate_cursorword(default_delay)\nend\n\nT['Autohighlighting']['removes highlight immediately after move'] = function()\n  set_cursor(2, 0)\n  sleep(default_delay)\n  eq(word_is_highlighted('aa'), true)\n  set_cursor(3, 0)\n  eq(child.fn.getmatches(), {})\nend\n\nlocal validate_immediate = function(move_command)\n  set_cursor(2, 0)\n  sleep(default_delay)\n  eq(word_is_highlighted('aa'), true)\n\n  local match_gen = get_match('MiniCursorword')\n  child.cmd(move_command)\n  child.poke_eventloop()\n  eq(word_is_highlighted('aa'), true)\n\n  -- Check that general match group didn't change (as word is same)\n  eq(match_gen, get_match('MiniCursorword'))\nend\n\nT['Autohighlighting']['highlights immediately inside current word'] = function() validate_immediate('normal! l') end\n\nT['Autohighlighting']['highlights immediately same word in other place'] = function() validate_immediate('normal! k') end\n\nT['Autohighlighting']['highlights only \"keyword\" symbols'] = function()\n  local validate_highlighted = function(cursor_pos, hl_word)\n    set_cursor(unpack(cursor_pos))\n    if hl_word == nil then\n      eq(child.fn.getmatches(), {})\n    else\n      eq(word_is_highlighted(hl_word), true)\n    end\n  end\n\n  child.lua('MiniCursorword.config.delay = 0')\n  set_lines({ 'a_111', '  ', 'aa bb', 'aa.bb', '!!!' })\n\n  validate_highlighted({ 1, 1 }, 'a_111')\n  validate_highlighted({ 1, 2 }, 'a_111')\n  validate_highlighted({ 2, 0 }, nil)\n  validate_highlighted({ 3, 1 }, 'aa')\n  validate_highlighted({ 3, 2 }, nil)\n  validate_highlighted({ 4, 0 }, 'aa')\n  validate_highlighted({ 4, 2 }, nil)\n  validate_highlighted({ 4, 3 }, 'bb')\n  validate_highlighted({ 5, 0 }, nil)\nend\n\nT['Autohighlighting']['stops in Insert mode'] = function()\n  set_cursor(2, 0)\n  sleep(default_delay)\n  eq(word_is_highlighted('aa'), true)\n  type_keys('i')\n  eq(word_is_highlighted('aa'), false)\nend\n\nT['Autohighlighting']['stops in Terminal mode'] = function()\n  set_cursor(2, 0)\n  sleep(default_delay)\n  eq(word_is_highlighted('aa'), true)\n  child.cmd('doautocmd TermEnter')\n  eq(word_is_highlighted('aa'), false)\nend\n\nT['Autohighlighting']['respects ModeChanged'] = function()\n  -- Add disabling in Visual mode\n  unload_module()\n  child.cmd([[\n      augroup VisualDisable\n        au!\n        au ModeChanged *:[vV\\x16]* lua vim.b.minicursorword_disable = true\n        au ModeChanged [vV\\x16]*:* lua vim.b.minicursorword_disable = false\n      augroup END\n    ]])\n  child.lua([[require('mini.cursorword').setup({ delay = 0 })]])\n\n  set_cursor(2, 0)\n  eq(word_is_highlighted('aa'), true)\n\n  type_keys('v')\n  eq(word_is_highlighted('aa'), false)\n\n  type_keys('v')\n  eq(word_is_highlighted('aa'), true)\nend\n\nT['Autohighlighting']['respects `vim.{g,b}.minicursorword_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    set_cursor(1, 1)\n\n    child[var_type].minicursorword_disable = true\n    set_cursor(1, 0)\n    sleep(default_delay)\n    eq(word_is_highlighted('aa'), false)\n\n    child[var_type].minicursorword_disable = false\n    set_cursor(1, 1)\n    sleep(default_delay)\n    eq(word_is_highlighted('aa'), true)\n  end,\n})\n\nT['Autohighlighting']['respects deferred `vim.{g,b}.minicursorword_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    set_cursor(1, 1)\n\n    local lua_cmd = string.format(\n      'vim.defer_fn(function() vim.%s.minicursorword_disable = true end, %d)',\n      var_type,\n      math.floor(0.5 * default_delay)\n    )\n    child.lua(lua_cmd)\n    set_cursor(1, 0)\n\n    sleep(default_delay)\n    eq(word_is_highlighted('aa'), false)\n  end,\n})\n\nreturn T\n"
  },
  {
    "path": "tests/test_deps.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('deps', config) end\nlocal unload_module = function() child.mini_unload('deps') end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nlocal islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nlocal test_dir = 'tests/dir-deps'\nlocal test_dir_absolute = vim.fs.normalize(vim.fn.fnamemodify(test_dir, ':p')):gsub('(.)/$', '%1')\nlocal test_opt_dir = test_dir_absolute .. '/pack/deps/opt'\nlocal test_snap_path = test_dir_absolute .. '/snapshots/snap'\nlocal test_log_path = test_dir_absolute .. '/mini-deps.log'\n\n-- Common test helpers\nlocal log_level = function(level)\n  if level == nil then return nil end\n  return child.lua_get('vim.log.levels.' .. level)\nend\n\nlocal clone_args = function(from, to)\n  --stylua: ignore\n  return {\n    'clone', '--quiet', '--filter=blob:none',\n    '--recurse-submodules', '--also-filter-submodules',\n    '--origin', 'origin', from, to,\n  }\nend\n\nlocal log_args = function(range)\n  return { 'log', '--pretty=format:%m %h | %ai | %an%d%n  %s%n', '--topo-order', '--decorate-refs=refs/tags', range }\nend\n\nlocal validate_confirm_buf = function(name)\n  eq(child.api.nvim_buf_get_name(0), 'minideps://' .. child.api.nvim_get_current_buf() .. '/' .. name)\n  eq(child.bo.buftype, 'acwrite')\n  eq(child.bo.filetype, 'minideps-confirm')\n  eq(#child.api.nvim_list_tabpages() > 1, true)\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\nend\n\nlocal validate_not_confirm_buf = function()\n  eq(#child.api.nvim_list_tabpages(), 1)\n  eq(child.bo.filetype ~= 'minideps-confirm', true)\nend\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal add = forward_lua('MiniDeps.add')\nlocal get_session = forward_lua('MiniDeps.get_session')\n\n-- Common mocks\nlocal mock_test_package = function(path)\n  path = path or test_dir_absolute\n  local lua_cmd = string.format(\n    [[local config = vim.deepcopy(MiniDeps.config)\n      config.path.package = %s\n      MiniDeps.setup(config)]],\n    vim.inspect(path)\n  )\n  child.lua(lua_cmd)\nend\n\nlocal mock_plugin = function(path)\n  local lua_dir = path .. '/lua'\n  child.fn.mkdir(lua_dir, 'p')\n  child.fn.writefile({ 'return {}' }, lua_dir .. '/module.lua')\nend\n\nlocal mock_timestamp = function(timestamp)\n  timestamp = timestamp or '2024-01-02 03:04:05'\n  local lua_cmd = string.format('vim.fn.strftime = function() return %s end', vim.inspect(timestamp))\n  child.lua(lua_cmd)\nend\n\nlocal mock_bad_env_vars = function()\n  child.fn.setenv('GIT_DIR', test_dir_absolute .. '/.git')\n  child.fn.setenv('GIT_WORK_TREE', test_dir_absolute)\nend\n\nlocal mock_hide_path = function(path)\n  path = path or test_dir_absolute\n  -- NOTE: use \"^\" as pattern separator because \"/\" can cause troubles\n  child.cmd(':%s^' .. child.fn.escape(path, ' /') .. '^MOCKDIR^')\n  child.bo.modified = false\nend\n\nlocal mock_spawn = function()\n  local mock_file = test_dir_absolute .. '/mocks/spawn.lua'\n  local lua_cmd = string.format('dofile(%s)', vim.inspect(mock_file))\n  child.lua(lua_cmd)\nend\n\nlocal get_spawn_log = function() return child.lua_get('_G.spawn_log') end\n\nlocal validate_git_spawn_log = function(ref_log)\n  local spawn_log = get_spawn_log()\n\n  local env_map = child.fn.environ()\n  -- Should never include environment variables that can affect Git operations\n  env_map.GIT_DIR, env_map.GIT_WORK_TREE = nil, nil\n  local ref_env_map = {}\n  for k, v in pairs(env_map) do\n    ref_env_map[k .. '=' .. tostring(v)] = true\n  end\n\n  local n = math.max(#spawn_log, #ref_log)\n  for i = 1, n do\n    local real, ref = spawn_log[i], ref_log[i]\n    if real == nil then\n      eq('Real spawn log does not have entry for present reference log entry', ref)\n    elseif ref == nil then\n      eq(real, 'Reference does not have entry for present spawn log entry')\n    elseif islist(ref) then\n      -- Assume default `git` options\n      local args = { '-c', 'gc.auto=0' }\n      vim.list_extend(args, ref)\n      local opts = { args = args, cwd = real.options.cwd, env = real.options.env }\n      local ref_val = { executable = 'git', options = opts }\n      eq(real, ref_val)\n    else\n      local opts = vim.deepcopy(ref)\n      -- Assume default `git` options\n      local args = { '-c', 'gc.auto=0' }\n      opts.args = vim.list_extend(args, opts.args)\n      opts.env = real.options.env\n      eq(real, { executable = 'git', options = opts })\n    end\n\n    -- Validate environment variables separately because it is a string array\n    -- without order guarantee\n    local real_env_map = {}\n    for _, v in ipairs(real.options.env) do\n      real_env_map[v] = true\n    end\n    eq(real_env_map, ref_env_map)\n  end\nend\n\nlocal get_process_log = function() return child.lua_get('_G.process_log') end\n\n-- Work with notifications\nlocal mock_notify = function()\n  child.lua([[\n    _G.notify_log = {}\n    vim.notify = function(...) table.insert(_G.notify_log, { ... }) end\n  ]])\nend\n\nlocal get_notify_log = function() return child.lua_get('_G.notify_log') end\n\nlocal validate_notifications = function(ref_log, msg_pattern)\n  local notify_log = get_notify_log()\n  local n = math.max(#notify_log, #ref_log)\n  for i = 1, n do\n    local real, ref = notify_log[i], ref_log[i]\n    if real == nil then\n      eq('Real notify log does not have entry for present reference log entry', ref)\n    elseif ref == nil then\n      eq(real, 'Reference does not have entry for present notify log entry')\n    else\n      local expect_msg = msg_pattern and expect.match or eq\n      expect_msg(real[1], ref[1])\n      eq(real[2], log_level(ref[2]))\n    end\n  end\nend\n\nlocal clear_notify_log = function() return child.lua('_G.notify_log = {}') end\n\n-- Common validators\nlocal is_in_rtp = function(path)\n  path = child.fs.normalize(path)\n  for _, p in ipairs(child.api.nvim_list_runtime_paths()) do\n    if path == child.fs.normalize(p) then return true end\n  end\n  return false\nend\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\nlocal micro_time = 1\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Load module\n      load_module()\n\n      -- Make more comfortable screenshots\n      child.o.laststatus = 0\n      child.o.ruler = false\n      child.o.showtabline = 0\n\n      -- Mock `vim.notify()`\n      mock_notify()\n\n      -- Mock `vim.loop.spawn()`\n      mock_spawn()\n\n      -- Mock getting reproducible timestamp\n      mock_timestamp()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniDeps)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniDeps'), 1)\n\n  -- User commands\n  local has_user_command = function(cmd) eq(child.fn.exists(':' .. cmd), 2) end\n  has_user_command('DepsAdd')\n  has_user_command('DepsUpdate')\n  has_user_command('DepsUpdateOffline')\n  has_user_command('DepsShowLog')\n  has_user_command('DepsClean')\n  has_user_command('DepsSnapSave')\n  has_user_command('DepsSnapLoad')\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  local is_010 = child.fn.has('nvim-0.10') == 1\n  has_highlight('MiniDepsChangeAdded', 'links to ' .. (is_010 and 'Added' or 'diffAdded'))\n  has_highlight('MiniDepsChangeRemoved', 'links to ' .. (is_010 and 'Removed' or 'diffRemoved'))\n  has_highlight('MiniDepsHint', 'links to DiagnosticHint')\n  has_highlight('MiniDepsInfo', 'links to DiagnosticInfo')\n  has_highlight('MiniDepsPlaceholder', 'links to Comment')\n  has_highlight('MiniDepsTitle', 'links to Title')\n  has_highlight('MiniDepsTitleError', 'links to DiffDelete')\n  has_highlight('MiniDepsTitleSame', 'links to DiffText')\n  has_highlight('MiniDepsTitleUpdate', 'links to DiffAdd')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniDeps.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniDeps.config.' .. field), value) end\n\n  expect_config('job.n_threads', vim.NIL)\n  expect_config('job.timeout', 30000)\n\n  expect_config('path.package', child.fn.stdpath('data') .. '/site')\n  expect_config('path.snapshot', child.fn.stdpath('config') .. '/mini-deps-snap')\n  expect_config('path.log', child.fn.stdpath('state') .. '/mini-deps.log')\n\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ silent = true })\n  eq(child.lua_get('MiniDeps.config.silent'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ job = 'a' }, 'job', 'table')\n  expect_config_error({ job = { n_threads = 'a' } }, 'job.n_threads', 'number')\n  expect_config_error({ job = { timeout = 'a' } }, 'job.timeout', 'number')\n\n  expect_config_error({ path = 'a' }, 'path', 'table')\n  expect_config_error({ path = { package = 1 } }, 'path.package', 'string')\n  expect_config_error({ path = { snapshot = 1 } }, 'path.snapshot', 'string')\n  expect_config_error({ path = { log = 1 } }, 'path.log', 'string')\n\n  expect_config_error({ silent = 'a' }, 'silent', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniDepsHint'), 'links to DiagnosticHint')\nend\n\nT['setup()'][\"prepends 'packpath' with package path\"] = function()\n  mock_test_package(test_dir_absolute)\n  eq(vim.startswith(child.o.packpath, test_dir_absolute), true)\nend\n\nT['setup()']['clears session'] = function()\n  load_module({ path = { package = test_dir_absolute } })\n  add('plugin_1')\n  eq(#get_session(), 1)\n\n  load_module({ path = { package = test_dir_absolute } })\n  eq(#get_session(), 0)\nend\n\nT['add()'] = new_set({ hooks = { pre_case = mock_test_package } })\n\nT['add()']['works for present plugins'] = new_set({ parametrize = { { 'plugin_1' }, { { name = 'plugin_1' } } } }, {\n  test = function(spec)\n    local ref_path = test_opt_dir .. '/plugin_1'\n    eq(is_in_rtp(ref_path), false)\n    eq(get_session(), {})\n\n    add(spec)\n\n    eq(is_in_rtp(ref_path), true)\n    eq(is_in_rtp(ref_path .. '/after'), true)\n    eq(get_session(), { { name = 'plugin_1', path = ref_path, hooks = {}, depends = {} } })\n\n    -- No CLI process should be run as plugin is already present\n    eq(get_spawn_log(), {})\n\n    -- Should load 'plugin/', 'after/plugin/', etc.\n    eq(child.lua_get('type(_G.plugin_log)'), 'table')\n  end,\n})\n\nT['add()']['infers name from source'] = new_set({\n  parametrize = {\n    { 'us-er1/plu-gin_0.nvim' },\n    { 'https://github.com/us-er1/plu-gin_0.nvim' },\n    { { source = 'us-er1/plu-gin_0.nvim' } },\n    { { source = 'https://github.com/us-er1/plu-gin_0.nvim' } },\n  },\n}, {\n  test = function(spec)\n    local ref_path = test_opt_dir .. '/plu-gin_0.nvim'\n    local ref_source = 'https://github.com/us-er1/plu-gin_0.nvim'\n    add(spec)\n    eq(is_in_rtp(ref_path), true)\n    eq(get_session(), { { source = ref_source, name = 'plu-gin_0.nvim', path = ref_path, hooks = {}, depends = {} } })\n  end,\n})\n\nT['add()']['uses only valid characters when infers source'] = function()\n  add('git@github.com:user/plugin_1')\n  local ref_path = test_opt_dir .. '/plugin_1'\n  eq(\n    get_session(),\n    { { source = 'git@github.com:user/plugin_1', name = 'plugin_1', path = ref_path, hooks = {}, depends = {} } }\n  )\nend\n\nT['add()'][\"properly sources 'plugin/' and 'after/plugin/'\"] = function()\n  add({ name = 'plugin_1', depends = { 'plugin_2' } })\n  --stylua: ignore\n  local ref_plugin_log = {\n          'plugin/plug_2.lua',\n          'plugin/plug_1.vim',       'plugin/plug_1.lua',       'plugin/subdir/plug_1_sub.lua',\n    'after/plugin/plug_2.lua',\n    'after/plugin/plug_1.lua', 'after/plugin/plug_1.vim', 'after/plugin/subdir/plug_1_sub.lua',\n  }\n  eq(child.lua_get('_G.plugin_log'), ref_plugin_log)\nend\n\nT['add()'][\"does not source 'after/plugin/' when not needed\"] = function()\n  -- During startup\n  local setup_cmd =\n    string.format(\"lua require('mini.deps').setup({ path = { package = %s } })\", vim.inspect(test_dir_absolute))\n  child.restart({ '-u', 'NONE', '--cmd', 'set rtp+=.', '--cmd', setup_cmd, '--cmd', \"lua MiniDeps.add('plugin_1')\" })\n\n  --stylua: ignore\n  eq(child.lua_get('_G.plugin_log'), {\n    -- 'plugin/' directory gets sourced both as part of startup and `:packadd`\n          'plugin/plug_1.vim',       'plugin/plug_1.lua',       'plugin/subdir/plug_1_sub.lua',\n          'plugin/plug_1.vim',       'plugin/plug_1.lua',       'plugin/subdir/plug_1_sub.lua',\n    -- But sourcing 'after/plugin/' in 'mini.deps' should not duplicate startup\n    'after/plugin/plug_1.vim', 'after/plugin/plug_1.lua', 'after/plugin/subdir/plug_1_sub.lua',\n  })\n\n  -- When 'loadplugins = false'\n  child.restart({ '-u', 'NONE', '--cmd', 'set rtp+=.', '--cmd', setup_cmd })\n  child.o.loadplugins = false\n  add('plugin_1')\n\n  -- - `:packadd` does not recognize 'loadplugins' and thus sources them\n  --   But 'after/plugin/' should not be sourced\n  eq(child.lua_get('_G.plugin_log'), { 'plugin/plug_1.vim', 'plugin/plug_1.lua', 'plugin/subdir/plug_1_sub.lua' })\nend\n\nT['add()']['can update session data'] = function()\n  add('plugin_1')\n  add('plugin_2')\n  eq(get_session(), {\n    { path = test_opt_dir .. '/plugin_1', name = 'plugin_1', depends = {}, hooks = {} },\n    { path = test_opt_dir .. '/plugin_2', name = 'plugin_2', depends = {}, hooks = {} },\n  })\n\n  add({ source = 'my_source', name = 'plugin_1' })\n  add({ name = 'plugin_2', depends = { 'plugin_3' } })\n  eq(get_session(), {\n    { path = test_opt_dir .. '/plugin_1', name = 'plugin_1', source = 'my_source', depends = {}, hooks = {} },\n    { path = test_opt_dir .. '/plugin_2', name = 'plugin_2', depends = { 'plugin_3' }, hooks = {} },\n    { path = test_opt_dir .. '/plugin_3', name = 'plugin_3', depends = {}, hooks = {} },\n  })\n\n  child.lua([[\n    MiniDeps.add({ name = 'plugin_3', hooks = { post_checkout = function() return 'Hello' end } })\n    _G.hello = MiniDeps.get_session()[3].hooks.post_checkout()\n  ]])\n  eq(child.lua_get('_G.hello'), 'Hello')\nend\n\nT['add()']['respects plugins from \"start\" directory'] = function()\n  local start_dir = test_dir_absolute .. '/pack/deps/start'\n  mock_plugin(start_dir .. '/plug')\n  MiniTest.finally(function() child.fn.delete(start_dir, 'rf') end)\n  mock_test_package(test_dir_absolute)\n\n  add('user/plug')\n  eq(get_session(), {\n    { path = start_dir .. '/plug', name = 'plug', source = 'https://github.com/user/plug', hooks = {}, depends = {} },\n  })\n\n  -- No CLI process should be run as plugin is already present\n  eq(get_spawn_log(), {})\nend\n\nT['add()']['allows nested dependencies'] = function()\n  add({\n    name = 'plugin_1',\n    depends = {\n      { source = 'user/plugin_2', depends = {\n        { name = 'plugin_3', checkout = 'hello' },\n      } },\n    },\n  })\n  eq(get_session(), {\n    { path = test_opt_dir .. '/plugin_3', name = 'plugin_3', checkout = 'hello', depends = {}, hooks = {} },\n    {\n      path = test_opt_dir .. '/plugin_2',\n      name = 'plugin_2',\n      source = 'https://github.com/user/plugin_2',\n      depends = { { checkout = 'hello', name = 'plugin_3' } },\n      hooks = {},\n    },\n    {\n      path = test_opt_dir .. '/plugin_1',\n      name = 'plugin_1',\n      depends = {\n        { source = 'user/plugin_2', depends = {\n          { checkout = 'hello', name = 'plugin_3' },\n        } },\n      },\n      hooks = {},\n    },\n  })\nend\n\nT['add()']['does not error on cyclic dependencies'] = function()\n  add({ name = 'plugin_1', depends = { 'plugin_1' } })\n  add({ source = 'user/plugin_2', depends = { 'plugin_2' } })\n  add({ source = 'user/plugin_3', depends = { 'new_user/plugin_3' } })\n  eq(get_session(), {\n    { path = test_opt_dir .. '/plugin_1', name = 'plugin_1', depends = { 'plugin_1' }, hooks = {} },\n    {\n      path = test_opt_dir .. '/plugin_2',\n      name = 'plugin_2',\n      source = 'https://github.com/user/plugin_2',\n      depends = { 'plugin_2' },\n      hooks = {},\n    },\n    {\n      path = test_opt_dir .. '/plugin_3',\n      name = 'plugin_3',\n      source = 'https://github.com/user/plugin_3',\n      depends = { 'new_user/plugin_3' },\n      hooks = {},\n    },\n  })\nend\n\nT['add()']['validates specification'] = function()\n  local validate = function(spec, err_pattern)\n    expect.error(function() add(spec) end, err_pattern)\n  end\n\n  validate('', '`name`.*should not be empty')\n  validate(1, 'table')\n  validate({}, '`source` or `name`')\n  validate({ source = 1 }, '`source` or `name`')\n  validate({ source = 1, name = 'plugin_1' }, '`source`.*string')\n  validate({ name = 1, source = 'user/plugin_1' }, '`name`.*string')\n  validate({ name = 'user/plugin_1' }, '`name`.*not contain \"/\"')\n  validate({ name = '' }, '`name`.*not be empty')\n  validate({ checkout = 1, name = 'plugin_1' }, '`checkout`.*string')\n  validate({ monitor = 1, name = 'plugin_1' }, '`monitor`.*string')\n  validate({ hooks = 1, name = 'plugin_1' }, '`hooks`.*table')\n  validate({ hooks = { pre_install = '' }, name = 'plugin_1' }, '`hooks%.pre_install`.*callable')\n  validate({ hooks = { post_install = '' }, name = 'plugin_1' }, '`hooks%.post_install`.*callable')\n  validate({ hooks = { pre_checkout = '' }, name = 'plugin_1' }, '`hooks%.pre_checkout`.*callable')\n  validate({ hooks = { post_checkout = '' }, name = 'plugin_1' }, '`hooks%.post_checkout`.*callable')\n  validate({ depends = 1, name = 'plugin_1' }, '`depends`.*array')\n  validate({ depends = { name = 'plugin_2' }, name = 'plugin_1' }, '`depends`.*array')\n\n  -- Should also validate inside dependencies\n  validate({ depends = { {} }, name = 'plugin_1' }, '`source` or `name`')\n  validate({ depends = { { name = 'plugin_2', depends = { {} } } }, name = 'plugin_1' }, '`source` or `name`')\nend\n\nT['add()']['validates `opts`'] = function()\n  expect.error(function() add('plugin_1', 'a') end, '`opts`.*table')\n  expect.error(function() add('plugin_1', { checkout = 'branch' }) end, '`add%(%)`.*only single spec')\nend\n\nT['add()']['respects `opts.bang`'] = function()\n  add('plugin_1', { bang = true })\n  eq(child.lua_get('_G.plugin_log'), vim.NIL)\nend\n\nT['add()']['does not modify input'] = function()\n  child.lua([[\n    _G.spec = {\n      name = 'plugin_1',\n      hooks = { post_update = function() end },\n      depends = { 'plugin_2' },\n    }\n    _G.spec_ref = vim.deepcopy(_G.spec)\n    MiniDeps.add(_G.spec)\n  ]])\n  eq(child.lua_get('#MiniDeps.get_session()'), 2)\n  eq(child.lua_get('vim.deep_equal(_G.spec, _G.spec_ref)'), true)\nend\n\nT['add()']['Install'] = new_set({\n  hooks = {\n    pre_case = function()\n      mock_test_package()\n\n      -- Mock `vim.fn.isdirectory` to always say that there is a directory to\n      -- simulate side-effect of `git clone`\n      child.lua('vim.fn.isdirectory = function() return 1 end')\n    end,\n  },\n})\n\nT['add()']['Install']['works'] = function()\n  mock_bad_env_vars()\n  local ref_environ = child.fn.environ()\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone\n      { out = 'sha0head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      { out = 'origin/main' },       -- Check if `main` is origin branch\n      { out = 'sha0head' },          -- Get commit of `origin/main`\n      {},                            -- Stash changes\n      {},                            -- Checkout changes\n    }\n\n    -- Mock non-trivial cloning duration\n    _G.process_mock_data = { { duration = 5 } }\n  ]])\n  add('user/new_plugin')\n\n  -- Should result into a proper sequence of CLI runs\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    clone_args('https://github.com/user/new_plugin', test_opt_dir .. '/new_plugin'),\n    {\n      args = { 'rev-list', '-1', 'HEAD' },\n      cwd = test_opt_dir .. '/new_plugin',\n    },\n    { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' },\n    { 'rev-list', '-1', 'origin/main' },\n\n    -- NOTE: Does not actually checkout because current commit is mocked the\n    -- same as target\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- All processes and streams should be properly closed\n  --stylua: ignore\n  eq(\n    get_process_log(),\n    {\n      'Stream out for process 1 was closed.', 'Stream err for process 1 was closed.', 'Process 1 was closed.',\n      'Stream out for process 2 was closed.', 'Stream err for process 2 was closed.', 'Process 2 was closed.',\n      'Stream out for process 3 was closed.', 'Stream err for process 3 was closed.', 'Process 3 was closed.',\n      'Stream out for process 4 was closed.', 'Stream err for process 4 was closed.', 'Process 4 was closed.',\n      'Stream out for process 5 was closed.', 'Stream err for process 5 was closed.', 'Process 5 was closed.',\n      'Stream out for process 6 was closed.', 'Stream err for process 6 was closed.', 'Process 6 was closed.',\n    }\n  )\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/1) Installed `new_plugin`', 'INFO' },\n  }\n  validate_notifications(ref_notify_log)\n\n  -- Should not affect any environment variables\n  eq(child.fn.environ(), ref_environ)\nend\n\nT['add()']['Install']['checks for executable Git'] = function()\n  child.lua([[\n    _G.stdio_queue = { { err = 'No Git'} }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n  expect.error(function() add('user/new_plugin') end, 'Could not find executable `git` CLI tool')\nend\n\nT['add()']['Install']['reacts to early Git version'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.35.10'}, -- Check Git executable\n      {},                             -- Clone\n      { out = 'sha0head' },           -- Get `HEAD`\n      { out = 'origin/main' },        -- Get default branch\n      { out = 'origin/main' },        -- Check if `main` is origin branch\n      { out = 'sha0head' },           -- Get commit of `origin/main`\n      {},                             -- Stash changes\n      {},                             -- Checkout changes\n    }\n  ]])\n  add('user/new_plugin')\n\n  -- Should result into a proper sequence of CLI runs\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    {\n      'clone', '--quiet', '--filter=blob:none', '--recurse-submodules', '--origin', 'origin',\n      'https://github.com/user/new_plugin', test_opt_dir .. '/new_plugin',\n    },\n    {\n      args = { 'rev-list', '-1', 'HEAD' },\n      cwd = test_opt_dir .. '/new_plugin',\n    },\n    { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' },\n    { 'rev-list', '-1', 'origin/main' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['add()']['Install']['checks out non-default target'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone\n      { out = 'sha0head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      { out = 'origin/hello' },      -- Check if `hello` is origin branch\n      { out = 'new0hello' },         -- Get commit of `hello`\n      {},                            -- Stash changes\n      {},                            -- Checkout changes\n    }\n\n    -- Mock non-trivial cloning duration\n    _G.process_mock_data = { { duration = 5 } }\n  ]])\n  add({ source = 'user/new_plugin', checkout = 'hello' })\n\n  -- Should result into a proper sequence of CLI runs\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    clone_args('https://github.com/user/new_plugin', test_opt_dir .. '/new_plugin'),\n    {\n      args = { 'rev-list', '-1', 'HEAD' },\n      cwd = test_opt_dir .. '/new_plugin',\n    },\n    -- NOTE: Default branch is still checked because `monitor` is `nil`\n    { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/hello' },\n    { 'rev-list', '-1', 'origin/hello' },\n    { 'stash', '--quiet', '--message', '(mini.deps) 2024-01-02 03:04:05 Stash before checkout' },\n    { 'checkout', '--quiet', 'new0hello' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/1) Installed `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/1) Checked out `hello` in `new_plugin`', 'INFO' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['can checkout to a not branch'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone\n      { out = 'sha0head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      { out = '' },                  -- Check if `stable_tag` is origin branch (it is not)\n      { out = 'new0hello' },         -- Get commit of `stable_tag`\n      {},                            -- Stash changes\n      {},                            -- Checkout changes\n    }\n  ]])\n  add({ source = 'user/new_plugin', checkout = 'stable_tag' })\n\n  -- Should result into a proper sequence of CLI runs\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    clone_args('https://github.com/user/new_plugin', test_opt_dir .. '/new_plugin'),\n    {\n      args = { 'rev-list', '-1', 'HEAD' },\n      cwd = test_opt_dir .. '/new_plugin',\n    },\n    -- NOTE: Default branch is still checked because `monitor` is `nil`\n    { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/stable_tag' },\n    -- Get commit of specifically 'stable_tag' and not 'origin/stable_tag'\n    { 'rev-list', '-1', 'stable_tag' },\n    { 'stash', '--quiet', '--message', '(mini.deps) 2024-01-02 03:04:05 Stash before checkout' },\n    { 'checkout', '--quiet', 'new0hello' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/1) Installed `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/1) Checked out `stable_tag` in `new_plugin`', 'INFO' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['installs dependencies in parallel'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone dep_plugin_2\n      {},                            -- Clone dep_plugin_1\n      {},                            -- Clone new_plugin\n      { out = 'sha2head' },          -- Get `HEAD` in dep_plugin_2\n      { out = 'sha1head' },          -- Get `HEAD` in dep_plugin_1\n      { out = 'sha0head' },          -- Get `HEAD` in new_plugin\n      { out = 'origin/trunk' },      -- Get default branch in dep_plugin_2\n      { out = 'origin/master' },     -- Get default branch in dep_plugin_1\n      { out = 'origin/main' },       -- Get default branch in new_plugin\n      { out = 'origin/trunk' },      -- Check if `trunk`  is origin branch in dep_plugin_2\n      { out = 'origin/master' },     -- Check if `master` is origin branch in dep_plugin_1\n      { out = 'origin/main' },       -- Check if `main`   is origin branch in new_plugin\n      { out = 'sha2head' },          -- Get commit of `trunk`  in dep_plugin_2\n      { out = 'new1head' },          -- Get commit of `master` in dep_plugin_1\n      { out = 'sha0head' },          -- Get commit of `main`   in new_plugin\n      {},                            -- Stash changes in dep_plugin_1\n      {},                            -- Checkout changes in dep_plugin_1\n    }\n\n    -- Mock non-trivial cloning duration\n    _G.process_mock_data = { [2] = { duration = 50 }, [3] = { duration = 30 }, [4] = { duration = 40 } }\n  ]])\n  local start_time = child.loop.hrtime()\n  add({\n    source = 'user/new_plugin',\n    depends = { { source = 'user/dep_plugin_1', checkout = 'master', depends = { 'user/dep_plugin_2' } } },\n  })\n  local duration = 0.000001 * (child.loop.hrtime() - start_time)\n  eq(50 <= duration and duration < 120, true)\n\n  -- Should result into a proper sequence of CLI runs\n  local cwd_new_plugin, cwd_dep_plugin_1, cwd_dep_plugin_2 =\n    test_opt_dir .. '/new_plugin', test_opt_dir .. '/dep_plugin_1', test_opt_dir .. '/dep_plugin_2'\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n\n    clone_args('https://github.com/user/dep_plugin_2', cwd_dep_plugin_2),\n    clone_args('https://github.com/user/dep_plugin_1', cwd_dep_plugin_1),\n    clone_args('https://github.com/user/new_plugin', cwd_new_plugin),\n\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_dep_plugin_2 },\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_dep_plugin_1 },\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_new_plugin },\n\n    -- NOTE: Default branch is still checked because `monitor` is `nil`\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_dep_plugin_2 },\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_dep_plugin_1 },\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_new_plugin },\n\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/trunk' }, cwd = cwd_dep_plugin_2 },\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/master' }, cwd = cwd_dep_plugin_1 },\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' }, cwd = cwd_new_plugin },\n\n    { args = { 'rev-list', '-1', 'origin/trunk' }, cwd = cwd_dep_plugin_2 },\n    { args = { 'rev-list', '-1', 'origin/master' }, cwd = cwd_dep_plugin_1 },\n    { args = { 'rev-list', '-1', 'origin/main' }, cwd = cwd_new_plugin },\n\n    { args = { 'stash', '--quiet', '--message', '(mini.deps) 2024-01-02 03:04:05 Stash before checkout' }, cwd = cwd_dep_plugin_1 },\n\n    { args = { 'checkout', '--quiet', 'new1head' }, cwd = cwd_dep_plugin_1 },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    -- NOTE: Cloning exit notifications are done immediately after job is done,\n    -- not in a session order\n    { '(mini.deps) (1/3) Installed `dep_plugin_1`', 'INFO' },\n    { '(mini.deps) (2/3) Installed `new_plugin`', 'INFO' },\n    { '(mini.deps) (3/3) Installed `dep_plugin_2`', 'INFO' },\n    { '(mini.deps) (1/1) Checked out `master` in `dep_plugin_1`', 'INFO' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['can handle both present and not present plugins'] = new_set({\n  parametrize = {\n    -- Present target, not present dependency\n    { { source = 'user/plugin_1', depends = { 'user/new_plugin' } } },\n    -- Present dependency, not present target\n    { { source = 'user/new_plugin', depends = { 'user/plugin_1' } } },\n  },\n}, {\n  test = function()\n    local validate = function(spec, clone_name)\n      -- Make clean mock\n      mock_spawn()\n\n      child.lua([[\n        _G.stdio_queue = {\n          { out = 'git version 2.43.0'}, -- Check Git executable\n          {},                            -- Clone\n          { out = 'sha0head' },          -- Get `HEAD`\n          { out = 'origin/main' },       -- Get default branch\n          { out = 'origin/main' },       -- Check if `main` is origin branch\n          { out = 'sha0head' },          -- Get commit of `origin/main`\n          {},                            -- Stash changes\n          {},                            -- Checkout changes\n        }\n      ]])\n      add(spec)\n\n      -- Should result into a proper sequence of CLI runs\n      --stylua: ignore\n      local ref_git_spawn_log = {\n        { args = { 'version' }, cwd = child.fn.getcwd() },\n        clone_args('https://github.com/user/new_plugin', test_opt_dir .. '/new_plugin'),\n        {\n          args = { 'rev-list', '-1', 'HEAD' },\n          cwd = test_opt_dir .. '/new_plugin',\n        },\n        { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n        { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' },\n        { 'rev-list', '-1', 'origin/main' },\n      }\n      validate_git_spawn_log(ref_git_spawn_log)\n    end\n  end,\n})\n\nT['add()']['Install']['properly executes `*_install` hooks'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone dep_plugin\n      {},                            -- Clone new_plugin\n      { out = 'sha1head' },          -- Get `HEAD` in dep_plugin\n      { out = 'sha0head' },          -- Get `HEAD` in new_plugin\n      { out = 'origin/master' },     -- Get default branch in dep_plugin\n      { out = 'origin/main' },       -- Get default branch in new_plugin\n      { out = 'origin/master' },     -- Check if `master` is origin branch in dep_plugin\n      { out = 'origin/main' },       -- Check if `main`   is origin branch in new_plugin\n      { out = 'new1head' },          -- Get commit of `master` in dep_plugin\n      { out = 'sha0head' },          -- Get commit of `main`   in new_plugin\n      {},                            -- Stash changes in dep_plugin\n      {},                            -- Checkout changes in dep_plugin\n    }\n\n    -- Mock non-trivial cloning duration to simulate out of order finish\n    _G.process_mock_data = { [2] = { duration = 10 }, [3] = { duration = 5 } }\n\n    -- Add plugin with dependency and hooks\n    _G.args = {}\n    local make_hook = function(msg)\n      return function(...)\n        table.insert(_G.args, { msg, { ... } })\n        vim.notify(msg)\n      end\n    end\n\n    local dep_spec = {\n      source = 'user/dep_plugin',\n      hooks = {\n        pre_install = make_hook('Dependency pre_install'),\n        post_install = make_hook('Dependency post_install'),\n      },\n    }\n    local spec = {\n      source = 'user/new_plugin',\n      depends = { dep_spec },\n      hooks = {\n        pre_install = make_hook('Target pre_install'),\n        post_install = make_hook('Target post_install'),\n      },\n    }\n\n    MiniDeps.add(spec)\n  ]])\n\n  -- Should be called with proper arguments\n  local cwd_new_plugin, cwd_dep_plugin = test_opt_dir .. '/new_plugin', test_opt_dir .. '/dep_plugin'\n  local ref_args = {\n    {\n      'Dependency pre_install',\n      { { path = cwd_dep_plugin, source = 'https://github.com/user/dep_plugin', name = 'dep_plugin' } },\n    },\n    {\n      'Target pre_install',\n      { { path = cwd_new_plugin, source = 'https://github.com/user/new_plugin', name = 'new_plugin' } },\n    },\n    {\n      'Dependency post_install',\n      { { path = cwd_dep_plugin, source = 'https://github.com/user/dep_plugin', name = 'dep_plugin' } },\n    },\n    {\n      'Target post_install',\n      { { path = cwd_new_plugin, source = 'https://github.com/user/new_plugin', name = 'new_plugin' } },\n    },\n  }\n  eq(child.lua_get('_G.args'), ref_args)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    -- Hooks are executed in a session order\n    { 'Dependency pre_install' },\n    { 'Target pre_install' },\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    -- Cloning exit notifications are done after job is finished\n    { '(mini.deps) (1/2) Installed `new_plugin`', 'INFO' },\n    { '(mini.deps) (2/2) Installed `dep_plugin`', 'INFO' },\n    { '(mini.deps) (1/1) Checked out `master` in `dep_plugin`', 'INFO' },\n    -- Hooks are executed in a session order\n    { 'Dependency post_install' },\n    { 'Target post_install' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['handles errors in hooks'] = function()\n  child.lua([[_G.stdio_queue = { { out = 'git version 2.43.0'} } -- Check Git executable]])\n  child.lua([[\n    MiniDeps.add({\n      source = 'user/new_plugin',\n      hooks = { pre_install = function() error('Error in `pre_install`') end },\n    })\n  ]])\n  --stylua: ignore\n  validate_notifications({\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    { '(mini.deps) Error executing pre_install hook in `new_plugin`:\\n[string \"<nvim>\"]:3: Error in `pre_install`', 'ERROR' },\n    { '(mini.deps) (1/1) Installed `new_plugin`', 'INFO' },\n  })\nend\n\nT['add()']['Install']['generates help tags'] = function()\n  -- Set up clear temporary directory\n  local cur_package_path = test_dir_absolute .. '/temp'\n  local cur_opt_dir = cur_package_path .. '/pack/deps/opt'\n\n  child.lua('_G.temp_package_path = ' .. vim.inspect(cur_package_path))\n  MiniTest.finally(function() child.lua('vim.fn.delete(_G.temp_package_path, \"rf\")') end)\n  child.lua('MiniDeps.setup({ path = { package = _G.temp_package_path } })')\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone dep_plugin_2\n      {},                            -- Clone dep_plugin_1\n      {},                            -- Clone new_plugin\n      { out = 'sha2head' },          -- Get `HEAD` in dep_plugin_2\n      { out = 'sha1head' },          -- Get `HEAD` in dep_plugin_1\n      { out = 'sha0head' },          -- Get `HEAD` in new_plugin\n      { out = 'origin/trunk' },      -- Get default branch in dep_plugin_2\n      { out = 'origin/master' },     -- Get default branch in dep_plugin_1\n      { out = 'origin/main' },       -- Get default branch in new_plugin\n      { out = 'origin/trunk' },      -- Check if `trunk`  is origin branch in dep_plugin_2\n      { out = 'origin/master' },     -- Check if `master` is origin branch in dep_plugin_1\n      { out = 'origin/main' },       -- Check if `main`   is origin branch in new_plugin\n      { out = 'new2head' },          -- Get commit of `trunk`  in dep_plugin_2\n      { out = 'new1head' },          -- Get commit of `master` in dep_plugin_1\n      { out = 'sha0head' },          -- Get commit of `main`   in new_plugin\n      {},                            -- Stash changes in dep_plugin_1\n      {},                            -- Checkout changes in dep_plugin_1\n    }\n\n    -- Mock action cloning side-effects which creates '/doc' directories\n    local opt_dir = _G.temp_package_path .. '/pack/deps/opt'\n    _G.process_mock_data = {\n      -- 'dep_plugin_2' has '/doc' with already present conflicting '/tag'\n      [2] = {\n        action = function()\n          vim.fn.mkdir(opt_dir .. '/dep_plugin_2/doc', 'p')\n          vim.fn.writefile({ 'old_dep_2_tag\tdep_2.txt\t/*old_dep_2_tag*' }, opt_dir .. '/dep_plugin_2/doc/dep_2.txt')\n          vim.fn.writefile({ '*depstest_dep_2_tag*', 'Help for dep_2.' }, opt_dir .. '/dep_plugin_2/doc/dep_2.txt')\n        end\n      },\n\n      -- 'dep_plugin_1' has '/doc' with help files and has explicit checkout\n      [3] = {\n        action = function()\n          vim.fn.mkdir(opt_dir .. '/dep_plugin_1/doc', 'p')\n          vim.fn.writefile({ '*depstest_dep_1_tag*', 'Help for dep_1.' }, opt_dir .. '/dep_plugin_1/doc/dep_1.txt')\n        end\n      },\n\n      -- 'new_plugin' has '/doc' with help files and has no explicit checkout\n      [4] = {\n        action = function()\n          vim.fn.mkdir(opt_dir .. '/new_plugin/doc', 'p')\n          vim.fn.writefile({ '*depstest_new_tag*', 'Help for new.' }, opt_dir .. '/new_plugin/doc/new.txt')\n        end\n      },\n    }\n  ]])\n  add({\n    source = 'user/new_plugin',\n    depends = { { source = 'user/dep_plugin_1', checkout = 'master', depends = { 'user/dep_plugin_2' } } },\n  })\n\n  local validate_tags = function(plugin_name, content)\n    local lines = child.fn.readfile(cur_opt_dir .. '/' .. plugin_name .. '/doc/tags')\n    eq(lines, content)\n  end\n\n  -- Already present conflicting `tag` file should be overridden\n  validate_tags('dep_plugin_2', { 'depstest_dep_2_tag\\tdep_2.txt\\t/*depstest_dep_2_tag*' })\n\n  -- With actual checkout\n  validate_tags('dep_plugin_1', { 'depstest_dep_1_tag\\tdep_1.txt\\t/*depstest_dep_1_tag*' })\n\n  -- Without actual checkout\n  validate_tags('new_plugin', { 'depstest_new_tag\\tnew.txt\\t/*depstest_new_tag*' })\n\n  -- Help tags are actually reachable\n  local help_tags = child.fn.getcompletion('depstest_', 'help')\n  table.sort(help_tags)\n  eq(help_tags, { 'depstest_dep_1_tag', 'depstest_dep_2_tag', 'depstest_new_tag' })\nend\n\nT['add()']['Install']['handles process errors and warnings'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'},                            -- Check Git executable\n      { err = 'filtering not recognized by server, ignoring' }, -- Clone dep_plugin\n      { err = 'Could not clone' },                              -- Clone new_plugin\n      { out = 'sha2head' },                                     -- Get `HEAD` in dep_plugin\n    }\n\n    -- Mock non-zero exit code in getting dep_plugin's head\n    _G.process_mock_data = { [3] = { exit_code = 1 }, [4] = { exit_code = 128 } }\n  ]])\n\n  add({ source = 'user/new_plugin', depends = { 'user/dep_plugin' } })\n\n  -- Errors should be treated as follows:\n  -- - If exit code is non-zero, it should error notify it with `stderr` output\n  -- - If exit code is zero, then process did not error and `stderr` is warning\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    clone_args('https://github.com/user/dep_plugin', test_opt_dir .. '/dep_plugin'),\n    clone_args('https://github.com/user/new_plugin', test_opt_dir .. '/new_plugin'),\n    {\n      args = { 'rev-list', '-1', 'HEAD' },\n      cwd = test_opt_dir .. '/dep_plugin',\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/2) Installed `dep_plugin`', 'INFO' },\n    {\n      '(mini.deps) Warnings in `dep_plugin` during installing plugin\\nfiltering not recognized by server, ignoring',\n      'WARN',\n    },\n    { '(mini.deps) Error in `dep_plugin` during installing plugin\\nERROR CODE 128', 'ERROR' },\n    { '(mini.deps) Error in `new_plugin` during installing plugin\\nERROR CODE 1\\nCould not clone', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['handles no `source` for absent plugin'] = function()\n  child.lua([[_G.stdio_queue = { { out = 'git version 2.43.0'} } -- Check Git executable]])\n  add({ name = 'new_plugin' })\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    {\n      '(mini.deps) Error in `new_plugin` during installing plugin\\nSPECIFICATION HAS NO `source` TO INSTALL PLUGIN.',\n      'ERROR',\n    },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['respects `config.job.n_threads`'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone dep_plugin\n      {},                            -- Clone new_plugin\n      { out = 'sha2head' },          -- Get `HEAD` in dep_plugin\n      { out = 'sha0head' },          -- Get `HEAD` in new_plugin\n      { out = 'origin/trunk' },      -- Get default branch in dep_plugin\n      { out = 'origin/main' },       -- Get default branch in new_plugin\n      { out = 'origin/trunk' },      -- Check if `trunk`  is origin branch in dep_plugin\n      { out = 'origin/main' },       -- Check if `main`   is origin branch in new_plugin\n      { out = 'sha2head' },          -- Get commit of `trunk`  in dep_plugin\n      { out = 'sha0head' },          -- Get commit of `main`   in new_plugin\n    }\n\n    -- Mock non-trivial cloning duration\n    _G.process_mock_data = { [2] = { duration = 30 }, [3] = { duration = 30 } }\n  ]])\n\n  child.lua('MiniDeps.config.job.n_threads = 1')\n\n  local start_time = child.loop.hrtime()\n  add({ source = 'user/new_plugin', depends = { 'user/dep_plugin' } })\n  local duration = 0.000001 * (child.loop.hrtime() - start_time)\n  eq(40 <= duration, true)\nend\n\nT['add()']['Install']['works when no information about number of cores is available'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone\n      { out = 'sha0head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      { out = 'origin/main' },       -- Check if `main` is origin branch\n      { out = 'sha0head' },          -- Get commit of `origin/main`\n      {},                            -- Stash changes\n      {},                            -- Checkout changes\n    }\n  ]])\n  child.lua('vim.loop.cpu_info = function() return nil end')\n  expect.no_error(function() add('user/new_plugin') end)\nend\n\nT['add()']['Install']['respects `config.job.timeout`'] = function()\n  child.lua('_G.duration = ' .. (10 * small_time))\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone dep_plugin\n      {},                            -- Clone new_plugin\n      { out = 'sha2head' },          -- Get `HEAD` in dep_plugin\n    }\n\n    -- Mock long execution of some jobs\n    _G.process_mock_data = { [2] = { duration = _G.duration }, [3] = { duration = 0 }, [4] = { duration = _G.duration } }\n  ]])\n\n  child.lua('MiniDeps.config.job.timeout = ' .. (5 * small_time))\n  add({ source = 'user/new_plugin', depends = { 'user/dep_plugin' } })\n\n  local ref_notify_log = {\n    { '(mini.deps) Installing `new_plugin`', 'INFO' },\n    { '(mini.deps) (1/2) Installed `new_plugin`', 'INFO' },\n    { '(mini.deps) Error in `dep_plugin` during installing plugin\\nERROR CODE 1\\nPROCESS REACHED TIMEOUT.', 'ERROR' },\n    { '(mini.deps) Error in `new_plugin` during installing plugin\\nERROR CODE 1\\nPROCESS REACHED TIMEOUT.', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['add()']['Install']['respects `config.silent`'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Clone\n      { out = 'sha0head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      { out = 'origin/hello' },      -- Check if `hello` is origin branch\n      { out = 'new0hello' },         -- Get commit of `hello`\n      {},                            -- Stash changes\n      {},                            -- Checkout changes\n    }\n  ]])\n  child.lua('MiniDeps.config.silent = true')\n  add({ source = 'user/new_plugin', checkout = 'hello' })\n\n  -- Should produce no notifications\n  validate_notifications({})\nend\n\nT['add()']['Install']['does not affect newly added session data'] = function()\n  child.lua([[_G.stdio_queue = { { out = 'git version 2.43.0'} } -- Check Git executable]])\n  add('user/new_plugin')\n  eq(get_session(), {\n    {\n      path = test_opt_dir .. '/new_plugin',\n      name = 'new_plugin',\n      source = 'https://github.com/user/new_plugin',\n      depends = {},\n      hooks = {},\n    },\n  })\nend\n\nT['update()'] = new_set({\n  hooks = {\n    pre_case = function() load_module({ path = { package = test_dir_absolute, log = test_log_path } }) end,\n    post_case = function()\n      child.fn.delete(test_log_path)\n      for i = 1, 3 do\n        child.fn.delete(string.format('%s/plugin_%d/doc/tags', test_opt_dir, i))\n      end\n    end,\n  },\n})\n\nlocal update = forward_lua('MiniDeps.update')\n\nT['update()']['works'] = function()\n  child.set_size(40, 80)\n  mock_bad_env_vars()\n  local ref_environ = child.fn.environ()\n\n  -- By default should update all plugins in session\n  add('plugin_1')\n  add({ source = 'https://new_source/plugin_2' })\n  add('plugin_3')\n\n  local plugin_2_log = table.concat({\n    '< sha2head | 2024-01-02 01:01:01 +0200 | Neo McVim',\n    '  Removed commit in plugin_2.',\n    '> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim',\n    '  Added commit in plugin_2.',\n  }, '\\n')\n  child.lua('_G.plugin_2_log = ' .. vim.inspect(plugin_2_log))\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      { out = 'https://github.com/user/plugin_1' }, -- Get source from `origin` in plugin_1\n      { err = 'Some warning' },                     -- Set `origin` to source in plugin_2\n      { err = 'Error computing origin' },           -- Get source from `origin` in plugin_3\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },          -- Get `HEAD` in plugin_2\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      { out = 'origin/master' },     -- Get default branch in plugin_2\n      {},                            -- Fetch in plugin_1\n      {},                            -- Fetch in plugin_2\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n      { out = 'origin/master' },     -- Check if `checkout` is origin branch in plugin_2\n      { out = 'sha1head' },          -- Get commit of `checkout` in plugin_1\n      { out = 'new2head' },          -- Get commit of `checkout` in plugin_2\n      { out = _G.plugin_2_log },     -- Get log of `checkout` changes in plugin_2\n    }\n\n    -- Mock non-trivial fetch duration\n    _G.process_mock_data = { [4] = { exit_code = 1 }, [9] = { duration = 50 }, [10] = { duration = 40 } }\n  ]])\n\n  -- Update should be done in parallel\n  local start_time = child.loop.hrtime()\n  update()\n  local duration = 0.000001 * (child.loop.hrtime() - start_time)\n  eq(50 <= duration and duration < 90, true)\n\n  -- Should result into a proper sequence of CLI runs\n  local cwd_plugin_1, cwd_plugin_2, cwd_plugin_3 =\n    test_opt_dir .. '/plugin_1', test_opt_dir .. '/plugin_2', test_opt_dir .. '/plugin_3'\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n\n    { args = { 'remote', 'get-url', 'origin' },                                cwd = cwd_plugin_1 },\n    { args = { 'remote', 'set-url', 'origin', 'https://new_source/plugin_2' }, cwd = cwd_plugin_2 },\n    { args = { 'remote', 'get-url', 'origin' },                                cwd = cwd_plugin_3 },\n\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_plugin_1 },\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_plugin_2 },\n\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_plugin_1 },\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_plugin_2 },\n\n    { args = { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' }, cwd = cwd_plugin_1 },\n    { args = { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' }, cwd = cwd_plugin_2 },\n\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' },   cwd = cwd_plugin_1 },\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/master' }, cwd = cwd_plugin_2 },\n\n    { args = { 'rev-list', '-1', 'origin/main' },   cwd = cwd_plugin_1 },\n    { args = { 'rev-list', '-1', 'origin/master' }, cwd = cwd_plugin_2 },\n\n    { args = log_args('sha2head...new2head'), cwd = cwd_plugin_2 },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Downloading 2 updates', 'INFO' },\n    { '(mini.deps) (1/2) Downloaded update for `plugin_2`', 'INFO' },\n    { '(mini.deps) (2/2) Downloaded update for `plugin_1`', 'INFO' },\n    { '(mini.deps) Warnings in `plugin_2` during update\\nSome warning', 'WARN' },\n    { '(mini.deps) Error in `plugin_3` during update\\nERROR CODE 1\\nError computing origin', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\n\n  -- Should show confirmation buffer. Plugin entries should be in order of\n  -- \"error\", \"has changes\", \"no changes\".\n  mock_hide_path(test_dir_absolute)\n  child.expect_screenshot()\n  validate_confirm_buf('confirm-update')\n\n  -- Should not affect any environment variables\n  eq(child.fn.environ(), ref_environ)\nend\n\nT['update()']['checks for executable Git'] = function()\n  add('plugin_1')\n  child.lua([[\n    _G.stdio_queue = { { err = 'No Git'} }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n  expect.error(function() update() end, 'Could not find executable `git` CLI tool')\nend\n\nT['update()']['Confirm buffer'] = new_set({\n  hooks = {\n    pre_case = function()\n      add('plugin_1')\n      add('plugin_2')\n\n      child.lua([[\n        _G.plugin_1_log = '> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim\\n  Added commit in plugin_1.'\n        _G.plugin_2_log = '> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim\\n  Added commit in plugin_2.'\n        _G.stdio_queue = {\n          { out = 'git version 2.43.0'}, -- Check Git executable\n          { out = 'https://github.com/user/plugin_1' }, -- Get source from `origin` in plugin_1\n          { out = 'https://github.com/user/plugin_2' }, -- Get source from `origin` in plugin_2\n          { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n          { out = 'sha2head' },          -- Get `HEAD` in plugin_2\n          { out = 'origin/main' },       -- Get default branch in plugin_1\n          { out = 'origin/master' },     -- Get default branch in plugin_2\n          {},                            -- Fetch in plugin_1\n          {},                            -- Fetch in plugin_2\n          { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n          { out = 'origin/master' },     -- Check if `checkout` is origin branch in plugin_2\n          { out = 'new1head' },          -- Get commit of `checkout` in plugin_1\n          { out = 'new2head' },          -- Get commit of `checkout` in plugin_2\n          { out = _G.plugin_1_log },     -- Get log of `checkout` changes in plugin_1\n          { out = _G.plugin_2_log },     -- Get log of `checkout` changes in plugin_2\n        }\n      ]])\n\n      -- Confirmation buffer should be configurable in `FileType` event with\n      -- window being current (so as to `vim.wo` can work)\n      child.cmd('au FileType minideps-confirm lua _G.minideps_ft_win_id = vim.api.nvim_get_current_win()')\n\n      update()\n      eq(#get_spawn_log(), 15)\n      eq(#get_notify_log(), 3)\n      validate_confirm_buf('confirm-update')\n      eq(child.lua_get('_G.minideps_ft_win_id') == child.api.nvim_get_current_win(), true)\n\n      child.lua([[\n        _G.prev_update = MiniDeps.update\n        MiniDeps.update = function(...)\n          _G.update_args = { ... }\n          prev_update(...)\n        end\n      ]])\n    end,\n  },\n})\n\nT['update()']['Confirm buffer']['can apply changes'] = function()\n  mock_bad_env_vars()\n  local ref_environ = child.fn.environ()\n\n  -- Should run `update()` on buffer write with only valid plugin names\n  -- Remove 'plugin_1' from being updated\n  child.cmd('g/^+++ plugin_1/normal! dd/')\n  child.cmd('write')\n\n  -- Should update and close confirmation buffer\n  eq(child.lua_get('_G.update_args'), { { 'plugin_2' }, { force = true, offline = true } })\n  validate_not_confirm_buf()\n\n  -- Should not affect any environment variables\n  eq(child.fn.environ(), ref_environ)\nend\n\nT['update()']['Confirm buffer']['can cancel'] = function()\n  child.cmd('close')\n  eq(child.lua_get('_G.update_args'), vim.NIL)\n  validate_not_confirm_buf()\nend\n\nT['update()']['Confirm buffer']['can open several'] = function()\n  child.lua('_G.prev_update()')\n  validate_confirm_buf('confirm-update')\nend\n\nT['update()']['can fold in confirm buffer'] = function()\n  child.set_size(30, 80)\n\n  -- Confirmation buffer should enable local folds\n  child.o.foldenable = false\n  child.o.foldmethod = 'indent'\n  child.o.foldlevel = 0\n  child.o.foldtext = '\"  >> \".getline(v:foldstart)'\n\n  -- Should be possible to automatically show folds on start\n  child.cmd('au FileType minideps-confirm setlocal foldlevel=0')\n\n  add('user/plugin_1')\n  add('user/plugin_2')\n  add('user/plugin_3')\n\n  local plugin_2_log = table.concat({\n    '< sha2head | 2024-01-02 01:01:01 +0200 | Neo McVim',\n    '  Removed commit in plugin_2.',\n    '> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim',\n    '  Added commit in plugin_2.',\n  }, '\\n')\n  child.lua('_G.plugin_2_log = ' .. vim.inspect(plugin_2_log))\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'},    -- Check Git executable\n      {},                               -- Set `origin` to source in plugin_1\n      {},                               -- Set `origin` to source in plugin_2\n      { err = 'Error setting origin' }, -- Set `origin` to source in plugin_3\n      { out = 'sha1head' },             -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },             -- Get `HEAD` in plugin_2\n      { out = 'origin/main' },          -- Get default branch in plugin_1\n      { out = 'origin/master' },        -- Get default branch in plugin_2\n      {},                               -- Fetch in plugin_1\n      {},                               -- Fetch in plugin_2\n      { out = 'origin/main' },          -- Check if `checkout` is origin branch in plugin_1\n      { out = 'origin/master' },        -- Check if `checkout` is origin branch in plugin_2\n      { out = 'sha1head' },             -- Get commit of `checkout` in plugin_1\n      { out = 'new2head' },             -- Get commit of `checkout` in plugin_2\n      { out = _G.plugin_2_log },        -- Get log of `checkout` changes in plugin_2\n    }\n\n    _G.process_mock_data = { [4] = { exit_code = 1 } }\n  ]])\n\n  update()\n  mock_hide_path(test_dir_absolute)\n\n  child.expect_screenshot()\n\n  -- Should not preserve fold options in new buffer in same window\n  child.cmd('enew')\n  eq(child.wo.foldenable, false)\n  eq(child.wo.foldmethod, 'indent')\n  eq(child.wo.foldlevel, 0)\n\n  -- Should not preserve fold options when quit\n  child.cmd('quit')\n  eq(child.wo.foldenable, false)\n  eq(child.wo.foldmethod, 'indent')\n  eq(child.wo.foldlevel, 0)\nend\n\nT['update()']['can highlight breaking changes'] = function()\n  child.set_size(33, 80)\n\n  add('plugin_1')\n\n  local plugin_1_log = table.concat({\n    '< sha2head | 2024-01-02 01:01:01 +0200 | Neo McVim',\n    '  feat!: a breaking feature',\n    '> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim',\n    '  fix(deps)!: a breaking fix',\n    '> wow2head | 2024-01-02 03:03:03 +0200 | Neo McVim',\n    '  fix: not a fix!: breaking change',\n  }, '\\n')\n  child.lua('_G.plugin_1_log = ' .. vim.inspect(plugin_1_log))\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      { out = 'https://github.com/user/plugin_1' }, -- Get source from `origin` in plugin_1\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      {},                            -- Fetch in plugin_1\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n      { out = 'wow1head' },          -- Get commit of `checkout` in plugin_1\n      { out = _G.plugin_1_log },     -- Get log of `checkout` changes in plugin_1\n    }\n  ]])\n\n  update()\n\n  -- Should show confirmation buffer with highlighted breaking messages\n  mock_hide_path(test_dir_absolute)\n  child.expect_screenshot()\nend\n\nT['update()']['can work with non-default branches'] = function()\n  child.set_size(32, 80)\n\n  add({ source = 'user/plugin_1', checkout = 'hello', monitor = 'world' })\n  child.lua([[\n    _G.checkout_log = '> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim\\n  Added commit in checkout.'\n    _G.monitor_log = '> new2head | 2024-01-02 02:02:02 +0200 | Neo McVim\\n  Added commit in monitor.'\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source\n      { out = 'sha1head' },          -- Get `HEAD`\n      -- NOTE: Don't get default branch as both every target is explicit\n      { out = 'origin/world' },      -- Check if `monitor` is origin branch\n      { out = 'sha2head' },          -- Get commit of `monitor`\n      {},                            -- Fetch\n      { out = 'origin/hello' },      -- Check if `checkout` is origin branch (it is)\n      { out = 'new1head' },          -- Get commit of `checkout`\n      { out = 'origin/world' },      -- Check if `monitor` is origin branch (it is)\n      { out = 'new2head' },          -- Get commit of `monitor`\n      { out = _G.checkout_log },     -- Get log of `checkout` changes\n      { out = _G.monitor_log },      -- Get log of `monitor` changes\n    }\n  ]])\n  update()\n\n  -- Should result into a proper sequence of CLI runs\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    { args = { 'remote', 'set-url', 'origin', 'https://github.com/user/plugin_1' }, cwd = test_opt_dir .. '/plugin_1' },\n    { 'rev-list', '-1', 'HEAD' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/world' },\n    { 'rev-list', '-1', 'origin/world' },\n    { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/hello' },\n    { 'rev-list', '-1', 'origin/hello' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/world' },\n    { 'rev-list', '-1', 'origin/world' },\n    log_args('sha1head...new1head'),\n    log_args('sha2head...new2head'),\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- - Modify absolute paths to be more reproducible\n  mock_hide_path(test_dir_absolute)\n  child.expect_screenshot()\nend\n\nT['update()']['shows empty monitor log'] = function()\n  child.set_size(27, 80)\n\n  add({ source = 'user/plugin_1', checkout = 'hello', monitor = 'world' })\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source\n      { out = 'sha1head' },          -- Get `HEAD`\n      -- NOTE: Don't get default branch as both every target is explicit\n      { out = 'origin/world' },      -- Check if `monitor` is origin branch\n      { out = 'sha2head' },          -- Get commit of `monitor`\n      {},                            -- Fetch\n      { out = 'origin/hello' },      -- Check if `checkout` is origin branch (it is)\n      { out = 'sha1head' },          -- Get commit of `checkout`\n      { out = 'origin/world' },      -- Check if `monitor` is origin branch (it is)\n      { out = 'sha2head' },          -- Get commit of `monitor`\n    }\n  ]])\n  update()\n\n  mock_hide_path(test_dir_absolute)\n  child.expect_screenshot()\nend\n\nT['update()']['properly executes `*_checkout` hooks'] = function()\n  child.lua([[\n    -- Add plugins with hooks\n    _G.args = {}\n    local make_hook = function(msg)\n      return function(...)\n        table.insert(_G.args, { msg, { ... } })\n        vim.notify(msg)\n      end\n    end\n\n    for i = 1, 3 do\n      local name = 'plugin_' .. i\n      MiniDeps.add({\n        source = 'user/' .. name,\n        hooks = {\n          pre_checkout = make_hook(name .. ' pre_checkout'),\n          post_checkout = make_hook(name .. ' post_checkout'),\n        },\n      })\n    end\n\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source in plugin_1\n      {},                            -- Set `origin` to source in plugin_2\n      {},                            -- Set `origin` to source in plugin_3\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },          -- Get `HEAD` in plugin_2\n      { out = 'sha3head' },          -- Get `HEAD` in plugin_3\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      { out = 'origin/master' },     -- Get default branch in plugin_2\n      { out = 'origin/master' },     -- Get default branch in plugin_3\n      {},                            -- Fetch in plugin_1\n      {},                            -- Fetch in plugin_2\n      {},                            -- Fetch in plugin_3\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n      { out = 'origin/master' },     -- Check if `checkout` is origin branch in plugin_2\n      { out = 'origin/master' },     -- Check if `checkout` is origin branch in plugin_3\n      { out = 'new1head' },          -- Get commit of `checkout` in plugin_1\n      { out = 'new2head' },          -- Get commit of `checkout` in plugin_2\n      { out = 'sha3head' },          -- Get commit of `checkout` in plugin_3\n      { out = 'Log 1' },             -- Get log of `checkout` changes in plugin_1\n      { out = 'Log 2' },             -- Get log of `checkout` changes in plugin_2\n      {},                            -- Stash in plugin_1\n      {},                            -- Stash in plugin_2\n      {},                            -- Checkout in plugin_1\n      {},                            -- Checkout in plugin_2\n    }\n  ]])\n  child.lua('MiniDeps.update(nil, { force = true })')\n\n  -- Should be called with proper arguments\n  local cwd_plugin_1, cwd_plugin_2 = test_opt_dir .. '/plugin_1', test_opt_dir .. '/plugin_2'\n  local ref_args = {\n    {\n      'plugin_1 pre_checkout',\n      { { path = cwd_plugin_1, source = 'https://github.com/user/plugin_1', name = 'plugin_1' } },\n    },\n    {\n      'plugin_2 pre_checkout',\n      { { path = cwd_plugin_2, source = 'https://github.com/user/plugin_2', name = 'plugin_2' } },\n    },\n    {\n      'plugin_1 post_checkout',\n      { { path = cwd_plugin_1, source = 'https://github.com/user/plugin_1', name = 'plugin_1' } },\n    },\n    {\n      'plugin_2 post_checkout',\n      { { path = cwd_plugin_2, source = 'https://github.com/user/plugin_2', name = 'plugin_2' } },\n    },\n  }\n  eq(child.lua_get('_G.args'), ref_args)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Downloading 3 updates', 'INFO' },\n    { '(mini.deps) (1/3) Downloaded update for `plugin_1`', 'INFO' },\n    { '(mini.deps) (2/3) Downloaded update for `plugin_2`', 'INFO' },\n    { '(mini.deps) (3/3) Downloaded update for `plugin_3`', 'INFO' },\n    { 'plugin_1 pre_checkout' },\n    { 'plugin_2 pre_checkout' },\n    -- No 'plugin_3' hooks should be executed as no checkout was done\n    { '(mini.deps) (1/2) Checked out `main` in `plugin_1`', 'INFO' },\n    { '(mini.deps) (2/2) Checked out `master` in `plugin_2`', 'INFO' },\n    { 'plugin_1 post_checkout' },\n    { 'plugin_2 post_checkout' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['update()']['handles errors in hooks'] = function()\n  child.lua([[\n    MiniDeps.add({\n      source = 'user/plugin_1',\n      hooks = { pre_checkout = function() error('Error in `pre_checkout`') end },\n    })\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source\n      { out = 'sha1head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      {},                            -- Fetch\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch\n      { out = 'new1head' },          -- Get commit of `checkout`\n      { out = 'Log 1' },             -- Get log of `checkout` changes\n      {},                            -- Stash\n      {},                            -- Checkout\n    }\n  ]])\n  child.lua('MiniDeps.update(nil, { force = true, offline = true })')\n  --stylua: ignore\n  validate_notifications({\n    { '(mini.deps) Error executing pre_checkout hook in `plugin_1`:\\n[string \"<nvim>\"]:3: Error in `pre_checkout`', 'ERROR' },\n    { '(mini.deps) (1/1) Checked out `main` in `plugin_1`', 'INFO' }\n  })\nend\n\nT['update()']['generates help tags'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source in plugin_1\n      {},                            -- Set `origin` to source in plugin_2\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },          -- Get `HEAD` in plugin_2\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      { out = 'origin/master' },     -- Get default branch in plugin_2\n      {},                            -- Fetch in plugin_1\n      {},                            -- Fetch in plugin_2\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n      { out = 'origin/master' },     -- Check if `checkout` is origin branch in plugin_2\n      { out = 'new1head' },          -- Get commit of `checkout` in plugin_1\n      { out = 'sha2head' },          -- Get commit of `checkout` in plugin_2\n      { out = 'Log 1' },             -- Get log of `checkout` changes in plugin_1\n      {},                            -- Stash in plugin_1\n      {},                            -- Checkout in plugin_1\n    }\n  ]])\n  add('user/plugin_1')\n  add('user/plugin_2')\n\n  child.lua('MiniDeps.update(nil, { force = true })')\n\n  local tags_lines = child.fn.readfile(test_opt_dir .. '/plugin_1/doc/tags')\n  eq(tags_lines, { 'depstest_plugin_1_tag\\thelp_1.txt\\t/*depstest_plugin_1_tag*' })\n  eq(child.fn.filereadable(test_opt_dir .. '/plugin_2/doc/tags'), 0)\n\n  -- Help tags are actually reachable\n  local help_tags = child.fn.getcompletion('depstest_', 'help')\n  table.sort(help_tags)\n  eq(help_tags, { 'depstest_plugin_1_tag' })\nend\n\nT['update()']['respects `names` argument'] = function()\n  add('plugin_1')\n  add('plugin_2')\n\n  local validate = function(names)\n    clear_notify_log()\n    update(names)\n    validate_notifications({\n      { '(mini.deps) Downloading 1 update', 'INFO' },\n      { '(mini.deps) (1/1) Downloaded update for `plugin_1`', 'INFO' },\n    })\n  end\n\n  validate({ 'plugin_1' })\n\n  -- Should silently drop names not in session\n  validate({ 'plugin_1', 'plugin_3', 'not_present_even_on_disk' })\n\n  -- Should allow empty array\n  clear_notify_log()\n  update({})\n  validate_notifications({ { '(mini.deps) Nothing to update', 'INFO' } })\nend\n\nT['update()']['valdiates arguments'] = function()\n  expect.error(function() update('plugin_1') end, '`names`.*array')\n  expect.error(function() update({ 'plugin_1', 1, { name = 'plugin_2' } }) end, '`names`.*strings')\nend\n\nT['update()']['respects `opts.force`'] = function()\n  add('user/plugin_1')\n\n  child.lua([[\n    _G.checkout_log = '> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim\\n  Added commit in checkout.'\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source\n      { out = 'sha1head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      {},                            -- Fetch\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch (it is)\n      { out = 'new1head' },          -- Get commit of `checkout`\n      { out = _G.checkout_log },     -- Get log of `checkout` changes\n      {},                            -- Stash\n      {},                            -- Checkout\n    }\n  ]])\n  child.lua('MiniDeps.update(nil, { force = true })')\n\n  -- Should result into a proper sequence of CLI runs\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    {\n      args = { 'remote', 'set-url', 'origin', 'https://github.com/user/plugin_1' },\n      cwd = test_opt_dir .. '/plugin_1',\n    },\n    { 'rev-list', '-1', 'HEAD' },\n    { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n    { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' },\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' },\n    { 'rev-list', '-1', 'origin/main' },\n    log_args('sha1head...new1head'),\n    { 'stash', '--quiet', '--message', '(mini.deps) 2024-01-02 03:04:05 Stash before checkout' },\n    { 'checkout', '--quiet', 'new1head' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Downloading 1 update', 'INFO' },\n    { '(mini.deps) (1/1) Downloaded update for `plugin_1`', 'INFO' },\n    { '(mini.deps) (1/1) Checked out `main` in `plugin_1`', 'INFO' },\n  }\n  validate_notifications(ref_notify_log)\n\n  -- Should do actual checkout right away without confirmation\n  validate_not_confirm_buf()\n\n  -- Should write to log file\n  local log_path = child.lua_get('MiniDeps.config.path.log')\n  local log_lines = child.fn.readfile(log_path)\n  -- - Make test more reproducible\n  log_lines = vim.tbl_map(function(l) return l:gsub(vim.pesc(test_dir_absolute), 'MOCKDIR') end, log_lines)\n\n  local ref_log_lines = {\n    '========== Update 2024-01-02 03:04:05 ==========',\n    '+++ plugin_1 +++',\n    'Path:         MOCKDIR/pack/deps/opt/plugin_1',\n    'Source:       https://github.com/user/plugin_1',\n    'State before: sha1head',\n    'State after:  new1head (main)',\n    '',\n    'Pending updates from `main`:',\n    '> new1head | 2024-01-02 01:01:01 +0200 | Neo McVim',\n    '  Added commit in checkout.',\n    '',\n  }\n  eq(log_lines, ref_log_lines)\nend\n\nT['update()']['respects `opts.offline`'] = function()\n  add('user/plugin_1')\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source\n      { out = 'sha1head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      -- No fetch with `opts.offline`\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch (it is)\n      { out = 'new1head' },          -- Get commit of `checkout`\n      { out = 'Log 1' },             -- Get log of `checkout` changes\n    }\n  ]])\n  child.lua('MiniDeps.update(nil, { offline = true })')\n\n  -- Should result into a proper sequence of CLI runs\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    {\n      args = { 'remote', 'set-url', 'origin', 'https://github.com/user/plugin_1' },\n      cwd = test_opt_dir .. '/plugin_1',\n    },\n    { 'rev-list', '-1', 'HEAD' },\n    { 'rev-parse', '--abbrev-ref', 'origin/HEAD' },\n    -- No fetch with `opts.offline`\n    { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/main' },\n    { 'rev-list', '-1', 'origin/main' },\n    log_args('sha1head...new1head'),\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  validate_notifications({})\nend\n\nT['update()']['respects `config.job.n_threads`'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source in plugin_1\n      {},                            -- Set `origin` to source in plugin_2\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },          -- Get `HEAD` in plugin_2\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      { out = 'origin/master' },     -- Get default branch in plugin_2\n      {},                            -- Fetch in plugin_1\n      {},                            -- Fetch in plugin_2\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n      { out = 'origin/master' },     -- Check if `checkout` is origin branch in plugin_2\n      { out = 'sha1head' },          -- Get commit of `checkout` in plugin_1\n      { out = 'sha2head' },          -- Get commit of `checkout` in plugin_2\n    }\n\n    -- Mock non-trivial fetch duration\n    _G.process_mock_data = { [8] = { duration = 30 }, [9] = { duration = 30 } }\n  ]])\n  add('user/plugin_1')\n  add('user/plugin_2')\n\n  child.lua('MiniDeps.config.job.n_threads = 1')\n  local start_time = child.loop.hrtime()\n  update()\n  local duration = 0.000001 * (child.loop.hrtime() - start_time)\n  eq(40 <= duration, true)\nend\n\nT['update()']['works when no information about number of cores is available'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source in plugin_1\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      {},                            -- Fetch in plugin_1\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch in plugin_1\n      { out = 'sha1head' },          -- Get commit of `checkout` in plugin_1\n    }\n  ]])\n  add('user/plugin_1')\n  child.lua('vim.loop.cpu_info = function() return nil end')\n  expect.no_error(update)\nend\n\nT['update()']['respects `config.job.timeout`'] = function()\n  helpers.skip_if_slow()\n\n  child.lua('_G.duration = ' .. (10 * small_time))\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source in plugin_1\n      {},                            -- Set `origin` to source in plugin_2\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'origin/main' },       -- Get default branch in plugin_1\n      {},                            -- Fetch in plugin_1\n    }\n\n    -- Mock non-trivial durations\n    _G.process_mock_data = { [3] = { duration = _G.duration }, [6] = { duration = _G.duration } }\n  ]])\n  add('user/plugin_1')\n  add('user/plugin_2')\n\n  child.lua('MiniDeps.config.job.timeout = ' .. (5 * small_time))\n  update()\n\n  local ref_notify_log = {\n    { '(mini.deps) Downloading 1 update', 'INFO' },\n    { '(mini.deps) Error in `plugin_1` during update\\nERROR CODE 1\\nPROCESS REACHED TIMEOUT.', 'ERROR' },\n    { '(mini.deps) Error in `plugin_2` during update\\nERROR CODE 1\\nPROCESS REACHED TIMEOUT.', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['update()']['respects `config.silent`'] = function()\n  add('user/plugin_1')\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      {},                            -- Set `origin` to source\n      { out = 'sha1head' },          -- Get `HEAD`\n      { out = 'origin/main' },       -- Get default branch\n      {},                            -- Fetch\n      { out = 'origin/main' },       -- Check if `checkout` is origin branch (it is)\n      { out = 'new1head' },          -- Get commit of `checkout`\n      { out = 'Log 1' },             -- Get log of `checkout` changes\n      {},                            -- Stash\n      {},                            -- Checkout\n    }\n  ]])\n\n  child.lua('MiniDeps.config.silent = true')\n  child.lua('MiniDeps.update(nil, { force = true })')\n\n  -- Should produce no notifications\n  validate_notifications({})\nend\n\nT['update()']['handles process errors and warnings'] = function()\n  add('user/plugin_1')\n  add('user/plugin_2')\n\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      { err = 'Some warning' },      -- Set `origin` to source in plugin_1\n      { err = 'Bad `origin`'},       -- Set `origin` to source in plugin_2\n      { out = 'sha2head' },          -- Get `HEAD` in plugin_1\n    }\n\n    -- Mock non-zero exit code in getting plugin_1's head\n    _G.process_mock_data = { [3] = { exit_code = 1 }, [4] = { exit_code = 128 } }\n  ]])\n\n  update()\n\n  -- If any error (from `stderr` or exit code) is encountered, all CLI jobs for\n  -- that particular plugin should not be done\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n    { args = { 'remote', 'set-url', 'origin', 'https://github.com/user/plugin_1' }, cwd = test_opt_dir .. '/plugin_1' },\n    { args = { 'remote', 'set-url', 'origin', 'https://github.com/user/plugin_2' }, cwd = test_opt_dir .. '/plugin_2' },\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = test_opt_dir .. '/plugin_1' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) Warnings in `plugin_1` during update\\nSome warning', 'WARN' },\n    { '(mini.deps) Error in `plugin_1` during update\\nERROR CODE 128', 'ERROR' },\n    { '(mini.deps) Error in `plugin_2` during update\\nERROR CODE 1\\nBad `origin`', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT['clean()'] = new_set({\n  hooks = {\n    pre_case = function()\n      local start_dir = test_dir_absolute .. '/pack/deps/start'\n      mock_plugin(start_dir .. '/start_plugin')\n      local not_in_session_1 = test_opt_dir .. '/plugin_not_in_session_1'\n      mock_plugin(not_in_session_1)\n      local not_in_session_2 = test_opt_dir .. '/plugin_not_in_session_2'\n      mock_plugin(not_in_session_2)\n      mock_test_package(test_dir_absolute)\n\n      local lua_cmd = string.format(\n        '_G.info = { start_dir = %s, not_in_session_1 = %s, not_in_session_2 = %s }',\n        vim.inspect(start_dir),\n        vim.inspect(not_in_session_1),\n        vim.inspect(not_in_session_2)\n      )\n      child.lua(lua_cmd)\n\n      add('plugin_1')\n      add('plugin_2')\n      add('plugin_3')\n      add('plu-gin_0.nvim')\n      eq(#get_session(), 5)\n    end,\n    post_case = function()\n      child.lua([[\n        vim.fn.delete(_G.info.start_dir, 'rf')\n        vim.fn.delete(_G.info.not_in_session_1, 'rf')\n        vim.fn.delete(_G.info.not_in_session_2, 'rf')\n      ]])\n    end,\n  },\n})\n\nlocal clean = forward_lua('MiniDeps.clean')\n\nT['clean()']['works'] = function()\n  child.set_size(15, 80)\n\n  -- Confirmation buffer should be configurable in `FileType` event with\n  -- window being current (so as to `vim.wo` can work)\n  child.cmd('au FileType minideps-confirm lua _G.minideps_ft_win_id = vim.api.nvim_get_current_win()')\n\n  clean()\n\n  -- By default should show confirmation buffer\n  child.set_cursor(1, 0)\n  child.wo.wrap = false\n  child.expect_screenshot()\n  validate_confirm_buf('confirm-clean')\n  eq(child.lua_get('_G.minideps_ft_win_id') == child.api.nvim_get_current_win(), true)\n\n  -- Should reveal concealed full path\n  child.set_cursor(9, 0)\n  -- - Mock absolute path only on current line as path in parenthesis is used\n  --   to determine which path to delete from disk.\n  child.cmd(':s/' .. child.fn.escape(test_dir_absolute, ' /') .. '/MOCKDIR/')\n  child.bo.modified = false\n  child.expect_screenshot()\n\n  -- Should delete from disk on buffer write but only listed plugin names\n  child.cmd('%g/not_in_session_1/normal! dd')\n  child.cmd('write')\n\n  eq(child.lua_get('vim.fn.isdirectory(_G.info.not_in_session_1)'), 1)\n  eq(child.lua_get('vim.fn.isdirectory(_G.info.not_in_session_2)'), 0)\n\n  -- Should produce notifications\n  validate_notifications({ { '(mini.deps) (1/1) Deleted `plugin_not_in_session_2` from disk', 'INFO' } })\n\n  -- Should close confirm buffer\n  validate_not_confirm_buf()\nend\n\nT['clean()']['can cancel confirm'] = function()\n  clean()\n  validate_confirm_buf('confirm-clean')\n  child.cmd('quit')\n  validate_not_confirm_buf()\n\n  -- Should not delete from disk\n  eq(child.lua_get('vim.fn.isdirectory(_G.info.not_in_session_1)'), 1)\n  eq(child.lua_get('vim.fn.isdirectory(_G.info.not_in_session_2)'), 1)\n  validate_notifications({})\nend\n\nT['clean()']['respects `opts.force`'] = function()\n  clean({ force = true })\n\n  -- Should delete from disk without confirmation\n  validate_not_confirm_buf()\n  eq(child.lua_get('vim.fn.isdirectory(_G.info.not_in_session_1)'), 0)\n  eq(child.lua_get('vim.fn.isdirectory(_G.info.not_in_session_2)'), 0)\n\n  validate_notifications({\n    { '(mini.deps) (1/2) Deleted `plugin_not_in_session_1` from disk', 'INFO' },\n    { '(mini.deps) (2/2) Deleted `plugin_not_in_session_2` from disk', 'INFO' },\n  })\nend\n\nT['clean()']['respects `config.silent`'] = function()\n  child.lua('MiniDeps.config.silent = true')\n  clean({ force = true })\n  validate_notifications({})\nend\n\nT['clean()']['shows notification when nothing to clean'] = function()\n  add('plugin_not_in_session_1')\n  add('plugin_not_in_session_2')\n  clean({ force = true })\n  validate_notifications({ { '(mini.deps) Nothing to clean', 'INFO' } })\nend\n\nT['snap_get()'] = new_set({\n  hooks = {\n    pre_case = function()\n      mock_plugin(test_dir_absolute .. '/pack/deps/start/start_plugin')\n      load_module({ path = { package = test_dir_absolute } })\n      add('plugin_1')\n    end,\n    post_case = function() child.fn.delete(test_dir_absolute .. '/pack/deps/start', 'rf') end,\n  },\n})\n\nlocal snap_get = forward_lua('MiniDeps.snap_get')\n\nT['snap_get()']['works'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      { out = 'sha1head' },          -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },          -- Get `HEAD` in start_plugin\n    }\n  ]])\n\n  local snap = snap_get()\n\n  -- Should return snapshot\n  eq(snap, { plugin_1 = 'sha1head', start_plugin = 'sha2head' })\n\n  -- Should not produce notifications\n  validate_notifications({})\nend\n\nT['snap_get()']['checks for executable Git'] = function()\n  add('plugin_1')\n  child.lua([[\n    _G.stdio_queue = { { err = 'No Git'} }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n  expect.error(snap_get, 'Could not find executable `git` CLI tool')\nend\n\nT['snap_get()']['handles process errors'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'}, -- Check Git executable\n      { err = 'Some error' },        -- Get `HEAD` in plugin_1\n      { out = 'sha2head' },          -- Get `HEAD` in start_plugin\n    }\n    _G.process_mock_data = { [2] = { exit_code = 1 } }\n  ]])\n\n  -- Should still return snapshot but without data for errored plugins\n  local snap = snap_get()\n  eq(snap, { start_plugin = 'sha2head' })\n\n  -- Should show error notifications\n  validate_notifications({\n    { '(mini.deps) Error in `plugin_1` during computing snapshot\\nERROR CODE 1\\nSome error', 'ERROR' },\n  })\nend\n\nT['snap_set()'] = new_set({\n  hooks = {\n    pre_case = function()\n      mock_plugin(test_dir_absolute .. '/pack/deps/start/start_plugin')\n      load_module({ path = { package = test_dir_absolute } })\n      add({ name = 'plugin_1', checkout = 'hello' })\n      add({ name = 'plugin_2' })\n    end,\n    post_case = function()\n      child.fn.delete(test_dir_absolute .. '/pack/deps/start', 'rf')\n      child.fn.delete(test_opt_dir .. '/plugin_1/doc/tags', 'rf')\n      child.fn.delete(test_opt_dir .. '/plugin_2/doc/tags', 'rf')\n    end,\n  },\n})\n\nlocal snap_set = forward_lua('MiniDeps.snap_set')\n\nT['snap_set()']['works'] = function()\n  local init_session = get_session()\n  child.lua([[\n    _G.stdio_queue = {\n      { out = 'git version 2.43.0'},  -- Check Git executable\n      { out = 'sha1head' },           -- Get `HEAD` in plugin_1\n      -- Should stop other steps for plugin after first error\n      { err = 'Error getting HEAD' }, -- Get `HEAD` in plugin_2\n      { out = 'shaShead' },           -- Get `HEAD` in start_plugin\n      { out = 'origin/main' },        -- Get default branch in plugin_1\n      { out = 'origin/master' },      -- Get default branch in start_plugin\n      { out = '' },                   -- Check if snap state is origin branch in plugin_1 (it is not)\n      { out = '' },                   -- Check if snap state is origin branch in start_plugin (it is not)\n      { out = 'new1head' },           -- Get commit of `checkout` in plugin_1\n      { out = 'shaShead' },           -- Get commit of `checkout` in start_plugin\n      {},                             -- Stash in start_plugin\n      {},                             -- Checkout in start_plugin\n    }\n    _G.process_mock_data = { [3] = { exit_code = 1 } }\n  ]])\n\n  -- Should apply only to plugins inside current session\n  snap_set({ plugin_1 = 'new1head', plugin_2 = 'sha2head', start_plugin = 'shaShead' })\n\n  local cwd_plugin_1, cwd_plugin_2, cwd_start_plugin =\n    test_opt_dir .. '/plugin_1', test_opt_dir .. '/plugin_2', test_dir_absolute .. '/pack/deps/start/start_plugin'\n  local ref_git_spawn_log = {\n    { args = { 'version' }, cwd = child.fn.getcwd() },\n\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_plugin_1 },\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_plugin_2 },\n    { args = { 'rev-list', '-1', 'HEAD' }, cwd = cwd_start_plugin },\n\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_plugin_1 },\n    { args = { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }, cwd = cwd_start_plugin },\n\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/new1head' }, cwd = cwd_plugin_1 },\n    { args = { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/shaShead' }, cwd = cwd_start_plugin },\n\n    { args = { 'rev-list', '-1', 'new1head' }, cwd = cwd_plugin_1 },\n    { args = { 'rev-list', '-1', 'shaShead' }, cwd = cwd_start_plugin },\n\n    {\n      args = { 'stash', '--quiet', '--message', '(mini.deps) 2024-01-02 03:04:05 Stash before checkout' },\n      cwd = cwd_plugin_1,\n    },\n    { args = { 'checkout', '--quiet', 'new1head' }, cwd = cwd_plugin_1 },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should produce notifications\n  local ref_notify_log = {\n    { '(mini.deps) (1/1) Checked out `new1head` in `plugin_1`', 'INFO' },\n    { '(mini.deps) Error in `plugin_2` during applying snapshot\\nERROR CODE 1\\nError getting HEAD', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\n\n  -- Should generate help tags in actually checked out plugins\n  local tags_lines = child.fn.readfile(test_opt_dir .. '/plugin_1/doc/tags')\n  eq(tags_lines, { 'depstest_plugin_1_tag\\thelp_1.txt\\t/*depstest_plugin_1_tag*' })\n  eq(child.fn.filereadable(test_opt_dir .. '/plugin_2/doc/tags'), 0)\n\n  -- - Help tags should be actually reachable\n  local help_tags = child.fn.getcompletion('depstest_', 'help')\n  table.sort(help_tags)\n  eq(help_tags, { 'depstest_plugin_1_tag' })\n\n  -- Should not affect current session data\n  eq(get_session(), init_session)\nend\n\nT['snap_set()']['checks for executable Git'] = function()\n  add('plugin_1')\n  child.lua([[\n    _G.stdio_queue = { { err = 'No Git'} }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n  expect.error(function() snap_set({}) end, 'Could not find executable `git` CLI tool')\nend\n\nT['snap_set()']['validates arguments'] = function()\n  expect.error(function() snap_set(1) end, 'Snapshot.*table')\nend\n\nT['snap_load()'] = new_set({\n  hooks = {\n    pre_case = function() child.lua('MiniDeps.snap_set = function(...) _G.snap_set_args = { ... } end') end,\n  },\n})\n\nlocal snap_load = forward_lua('MiniDeps.snap_load')\n\nT['snap_load()']['works'] = function()\n  load_module({ path = { snapshot = test_snap_path } })\n  snap_load()\n  eq(child.lua_get('_G.snap_set_args'), { { plugin_1 = 'sha1head', plugin_2 = 'sha2head' } })\nend\n\nT['snap_load()']['respects `path`'] = function()\n  local validate = function(path)\n    snap_load(path)\n    eq(child.lua_get('_G.snap_set_args'), { { plugin_1 = 'sha1head', plugin_2 = 'sha2head' } })\n    child.lua('_G.snap_set_args = nil')\n  end\n\n  -- Should work both with absolute and relative paths\n  validate(test_dir_absolute .. '/snapshots/snap')\n  validate(test_dir .. '/snapshots/snap')\nend\n\nT['snap_load()']['validates arguments'] = function()\n  expect.error(function() snap_load(1) end, '`path`.*readable file')\n\n  -- Should validate if file contains proper-ish snapshot\n  local validate = function(path)\n    expect.error(function() snap_load(path) end, '`path`.*not a path to proper snapshot')\n  end\n  validate(test_dir_absolute .. '/snapshots/not-proper-1')\n  validate(test_dir_absolute .. '/snapshots/not-proper-2')\nend\n\nT['snap_save()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Use path in non-existing directory to test parent directory creation\n      local snap_path = test_dir_absolute .. '/test-snap-save/snap'\n      load_module({ path = { snapshot = snap_path } })\n      child.lua([[\n        MiniDeps.snap_get = function() return { plugin_1 = 'sha1head', ['bad name'] = 'shaBhead' } end\n      ]])\n    end,\n    post_case = function() child.fn.delete(test_dir_absolute .. '/test-snap-save', 'rf') end,\n  },\n})\n\nlocal snap_save = forward_lua('MiniDeps.snap_save')\n\nT['snap_save()']['works'] = function()\n  local validate = function(path)\n    eq(child.fn.readfile(path), { 'return {', '  [\"bad name\"] = \"shaBhead\",', '  plugin_1 = \"sha1head\"', '}' })\n  end\n\n  snap_save()\n  local def_path = child.lua_get('MiniDeps.config.path.snapshot')\n  validate(def_path)\n\n  -- Should produce notifications\n  validate_notifications({\n    { '(mini.deps) Created snapshot at ' .. vim.inspect(def_path), 'INFO' },\n  })\n\n  -- Should respect `path`\n  local path = test_dir_absolute .. '/test-snap-save/other-snap'\n  snap_save(path)\n  validate(path)\nend\n\nT['snap_save()']['validates arguments'] = function()\n  expect.error(function() snap_save(1) end, '`path`.*string')\nend\n\nT['get_session()'] = new_set({ hooks = { pre_case = mock_test_package } })\n\nT['get_session()']['works'] = function()\n  add('plugin_1')\n  add({ source = 'https://my_site.com/plugin_2', depends = { 'user/plugin_3' } })\n  eq(get_session(), {\n    { path = test_opt_dir .. '/plugin_1', name = 'plugin_1', depends = {}, hooks = {} },\n    {\n      path = test_opt_dir .. '/plugin_3',\n      name = 'plugin_3',\n      source = 'https://github.com/user/plugin_3',\n      depends = {},\n      hooks = {},\n    },\n    {\n      path = test_opt_dir .. '/plugin_2',\n      name = 'plugin_2',\n      source = 'https://my_site.com/plugin_2',\n      depends = { 'user/plugin_3' },\n      hooks = {},\n    },\n  })\nend\n\nT['get_session()']['works even after several similar `add()`'] = function()\n  add({ source = 'user/plugin_1', checkout = 'hello', depends = { 'plugin_2' } })\n  -- Every extra adding should override previous but only new data fields\n  add({ name = 'plugin_1', checkout = 'hello' })\n  add({ name = 'plugin_2', checkout = 'world' })\n  add({ source = 'https://my_site.com/plugin_1', depends = { 'plugin_3' } })\n\n  eq(get_session(), {\n    { path = test_opt_dir .. '/plugin_2', name = 'plugin_2', depends = {}, hooks = {}, checkout = 'world' },\n    {\n      path = test_opt_dir .. '/plugin_1',\n      name = 'plugin_1',\n      source = 'https://my_site.com/plugin_1',\n      -- Although both 'plugin_2' and 'plugin_3' are in dependencies,\n      -- 'plugin_1' was added only indicating 'plugin_2' as dependency, so it\n      -- only has it in session before itself.\n      depends = { 'plugin_2', 'plugin_3' },\n      hooks = {},\n      checkout = 'hello',\n    },\n    { path = test_opt_dir .. '/plugin_3', name = 'plugin_3', depends = {}, hooks = {} },\n  })\nend\n\nT['get_session()'][\"respects plugins from 'start' directory which are in 'runtimepath'\"] = function()\n  local start_dir = test_dir_absolute .. '/pack/deps/start'\n  mock_plugin(start_dir .. '/start')\n  mock_plugin(start_dir .. '/start_manual')\n  mock_plugin(start_dir .. '/start_manual_dependency')\n  mock_plugin(start_dir .. '/start_not_in_rtp')\n  MiniTest.finally(function() child.fn.delete(start_dir, 'rf') end)\n  mock_test_package(test_dir_absolute)\n\n  -- Make sure that only somem of 'start' plugins are in 'runtimepath'\n  local lua_cmd = string.format(\n    'vim.api.nvim_list_runtime_paths = function() return { %s, %s, %s } end',\n    vim.inspect(start_dir .. '/start_manual'),\n    vim.inspect(start_dir .. '/start_manual_dependency'),\n    vim.inspect(start_dir .. '/start')\n  )\n  child.lua(lua_cmd)\n\n  -- Add some plugins manually both from 'opt' and 'start' directories\n  add('plugin_1')\n  add({ source = 'user/start_manual', depends = { 'start_manual_dependency' } })\n\n  eq(get_session(), {\n    -- Should add plugins from \"start\" *after* manually added ones\n    { path = test_opt_dir .. '/plugin_1', name = 'plugin_1', depends = {}, hooks = {} },\n\n    -- Should not affect or duplicate already manually added ones\n    { path = start_dir .. '/start_manual_dependency', name = 'start_manual_dependency', depends = {}, hooks = {} },\n\n    {\n      path = start_dir .. '/start_manual',\n      name = 'start_manual',\n      source = 'https://github.com/user/start_manual',\n      depends = { 'start_manual_dependency' },\n      hooks = {},\n    },\n\n    { path = start_dir .. '/start', name = 'start', depends = {}, hooks = {} },\n  })\nend\n\nT['get_session()']['returns copy'] = function()\n  add({ name = 'plugin_1', depends = { 'plugin_2' } })\n  child.lua([[\n    _G.session = MiniDeps.get_session()\n    _G.session[1].name = 'new name'\n    _G.session[2].depends = { 'new dep' }\n  ]])\n  local session = get_session()\n  eq(session[1].name, 'plugin_2')\n  eq(session[2].depends, { 'plugin_2' })\nend\n\nT['now()'] = new_set()\n\nT['now()']['works'] = function()\n  -- Should execute input right now\n  child.lua([[\n    _G.log = {}\n    MiniDeps.now(function() log[#log + 1] = 'now' end)\n    log[#log + 1] = 'after now'\n  ]])\n  eq(child.lua_get('_G.log'), { 'now', 'after now' })\nend\n\nT['now()']['can be called inside other `now()`/`later()` call'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniDeps.now(function()\n      log[#log + 1] = 'now'\n      MiniDeps.now(function() log[#log + 1] = 'now_now' end)\n    end)\n    MiniDeps.later(function()\n      log[#log + 1] = 'later'\n      MiniDeps.now(function() log[#log + 1] = 'later_now' end)\n    end)\n    _G.immediate_log = vim.deepcopy(_G.log)\n  ]])\n  eq(child.lua_get('_G.immediate_log'), { 'now', 'now_now' })\n\n  sleep(small_time)\n  eq(child.lua_get('_G.log'), { 'now', 'now_now', 'later', 'later_now' })\nend\n\nT['now()']['clears queue between different event loops'] = function()\n  child.lua([[\n    _G.log = {}\n    _G.f = function() log[#log + 1] = 'now' end\n    MiniDeps.now(_G.f)\n    _G.immediate_log = vim.deepcopy(_G.log)\n  ]])\n  eq(child.lua_get('_G.immediate_log'), { 'now' })\n\n  sleep(small_time)\n  child.lua('MiniDeps.now(_G.f)')\n  -- If it did not clear the queue, it would have been 3 elements\n  eq(child.lua_get('_G.log'), { 'now', 'now' })\nend\n\nT['now()']['notifies about errors after everything is executed'] = function()\n  child.lua([[\n    MiniDeps.now(function() error('Inside now()') end)\n    local f = function() vim.notify('Info', vim.log.levels.INFO) end\n    MiniDeps.later(f)\n    MiniDeps.later(f)\n  ]])\n\n  sleep(2 * small_time)\n  validate_notifications({ { 'Info', 'INFO' }, { 'Info', 'INFO' }, { 'errors.*Inside now()', 'ERROR' } }, true)\nend\n\nT['now()']['shows all errors at once'] = function()\n  child.lua([[\n    MiniDeps.now(function() error('Inside now() #1') end)\n    MiniDeps.now(function() error('Inside now() #2') end)\n  ]])\n  sleep(micro_time)\n  validate_notifications({ { 'errors.*Inside now%(%) #1.*Inside now%(%) #2', 'ERROR' } }, true)\nend\n\nT['now()']['does not respect `config.silent`'] = function()\n  -- Should still show errors even if `config.silent = true`\n  child.lua('MiniDeps.config.silent = true')\n  child.lua('MiniDeps.now(function() error(\"Inside now()\") end)')\n  sleep(micro_time)\n  validate_notifications({ { 'Inside now%(%)', 'ERROR' } }, true)\nend\n\nT['later()'] = new_set()\n\nT['later()']['works'] = function()\n  -- Should execute input later without blocking\n  child.lua([[\n    _G.log = {}\n    MiniDeps.later(function() log[#log + 1] = 'later' end)\n    log[#log + 1] = 'after later'\n    _G.log_in_this_loop = vim.deepcopy(_G.log)\n  ]])\n  eq(child.lua_get('_G.log_in_this_loop'), { 'after later' })\n\n  sleep(small_time)\n  eq(child.lua_get('_G.log'), { 'after later', 'later' })\nend\n\nT['later()']['can be called inside other `now()`/`later()` call'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniDeps.later(function()\n      log[#log + 1] = 'later'\n      MiniDeps.later(function() log[#log + 1] = 'later_later' end)\n    end)\n    MiniDeps.now(function()\n      log[#log + 1] = 'now'\n      MiniDeps.later(function() log[#log + 1] = 'now_later' end)\n    end)\n    _G.immediate_log = vim.deepcopy(_G.log)\n  ]])\n  eq(child.lua_get('_G.immediate_log'), { 'now' })\n\n  sleep(2 * small_time)\n  eq(child.lua_get('_G.log'), { 'now', 'later', 'now_later', 'later_later' })\nend\n\nT['later()']['clears queue between different event loops'] = function()\n  child.lua([[\n    _G.log = {}\n    _G.f = function() log[#log + 1] = 'later' end\n    MiniDeps.later(_G.f)\n    _G.immediate_log = vim.deepcopy(_G.log)\n  ]])\n  eq(child.lua_get('_G.immediate_log'), {})\n  sleep(micro_time)\n  eq(child.lua_get('_G.log'), { 'later' })\n\n  child.lua('MiniDeps.later(_G.f)')\n  -- If it did not clear the queue, it would have been 3 elements\n  sleep(2 * micro_time)\n  eq(child.lua_get('_G.log'), { 'later', 'later' })\nend\n\nT['later()']['notifies about errors after everything is executed'] = function()\n  child.lua([[\n    MiniDeps.later(function() error('Inside later()') end)\n    local f = function() vim.notify('Info', vim.log.levels.INFO) end\n    MiniDeps.later(f)\n    MiniDeps.later(f)\n  ]])\n\n  sleep(2 * small_time)\n  validate_notifications({ { 'Info', 'INFO' }, { 'Info', 'INFO' }, { 'errors.*Inside later()', 'ERROR' } }, true)\nend\n\nT['later()']['shows all errors at once'] = function()\n  child.lua([[\n    MiniDeps.later(function() error('Inside later() #1') end)\n    MiniDeps.later(function() error('Inside later() #2') end)\n  ]])\n  sleep(2 * small_time)\n  validate_notifications({ { 'errors.*Inside later%(%) #1.*Inside later%(%) #2', 'ERROR' } }, true)\nend\n\nT['later()']['does not respect `config.silent`'] = function()\n  -- Should still show errors even if `config.silent = true`\n  child.lua('MiniDeps.config.silent = true')\n  child.lua('MiniDeps.later(function() error(\"Inside later()\") end)')\n  sleep(small_time)\n  validate_notifications({ { 'Inside later%(%)', 'ERROR' } }, true)\nend\n\n-- Integration tests ----------------------------------------------------------\nT['Commands'] =\n  new_set({ hooks = {\n    pre_case = function()\n      mock_test_package()\n      child.set_size(10, 30)\n    end,\n  } })\n\nlocal validate_cmd = function(cmd, ref_args)\n  child.lua('_G.args = nil')\n  child.cmd(cmd)\n  -- Use `vim.inspect()` because some arguments have troubles going through RPC\n  -- (like {nil, { ... }})\n  eq(child.lua_get('vim.inspect(_G.args)'), vim.inspect(ref_args))\nend\n\nT['Commands'][':DepsAdd works'] = function()\n  child.lua('MiniDeps.add = function(...) _G.args = { ... } end')\n\n  validate_cmd('DepsAdd user/new_plugin nothing_more should_be_added', { 'user/new_plugin' })\n\n  -- Should have proper completion\n  child.type_keys(':DepsAdd ', '<Tab>')\n  if child.fn.has('nvim-0.12') == 0 then\n    child.expect_screenshot()\n    return\n  end\n  local ref_cmdcomplete_info = {\n    cmdline_orig = 'DepsAdd ',\n    matches = { 'plu-gin_0.nvim', 'plugin_1', 'plugin_2', 'plugin_3' },\n    pum_visible = 1,\n    selected = 0,\n  }\n  eq(child.fn.cmdcomplete_info(), ref_cmdcomplete_info)\nend\n\nT['Commands'][':DepsUpdate works'] = function()\n  child.lua('MiniDeps.update = function(...) _G.args = { ... } end')\n  add('plugin_1')\n  add('plugin_2')\n\n  validate_cmd('DepsUpdate', { nil, { force = false, offline = false } })\n  validate_cmd(\n    'DepsUpdate plugin_1 plugin_2 plugin_3',\n    { { 'plugin_1', 'plugin_2', 'plugin_3' }, { force = false, offline = false } }\n  )\n\n  -- Should accept bang\n  validate_cmd('DepsUpdate!', { nil, { force = true, offline = false } })\n  validate_cmd(\n    'DepsUpdate! plugin_1 plugin_2 plugin_3',\n    { { 'plugin_1', 'plugin_2', 'plugin_3' }, { force = true, offline = false } }\n  )\n\n  -- Should have proper completion\n  child.type_keys(':DepsUpdate ', '<Tab>')\n  if child.fn.has('nvim-0.12') == 0 then\n    child.expect_screenshot()\n    return\n  end\n  local ref_cmdcomplete_info = {\n    cmdline_orig = 'DepsUpdate ',\n    matches = { 'plugin_1', 'plugin_2' },\n    pum_visible = 1,\n    selected = 0,\n  }\n  eq(child.fn.cmdcomplete_info(), ref_cmdcomplete_info)\nend\n\nT['Commands'][':DepsUpdateOffline works'] = function()\n  child.lua('MiniDeps.update = function(...) _G.args = { ... } end')\n  add('plugin_1')\n  add('plugin_2')\n\n  validate_cmd('DepsUpdateOffline', { nil, { force = false, offline = true } })\n  validate_cmd(\n    'DepsUpdateOffline plugin_1 plugin_2 plugin_3',\n    { { 'plugin_1', 'plugin_2', 'plugin_3' }, { force = false, offline = true } }\n  )\n\n  -- Should accept bang\n  validate_cmd('DepsUpdateOffline!', { nil, { force = true, offline = true } })\n  validate_cmd(\n    'DepsUpdateOffline! plugin_1 plugin_2 plugin_3',\n    { { 'plugin_1', 'plugin_2', 'plugin_3' }, { force = true, offline = true } }\n  )\n\n  -- Should have proper completion\n  child.type_keys(':DepsUpdateOffline ', '<Tab>')\n  if child.fn.has('nvim-0.12') == 0 then\n    child.expect_screenshot()\n    return\n  end\n  local ref_cmdcomplete_info = {\n    cmdline_orig = 'DepsUpdateOffline ',\n    matches = { 'plugin_1', 'plugin_2' },\n    pum_visible = 1,\n    selected = 0,\n  }\n  eq(child.fn.cmdcomplete_info(), ref_cmdcomplete_info)\nend\n\nT['Commands'][':DepsShowLog works'] = function()\n  child.set_size(12, 60)\n  load_module({ path = { package = test_opt_dir, log = test_dir_absolute .. '/test-log' } })\n  local n_bufs = #child.api.nvim_list_bufs()\n  child.cmd('DepsShowLog')\n  child.expect_screenshot()\n\n  -- Should open path in relative form for nicer `:buffers`\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), 'tests/dir%-deps/test%-log')\n\n  -- Should mimic `:h buffer-reuse` similar to how `:edit` does it\n  eq(#child.api.nvim_list_bufs(), n_bufs)\nend\n\nT['Commands'][':DepsClean works'] = function()\n  child.lua('MiniDeps.clean = function(...) _G.args = { ... } end')\n  validate_cmd('DepsClean', { { force = false } })\n  validate_cmd('DepsClean!', { { force = true } })\nend\n\nT['Commands'][':DepsSnapSave works'] = function()\n  child.lua('MiniDeps.snap_save = function(...) _G.args = { ... } end')\n\n  validate_cmd('DepsSnapSave', {})\n  validate_cmd('DepsSnapSave path/to/file should_not be_used', { 'path/to/file' })\n\n  -- Should have proper completion\n  eq(child.api.nvim_get_commands({})['DepsSnapSave'].complete, 'file')\nend\n\nT['Commands'][':DepsSnapLoad works'] = function()\n  child.lua('MiniDeps.snap_load = function(...) _G.args = { ... } end')\n\n  validate_cmd('DepsSnapLoad', {})\n  validate_cmd('DepsSnapLoad path/to/file should_not be_used', { 'path/to/file' })\n\n  -- Should have proper completion\n  eq(child.api.nvim_get_commands({})['DepsSnapLoad'].complete, 'file')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_diff.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('diff', config) end\nlocal unload_module = function(config) child.mini_unload('diff', config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\nlocal new_buf = function() return child.api.nvim_create_buf(true, false) end\nlocal new_scratch_buf = function() return child.api.nvim_create_buf(false, true) end\nlocal get_buf = function() return child.api.nvim_get_current_buf() end\nlocal set_buf = function(buf_id) child.api.nvim_set_current_buf(buf_id) end\n--stylua: ignore end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nlocal islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nlocal test_dir = 'tests/dir-diff'\nlocal test_dir_absolute = vim.fs.normalize(vim.fn.fnamemodify(test_dir, ':p')):gsub('(.)/$', '%1')\nlocal test_file_path = test_dir_absolute .. '/file'\n\nlocal git_repo_dir = test_dir_absolute .. '/git-repo'\nlocal git_git_dir = git_repo_dir .. '/.git-dir'\nlocal git_dir_path = git_repo_dir .. '/dir-in-git'\nlocal git_file_basename = 'file-in-git'\nlocal git_file_path = git_repo_dir .. '/dir-in-git/' .. git_file_basename\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\n-- Time constants\nlocal default_watch_debounce_delay = 50\nlocal dummy_text_change_delay = helpers.get_time_const(30)\nlocal small_time = helpers.get_time_const(10)\nlocal micro_time = 1\n\n-- Common wrappers\nlocal edit = function(path)\n  child.cmd('edit ' .. child.fn.fnameescape(path))\n  -- Slow context needs a small delay to get things up to date\n  if helpers.is_slow() then sleep(small_time) end\nend\n\nlocal set_ref_text = function(...)\n  child.lua([[require('mini.diff').set_ref_text(...)]], { ... })\n  -- Slow context needs a small delay to get things up to date\n  if helpers.is_slow() then sleep(small_time) end\nend\n\nlocal get_buf_hunks = function(buf_id)\n  buf_id = buf_id or 0\n  return child.lua_get('require(\"mini.diff\").get_buf_data(' .. buf_id .. ').hunks')\nend\n\nlocal get_buf_data = function(buf_id)\n  return child.lua(\n    [[\n      local res = require('mini.diff').get_buf_data(...)\n      if res == nil then return nil end\n      -- Can not return callables from child process\n      res.config.source = nil\n      return res\n    ]],\n    { buf_id }\n  )\nend\n\nlocal is_buf_enabled = function(buf_id) return get_buf_data(buf_id) ~= vim.NIL end\n\n-- - Dummy source, which is set by default in most tests\nlocal setup_with_dummy_source = function(text_change_delay)\n  text_change_delay = text_change_delay or dummy_text_change_delay\n  child.lua('_G.text_change_delay = ' .. text_change_delay)\n  child.lua([[\n    _G.dummy_log = {}\n    _G.dummy_source = {\n      name = 'dummy',\n      attach = function(...) table.insert(_G.dummy_log, { 'attach', { ... } }) end,\n      detach = function(...) table.insert(_G.dummy_log, { 'detach', { ... } }) end,\n      apply_hunks = function(...) table.insert(_G.dummy_log, { 'apply_hunks', { ... } }) end,\n    }\n    require('mini.diff').setup({ source = _G.dummy_source, delay = { text_change = _G.text_change_delay } })\n  ]])\nend\n\nlocal validate_dummy_log = function(ref_log) eq(child.lua_get('_G.dummy_log'), ref_log) end\n\nlocal clean_dummy_log = function() child.lua('_G.dummy_log = {}') end\n\n-- - Git mocks\nlocal mock_count_set_ref_text = function()\n  child.lua([[\n    local set_ref_text_orig = MiniDiff.set_ref_text\n    _G.n_set_ref_text_calls = 0\n    MiniDiff.set_ref_text = function(...)\n      _G.n_set_ref_text_calls = _G.n_set_ref_text_calls + 1\n      set_ref_text_orig(...)\n    end\n  ]])\nend\n\nlocal mock_change_git_index = function()\n  local index_path = git_git_dir .. '/index'\n  child.fn.writefile({}, index_path .. '.lock')\n  sleep(micro_time)\n  child.fn.delete(index_path)\n  child.loop.fs_rename(index_path .. '.lock', index_path)\nend\n\nlocal mock_spawn = function()\n  local mock_file = test_dir_absolute .. '/mocks/spawn.lua'\n  local lua_cmd = string.format('dofile(%s)', vim.inspect(mock_file))\n  child.lua(lua_cmd)\nend\n\nlocal get_spawn_log = function() return child.lua_get('_G.spawn_log') end\n\nlocal validate_git_spawn_log = function(ref_log)\n  local spawn_log = get_spawn_log()\n\n  local n = math.max(#spawn_log, #ref_log)\n  for i = 1, n do\n    local real, ref = spawn_log[i], ref_log[i]\n    if real == nil then\n      eq('Real spawn log does not have entry for present reference log entry', ref)\n    elseif ref == nil then\n      eq(real, 'Reference does not have entry for present spawn log entry')\n    elseif islist(ref) then\n      eq(real, { executable = 'git', options = { args = ref, cwd = real.options.cwd } })\n    else\n      if real.options.cwd ~= nil then real.options.cwd = child.fs.normalize(real.options.cwd) end\n      eq(real, { executable = 'git', options = ref })\n    end\n  end\nend\n\nlocal get_process_log = function() return child.lua_get('_G.process_log') end\n\n-- - Notifications\nlocal mock_notify = function()\n  child.lua([[\n    _G.notify_log = {}\n    vim.notify = function(...) table.insert(_G.notify_log, { ... }) end\n  ]])\nend\n\nlocal get_notify_log = function() return child.lua_get('_G.notify_log') end\n\nlocal validate_notifications = function(ref_log, msg_pattern)\n  local notify_log = get_notify_log()\n  local n = math.max(#notify_log, #ref_log)\n  for i = 1, n do\n    local real, ref = notify_log[i], ref_log[i]\n    if real == nil then\n      eq('Real notify log does not have entry for present reference log entry', ref)\n    elseif ref == nil then\n      eq(real, 'Reference does not have entry for present notify log entry')\n    else\n      local expect_msg = msg_pattern and expect.match or eq\n      expect_msg(real[1], ref[1])\n      eq(real[2], child.lua_get('vim.log.levels.' .. ref[2]))\n    end\n  end\nend\n\nlocal clear_notify_log = function() return child.lua('_G.notify_log = {}') end\n\n-- Module helpers\nlocal setup_enabled_buffer = function()\n  -- Usually used to make tests on not initial (kind of special) buffer\n  local init_buf_id = get_buf()\n  set_buf(new_buf())\n  child.lua('MiniDiff.enable(0)')\n  child.api.nvim_buf_delete(init_buf_id, { force = true })\n  clean_dummy_log()\nend\n\nlocal get_viz_extmarks = function(buf_id)\n  local ns_id = child.api.nvim_get_namespaces().MiniDiffViz\n  local full_extmarks = child.api.nvim_buf_get_extmarks(buf_id, ns_id, 0, -1, { details = true })\n  local res = {}\n  for _, e in ipairs(full_extmarks) do\n    -- Do not test with dummy extmark (placed to ensure visible signcolumn)\n    local is_dummy_extmark = e[2] == 0\n      and e[3] == 0\n      and e[4].sign_text == '  '\n      and e[4].sign_hl_group == 'SignColumn'\n      and e[4].cursorline_hl_group == 'CursorLineSign'\n      and e[4].right_gravity == false\n    if not is_dummy_extmark then\n      table.insert(res, {\n        line = e[2] + 1,\n        sign_hl_group = e[4].sign_hl_group,\n        sign_text = e[4].sign_text,\n        number_hl_group = e[4].number_hl_group,\n      })\n    end\n  end\n  return res\nend\n\nlocal validate_viz_extmarks = function(buf_id, ref) eq(get_viz_extmarks(buf_id), ref) end\n\nlocal get_overlay_extmarks = function(buf_id, from_line, to_line)\n  local ns_id = child.api.nvim_get_namespaces().MiniDiffOverlay\n  return child.api.nvim_buf_get_extmarks(buf_id, ns_id, { from_line - 1, 0 }, { to_line - 1, -1 }, { details = true })\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      child.set_size(10, 15)\n      mock_notify()\n      setup_with_dummy_source()\n      clean_dummy_log()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniDiff)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniDiff'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local is_010 = child.fn.has('nvim-0.10') == 1\n  local validate_hl_group = function(name, pattern) expect.match(child.cmd_capture('hi ' .. name), pattern) end\n\n  validate_hl_group('MiniDiffSignAdd', 'links to ' .. (is_010 and 'Added' or 'diffAdded'))\n  validate_hl_group('MiniDiffSignChange', 'links to ' .. (is_010 and 'Changed' or 'diffChanged'))\n  validate_hl_group('MiniDiffSignDelete', 'links to ' .. (is_010 and 'Removed' or 'diffRemoved'))\n  validate_hl_group('MiniDiffOverAdd', 'links to DiffAdd')\n  validate_hl_group('MiniDiffOverChange', 'links to DiffText')\n  validate_hl_group('MiniDiffOverChangeBuf', 'links to MiniDiffOverChange')\n  validate_hl_group('MiniDiffOverContext', 'links to DiffChange')\n  eq(child.fn.hlexists('MiniFilesFile'), 1)\n  validate_hl_group('MiniDiffOverDelete', 'links to DiffDelete')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n\n  eq(child.lua_get('type(_G.MiniDiff.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniDiff.config.' .. field), value) end\n\n  expect_config('view.style', 'sign')\n  expect_config('view.signs', { add = '▒', change = '▒', delete = '▒' })\n  expect_config('view.priority', child.highlight.priorities.user - 1)\n  expect_config('source', vim.NIL)\n  expect_config('delay.text_change', 200)\n  expect_config('mappings.apply', 'gh')\n  expect_config('mappings.reset', 'gH')\n  expect_config('mappings.textobject', 'gh')\n  expect_config('mappings.goto_first', '[H')\n  expect_config('mappings.goto_prev', '[h')\n  expect_config('mappings.goto_next', ']h')\n  expect_config('mappings.goto_last', ']H')\n  expect_config('options.algorithm', 'histogram')\n  expect_config('options.indent_heuristic', true)\n  expect_config('options.linematch', 60)\n  expect_config('options.wrap_goto', false)\nend\n\nT['setup()'][\"respects global 'number' option when setting default `view.style`\"] = function()\n  unload_module()\n  child.go.number, child.wo.number = true, false\n  load_module()\n  eq(child.lua_get('MiniDiff.config.view.style'), 'number')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  load_module({ delay = { text_change = 20 } })\n  eq(child.lua_get('MiniDiff.config.delay.text_change'), 20)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ view = 'a' }, 'view', 'table')\n  expect_config_error({ view = { style = 1 } }, 'view.style', 'string')\n  expect_config_error({ view = { signs = 'a' } }, 'view.signs', 'table')\n  expect_config_error({ view = { signs = { add = 1 } } }, 'view.signs.add', 'string')\n  expect_config_error({ view = { signs = { change = 1 } } }, 'view.signs.change', 'string')\n  expect_config_error({ view = { signs = { delete = 1 } } }, 'view.signs.delete', 'string')\n  expect_config_error({ view = { priority = 'a' } }, 'view.priority', 'number')\n\n  expect_config_error({ source = 'a' }, 'source', 'table')\n\n  expect_config_error({ delay = 'a' }, 'delay', 'table')\n  expect_config_error({ delay = { text_change = 'a' } }, 'delay.text_change', 'number')\n\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { apply = 1 } }, 'mappings.apply', 'string')\n  expect_config_error({ mappings = { reset = 1 } }, 'mappings.reset', 'string')\n  expect_config_error({ mappings = { textobject = 1 } }, 'mappings.textobject', 'string')\n  expect_config_error({ mappings = { goto_first = 1 } }, 'mappings.goto_first', 'string')\n  expect_config_error({ mappings = { goto_prev = 1 } }, 'mappings.goto_prev', 'string')\n  expect_config_error({ mappings = { goto_next = 1 } }, 'mappings.goto_next', 'string')\n  expect_config_error({ mappings = { goto_last = 1 } }, 'mappings.goto_last', 'string')\n\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { algorithm = 1 } }, 'options.algorithm', 'string')\n  expect_config_error({ options = { indent_heuristic = 'a' } }, 'options.indent_heuristic', 'boolean')\n  expect_config_error({ options = { linematch = 'a' } }, 'options.linematch', 'number')\n  expect_config_error({ options = { wrap_goto = 'a' } }, 'options.wrap_goto', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniDiffOverAdd'), 'links to DiffAdd')\nend\n\nT['setup()']['auto enables in all existing loaded buffers'] = function()\n  unload_module()\n\n  local buf_id_cur_normal = new_buf()\n  set_buf(buf_id_cur_normal)\n  local buf_id_other_normal = new_buf()\n\n  local buf_id_bad_1 = new_scratch_buf()\n  local buf_id_bad_2 = new_buf()\n  child.api.nvim_buf_set_lines(buf_id_bad_2, 0, -1, false, { '\\0' })\n\n  local buf_id_bad_3 = new_buf()\n  child.api.nvim_buf_delete(buf_id_bad_3, { unload = true })\n  eq(child.api.nvim_buf_is_loaded(buf_id_bad_3), false)\n  child.api.nvim_set_option_value('buflisted', true, { buf = buf_id_bad_3 })\n\n  setup_with_dummy_source()\n\n  -- Only normal valid loaded text buffers should be auto enabled\n  eq(is_buf_enabled(buf_id_cur_normal), true)\n  eq(is_buf_enabled(buf_id_other_normal), true)\n  eq(is_buf_enabled(buf_id_bad_1), false)\n  eq(is_buf_enabled(buf_id_bad_2), false)\n  eq(is_buf_enabled(buf_id_bad_3), false)\n\n  -- Should not force load unloaded buffers\n  eq(child.api.nvim_buf_is_loaded(buf_id_bad_3), false)\nend\n\nT['setup()']['can not create mappings'] = function()\n  child.api.nvim_del_keymap('n', 'gh')\n  load_module({ mappings = { apply = '' } })\n  eq(child.fn.maparg('gh', 'n'), '')\nend\n\nT['enable()'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nlocal enable = forward_lua('MiniDiff.enable')\n\nT['enable()']['works in not normal buffer'] = function()\n  local buf_id = new_scratch_buf()\n  set_buf(buf_id)\n  clean_dummy_log()\n  enable(buf_id)\n  validate_dummy_log({ { 'attach', { buf_id } } })\nend\n\nT['enable()']['works in not current buffer'] = function()\n  local buf_id = new_buf()\n  enable(buf_id)\n  validate_dummy_log({ { 'attach', { buf_id } } })\n  eq(is_buf_enabled(buf_id), true)\nend\n\nT['enable()']['normalizes input buffer'] = function()\n  local buf_id = new_scratch_buf()\n  set_buf(buf_id)\n  clean_dummy_log()\n  enable(0)\n  eq(is_buf_enabled(buf_id), true)\nend\n\nT['enable()']['does not re-enable already enabled buffer'] = function()\n  enable()\n  validate_dummy_log({})\nend\n\nT['enable()']['makes sure buffer is loaded'] = function()\n  -- Set up not loaded but existing buffer with lines\n  local new_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(new_buf_id, 0, -1, false, { 'aaa', 'bbb' })\n  child.api.nvim_buf_set_option(new_buf_id, 'modified', false)\n  child.api.nvim_buf_delete(new_buf_id, { unload = true })\n  eq(child.api.nvim_buf_get_lines(new_buf_id, 0, -1, false), {})\n\n  -- Should also not trigger `*Enter` events\n  child.cmd('au BufEnter,BufWinEnter * lua _G.n = (_G.n or 0) + 1')\n  enable(new_buf_id)\n  eq(child.fn.bufloaded(new_buf_id), 1)\n  eq(child.lua_get('_G.n'), vim.NIL)\nend\n\nT['enable()']['makes buffer update cache on `BufWinEnter`'] = function()\n  eq(get_buf_data().config.delay.text_change, dummy_text_change_delay)\n  child.b.minidiff_config = { delay = { text_change = 200 } }\n  child.api.nvim_exec_autocmds('BufWinEnter', { buffer = get_buf() })\n  eq(get_buf_data().config.delay.text_change, 200)\nend\n\nT['enable()']['makes buffer disabled when deleted'] = function()\n  local alt_buf_id = new_buf()\n  enable(alt_buf_id)\n  clean_dummy_log()\n\n  local buf_id = get_buf()\n  child.api.nvim_buf_delete(buf_id, { force = true })\n  validate_dummy_log({ { 'detach', { buf_id } } })\nend\n\nT['enable()']['makes buffer reset on rename'] = function()\n  local buf_id = get_buf()\n  child.api.nvim_buf_set_name(0, 'hello')\n  validate_dummy_log({ { 'detach', { buf_id } }, { 'attach', { buf_id } } })\nend\n\nT['enable()']['validates arguments'] = function()\n  expect.error(function() enable({}) end, '`buf_id`.*valid buffer id')\nend\n\nT['enable()']['respects `vim.{g,b}.minidiff_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local buf_id = new_buf()\n    if var_type == 'b' then child.api.nvim_buf_set_var(buf_id, 'minidiff_disable', true) end\n    if var_type == 'g' then child.api.nvim_set_var('minidiff_disable', true) end\n    enable(buf_id)\n    validate_dummy_log({})\n    eq(is_buf_enabled(buf_id), false)\n  end,\n})\n\nT['enable()']['respects `vim.b.minidiff_config`'] = function()\n  local buf_id = new_buf()\n  child.api.nvim_buf_set_var(buf_id, 'minidiff_config', { delay = { text_change = 200 } })\n  enable(buf_id)\n  eq(get_buf_data(buf_id).config.delay.text_change, 200)\nend\n\nT['disable()'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nlocal disable = forward_lua('MiniDiff.disable')\n\nT['disable()']['works'] = function()\n  local buf_id = get_buf()\n  eq(is_buf_enabled(buf_id), true)\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n  eq(child.b.minidiff_summary == vim.NIL, false)\n  eq(child.b.minidiff_summary_string == vim.NIL, false)\n\n  disable(buf_id)\n  eq(is_buf_enabled(buf_id), false)\n\n  -- Should delete buffer autocommands\n  eq(child.api.nvim_get_autocmds({ buffer = buf_id }), {})\n\n  -- Should delete buffer-local variables\n  eq(child.b.minidiff_summary == vim.NIL, true)\n  eq(child.b.minidiff_summary_string == vim.NIL, true)\n\n  -- Should detach source\n  validate_dummy_log({ { 'detach', { buf_id } } })\n\n  -- Should clear visualization\n  child.expect_screenshot()\nend\n\nT['disable()']['works in not current buffer'] = function()\n  local buf_id = new_buf()\n  enable(buf_id)\n  clean_dummy_log()\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n\n  disable(buf_id)\n  eq(is_buf_enabled(buf_id), false)\n  validate_dummy_log({ { 'detach', { buf_id } } })\nend\n\nT['disable()']['works in not enabled buffer'] = function()\n  local buf_id = new_buf()\n  eq(is_buf_enabled(buf_id), false)\n  expect.no_error(function() disable(buf_id) end)\nend\n\nT['disable()']['normalizes input buffer'] = function()\n  local buf_id = new_scratch_buf()\n  set_buf(buf_id)\n\n  enable(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n  disable(0)\n  eq(is_buf_enabled(buf_id), false)\nend\n\nT['disable()']['validates arguments'] = function()\n  expect.error(function() disable('a') end, '`buf_id`.*valid buffer id')\nend\n\nT['toggle()'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nlocal toggle = forward_lua('MiniDiff.toggle')\n\nT['toggle()']['works'] = function()\n  child.lua([[\n    _G.log = {}\n    local cur_enable = MiniDiff.enable\n    MiniDiff.enable = function(...)\n      table.insert(_G.log, { 'enabled', { ... } })\n      cur_enable(...)\n    end\n    local cur_disable = MiniDiff.disable\n    MiniDiff.disable = function(...)\n      cur_disable(...)\n      table.insert(_G.log, { 'disabled', { ... } })\n    end\n  ]])\n\n  local buf_id = get_buf()\n  eq(is_buf_enabled(buf_id), true)\n  toggle(buf_id)\n  eq(is_buf_enabled(buf_id), false)\n  toggle(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n\n  eq(child.lua_get('_G.log'), { { 'disabled', { buf_id } }, { 'enabled', { buf_id } } })\nend\n\nT['toggle_overlay()'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nlocal toggle_overlay = forward_lua('MiniDiff.toggle_overlay')\n\nT['toggle_overlay()']['works'] = function()\n  local init_buf_id = get_buf()\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  -- Should be disabled by default\n  child.expect_screenshot()\n  toggle_overlay(init_buf_id)\n  child.expect_screenshot()\n\n  -- Should work per buffer\n  local buf_id = new_buf()\n  set_buf(buf_id)\n  set_lines({ 'AAA', 'uuu', 'BBB' })\n  set_ref_text(0, { 'AAA', 'BBB' })\n\n  child.expect_screenshot()\n  toggle_overlay(buf_id)\n  child.expect_screenshot()\n\n  -- Should work in not current buffer\n  toggle_overlay(init_buf_id)\n  set_buf(init_buf_id)\n  child.expect_screenshot()\nend\n\nT['toggle_overlay()']['validates arguments'] = function()\n  expect.error(function() toggle_overlay('a') end, '`buf_id`.*valid buffer id')\n\n  disable()\n  expect.error(function() toggle_overlay(0) end, 'Buffer.*not enabled')\nend\n\nT['export()'] = new_set()\n\nlocal export = forward_lua('MiniDiff.export')\n\nT['export()']['works with \"qf\" format'] = function()\n  edit(test_file_path)\n  local buf_id_1 = get_buf()\n  set_ref_text(buf_id_1, { 'aaa' })\n\n  local buf_id_2 = new_buf()\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(buf_id_2, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  --stylua: ignore\n  local ref = {\n    { bufnr = buf_id_1, lnum = 2, col = 1, end_lnum = 2, end_col = 4, type = 'A', text = 'Add',    filename = test_file_path },\n    { bufnr = buf_id_2, lnum = 2, col = 1, end_lnum = 2, end_col = 4, type = 'A', text = 'Add',    filename = '' },\n    { bufnr = buf_id_2, lnum = 4, col = 1, end_lnum = 4, end_col = 4, type = 'C', text = 'Change', filename = '' },\n    { bufnr = buf_id_2, lnum = 5, col = 1, end_lnum = 5, end_col = 1, type = 'D', text = 'Delete', filename = '' },\n  }\n  eq(export('qf'), ref)\nend\n\nT['export()']['works with multiline hunks'] = function()\n  local buf_id_1 = new_buf()\n  child.api.nvim_buf_set_lines(buf_id_1, 0, -1, false, { 'AAA', 'uuu', 'vv', 'BBB', 'CcC', 'DdD', 'EEE', 'HHH' })\n  set_ref_text(buf_id_1, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF', 'GGG', 'HHH' })\n  --stylua: ignore\n  local ref = {\n    { bufnr = buf_id_1, lnum = 2, col = 1, end_lnum = 3, end_col = 3, type = 'A', text = 'Add',    filename = '' },\n    { bufnr = buf_id_1, lnum = 5, col = 1, end_lnum = 6, end_col = 4, type = 'C', text = 'Change', filename = '' },\n    { bufnr = buf_id_1, lnum = 7, col = 1, end_lnum = 7, end_col = 1, type = 'D', text = 'Delete', filename = '' },\n  }\n  eq(export('qf'), ref)\nend\n\nT['export()']['respects `opts.scope`'] = function()\n  local buf_id_1 = new_buf()\n  child.api.nvim_buf_set_lines(buf_id_1, 0, -1, false, { 'aaa', 'uuu' })\n  set_ref_text(buf_id_1, { 'aaa' })\n  local buf_id_2 = new_buf()\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { 'aaa', 'uuu' })\n  set_ref_text(buf_id_2, { 'aaa' })\n\n  eq(export('qf', { scope = 'current' }), {})\n\n  set_buf(buf_id_1)\n  local ref_entry = { bufnr = 2, lnum = 2, col = 1, end_lnum = 2, end_col = 4, type = 'A', text = 'Add', filename = '' }\n  eq(export('qf', { scope = 'current' }), { ref_entry })\nend\n\nT['export()']['validates arguments'] = function()\n  expect.error(function() export('aaa') end, 'one of')\nend\n\nT['get_buf_data()'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nT['get_buf_data()']['works'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n\n  child.lua('_G.buf_data = MiniDiff.get_buf_data()')\n\n  -- Should have proper structure\n  local fields = child.lua_get('vim.tbl_keys(_G.buf_data)')\n  table.sort(fields)\n  eq(fields, { 'config', 'hunks', 'overlay', 'ref_text', 'summary' })\n\n  eq(child.lua_get('vim.deep_equal(MiniDiff.config, _G.buf_data.config)'), true)\n  eq(child.lua_get('_G.buf_data.summary'), { source_name = 'dummy', add = 1, change = 0, delete = 0, n_ranges = 1 })\n  eq(\n    child.lua_get('_G.buf_data.hunks'),\n    { { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' } }\n  )\n  eq(child.lua_get('_G.buf_data.ref_text'), 'aaa\\n')\n\n  eq(child.lua_get('_G.buf_data.overlay'), false)\n  toggle_overlay()\n  eq(child.lua_get('MiniDiff.get_buf_data().overlay'), true)\nend\n\nT['get_buf_data()']['works with not set reference text'] = function()\n  local buf_data = get_buf_data()\n  eq(buf_data.hunks, {})\n  eq(buf_data.summary, {})\n  eq(buf_data.ref_text, nil)\nend\n\nT['get_buf_data()']['works on not enabled buffer'] = function()\n  local out = child.lua([[\n    local buf_id = vim.api.nvim_create_buf(true, false)\n    return MiniDiff.get_buf_data(buf_id) == nil\n  ]])\n  eq(out, true)\nend\n\nT['get_buf_data()']['validates arguments'] = function()\n  expect.error(function() get_buf_data('a') end, '`buf_id`.*valid buffer id')\nend\n\nT['get_buf_data()']['returns copy of underlying data'] = function()\n  local out = child.lua([[\n    local buf_data = MiniDiff.get_buf_data()\n    buf_data.hunks = 'aaa'\n    return MiniDiff.get_buf_data().hunks ~= 'aaa'\n  ]])\n  eq(out, true)\nend\n\nT['get_buf_data()']['correctly computes summary numbers'] = function()\n  child.lua('MiniDiff.config.options.linematch = 0')\n  local buf_id = new_buf()\n  set_buf(buf_id)\n  enable(buf_id)\n  eq(get_buf_data(buf_id).config.options.linematch, 0)\n\n  local validate = function(ref_summary) eq(get_buf_data(buf_id).summary, ref_summary) end\n\n  -- Delete lines\n  set_lines({ 'BBB', 'DDD' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD' })\n  -- NOTE: Number of ranges is 1 because in buffer two delete hunks start on\n  -- consecutive lines\n  validate({ source_name = 'dummy', add = 0, change = 0, delete = 2, n_ranges = 1 })\n\n  -- Add lines\n  set_lines({ 'AAA', 'uuu', 'BBB', 'vvv' })\n  set_ref_text(0, { 'AAA', 'BBB' })\n  validate({ source_name = 'dummy', add = 2, change = 0, delete = 0, n_ranges = 2 })\n\n  -- Changed lines are computed per hunk as minimum number of added and deleted\n  -- lines. Excess is counted as corresponding lines (added/deleted)\n  set_lines({ 'aaa', 'CCC', 'ddd', 'eee', 'uuu' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE' })\n  local ref_hunks = {\n    { buf_start = 1, buf_count = 1, ref_start = 1, ref_count = 2, type = 'change' },\n    { buf_start = 3, buf_count = 3, ref_start = 4, ref_count = 2, type = 'change' },\n  }\n  eq(get_buf_hunks(buf_id), ref_hunks)\n  validate({ source_name = 'dummy', add = 1, change = 3, delete = 1, n_ranges = 2 })\nend\n\nT['get_buf_data()']['uses number of contiguous ranges in summary'] = function()\n  set_lines({ 'AAA', 'uuu', 'BbB', 'DDD', 'www', 'EEE' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE' })\n  local buf_data = get_buf_data()\n  eq(buf_data.hunks, {\n    { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' },\n    { buf_start = 3, buf_count = 1, ref_start = 2, ref_count = 1, type = 'change' },\n    { buf_start = 3, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' },\n    { buf_start = 5, buf_count = 1, ref_start = 4, ref_count = 0, type = 'add' },\n  })\n\n  eq(buf_data.summary.n_ranges, 2)\nend\n\nT['set_ref_text()'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nT['set_ref_text()']['works'] = function()\n  set_lines({ 'aaa' })\n\n  local validate = function(input_ref_text, ref_ref_text, ref_hunks)\n    set_ref_text(0, input_ref_text)\n    eq(get_buf_data().ref_text, ref_ref_text)\n    eq(get_buf_data().hunks, ref_hunks)\n  end\n  local ref_hunks = { { buf_start = 1, buf_count = 0, ref_start = 2, ref_count = 1, type = 'delete' } }\n\n  -- Should work with table input (as an array of lines)\n  validate({ 'aaa', 'bbb' }, 'aaa\\nbbb\\n', ref_hunks)\n\n  -- Should work with empty table to remove reference text\n  validate({}, nil, {})\n\n  -- Should work with string input\n  validate('aaa\\n\\n', 'aaa\\n\\n', ref_hunks)\n\n  -- Should append newline if not present\n  validate('aaa\\nccc', 'aaa\\nccc\\n', ref_hunks)\n  validate('aaa\\nccc\\n', 'aaa\\nccc\\n', ref_hunks)\nend\n\nT['set_ref_text()']['removing reference text removes visualization'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n  child.expect_screenshot()\n  set_ref_text(0, {})\n  child.expect_screenshot()\nend\n\nT['set_ref_text()']['enables not enabled buffer'] = function()\n  local buf_id = new_buf()\n  set_ref_text(buf_id, { 'aaa' })\n  eq(is_buf_enabled(buf_id), true)\n\n  -- Give informative error if could not enable\n  child.lua('MiniDiff.config.source = { attach = function() return false end }')\n  local new_buf_id = new_buf()\n  expect.error(function() set_ref_text(new_buf_id, { 'bbb' }) end, 'not enabled')\nend\n\nT['set_ref_text()']['immediately updates diff data and visualization'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n  local ref_hunks = { { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' } }\n  eq(get_buf_hunks(0), ref_hunks)\n  child.expect_screenshot()\nend\n\nT['set_ref_text()']['validates arguments'] = function()\n  expect.error(function() set_ref_text('a') end, '`buf_id`.*valid buffer id')\nend\n\nT['gen_source'] = new_set()\n\nT['gen_source']['git()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Although it is the default source, \"dummy\" source is set in earlier hook\n      child.lua('MiniDiff.config.source = MiniDiff.gen_source.git()')\n      local init_buf_id = get_buf()\n      set_buf(new_buf())\n      child.api.nvim_buf_delete(init_buf_id, { force = true })\n\n      -- Mock\n      mock_spawn()\n\n      -- Set some data in child process\n      child.lua('_G.git_dir = ' .. vim.inspect(git_git_dir))\n    end,\n    post_case = function()\n      -- Ensure no changes in reference git repo\n      local index_path = git_git_dir .. '/index'\n      vim.fn.delete(index_path .. '.lock')\n      if vim.fn.filereadable(index_path) == 0 then vim.fn.writefile({}, index_path) end\n    end,\n  },\n})\n\nT['gen_source']['git()']['works'] = function()\n  child.lua([[\n    _G.stdio_queue = {\n      { { 'out', _G.git_dir } },         -- Get path to repo's Git dir\n      { { 'out', 'Line 1\\nLine 2\\n' } }, -- Get reference text\n    }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), true)\n\n  -- Should set reference text immediately\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLine 2\\n')\n\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = git_dir_path },\n    { args = { 'show', ':0:./' .. git_file_basename }, cwd = git_dir_path },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLine 2\\n')\n\n  -- All processes and streams should be properly closed\n  --stylua: ignore\n  local ref_process_log = {\n    'Stream out for process 1 was closed.', 'Process 1 was closed.',\n    'Stream out for process 2 was closed.', 'Process 2 was closed.',\n  }\n  eq(get_process_log(), ref_process_log)\nend\n\nT['gen_source']['git()']['can apply hunks'] = function()\n  child.lua([[\n    local ref_text = table.concat({ 'Line -1', 'Line 0', 'Line 1', 'Line 22', 'Line 33', 'Line 4' }, '\\n')\n    _G.stdio_queue = {\n      { { 'out', _G.git_dir } },              -- Get path to repo's Git dir\n      { { 'out', ref_text } },                -- Get reference text\n      { { 'out', '100644 lf file-in-git' } }, -- Get path data for the patch\n      { { 'in' } },                           -- Apply patch\n    }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_data(0).ref_text, 'Line -1\\nLine 0\\nLine 1\\nLine 22\\nLine 33\\nLine 4\\n')\n\n  -- Make change\n  type_keys('G', 'cc', 'world')\n  sleep(small_time)\n\n  local ref_hunks = {\n    { buf_start = 0, buf_count = 0, ref_start = 1, ref_count = 2, type = 'delete' },\n    { buf_start = 2, buf_count = 2, ref_start = 4, ref_count = 2, type = 'change' },\n    { buf_start = 5, buf_count = 1, ref_start = 6, ref_count = 0, type = 'add' },\n  }\n  eq(get_buf_hunks(0), ref_hunks)\n\n  child.lua([[MiniDiff.do_hunks(0, 'apply')]])\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = git_dir_path },\n    { args = { 'show', ':0:./' .. git_file_basename }, cwd = git_dir_path },\n    {\n      args = { 'ls-files', '-z', '--full-name', '--format=%(objectmode) %(eolinfo:index) %(path)', '--', git_file_basename },\n      cwd = git_dir_path,\n    },\n    { args = { 'apply', '--whitespace=nowarn', '--cached', '--unidiff-zero', '-' }, cwd = git_dir_path },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- All processes and streams should be properly closed\n  --stylua: ignore\n  local ref_process_log = {\n    'Stream out for process 1 was closed.', 'Process 1 was closed.',\n    'Stream out for process 2 was closed.', 'Process 2 was closed.',\n    'Stream out for process 3 was closed.', 'Process 3 was closed.',\n    -- Proper patch should be written in 'stdin'\n    'Stream in for process 4 wrote: diff --git a/file-in-git b/file-in-git',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: index 000000..000000 100644',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: --- a/file-in-git',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +++ b/file-in-git',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: @@ -1,2 +1,0 @@',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: -Line -1',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: -Line 0',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: @@ -4,2 +2,2 @@',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: -Line 22',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: -Line 33',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +Line 2',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +Line 3',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: @@ -7,0 +5,1 @@',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +world',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 was shut down.', 'Process 4 was closed.',\n  }\n  eq(get_process_log(), ref_process_log)\nend\n\nT['gen_source']['git()']['handles \"crlf\" line endings in index'] = function()\n  -- Computing reference text\n  child.lua([[\n    _G.stdio_queue = {\n      { { 'out', _G.git_dir } },                   -- Get path to repo's Git dir\n      { { 'out', 'Line 1\\r\\nLINE 2\\r\\nLine 3' } }, -- Get reference text\n      { { 'out', '100644 crlf file-in-git' } },    -- Get path data for the patch\n      { { 'in' } },                                -- Apply patch\n    }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), true)\n\n  -- - Should set reference text with only '\\n' representing end of line\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLINE 2\\nLine 3\\n')\n\n  -- Applying hunks\n  child.lua([[MiniDiff.do_hunks(0, 'apply')]])\n  --stylua: ignore\n  local ref_process_log = {\n    'Stream out for process 1 was closed.', 'Process 1 was closed.',\n    'Stream out for process 2 was closed.', 'Process 2 was closed.',\n    'Stream out for process 3 was closed.', 'Process 3 was closed.',\n    'Stream in for process 4 wrote: diff --git a/file-in-git b/file-in-git',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: index 000000..000000 100644',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: --- a/file-in-git',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +++ b/file-in-git',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: @@ -2,1 +2,1 @@',\n    'Stream in for process 4 wrote: \\n',\n    -- Should append \"\\r\" at end of line if CRLF is used in index\n    'Stream in for process 4 wrote: -LINE 2\\r',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +Line 2\\r',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: @@ -4,0 +4,2 @@',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +Line 4\\r',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 wrote: +Line 5\\r',\n    'Stream in for process 4 wrote: \\n',\n    'Stream in for process 4 was shut down.', 'Process 4 was closed.',\n  }\n  eq(get_process_log(), ref_process_log)\nend\n\nT['gen_source']['git()']['returns correct structure'] = function()\n  eq(\n    child.lua_get('vim.tbl_map(type, MiniDiff.gen_source.git())'),\n    { apply_hunks = 'function', attach = 'function', detach = 'function', name = 'string' }\n  )\n  eq(child.lua_get('MiniDiff.gen_source.git().name'), 'git')\nend\n\nT['gen_source']['git()'][\"reacts to change in 'index' Git file\"] = function()\n  helpers.skip_if_slow()\n\n  child.lua([[\n    _G.stdio_queue = {\n      { { 'out', _G.git_dir } },          -- Get path to repo's Git dir\n      { { 'out', 'Line 1\\nLine 2\\n' } },  -- Get reference text\n      { { 'out', 'Line 1\\nLine 22\\n' } }, -- Get reference text after 'index' update\n    }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLine 2\\n')\n\n  -- Emulate change in 'index' as it is done by Git\n  mock_count_set_ref_text()\n\n  -- Use slightly bigger yet constrained delay for more robust tests\n  local small_time_bigger = math.min(2 * small_time, 0.9 * default_watch_debounce_delay)\n\n  -- Should react to change in 'index' file by reasking reference text\n  -- These reactions should be debounced\n  mock_change_git_index()\n  sleep(default_watch_debounce_delay - small_time_bigger)\n  -- - No changes as less than 50 ms has passed\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLine 2\\n')\n  eq(child.lua_get('_G.n_set_ref_text_calls'), 0)\n\n  mock_change_git_index()\n  sleep(default_watch_debounce_delay - small_time_bigger)\n  eq(child.lua_get('_G.n_set_ref_text_calls'), 0)\n  sleep(small_time_bigger + small_time)\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLine 22\\n')\n  eq(child.lua_get('_G.n_set_ref_text_calls'), 1)\n\n  -- Should react __only__ to changes in 'index' file\n  child.fn.writefile({}, git_git_dir .. '/index.lock')\n  sleep(default_watch_debounce_delay + small_time)\n  eq(child.lua_get('_G.n_set_ref_text_calls'), 1)\n\n  -- Should stop reacting after detaching\n  disable()\n  mock_change_git_index()\n  sleep(2 * small_time)\n  eq(child.lua_get('_G.n_set_ref_text_calls'), 1)\n\n  -- Should make proper process spawns\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = git_dir_path },\n    { args = { 'show', ':0:./' .. git_file_basename }, cwd = git_dir_path },\n    { args = { 'show', ':0:./' .. git_file_basename }, cwd = git_dir_path },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['gen_source']['git()']['attaches only in readable file buffers'] = function()\n  edit('not-real-file')\n  eq(is_buf_enabled(0), false)\n\n  set_buf(new_scratch_buf())\n  eq(is_buf_enabled(0), false)\n\n  child.lua('vim.loop.fs_realpath = function() return nil end')\n  edit(test_file_path)\n  eq(is_buf_enabled(0), false)\n\n  -- No spawns should be needed for these early checks\n  validate_git_spawn_log({})\nend\n\nT['gen_source']['git()']['works with errors during attach'] = function()\n  -- Like if file is not in Git repo or there is no `git` executable\n  child.lua([[\n    _G.stdio_queue = {\n      { {} }, -- Get path to repo's Git dir\n    }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), false)\nend\n\nT['gen_source']['git()']['works with wiped out target buffer'] = function()\n  child.lua([[_G.stdio_queue = { { { 'out', _G.git_dir } } }]])\n\n  child.lua('_G.path = ' .. vim.inspect(git_file_path))\n  local buf_id = child.lua([[\n    vim.cmd('edit ' .. vim.fn.fnameescape(_G.path))\n    local buf_id = vim.api.nvim_get_current_buf()\n    -- Should not result in an error\n    vim.schedule(function() vim.api.nvim_buf_delete(buf_id, { force = true }) end)\n    return buf_id\n  ]])\n\n  eq(is_buf_enabled(0), false)\n  eq(child.api.nvim_buf_is_valid(buf_id), false)\n  eq(child.cmd_capture('messages'), '')\n\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = git_dir_path },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['gen_source']['git()']['works with errors during getting reference text'] = function()\n  -- Should attach but reset ref text (to react if it *gets* in index)\n  child.lua([[\n    _G.stdio_queue = {\n      { { 'out', _G.git_dir } }, -- Get path to repo's Git dir\n      { {} },                    -- Get reference text\n    }\n    _G.process_mock_data = { [2] = { exit_code = 1 } }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_data(0).ref_text, nil)\n\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = git_dir_path },\n    { args = { 'show', ':0:./' .. git_file_basename }, cwd = git_dir_path },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['gen_source']['git()']['reacts to file rename'] = function()\n  -- Should disable/enable file because it might have changed Git repo\n  child.lua([[\n    _G.stdio_queue = {\n      { { 'out', _G.git_dir } },         -- Get path to repo's Git dir\n      { { 'out', 'Line 1\\nLine 2\\n' } }, -- Get reference text\n      { { 'out', vim.fn.getcwd() } },    -- Get path to repo's Git dir after rename\n      { { 'out', 'Hello\\nWorld\\n' } },   -- Get reference text after rename\n    }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_data(0).ref_text, 'Line 1\\nLine 2\\n')\n\n  child.api.nvim_buf_set_name(0, test_file_path)\n\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = git_dir_path },\n    { args = { 'show', ':0:./' .. 'file-in-git' }, cwd = git_dir_path },\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = test_dir_absolute },\n    { args = { 'show', ':0:./' .. 'file' }, cwd = test_dir_absolute },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_data(0).ref_text, 'Hello\\nWorld\\n')\nend\n\nT['gen_source']['git()']['should try attaching same buffer exactly once'] = function()\n  -- If buffer was not attached on `BufEnter` after it tried, then it should\n  -- stop trying. This is an example of when buffer's file is not in Git repo.\n  -- Should disable/enable file because it might have changed Git repo\n  child.lua([[\n    _G.stdio_queue = {\n      { {} }, -- Get path to repo's Git dir\n    }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n\n  edit(test_file_path)\n  local init_buf = get_buf()\n  eq(is_buf_enabled(0), false)\n\n  -- Simulate `BufEnter`\n  set_buf(new_scratch_buf())\n  set_buf(init_buf)\n  eq(is_buf_enabled(0), false)\n\n  -- Spawn should be done only once (on the first try)\n  local ref_git_spawn_log = {\n    { args = { 'rev-parse', '--path-format=absolute', '--git-dir' }, cwd = test_dir_absolute },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['gen_source']['none()'] = new_set()\n\nT['gen_source']['none()']['works'] = function()\n  child.lua('MiniDiff.config.source = MiniDiff.gen_source.none()')\n\n  -- Should return proper structure\n  eq(child.lua_get('vim.tbl_map(type, MiniDiff.config.source)'), { attach = 'function', name = 'string' })\n  eq(child.lua_get('MiniDiff.config.source.name'), 'none')\n\n  -- Should allow enabling buffer but not set any reference text\n  local buf_id = new_buf()\n  enable(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n  eq(get_buf_data(buf_id).ref_text, nil)\n\n  -- Should allow setting reference text manually\n  set_ref_text(buf_id, { 'aaa' })\n  eq(get_buf_data(buf_id).ref_text, 'aaa\\n')\nend\n\nT['gen_source']['save()'] = new_set()\n\nT['gen_source']['save()']['works'] = function()\n  child.lua('MiniDiff.config.source = MiniDiff.gen_source.save()')\n  edit(test_file_path)\n  local init_lines = get_lines()\n  MiniTest.finally(function() child.fn.writefile(init_lines, test_file_path) end)\n\n  local validate_ref_text = function(ref) eq(get_buf_data(0).ref_text, ref) end\n\n  -- Should return proper structure\n  eq(\n    child.lua_get('vim.tbl_map(type, MiniDiff.config.source)'),\n    { attach = 'function', detach = 'function', name = 'string' }\n  )\n  eq(child.lua_get('MiniDiff.config.source.name'), 'save')\n\n  -- Should update reference text on save\n  validate_ref_text('aaa\\nuuu\\n')\n  type_keys('G', 'o', 'vvv', '<Esc>')\n  sleep(small_time + small_time)\n  validate_ref_text('aaa\\nuuu\\n')\n  child.cmd('write')\n  validate_ref_text('aaa\\nuuu\\nvvv\\n')\n\n  -- Should work with trailing empty/blank lines\n  type_keys('G', 'o', '<Esc>')\n  child.cmd('write')\n  validate_ref_text('aaa\\nuuu\\nvvv\\n\\n')\n\n  type_keys('G', 'o', ' ', '<Esc>')\n  child.cmd('write')\n  validate_ref_text('aaa\\nuuu\\nvvv\\n\\n \\n')\n\n  -- Should still work after `:edit`\n  child.cmd('edit')\n  validate_ref_text('aaa\\nuuu\\nvvv\\n\\n \\n')\n\n  -- Should update reference text when file change outside buffer\n  child.fn.writefile({ 'bbb', 'xxx' }, test_file_path)\n  local cur_changedtick = child.api.nvim_buf_get_changedtick(0)\n  child.cmd('silent! checktime')\n  -- - Wait for `:checktime` itself to process\n  for _ = 1, 100 do\n    if child.api.nvim_buf_get_changedtick(0) ~= cur_changedtick then break end\n    vim.loop.sleep(small_time)\n  end\n  if child.api.nvim_buf_get_changedtick(0) == cur_changedtick then\n    MiniTest.skip('Could not wait for `silent! checktime` to take effect')\n  end\n  validate_ref_text('bbb\\nxxx\\n')\n\n  -- Should clean up buffer autocommands on detach\n  local has_save_autocommands = function()\n    return #child.api.nvim_get_autocmds({ event = 'BufWritePost', buffer = get_buf() }) > 0\n  end\n  eq(has_save_autocommands(), true)\n  disable()\n  eq(has_save_autocommands(), false)\nend\n\nT['gen_source']['save()']['works with BOM bytes'] = function()\n  child.lua('MiniDiff.config.source = MiniDiff.gen_source.save()')\n  local path = test_dir_absolute .. '/file-bom'\n  edit(path)\n\n  local init_content = child.fn.readblob(path, 'b')\n  MiniTest.finally(function()\n    local file = io.open(path, 'w')\n    assert(file)\n    file:write(init_content)\n    file:close()\n  end)\n\n  local validate_ref_text = function(ref) eq(get_buf_data(0).ref_text, ref) end\n\n  eq(child.bo.fileencoding, 'utf-8')\n  local utf8_bom_bytes = string.char(0xef, 0xbb, 0xbf)\n  validate_ref_text(utf8_bom_bytes .. 'bbb\\nvvv\\n')\n\n  type_keys('G', 'o', 'hello', '<Esc>')\n  child.cmd('write')\n  validate_ref_text(utf8_bom_bytes .. 'bbb\\nvvv\\nhello\\n')\nend\n\nT['do_hunks()'] = new_set()\n\nlocal do_hunks = forward_lua('MiniDiff.do_hunks')\n\nT['do_hunks()']['works'] = function()\n  set_lines({ 'aaa', 'BBB' })\n  child.bo.modified = false\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  -- - By default should do action on all lines\n  local ref_hunks = {\n    { buf_start = 1, buf_count = 1, ref_start = 1, ref_count = 1, type = 'change' },\n    { buf_start = 2, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'AAA\\nCCC\\n')\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC' })\n  eq(child.bo.modified, true)\nend\n\nT['do_hunks()']['works with no hunks'] = function()\n  set_lines({ 'aaa' })\n  set_ref_text(0, { 'aaa' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  validate_dummy_log({})\n  validate_notifications({ { '(mini.diff) No hunks to apply', 'INFO' } })\n  clear_notify_log()\n\n  -- Yank\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), '')\n  validate_notifications({ { '(mini.diff) No hunks to yank', 'INFO' } })\n  clear_notify_log()\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'aaa' })\n  validate_notifications({ { '(mini.diff) No hunks to reset', 'INFO' } })\n  clear_notify_log()\nend\n\nT['do_hunks()']['works with \"add\" hunks'] = function()\n  local ref_hunks\n\n  set_lines({ 'uuu', 'aaa', 'vvv', 'ccc', 'www', 'xxx' })\n  set_ref_text(0, { 'aaa', 'ccc' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  ref_hunks = {\n    { buf_start = 1, buf_count = 1, ref_start = 0, ref_count = 0, type = 'add' },\n    { buf_start = 3, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' },\n    { buf_start = 5, buf_count = 2, ref_start = 2, ref_count = 0, type = 'add' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank')\n  -- - No reference lines to yank\n  eq(child.fn.getreg('\"'), '')\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'aaa', 'ccc' })\nend\n\nT['do_hunks()']['works with \"change\" hunks'] = function()\n  set_lines({ 'aaa', 'BBB', 'ccc', 'DDD', 'eee', 'fff' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  local ref_hunks = {\n    { buf_start = 1, buf_count = 1, ref_start = 1, ref_count = 1, type = 'change' },\n    { buf_start = 3, buf_count = 1, ref_start = 3, ref_count = 1, type = 'change' },\n    { buf_start = 5, buf_count = 2, ref_start = 5, ref_count = 2, type = 'change' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'AAA\\nCCC\\nEEE\\nFFF\\n')\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\nend\n\nT['do_hunks()']['works with \"delete\" hunks'] = function()\n  set_lines({ 'bbb', 'ddd' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  local ref_hunks = {\n    { buf_start = 0, buf_count = 0, ref_start = 1, ref_count = 1, type = 'delete' },\n    { buf_start = 1, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' },\n    { buf_start = 2, buf_count = 0, ref_start = 5, ref_count = 2, type = 'delete' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'aaa\\nccc\\neee\\nfff\\n')\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' })\nend\n\nT['do_hunks()']['works with \"delete\" hunks on edges as target'] = function()\n  local ref_hunks\n\n  -- First line\n  set_lines({ 'bbb' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n\n  do_hunks(0, 'apply', { line_start = 1, line_end = 1 })\n  ref_hunks = { { buf_start = 0, buf_count = 0, ref_start = 1, ref_count = 1, type = 'delete' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  clean_dummy_log()\n\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'aaa\\n')\n\n  do_hunks(0, 'reset', { line_start = 1, line_end = 1 })\n  eq(get_lines(), { 'aaa', 'bbb' })\n\n  -- Last line\n  set_lines({ 'aaa' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n\n  do_hunks(0, 'apply', { line_start = 2, line_end = 2 })\n  ref_hunks = { { buf_start = 1, buf_count = 0, ref_start = 2, ref_count = 1, type = 'delete' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  clean_dummy_log()\n\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'bbb\\n')\n\n  do_hunks(0, 'reset', { line_start = 2, line_end = 2 })\n  eq(get_lines(), { 'aaa', 'bbb' })\nend\n\nT['do_hunks()']['works when \"change\" and \"delete\" hunks overlap'] = function()\n  set_lines({ 'AAA', 'CcC', 'EeE', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  local ref_hunks = {\n    { buf_start = 1, buf_count = 0, ref_start = 2, ref_count = 1, type = 'delete' },\n    { buf_start = 2, buf_count = 1, ref_start = 3, ref_count = 1, type = 'change' },\n    { buf_start = 2, buf_count = 0, ref_start = 4, ref_count = 1, type = 'delete' },\n    { buf_start = 3, buf_count = 1, ref_start = 5, ref_count = 1, type = 'change' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  clean_dummy_log()\n\n  -- Yank\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'BBB\\nCCC\\nDDD\\nEEE\\n')\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\nend\n\nT['do_hunks()']['respects `opts.line_start`'] = function()\n  set_lines({ 'aaa', 'BBB' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  -- Apply\n  do_hunks(0, 'apply', { line_start = 2 })\n  local ref_hunks = { { buf_start = 2, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank', { line_start = 2 })\n  eq(child.fn.getreg('\"'), 'CCC\\n')\n\n  -- Reset\n  do_hunks(0, 'reset', { line_start = 2 })\n  eq(get_lines(), { 'aaa', 'BBB', 'CCC' })\nend\n\nT['do_hunks()']['respects `opts.line_end`'] = function()\n  set_lines({ 'aaa', 'BBB' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  -- Apply\n  do_hunks(0, 'apply', { line_end = 1 })\n  local ref_hunks = { { buf_start = 1, buf_count = 1, ref_start = 1, ref_count = 1, type = 'change' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank', { line_end = 1 })\n  eq(child.fn.getreg('\"'), 'AAA\\n')\n\n  -- Reset\n  do_hunks(0, 'reset', { line_end = 1 })\n  eq(get_lines(), { 'AAA', 'BBB' })\nend\n\nT['do_hunks()']['respects `opts.register`'] = function()\n  set_lines({ 'aaa', 'BBB' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n  do_hunks(0, 'yank', { register = 'a' })\n  eq(child.fn.getreg('a'), 'AAA\\nCCC\\n')\n  eq(child.fn.getreg('\"'), '')\nend\n\nT['do_hunks()']['allows negative target lines'] = function()\n  set_lines({ 'aaa', 'BBB' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  -- Apply\n  do_hunks(0, 'apply', { line_start = -2, line_end = -1 })\n  local ref_hunks = {\n    { buf_start = 1, buf_count = 1, ref_start = 1, ref_count = 1, type = 'change' },\n    { buf_start = 2, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank', { line_start = -2, line_end = -1 })\n  eq(child.fn.getreg('\"'), 'AAA\\nCCC\\n')\n\n  -- Reset\n  do_hunks(0, 'reset', { line_start = -2, line_end = -1 })\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC' })\nend\n\nT['do_hunks()']['allows target range to contain lines between hunks'] = function()\n  set_lines({ 'bbb', 'uuu', 'vvv', 'ccc', 'www', 'ddd' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee' })\n\n  -- Apply\n  do_hunks(0, 'apply')\n  -- - By default should do action on all lines\n  local ref_hunks = {\n    { buf_start = 0, buf_count = 0, ref_start = 1, ref_count = 1, type = 'delete' },\n    { buf_start = 2, buf_count = 2, ref_start = 2, ref_count = 0, type = 'add' },\n    { buf_start = 5, buf_count = 1, ref_start = 3, ref_count = 0, type = 'add' },\n    { buf_start = 6, buf_count = 0, ref_start = 5, ref_count = 1, type = 'delete' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank')\n  eq(child.fn.getreg('\"'), 'aaa\\neee\\n')\n\n  -- Reset\n  do_hunks(0, 'reset')\n  eq(get_lines(), { 'aaa', 'bbb', 'ccc', 'ddd', 'eee' })\nend\n\nT['do_hunks()']['can act on hunk part'] = function()\n  set_lines({ 'uuu', 'vvv', 'aaa', 'bbb', 'ccc' })\n  set_ref_text(0, { 'aaa', 'BBB', 'CCC' })\n\n  -- Apply\n  do_hunks(0, 'apply', { line_start = 2, line_end = 4 })\n  local ref_hunks = {\n    { buf_start = 2, buf_count = 1, ref_start = 0, ref_count = 0, type = 'add' },\n    -- If hunk intersects target range, its reference part is used in full\n    { buf_start = 4, buf_count = 1, ref_start = 2, ref_count = 2, type = 'change' },\n  }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n\n  -- Yank\n  do_hunks(0, 'yank', { line_start = 2, line_end = 4 })\n  eq(child.fn.getreg('\"'), 'BBB\\nCCC\\n')\n\n  -- Reset\n  do_hunks(0, 'reset', { line_start = 2, line_end = 4 })\n  eq(get_lines(), { 'uuu', 'aaa', 'BBB', 'CCC', 'ccc' })\nend\n\nT['do_hunks()']['validates arguments'] = function()\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n\n  expect.error(function() do_hunks(-1) end, 'valid buffer')\n\n  expect.error(function() do_hunks(0, 'aaa') end, '`action`.*one of')\n\n  expect.error(function() do_hunks(0, 'apply', { line_start = 'a' }) end, '`line_start`.*number')\n  expect.error(function() do_hunks(0, 'apply', { line_end = 'a' }) end, '`line_end`.*number')\n  expect.error(function() do_hunks(0, 'apply', { line_start = 2, line_end = 1 }) end, '`line_start`.*less.*`line_end`')\n\n  disable()\n  expect.error(function() do_hunks(0) end, 'Buffer.*not enabled')\nend\n\nT['goto_hunk()'] = new_set()\n\nlocal goto_hunk = forward_lua('MiniDiff.goto_hunk')\n\nT['goto_hunk()']['works'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, ref_cursor)\n    set_cursor(4, 0)\n    goto_hunk(direction)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('first', { 1, 0 })\n  validate('prev', { 3, 0 })\n  validate('next', { 5, 0 })\n  validate('last', { 7, 0 })\nend\n\nT['goto_hunk()']['works when inside hunk range'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'www', 'xxx', 'ccc', 'yyy' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, ref_cursor)\n    set_cursor(4, 0)\n    goto_hunk(direction)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  -- Should not count current hunk when computing target\n  validate('first', { 1, 0 })\n  validate('prev', { 1, 0 })\n  validate('next', { 7, 0 })\n  validate('last', { 7, 0 })\nend\n\nT['goto_hunk()']['respects `opts.n_times`'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, ref_cursor)\n    set_cursor(4, 0)\n    goto_hunk(direction, { n_times = 2 })\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('first', { 3, 0 })\n  validate('prev', { 1, 0 })\n  validate('next', { 7, 0 })\n  validate('last', { 5, 0 })\nend\n\nT['goto_hunk()']['allows too big `opts.n_times`'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, ref_cursor)\n    set_cursor(4, 0)\n    goto_hunk(direction, { n_times = 1000 })\n    eq(get_cursor(), ref_cursor)\n    validate_notifications({})\n  end\n\n  -- Should partially go until reaches the end\n  validate('first', { 7, 0 })\n  validate('prev', { 1, 0 })\n  validate('next', { 7, 0 })\n  validate('last', { 1, 0 })\nend\n\nT['goto_hunk()']['respects `opts.line_start`'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, ref_cursor)\n    set_cursor(1, 0)\n    goto_hunk(direction, { line_start = 4 })\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('first', { 1, 0 })\n  validate('prev', { 3, 0 })\n  validate('next', { 5, 0 })\n  validate('last', { 7, 0 })\nend\n\nT['goto_hunk()']['respects `opts.wrap`'] = function()\n  -- Should use `config.options.wrap_goto` as default value\n  child.lua('MiniDiff.config.options.wrap_goto = true')\n\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, init_cursor, ref_cursor, n_times)\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction, { n_times = n_times })\n    eq(get_cursor(), ref_cursor)\n    validate_notifications({ { '(mini.diff) Wrapped around edge in direction \"' .. direction .. '\"', 'INFO' } })\n    clear_notify_log()\n  end\n\n  validate('prev', { 1, 0 }, { 7, 0 })\n  validate('next', { 7, 0 }, { 1, 0 })\n\n  validate('prev', { 2, 0 }, { 7, 0 }, 2)\n  validate('next', { 6, 0 }, { 1, 0 }, 2)\n\n  validate('prev', { 2, 0 }, { 7, 0 }, 6)\n  validate('next', { 6, 0 }, { 1, 0 }, 6)\n\n  validate('first', { 4, 0 }, { 1, 0 }, 5)\n  validate('last', { 4, 0 }, { 7, 0 }, 5)\n\n  validate('first', { 4, 0 }, { 3, 0 }, 10)\n  validate('last', { 4, 0 }, { 5, 0 }, 10)\n\n  -- Explicit `opts` should take preference\n  set_cursor(1, 1)\n  goto_hunk('prev', { wrap = false })\n  eq(get_cursor(), { 1, 1 })\nend\n\nT['goto_hunk()']['does not wrap around edges by default'] = function()\n  set_lines({ 'aaa', 'vvv', 'bbb', 'www', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(direction, init_cursor)\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction)\n    eq(get_cursor(), init_cursor)\n    validate_notifications({ { '(mini.diff) No hunk ranges in direction \"' .. direction .. '\"', 'INFO' } })\n    clear_notify_log()\n  end\n\n  validate('prev', { 2, 1 })\n  validate('next', { 4, 1 })\nend\n\nT['goto_hunk()']['works with no hunks'] = function()\n  set_lines({ 'aaa' })\n  set_ref_text(0, { 'aaa' })\n\n  local cursor = get_cursor()\n  goto_hunk('next')\n  eq(get_cursor(), cursor)\n  validate_notifications({ { '(mini.diff) No hunks to go to', 'INFO' } })\nend\n\nT['goto_hunk()']['correctly computes contiguous ranges'] = function()\n  local validate = function(init_cursor, direction, opts, ref_cursor)\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction, opts)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  -- \"Change\" hunk adjacent to \"add\" and \"delete\" hunks\n  set_lines({ 'AAA', 'uuu', 'BbB', 'DDD', 'www', 'EEE' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE' })\n  eq(get_buf_hunks(), {\n    { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' },\n    { buf_start = 3, buf_count = 1, ref_start = 2, ref_count = 1, type = 'change' },\n    { buf_start = 3, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' },\n    { buf_start = 5, buf_count = 1, ref_start = 4, ref_count = 0, type = 'add' },\n  })\n\n  validate({ 1, 0 }, 'first', {}, { 2, 0 })\n  validate({ 1, 0 }, 'first', { n_times = 2 }, { 5, 0 })\n\n  validate({ 6, 0 }, 'prev', {}, { 5, 0 })\n  validate({ 5, 0 }, 'prev', {}, { 2, 0 })\n\n  validate({ 1, 0 }, 'next', {}, { 2, 0 })\n  validate({ 2, 0 }, 'next', {}, { 5, 0 })\n\n  validate({ 6, 0 }, 'last', {}, { 5, 0 })\n  validate({ 6, 0 }, 'last', { n_times = 2 }, { 2, 0 })\nend\n\nT['goto_hunk()']['adds current position to jump list'] = function()\n  set_lines({ 'aaa', 'uuu', 'bbb', 'vvv', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(init_cursor, direction, ref_cursor)\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction)\n    eq(get_cursor(), ref_cursor)\n    type_keys('<C-o>')\n    eq(get_cursor(), init_cursor)\n  end\n\n  validate({ 3, 1 }, 'first', { 2, 0 })\n  validate({ 3, 1 }, 'prev', { 2, 0 })\n  validate({ 3, 1 }, 'next', { 4, 0 })\n  validate({ 3, 1 }, 'last', { 4, 0 })\nend\n\nT['goto_hunk()']['puts cursor on first line of range'] = function()\n  set_lines({ 'aaa', 'uuu', 'vvv', 'bbb', 'www', 'xxx', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(init_cursor, direction, ref_cursor)\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate({ 1, 0 }, 'first', { 2, 0 })\n  validate({ 7, 0 }, 'first', { 2, 0 })\n\n  validate({ 6, 0 }, 'prev', { 2, 0 })\n  validate({ 4, 0 }, 'prev', { 2, 0 })\n\n  validate({ 1, 0 }, 'next', { 2, 0 })\n  validate({ 4, 0 }, 'next', { 5, 0 })\n\n  validate({ 7, 0 }, 'last', { 5, 0 })\n  validate({ 4, 0 }, 'last', { 5, 0 })\nend\n\nT['goto_hunk()']['puts cursor on first non-blank column'] = function()\n  set_lines({ 'AAA', '  uuu', 'BBB', '\\tvvv', 'CCC', '\\t www', 'DDD' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD' })\n\n  local validate = function(init_cursor, direction, opts, ref_cursor)\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction, opts)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate({ 1, 0 }, 'first', {}, { 2, 2 })\n  validate({ 1, 0 }, 'first', { n_times = 2 }, { 4, 1 })\n  validate({ 1, 0 }, 'first', { n_times = 3 }, { 6, 2 })\n\n  validate({ 7, 0 }, 'prev', {}, { 6, 2 })\n  validate({ 5, 0 }, 'prev', {}, { 4, 1 })\n  validate({ 3, 0 }, 'prev', {}, { 2, 2 })\n\n  validate({ 1, 0 }, 'next', {}, { 2, 2 })\n  validate({ 3, 0 }, 'next', {}, { 4, 1 })\n  validate({ 5, 0 }, 'next', {}, { 6, 2 })\n\n  validate({ 7, 0 }, 'last', {}, { 6, 2 })\n  validate({ 7, 0 }, 'last', { n_times = 2 }, { 4, 1 })\n  validate({ 7, 0 }, 'last', { n_times = 3 }, { 2, 2 })\nend\n\nT['goto_hunk()']['opens just enough folds'] = function()\n  set_lines({ 'aaa', 'uuu', 'bbb', 'ccc', 'ddd', 'eee' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee' })\n\n  local validate = function(init_cursor, direction)\n    child.cmd('2,3fold')\n    child.cmd('5,6fold')\n    for i, s in ipairs({ -1, 2, 2, -1, 5, 5 }) do\n      eq(child.fn.foldclosed(i), s)\n    end\n\n    set_cursor(unpack(init_cursor))\n    goto_hunk(direction)\n    eq(get_cursor(), { 2, 0 })\n    for i, s in ipairs({ -1, -1, -1, -1, 5, 5 }) do\n      eq(child.fn.foldclosed(i), s)\n    end\n  end\n\n  validate({ 1, 0 }, 'first')\n  validate({ 3, 0 }, 'prev')\n  validate({ 1, 0 }, 'next')\n  validate({ 6, 0 }, 'last')\nend\n\nT['goto_hunk()']['validates arguments'] = function()\n  expect.error(function() goto_hunk('aaa') end, '`direction`.*one of')\n  expect.error(function() goto_hunk('next', { n_times = 'a' }) end, '`opts.n_times`.*number')\n  expect.error(function() goto_hunk('next', { n_times = 0 }) end, '`opts.n_times`.*positive')\n  expect.error(function() goto_hunk('next', { line_start = 'a' }) end, '`opts.line_start`.*number')\n\n  disable()\n  expect.error(function() goto_hunk() end, 'Buffer.*not enabled')\nend\n\n-- More thorough tests are done in \"Integration tests\"\nT['operator()'] = new_set()\n\nT['operator()']['is present'] = function() eq(child.lua_get('type(MiniDiff.operator)'), 'function') end\n\nT['operator()']['can be used in a mapping'] = function()\n  child.lua([[\n    local rhs = function() return MiniDiff.operator('yank') .. 'gh' end\n    vim.keymap.set('n', 'ghy', rhs, { expr = true, remap = true })\n  ]])\n\n  set_lines({ 'ccc', 'DDD', 'EEE', 'fff' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' })\n  type_keys('ghy')\n  eq(child.fn.getreg('\"'), 'aaa\\nbbb\\nddd\\neee\\n')\n\n  -- Can be used with register\n  set_lines({ 'aaa' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n  type_keys('\"aghy')\n  eq(child.fn.getreg('a'), 'bbb\\n')\n  eq(child.fn.getreg('\"'), 'aaa\\nbbb\\nddd\\neee\\n')\nend\n\n-- More thorough tests are done in \"Integration tests\"\nT['textobject()'] = new_set()\n\nT['textobject()']['is present'] = function() eq(child.lua_get('type(MiniDiff.textobject)'), 'function') end\n\n-- More thorough tests are done in \"Multiple source\" set of \"Integration tests\"\nT['fail_attach()'] = new_set()\n\nT['fail_attach()']['validates arguments'] = function()\n  expect.error(function() child.lua('MiniDiff.fail_attach(\"a\")') end, '`buf_id`.*valid buffer id')\nend\n\n-- Integration tests ==========================================================\nT['Auto enable'] = new_set()\n\nT['Auto enable']['works'] = function()\n  local buf_id = new_buf()\n  set_buf(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n\n  -- Should auto enable only in listed buffers\n  local buf_id_unlisted = child.api.nvim_create_buf(false, false)\n  set_buf(buf_id_unlisted)\n  eq(is_buf_enabled(buf_id_unlisted), false)\n\n  -- Should try auto enable in `BufEnter`\n  disable(buf_id)\n  eq(is_buf_enabled(buf_id), false)\n  set_buf(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n\n  -- Should not error if buffer is not valid\n  expect.no_error(function()\n    child.lua([[\n      local buf_id = vim.api.nvim_create_buf(true, false)\n      vim.api.nvim_set_current_buf(buf_id)\n      vim.api.nvim_buf_delete(buf_id, { force = true })\n    ]])\n    eq(child.cmd_capture('1messages'), '')\n  end)\nend\n\nT['Auto enable']['does not enable in not proper buffers'] = function()\n  -- Has set `vim.b.minidiff_disable`\n  local buf_id_disabled = new_buf()\n  child.api.nvim_buf_set_var(buf_id_disabled, 'minidiff_disable', true)\n  set_buf(buf_id_disabled)\n  eq(is_buf_enabled(buf_id_disabled), false)\n\n  -- Is not normal\n  set_buf(new_scratch_buf())\n  eq(is_buf_enabled(0), false)\n\n  -- Is not text buffer\n  local buf_id_not_text = new_buf()\n  child.api.nvim_buf_set_lines(buf_id_not_text, 0, -1, false, { 'aa', '\\0', 'bb' })\n  set_buf(buf_id_not_text)\n  eq(is_buf_enabled(buf_id_not_text), false)\nend\n\nT['Auto enable']['works after `:edit`'] = function()\n  child.lua([[\n    MiniDiff.config.source = { attach = function(buf_id) MiniDiff.set_ref_text(buf_id, { 'aaa' }) end }\n  ]])\n\n  edit(test_file_path)\n  eq(is_buf_enabled(0), true)\n  local ref_hunks = { { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' } }\n  eq(get_buf_hunks(0), ref_hunks)\n\n  -- - It should be able to use `:edit` to update buffer config\n  child.b.minidiff_config = { options = { algorithm = 'minimal' } }\n  eq(get_buf_data(0).config.options.algorithm, 'histogram')\n\n  child.cmd('edit')\n  eq(get_lines(), { 'aaa', 'uuu' })\n\n  eq(is_buf_enabled(0), true)\n  eq(get_buf_hunks(0), ref_hunks)\n  eq(get_buf_data(0).config.options.algorithm, 'minimal')\n  validate_viz_extmarks(0, { { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' } })\nend\n\nT['Visualization'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nT['Visualization']['works'] = function()\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  local init_viz_extmarks = {\n    { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 4, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n    { line = 5, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n  }\n  validate_viz_extmarks(0, init_viz_extmarks)\n  child.expect_screenshot()\n\n  -- Should update in debounce fashion\n  set_cursor(6, 0)\n  type_keys('o', 'hello')\n  validate_viz_extmarks(0, init_viz_extmarks)\n\n  sleep(dummy_text_change_delay - 2 * small_time)\n  validate_viz_extmarks(0, init_viz_extmarks)\n\n  type_keys('<CR>', 'world')\n  sleep(dummy_text_change_delay - 2 * small_time)\n  validate_viz_extmarks(0, init_viz_extmarks)\n\n  sleep(2 * small_time + small_time)\n  validate_viz_extmarks(0, {\n    { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 4, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n    { line = 5, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n    { line = 7, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 8, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n  })\nend\n\nT['Visualization']['does not appear if there is no gutter'] = function()\n  child.o.signcolumn, child.o.number = 'no', false\n  disable()\n  enable()\n\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n  -- Shouldn't force neither sign nor number column\n  child.expect_screenshot()\nend\n\nT['Visualization']['can be visually disabled'] = function()\n  child.lua('MiniDiff.config.view.style = \"sign\"')\n  child.lua('MiniDiff.config.view.signs = { add = \"\", change = \"\", delete = \"\" }')\n  disable()\n  enable()\n\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n  -- Shouldn't show sign column, although extmarks are still placed\n  child.expect_screenshot()\n  eq(#get_viz_extmarks(0) > 0, true)\nend\n\nT['Visualization']['works with \"add\" hunks'] = function()\n  -- Every added line should be visualized as part of hunk\n  set_lines({ 'aaa', 'uuu', 'vvv', 'bbb', 'www', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n  validate_viz_extmarks(0, {\n    { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 3, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 5, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\n\n  -- Should work if added is on edge\n  set_lines({ 'uuu', 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n  validate_viz_extmarks(0, {\n    { line = 1, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 3, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\nend\n\nT['Visualization']['works with \"change\" hunks'] = function()\n  -- Every changed line should be visualized as part of hunk\n  set_lines({ 'AAA', 'BbB', '', 'DDD', 'EeE', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n  validate_viz_extmarks(0, {\n    { line = 2, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n    { line = 3, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n    { line = 5, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\n\n  -- Should work if added is on edge\n  set_lines({ 'AaA', 'BBB', 'CcC' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n  validate_viz_extmarks(0, {\n    { line = 1, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n    { line = 3, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\nend\n\nT['Visualization']['works with \"delete\" hunks'] = function()\n  -- Whole deleted hunk should be visualized at single line nearby\n  set_lines({ 'aaa', 'ddd', 'eee', 'ggg' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg' })\n  validate_viz_extmarks(0, {\n    { line = 1, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n    { line = 3, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\n\n  -- Should work if hunk is on edge\n  set_lines({ 'bbb', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd' })\n  validate_viz_extmarks(0, {\n    { line = 1, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n    { line = 2, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\n\n  -- Should work if overlap\n  set_lines({ 'bbb' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n  validate_viz_extmarks(0, {\n    { line = 1, sign_hl_group = 'MiniDiffSignDelete', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\nend\n\nT['Visualization']['works when \"change\" overlaps with \"delete\"'] = function()\n  -- Should prefer \"change\"\n  set_lines({ 'AAA', 'BbB', 'DDD' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD' })\n  validate_viz_extmarks(0, { { line = 2, sign_hl_group = 'MiniDiffSignChange', sign_text = '▒ ' } })\nend\n\nT['Visualization']['reacts to hunk lines delete/move'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Reaction to line delete/move is available on Neovim>=0.10.') end\n  child.o.signcolumn = 'yes'\n\n  set_lines({ 'aaa', 'bbb', 'uuu', 'vvv', 'ccc', 'ddd' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd' })\n\n  validate_viz_extmarks(0, {\n    { line = 3, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 4, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n  })\n\n  set_cursor(3, 0)\n  type_keys('dj', 'k', 'P')\n  -- Should be immediately not drawn (invalidated)\n  child.expect_screenshot()\n\n  sleep(dummy_text_change_delay + small_time)\n  validate_viz_extmarks(0, {\n    { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n    { line = 3, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' },\n  })\n  child.expect_screenshot()\nend\n\nT['Visualization']['forces redraw when it is needed'] = function()\n  child.set_size(10, 15)\n\n  child.api.nvim_set_keymap('n', '<C-y>', '<Cmd>normal! yyp<CR>', {})\n  local ctrls_rhs = '<Cmd>lua MiniDiff.set_ref_text(0, vim.api.nvim_buf_get_lines(0, 0, -1, false))<CR>'\n  child.api.nvim_set_keymap('n', '<C-s>', ctrls_rhs, {})\n\n  set_lines({ 'aaa' })\n  set_ref_text(0, { 'aaa' })\n\n  type_keys('gg', '<C-y>')\n  sleep(dummy_text_change_delay + small_time)\n  validate_viz_extmarks(0, { { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '▒ ' } })\n  child.expect_screenshot()\n\n  type_keys('<C-s>')\n  child.expect_screenshot()\nend\n\nT['Visualization']['respects `view.style`'] = function()\n  child.lua([[MiniDiff.config.view.style = 'number']])\n  child.o.number = true\n  disable()\n  enable()\n\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  local viz_extmarks = {\n    { line = 2, number_hl_group = 'MiniDiffSignAdd' },\n    { line = 4, number_hl_group = 'MiniDiffSignChange' },\n    { line = 5, number_hl_group = 'MiniDiffSignDelete' },\n  }\n  validate_viz_extmarks(0, viz_extmarks)\n\n  child.expect_screenshot()\n\n  -- Should work even without 'number' set\n  child.o.number = false\n  disable()\n  enable()\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n  validate_viz_extmarks(0, viz_extmarks)\n  child.expect_screenshot()\nend\n\nT['Visualization']['shows signcolumn even if hunks are outside of view'] = function()\n  -- Make sure that extmark has no visible side effects\n  child.o.signcolumn = 'auto:2'\n  child.o.cursorline = true\n  child.cmd('hi CursrLineSign guibg=Red ctermbg=Red')\n  child.cmd('hi SignColumn guibg=Blue ctermbg=Blue')\n\n  child.lua('MiniDiff.config.delay.text_change = ' .. small_time)\n  disable()\n  enable()\n\n  local lines = { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF', 'GGG', 'HHH', 'III', 'JJJ' }\n  set_lines(lines)\n  table.insert(lines, 'uuu')\n  set_ref_text(0, lines)\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  -- Should be deleted when not needed, making sign column still only single\n  -- \"sign width\" wide (2 cells)\n  type_keys('gg', 'O', '<CR>', '<Esc>')\n  sleep(small_time + small_time)\n  local ns_id = child.api.nvim_get_namespaces().MiniDiffViz\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n  eq(#extmarks, 2)\n  -- Neovim>=0.11 has signs combine attributes, so check screenshot only there\n  if child.fn.has('nvim-0.11') == 1 then child.expect_screenshot() end\nend\n\nT['Visualization']['respects `view.signs`'] = function()\n  child.lua([[MiniDiff.config.view.signs = { add = '+', change = '~', delete = '-' }]])\n  disable()\n  enable()\n\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  local viz_extmarks = {\n    { line = 2, sign_hl_group = 'MiniDiffSignAdd', sign_text = '+ ' },\n    { line = 4, sign_hl_group = 'MiniDiffSignChange', sign_text = '~ ' },\n    { line = 5, sign_hl_group = 'MiniDiffSignDelete', sign_text = '- ' },\n  }\n  validate_viz_extmarks(0, viz_extmarks)\n  child.expect_screenshot()\nend\n\nT['Visualization']['respects `view.priority`'] = function()\n  child.lua('MiniDiff.config.view.priority = 100')\n  disable()\n  enable()\n\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  local ns_id = child.api.nvim_get_namespaces().MiniDiffViz\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n  eq(vim.tbl_map(function(e) return e[4].priority end, extmarks), { 100, 100, 100 })\nend\n\nT['Visualization']['respects `vim.b.minidiff_config`'] = function()\n  local buf_id = new_buf()\n  child.api.nvim_buf_set_var(buf_id, 'minidiff_config', { view = { style = 'number' } })\n  set_buf(buf_id)\n\n  set_lines({ 'AAA', 'uuu', 'BBB' })\n  set_ref_text(buf_id, { 'AAA', 'BBB' })\n\n  validate_viz_extmarks(0, { { line = 2, number_hl_group = 'MiniDiffSignAdd' } })\nend\n\nT['Overlay'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(15, 15)\n      setup_enabled_buffer()\n      toggle_overlay(0)\n    end,\n  },\n})\n\nT['Overlay']['works'] = function()\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  child.expect_screenshot()\n\n  -- Should be updated interactively when diff itself is updated\n  set_cursor(5, 0)\n  type_keys('A', '<CR>', 'EeE')\n\n  child.expect_screenshot()\n  sleep(dummy_text_change_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Overlay']['works with \"add\" hunks'] = function()\n  set_lines({ 'aaa', 'uuu', 'vvv', 'bbb', 'www', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n  child.expect_screenshot()\nend\n\nT['Overlay']['works with \"change\" hunks'] = function()\n  child.lua('MiniDiff.config.options.linematch = 0')\n\n  -- When number of added and deleted lines are the same, reference lines\n  -- should be shown next to the corresponding buffer lines\n  set_lines({ 'AAA', 'BbB', 'CcC', 'DdD', 'EEE' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE' })\n  child.expect_screenshot()\n\n  -- When number of added and deleted lines are not the same, all reference\n  -- lines should be shown together above hunk's first buffer line\n  set_lines({ 'AAA', 'uuu', 'BbB', 'CcC', 'DdD', 'EEE' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE' })\n  child.expect_screenshot()\nend\n\nT['Overlay']['works with \"delete\" hunks'] = function()\n  set_lines({ 'aaa', 'ddd', 'fff' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' })\n  child.expect_screenshot()\nend\n\nT['Overlay']['always highlights whole lines'] = function()\n  child.set_size(10, 15)\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  child.set_size(10, 25)\n  child.expect_screenshot()\nend\n\nT['Overlay']['scrolls along with buffer lines'] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip('Virtual line scroll is available only on Neovim>=0.11') end\n\n  child.set_size(10, 15)\n  child.o.wrap = false\n  local l = 'abcdefghijklmnopqrstuvwxyz'\n  local L = l:upper()\n  local ref_lines = { 1 .. l, 2 .. l, 3 .. l, 4 .. l, 5 .. l, 6 .. l }\n  set_lines({ 1 .. l, 3 .. l, 4 .. L, 6 .. l })\n  set_cursor(1, 0)\n  set_ref_text(0, ref_lines)\n\n  -- Should scroll virtual lines for deleted and changed with linematch hunks\n  type_keys('zL')\n  child.expect_screenshot()\n\n  -- Should also scroll virtual lines for change hunks without linematch\n  child.lua('MiniDiff.config.options.linematch = 0')\n  set_cursor(1, 0)\n  set_ref_text(0, ref_lines)\n  type_keys('zL')\n  child.expect_screenshot()\nend\n\nT['Overlay']['works at edge lines'] = function()\n  child.set_size(10, 15)\n  -- Virtual lines above first line need scroll to become visible\n  -- See https://github.com/neovim/neovim/issues/16166\n  -- Better with `<C-y>`. See https://github.com/neovim/neovim/issues/27967.\n\n  -- 'Add' hunks\n  set_lines({ 'uuu', 'aaa', 'vvv' })\n  set_ref_text(0, { 'aaa' })\n  child.expect_screenshot()\n\n  -- 'Change' hunks\n  set_lines({ 'AaA', 'BBB', 'CcC' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n  type_keys('<C-y>')\n  child.expect_screenshot()\n\n  -- 'Delete' hunks\n  set_lines({ 'BBB' })\n  set_ref_text(0, { 'AAA', 'BBB', 'DDD' })\n  type_keys('<C-y>')\n  child.expect_screenshot()\nend\n\nT['Overlay']['works when \"change\" overlaps with \"delete\"'] = function()\n  set_lines({ 'AAA', 'BbB', 'DDD' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD' })\n  child.expect_screenshot()\nend\n\nT['Overlay']['uses correct highlight groups'] = function()\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n\n  -- 'Add'\n  local add_extmarks = get_overlay_extmarks(0, 2, 2)\n  eq(#add_extmarks, 1)\n  eq(add_extmarks[1][4].hl_group, 'MiniDiffOverAdd')\n\n  -- 'Change'\n  local change_extmarks = get_overlay_extmarks(0, 4, 4)\n  eq(#change_extmarks, 3)\n\n  -- - Context of buffer changes as whole line highlighting\n  local change_details_1 = change_extmarks[1][4]\n  eq(change_extmarks[1][2], 3)\n  eq(change_extmarks[1][3], 0)\n  eq(change_details_1.end_row, 4)\n  eq(change_details_1.end_col, 0)\n  eq(change_details_1.hl_eol, true)\n  eq(change_details_1.hl_group, 'MiniDiffOverContextBuf')\n  eq(change_details_1.priority, 198)\n\n  -- - Context and change of reference text (as virtual line)\n  local change_virt_lines = change_extmarks[2][4].virt_lines\n  eq(#change_virt_lines, 1)\n  eq(change_virt_lines[1][1], { 'C', 'MiniDiffOverContext' })\n  eq(change_virt_lines[1][2], { 'C', 'MiniDiffOverChange' })\n  eq(change_virt_lines[1][3], { 'C', 'MiniDiffOverContext' })\n  eq(change_extmarks[2][4].virt_lines_above, true)\n\n  -- - Buffer changes as separate extmarks\n  eq(change_extmarks[3][4].hl_group, 'MiniDiffOverChangeBuf')\n\n  -- 'Delete'\n  local delete_extmarks = get_overlay_extmarks(0, 5, 5)\n  eq(#delete_extmarks, 1)\n\n  eq(delete_extmarks[1][4].virt_lines_above, false)\n  eq(delete_extmarks[1][4].virt_lines_above, false)\n  local delete_virt_lines = delete_extmarks[1][4].virt_lines\n  eq(#delete_virt_lines, 1)\n  eq(delete_virt_lines[1][1], { 'EEE', 'MiniDiffOverDelete' })\nend\n\nT['Overlay']['uses correct highlight groups in uneven change hunks'] = function()\n  child.lua('MiniDiff.config.options.linematch = 0')\n  set_lines({ 'aaa', 'eee', 'fff', 'ggg', 'ddd' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc', 'ddd' })\n  local extmarks = get_overlay_extmarks(0, 1, 5)\n\n  eq(#extmarks, 1)\n  -- Both changed reference lines should be shown as virtual lines\n  local virt_lines = extmarks[1][4].virt_lines\n  eq(virt_lines[1][1][2], 'MiniDiffOverChange')\n  eq(virt_lines[2][1][2], 'MiniDiffOverChange')\n\n  -- All three changed lines should be highlighted as whole lines\n  eq(extmarks[1][2], 1)\n  eq(extmarks[1][3], 0)\n  eq(extmarks[1][4].end_row, 4)\n  eq(extmarks[1][4].end_col, 0)\n  eq(extmarks[1][4].hl_eol, true)\n  eq(extmarks[1][4].hl_group, 'MiniDiffOverContextBuf')\nend\n\nT['Overlay']['respects `view.priority`'] = function()\n  child.lua('MiniDiff.config.view.priority = MiniDiff.config.view.priority - 10')\n  local ref_priority = child.lua_get('MiniDiff.config.view.priority')\n\n  set_lines({ 'AAA', 'uuu', 'BBB', 'CcC', 'DDD', 'FFF' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' })\n  local overlay_extmarks = get_overlay_extmarks(0, 1, 6)\n  local priorities = vim.tbl_map(function(t) return t[4].priority end, overlay_extmarks)\n  -- Some extmarks (for context of changed buffer text) have one less of\n  -- reference priority to be below highlighting for changed buffer text\n  local is_proper = vim.tbl_map(function(p) return p == ref_priority or p == (ref_priority - 1) end, priorities)\n  eq(is_proper, vim.tbl_map(function() return true end, priorities))\nend\n\nT['Overlay']['word diff'] = new_set()\n\nT['Overlay']['word diff']['works'] = function()\n  set_lines({ 'AAA', 'b_BBB_b', 'CCcccC', 'DDD', 'xxx' })\n  set_ref_text(0, { 'AAA', 'B_BBB_B', 'CCC', 'DDdddD', 'EEE' })\n  child.expect_screenshot()\nend\n\nT['Overlay']['word diff']['works with one of lines being empty'] = function()\n  child.set_size(7, 15)\n  set_lines({ 'uuu', '', 'vvv' })\n  set_ref_text(0, { 'uuu', 'AAA', 'vvv' })\n  child.expect_screenshot()\n  set_lines({ 'uuu', 'AAA', 'vvv' })\n  set_ref_text(0, { 'uuu', '', 'vvv' })\n  child.expect_screenshot()\nend\n\nT['Overlay']['word diff']['has non-zero interhunk context'] = function()\n  -- Changed characters which are near enough should be visualized as the whole\n  -- range between them is also changed. This reduces visual noise.\n  set_lines({ '__34567890', '_2_4567890', '_23_567890', '_234_67890', '_2345_7890', '_23456_890' })\n  set_ref_text(0, { '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890' })\n  type_keys('<C-y>')\n  child.expect_screenshot()\nend\n\nT['Overlay']['word diff']['works with multibyte characters'] = function()\n  child.set_size(10, 15)\n\n  local validate = function(buf_lines, ref_lines)\n    set_lines(buf_lines)\n    set_ref_text(0, ref_lines)\n    type_keys('<C-y>')\n    child.expect_screenshot()\n  end\n\n  -- Byte representation of characters (for reference):\n  -- - ы - { '<d1>', '<8b>' }\n  -- - ф - { '<d1>', '<84>' }\n  -- - ▒ - { '<e2>', '<96>', '<92>' }\n  -- - ┃ - { '<e2>', '<94>', '<83>' }\n  validate({ 'фыы', 'ыфы', 'ыыф' }, { 'ыыы', 'ыыы', 'ыыы' })\n  validate({ 'ыыы', 'ыыы', 'ыыы' }, { 'фыы', 'ыфы', 'ыыф' })\n  validate({ 'фыы', 'ыфы', 'ыыф' }, { 'ыы', 'ыы', 'ыы' })\n  validate({ 'ыы', 'ыы', 'ыы' }, { 'фыы', 'ыфы', 'ыыф' })\n\n  validate({ '┃▒▒', '▒┃▒', '▒▒┃' }, { '▒▒▒', '▒▒▒', '▒▒▒' })\n  validate({ '▒▒▒', '▒▒▒', '▒▒▒' }, { '┃▒▒', '▒┃▒', '▒▒┃' })\n  validate({ '┃▒▒', '▒┃▒', '▒▒┃' }, { '▒▒', '▒▒', '▒▒' })\n  validate({ '▒▒', '▒▒', '▒▒' }, { '┃▒▒', '▒┃▒', '▒▒┃' })\n\n  validate({ 'ыxx', 'xыx', 'xxы' }, { 'xxx', 'xxx', 'xxx' })\n  validate({ 'xxx', 'xxx', 'xxx' }, { 'ыxx', 'xыx', 'xxы' })\nend\n\nT['Overlay']['word diff']['works with BOM bytes'] = function()\n  local path = test_dir_absolute .. '/file-bom'\n  edit(path)\n  local content = child.fn.readblob(path, 'b'):gsub('\\r', '')\n\n  toggle_overlay(0)\n  set_lines({ 'bBb', 'vvv' })\n  set_ref_text(0, content)\n\n  type_keys('<C-y>')\n  child.expect_screenshot()\nend\n\nT['Diff'] = new_set({ hooks = { pre_case = setup_enabled_buffer } })\n\nT['Diff']['works'] = function()\n  set_lines({ 'aaa', 'uuu', 'bbb' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n  local other_buf_id = new_buf()\n  child.api.nvim_buf_set_lines(other_buf_id, 0, -1, false, { 'ccc', 'vvv', 'ddd' })\n  set_ref_text(other_buf_id, { 'ccc', 'ddd' })\n\n  local ref_hunks_before = { { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' } }\n  eq(get_buf_hunks(0), ref_hunks_before)\n  eq(get_buf_hunks(other_buf_id), ref_hunks_before)\n\n  -- Should be updated in debounce fashion across all buffers\n  set_cursor(2, 0)\n  type_keys('o', 'hello', '<Esc>')\n  eq(get_buf_hunks(0), ref_hunks_before)\n  eq(get_buf_hunks(other_buf_id), ref_hunks_before)\n\n  local small_time_bigger = 2 * small_time\n\n  sleep(dummy_text_change_delay - small_time_bigger)\n  eq(get_buf_hunks(0), ref_hunks_before)\n  eq(get_buf_hunks(other_buf_id), ref_hunks_before)\n\n  set_buf(other_buf_id)\n  set_cursor(2, 0)\n  type_keys('o', 'world', '<Esc>')\n\n  sleep(dummy_text_change_delay - small_time_bigger)\n  eq(get_buf_hunks(0), ref_hunks_before)\n  eq(get_buf_hunks(other_buf_id), ref_hunks_before)\n\n  sleep(small_time_bigger + small_time)\n\n  local ref_hunks_after = { { buf_start = 2, buf_count = 2, ref_start = 1, ref_count = 0, type = 'add' } }\n  eq(get_buf_hunks(0), ref_hunks_after)\n  eq(get_buf_hunks(other_buf_id), ref_hunks_after)\nend\n\nT['Diff']['sets proper summary buffer-local variables'] = function()\n  set_lines({ 'AAA', 'uuu', 'BBB', 'ccc', 'DDD', 'EEE', 'GGG' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF', 'GGG' })\n\n  eq(child.b.minidiff_summary, { source_name = 'dummy', add = 1, change = 1, delete = 1, n_ranges = 3 })\n  eq(child.b.minidiff_summary_string, '#3 +1 ~1 -1')\n\n  -- Summary string should maintain order of \"n-add-change-delete\"\n  local validate_summary_string = function(buf_lines, ref_lines, ref_summary_string)\n    set_lines(buf_lines)\n    set_ref_text(0, ref_lines)\n    eq(child.b.minidiff_summary_string, ref_summary_string)\n  end\n\n  validate_summary_string({ 'AAA', 'uuu' }, { 'AAA' }, '#1 +1')\n  validate_summary_string({ 'aaa' }, { 'AAA' }, '#1 ~1')\n  validate_summary_string({ 'AAA' }, { 'AAA', 'BBB' }, '#1 -1')\n\n  validate_summary_string({ 'AAA', 'CCC', 'ddd' }, { 'AAA', 'BBB', 'CCC', 'DDD' }, '#2 ~1 -1')\n  validate_summary_string({ 'AAA', 'CCC', 'uuu' }, { 'AAA', 'BBB', 'CCC' }, '#2 +1 -1')\n  validate_summary_string({ 'AAA', 'uuu', 'BBB', 'ccc', 'DDD' }, { 'AAA', 'BBB', 'CCC', 'DDD' }, '#2 +1 ~1')\n\n  -- Should still set if enabled but no ref text\n  validate_summary_string({ 'AAA', 'uuu' }, {}, '')\n  set_ref_text(0, {})\n  eq(child.b.minidiff_summary, { source_name = 'dummy' })\nend\n\nT['Diff']['respects `options.algorithm`'] = function()\n  child.lua('MiniDiff.config.options.linematch = 0')\n  local ref_lines = { '[', ']', 'AAA', 'CCC', 'BBB', '[', ']' }\n\n  set_lines({ '[', 'AAA', ']', 'CCC', '[', 'BBB', ']' })\n  set_ref_text(0, ref_lines)\n  local histogram_hunks = {\n    { buf_start = 1, buf_count = 0, ref_start = 2, ref_count = 1, type = 'delete' },\n    { buf_start = 3, buf_count = 4, ref_start = 4, ref_count = 3, type = 'change' },\n  }\n  eq(get_buf_hunks(0), histogram_hunks)\n\n  child.lua([[MiniDiff.config.options.algorithm = 'myers']])\n  set_ref_text(0, ref_lines)\n  local myers_hunks = {\n    { buf_start = 1, buf_count = 0, ref_start = 2, ref_count = 1, type = 'delete' },\n    { buf_start = 3, buf_count = 1, ref_start = 3, ref_count = 0, type = 'add' },\n    { buf_start = 4, buf_count = 0, ref_start = 5, ref_count = 1, type = 'delete' },\n    { buf_start = 6, buf_count = 1, ref_start = 6, ref_count = 0, type = 'add' },\n  }\n  eq(get_buf_hunks(0), myers_hunks)\nend\n\nT['Diff']['respects `options.indent_heuristic`'] = function()\n  set_lines({ 'xxx', ' aaa', ' bbb', '', '', ' aaa', 'xxx' })\n  local ref_lines = { 'xxx', ' aaa', 'xxx' }\n\n  set_ref_text(0, ref_lines)\n  eq(get_buf_hunks(0), { { buf_start = 2, buf_count = 4, ref_start = 1, ref_count = 0, type = 'add' } })\n\n  child.lua('MiniDiff.config.options.indent_heuristic = false')\n  set_ref_text(0, ref_lines)\n  eq(get_buf_hunks(0), { { buf_start = 3, buf_count = 4, ref_start = 2, ref_count = 0, type = 'add' } })\nend\n\nT['Diff']['respects `options.linematch`'] = function()\n  set_lines({ 'xxx', 'uuu', 'AaA', 'xxx' })\n  local ref_lines = { 'xxx', 'AAA', 'xxx' }\n\n  set_ref_text(0, ref_lines)\n  local linematch_hunks = {\n    { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' },\n    { buf_start = 3, buf_count = 1, ref_start = 2, ref_count = 1, type = 'change' },\n  }\n  eq(get_buf_hunks(0), linematch_hunks)\n\n  child.lua('MiniDiff.config.options.linematch = 0')\n  set_ref_text(0, ref_lines)\n  local nolinematch_hunks = {\n    { buf_start = 2, buf_count = 2, ref_start = 2, ref_count = 1, type = 'change' },\n  }\n  eq(get_buf_hunks(0), nolinematch_hunks)\nend\n\nT['Diff']['works with BOM bytes'] = function()\n  local small_text_change_delay = 3 * small_time\n  child.lua('MiniDiff.config.delay.text_change = ' .. small_text_change_delay)\n  local lines = { 'aaa', 'bbb' }\n\n  local validate_bom_buffer = function(fileencoding, bytes)\n    -- Mock buffer with BOM bytes\n    local buf_id = new_scratch_buf()\n    set_buf(buf_id)\n\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n    child.api.nvim_set_option_value('fileencoding', fileencoding, { buf = buf_id })\n    child.api.nvim_set_option_value('bomb', true, { buf = buf_id })\n\n    local text_lines = vim.deepcopy(lines)\n    text_lines[1] = bytes .. text_lines[1]\n    set_ref_text(buf_id, text_lines)\n\n    -- Should respect BOM bytes and not report first line as \"change\" hunk\n    eq(get_buf_data().hunks, {})\n\n    type_keys('G', 'o', 'hello', '<Esc>')\n    sleep(small_text_change_delay + small_time)\n    eq(get_buf_data().hunks, { { type = 'add', buf_start = 3, buf_count = 1, ref_start = 2, ref_count = 0 } })\n  end\n\n  validate_bom_buffer('utf-8', string.char(0xef, 0xbb, 0xbf))\n  validate_bom_buffer('utf-16be', string.char(0xfe, 0xff))\n  validate_bom_buffer('utf-16', string.char(0xfe, 0xff))\n  validate_bom_buffer('utf-16le', string.char(0xff, 0xfe))\n  validate_bom_buffer('ucs-4be', string.char(0x00, 0x00, 0xfe, 0xff))\n  validate_bom_buffer('ucs-4', string.char(0x00, 0x00, 0xfe, 0xff))\n  validate_bom_buffer('ucs-4le', string.char(0xff, 0xfe, 0x00, 0x00))\n\n  validate_bom_buffer('unknown', '')\nend\n\nT['Diff']['redraws statusline when diff is updated'] = function()\n  set_lines({ 'aaa', 'uuu' })\n  set_ref_text(0, { 'aaa' })\n\n  child.o.statusline = '%!b:minidiff_summary_string'\n  child.expect_screenshot()\n\n  set_cursor(2, 0)\n  type_keys('o', 'hello')\n  sleep(dummy_text_change_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Diff']['triggers dedicated event'] = function()\n  child.lua([[\n    _G.event_log = {}\n    local track = function(ev) table.insert(_G.event_log, ev.buf) end\n    vim.api.nvim_create_autocmd('User', { pattern = 'MiniDiffUpdated', callback = track})\n  ]])\n\n  set_lines({ 'aaa', 'uuu' })\n  local buf_id = get_buf()\n\n  set_buf(new_buf())\n  set_ref_text(buf_id, { 'aaa' })\n  -- Should trigger with correct buffer in event data\n  eq(child.lua_get('_G.event_log'), { buf_id })\n  set_buf(buf_id)\n\n  set_cursor(2, 0)\n  type_keys('o', 'hello')\n\n  eq(child.lua_get('_G.event_log'), { buf_id })\n  sleep(dummy_text_change_delay + small_time)\n  eq(child.lua_get('_G.event_log'), { buf_id, buf_id })\nend\n\nT['Diff']['`MiniDiffUpdated` event can be used to override `minidiff_summary_string` variable'] = function()\n  child.set_size(10, 15)\n  child.o.laststatus = 2\n  child.o.statusline = '%{getbufvar(\"%\", \"minidiff_summary_string\", \"\")}'\n\n  child.cmd('au User MiniDiffUpdated lua vim.b.minidiff_summary_string = \"Hello\"')\n  set_lines({ 'aaa', 'uuu' })\n  set_ref_text(0, { 'aaa' })\n  eq(child.b.minidiff_summary_string, 'Hello')\n\n  -- Should redraw statusline after `MiniDiffUpdated` event is triggered\n  child.expect_screenshot()\nend\n\n-- More thorough tests are done in \"do_hunks\"\nT['Operator'] = new_set({ hooks = { pre_case = clean_dummy_log } })\n\nT['Operator']['apply'] = new_set()\n\nT['Operator']['apply']['works in Normal mode'] = function()\n  local ref_hunks\n  set_lines({ 'aaa', 'bbb', 'CCC', 'uuu', 'vvv' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  set_cursor(1, 0)\n  type_keys('gh', 'j')\n  ref_hunks = { { buf_start = 1, buf_count = 2, ref_start = 1, ref_count = 2, type = 'change' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  clean_dummy_log()\n\n  -- With dot-repeat\n  set_cursor(4, 0)\n  type_keys('.')\n  ref_hunks = { { buf_start = 4, buf_count = 2, ref_start = 3, ref_count = 0, type = 'add' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\nend\n\nT['Operator']['apply']['allows dot-repeat across buffers'] = function()\n  local ref_hunks\n  set_lines({ 'aaa', 'uuu', 'vvv' })\n  set_ref_text(0, { 'aaa' })\n  set_cursor(2, 0)\n  type_keys('gh', '_')\n  ref_hunks = { { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  clean_dummy_log()\n\n  local new_buf_id = new_buf()\n  set_buf(new_buf_id)\n  set_lines({ 'ccc', 'ddd', 'www', 'xxx', 'eee' })\n  set_ref_text(0, { 'ccc', 'ddd', 'eee' })\n  set_cursor(3, 0)\n  type_keys('.')\n  ref_hunks = { { buf_start = 3, buf_count = 1, ref_start = 2, ref_count = 0, type = 'add' } }\n  validate_dummy_log({ { 'attach', { new_buf_id } }, { 'apply_hunks', { new_buf_id, ref_hunks } } })\n  clean_dummy_log()\nend\n\nT['Operator']['apply']['works in Visual mode'] = function()\n  set_lines({ 'aaa', 'bbb', 'CCC', 'uuu', 'vvv' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  set_cursor(1, 0)\n  type_keys('vj', 'gh')\n  local ref_hunks = { { buf_start = 1, buf_count = 2, ref_start = 1, ref_count = 2, type = 'change' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  eq(child.fn.mode(), 'n')\nend\n\nT['Operator']['apply']['works on not proper textobject'] = function()\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_ref_text(0, { 'aaa', 'ccc' })\n\n  type_keys('G', 'ghgh')\n  validate_notifications({\n    { '(mini.diff) No hunk range under cursor', 'INFO' },\n    { '(mini.diff) Not a proper textobject', 'INFO' },\n  })\nend\n\nT['Operator']['apply']['restores window view'] = function()\n  child.set_size(7, 15)\n  local ref_hunks\n\n  -- Should restore on first application\n  set_lines({ 'ooo', 'ppp', 'qqq', 'rrr', 'aaa', 'sss', 'ttt', 'uuu', 'bbb' })\n\n  set_ref_text(0, { 'aaa', 'bbb' })\n  set_cursor(4, 2)\n  type_keys('zz')\n  eq(child.fn.line('w0'), 2)\n\n  type_keys('gh', 'gg')\n  ref_hunks = { { buf_start = 1, buf_count = 4, ref_start = 0, ref_count = 0, type = 'add' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  clean_dummy_log()\n\n  eq(get_cursor(), { 4, 2 })\n  eq(child.fn.line('w0'), 2)\n\n  -- Should not interfere with dot-repeat\n  set_ref_text(0, { 'ooo', 'ppp', 'qqq', 'rrr', 'aaa', 'bbb' })\n  set_cursor(8, 2)\n  type_keys('zz')\n  eq(child.fn.line('w0'), 6)\n  type_keys('.')\n  ref_hunks = { { buf_start = 6, buf_count = 3, ref_start = 5, ref_count = 0, type = 'add' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\n  -- - Places cursor at the start of textobject as all operators do\n  eq(get_cursor(), { 1, 2 })\n  eq(child.fn.line('w0'), 1)\nend\n\nT['Operator']['apply']['works with different mapping'] = function()\n  child.lua([[MiniDiff.setup({ source = _G.dummy_source, mappings = { apply = 'Gh' } })]])\n\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n\n  set_cursor(2, 0)\n  type_keys('Gh', '_')\n  local ref_hunks = { { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' } }\n  validate_dummy_log({ { 'apply_hunks', { get_buf(), ref_hunks } } })\nend\n\nT['Operator']['reset'] = new_set()\n\nT['Operator']['reset']['works in Normal mode'] = function()\n  set_lines({ 'aaa', 'bbb', 'CCC', 'uuu', 'vvv' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  set_cursor(1, 2)\n  type_keys('gH', 'j')\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC', 'uuu', 'vvv' })\n  eq(get_cursor(), { 1, 2 })\n\n  -- With dot-repeat\n  set_cursor(4, 1)\n  type_keys('.')\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC' })\n  eq(get_cursor(), { 3, 1 })\nend\n\nT['Operator']['reset']['allows dot-repeat across buffers'] = function()\n  set_lines({ 'aaa', 'uuu', 'vvv' })\n  set_ref_text(0, { 'aaa' })\n  set_cursor(2, 0)\n  type_keys('gH', '_')\n  eq(get_lines(), { 'aaa', 'vvv' })\n\n  local new_buf_id = new_buf()\n  set_buf(new_buf_id)\n  set_lines({ 'ccc', 'ddd', 'www', 'xxx', 'eee' })\n  set_ref_text(0, { 'ccc', 'ddd', 'eee' })\n  set_cursor(3, 0)\n  type_keys('.')\n  eq(get_lines(), { 'ccc', 'ddd', 'xxx', 'eee' })\nend\n\nT['Operator']['reset']['works in Visual mode'] = function()\n  set_lines({ 'aaa', 'bbb', 'CCC', 'uuu', 'vvv' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC' })\n\n  set_cursor(1, 2)\n  type_keys('vj', 'gH')\n  eq(get_lines(), { 'AAA', 'BBB', 'CCC', 'uuu', 'vvv' })\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['Operator']['reset']['works on not proper textobject'] = function()\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_ref_text(0, { 'aaa', 'ccc' })\n\n  type_keys('G', 'gHgh')\n  validate_notifications({\n    { '(mini.diff) No hunk range under cursor', 'INFO' },\n    { '(mini.diff) Not a proper textobject', 'INFO' },\n  })\nend\n\nT['Operator']['reset']['works with different mapping'] = function()\n  child.lua([[MiniDiff.setup({ source = _G.dummy_source, mappings = { reset = 'GH' } })]])\n\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n\n  set_cursor(2, 0)\n  type_keys('GH', '_')\n  eq(get_lines(), { 'aaa' })\nend\n\nT['Textobject'] = new_set()\n\nT['Textobject']['works'] = function()\n  set_lines({ 'aaa', 'uuu', 'vvv', 'bbb', 'ccc', 'www' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  set_cursor(2, 0)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'aaa', 'bbb', 'ccc', 'www' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- With dot-repeat\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  set_cursor(4, 0)\n  type_keys('.')\n  eq(get_lines(), { 'aaa', 'bbb', 'ccc' })\n  eq(get_cursor(), { 3, 0 })\nend\n\nT['Textobject']['can work in Visual mode'] = function()\n  load_module({ mappings = { textobject = 'GH' } })\n  set_lines({ 'aaa', 'uuu', 'vvv', 'bbb', 'ccc', 'www' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  set_cursor(2, 0)\n  type_keys('v', 'GH', 'd')\n  eq(get_lines(), { 'aaa', 'bbb', 'ccc', 'www' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Dot-repeat after first application in Visual mode should apply to the same\n  -- relative region\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  set_cursor(1, 0)\n  type_keys('.')\n  eq(get_lines(), { 'ccc', 'www' })\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Textobject']['prefers operator mappings in Visual mode'] = function()\n  load_module({ mappings = { apply = 'Gh', textobject = 'Gh' } })\n  expect.match(child.cmd_capture('xmap Gh'), 'Apply hunks')\n\n  load_module({ mappings = { reset = 'GH', textobject = 'GH' } })\n  expect.match(child.cmd_capture('xmap GH'), 'Reset hunks')\nend\n\nT['Textobject']['does not depend on relative position inside hunk'] = function()\n  set_lines({ 'aaa', 'uuu', 'vvv', 'www', 'bbb' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n\n  set_cursor(3, 0)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'aaa', 'bbb' })\nend\n\nT['Textobject']['works when not inside hunk range'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n\n  set_cursor(1, 0)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'aaa', 'bbb' })\n  validate_notifications({ { '(mini.diff) No hunk range under cursor', 'INFO' } })\nend\n\nT['Textobject']['allows dot-repeat across buffers'] = function()\n  set_lines({ 'aaa', 'uuu' })\n  set_ref_text(0, { 'aaa' })\n  set_cursor(2, 0)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'aaa' })\n\n  local new_buf_id = new_buf()\n  set_buf(new_buf_id)\n  set_lines({ 'bbb', 'ccc', 'vvv', 'www', 'ddd' })\n  set_ref_text(0, { 'bbb', 'ccc', 'ddd' })\n  set_cursor(3, 0)\n  type_keys('.')\n  eq(get_lines(), { 'bbb', 'ccc', 'ddd' })\nend\n\nT['Textobject']['correctly computes contiguous ranges'] = function()\n  -- \"Change\" hunk adjacent to \"add\" and \"delete\" hunks\n  set_lines({ 'AAA', 'uuu', 'BbB', 'DDD', 'www', 'EEE' })\n  set_ref_text(0, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE' })\n  eq(get_buf_hunks(), {\n    { buf_start = 2, buf_count = 1, ref_start = 1, ref_count = 0, type = 'add' },\n    { buf_start = 3, buf_count = 1, ref_start = 2, ref_count = 1, type = 'change' },\n    { buf_start = 3, buf_count = 0, ref_start = 3, ref_count = 1, type = 'delete' },\n    { buf_start = 5, buf_count = 1, ref_start = 4, ref_count = 0, type = 'add' },\n  })\n\n  set_cursor(3, 0)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'AAA', 'DDD', 'www', 'EEE' })\nend\n\nT['Textobject']['works with \"delete\" hunks on edges as target'] = function()\n  -- First line\n  set_lines({ 'bbb', 'ccc' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  set_cursor(1, 1)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'ccc' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- Last line\n  set_lines({ 'aaa', 'bbb' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  set_cursor(2, 1)\n  type_keys('d', 'gh')\n  eq(get_lines(), { 'aaa' })\n  eq(get_cursor(), { 1, 1 })\nend\n\nT['Textobject']['works with different mapping'] = function()\n  child.lua([[\n    MiniDiff.setup({ source = _G.dummy_source, mappings = { textobject = 'Gh' } })\n  ]])\n\n  set_lines({ 'aaa', 'uuu', 'bbb' })\n  set_ref_text(0, { 'aaa', 'bbb' })\n\n  set_cursor(2, 0)\n  type_keys('d', 'Gh')\n  eq(get_lines(), { 'aaa', 'bbb' })\nend\n\nT['Textobject']['throws error in not enabled buffer'] = function()\n  child.set_size(30, 80)\n  child.o.cmdheight = 10\n  disable()\n  expect.error(function() type_keys('d', 'gh') end, 'not enabled')\nend\n\nT['Textobject']['respects `vim.{g,b}.minidiff_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child.set_size(30, 80)\n    child.o.cmdheight = 10\n    set_lines({ 'aaa', 'uuu' })\n    set_ref_text(0, { 'aaa' })\n\n    child[var_type].minidiff_disable = true\n    disable()\n    enable()\n    set_cursor(2, 0)\n    expect.error(function() type_keys('d', 'gh') end, 'not enabled')\n  end,\n})\n\n-- More thorough tests are done in \"goto_hunk\"\nT['Goto'] = new_set()\n\nT['Goto']['works in Normal mode'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(keys, ref_cursor)\n    set_cursor(4, 0)\n    type_keys(keys)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('[H', { 1, 0 })\n  validate('[h', { 3, 0 })\n  validate(']h', { 5, 0 })\n  validate(']H', { 7, 0 })\nend\n\nT['Goto']['works in Visual mode'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(keys, ref_cursor)\n    child.ensure_normal_mode()\n    set_cursor(4, 0)\n    type_keys('v', keys)\n    eq(get_cursor(), ref_cursor)\n    eq(child.fn.mode(), 'v')\n  end\n\n  validate('[H', { 1, 0 })\n  validate('[h', { 3, 0 })\n  validate(']h', { 5, 0 })\n  validate(']H', { 7, 0 })\nend\n\nT['Goto']['works in Operator-pending mode'] = function()\n  local validate = function(keys, ref_lines, ref_cursor)\n    set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n    set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n    set_cursor(4, 1)\n\n    -- Should operate linewise\n    type_keys('d', keys)\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n\n    -- With dot-repeat\n    set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n    set_cursor(4, 1)\n    type_keys('.')\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('[H', { 'www', 'ccc', 'xxx' }, { 1, 1 })\n  validate('[h', { 'uuu', 'aaa', 'www', 'ccc', 'xxx' }, { 3, 1 })\n  validate(']h', { 'uuu', 'aaa', 'vvv', 'ccc', 'xxx' }, { 4, 1 })\n  validate(']H', { 'uuu', 'aaa', 'vvv' }, { 3, 1 })\nend\n\nT['Goto']['allows dot-repeat across buffers'] = function()\n  set_lines({ 'aaa', 'uuu', 'bbb' })\n  set_ref_text(0, { 'aaa' })\n  set_cursor(1, 0)\n  type_keys('d', ']h')\n  eq(get_lines(), { 'bbb' })\n\n  local new_buf_id = new_buf()\n  set_buf(new_buf_id)\n  set_lines({ 'ccc', 'ddd', 'vvv', 'www', 'eee' })\n  set_ref_text(0, { 'ccc', 'ddd', 'eee' })\n  set_cursor(2, 0)\n  type_keys('.')\n  eq(get_lines(), { 'ccc', 'www', 'eee' })\nend\n\nT['Goto']['respects [count]'] = function()\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(keys, ref_cursor)\n    set_cursor(4, 0)\n    type_keys('2', keys)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('[H', { 3, 0 })\n  validate('[h', { 1, 0 })\n  validate(']h', { 7, 0 })\n  validate(']H', { 5, 0 })\nend\n\nT['Goto']['respects `options.wrap_goto`'] = function()\n  child.lua('MiniDiff.config.options.wrap_goto = true')\n\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(keys, init_cursor, ref_cursor)\n    set_cursor(unpack(init_cursor))\n    type_keys(keys)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('[h', { 1, 0 }, { 7, 0 })\n  validate(']h', { 7, 0 }, { 1, 0 })\n\n  validate('2[h', { 1, 0 }, { 5, 0 })\n  validate('2]h', { 7, 0 }, { 3, 0 })\n\n  validate('6[H', { 4, 0 }, { 3, 0 })\n  validate('6]H', { 4, 0 }, { 5, 0 })\nend\n\nT['Goto']['works with different mappings'] = function()\n  child.lua([[\n    MiniDiff.setup({\n      source = _G.dummy_source,\n      mappings = {\n        goto_first = '[G',\n        goto_prev = '[g',\n        goto_next = ']g',\n        goto_last = ']G',\n      }\n    })\n  ]])\n\n  set_lines({ 'uuu', 'aaa', 'vvv', 'bbb', 'www', 'ccc', 'xxx' })\n  set_ref_text(0, { 'aaa', 'bbb', 'ccc' })\n\n  local validate = function(keys, ref_cursor)\n    set_cursor(4, 0)\n    type_keys(keys)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  validate('[G', { 1, 0 })\n  validate('[g', { 3, 0 })\n  validate(']g', { 5, 0 })\n  validate(']G', { 7, 0 })\nend\n\nT['Array of sources'] = new_set()\n\nlocal setup_array_sources = function(n_attach_fails, fail_delay, text_change_delay)\n  child.lua('_G.n_attach_fails = ' .. (n_attach_fails or 2))\n  child.lua('_G.fail_delay = ' .. (fail_delay or (2 * small_time)))\n  child.lua('_G.text_change_delay = ' .. (text_change_delay or (3 * small_time)))\n\n  child.lua([[\n    _G.log = {}\n    local make_source = function(id, do_attach, fail)\n      return {\n        name = 'Source ' .. id,\n        attach = function(buf_id)\n          table.insert(_G.log, 'Source ' .. id .. ' attach')\n          if not do_attach() then return fail(buf_id, 'Source ' .. id) end\n          MiniDiff.set_ref_text(buf_id, 'This is source ' .. id .. '\\n')\n          table.insert(_G.log, 'Source ' .. id .. ' attach success')\n        end,\n        detach = function(buf_id) table.insert(_G.log, 'Source ' .. id .. ' detach') end,\n        apply_hunks = function(buf_id, hunks)\n          table.insert(_G.log, 'Source ' .. id .. ' apply hunks')\n          MiniDiff.set_ref_text(buf_id, 'This is source ' .. id .. '\\nAfter applying hunks\\n')\n        end,\n      }\n    end\n\n    _G.n_attach_tries = 0\n    local do_attach = function()\n      _G.n_attach_tries = _G.n_attach_tries + 1\n      return _G.n_attach_tries > _G.n_attach_fails\n    end\n\n    local fail_now = function(_, source_name)\n      table.insert(_G.log, source_name .. ' attach fail')\n      return false\n    end\n    local fail_later = function(buf_id, source_name)\n      vim.defer_fn(function()\n        table.insert(_G.log, source_name .. ' attach fail')\n        MiniDiff.fail_attach(buf_id)\n      end, _G.fail_delay)\n    end\n\n    local source_1 = make_source(1, do_attach, fail_now)\n    local source_2 = make_source(2, do_attach, fail_later)\n    local source_3 = make_source(3, do_attach, fail_now)\n\n    require('mini.diff').setup({\n      -- Supplying array of sources should try to attach them in order\n      source = { source_1, source_2, source_3 },\n      delay = { text_change = text_change_delay },\n    })\n  ]])\nend\n\nT['Array of sources']['works'] = function()\n  local n_attach_fails, fail_delay, text_change_delay = 2, 2 * small_time, 3 * small_time\n  setup_array_sources(n_attach_fails, fail_delay, text_change_delay)\n\n  set_buf(new_scratch_buf())\n  set_lines({ 'This is' })\n  enable(0)\n\n  local ref_log = {\n    -- First source fails immediately\n    'Source 1 attach',\n    'Source 1 attach fail',\n    -- Second source delays its fail\n    'Source 2 attach',\n  }\n  eq(child.lua_get('_G.log'), ref_log)\n\n  -- - No source should be yet attached\n  eq(get_buf_data(0).ref_text, nil)\n  eq(child.b.minidiff_summary, vim.NIL)\n\n  -- After waiting for source 2 to fail, it should attach source 3\n  sleep(fail_delay + small_time)\n  vim.list_extend(ref_log, { 'Source 2 attach fail', 'Source 3 attach', 'Source 3 attach success' })\n\n  eq(child.lua_get('_G.log'), ref_log)\n  eq(get_buf_data(0).ref_text, 'This is source 3\\n')\n\n  local ref_summary = { add = 0, change = 1, delete = 0, n_ranges = 1, source_name = 'Source 3' }\n  eq(child.b.minidiff_summary, ref_summary)\n\n  -- Should react to text change\n  set_lines({ 'This is', 'new', 'lines' })\n  sleep(text_change_delay + small_time)\n  ref_summary.add = 2\n  eq(child.b.minidiff_summary, ref_summary)\n\n  -- Should use methods from proper source\n  child.lua('_G.log = {}')\n  do_hunks(0, 'apply')\n  eq(child.lua_get('_G.log'), { 'Source 3 apply hunks' })\n\n  child.lua('_G.log = {}')\n  disable(0)\n  eq(child.lua_get('_G.log'), { 'Source 3 detach' })\nend\n\nT['Array of sources']['can not attach'] = function()\n  local n_attach_fails, fail_delay, text_change_delay = 4, 2 * small_time, 3 * small_time\n  setup_array_sources(n_attach_fails, fail_delay, text_change_delay)\n\n  set_buf(new_scratch_buf())\n  enable(0)\n\n  -- Should fail at all three attaches and not call any `detach`\n  sleep(fail_delay + small_time)\n  --stylua: ignore\n  local ref_log = {\n    'Source 1 attach', 'Source 1 attach fail',\n    'Source 2 attach', 'Source 2 attach fail',\n    'Source 3 attach', 'Source 3 attach fail',\n  }\n  eq(child.lua_get('_G.log'), ref_log)\n\n  -- Should properly clean up buffer\n  eq(is_buf_enabled(), false)\n  eq(child.b.minidiff_summary, vim.NIL)\n  eq(child.api.nvim_get_autocmds({ buffer = get_buf() }), {})\n\n  -- Next enable should try attaching from first source\n  child.lua('_G.log = {}')\n  enable(0)\n  sleep(fail_delay + small_time)\n  ref_log = { 'Source 1 attach', 'Source 1 attach fail', 'Source 2 attach', 'Source 2 attach success' }\n  eq(child.lua_get('_G.log'), ref_log)\n\n  local ref_summary = { add = 0, change = 1, delete = 0, n_ranges = 1, source_name = 'Source 2' }\n  eq(child.b.minidiff_summary, ref_summary)\n\n  -- Should still properly track changes\n  set_lines({ 'This is', 'new', 'lines' })\n  sleep(text_change_delay + small_time)\n  ref_summary.add = 2\n  eq(child.b.minidiff_summary, ref_summary)\nend\n\nT['Array of sources']['works after `:edit`'] = function()\n  local n_attach_fails, fail_delay, text_change_delay = 1, 2 * small_time, 3 * small_time\n  setup_array_sources(n_attach_fails, fail_delay, text_change_delay)\n\n  edit(test_file_path)\n  sleep(text_change_delay + small_time)\n\n  local ref_log = {\n    -- First source fails immediately\n    'Source 1 attach',\n    'Source 1 attach fail',\n    -- Second source attaches successfully (also immediately)\n    'Source 2 attach',\n    'Source 2 attach success',\n  }\n  eq(child.lua_get('_G.log'), ref_log)\n  eq(get_buf_data(0).ref_text, 'This is source 2\\n')\n\n  local ref_summary = { add = 1, change = 1, delete = 0, n_ranges = 1, source_name = 'Source 2' }\n  eq(child.b.minidiff_summary, ref_summary)\n\n  -- Should try attaching from first source\n  child.lua('_G.log = {}')\n  child.cmd('edit')\n  ref_log = { 'Source 2 detach', 'Source 1 attach', 'Source 1 attach success' }\n  eq(child.lua_get('_G.log'), ref_log)\n\n  -- Should properly track changes\n  set_lines({ 'This is' })\n  sleep(text_change_delay + small_time)\n  ref_summary.add, ref_summary.source_name = 0, 'Source 1'\n  eq(child.b.minidiff_summary, ref_summary)\nend\n\nT['Array of sources']['respects buffer-local config'] = function()\n  local n_attach_fails, fail_delay, text_change_delay = 1, 2 * small_time, 3 * small_time\n  setup_array_sources(n_attach_fails, fail_delay, text_change_delay)\n\n  set_buf(new_scratch_buf())\n  child.lua('vim.b.minidiff_config = { source = { MiniDiff.config.source[3], MiniDiff.config.source[2] } }')\n  set_lines({ 'This is' })\n  enable(0)\n\n  local ref_log = { 'Source 3 attach', 'Source 3 attach fail', 'Source 2 attach', 'Source 2 attach success' }\n  eq(child.lua_get('_G.log'), ref_log)\nend\n\nT['Array of sources']['works with built-in sources'] = function()\n  mock_spawn()\n  child.lua([[\n    -- Fails to attach\n    _G.stdio_queue = {\n      { {} }, -- Get path to repo's Git dir\n    }\n    _G.process_mock_data = { { exit_code = 1 } }\n  ]])\n\n  local text_change_delay = 3 * small_time\n  child.lua('_G.text_change_delay = ' .. text_change_delay)\n\n  child.lua([[\n    MiniDiff.config.source = { MiniDiff.gen_source.git(), MiniDiff.gen_source.save() }\n    MiniDiff.config.delay.text_change = _G.text_change_delay\n  ]])\n  edit(git_file_path)\n  local init_lines = get_lines()\n  MiniTest.finally(function() child.fn.writefile(init_lines, git_file_path) end)\n\n  eq(is_buf_enabled(0), true)\n  local ref_summary_saved = { add = 0, change = 0, delete = 0, n_ranges = 0, source_name = 'save' }\n  eq(child.b.minidiff_summary, ref_summary_saved)\n\n  -- Should properly track changes\n  set_lines({ 'This is' })\n  sleep(text_change_delay + small_time)\n  local ref_summary_modified = { add = 0, change = 1, delete = 4, n_ranges = 1, source_name = 'save' }\n  eq(child.b.minidiff_summary, ref_summary_modified)\n\n  child.cmd('write')\n  eq(child.b.minidiff_summary, ref_summary_saved)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_doc.lua",
    "content": "-- NOTE: These are basic tests which cover basic functionliaty. A lot of\n-- nuances are not tested to meet \"complexity-necessity\" trade-off.\nlocal helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('doc', config) end\nlocal unload_module = function() child.mini_unload('doc') end\nlocal cd = function(path) child.cmd('cd ' .. path) end\nlocal source_helpers = function() child.cmd('luafile tests/dir-doc/helpers.lua') end\nlocal remove_dir = function(path) child.lua('_G.remove_dir(...)', { path }) end\n--stylua: ignore end\n\n-- Make helpers\nlocal expect_equal_file_contents = function(file1, file2) eq(child.fn.readfile(file1), child.fn.readfile(file2)) end\n\n-- Data =======================================================================\n--stylua: ignore start\nlocal default_section_names = {\n  '@alias',  '@class',    '@diagnostic', '@eval',\n  '@field',  '@overload', '@param',      '@private',\n  '@return', '@seealso',  '@signature',  '@tag',\n  '@text',   '@toc',      '@toc_entry',  '@type',\n  '@usage',\n}\n--stylua: ignore end\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniDoc)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniDoc.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniDoc.config.' .. field), value) end\n  local expect_config_function = function(field)\n    local command = ('type(MiniDoc.config.%s)'):format(field)\n    eq(child.lua_get(command), 'function')\n  end\n  local expect_sections = function(section_names)\n    local t = child.lua_get('vim.tbl_keys(MiniDoc.config.hooks.sections)')\n    table.sort(t)\n    eq(t, section_names)\n\n    for _, key in ipairs(t) do\n      local command = string.format('type(MiniDoc.config.hooks.sections[%s])', vim.inspect(key))\n      eq(child.lua_get(command), 'function')\n    end\n  end\n\n  -- Check default values\n  expect_config_function('annotation_extractor')\n  expect_config('default_section_id', '@text')\n  expect_config_function('hooks.block_pre')\n  expect_config_function('hooks.section_pre')\n  expect_sections(default_section_names)\n  expect_config_function('hooks.section_post')\n  expect_config_function('hooks.block_post')\n  expect_config_function('hooks.file')\n  expect_config_function('hooks.doc')\n  expect_config_function('hooks.write_pre')\n  expect_config_function('hooks.write_post')\n  expect_config('script_path', 'scripts/minidoc.lua')\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ default_section_id = 'aaa' })\n  eq(child.lua_get('MiniDoc.config.default_section_id'), 'aaa')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  local expect_sections_validation = function(section_names)\n    expect_config_error({ hooks = { sections = 1 } }, 'hooks.sections', 'table')\n    for _, s_name in ipairs(section_names) do\n      expect_config_error({ hooks = { sections = { [s_name] = 1 } } }, 'hooks.sections.' .. s_name, 'function')\n    end\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ annotation_extractor = 'a' }, 'annotation_extractor', 'function')\n  expect_config_error({ default_section_id = 1 }, 'default_section_id', 'string')\n  expect_config_error({ hooks = 1 }, 'hooks', 'table')\n  expect_config_error({ hooks = { block_pre = 1 } }, 'hooks.block_pre', 'function')\n  expect_config_error({ hooks = { section_pre = 1 } }, 'hooks.section_pre', 'function')\n  expect_sections_validation(default_section_names)\n  expect_config_error({ hooks = { section_post = 1 } }, 'hooks.section_post', 'function')\n  expect_config_error({ hooks = { block_post = 1 } }, 'hooks.block_post', 'function')\n  expect_config_error({ hooks = { file = 1 } }, 'hooks.file', 'function')\n  expect_config_error({ hooks = { doc = 1 } }, 'hooks.doc', 'function')\n  expect_config_error({ hooks = { write_pre = 1 } }, 'hooks.write_pre', 'function')\n  expect_config_error({ hooks = { write_post = 1 } }, 'hooks.write_post', 'function')\n  expect_config_error({ script_path = 1 }, 'script_path', 'string')\n  expect_config_error({ silent = 1 }, 'silent', 'boolean')\nend\n\nT['default_hooks'] = new_set()\n\nT['default_hooks']['is same as default `MiniDoc.config.hooks`'] = function()\n  -- `vim.deep_equal()` tests equality of functions by their address, so this\n  -- indeed tests what it should\n  eq(child.lua_get('vim.deep_equal(MiniDoc.default_hooks, MiniDoc.config.hooks)'), true)\nend\n\n-- General overview of testing workflow:\n-- - Tests are organized per test scope: collection of source code file with\n--   annotations demonstrating similar functionality. Every test scope organized\n--   in separate subdirectory of 'tests/dir-doc'.\n-- - Testing is performed by evaluating `MiniDoc.generate()` (with possibly\n--   non-default arguments) with current directory being equal to directory of\n--   tested scope (for example, 'default-collation'). It will produce some\n--   output help file ('doc/default-collation.txt' by default). Test is\n--   performed by comparing its contents line by line with manually computed\n--   reference file ('default-collation_reference.txt' by default).\n-- - To add/update tests either:\n--     - Update files in existing test scope and regenerate reference file (run\n--       corresponding `MiniDoc.generate()` manually and save it to correct\n--       '***_reference.txt' file).\n--     - Add new test scope: create directory, add files, generate reference\n--       help file, add separate test case.\nT['generate()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Add inside child process some useful codebase\n      source_helpers()\n\n      -- Set current directory to one containing all input data for tests\n      cd('tests/dir-doc')\n    end,\n  },\n})\n\nlocal validate_test_scope = function(test_scope_name)\n  cd(test_scope_name)\n  child.lua('MiniDoc.generate()')\n  local output_path = ('doc/%s.txt'):format(test_scope_name)\n  local reference_path = ('%s_reference.txt'):format(test_scope_name)\n  expect_equal_file_contents(output_path, reference_path)\n\n  -- Cleanup 'doc' subdirectory from current directory\n  remove_dir('doc')\nend\n\nT['generate()']['uses correct default collation order'] = function() validate_test_scope('default-collation') end\n\nT['generate()']['makes correct afterlines inference'] = function() validate_test_scope('inference') end\n\nT['generate()']['handles sections correctly'] = function() validate_test_scope('sections') end\n\nT['generate()']['respects arguments'] = function()\n  unload_module()\n\n  -- Add project root to runtimepath to be able to `require('mini.doc')`\n  child.cmd('set rtp+=../..')\n  child.lua([[\n      require('mini.doc').setup({\n        hooks = {\n          section_post = function(s)\n            s:insert('This line should be added in `section_post` hook.')\n          end,\n        },\n      })\n    ]])\n\n  cd('arguments')\n  child.lua([[\n      MiniDoc.generate({ 'file.lua' }, 'output.txt', {\n        annotation_extractor = function(l)\n          return string.find(l, '^%-%-(%S*) ?')\n        end,\n      })\n    ]])\n\n  expect_equal_file_contents('output.txt', 'output_reference.txt')\n\n  -- Cleanup\n  child.loop.fs_unlink('output.txt')\nend\n\nT['generate()']['respects `vim.b.minidoc_config`'] = function()\n  child.b.minidoc_config = { script_path = 'buffer-local_script.lua' }\n  child.lua('MiniDoc.generate()')\n  eq(child.lua_get('_G.is_inside_buffer_local_script'), true)\n  eq(child.b.minidoc_config, { script_path = 'buffer-local_script.lua' })\nend\n\nT['generate()']['returns correct data structure'] = function()\n  child.cmd('luafile helpers.lua')\n  cd('structure')\n\n  expect.no_error(function() child.lua('_G.validate_doc_structure(MiniDoc.generate())') end)\n\n  remove_dir('doc')\nend\n\nT['generate()']['uses custom script'] = function()\n  -- Add project root to runtimepath to be able to `require('mini.doc')`\n  child.cmd('set rtp+=../..')\n  cd('custom-script')\n  child.lua([[MiniDoc.config.script_path = 'gendoc/gendoc-script.lua']])\n\n  -- This should execute 'gendoc/gendoc-script.lua' and return what it returns\n  expect.no_error(function() child.lua('_G.validate_doc_structure(MiniDoc.generate())') end)\n  expect_equal_file_contents('output.txt', 'output_reference.txt')\n\n  -- Script is executed only if all arguments are `nil` (default).\n  child.lua([[MiniDoc.generate({ 'init.lua' })]])\n  expect_equal_file_contents('doc/custom-script.txt', 'output_reference.txt')\n  eq(child.lua_get('type(MiniDoc.config.aaa)'), 'nil')\n\n  -- Cleanup\n  child.loop.fs_unlink('output.txt')\n  remove_dir('doc')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_extra.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('extra', config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nlocal islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\n-- Tweak `expect_screenshot()` to test only on Neovim>=0.10 (as it has floating\n-- window footer). Use `child.expect_screenshot_orig()` for original testing.\nchild.expect_screenshot_orig = child.expect_screenshot\nchild.expect_screenshot = function(opts)\n  if child.fn.has('nvim-0.10') == 0 then return end\n  child.expect_screenshot_orig(opts)\nend\n\n-- Test paths helpers\nlocal path_sep = package.config:sub(1, 1)\nlocal join_path = function(...) return (table.concat({ ... }, path_sep):gsub('([\\\\/])[\\\\/]*', '%1')) end\nlocal full_path = function(x) return (child.fn.fnamemodify(x, ':p'):gsub('(.)[\\\\/]$', '%1')) end\n\nlocal test_dir = 'tests/dir-extra'\nlocal test_dir_absolute = vim.fn.fnamemodify(test_dir, ':p'):gsub('(.)[\\\\/]$', '%1')\nlocal real_files_dir = 'tests/dir-extra/real-files'\n\nlocal make_testpath = function(...) return join_path(test_dir, ...) end\n\nlocal real_file = function(basename) return join_path(real_files_dir, basename) end\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal forward_lua_notify = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_notify(lua_cmd, { ... }) end\nend\n\nlocal stop_picker = forward_lua('MiniPick.stop')\nlocal get_picker_items = forward_lua('MiniPick.get_picker_items')\nlocal get_picker_matches = forward_lua('MiniPick.get_picker_matches')\nlocal is_picker_active = forward_lua('MiniPick.is_picker_active')\n\n-- Common test helpers\nlocal validate_buf_name = function(buf_id, name)\n  buf_id = buf_id or child.api.nvim_get_current_buf()\n  name = name ~= '' and full_path(name) or ''\n  eq(child.api.nvim_buf_get_name(buf_id), name)\nend\n\nlocal validate_edit = function(lines_before, cursor_before, keys, lines_after, cursor_after)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n\n  child.ensure_normal_mode()\nend\n\nlocal validate_edit1d = function(line_before, col_before, keys, line_after, col_after)\n  validate_edit({ line_before }, { 1, col_before }, keys, { line_after }, { 1, col_after })\nend\n\nlocal validate_selection = function(selection_from, selection_to, visual_mode)\n  eq(child.fn.mode(), visual_mode or 'v')\n\n  -- Compute two correctly ordered edges\n  local from = { child.fn.line('v'), child.fn.col('v') - 1 }\n  local to = { child.fn.line('.'), child.fn.col('.') - 1 }\n  if to[1] < from[1] or (to[1] == from[1] and to[2] < from[2]) then\n    from, to = to, from\n  end\n  eq(from, selection_from)\n  eq(to, selection_to)\nend\n\nlocal validate_picker_name = function(ref_name) eq(child.lua_get('MiniPick.get_picker_opts().source.name'), ref_name) end\n\nlocal validate_picker_cwd = function(ref_cwd) eq(child.lua_get('MiniPick.get_picker_opts().source.cwd'), ref_cwd) end\n\nlocal validate_partial_equal_arr = function(test_arr, ref_arr)\n  -- Same length\n  eq(#test_arr, #ref_arr)\n\n  -- Partial values\n  local test_arr_mod = {}\n  for i = 1, #ref_arr do\n    local test_with_ref_keys = {}\n    for key, _ in pairs(ref_arr[i]) do\n      test_with_ref_keys[key] = test_arr[i][key]\n    end\n    test_arr_mod[i] = test_with_ref_keys\n  end\n  eq(test_arr_mod, ref_arr)\nend\n\nlocal get_extra_picker_extmarks = function(from, to)\n  local ns_id = child.api.nvim_get_namespaces().MiniExtraPickers\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, from, to, { details = true })\n  return vim.tbl_map(function(x) return { row = x[2], col = x[3], hl_group = x[4].hl_group } end, extmarks)\nend\n\n-- Common mocks\nlocal mock_fn_executable = function(available_executables)\n  local lua_cmd = string.format(\n    'vim.fn.executable = function(x) return vim.tbl_contains(%s, x) and 1 or 0 end',\n    vim.inspect(available_executables)\n  )\n  child.lua(lua_cmd)\nend\n\nlocal mock_git_repo = function(repo_dir)\n  mock_fn_executable({ 'git' })\n\n  local lua_cmd = string.format(\n    [[\n      _G.systemlist_orig = _G.systemlist_orig or vim.fn.systemlist\n      vim.fn.systemlist = function(...)\n        _G.systemlist_args = {...}\n        return %s\n      end]],\n    vim.inspect({ repo_dir })\n  )\n  child.lua(lua_cmd)\nend\n\nlocal mock_no_git_repo = function()\n  mock_fn_executable({ 'git' })\n  child.lua([[\n    _G.systemlist_orig = _G.systemlist_orig or vim.fn.systemlist\n    -- Mock shell error after running check for Git repo\n    vim.fn.systemlist = function() return _G.systemlist_orig('non-existing-cli-command') end\n  ]])\nend\n\nlocal validate_git_repo_check = function(target_dir)\n  eq(child.lua_get('_G.systemlist_args'), { { 'git', '-C', target_dir, 'rev-parse', '--show-toplevel' } })\nend\n\nlocal clear_git_repo_check = function() child.lua('_G.systemlist_args = nil') end\n\nlocal mock_spawn = function()\n  local mock_file = join_path(test_dir, 'mocks', 'spawn.lua')\n  local lua_cmd = string.format('dofile(%s)', vim.inspect(mock_file))\n  child.lua(lua_cmd)\nend\n\nlocal mock_stdout_feed = function(feed) child.lua('_G.stdout_data_feed = ' .. vim.inspect(feed)) end\n\nlocal mock_stderr_feed = function(feed) child.lua('_G.stderr_data_feed = ' .. vim.inspect(feed)) end\n\nlocal mock_cli_return = function(lines)\n  mock_stdout_feed({ table.concat(lines, '\\n') })\n  mock_stderr_feed({})\nend\n\nlocal get_spawn_log = function() return child.lua_get('_G.spawn_log') end\n\nlocal clear_spawn_log = function() child.lua('_G.spawn_log = {}') end\n\nlocal validate_spawn_log = function(ref, index)\n  local present = get_spawn_log()\n  if type(index) == 'number' then present = present[index] end\n  eq(present, ref)\nend\n\nlocal get_process_log = function() return child.lua_get('_G.process_log') end\n\nlocal clear_process_log = function() child.lua('_G.process_log = {}') end\n\n-- Mock consistent paths for more robust screenshot testing\nlocal mock_slash_path_sep = function()\n  if path_sep == '/' then return end\n  child.lua([[\n    _G.fnamemodify_orig = vim.fn.fnamemodify\n    vim.fn.fnamemodify = function(...)\n      return (_G.fnamemodify_orig(...):gsub('\\\\', '/'))\n    end\n\n    _G.getcwd_orig = vim.fn.getcwd\n    vim.fn.getcwd = function() return (getcwd_orig():gsub('\\\\', '/')) end\n  ]])\nend\n\nlocal unmock_slash_path_sep = function()\n  if path_sep == '/' then return end\n  child.lua([[\n    package.config = _G.package_config_orig\n    vim.fn.fnamemodify, vim.fn.getcwd = _G.fnamemodify_orig, _G.getcwd_orig\n  ]])\nend\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Make more comfortable screenshots\n      child.o.laststatus = 0\n      child.o.ruler = false\n      child.set_size(15, 40)\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  child.lua([[require('mini.extra').setup()]])\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniExtra)'), 'table')\nend\n\nT['setup()']['pickers are added to `MiniPick.registry`'] = new_set(\n  { parametrize = { { 'pick_first' }, { 'extra_first' } } },\n  {\n    test = function(init_order)\n      if init_order == 'extra_first' then\n        load_module()\n        child.lua([[require('mini.pick').setup()]])\n      end\n      if init_order == 'pick_first' then\n        child.lua([[require('mini.pick').setup()]])\n        load_module()\n      end\n\n      local extra_pickers = child.lua_get('vim.tbl_keys(MiniExtra.pickers)')\n      for _, picker_name in ipairs(extra_pickers) do\n        local lua_cmd = string.format([[type(MiniPick.registry['%s'])]], picker_name)\n        eq(child.lua_get(lua_cmd), 'function')\n      end\n    end,\n  }\n)\n\nT['setup()']['does not override user picker in `MiniPick.registry`'] = function()\n  child.lua([[\n    require('mini.pick').setup()\n    MiniPick.registry.buf_lines = function() _G.hello = 'world' end\n  ]])\n  load_module()\n  child.lua_notify('MiniPick.registry.buf_lines()')\n  eq(child.lua_get('_G.hello'), 'world')\nend\n\nT['gen_ai_spec'] = new_set({ hooks = { pre_case = load_module } })\n\nT['gen_ai_spec']['buffer()'] = new_set()\n\nT['gen_ai_spec']['buffer()']['works as `a` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { B = MiniExtra.gen_ai_spec.buffer() } })]])\n\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'caB', 'xx', '<Esc>' }, { 'xx' }, { 1, 1 })\n  validate_edit({ 'aa', 'bb' }, { 2, 0 }, { 'caB', 'xx', '<Esc>' }, { 'xx' }, { 1, 1 })\n\n  local validate_delete = function(lines_before, cursor_before)\n    validate_edit(lines_before, cursor_before, { 'daB' }, { '' }, { 1, 0 })\n  end\n\n  validate_delete({ '', ' ', '\\t', 'aa', '\\t', ' ', '' }, { 1, 0 })\n  validate_delete({ '', ' ', '\\t', 'aa', '\\t', ' ', '' }, { 4, 0 })\n  validate_delete({ '', 'aa', '', 'cc', '' }, { 1, 0 })\n\n  validate_delete({ 'aa' }, { 1, 0 })\n  validate_delete({ 'aa', '' }, { 1, 0 })\n  validate_delete({ '' }, { 1, 0 })\n  validate_delete({ ' ', ' ', ' ' }, { 1, 0 })\n\n  -- Should work with dot-repeat\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { ' ', 'bb', ' ' })\n\n  set_lines({ ' ', 'aa', ' ' })\n  type_keys('caB', 'xx', '<Esc>')\n  eq(get_lines(), { 'xx' })\n  child.api.nvim_set_current_buf(buf_id_2)\n  type_keys('.')\n  eq(get_lines(), { 'xx' })\nend\n\nT['gen_ai_spec']['buffer()']['works as `i` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { B = MiniExtra.gen_ai_spec.buffer() } })]])\n\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'ciB', 'xx', '<Esc>' }, { 'xx' }, { 1, 1 })\n  validate_edit({ 'aa', 'bb' }, { 2, 0 }, { 'ciB', 'xx', '<Esc>' }, { 'xx' }, { 1, 1 })\n\n  local lines_with_blanks = { '', ' ', '\\t', 'aa', '\\t', ' ', '' }\n  validate_edit(lines_with_blanks, { 1, 0 }, { 'diB' }, { '', ' ', '\\t', '', '\\t', ' ', '' }, { 4, 0 })\n  validate_edit(lines_with_blanks, { 4, 0 }, { 'diB' }, { '', ' ', '\\t', '', '\\t', ' ', '' }, { 4, 0 })\n\n  validate_edit({ '', 'aa', '', 'cc', '' }, { 1, 0 }, { 'ciB', 'xx', '<Esc>' }, { '', 'xx', '' }, { 2, 1 })\n  validate_edit({ '  aa', '  ', 'bb  ' }, { 1, 0 }, { 'ciB', 'xx', '<Esc>' }, { 'xx' }, { 1, 1 })\n\n  validate_edit({ 'aa' }, { 1, 0 }, { 'diB' }, { '' }, { 1, 0 })\n  validate_edit({ 'aa', '' }, { 1, 0 }, { 'diB' }, { '', '' }, { 1, 0 })\n  validate_edit({ '', 'aa' }, { 1, 0 }, { 'diB' }, { '', '' }, { 2, 0 })\n  validate_edit({ '' }, { 1, 0 }, { 'diB' }, { '' }, { 1, 0 })\n  validate_edit({ ' ', ' ', ' ' }, { 1, 0 }, { 'diB' }, { ' ', ' ', ' ' }, { 1, 0 })\n\n  -- Should work with dot-repeat\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { ' ', '  bb', ' ' })\n\n  set_lines({ ' ', '  aa', ' ' })\n  type_keys('ciB', 'xx', '<Esc>')\n  eq(get_lines(), { ' ', 'xx', ' ' })\n  child.api.nvim_set_current_buf(buf_id_2)\n  type_keys('.')\n  eq(get_lines(), { ' ', 'xx', ' ' })\nend\n\nT['gen_ai_spec']['diagnostic()'] = new_set({\n  hooks = {\n    pre_case = function()\n      local mock_path = make_testpath('mocks', 'diagnostic.lua')\n      child.lua(string.format('dofile(%s)', vim.inspect(mock_path)))\n    end,\n  },\n})\n\nT['gen_ai_spec']['diagnostic()']['works'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { D = MiniExtra.gen_ai_spec.diagnostic() } })]])\n  local buf_cur, buf_other = child.api.nvim_get_current_buf(), child.lua_get('_G.buf_id_1')\n\n  local validate = function(ai_type)\n    child.ensure_normal_mode()\n    child.api.nvim_set_current_buf(buf_cur)\n    set_cursor(1, 0)\n\n    type_keys('v', ai_type, 'D')\n    validate_selection({ 1, 0 }, { 1, 4 })\n\n    -- Consecutive application should work\n    type_keys(ai_type, 'D')\n    validate_selection({ 2, 0 }, { 2, 6 })\n\n    -- Should support `[count]`\n    type_keys('2', ai_type, 'D')\n    validate_selection({ 4, 0 }, { 4, 3 })\n\n    -- Should support `next`/`prev`\n    type_keys(ai_type, 'l', 'D')\n    validate_selection({ 3, 0 }, { 3, 3 })\n\n    type_keys(ai_type, 'n', 'D')\n    validate_selection({ 4, 0 }, { 4, 3 })\n\n    -- Different buffer\n    child.ensure_normal_mode()\n    child.api.nvim_set_current_buf(buf_other)\n    set_cursor(2, 0)\n    type_keys('v', ai_type, 'D')\n    validate_selection({ 2, 2 }, { 2, 6 })\n  end\n\n  -- Both `a` and `i` should behave the same\n  validate('a')\n  validate('i')\nend\n\nT['gen_ai_spec']['diagnostic()']['respects `severity` argument'] = function()\n  child.lua([[require('mini.ai').setup({\n    custom_textobjects = { D = MiniExtra.gen_ai_spec.diagnostic(vim.diagnostic.severity.WARN) },\n  })]])\n  local buf_other = child.lua_get('_G.buf_id_1')\n  child.api.nvim_set_current_buf(buf_other)\n\n  local validate = function(ai_type)\n    child.ensure_normal_mode()\n    set_cursor(1, 0)\n\n    type_keys('v', ai_type, 'D')\n    validate_selection({ 1, 6 }, { 1, 12 })\n    type_keys(ai_type, 'D')\n    validate_selection({ 3, 2 }, { 3, 8 })\n  end\n\n  validate('a')\n  validate('i')\nend\n\nT['gen_ai_spec']['indent()'] = new_set()\n\nlocal ai_indent = function(...) return child.lua_get('MiniExtra.gen_ai_spec.indent()(...)', { ... }) end\n\nT['gen_ai_spec']['indent()']['works as `a` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { I = MiniExtra.gen_ai_spec.indent() } })]])\n\n  set_lines({ 'aa', ' bb', '  cc', ' bb', 'aa', ' bb', 'aa', ' bb', 'aa' })\n\n  set_cursor(3, 0)\n  type_keys('v', 'aI')\n  validate_selection({ 2, 0 }, { 4, 3 })\n\n  -- Consecutive application should work\n  type_keys('aI')\n  validate_selection({ 1, 0 }, { 5, 2 })\n\n  -- Should support `[count]`\n  type_keys('2aI')\n  validate_selection({ 7, 0 }, { 9, 2 })\n\n  -- Should support `next`/`prev`\n  type_keys('alI')\n  validate_selection({ 5, 0 }, { 7, 2 })\n\n  type_keys('anI')\n  validate_selection({ 7, 0 }, { 9, 2 })\nend\n\nT['gen_ai_spec']['indent()']['works as `i` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { I = MiniExtra.gen_ai_spec.indent() } })]])\n\n  set_lines({ 'aa', ' bb', '  cc', ' bb', 'aa', ' bb', 'aa', ' bb', 'aa' })\n\n  set_cursor(3, 0)\n  type_keys('v', 'iI')\n  validate_selection({ 3, 2 }, { 3, 3 })\n\n  -- Consecutive application should work\n  type_keys('iI')\n  validate_selection({ 2, 1 }, { 4, 2 })\n\n  -- Should support `[count]`\n  type_keys('2iI')\n  validate_selection({ 8, 1 }, { 8, 2 })\n\n  -- Should support `next`/`prev`\n  type_keys('ilI')\n  validate_selection({ 6, 1 }, { 6, 2 })\n\n  type_keys('inI')\n  validate_selection({ 8, 1 }, { 8, 2 })\nend\n\nT['gen_ai_spec']['indent()']['works when started on blank line'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { I = MiniExtra.gen_ai_spec.indent() } })]])\n  set_lines({ 'aa', '', '   ', ' bb', 'aa' })\n  local validate = function(line, col)\n    child.ensure_normal_mode()\n    set_cursor(line, col)\n    type_keys('v', 'aI')\n    validate_selection({ 1, 0 }, { 5, 2 })\n  end\n\n  validate(2, 0)\n  validate(3, 2)\nend\n\nT['gen_ai_spec']['indent()']['returns correct structure'] = function()\n  set_lines({ 'aa', ' bb', '  cc', ' bb', 'aa' })\n  eq(ai_indent('a'), {\n    { from = { line = 1, col = 1 }, to = { line = 5, col = 3 } },\n    { from = { line = 2, col = 1 }, to = { line = 4, col = 4 } },\n  })\n  eq(ai_indent('i'), {\n    { from = { line = 2, col = 2 }, to = { line = 4, col = 3 } },\n    { from = { line = 3, col = 3 }, to = { line = 3, col = 4 } },\n  })\nend\n\nlocal validate_ai_indent = function(ref_region_lines)\n  local output = ai_indent('a')\n  local output_region_lines = {}\n  for _, region in ipairs(output) do\n    table.insert(output_region_lines, { region.from.line, region.to.line })\n  end\n  eq(output_region_lines, ref_region_lines)\nend\n\nT['gen_ai_spec']['indent()']['works with tabs'] = function()\n  -- When only tabs are present\n  set_lines({ 'aa', '\\tbb', '\\t\\tcc', '\\tbb', 'aa' })\n  validate_ai_indent({ { 1, 5 }, { 2, 4 } })\n\n  -- Should respect 'tabstop' if tabs and spaces are mixed\n  child.o.tabstop = 3\n  set_lines({ '   aa', '    cc', '\\t\\txx', ' \\tyy', '   aa' })\n  validate_ai_indent({ { 1, 5 }, { 2, 4 } })\nend\n\nT['gen_ai_spec']['indent()']['ignores blank lines indent when computing scopes'] = function()\n  set_lines({ 'aa', ' bb', '    ', '', 'aa' })\n  validate_ai_indent({ { 1, 5 } })\nend\n\nT['gen_ai_spec']['indent()']['includes edge blank lines in `i` textobject'] = function()\n  set_lines({ 'aa', '', '  ', ' bb', '  ', '', 'aa' })\n  validate_ai_indent({ { 1, 7 } })\nend\n\nT['gen_ai_spec']['indent()']['ignores not enclosed regions'] = function()\n  set_lines({ '', '  ', 'aa', ' bb', 'aa', '  ', '' })\n  validate_ai_indent({ { 3, 5 } })\n\n  set_lines({ '', '  ', 'aa', '  ', '' })\n  validate_ai_indent({})\nend\n\nT['gen_ai_spec']['indent()']['does not include scopes with only blank inside'] = function()\n  set_lines({ 'aa', ' bb', '  ', '', '  ', ' bb', 'aa' })\n  validate_ai_indent({ { 1, 7 } })\nend\n\nT['gen_ai_spec']['indent()']['casts rays from top to bottom'] = function()\n  -- NOTE: Not necessarily a good feature, but a documented behavior\n  set_lines({ ' bb', '   dd', '  cc', 'aa' })\n  validate_ai_indent({ { 1, 4 } })\nend\n\nT['gen_ai_spec']['line()'] = new_set()\n\nT['gen_ai_spec']['line()']['works as `a` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { L = MiniExtra.gen_ai_spec.line() } })]])\n\n  validate_edit1d('aa', 0, { 'caL', 'xx', '<Esc>' }, 'xx', 1)\n  validate_edit1d('  aa', 0, { 'caL', 'xx', '<Esc>' }, 'xx', 1)\n  validate_edit1d('\\taa', 0, { 'caL', 'xx', '<Esc>' }, 'xx', 1)\n  validate_edit1d('  aa', 2, { 'caL', 'xx', '<Esc>' }, 'xx', 1)\n\n  -- Should operate charwise inside a line\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 1 }, { 'daL' }, { '', 'bb', 'cc' }, { 1, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 2, 1 }, { 'daL' }, { 'aa', '', 'cc' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 3, 1 }, { 'daL' }, { 'aa', 'bb', '' }, { 3, 0 })\n\n  -- Should work with dot-repeat\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'caL', 'xx', '<Esc>', 'j', '.' }, { 'xx', 'xx' }, { 2, 1 })\nend\n\nT['gen_ai_spec']['line()']['works as `i` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { L = MiniExtra.gen_ai_spec.line() } })]])\n\n  validate_edit1d('aa', 0, { 'ciL', 'xx', '<Esc>' }, 'xx', 1)\n  validate_edit1d('  aa', 0, { 'ciL', 'xx', '<Esc>' }, '  xx', 3)\n  validate_edit1d('\\taa', 0, { 'ciL', 'xx', '<Esc>' }, '\\txx', 2)\n  validate_edit1d(' \\taa', 0, { 'ciL', 'xx', '<Esc>' }, ' \\txx', 3)\n  validate_edit1d('  aa', 2, { 'ciL', 'xx', '<Esc>' }, '  xx', 3)\n\n  -- Should operate charwise inside a line\n  validate_edit({ '  aa', '  bb', '  cc' }, { 1, 1 }, { 'diL' }, { '  ', '  bb', '  cc' }, { 1, 1 })\n  validate_edit({ '  aa', '  bb', '  cc' }, { 2, 1 }, { 'diL' }, { '  aa', '  ', '  cc' }, { 2, 1 })\n  validate_edit({ '  aa', '  bb', '  cc' }, { 3, 1 }, { 'diL' }, { '  aa', '  bb', '  ' }, { 3, 1 })\n\n  -- Should work with dot-repeat\n  validate_edit({ '  aa', '  bb' }, { 1, 0 }, { 'ciL', 'xx', '<Esc>', 'j', '.' }, { '  xx', '  xx' }, { 2, 3 })\nend\n\nT['gen_ai_spec']['number()'] = new_set()\n\nT['gen_ai_spec']['number()']['works as `a` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { N = MiniExtra.gen_ai_spec.number() } })]])\n\n  set_lines({ '111', '-222', '3.33', '-4.44' })\n\n  set_cursor(1, 0)\n  type_keys('v', 'aN')\n  validate_selection({ 1, 0 }, { 1, 2 })\n\n  -- Consecutive application should work\n  type_keys('aN')\n  validate_selection({ 2, 0 }, { 2, 3 })\n\n  -- Should support `[count]`\n  type_keys('2aN')\n  validate_selection({ 4, 0 }, { 4, 4 })\n\n  -- Should support `next`/`prev`\n  type_keys('alN')\n  validate_selection({ 3, 0 }, { 3, 3 })\n\n  type_keys('anN')\n  validate_selection({ 4, 0 }, { 4, 4 })\nend\n\n--stylua: ignore\nT['gen_ai_spec']['number()']['works as `a` in all necessary cases'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { N = MiniExtra.gen_ai_spec.number() } })]])\n\n  local validate = function(number_string)\n    local ref_output = number_string:gsub('.', 'x')\n    validate_edit1d(number_string, 0, {'vaN', 'rx'}, ref_output, 0)\n  end\n\n  validate('1')\n  validate('11')\n  validate('-2')\n  validate('-22')\n  validate('3.3')\n  validate('3.33')\n  validate('33.3')\n  validate('-4.4')\n  validate('-4.44')\n  validate('-44.4')\n\n  validate('00')\n  validate('-00')\n  validate('00.00')\n  validate('-00.00')\n\n  validate_edit1d('-.11', 0, { 'vaN', 'rx' }, '-.xx', 2)\n  validate_edit1d('.11',  0, { 'vaN', 'rx' }, '.xx',  1)\nend\n\nT['gen_ai_spec']['number()']['works as `i` textobject'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { N = MiniExtra.gen_ai_spec.number() } })]])\n\n  set_lines({ '11.2-33 44' })\n\n  set_cursor(1, 0)\n  type_keys('v', 'iN')\n  validate_selection({ 1, 0 }, { 1, 1 })\n\n  -- Consecutive application should work\n  type_keys('iN')\n  validate_selection({ 1, 3 }, { 1, 3 })\n\n  -- Should support `[count]`\n  type_keys('2iN')\n  validate_selection({ 1, 8 }, { 1, 9 })\n\n  -- Should support `next`/`prev`\n  type_keys('ilN')\n  validate_selection({ 1, 5 }, { 1, 6 })\n\n  type_keys('inN')\n  validate_selection({ 1, 8 }, { 1, 9 })\nend\n\nT['gen_ai_spec']['number()']['works as `i` in all necessary cases'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { N = MiniExtra.gen_ai_spec.number() } })]])\n\n  local validate = function(line_before, line_after, col_after)\n    validate_edit1d(line_before, 0, { 'viN', 'rx' }, line_after, col_after)\n  end\n\n  validate('1', 'x', 0)\n  validate('11', 'xx', 0)\n  validate('-2', '-x', 1)\n  validate('-22', '-xx', 1)\n  validate(' 3.3', ' x.3', 1)\n  validate(' 3.33', ' x.33', 1)\n  validate('33.3', 'xx.3', 0)\n  validate('-4.4', '-x.4', 1)\n  validate('-4.44', '-x.44', 1)\n  validate('-44.4', '-xx.4', 1)\n\n  validate('00', 'xx', 0)\n  validate('-00', '-xx', 1)\n  validate('00.00', 'xx.00', 0)\n  validate('-00.00', '-xx.00', 1)\n\n  validate('.11', '.xx', 1)\n  validate('-.11', '-.xx', 2)\n  validate_edit1d('11.22', 3, { 'viN', 'rx' }, '11.xx', 3)\nend\n\nT['gen_ai_spec']['number()']['works with cursor on any part of match'] = function()\n  child.lua([[require('mini.ai').setup({ custom_textobjects = { N = MiniExtra.gen_ai_spec.number() } })]])\n\n  -- `a` textobject\n  set_lines({ '-123.456 789' })\n  for i = 0, 7 do\n    child.ensure_normal_mode()\n    set_cursor(1, i)\n    type_keys('v', 'aN')\n    validate_selection({ 1, 0 }, { 1, 7 })\n  end\n\n  -- `i` textobject\n  for i = 8, 11 do\n    child.ensure_normal_mode()\n    set_cursor(1, i)\n    type_keys('v', 'iN')\n    validate_selection({ 1, 9 }, { 1, 11 })\n  end\nend\n\nT['gen_highlighter'] = new_set({ hooks = { pre_case = load_module } })\n\nT['gen_highlighter']['words()'] = new_set()\n\nlocal hi_words = forward_lua('MiniExtra.gen_highlighter.words')\n\nT['gen_highlighter']['words()']['works'] = function()\n  eq(hi_words({ 'aaa' }, 'Error'), { pattern = { '%f[%w]()aaa()%f[%W]' }, group = 'Error' })\n  eq(\n    hi_words({ 'aaa', 'bbb' }, 'Error'),\n    { pattern = { '%f[%w]()aaa()%f[%W]', '%f[%w]()bbb()%f[%W]' }, group = 'Error' }\n  )\n\n  -- Should escape special characters\n  eq(hi_words({ 'a.+?-b' }, 'Error'), { pattern = { '%f[%w]()a%.%+%?%-b()%f[%W]' }, group = 'Error' })\n\n  -- Should use `extmark_opts` as is\n  eq(\n    hi_words({ 'aaa' }, 'Error', { priority = 100 }),\n    { pattern = { '%f[%w]()aaa()%f[%W]' }, group = 'Error', extmark_opts = { priority = 100 } }\n  )\nend\n\nT['gen_highlighter']['words()']['validates arguments'] = function()\n  expect.error(function() hi_words('todo', 'Error') end, '`words`.*array')\n  expect.error(function() hi_words({ 1 }, 'Error') end, '`words`.*strings')\n  expect.error(function() hi_words({ 'todo' }, 1) end, '`group`.*string or callable')\nend\n\nT['pickers'] = new_set({\n  hooks = {\n    pre_case = function()\n      load_module()\n      child.lua([[require('mini.pick').setup()]])\n\n      -- Make some UI elements differentiable in screenshots\n      child.cmd('hi MiniPickBorder guifg=Red ctermfg=1')\n      child.cmd('hi MiniPickPrompt guifg=Green ctermfg=2')\n      child.cmd('hi MiniPickPromptCaret guifg=Yellow ctermfg=3')\n      child.cmd('hi MiniPickPromptPrefix guifg=Azure ctermfg=4')\n    end,\n  },\n})\n\nlocal validate_active_picker = function() eq(child.lua_get('require(\"mini.pick\").get_picker_state() ~= nil'), true) end\n\nlocal validate_global_source_options = function(picker_start, check_preview, check_choose)\n  child.lua([[\n    MiniPick.config.source.preview = function(buf_id, item)\n      vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, { \"My preview\" })\n      _G.custom_preview = true\n    end\n    MiniPick.config.source.choose = function(item)\n      _G.custom_choose = true\n    end\n  ]])\n  picker_start()\n  local ref_custom_preview = check_preview == false and vim.NIL or true\n  type_keys('<Tab>')\n  eq(child.lua_get('_G.custom_preview'), ref_custom_preview)\n  local ref_custom_choose = check_choose == false and vim.NIL or true\n  type_keys('<CR>')\n  eq(child.lua_get('_G.custom_choose'), ref_custom_choose)\n  type_keys('<C-c>')\nend\n\nT['pickers'][\"validate no 'mini.pick'\"] = function()\n  child.lua([[require = function(module) error() end]])\n\n  local extra_pickers = child.lua_get('vim.tbl_keys(MiniExtra.pickers)')\n  for _, picker_name in ipairs(extra_pickers) do\n    local err_pattern = '%(mini%.extra%) `pickers%.' .. picker_name .. \"%(%)` requires 'mini%.pick'\"\n\n    expect.error(function()\n      local lua_cmd = string.format([[MiniExtra.pickers['%s']()]], picker_name)\n      child.lua(lua_cmd)\n    end, err_pattern)\n  end\nend\n\nT['pickers']['buf_lines()'] = new_set()\n\nlocal pick_buf_lines = forward_lua_notify('MiniExtra.pickers.buf_lines')\n\nlocal setup_buffers = function()\n  -- Normal buffer with name\n  local buf_id_1 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_1, 0, -1, false, { 'This is', '  buffer 1' })\n  child.api.nvim_buf_set_name(buf_id_1, 'buffer-1')\n\n  -- Normal buffer without name\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { 'This is', '  buffer 2' })\n\n  -- Normal buffer without lines\n  local buf_id_3 = child.api.nvim_create_buf(true, false)\n\n  -- Not listed normal buffer\n  local buf_id_4 = child.api.nvim_create_buf(false, false)\n\n  -- Not normal buffer\n  local buf_id_5 = child.api.nvim_create_buf(false, true)\n\n  -- Set current buffer\n  local buf_init = child.api.nvim_get_current_buf()\n  child.api.nvim_set_current_buf(buf_id_1)\n  child.api.nvim_buf_delete(buf_init, { force = true })\n\n  return { buf_id_1, buf_id_2, buf_id_3, buf_id_4, buf_id_5 }\nend\n\nT['pickers']['buf_lines()']['works'] = function()\n  local buffers = setup_buffers()\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.buf_lines()')\n  validate_picker_name('Buffer lines (all)')\n  child.expect_screenshot()\n\n  -- Should properly choose (and also support choosing in same buffer)\n  type_keys('<C-n>')\n  type_keys('<CR>')\n  validate_buf_name(0, 'buffer-1')\n  eq(get_cursor(), { 2, 0 })\n\n  -- Should return chosen value with proper structure\n  eq(child.lua_get('_G.return_item'), { bufnr = buffers[1], lnum = 2, text = 'buffer-1\\0002\\000  buffer 1' })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_buf_lines()\n  validate_active_picker()\nend\n\nT['pickers']['buf_lines()']['respects `local_opts.scope`'] = function()\n  setup_buffers()\n  pick_buf_lines({ scope = 'current' })\n  validate_picker_name('Buffer lines (current)')\n  child.expect_screenshot()\nend\n\nT['pickers']['buf_lines()']['respects `local_opts.preserve_order`'] = function()\n  set_lines({ 'axay', 'b', 'aaxy', 'ccc', 'xaa' })\n  pick_buf_lines({ scope = 'current', preserve_order = true })\n\n  type_keys('x')\n  eq(get_picker_matches().all_inds, { 1, 3, 5 })\n  type_keys('y')\n  eq(get_picker_matches().all_inds, { 1, 3 })\nend\n\nT['pickers']['buf_lines()']['pads line numbers'] = function()\n  local set_n_lines = function(buf_id, prefix, n)\n    local lines = {}\n    for i = 1, n do\n      lines[i] = prefix .. '-' .. i\n    end\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n  end\n\n  local buf_id_1 = child.api.nvim_create_buf(true, false)\n  set_n_lines(buf_id_1, 'buf-1', 9)\n\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  set_n_lines(buf_id_2, 'buf-2', 10)\n\n  local buf_id_3 = child.api.nvim_create_buf(true, false)\n  set_n_lines(buf_id_3, 'buf-3', 99)\n\n  local buf_id_4 = child.api.nvim_create_buf(true, false)\n  set_n_lines(buf_id_4, 'buf-4', 100)\n\n  -- Should pad line numbers to achieve more aligned look\n  child.lua_notify('MiniExtra.pickers.buf_lines()')\n  sleep(small_time)\n  local items = get_picker_items()\n\n  local validate_has_item_with_text = function(text)\n    local res = false\n    for _, item in ipairs(items) do\n      if item.text == text then res = true end\n    end\n    eq(res, true)\n  end\n\n  validate_has_item_with_text('\\0001\\000buf-1-1')\n  validate_has_item_with_text('\\0009\\000buf-1-9')\n\n  validate_has_item_with_text('\\000 1\\000buf-2-1')\n  validate_has_item_with_text('\\000 9\\000buf-2-9')\n  validate_has_item_with_text('\\00010\\000buf-2-10')\n\n  validate_has_item_with_text('\\000 1\\000buf-3-1')\n  validate_has_item_with_text('\\00099\\000buf-3-99')\n\n  validate_has_item_with_text('\\000  1\\000buf-4-1')\n  validate_has_item_with_text('\\000 99\\000buf-4-99')\n  validate_has_item_with_text('\\000100\\000buf-4-100')\n\n  type_keys('<C-c>')\n\n  -- Should work with `scope='current'`\n  child.api.nvim_set_current_buf(buf_id_4)\n  child.lua_notify('MiniExtra.pickers.buf_lines({ scope = \"current\" })')\n  sleep(small_time)\n  items = get_picker_items()\n\n  validate_has_item_with_text('  1\\000buf-4-1')\n  validate_has_item_with_text(' 99\\000buf-4-99')\n  validate_has_item_with_text('100\\000buf-4-100')\n  type_keys('<C-c>')\nend\n\nT['pickers']['buf_lines()']['can not show icons'] = function()\n  setup_buffers()\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  pick_buf_lines()\n  child.expect_screenshot()\nend\n\nT['pickers']['buf_lines()']['respects `opts`'] = function()\n  pick_buf_lines({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['buf_lines()']['respects global source options'] = function()\n  validate_global_source_options(pick_buf_lines, true, true)\nend\n\nT['pickers']['buf_lines()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.buf_lines(...)', { local_opts }) end, error_pattern)\n  end\n  validate({ scope = '1' }, '`pickers%.buf_lines`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['colorschemes()'] = new_set()\n\nlocal pick_colorschemes = forward_lua_notify('MiniExtra.pickers.colorschemes')\n\nT['pickers']['colorschemes()']['works'] = function()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.colorschemes()')\n  validate_picker_name('Colorschemes')\n  type_keys('^mini')\n\n  -- Should find bundled 'mini*' color schemes\n  child.expect_screenshot({ ignore_text = { 14 } })\n\n  -- Should have proper preview\n  type_keys('<Tab>')\n  eq(child.g.colors_name, 'miniautumn')\n  child.expect_screenshot({ ignore_text = { 14 } })\n\n  -- Should properly choose\n  type_keys('<CR>')\n  eq(child.g.colors_name, 'miniautumn')\n  expect.match(child.cmd_capture('hi Normal'), 'guibg=#262029')\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), 'miniautumn')\nend\n\nT['pickers']['colorschemes()']['works with preview'] = function()\n  pick_colorschemes()\n  type_keys('^mini')\n\n  -- Preview should actually apply the color scheme\n  local validate = function(ref_name, ref_normal_bg)\n    eq(child.g.colors_name, ref_name)\n    expect.match(child.cmd_capture('hi Normal'), 'guibg=' .. ref_normal_bg)\n    child.expect_screenshot({ ignore_text = { 14 } })\n  end\n\n  type_keys('<Tab>')\n  validate('miniautumn', '#262029')\n\n  type_keys('<C-n>')\n  validate('minicyan', '#0a2a2a')\n\n  type_keys('<C-p>')\n  validate('miniautumn', '#262029')\nend\n\nT['pickers']['colorschemes()']['previews with original background'] = function()\n  child.cmd('set rtp+=tests/dir-extra/colorschemes')\n\n  child.o.background = 'dark'\n  pick_colorschemes()\n  type_keys('^mini', '<C-n>', '<C-n>', '<Tab>')\n  eq(child.o.background, 'light')\n  eq(child.g.colors_name, 'miniforcebg')\n\n  type_keys('<C-n>')\n  eq(child.o.background, 'dark')\n  eq(child.g.colors_name, 'minischeme')\nend\n\nT['pickers']['colorschemes()']['can choose marked'] = function()\n  pick_colorschemes()\n  type_keys('^mini')\n  type_keys('<C-x>', '<C-n>', '<C-x>', '<M-CR>')\n  eq(child.g.colors_name, 'miniautumn')\nend\n\nT['pickers']['colorschemes()'][\"can cancel with 'mini.colors'\"] = function()\n  child.cmd('colorscheme minischeme')\n  -- These customizations should persist even if there was preview\n  child.api.nvim_set_hl(0, 'Normal', { fg = '#000000' })\n  child.g.terminal_color_0 = '#010101'\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.colorschemes()')\n  type_keys('^mini', '<Tab>')\n  eq(child.g.colors_name, 'miniautumn')\n\n  -- Should trigger 'ColorScheme' event\n  child.cmd('au ColorScheme * lua _G.n = (_G.n or 0) + 1')\n  type_keys('<C-c>')\n  eq(child.lua_get('_G.n'), child.fn.has('nvim-0.10') == 1 and 1 or 2)\n\n  eq(child.lua_get('_G.return_item'), vim.NIL)\n  eq(child.g.colors_name, 'minischeme')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#000000')\n  eq(child.g.terminal_color_0, '#010101')\nend\n\nT['pickers']['colorschemes()'][\"can cancel without 'mini.colors'\"] = function()\n  -- Mock absent 'mini.colors'\n  child.lua([[\n    local require_orig = require\n    require = function(modname)\n      if modname == 'mini.colors' then error(\"module 'mini.colors' not found\") end\n      return require_orig(modname)\n    end\n  ]])\n\n  child.cmd('colorscheme miniwinter')\n  -- These customizations can not persist even if there was preview\n  child.api.nvim_set_hl(0, 'Normal', { fg = '#000000' })\n  child.g.terminal_color_0 = '#010101'\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.colorschemes()')\n  type_keys('^mini', '<Tab>')\n  eq(child.g.colors_name, 'miniautumn')\n\n  type_keys('<C-c>')\n\n  eq(child.lua_get('_G.return_item'), vim.NIL)\n  eq(child.g.colors_name, 'miniwinter')\n  expect.match(child.cmd_capture('hi Normal'), 'guifg=#d8d4cd')\n  eq(child.g.terminal_color_0, '#000f15')\n\n  -- Should work if there is no `g:colors_name` defined before starting picker\n  child.g.colors_name = nil\n  pick_colorschemes()\n  type_keys('^mini', '<Tab>', '<C-c>')\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['pickers']['colorschemes()']['restores original color scheme only if needed'] = function()\n  pick_colorschemes()\n  child.cmd('au ColorScheme * lua _G.n = (_G.n or 0) + 1')\n  type_keys('<C-c>')\n  eq(child.lua_get('_G.n'), vim.NIL)\nend\n\nT['pickers']['colorschemes()']['respects `local_opts.names`'] = function()\n  pick_colorschemes({ names = { 'minisummer', 'minispring' } })\n  eq(get_picker_items(), { 'minisummer', 'minispring' })\n  type_keys('<Tab>')\n  eq(child.g.colors_name, 'minisummer')\n  type_keys('<C-c>')\n\n  -- Should validate\n  expect.error(function() child.lua('MiniExtra.pickers.colorschemes({ names = 1 })') end, '`names`.*array')\n  expect.error(function() child.lua('MiniExtra.pickers.colorschemes({ names = { \"xxx\" } })') end, '\"xxx\".*not')\nend\n\nT['pickers']['colorschemes()']['respects `local_opts.preview_hl_groups`'] = function()\n  pick_colorschemes({ preview_hl_groups = { 'Normal', 'MiniPickBorder' } })\n  type_keys('^mini', '<Tab>')\n  child.expect_screenshot({ ignore_text = { 14 } })\n\n  -- Should validate\n  expect.error(\n    function() child.lua('MiniExtra.pickers.colorschemes({ preview_hl_groups = 1 })') end,\n    '`preview_hl_groups`.*array'\n  )\nend\n\nT['pickers']['colorschemes()']['respects `opts`'] = function()\n  pick_colorschemes({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['commands()'] = new_set()\n\nlocal pick_commands = forward_lua_notify('MiniExtra.pickers.commands')\n\nT['pickers']['commands()']['works'] = function()\n  child.set_size(10, 80)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.commands()')\n  validate_picker_name('Commands')\n  type_keys(\"'chdir\")\n  child.expect_screenshot({ ignore_text = { 9 } })\n\n  -- Should have proper preview\n  type_keys('<Tab>')\n  -- - No data for built-in commands is yet available\n  child.expect_screenshot({ ignore_text = { 9 } })\n\n  -- Should properly choose\n  type_keys('<CR>')\n  eq(child.fn.getcmdline(), 'chdir ')\n  eq(child.fn.getcmdpos(), 7)\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), 'chdir')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_commands()\n  validate_active_picker()\nend\n\nT['pickers']['commands()']['respects user commands'] = function()\n  local expect_screenshot = function(...)\n    -- Screenshots are generated for Neovim>=0.12, since the output structure\n    -- of `nvim_get_commands()` has changed\n    if child.fn.has('nvim-0.12') == 0 then return end\n    child.expect_screenshot(...)\n  end\n\n  child.set_size(25, 75)\n  child.cmd('command -nargs=0 MyCommand lua _G.my_command = true')\n  child.cmd('command -nargs=* -buffer MyCommandBuf lua _G.my_command_buf = true')\n\n  -- Both global and buffer-local\n  pick_commands()\n  type_keys('^MyCommand')\n  eq(get_picker_matches().all, { 'MyCommand', 'MyCommandBuf' })\n\n  -- Should have proper preview with data\n  type_keys('<Tab>')\n  expect_screenshot({ ignore_text = { 24 } })\n  type_keys('<C-n>')\n  expect_screenshot({ ignore_text = { 24 } })\n\n  -- Should on choose execute command if it is without arguments\n  type_keys('<C-p>', '<CR>')\n  eq(is_picker_active(), false)\n  eq(child.lua_get('_G.my_command'), true)\n  eq(child.lua_get('_G.my_command_buf'), vim.NIL)\nend\n\nT['pickers']['commands()']['respects `opts`'] = function()\n  pick_commands({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['commands()']['respects global source options'] = function()\n  validate_global_source_options(pick_commands, false, false)\nend\n\nT['pickers']['diagnostic()'] = new_set({\n  hooks = {\n    pre_case = function()\n      local mock_path = make_testpath('mocks', 'diagnostic.lua')\n      child.lua(string.format('dofile(%s)', vim.inspect(mock_path)))\n    end,\n  },\n})\n\nlocal pick_diagnostic = forward_lua_notify('MiniExtra.pickers.diagnostic')\n\nT['pickers']['diagnostic()']['works'] = function()\n  child.set_size(25, 100)\n  child.cmd('enew')\n\n  mock_slash_path_sep()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.diagnostic()')\n  validate_picker_name('Diagnostic (all)')\n  child.expect_screenshot()\n\n  -- Should use proper highlight groups\n  validate_partial_equal_arr(get_extra_picker_extmarks(0, -1), {\n    { hl_group = 'DiagnosticFloatingError' },\n    { hl_group = 'DiagnosticFloatingError' },\n    { hl_group = 'DiagnosticFloatingError' },\n    { hl_group = 'DiagnosticFloatingWarn' },\n    { hl_group = 'DiagnosticFloatingWarn' },\n    { hl_group = 'DiagnosticFloatingWarn' },\n    { hl_group = 'DiagnosticFloatingInfo' },\n    { hl_group = 'DiagnosticFloatingInfo' },\n    { hl_group = 'DiagnosticFloatingInfo' },\n    { hl_group = 'DiagnosticFloatingHint' },\n    { hl_group = 'DiagnosticFloatingHint' },\n    { hl_group = 'DiagnosticFloatingHint' },\n  })\n\n  -- Should have proper preview\n  type_keys('<C-n>')\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  unmock_slash_path_sep()\n\n  -- Should properly choose\n  type_keys('<CR>')\n  validate_buf_name(0, make_testpath('mocks', 'diagnostic-file-1'))\n  eq(get_cursor(), { 2, 2 })\n\n  local return_item = child.lua_get('_G.return_item')\n  -- - Remove any private fields (like `_extmark_id` on Neovim>=0.12)\n  for _, k in ipairs(vim.tbl_keys(return_item)) do\n    if k:sub(1, 1) == '_' then return_item[k] = nil end\n  end\n\n  --stylua: ignore\n  -- Should return chosen value with proper structure\n  eq(return_item, {\n    bufnr    = 1, namespace = child.lua_get('_G.diag_ns'),\n    severity = 1,\n    col      = 3, end_col   = 8,\n    end_lnum = 2, lnum      = 2,\n    path     = 'tests/dir-extra/mocks/diagnostic-file-1',\n    message  = 'Error 2',\n    text     = 'E │ tests/dir-extra/mocks/diagnostic-file-1 │ Error 2',\n  })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_diagnostic()\n  validate_active_picker()\nend\n\nT['pickers']['diagnostic()']['respects `local_opts.get_opts`'] = function()\n  local hint_severity = child.lua_get('vim.diagnostic.severity.HINT')\n  pick_diagnostic({ get_opts = { severity = hint_severity } })\n  validate_partial_equal_arr(\n    get_picker_items(),\n    { { severity = hint_severity }, { severity = hint_severity }, { severity = hint_severity } }\n  )\nend\n\nT['pickers']['diagnostic()']['respects `local_opts.scope`'] = function()\n  local buf_id = child.api.nvim_get_current_buf()\n  pick_diagnostic({ scope = 'current' })\n  validate_picker_name('Diagnostic (current)')\n  validate_partial_equal_arr(\n    get_picker_items(),\n    { { bufnr = buf_id }, { bufnr = buf_id }, { bufnr = buf_id }, { bufnr = buf_id } }\n  )\nend\n\nT['pickers']['diagnostic()']['respects `local_opts.sort_by`'] = function()\n  local sev_error = child.lua_get('_G.vim.diagnostic.severity.ERROR')\n  local sev_warn = child.lua_get('_G.vim.diagnostic.severity.WARN')\n  local sev_info = child.lua_get('_G.vim.diagnostic.severity.INFO')\n  local sev_hint = child.lua_get('_G.vim.diagnostic.severity.HINT')\n\n  local path_1 = make_testpath('mocks', 'diagnostic-file-1')\n  local path_2 = make_testpath('mocks', 'diagnostic-file-2')\n  if path_sep == '\\\\' then\n    path_1, path_2 = (path_1:gsub('/', '\\\\')), (path_2:gsub('/', '\\\\'))\n  end\n\n  pick_diagnostic({ sort_by = 'severity' })\n  --stylua: ignore\n  validate_partial_equal_arr(\n    get_picker_items(),\n    {\n      { severity = sev_error, path = path_1, message = 'Error 1' },\n      { severity = sev_error, path = path_1, message = 'Error 2' },\n      { severity = sev_error, path = path_2, message = 'Error 3' },\n      { severity = sev_warn,  path = path_1, message = 'Warning 1' },\n      { severity = sev_warn,  path = path_1, message = 'Warning 2' },\n      { severity = sev_warn,  path = path_2, message = 'Warning 3' },\n      { severity = sev_info,  path = path_1, message = 'Info 1' },\n      { severity = sev_info,  path = path_1, message = 'Info 2' },\n      { severity = sev_info,  path = path_2, message = 'Info 3' },\n      { severity = sev_hint,  path = path_1, message = 'Hint 1' },\n      { severity = sev_hint,  path = path_1, message = 'Hint 2' },\n      { severity = sev_hint,  path = path_2, message = 'Hint 3' },\n    }\n  )\n  stop_picker()\n\n  pick_diagnostic({ sort_by = 'path' })\n  --stylua: ignore\n  validate_partial_equal_arr(\n    get_picker_items(),\n    {\n      { severity = sev_error, path = path_1, message = 'Error 1' },\n      { severity = sev_error, path = path_1, message = 'Error 2' },\n      { severity = sev_warn,  path = path_1, message = 'Warning 1' },\n      { severity = sev_warn,  path = path_1, message = 'Warning 2' },\n      { severity = sev_info,  path = path_1, message = 'Info 1' },\n      { severity = sev_info,  path = path_1, message = 'Info 2' },\n      { severity = sev_hint,  path = path_1, message = 'Hint 1' },\n      { severity = sev_hint,  path = path_1, message = 'Hint 2' },\n      { severity = sev_error, path = path_2, message = 'Error 3' },\n      { severity = sev_warn,  path = path_2, message = 'Warning 3' },\n      { severity = sev_info,  path = path_2, message = 'Info 3' },\n      { severity = sev_hint,  path = path_2, message = 'Hint 3' },\n    }\n  )\n  stop_picker()\nend\n\nT['pickers']['diagnostic()']['respects `opts`'] = function()\n  pick_diagnostic({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['diagnostic()']['respects global source options'] = function()\n  validate_global_source_options(pick_diagnostic, true, false)\nend\n\nT['pickers']['diagnostic()']['does not modify diagnostic table'] = function()\n  local diagnostic_current = child.lua_get('vim.diagnostic.get()')\n  pick_diagnostic()\n  stop_picker()\n  eq(child.lua_get('vim.diagnostic.get()'), diagnostic_current)\nend\n\nT['pickers']['diagnostic()'][\"forces 'buflisted' on opened buffer\"] = function()\n  -- This matters for project wide diagnostic done inside unlisted buffers\n  child.lua('vim.bo[_G.buf_id_2].buflisted = false')\n\n  pick_diagnostic()\n  type_keys('<C-p>', '<CR>')\n  eq(child.bo.buflisted, true)\nend\n\nT['pickers']['diagnostic()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.diagnostic(...)', { local_opts }) end, error_pattern)\n  end\n  validate({ scope = '1' }, '`pickers%.diagnostic`.*\"scope\".*\"1\".*one of')\n  validate({ sort_by = '1' }, '`pickers%.diagnostic`.*\"sort_by\".*\"1\".*one of')\nend\n\nT['pickers']['explorer()'] = new_set()\n\nlocal pick_explorer = forward_lua_notify('MiniExtra.pickers.explorer')\n\nT['pickers']['explorer()']['works'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.explorer()')\n  validate_picker_name('File explorer')\n  validate_picker_cwd(init_dir)\n  local init_items = get_picker_items()\n  child.expect_screenshot()\n\n  -- Can navigate inside directory\n  type_keys('<C-n>', '<CR>')\n  child.expect_screenshot()\n  validate_picker_name('File explorer')\n  validate_picker_cwd(init_dir .. '/dir1')\n\n  -- - Should actually change items\n  eq(vim.deep_equal(init_items, get_picker_items()), false)\n\n  -- Can preview directory (both regular and `..`) and file\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-n>')\n  child.expect_screenshot()\n  type_keys('<C-n>')\n  child.expect_screenshot()\n\n  -- Can navigate up\n  type_keys('<C-g>', '<CR>')\n  child.expect_screenshot()\n  validate_picker_cwd(init_dir)\n\n  -- Can choose file\n  type_keys('<C-p>', '<CR>')\n  validate_buf_name(0, 'file3')\n  eq(get_lines(), { 'File 3' })\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), { fs_type = 'file', path = init_dir .. '/file3', text = 'file3' })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_explorer()\n  validate_active_picker()\nend\n\nT['pickers']['explorer()']['works with query'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n\n  pick_explorer()\n  type_keys('^D')\n  eq(get_picker_matches().all, { { fs_type = 'directory', path = init_dir .. '/Dir2', text = 'Dir2/' } })\n\n  type_keys('<CR>')\n  eq(get_picker_matches().all, {\n    { fs_type = 'directory', path = init_dir, text = '..' },\n    { fs_type = 'file', path = init_dir .. '/Dir2/file2-1', text = 'file2-1' },\n  })\n  -- - Should reset the query\n  eq(child.lua_get('MiniPick.get_picker_query()'), {})\nend\n\nT['pickers']['explorer()']['can be resumed'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n  pick_explorer()\n  type_keys('<C-n>', '<CR>', '<C-n>')\n  child.expect_screenshot()\n  stop_picker()\n\n  child.lua_notify('MiniPick.builtin.resume()')\n  validate_picker_cwd(init_dir .. '/dir1')\n  child.expect_screenshot()\nend\n\nT['pickers']['explorer()']['respects `local_opts.cwd`'] = function()\n  local validate = function(cwd, ref_picker_cwd)\n    local init_win_id, init_cwd = child.api.nvim_get_current_win(), child.fn.getcwd()\n    local cwd_absolute = cwd == '..' and vim.fn.fnamemodify(init_cwd, ':h') or full_path(cwd)\n    pick_explorer({ cwd = cwd })\n    validate_picker_cwd(ref_picker_cwd)\n\n    -- Picker window's directory should change, but other should stay the same\n    eq(child.fn.getcwd(0), cwd_absolute)\n    eq(child.fn.getcwd(init_win_id), init_cwd)\n\n    -- Cleanup\n    stop_picker()\n  end\n\n  local path = make_testpath('explorer')\n\n  -- Relative path\n  validate(path, full_path(path))\n\n  -- Absolute path\n  validate(full_path(path), full_path(path))\n\n  -- Parent path\n  child.fn.chdir(path)\n  validate('..', test_dir_absolute)\nend\n\nT['pickers']['explorer()']['respects `local_opts.filter`'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n  child.lua([[\n    _G.filter_log = {}\n    _G.dir_filter = function(item)\n      table.insert(_G.filter_log, vim.deepcopy(item))\n      return item.fs_type == 'directory'\n    end\n  ]])\n  child.lua_notify('MiniExtra.pickers.explorer({ filter = _G.dir_filter })')\n  child.expect_screenshot()\n\n  -- Should work when navigate into subdirectory\n  type_keys('<C-n>', '<CR>')\n  child.expect_screenshot()\n\n  -- Should be called with proper arguments\n  local filter_log = child.lua_get('_G.filter_log')\n  eq(#filter_log, 7 + 3)\n  eq(filter_log[1], { fs_type = 'directory', path = test_dir_absolute, text = '..' })\nend\n\nT['pickers']['explorer()']['respects `local_opts.sort`'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n  child.lua([[\n    _G.sort_log = {}\n    _G.sort_plain = function(items)\n      table.insert(_G.sort_log, vim.deepcopy(items))\n      local res = vim.deepcopy(items)\n      table.sort(res, function(a, b) return a.text < b.text end)\n      return res\n    end\n  ]])\n  child.lua_notify('MiniExtra.pickers.explorer({ sort = _G.sort_plain })')\n  child.expect_screenshot()\n\n  -- Should work when navigate into subdirectory\n  type_keys('<C-n>', '<C-n>', '<C-n>', '<CR>')\n  child.expect_screenshot()\n\n  -- Should be called with proper arguments\n  local sort_log = child.lua_get('_G.sort_log')\n  eq(#sort_log, 2)\n  eq(islist(sort_log[1]), true)\n  eq(sort_log[1][1], { fs_type = 'directory', path = test_dir_absolute, text = '..' })\nend\n\nT['pickers']['explorer()']['can not show icons'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  pick_explorer()\n  child.expect_screenshot()\n  type_keys('<C-n>', '<CR>')\n  child.expect_screenshot()\nend\n\nT['pickers']['explorer()']['respects `opts`'] = function()\n  local init_dir = full_path(make_testpath('explorer'))\n  child.fn.chdir(init_dir)\n  pick_explorer({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['explorer()']['respects global source options'] = function()\n  validate_global_source_options(pick_explorer, true, false)\nend\n\nT['pickers']['explorer()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.explorer(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ cwd = '1' }, '`local_opts%.cwd`.*valid directory path')\n  validate({ filter = '1' }, '`local_opts%.filter`.*callable')\n  validate({ sort = '1' }, '`local_opts%.sort`.*callable')\nend\n\nT['pickers']['git_branches()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal pick_git_branches = forward_lua_notify('MiniExtra.pickers.git_branches')\n\nT['pickers']['git_branches()']['works'] = function()\n  child.set_size(10, 90)\n\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  local branch_lines = {\n    '* main              0123456 Commit message.',\n    'remotes/origin/HEAD -> origin/main',\n    'remotes/origin/main aaaaaaa Another commit message.',\n  }\n  mock_cli_return(branch_lines)\n\n  local buf_init = child.api.nvim_get_current_buf()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.git_branches()')\n  validate_picker_name('Git branches (all)')\n  child.expect_screenshot()\n\n  eq(get_spawn_log(), {\n    { executable = 'git', options = { args = { 'branch', '--all', '-v', '--no-color', '--list' }, cwd = repo_dir } },\n  })\n  clear_spawn_log()\n  clear_process_log()\n\n  -- Should have proper preview\n  child.lua([[_G.stream_type_queue = { 'stdout', 'stderr' }]])\n  local log_lines = { '0123456 Commit message.', 'aaaaaaa Another commit message.' }\n  mock_cli_return(log_lines)\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  eq(get_spawn_log(), {\n    { executable = 'git', options = { args = { '-C', repo_dir, 'log', 'main', '--format=format:%h %s' } } },\n  })\n  -- - It should properly close both stdout and stderr\n  --stylua: ignore\n  local ref_log = {\n    'stdout_2 finished reading.', 'stdout_2 was closed.',\n    'stderr_1 finished reading.', 'stderr_1 was closed.',\n    'Process Pid_2 was closed.',\n  }\n  eq(get_process_log(), ref_log)\n\n  -- Should properly choose by showing history in the new scratch buffer\n  child.lua([[_G.stream_type_queue = { 'stdout', 'stderr' }]])\n  mock_cli_return(log_lines)\n  type_keys('<CR>')\n\n  eq(get_lines(), log_lines)\n  local buf_cur = child.api.nvim_get_current_buf()\n  eq(buf_init ~= buf_cur, true)\n  eq(child.bo.buftype, 'nofile')\n  eq(child.api.nvim_buf_get_name(buf_cur), 'miniextra://' .. buf_cur .. '/main')\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), branch_lines[1])\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_git_branches()\n  validate_active_picker()\nend\n\nT['pickers']['git_branches()']['respects `local_opts.path`'] = function()\n  local repo_dir = test_dir_absolute\n  mock_git_repo(repo_dir)\n  local dir_path = make_testpath('git-files')\n  local dir_path_full = full_path(dir_path)\n\n  local validate = function(path, ref_repo_dir)\n    pick_git_branches({ path = path })\n    eq(get_spawn_log()[1].options, { args = { 'branch', '--all', '-v', '--no-color', '--list' }, cwd = ref_repo_dir })\n    validate_picker_cwd(ref_repo_dir)\n    validate_git_repo_check(dir_path_full)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n    clear_git_repo_check()\n  end\n\n  -- Should always use parent repository path\n  -- - Directory path\n  validate(dir_path_full, repo_dir)\n\n  -- - File path\n  validate(join_path(dir_path, 'git-file-1'), repo_dir)\n\n  -- - Default with different current directory\n  child.fn.chdir(dir_path_full)\n  validate(nil, repo_dir)\nend\n\nT['pickers']['git_branches()']['respects `local_opts.scope`'] = function()\n  mock_git_repo(test_dir_absolute)\n  child.fn.chdir(test_dir_absolute)\n\n  local validate = function(scope, ref_args, ref_picker_name)\n    pick_git_branches({ scope = scope })\n    eq(get_spawn_log()[1].options.args, ref_args)\n    validate_picker_name(ref_picker_name)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n  end\n\n  validate('all', { 'branch', '--all', '-v', '--no-color', '--list' }, 'Git branches (all)')\n  validate('local', { 'branch', '-v', '--no-color', '--list' }, 'Git branches (local)')\n  validate('remotes', { 'branch', '--remotes', '-v', '--no-color', '--list' }, 'Git branches (remotes)')\nend\n\nT['pickers']['git_branches()']['respects `opts`'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  pick_git_branches({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['git_branches()']['respects global source options'] = function()\n  validate_global_source_options(pick_git_branches, false, false)\nend\n\nT['pickers']['git_branches()']['validates git'] = function()\n  -- CLI\n  mock_fn_executable({})\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_branches()') end,\n    '`pickers%.git_branches` requires executable `git`'\n  )\n\n  -- Repo\n  mock_no_git_repo()\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_branches()') end,\n    '`pickers%.git_branches` could not find Git repo for ' .. vim.pesc(child.fn.getcwd())\n  )\nend\n\nT['pickers']['git_branches()']['validates arguments'] = function()\n  mock_git_repo(test_dir_absolute)\n  child.fn.chdir(test_dir_absolute)\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.git_branches(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ path = '1' }, 'Path.*1 is not a valid path')\n  validate({ path = '' }, 'Path.*is empty')\n  validate({ scope = '1' }, '`pickers%.git_branches`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['git_commits()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal pick_git_commits = forward_lua_notify('MiniExtra.pickers.git_commits')\n\nT['pickers']['git_commits()']['works'] = function()\n  child.set_size(33, 100)\n\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  local log_lines = { '0123456 Commit message.', 'aaaaaaa Another commit message.', '1111111 Initial commit.' }\n  mock_cli_return(log_lines)\n  child.lua([[\n    vim.treesitter.get_parser = function(...)\n      _G.ts_get_parser_args = { ... }\n      errror('No parser')\n    end\n  ]])\n\n  local buf_init = child.api.nvim_get_current_buf()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.git_commits()')\n  validate_picker_name('Git commits (all)')\n  child.expect_screenshot()\n\n  eq(get_spawn_log(), {\n    { executable = 'git', options = { args = { 'log', '--format=format:%h %s', '--', repo_dir }, cwd = repo_dir } },\n  })\n  clear_spawn_log()\n  clear_process_log()\n\n  -- Should have proper preview (should try to load tree-sitter first)\n  child.lua([[_G.stream_type_queue = { 'stdout', 'stderr' }]])\n  local show_commit_lines = child.fn.readfile(join_path('mocks', 'git-commit'))\n  mock_cli_return(show_commit_lines)\n  type_keys('<C-p>', '<Tab>')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.ts_get_parser_args[2]'), 'git')\n\n  eq(get_spawn_log(), {\n    { executable = 'git', options = { args = { '-C', repo_dir, '--no-pager', 'show', '1111111' } } },\n  })\n  -- - It should properly close both stdout and stderr\n  --stylua: ignore\n  local ref_log = {\n    'stdout_2 finished reading.', 'stdout_2 was closed.',\n    'stderr_1 finished reading.', 'stderr_1 was closed.',\n    'Process Pid_2 was closed.',\n  }\n  eq(get_process_log(), ref_log)\n\n  -- Should properly choose by showing commit in the new scratch buffer\n  child.lua([[_G.stream_type_queue = { 'stdout', 'stderr' }]])\n  mock_cli_return(show_commit_lines)\n  type_keys('<CR>')\n\n  eq(get_lines(), show_commit_lines)\n  local buf_cur = child.api.nvim_get_current_buf()\n  eq(buf_init ~= buf_cur, true)\n  eq(child.bo.buftype, 'nofile')\n  eq(child.api.nvim_buf_get_name(buf_cur), 'miniextra://' .. buf_cur .. '/1111111')\n  eq(child.bo.syntax, 'git')\n  eq(child.bo.filetype, 'git')\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), log_lines[#log_lines])\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_git_commits()\n  validate_active_picker()\nend\n\nT['pickers']['git_commits()']['respects `local_opts.path`'] = function()\n  local repo_dir = test_dir_absolute\n  mock_git_repo(repo_dir)\n  child.fn.chdir(repo_dir)\n  local dir_path_full = full_path('git-files')\n\n  local validate = function(path, ref_repo_dir)\n    pick_git_commits({ path = path })\n    eq(\n      get_spawn_log()[1].options,\n      { args = { 'log', [[--format=format:%h %s]], '--', path or ref_repo_dir }, cwd = ref_repo_dir }\n    )\n    validate_picker_cwd(ref_repo_dir)\n    validate_picker_name(path == nil and 'Git commits (all)' or 'Git commits (for path)')\n    validate_git_repo_check(dir_path_full)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n    clear_git_repo_check()\n  end\n\n  -- Should always use repo dir as cwd and use path verbatim\n  -- - Directory path\n  validate(dir_path_full, repo_dir)\n\n  -- - File path\n  validate(join_path(dir_path_full, 'git-file-1'), repo_dir)\n\n  -- - Default with different current directory should use repo dir as path\n  child.fn.chdir(dir_path_full)\n  validate(nil, repo_dir)\nend\n\nT['pickers']['git_commits()']['respects `opts`'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  pick_git_commits({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['git_commits()']['respects global source options'] = function()\n  validate_global_source_options(pick_git_branches, false, false)\nend\n\nT['pickers']['git_commits()']['validates git'] = function()\n  -- CLI\n  mock_fn_executable({})\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_commits()') end,\n    '`pickers%.git_commits` requires executable `git`'\n  )\n\n  -- Repo\n  mock_no_git_repo()\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_commits()') end,\n    '`pickers%.git_commits` could not find Git repo for ' .. vim.pesc(child.fn.getcwd())\n  )\nend\n\nT['pickers']['git_commits()']['validates arguments'] = function()\n  mock_git_repo(test_dir_absolute)\n  child.fn.chdir(test_dir_absolute)\n\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.git_commits(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ path = '1' }, 'Path.*1 is not a valid path')\n  validate({ path = '' }, 'Path.*is empty')\nend\n\nT['pickers']['git_files()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal pick_git_files = forward_lua_notify('MiniExtra.pickers.git_files')\n\nT['pickers']['git_files()']['works'] = function()\n  child.set_size(10, 50)\n\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir .. '/git-files')\n  mock_git_repo(repo_dir)\n  mock_cli_return({ 'git-files/git-file-1', 'git-files/git-file-2' })\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.git_files()')\n  validate_picker_name('Git files (tracked)')\n  child.expect_screenshot()\n  local ref_args = { '-C', repo_dir, '-c', 'core.quotepath=false', 'ls-files', '--cached' }\n  eq(get_spawn_log(), { { executable = 'git', options = { args = ref_args, cwd = repo_dir } } })\n\n  -- Should have proper preview\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose\n  type_keys('<CR>')\n  validate_buf_name(0, join_path('git-file-1'))\n  eq(child.fn.getcwd():gsub('\\\\', '/'), repo_dir:gsub('\\\\', '/') .. '/git-files')\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), 'git-files/git-file-1')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_git_files()\n  validate_active_picker()\nend\n\nT['pickers']['git_files()']['respects `local_opts.path`'] = function()\n  local repo_dir = test_dir_absolute\n  mock_git_repo(repo_dir)\n  local dir_path = make_testpath('git-files')\n  local dir_path_full = full_path(dir_path)\n\n  local validate = function(path, ref_cwd)\n    pick_git_files({ path = path })\n    local ref_args = { '-C', ref_cwd, '-c', 'core.quotepath=false', 'ls-files', '--cached' }\n    eq(get_spawn_log()[1].options, { args = ref_args, cwd = ref_cwd })\n    validate_picker_cwd(ref_cwd)\n    validate_git_repo_check(dir_path_full)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n    clear_git_repo_check()\n  end\n\n  -- Directory path\n  validate(dir_path_full, dir_path_full)\n\n  -- File path (should use its parent directory path)\n  validate(join_path(dir_path, 'git-file-1'), dir_path_full)\n\n  -- Default with different current directory should use repo dir\n  child.fn.chdir(dir_path_full)\n  validate(nil, repo_dir)\nend\n\nT['pickers']['git_files()']['respects `local_opts.scope`'] = function()\n  mock_git_repo(test_dir_absolute)\n  child.fn.chdir(test_dir_absolute)\n\n  local validate = function(scope, flags, ref_picker_name)\n    pick_git_files({ scope = scope })\n    local ref_args = { '-C', test_dir_absolute, '-c', 'core.quotepath=false', 'ls-files' }\n    vim.list_extend(ref_args, flags)\n    eq(get_spawn_log()[1].options.args, ref_args)\n    validate_picker_name(ref_picker_name)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n  end\n\n  validate('tracked', { '--cached' }, 'Git files (tracked)')\n  validate('modified', { '--modified' }, 'Git files (modified)')\n  validate('untracked', { '--others' }, 'Git files (untracked)')\n  validate('ignored', { '--others', '--ignored', '--exclude-standard' }, 'Git files (ignored)')\n  validate('deleted', { '--deleted' }, 'Git files (deleted)')\nend\n\nT['pickers']['git_files()']['can not show icons'] = function()\n  child.set_size(10, 50)\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  mock_cli_return({ 'git-files/git-file-1', 'git-files/git-file-2' })\n\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  pick_git_files()\n  child.expect_screenshot()\nend\n\nT['pickers']['git_files()']['respects `opts`'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  pick_git_files({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['git_files()']['respects global source options'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  mock_cli_return({ 'git-files/git-file-1', 'git-files/git-file-2' })\n  validate_global_source_options(pick_git_files, true, true)\nend\n\nT['pickers']['git_files()']['validates git'] = function()\n  -- CLI\n  mock_fn_executable({})\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_files()') end,\n    '`pickers%.git_files` requires executable `git`'\n  )\n\n  -- Repo\n  mock_no_git_repo()\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_files()') end,\n    '`pickers%.git_files` could not find Git repo for ' .. vim.pesc(child.fn.getcwd())\n  )\nend\n\nT['pickers']['git_files()']['validates arguments'] = function()\n  mock_git_repo(test_dir_absolute)\n  child.fn.chdir(test_dir_absolute)\n\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.git_files(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ path = '1' }, 'Path.*1 is not a valid path')\n  validate({ path = '' }, 'Path.*is empty')\n  validate({ scope = '1' }, '`pickers%.git_files`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['git_hunks()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal pick_git_hunks = forward_lua_notify('MiniExtra.pickers.git_hunks')\n\nT['pickers']['git_hunks()']['works'] = function()\n  child.set_size(33, 100)\n\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  local diff_lines = child.fn.readfile(join_path('mocks', 'git-diff'))\n  mock_cli_return(diff_lines)\n  child.lua([[\n    vim.treesitter.get_parser = function(...)\n      _G.ts_get_parser_args = { ... }\n      errror('No parser')\n    end\n  ]])\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.git_hunks()')\n  validate_picker_name('Git hunks (unstaged all)')\n  child.expect_screenshot()\n\n  local ref_args = { 'diff', '--patch', '--unified=3', '--color=never', '--', repo_dir }\n  eq(get_spawn_log(), { { executable = 'git', options = { args = ref_args, cwd = repo_dir } } })\n\n  -- Should have proper preview (without extra CLI calls, but with trying to\n  -- load tree-sitter first)\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  for _ = 1, (#get_picker_items() - 1) do\n    type_keys('<C-n>')\n    child.expect_screenshot()\n  end\n  eq(child.lua_get('_G.ts_get_parser_args[2]'), 'diff')\n\n  -- Should properly choose by navigating to the first hunk change\n  type_keys('<CR>')\n  local target_path = join_path('git-files', 'git-file-2')\n  validate_buf_name(0, target_path)\n  eq(get_cursor(), { 12, 0 })\n\n  -- Should return chosen value\n  local return_item = child.lua_get('_G.return_item')\n  local return_item_keys = vim.tbl_keys(return_item)\n  table.sort(return_item_keys)\n  eq(return_item_keys, { 'header', 'hunk', 'lnum', 'path', 'text' })\n  eq(return_item.path, 'git-files/git-file-2')\n  eq(return_item.lnum, 12)\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_git_hunks()\n  validate_active_picker()\nend\n\nT['pickers']['git_hunks()']['works in edge cases'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  local diff_lines = child.fn.readfile(join_path('mocks', 'git-diff-edge-cases'))\n  mock_cli_return(diff_lines)\n\n  pick_git_hunks()\n\n  local items = get_picker_items()\n  eq(#items, 2)\n  -- Should recognize diffs that come with `diff.mnemonicPrefix=true`\n  eq(items[1].text, 'git-files/git-file-1 │ -1,4 +1,3  │ ')\n  -- Should recognize diffs that come from deleted file\n  eq(items[2].text, 'git-files/git-file-2 │ -1,21 +0,0 │ ')\n  -- - NOTE: Although it still points to a deleted file, so no navigation to it\n  eq(items[2].path, 'git-files/git-file-2')\nend\n\nT['pickers']['git_hunks()']['respects `local_opts.n_context`'] = new_set({ parametrize = { { 0 }, { 20 } } }, {\n  test = function(n_context)\n    child.set_size(15, 100)\n    local repo_dir = test_dir_absolute\n    mock_git_repo(repo_dir)\n    child.fn.chdir(repo_dir)\n\n    -- Zero context\n    local mock_path = join_path('mocks', 'git-diff-unified-' .. n_context)\n    local diff_lines = child.fn.readfile(mock_path)\n    mock_cli_return(diff_lines)\n\n    pick_git_hunks({ n_context = n_context })\n    eq(get_spawn_log(), {\n      {\n        executable = 'git',\n        options = {\n          args = { 'diff', '--patch', '--unified=' .. n_context, '--color=never', '--', repo_dir },\n          cwd = repo_dir,\n        },\n      },\n    })\n    child.expect_screenshot()\n\n    -- - Preview\n    type_keys('<Tab>')\n    child.expect_screenshot()\n    type_keys('<C-n>')\n    child.expect_screenshot()\n\n    -- - Choose\n    type_keys('<CR>')\n    if n_context == 0 then\n      validate_buf_name(0, join_path('git-files', 'git-file-1'))\n      eq(get_cursor(), { 11, 0 })\n    end\n    if n_context == 20 then\n      validate_buf_name(0, join_path('git-files', 'git-file-2'))\n      eq(get_cursor(), { 2, 0 })\n    end\n  end,\n})\n\nT['pickers']['git_hunks()']['respects `local_opts.path`'] = function()\n  local repo_dir = test_dir_absolute\n  mock_git_repo(repo_dir)\n  child.fn.chdir(repo_dir)\n  local dir_path_full = full_path('git-files')\n\n  local validate = function(path, ref_repo_dir)\n    pick_git_hunks({ path = path })\n    eq(\n      get_spawn_log()[1].options,\n      { args = { 'diff', '--patch', '--unified=3', '--color=never', '--', path or ref_repo_dir }, cwd = ref_repo_dir }\n    )\n    validate_picker_cwd(ref_repo_dir)\n    validate_picker_name(path == nil and 'Git hunks (unstaged all)' or 'Git hunks (unstaged for path)')\n    validate_git_repo_check(dir_path_full)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n    clear_git_repo_check()\n  end\n\n  -- Should always use repo dir as cwd and use path verbatim\n  -- - Directory path\n  validate(dir_path_full, repo_dir)\n\n  -- - File path\n  validate(join_path(dir_path_full, 'git-file-1'), repo_dir)\n\n  -- - Default with different current directory should use repo dir as path\n  child.fn.chdir(dir_path_full)\n  validate(nil, repo_dir)\nend\n\nT['pickers']['git_hunks()']['respects `local_opts.scope`'] = function()\n  local repo_dir = test_dir_absolute\n  mock_git_repo(repo_dir)\n  child.fn.chdir(repo_dir)\n\n  local validate = function(scope, ref_args, ref_picker_name)\n    pick_git_hunks({ scope = scope })\n    eq(get_spawn_log()[1].options.args, ref_args)\n    validate_picker_name(ref_picker_name)\n\n    -- Cleanup\n    stop_picker()\n    clear_spawn_log()\n  end\n\n  validate(\n    'unstaged',\n    { 'diff', '--patch', '--unified=3', '--color=never', '--', repo_dir },\n    'Git hunks (unstaged all)'\n  )\n\n  validate(\n    'staged',\n    { 'diff', '--patch', '--cached', '--unified=3', '--color=never', '--', repo_dir },\n    'Git hunks (staged all)'\n  )\nend\n\nT['pickers']['git_hunks()']['respects `opts`'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  pick_git_hunks({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['git_hunks()']['respects global source options'] = function()\n  local repo_dir = test_dir_absolute\n  child.fn.chdir(repo_dir)\n  mock_git_repo(repo_dir)\n  local diff_lines = child.fn.readfile(join_path('mocks', 'git-diff'))\n  mock_cli_return(diff_lines)\n  validate_global_source_options(pick_git_hunks, false, true)\nend\n\nT['pickers']['git_hunks()']['validates git'] = function()\n  -- CLI\n  mock_fn_executable({})\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_hunks()') end,\n    '`pickers%.git_hunks` requires executable `git`'\n  )\n\n  -- Repo\n  mock_no_git_repo()\n  expect.error(\n    function() child.lua('MiniExtra.pickers.git_hunks()') end,\n    '`pickers%.git_hunks` could not find Git repo for ' .. vim.pesc(child.fn.getcwd())\n  )\nend\n\nT['pickers']['git_hunks()']['validates arguments'] = function()\n  mock_git_repo(test_dir_absolute)\n  child.fn.chdir(test_dir_absolute)\n\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.git_hunks(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ n_context = 'a' }, '`n_context`.*`pickers%.git_hunks`.*number')\n  validate({ path = '1' }, 'Path.*1 is not a valid path')\n  validate({ path = '' }, 'Path.*is empty')\n  validate({ scope = '1' }, '`pickers%.git_hunks`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['hipatterns()'] = new_set()\n\nlocal pick_hipatterns = forward_lua_notify('MiniExtra.pickers.hipatterns')\n\nlocal setup_hipatterns = function()\n  child.lua('_G.delay = ' .. (2 * small_time))\n  child.lua([[require('mini.hipatterns').setup({\n    highlighters = {\n      minmax = { pattern = { 'min', 'max' }, group = 'Error' },\n      ['local'] = { pattern = 'local', group = 'Comment' },\n    },\n    delay = { text_change = _G.delay },\n  })]])\n  child.cmd('edit ' .. real_file('a.lua'))\n  local buf_id_1 = child.api.nvim_create_buf(true, false)\n\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_id_2)\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { '', 'min', 'max', 'local' })\n  sleep(2 * small_time + small_time)\n\n  -- Should not be present in results\n  local buf_id_not_enabled = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_not_enabled, 0, -1, false, { 'min max local' })\n\n  return buf_id_1, buf_id_2\nend\n\nT['pickers']['hipatterns()']['works'] = function()\n  child.set_size(15, 120)\n  local _, buf_id_2 = setup_hipatterns()\n\n  mock_slash_path_sep()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.hipatterns()')\n  validate_picker_name('Mini.hipatterns matches (all)')\n  child.expect_screenshot()\n\n  -- Should highlight highlighter's name with its group\n  local ns_id = child.api.nvim_get_namespaces().MiniExtraPickers\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n  local extmark_data = vim.tbl_map(\n    function(x)\n      return { row = x[2], row_end = x[4].end_row, col = x[3], col_end = x[4].end_col, hl_group = x[4].hl_group }\n    end,\n    extmarks\n  )\n  --stylua: ignore\n  eq(extmark_data, {\n    { hl_group = 'Comment', row = 0, row_end = 0, col = 0, col_end = 5 },\n    { hl_group = 'Comment', row = 1, row_end = 1, col = 0, col_end = 5 },\n    { hl_group = 'Error',   row = 2, row_end = 2, col = 0, col_end = 6 },\n    { hl_group = 'Error',   row = 3, row_end = 3, col = 0, col_end = 6 },\n    { hl_group = 'Comment', row = 4, row_end = 4, col = 0, col_end = 5 },\n    { hl_group = 'Error',   row = 5, row_end = 5, col = 0, col_end = 6 },\n    { hl_group = 'Error',   row = 6, row_end = 6, col = 0, col_end = 6 },\n  })\n\n  -- Can preview match region\n  type_keys('<C-p>', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose by positioning on region start\n  type_keys('<CR>')\n  eq(child.api.nvim_get_current_buf(), buf_id_2)\n  eq(get_cursor(), { 3, 0 })\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), {\n    bufnr = buf_id_2,\n    highlighter = 'minmax',\n    hl_group = 'Error',\n    lnum = 3,\n    end_lnum = 3,\n    col = 1,\n    end_col = 4,\n    text = 'minmax │ Buffer_3│3│1│max',\n  })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_hipatterns()\n  validate_active_picker()\nend\n\nT['pickers']['hipatterns()']['respects `local_opts.scope`'] = function()\n  child.set_size(15, 50)\n  setup_hipatterns()\n  pick_hipatterns({ scope = 'current' })\n  validate_picker_name('Mini.hipatterns matches (current)')\n  child.expect_screenshot()\nend\n\nT['pickers']['hipatterns()']['respects `local_opts.highlighters`'] = function()\n  child.set_size(15, 120)\n  setup_hipatterns()\n\n  mock_slash_path_sep()\n  pick_hipatterns({ highlighters = { 'minmax' } })\n  child.expect_screenshot()\n  stop_picker()\n\n  -- Empty table\n  pick_hipatterns({ highlighters = {} })\n  eq(get_picker_items(), {})\nend\n\nT['pickers']['hipatterns()']['respects `opts`'] = function()\n  setup_hipatterns()\n  pick_hipatterns({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['hipatterns()']['respects global source options'] = function()\n  setup_hipatterns()\n  validate_global_source_options(pick_hipatterns, true, true)\nend\n\nT['pickers']['hipatterns()'][\"checks for present 'mini.hipatterns'\"] = function()\n  child.lua([[\n    local require_orig = require\n    require = function(x)\n      if x == 'mini.hipatterns' then error() end\n      require_orig(x)\n    end\n  ]])\n  expect.error(function() child.lua('MiniExtra.pickers.hipatterns()') end, '`pickers%.hipatterns`.*mini%.hipatterns')\nend\n\nT['pickers']['hipatterns()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.hipatterns(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ scope = '1' }, '`pickers%.hipatterns`.*\"scope\".*\"1\".*one of')\n  validate({ highlighters = '1' }, '`local_opts%.highlighters.*array')\nend\n\nT['pickers']['history()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.cmd('set history=100')\n\n      -- Command-line history\n      child.lua('_G.n = 0')\n      type_keys(':lua _G.n = _G.n + 1<CR>')\n      type_keys(':lua _G.n = _G.n + 2<CR>')\n\n      -- Search history\n      child.api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })\n      type_keys('/aaa<CR>')\n      type_keys('/bbb<CR>')\n\n      -- Expressions history\n      type_keys('O', '<C-r>=1+1<CR>', '<Esc>')\n      type_keys('o', '<C-r>=2+2<CR>', '<Esc>')\n\n      -- Input history\n      child.lua_notify([[vim.fn.input('Prompt')]])\n      type_keys('input 1', '<CR>')\n      child.lua_notify([[vim.fn.input('Prompt')]])\n      type_keys('input 2', '<CR>')\n\n      -- Debug mode\n      -- Can't really emulate debug mode\n\n      child.api.nvim_buf_set_lines(0, 0, -1, false, {})\n    end,\n  },\n})\n\nlocal pick_history = forward_lua_notify('MiniExtra.pickers.history')\n\nT['pickers']['history()']['works'] = function()\n  child.set_size(20, 70)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.history()')\n  -- - Should by default list all history\n  validate_picker_name('History (all)')\n  child.expect_screenshot()\n\n  -- Should have no preview\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should return chosen value with proper structure\n  type_keys('<CR>')\n  eq(child.lua_get('_G.return_item'), ': lua _G.n = _G.n + 2')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_history()\n  validate_active_picker()\nend\n\nT['pickers']['history()']['works for command-line history'] = function()\n  -- Works\n  pick_history({ scope = 'cmd' })\n  eq(get_picker_items(), { ': lua _G.n = _G.n + 2', ': lua _G.n = _G.n + 1' })\n  validate_picker_name('History (cmd)')\n\n  -- Should execute command on choose\n  local n = child.lua_get('_G.n')\n  type_keys('<C-n>', '<CR>')\n  eq(child.lua_get('_G.n'), n + 1)\n\n  -- Should work with aliases\n  pick_history({ scope = ':' })\n  validate_picker_name('History (:)')\n  -- Should update command line history\n  eq(get_picker_items(), { ': lua _G.n = _G.n + 1', ': lua _G.n = _G.n + 2' })\nend\n\nT['pickers']['history()']['works for search history'] = function()\n  set_lines({ 'bbb', '  aaa' })\n\n  -- Works\n  pick_history({ scope = 'search' })\n  validate_picker_name('History (search)')\n  eq(get_picker_items(), { '/ bbb', '/ aaa' })\n\n  -- Should restart search on choose (and update history)\n  type_keys('<C-n>', '<CR>')\n  eq(get_cursor(), { 2, 2 })\n  eq(child.o.hlsearch, true)\n  -- - `:history` lists from oldest to newest\n  expect.match(child.cmd_capture('history search'), 'bbb.*aaa')\n\n  -- Should work with aliases\n  pick_history({ scope = '/' })\n  validate_picker_name('History (/)')\n  -- - Should have updated the history\n  eq(get_picker_items(), { '/ aaa', '/ bbb' })\n  stop_picker()\n\n  -- - For `?` alias should search backward\n  set_lines({ 'aaa', 'bbb', 'aaa' })\n  set_cursor(2, 0)\n  pick_history({ scope = '?' })\n  validate_picker_name('History (?)')\n  eq(get_picker_items(), { '? aaa', '? bbb' })\n\n  type_keys('<CR>')\n  eq(get_cursor(), { 1, 0 })\n  eq(child.o.hlsearch, true)\nend\n\nT['pickers']['history()']['works for expression register history'] = function()\n  pick_history({ scope = 'expr' })\n  validate_picker_name('History (expr)')\n  eq(get_picker_items(), { '= 2+2', '= 1+1' })\n\n  -- Nothing is expected to be done on choose\n  type_keys('<CR>')\n\n  -- Should work with aliases\n  pick_history({ scope = '=' })\n  validate_picker_name('History (=)')\n  eq(get_picker_items(), { '= 2+2', '= 1+1' })\nend\n\nT['pickers']['history()']['works for input history'] = function()\n  pick_history({ scope = 'input' })\n  validate_picker_name('History (input)')\n  eq(get_picker_items(), { '@ input 2', '@ input 1' })\n\n  -- Nothing is expected to be done on choose\n  type_keys('<CR>')\n\n  -- Should work with aliases\n  pick_history({ scope = '@' })\n  validate_picker_name('History (@)')\n  eq(get_picker_items(), { '@ input 2', '@ input 1' })\nend\n\nT['pickers']['history()']['works with too wide entries'] = function()\n  child.set_size(10, 15)\n  pick_history({ scope = 'cmd' })\n  eq(get_picker_items(), { ': lua _G.n = _G.n + 2', ': lua _G.n = _G.n + 1' })\nend\n\nT['pickers']['history()']['respects `opts`'] = function()\n  pick_history({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['history()']['respects global source options'] = function()\n  validate_global_source_options(pick_history, false, false)\nend\n\nT['pickers']['history()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.history(...)', { local_opts }) end, error_pattern)\n  end\n  validate({ scope = '1' }, '`pickers%.history`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['history()']['has custom \"edit_command\" mapping'] = function()\n  local validate = function(type, content, active)\n    eq(child.fn.getcmdtype(), type)\n    eq(child.fn.getcmdline(), content)\n    eq(is_picker_active(), active)\n    type_keys('<C-c>')\n  end\n\n  pick_history()\n  eq(child.lua_get('MiniPick.get_picker_opts().mappings.edit_command.char'), '<C-e>')\n  type_keys(':', '<C-e>')\n  validate(':', 'lua _G.n = _G.n + 2', false)\n\n  pick_history()\n  type_keys('/', '<C-e>')\n  validate('/', 'bbb', false)\n\n  pick_history()\n  type_keys('@', '<C-e>')\n  validate('', '', true)\n\n  pick_history({ scope = ':' })\n  type_keys('<C-e>')\n  validate(':', 'lua _G.n = _G.n + 2', false)\n\n  pick_history({ scope = '/' })\n  type_keys('<C-e>')\n  validate('/', 'bbb', false)\nend\n\nT['pickers']['hl_groups()'] = new_set()\n\nlocal pick_hl_groups = forward_lua_notify('MiniExtra.pickers.hl_groups')\n\nT['pickers']['hl_groups()']['works'] = function()\n  child.set_size(10, 80)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.hl_groups()')\n  validate_picker_name('Highlight groups')\n  type_keys('^Spell')\n  child.expect_screenshot({ ignore_text = { 9 } })\n\n  -- Should use same group for line highlighting\n  local matches = get_picker_matches().all\n  validate_partial_equal_arr(get_extra_picker_extmarks(0, -1), {\n    { row = 0, col = 0, hl_group = matches[1] },\n    { row = 1, col = 0, hl_group = matches[2] },\n    { row = 2, col = 0, hl_group = matches[3] },\n    { row = 3, col = 0, hl_group = matches[4] },\n  })\n\n  -- Should have proper preview\n  type_keys('<Tab>')\n  child.expect_screenshot({ ignore_text = { 9 } })\n\n  -- Should properly choose\n  type_keys('<CR>')\n  eq(child.fn.getcmdline(), 'hi SpellBad cterm=undercurl gui=undercurl guisp=#eab3d9')\n  eq(child.fn.getcmdpos(), 56)\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), 'SpellBad')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_hl_groups()\n  validate_active_picker()\nend\n\nT['pickers']['hl_groups()']['respects non-default/linked highlight groups'] = function()\n  child.set_size(10, 40)\n  child.cmd('hi AAAA guifg=#aaaaaa')\n  child.cmd('hi link AAAB AAAA')\n\n  pick_hl_groups()\n  type_keys('^AAA')\n  child.expect_screenshot()\n  validate_partial_equal_arr(get_extra_picker_extmarks(0, -1), {\n    { row = 0, col = 0, hl_group = 'AAAA' },\n    { row = 1, col = 0, hl_group = 'AAAB' },\n  })\nend\n\nT['pickers']['hl_groups()']['respects `opts`'] = function()\n  pick_hl_groups({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['hl_groups()']['respects global source options'] = function()\n  validate_global_source_options(pick_hl_groups, false, false)\nend\n\nT['pickers']['keymaps()'] = new_set()\n\nlocal pick_keymaps = forward_lua_notify('MiniExtra.pickers.keymaps')\n\nlocal setup_keymaps = function()\n  local all_modes = { 'n', 'x', 's', 'o', 'i', 'l', 'c', 't' }\n\n  for _, mode in ipairs(all_modes) do\n    -- Remove all built-in mappings\n    child.cmd(mode .. 'mapclear')\n\n    -- Make custom mappings for more control in tests\n    local rhs = string.format('<Cmd>lua _G.res = \"%s\"<CR>', mode)\n    child.api.nvim_set_keymap(mode, '<Space>' .. mode, rhs, {})\n  end\n\n  -- - With description\n  child.api.nvim_set_keymap('n', '<Space>d', '<Cmd>lua _G.res = \"desc\"<CR>', { desc = 'Description' })\n\n  -- - With longer LHS (to test width aligning)\n  child.api.nvim_set_keymap('n', '<Space>nnn', '<Cmd>lua _G.res = \"long\"<CR>', {})\n\n  -- - Buffer local\n  child.api.nvim_buf_set_keymap(0, 'n', '<Space>b', '<Cmd>lua _G.res = \"buf\"<CR>', {})\nend\n\nT['pickers']['keymaps()']['works'] = function()\n  child.set_size(31, 80)\n  setup_keymaps()\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.keymaps()')\n  validate_picker_name('Keymaps (all)')\n  child.expect_screenshot()\n\n  -- Should have proper preview\n  type_keys('<Tab>')\n  if child.fn.has('nvim-0.12') == 1 then child.expect_screenshot() end\n\n  -- Should properly choose by executing LHS keys\n  type_keys('<CR>')\n  eq(child.lua_get('_G.res'), 'buf')\n\n  -- Should return chosen value\n  local ref_maparg = child.fn.maparg(' b', 'n', false, true)\n  ref_maparg.lhs = child.api.nvim_replace_termcodes(ref_maparg.lhs, true, true, true)\n  eq(child.lua_get('_G.return_item'), {\n    desc = '<Cmd>lua _G.res = \"buf\"<CR>',\n    lhs = '<Space>b',\n    maparg = ref_maparg,\n    text = 'n @ │ <Space>b   │ <Cmd>lua _G.res = \"buf\"<CR>',\n  })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_keymaps()\n  validate_active_picker()\nend\n\nT['pickers']['keymaps()']['can be chosen in non-Normal modes'] = function()\n  setup_keymaps()\n  local validate = function(mode, init_keys)\n    type_keys(init_keys)\n    pick_keymaps()\n    type_keys('^' .. mode, '<CR>')\n    eq(child.lua_get('_G.res'), mode)\n    child.ensure_normal_mode()\n  end\n\n  validate('i', 'i')\n  validate('x', 'v')\n  validate('o', 'd')\n  validate('c', ':')\nend\n\nT['pickers']['keymaps()']['shows source of Lua callback in preview'] = function()\n  child.set_size(20, 100)\n  setup_keymaps()\n  child.cmd('source ' .. make_testpath('mocks', 'keymaps.lua'))\n  pick_keymaps()\n  type_keys(\"'ga \")\n  child.expect_screenshot()\n\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-b>')\n  child.expect_screenshot()\nend\n\nT['pickers']['keymaps()']['respects `local_opts.mode`'] = function()\n  child.lua([[\n    _G.all_items_same_mode = function(mode)\n      for _, item in ipairs(MiniPick.get_picker_items()) do\n        local char = item.text:sub(1, 1)\n        -- Allow 'v' mode mappings when 'x' or 's' is requested\n        local is_v_mode = mode == 'x' or mode == 's'\n        if not (char == mode or (is_v_mode and char == 'v')) then return false end\n      end\n      return true\n    end\n  ]])\n  local validate = function(mode)\n    pick_keymaps({ mode = mode })\n    local lua_cmd = string.format('_G.all_items_same_mode(%s)', vim.inspect(mode))\n    eq(child.lua_get(lua_cmd), true)\n    stop_picker()\n  end\n\n  validate('n')\n  validate('x')\n  validate('s')\n  validate('o')\n  validate('i')\n  validate('l')\n  validate('c')\n  validate('t')\nend\n\nT['pickers']['keymaps()']['respects `local_opts.scope`'] = function()\n  setup_keymaps()\n\n  local has_scopes = function()\n    local has_global, has_buf = false, false\n    for _, item in ipairs(get_picker_items()) do\n      local is_buffer = item.text:sub(3, 3) == '@'\n      if is_buffer then has_buf = true end\n      if not is_buffer then has_global = true end\n    end\n    return { global = has_global, buf = has_buf }\n  end\n\n  pick_keymaps({ scope = 'global' })\n  eq(has_scopes(), { global = true, buf = false })\n  stop_picker()\n\n  pick_keymaps({ scope = 'buf' })\n  eq(has_scopes(), { global = false, buf = true })\n  stop_picker()\nend\n\nT['pickers']['keymaps()']['respects `opts`'] = function()\n  pick_keymaps({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['keymaps()']['respects global source options'] = function()\n  validate_global_source_options(pick_keymaps, false, false)\nend\n\nT['pickers']['keymaps()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.keymaps(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ mode = '1' }, '`pickers%.keymaps`.*\"mode\".*\"1\".*one of')\n  validate({ scope = '1' }, '`pickers%.keymaps`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['list()'] = new_set()\n\nlocal pick_list = forward_lua_notify('MiniExtra.pickers.list')\n\nlocal validate_qf_loc = function(scope)\n  child.set_size(20, 70)\n\n  -- Setup quickfix/location list\n  mock_slash_path_sep()\n  local path = real_file('a.lua')\n  child.cmd('edit ' .. path)\n  child.cmd('enew')\n  local buf_cur = child.api.nvim_get_current_buf()\n  set_lines({ 'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee' })\n  local list = {\n    { filename = full_path(path), lnum = 1, col = 7, text = 'File' },\n    { bufnr = buf_cur, lnum = 2, col = 2, text = 'Buffer' },\n    { bufnr = buf_cur, lnum = 3, col = 3, end_lnum = 4, end_col = 4 },\n  }\n  if scope == 'quickfix' then child.fn.setqflist(list) end\n  if scope == 'location' then child.fn.setloclist(0, list) end\n\n  -- Start picker\n  child.lua_notify('_G.return_item = MiniExtra.pickers.list({ scope = ' .. vim.inspect(scope) .. ' })')\n  validate_picker_name('List (' .. scope .. ')')\n  child.expect_screenshot()\n\n  -- Should preview position/region\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-n>')\n  child.expect_screenshot()\n  type_keys('<C-n>')\n  child.expect_screenshot()\n\n  -- Should properly choose by positioning on region start\n  type_keys('<CR>')\n  eq(child.api.nvim_get_current_buf(), buf_cur)\n  eq(get_cursor(), { 3, 2 })\n\n  -- Should return chosen value\n  validate_partial_equal_arr(\n    { child.lua_get('_G.return_item') },\n    { { bufnr = 2, lnum = 3, end_lnum = 4, col = 3, end_col = 4, text = 'Buffer_2│3│3' } }\n  )\nend\n\nT['pickers']['list()']['works for `quickfix`'] = function() validate_qf_loc('quickfix') end\n\nT['pickers']['list()']['works for `location`'] = function() validate_qf_loc('location') end\n\nT['pickers']['list()']['works for `jump`'] = function()\n  child.set_size(20, 70)\n\n  -- Setup jump list\n  local path = real_file('a.lua')\n  child.cmd('edit ' .. path)\n  type_keys('G')\n\n  child.cmd('enew')\n  local buf_cur = child.api.nvim_get_current_buf()\n  set_lines({ 'aaaaa', 'bbbbb' })\n  type_keys('G', 'gg')\n\n  -- Start picker\n  mock_slash_path_sep()\n  child.lua_notify([[_G.return_item = MiniExtra.pickers.list({ scope = 'jump' })]])\n  validate_picker_name('List (jump)')\n  child.expect_screenshot()\n\n  -- Should preview position\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose by moving to position\n  type_keys('<CR>')\n  eq(child.api.nvim_get_current_buf(), buf_cur)\n  eq(get_cursor(), { 2, 0 })\n\n  -- Should return chosen value\n  validate_partial_equal_arr(\n    { child.lua_get('_G.return_item') },\n    { { bufnr = buf_cur, lnum = 2, col = 1, text = 'Buffer_2│2│1' } }\n  )\nend\n\nT['pickers']['list()']['works for `change`'] = function()\n  child.set_size(20, 70)\n\n  -- Setup jump list\n  local path = real_file('a.lua'):gsub('\\\\', '/')\n  child.cmd('edit ' .. path)\n  set_cursor(1, 1)\n  type_keys('i', ' Change 1 ', '<Esc>')\n\n  set_cursor(3, 3)\n  type_keys('i', ' Change 2 ', '<Esc>')\n\n  -- Start picker\n  mock_slash_path_sep()\n  child.lua_notify([[_G.return_item = MiniExtra.pickers.list({ scope = 'change' })]])\n  validate_picker_name('List (change)')\n  child.expect_screenshot()\n\n  -- Should preview position\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose by moving to position\n  type_keys('<CR>')\n  eq(get_cursor(), { 1, 10 })\n\n  -- Should return chosen value\n  validate_partial_equal_arr(\n    { child.lua_get('_G.return_item') },\n    { { bufnr = 1, col = 11, coladd = 0, lnum = 1, text = path .. '│1│11' } }\n  )\nend\n\nT['pickers']['list()']['works with empty list'] = function()\n  local validate = function(scope)\n    pick_list({ scope = scope })\n    eq(get_picker_items(), {})\n    stop_picker()\n  end\n\n  validate('quickfix')\n  validate('location')\n  validate('jump')\n  validate('change')\nend\n\nT['pickers']['list()']['respects `opts`'] = function()\n  pick_list({ scope = 'jump' }, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['list()']['respects global source options'] = function()\n  local path = real_file('a.lua')\n  child.cmd('edit ' .. path)\n  type_keys('G')\n  type_keys('gg')\n  validate_global_source_options(function() pick_list({ scope = 'jump' }) end, true, false)\nend\n\nT['pickers']['list()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.list(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({}, '`pickers%.list` needs an explicit scope')\n  validate({ scope = '1' }, '`pickers%.list`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['lsp()'] = new_set()\n\nlocal pick_lsp = forward_lua_notify('MiniExtra.pickers.lsp')\n\nlocal setup_lsp = function()\n  child.set_size(15, 90)\n\n  -- Set up file\n  local file_path = real_file('a.lua')\n  child.cmd('edit ' .. file_path)\n\n  -- Mock server\n  child.cmd('luafile tests/mock-lsp/extra.lua')\n\n  return file_path, full_path(file_path)\nend\n\nlocal scope_to_request = {\n  declaration = 'textDocument/declaration',\n  definition = 'textDocument/definition',\n  document_symbol = 'textDocument/documentSymbol',\n  implementation = 'textDocument/implementation',\n  references = 'textDocument/references',\n  type_definition = 'textDocument/typeDefinition',\n  workspace_symbol = 'workspace/symbol',\n  workspace_symbol_live = 'workspace/symbol',\n}\n\nlocal validate_location_scope = function(scope)\n  local file_path, file_path_full = setup_lsp()\n\n  mock_slash_path_sep()\n  pick_lsp({ scope = scope })\n  eq(child.lua_get('_G.lsp_requests'), { scope_to_request[scope] })\n  validate_picker_name('LSP (' .. scope .. ')')\n  child.expect_screenshot()\n\n  -- Should preview position\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  unmock_slash_path_sep()\n\n  -- Should have proper items\n  local ref_item = {\n    filename = file_path_full,\n    path = file_path_full,\n    lnum = 3,\n    col = 16,\n    end_lnum = 3,\n    end_col = 17,\n    text = file_path:gsub('\\\\', '/') .. '│3│16│   x = math.max(a, 2),',\n    user_data = {\n      range = { start = { line = 2, character = 15 }, ['end'] = { line = 2, character = 16 } },\n      uri = 'file://' .. (helpers.is_windows() and '/' or '') .. file_path_full:gsub('\\\\', '/'),\n    },\n  }\n  if child.fn.has('nvim-0.11') == 0 then\n    ref_item.end_lnum, ref_item.end_col = nil, nil\n  end\n  if child.fn.has('nvim-0.10') == 0 then ref_item.user_data = nil end\n  eq(get_picker_items()[1], ref_item)\n\n  -- Should properly choose by moving to the position\n  type_keys('<CR>')\n  validate_buf_name(0, file_path)\n  eq(get_cursor(), { 3, 15 })\n\n  -- Should open path in relative form for nicer `:buffers`.\n  -- It isn't testing much as `vim.lsp.buf` is mocked, but just in case.\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]' .. vim.pesc(file_path:gsub('\\\\', '/')))\nend\n\nlocal validate_symbol_scope = function(scope, skip_preview)\n  local file_path, file_path_full = setup_lsp()\n\n  mock_slash_path_sep()\n  pick_lsp({ scope = scope })\n  validate_picker_name('LSP (' .. scope .. ')')\n  eq(child.lua_get('_G.lsp_requests'), { scope_to_request[scope] })\n  if scope == 'workspace_symbol' then eq(child.lua_get('_G.params.query'), '') end\n  child.expect_screenshot()\n\n  -- Should highlight some symbols\n  local has_mini_icons = child.lua_get('_G.MiniIcons ~= nil')\n  local ref_extmark_data = {\n    { hl_group = '@number', row = 0, col = 0 },\n    { hl_group = '@object', row = 1, col = 0 },\n    { hl_group = '@variable', row = 2, col = 0 },\n    { hl_group = '@variable', row = 3, col = 0 },\n  }\n  if has_mini_icons then\n    ref_extmark_data[1].hl_group = 'MiniIconsOrange'\n    ref_extmark_data[2].hl_group = 'MiniIconsGrey'\n    ref_extmark_data[3].hl_group = 'MiniIconsCyan'\n    ref_extmark_data[4].hl_group = 'MiniIconsCyan'\n  end\n  eq(get_extra_picker_extmarks(0, -1), ref_extmark_data)\n\n  -- Should preview position\n  if not skip_preview then\n    type_keys('<Tab>')\n    child.expect_screenshot()\n  end\n  unmock_slash_path_sep()\n\n  -- Should have proper items\n  local text_prefix = scope == 'workspace_symbol' and (file_path:gsub('\\\\', '/') .. '│1│7│ ') or ''\n  local kind_name = child.lua_get('vim.lsp.protocol.SymbolKind[16]')\n  -- - Icon should be added only if it is not already assumed to be inside\n  --   `SymbolKind` map (as after `MiniIcons.tweak_lsp_kind()`).\n  if has_mini_icons and kind_name == 'Number' then text_prefix = ' ' .. text_prefix end\n  local ref_item = {\n    filename = file_path_full,\n    path = file_path_full,\n    lnum = 1,\n    col = 7,\n    end_lnum = 1,\n    end_col = 8,\n    kind = 'Number',\n    text = text_prefix .. '[' .. kind_name .. '] a',\n    hl = ref_extmark_data[1].hl_group,\n  }\n  if child.fn.has('nvim-0.11') == 0 then\n    ref_item.end_lnum, ref_item.end_col = nil, nil\n  end\n  eq(get_picker_items()[1], ref_item)\n\n  -- Should properly choose by moving to the position\n  type_keys('<CR>')\n  validate_buf_name(0, file_path)\n  eq(get_cursor(), { 1, 6 })\n\n  -- Should open path in relative form for nicer `:buffers`.\n  -- It isn't testing much as `vim.lsp.buf` is mocked, but just in case.\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]' .. vim.pesc(file_path:gsub('\\\\', '/')))\nend\n\nlocal validate_symbol_scope_with_tweaked_kind = function(scope, tweak_lsp_kind_mode)\n  child.lua('_G.symbol_kind_orig = vim.deepcopy(vim.lsp.protocol.SymbolKind)')\n  child.lua(\"require('mini.icons').setup()\")\n  child.lua('MiniIcons.tweak_lsp_kind(...)', { tweak_lsp_kind_mode })\n\n  validate_symbol_scope(scope, true)\n\n  child.lua('vim.lsp.protocol.SymbolKind = _G.symbol_kind_orig')\nend\n\nT['pickers']['lsp()']['works for `declaration`'] = function() validate_location_scope('declaration') end\n\nT['pickers']['lsp()']['works for `definition`'] = function() validate_location_scope('definition') end\n\nT['pickers']['lsp()']['works for `document_symbol`'] = function() validate_symbol_scope('document_symbol') end\n\nT['pickers']['lsp()'][\"works for `document_symbol` with 'mini.icons' set up\"] = function()\n  child.lua(\"require('mini.icons').setup()\")\n  validate_symbol_scope('document_symbol')\nend\n\nT['pickers']['lsp()']['works for `document_symbol` after `MiniIcons.tweak_lsp_kind()`'] = function()\n  validate_symbol_scope_with_tweaked_kind('document_symbol', 'prepend')\n  validate_symbol_scope_with_tweaked_kind('document_symbol', 'append')\n  validate_symbol_scope_with_tweaked_kind('document_symbol', 'replace')\nend\n\nT['pickers']['lsp()']['works for `implementation`'] = function() validate_location_scope('implementation') end\n\nT['pickers']['lsp()']['works for `references`'] = function()\n  local file_path, file_path_full = setup_lsp()\n\n  mock_slash_path_sep()\n  pick_lsp({ scope = 'references' })\n  validate_picker_name('LSP (references)')\n  eq(child.lua_get('_G.lsp_requests'), { 'textDocument/references' })\n  child.expect_screenshot()\n\n  -- Should preview position\n  type_keys('<C-n>', '<Tab>')\n  child.expect_screenshot()\n  unmock_slash_path_sep()\n\n  -- Should have proper items\n  local ref_item = {\n    filename = file_path_full,\n    path = file_path_full,\n    lnum = 3,\n    col = 16,\n    end_lnum = 3,\n    end_col = 17,\n    text = file_path:gsub('\\\\', '/') .. '│3│16│   x = math.max(a, 2),',\n    user_data = {\n      uri = 'file://' .. (helpers.is_windows() and '/' or '') .. file_path_full:gsub('\\\\', '/'),\n      range = { start = { line = 2, character = 15 }, ['end'] = { line = 2, character = 16 } },\n    },\n  }\n  if child.fn.has('nvim-0.11') == 0 then\n    ref_item.end_lnum, ref_item.end_col = nil, nil\n  end\n  if child.fn.has('nvim-0.10') == 0 then ref_item.user_data = nil end\n  eq(get_picker_items()[2], ref_item)\n\n  -- Should properly choose by moving to the position\n  type_keys('<CR>')\n  validate_buf_name(0, file_path)\n  eq(get_cursor(), { 3, 15 })\nend\n\nT['pickers']['lsp()']['works for `type_definition`'] = function() validate_location_scope('type_definition') end\n\nT['pickers']['lsp()']['works for `workspace_symbol`'] = function() validate_symbol_scope('workspace_symbol') end\n\nT['pickers']['lsp()'][\"works for `workspace_symbol` with 'mini.icons' set up\"] = function()\n  child.lua(\"require('mini.icons').setup()\")\n  validate_symbol_scope('workspace_symbol')\nend\n\nT['pickers']['lsp()']['works for `workspace_symbol` after `MiniIcons.tweak_lsp_kind()`'] = function()\n  validate_symbol_scope_with_tweaked_kind('workspace_symbol', 'prepend')\n  validate_symbol_scope_with_tweaked_kind('workspace_symbol', 'append')\n  validate_symbol_scope_with_tweaked_kind('workspace_symbol', 'replace')\nend\n\nT['pickers']['lsp()']['works for `workspace_symbol_live`'] = function()\n  setup_lsp()\n  mock_slash_path_sep()\n\n  -- Test only \"live\" part in the hope that \"workspace_symbol\" part is the same\n  local validate = function(n_requests, query)\n    local ref_requests, lsp_method = {}, scope_to_request.workspace_symbol_live\n    for i = 1, n_requests do\n      ref_requests[i] = lsp_method\n    end\n    eq(child.lua_get('_G.lsp_requests'), ref_requests)\n    eq(child.lua_get('_G.params'), query ~= nil and { query = query } or vim.NIL)\n\n    child.lua('_G.lsp_requests, _G.params = {}, nil')\n  end\n\n  -- Should not do any request on start\n  pick_lsp({ scope = 'workspace_symbol_live' })\n  validate_picker_name('LSP (workspace_symbol_live)')\n  validate(0, nil)\n  eq(get_picker_items(), {})\n\n  -- Should make new request on every picker query change\n  type_keys('a')\n  validate(1, 'a')\n\n  type_keys('x')\n  validate(1, 'ax')\n\n  -- Should not make request for empty query and show no items instead\n  type_keys('<C-u>')\n  validate(0, nil)\n  eq(get_picker_items(), {})\nend\n\nT['pickers']['lsp()']['respects `local_opts.symbol_query`'] = function()\n  setup_lsp()\n\n  pick_lsp({ scope = 'workspace_symbol', symbol_query = 'aaa' })\n  eq(child.lua_get('_G.params.query'), 'aaa')\nend\n\nT['pickers']['lsp()']['respects `opts`'] = function()\n  setup_lsp()\n  pick_lsp({ scope = 'references' }, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['lsp()']['respects global source options'] = function()\n  setup_lsp()\n  validate_global_source_options(function() pick_lsp({ scope = 'document_symbol' }) end, true, false)\nend\n\nT['pickers']['lsp()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.lsp(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({}, '`pickers%.lsp` needs an explicit scope')\n  validate({ scope = '1' }, '`pickers%.lsp`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['manpages()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Mock `vim.loop.spawn` for `MiniPick.builtin.cli()`\n      mock_spawn()\n\n      -- Mock `:Man` command for robust testing\n      child.lua([[\n        _G.man_cmd_log = {}\n        local callback = function(cmd_data)\n          table.insert(_G.man_cmd_log, cmd_data)\n\n          -- Mock opening a manpage buffer in the same window\n          local name, section = cmd_data.fargs[2], cmd_data.fargs[1]\n          local buf_name = string.format('man://%s(%s)', name, section)\n          -- table.insert(_G.man_cmd_log, buf_name)\n          vim.cmd('noautocmd edit! ' .. vim.fn.fnameescape(buf_name))\n\n          local lines = { string.format('%s (%s) - Manual Page', name, section) }\n          vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)\n          vim.bo.modified = false\n\n          vim.bo.filetype = 'man'\n        end\n\n        local opts = { addr = 'other', bang = true, bar = true, nargs = '*', range = true }\n        vim.api.nvim_create_user_command('Man', callback, opts)\n      ]])\n    end,\n  },\n})\n\nlocal pick_manpages = forward_lua_notify('MiniExtra.pickers.manpages')\n\nlocal mock_man_list = function()\n  mock_cli_return({\n    -- \"Regular\" output\n    'st (1)               - simple terminal',\n    'IO::Socket::IP (3perl) - Family-neutral IP socket supporting both IPv4 and IPv6',\n\n    -- \"Exotic\" output (like Void Linux, OpenBSD)\n    -- - Several commands separated by comma\n    'alacritty, Alacritty (1) - A fast, cross-platform, OpenGL terminal emulator.',\n    -- - Several sections separated by comma\n    'afterstep_faq (1, 2)',\n    -- - No space before `(section)`\n    'alacritty-msg(1) - Send messages to Alacritty.',\n    -- - Unexpected characters in `(section)`\n    'amd64_iopl(2/amd64)',\n  })\nend\n\nT['pickers']['manpages()']['works'] = function()\n  child.set_size(20, 70)\n  mock_man_list()\n\n  -- Should compute items with `man -k .` system call\n  child.fn.setenv('PATH', '/home,/home/user')\n  child.fn.setenv('MANPATH', '/home,/home/manpage')\n  child.lua_notify('_G.return_item = MiniExtra.pickers.manpages()')\n  validate_picker_name('Manpages')\n  child.expect_screenshot()\n\n  local cwd = child.fn.getcwd()\n  local spawn_env = { 'MANWIDTH=999', 'PATH=/home,/home/user', 'MANPATH=/home,/home/manpage' }\n  eq(get_spawn_log(), { { executable = 'man', options = { args = { '-k', '.' }, cwd = cwd, env = spawn_env } } })\n  clear_spawn_log()\n  clear_process_log()\n\n  -- Should use `:Man` to preview and choose manpage\n  local preview_win_id = child.lua_get('MiniPick.get_picker_state().windows.main')\n\n  local buf_scope = child.fn.has('nvim-0.11') == 1 and 'local' or nil\n  local get_buf_option = function(buf_id, name)\n    return child.api.nvim_get_option_value(name, { scope = buf_scope, buf = buf_id })\n  end\n\n  local validate_preview = function(ref_man_args)\n    local man_cmd_log = child.lua_get('_G.man_cmd_log')\n    eq(#man_cmd_log, 1)\n    eq(man_cmd_log[1].args, ref_man_args)\n    eq(man_cmd_log[1].mods, 'hide')\n    child.lua('_G.man_cmd_log = {}')\n    child.lua('_G.log = {}')\n\n    -- Should force non-listed temporary buffer\n    local buf_id = child.api.nvim_win_get_buf(preview_win_id)\n    eq(get_buf_option(buf_id, 'buflisted'), false)\n    eq(get_buf_option(buf_id, 'bufhidden'), 'wipe')\n  end\n\n  type_keys('<Tab>')\n\n  -- - Should use syntax `man <section> <command>`\n  validate_preview('1 st')\n  child.expect_screenshot()\n\n  -- - Should extract valid section value (see `:Man man`)\n  type_keys('<C-n>')\n  validate_preview('3perl IO::Socket::IP')\n\n  -- - Should use first command if there are several\n  type_keys('<C-n>')\n  validate_preview('1 alacritty')\n\n  -- - Should use first section if there are several\n  type_keys('<C-n>')\n  validate_preview('1 afterstep_faq')\n\n  -- - Should handle no space before `(section)`\n  type_keys('<C-n>')\n  validate_preview('1 alacritty-msg')\n\n  -- - Should handle non-digits in `(section)`\n  type_keys('<C-n>')\n  validate_preview('2 amd64_iopl')\n\n  -- Should properly choose by showing manpage in target window (not split)\n  type_keys('<CR>')\n  child.expect_screenshot()\n  validate_buf_name(0, 'man://amd64_iopl(2)')\n  -- - Should not preserve `buflisted=false` from preview\n  eq(get_buf_option(0, 'buflisted'), true)\n\n  local man_cmd_log = child.lua_get('_G.man_cmd_log')\n  eq(#man_cmd_log, 1)\n  eq(man_cmd_log[1].args, '2 amd64_iopl')\n  eq(man_cmd_log[1].mods, 'hide')\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), 'amd64_iopl(2/amd64)')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  mock_man_list()\n  pick_manpages()\n  validate_active_picker()\nend\n\nT['pickers']['manpages()']['can choose in split'] = function()\n  mock_man_list()\n  pick_manpages()\n  type_keys('<C-v>')\n  child.expect_screenshot()\nend\n\nT['pickers']['manpages()']['respects `opts`'] = function()\n  pick_manpages({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['manpages()']['respects global source options'] = function()\n  validate_global_source_options(pick_manpages, false, false)\nend\n\nT['pickers']['manpages()']['validates `:Man` dependency'] = function()\n  child.api.nvim_del_user_command('Man')\n  expect.error(function() child.lua('MiniExtra.pickers.manpages()') end, '`manpages` picker needs `:Man` command')\nend\n\nT['pickers']['marks()'] = new_set()\n\nlocal pick_marks = forward_lua_notify('MiniExtra.pickers.marks')\n\nlocal setup_marks = function()\n  child.cmd('edit ' .. real_file('a.lua'))\n  local buf_file = child.api.nvim_get_current_buf()\n  set_cursor(1, 5)\n  type_keys('mA')\n  set_cursor(1, 0)\n\n  local buf_main = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_main)\n  set_lines({ 'Line 1-1', 'Line 1-2', 'Line 1-3' })\n  set_cursor(1, 3)\n  type_keys('ma')\n  set_cursor(3, 5)\n  type_keys('mb')\n  set_cursor(1, 0)\n\n  local buf_alt = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_alt)\n  set_lines({ 'Line 2-1', 'Line 2-2', 'line 2-3' })\n  set_cursor(2, 2)\n  type_keys('ma')\n  set_cursor(1, 0)\n\n  child.api.nvim_set_current_buf(buf_main)\n\n  return { main = buf_main, alt = buf_alt, file = buf_file }\nend\n\nT['pickers']['marks()']['works'] = function()\n  child.set_size(20, 70)\n  setup_marks()\n\n  mock_slash_path_sep()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.marks()')\n  validate_picker_name('Marks (all)')\n  child.expect_screenshot()\n\n  -- Should preview mark's position\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-n>')\n  child.expect_screenshot()\n  type_keys('<C-n>', '<C-n>', '<C-n>', '<C-n>')\n  child.expect_screenshot()\n  unmock_slash_path_sep()\n\n  -- Should properly choose by positioning on mark\n  local path = real_file('a.lua')\n  type_keys('<CR>')\n  validate_buf_name(0, path)\n  eq(get_cursor(), { 1, 5 })\n\n  -- Should return chosen value\n  local path_slash = path:gsub('\\\\', '/')\n  local ref_item = { col = 6, lnum = 1, path = path_slash, text = 'A │ ' .. path_slash .. '│1│6' }\n  eq(child.lua_get('_G.return_item'), ref_item)\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_marks()\n  validate_active_picker()\nend\n\nT['pickers']['marks()']['respects `local_opts.scope`'] = function()\n  local buffers = setup_marks()\n  child.set_size(15, 40)\n\n  mock_slash_path_sep()\n  pick_marks({ scope = 'global' })\n  child.expect_screenshot()\n  stop_picker()\n\n  pick_marks({ scope = 'buf' })\n  validate_picker_name('Marks (buf)')\n  child.expect_screenshot()\n  stop_picker()\n\n  child.api.nvim_set_current_buf(buffers.alt)\n  pick_marks({ scope = 'buf' })\n  child.expect_screenshot()\n  stop_picker()\nend\n\nT['pickers']['marks()']['respects `opts`'] = function()\n  pick_marks({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['marks()']['respects global source options'] = function()\n  setup_marks()\n  validate_global_source_options(pick_marks, true, true)\nend\n\nT['pickers']['marks()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.marks(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ scope = '1' }, '`pickers%.marks`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['oldfiles()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(10, 70)\n      mock_slash_path_sep()\n    end,\n  },\n})\n\nlocal pick_oldfiles = forward_lua_notify('MiniExtra.pickers.oldfiles')\n\nT['pickers']['oldfiles()']['works'] = function()\n  local path_1, path_2 = real_file('LICENSE'), make_testpath('mocks', 'diagnostic.lua')\n  local ref_oldfiles = { full_path(path_1), full_path(path_2), 'not-existing' }\n  child.v.oldfiles = ref_oldfiles\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.oldfiles()')\n  validate_picker_name('Old files')\n  child.expect_screenshot()\n  unmock_slash_path_sep()\n\n  -- Should have proper items (only readable files with short paths)\n  local path_1_slash, path_2_slash = (path_1:gsub('\\\\', '/')), (path_2:gsub('\\\\', '/'))\n  eq(get_picker_items(), { path_1_slash, path_2_slash })\n\n  -- Should properly choose\n  type_keys('<CR>')\n  validate_buf_name(0, path_1)\n  eq(get_cursor(), { 1, 0 })\n\n  --stylua: ignore\n  -- Should return chosen value with proper structure\n  eq(child.lua_get('_G.return_item'), path_1_slash)\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_oldfiles()\n  validate_active_picker()\nend\n\nT['pickers']['oldfiles()']['works with empty `v:oldfiles`'] = function()\n  child.v.oldfiles = {}\n  pick_oldfiles()\n  eq(get_picker_items(), {})\nend\n\nT['pickers']['oldfiles()']['can not show icons'] = function()\n  child.set_size(10, 70)\n  local ref_oldfiles = { full_path(real_file('LICENSE')), full_path(make_testpath('mocks', 'diagnostic.lua')) }\n  child.v.oldfiles = ref_oldfiles\n\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  pick_oldfiles()\n  child.expect_screenshot()\nend\n\nT['pickers']['oldfiles()']['respects `local_opts.current_dir'] = function()\n  child.set_size(10, 70)\n  local ref_oldfiles = { full_path(real_file('LICENSE')), full_path(make_testpath('mocks', 'diagnostic.lua')) }\n  child.v.oldfiles = ref_oldfiles\n\n  child.fn.chdir(real_files_dir)\n  pick_oldfiles({ current_dir = true })\n  local items = get_picker_items()\n  -- - Only paths inside current directory are shown\n  eq(#items, 1)\n  eq(items[1], 'LICENSE')\nend\n\nT['pickers']['oldfiles()']['respects `local_opts.preserve_order`'] = function()\n  child.lua('vim.fn.filereadable = function() return 1 end')\n  child.v.oldfiles = { 'axay', 'b', 'aaxy', 'ccc', 'xaa' }\n  pick_oldfiles({ preserve_order = true })\n\n  type_keys('x')\n  eq(get_picker_matches().all_inds, { 1, 3, 5 })\n  type_keys('y')\n  eq(get_picker_matches().all_inds, { 1, 3 })\nend\n\nT['pickers']['oldfiles()']['respects `opts`'] = function()\n  pick_oldfiles({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['oldfiles()']['respects global source options'] = function()\n  local path_1, path_2 = real_file('LICENSE'), make_testpath('mocks', 'diagnostic.lua')\n  local ref_oldfiles = { full_path(path_1), full_path(path_2), 'not-existing' }\n  child.v.oldfiles = ref_oldfiles\n  validate_global_source_options(pick_oldfiles, true, true)\nend\n\nT['pickers']['oldfiles()']['respects `opts.source.cwd`'] = function()\n  child.set_size(10, 70)\n  local ref_oldfiles = { full_path(real_file('LICENSE')), full_path(make_testpath('mocks', 'diagnostic.lua')) }\n  child.v.oldfiles = ref_oldfiles\n\n  pick_oldfiles({}, { source = { cwd = real_files_dir } })\n  local items = get_picker_items()\n  eq(items[1], 'LICENSE')\n  -- - For paths not from `cwd` it should shorten home directory to `~`\n  expect.match(items[2], vim.pesc(child.fn.fnamemodify(ref_oldfiles[2], ':~')))\nend\n\nT['pickers']['options()'] = new_set()\n\nlocal pick_options = forward_lua_notify('MiniExtra.pickers.options')\n\nT['pickers']['options()']['works'] = function()\n  child.set_size(35, 60)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.options()')\n  validate_picker_name('Options (all)')\n  type_keys('^cursor')\n  child.expect_screenshot({ ignore_text = { 34 } })\n\n  -- Should have proper preview\n  type_keys('<Tab>')\n  child.expect_screenshot({ ignore_text = { 34 } })\n\n  -- - Should use proper highlight group for headers\n  validate_partial_equal_arr(get_extra_picker_extmarks(0, -1), {\n    { row = 0, col = 0, hl_group = 'MiniPickHeader' },\n    { row = 3, col = 0, hl_group = 'MiniPickHeader' },\n  })\n\n  -- Should properly choose\n  type_keys('<CR>')\n  eq(child.fn.getcmdline(), 'set cursorbind')\n  eq(child.fn.getcmdpos(), 15)\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), { text = 'cursorbind', info = child.api.nvim_get_option_info2('cursorbind', {}) })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_options()\n  validate_active_picker()\nend\n\nT['pickers']['options()']['respects set options'] = function()\n  child.set_size(10, 40)\n  child.o.cursorline = true\n  child.wo.cursorcolumn = true\n  child.bo.commentstring = '### %s'\n\n  pick_options()\n  type_keys('^cursor')\n  child.expect_screenshot()\n\n  -- Should highlight not set options as dimmed\n  validate_partial_equal_arr(get_extra_picker_extmarks(0, -1), {\n    { row = 0, col = 0, hl_group = 'Comment' },\n    { row = 3, col = 0, hl_group = 'Comment' },\n  })\n\n  -- Should show valid present value (in the scope of target) window in preview\n  -- - Window local option\n  type_keys('<C-n>', '<Tab>')\n  child.expect_screenshot()\n\n  -- Buffer-local option\n  type_keys('<C-u>', '^commentstring', '<Tab>')\n  child.expect_screenshot()\nend\n\nT['pickers']['options()']['correctly chooses non-binary options'] = function()\n  pick_options()\n  type_keys('^laststatus', '<CR>')\n  eq(child.fn.getcmdline(), 'set laststatus=')\n  eq(child.fn.getcmdpos(), 16)\nend\n\nT['pickers']['options()']['correctly previews deprecated options'] = function()\n  -- There shouldn't be \"deprecated\" options listed after Neovim 0.11 refactors\n  if child.fn.has('nvim-0.11') == 1 then return end\n  child.set_size(10, 115)\n  pick_options()\n  type_keys('^aleph', '<Tab>')\n  child.expect_screenshot({ ignore_text = { 9 } })\nend\n\nT['pickers']['options()']['respects `local_opts.scope`'] = function()\n  local validate = function(scope)\n    pick_options({ scope = scope })\n    validate_picker_name('Options (' .. scope .. ')')\n\n    if scope == 'all' then return stop_picker() end\n\n    -- Validate proper set of options\n    local is_010 = child.fn.has('nvim-0.10') == 1 and child.fn.has('nvim-0.11') == 0\n    for _, item in ipairs(get_picker_items()) do\n      -- Neovim=0.10 has `nvim_get_option_info2()` throwing error for options\n      -- that are obsolete (like 'aleph').\n      -- It doesn't happen on Neovim=0.9 or Neovim>=0.11.\n      local ok, item_info = pcall(child.api.nvim_get_option_info2, item.text, {})\n      local item_scope = (not ok and is_010) and scope or item_info.scope\n      eq(item_scope, scope)\n    end\n\n    stop_picker()\n  end\n\n  validate('all')\n  validate('global')\n  validate('win')\n  validate('buf')\nend\n\nT['pickers']['options()']['respects `opts`'] = function()\n  pick_options({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['options()']['respects global source options'] = function()\n  validate_global_source_options(pick_options, false, false)\nend\n\nT['pickers']['options()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.options(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ scope = '1' }, '`pickers%.options`.*\"scope\".*\"1\".*one of')\nend\n\nT['pickers']['registers()'] = new_set()\n\nlocal pick_registers = forward_lua_notify('MiniExtra.pickers.registers')\n\nlocal setup_registers = function()\n  child.fn.setreg('a', 'Register a')\n  child.fn.setreg('=', '1 + 1')\n  set_lines({ 'Yank register', 'Contains multiline text' })\n  type_keys('yj')\n  set_lines({})\nend\n\nT['pickers']['registers()']['works'] = function()\n  child.set_size(80, 40)\n  setup_registers()\n\n  -- Mock constant clipboard for better reproducibility of system registers\n  -- (mostly on CI). As `setreg('+', '')` is not guaranteed to be working for\n  -- system clipboard, use `g:clipboard` which copies/pastes nothing.\n  child.lua([[\n    local empty = function() return '' end\n    vim.g.clipboard = {\n      name  = 'myClipboard',\n      copy  = { ['+'] = empty, ['*'] = empty },\n      paste = { ['+'] = empty, ['*'] = empty },\n    }\n  ]])\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.registers()')\n  validate_picker_name('Registers')\n  child.expect_screenshot()\n\n  -- Should preview register content (even multiline)\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose pasting register contents\n  type_keys('^a', '<CR>')\n  eq(get_lines(), { 'Register a' })\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), { regname = 'a', regcontents = 'Register a', text = 'a │ Register a' })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_registers()\n  validate_active_picker()\nend\n\nT['pickers']['registers()']['can be chosen in non-Normal modes'] = function()\n  setup_registers()\n  local pick_reg_a = function()\n    pick_registers()\n    type_keys('^a', '<CR>')\n  end\n\n  -- -- Doesn't really work in Visual mode because 'mini.pick' doesn't\n  -- type_keys('i', 'toremove', '<Esc>', 'viw')\n  -- pick_reg_a()\n  -- eq(is_picker_active(), false)\n  -- eq(get_lines(), { 'Register a' })\n  -- eq(child.fn.mode(), 'v')\n  -- child.ensure_normal_mode()\n  -- set_lines({})\n\n  -- Insert mode\n  type_keys('i')\n  pick_reg_a()\n  eq(is_picker_active(), false)\n  eq(get_lines(), { 'Register a' })\n  eq(child.fn.mode(), 'i')\n  child.ensure_normal_mode()\n  set_lines({})\n\n  -- Command-line mode\n  type_keys(':')\n  pick_reg_a()\n  eq(is_picker_active(), false)\n  eq(child.fn.mode(), 'c')\n  eq(child.fn.getcmdline(), 'Register a')\n  eq(child.fn.getcmdpos(), 11)\n  child.ensure_normal_mode()\n  set_lines({})\nend\n\nT['pickers']['registers()']['works with expression register'] = function()\n  setup_registers()\n  local pick_expr_reg = function()\n    pick_registers()\n    type_keys('^=', '<CR>')\n  end\n\n  -- Should reevaluate and paste\n  -- - Normal mode\n  pick_expr_reg()\n  eq(get_lines(), { '2' })\n  eq(child.fn.mode(), 'n')\n  set_lines({})\n\n  -- - Insert mode\n  type_keys('i')\n  pick_expr_reg()\n  eq(get_lines(), { '2' })\n  eq(child.fn.mode(), 'i')\n  child.ensure_normal_mode()\n  set_lines({})\n\n  -- - Command-line mode\n  type_keys(':')\n  pick_expr_reg()\n  eq(child.fn.mode(), 'c')\n  eq(child.fn.getcmdline(), '2')\n  eq(child.fn.getcmdpos(), 2)\n  child.ensure_normal_mode()\n  set_lines({})\nend\n\nT['pickers']['registers()']['respects `opts`'] = function()\n  pick_registers({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['registers()']['respects global source options'] = function()\n  setup_registers()\n  validate_global_source_options(pick_registers, false, false)\nend\n\nT['pickers']['spellsuggest()'] = new_set()\n\nlocal pick_spellsuggest = forward_lua_notify('MiniExtra.pickers.spellsuggest')\n\nlocal setup_spell = function()\n  set_lines({ 'hello wold' })\n  set_cursor(1, 8)\nend\n\nT['pickers']['spellsuggest()']['works'] = function()\n  child.set_size(15, 70)\n\n  setup_spell()\n  child.lua_notify('_G.return_item = MiniExtra.pickers.spellsuggest()')\n  validate_picker_name('Spell suggestions for \"wold\"')\n  eq(#get_picker_items(), 25)\n  child.expect_screenshot()\n\n  -- Should have no preview\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose by replacing suggestion\n  type_keys('<CR>')\n  eq(get_lines(), { 'hello world' })\n  eq(get_cursor(), { 1, 6 })\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), { index = 1, text = 'world' })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_spellsuggest()\n  validate_active_picker()\nend\n\nT['pickers']['spellsuggest()']['respects `local_opts.n_suggestions`'] = function()\n  setup_spell()\n  pick_spellsuggest({ n_suggestions = 10 })\n  eq(#get_picker_items(), 10)\nend\n\nT['pickers']['spellsuggest()']['respects `opts`'] = function()\n  setup_spell()\n  pick_spellsuggest({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['spellsuggest()']['respects global source options'] = function()\n  setup_spell()\n  validate_global_source_options(pick_spellsuggest, false, false)\nend\n\nT['pickers']['spellsuggest()']['validates arguments'] = function()\n  local validate = function(local_opts, error_pattern)\n    expect.error(function() child.lua('MiniExtra.pickers.spellsuggest(...)', { local_opts }) end, error_pattern)\n  end\n\n  validate({ n_suggestions = '1' }, '`local_opts%.n_suggestions.*number')\n  validate({ n_suggestions = 0 }, '`local_opts%.n_suggestions.*positive')\nend\n\nT['pickers']['treesitter()'] = new_set()\n\nlocal pick_treesitter = forward_lua_notify('MiniExtra.pickers.treesitter')\n\nlocal setup_treesitter = function()\n  local path = real_file('a.lua')\n  child.cmd('edit ' .. path)\n  child.lua('vim.treesitter.start()')\n  sleep(small_time)\n\n  return path\nend\n\nT['pickers']['treesitter()']['works'] = function()\n  child.set_size(52, 70)\n  local path = setup_treesitter()\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.treesitter()')\n  validate_picker_name('Tree-sitter nodes')\n  child.expect_screenshot()\n\n  -- Should preview node's region\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-n>')\n  child.expect_screenshot()\n\n  -- Should properly choose by positioning on region start\n  type_keys('<CR>')\n  validate_buf_name(0, path)\n  eq(get_cursor(), { 1, 6 })\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), {\n    bufnr = child.api.nvim_get_current_buf(),\n    col = 7,\n    end_col = 12,\n    end_lnum = 1,\n    lnum = 1,\n    text = ' assignment_statement (1│7 - 1│12)',\n  })\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_treesitter()\n  validate_active_picker()\nend\n\nT['pickers']['treesitter()']['checks for active tree-sitter'] = function()\n  expect.error(function() child.lua('MiniExtra.pickers.treesitter()') end, '`pickers%.treesitter`.*parser')\nend\n\nT['pickers']['treesitter()']['respects `opts`'] = function()\n  setup_treesitter()\n  pick_treesitter({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['treesitter()']['respects global source options'] = function()\n  setup_treesitter()\n  validate_global_source_options(pick_treesitter, true, true)\nend\n\nlocal setup_visits = function()\n  -- NOTE: 'mini.visits' uses forward slashes in index\n  local dir = test_dir_absolute:gsub('\\\\', '/')\n  local path_1 = full_path(make_testpath('git-files', 'git-file-1')):gsub('\\\\', '/')\n  local path_2 = full_path(make_testpath('git-files', 'git-file-2')):gsub('\\\\', '/')\n  local visit_index = {\n    [dir] = {\n      [dir .. '/file-xyyx'] = { count = 5, latest = 5 },\n      [dir .. '/file-xx'] = { count = 1, labels = { xxx = true, uuu = true }, latest = 10 },\n      [dir .. '/file-xyx'] = { count = 10, labels = { xxx = true }, latest = 2 },\n      [dir .. '/real-files/a.lua'] = { count = 3, labels = { yyy = true }, latest = 3 },\n    },\n    [dir .. '/git-files'] = {\n      [path_1] = { count = 0, labels = { xxx = true, www = true }, latest = 0 },\n      [path_2] = { count = 100, latest = 100 },\n    },\n  }\n\n  child.lua([[require('mini.visits').set_index(...)]], { visit_index })\n  child.fn.chdir(dir)\nend\n\nT['pickers']['visit_paths()'] = new_set({ hooks = { pre_case = setup_visits } })\n\nlocal pick_visit_paths = forward_lua_notify('MiniExtra.pickers.visit_paths')\n\nT['pickers']['visit_paths()']['works'] = function()\n  child.set_size(15, 60)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.visit_paths()')\n  validate_picker_name('Visit paths (cwd)')\n  child.expect_screenshot()\n\n  -- Can preview path\n  type_keys('<C-p>', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose\n  type_keys('<CR>')\n  validate_buf_name(0, join_path('real-files', 'a.lua'))\n\n  -- Should return chosen value\n  eq(child.lua_get('_G.return_item'), 'real-files/a.lua')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_visit_paths()\n  validate_active_picker()\nend\n\nT['pickers']['visit_paths()']['respects `local_opts.cwd`'] = function()\n  pick_visit_paths({ cwd = '' })\n  validate_picker_name('Visit paths (all)')\n  eq(get_picker_items(), {\n    -- Should use short paths relative to the current working directory\n    'git-files/git-file-2',\n    'file-xyyx',\n    'file-xx',\n    'file-xyx',\n    'real-files/a.lua',\n    'git-files/git-file-1',\n  })\nend\n\nT['pickers']['visit_paths()']['respects `local_opts.filter`'] = function()\n  pick_visit_paths({ filter = 'xxx' })\n  eq(get_picker_items(), { 'file-xx', 'file-xyx' })\nend\n\nT['pickers']['visit_paths()']['respects `local_opts.preserve_order`'] = function()\n  -- Should not preserve original sort by default\n  pick_visit_paths()\n  type_keys('x', 'x')\n  eq(get_picker_matches().all, { 'file-xx', 'file-xyx', 'file-xyyx' })\n  type_keys('<Esc>')\n\n  -- Should preserve original order with `preserve_order`\n  pick_visit_paths({ preserve_order = true })\n  type_keys('x', 'x')\n  eq(get_picker_matches().all, { 'file-xyyx', 'file-xx', 'file-xyx' })\n  type_keys('<Esc>')\nend\n\nT['pickers']['visit_paths()']['respects `local_opts.recency_weight`'] = function()\n  pick_visit_paths({ recency_weight = 1 })\n  eq(get_picker_items(), { 'file-xx', 'file-xyyx', 'real-files/a.lua', 'file-xyx' })\nend\n\nT['pickers']['visit_paths()']['respects `local_opts.sort`'] = function()\n  child.lua([[_G.sort = function() return { { path = vim.fn.getcwd():gsub('\\\\', '/') .. '/aaa' } } end]])\n  child.lua_notify([[MiniExtra.pickers.visit_paths({ sort = _G.sort })]])\n  eq(get_picker_items(), { 'aaa' })\nend\n\nT['pickers']['visit_paths()']['can not show icons'] = function()\n  child.set_size(15, 60)\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  pick_visit_paths()\n  child.expect_screenshot()\nend\n\nT['pickers']['visit_paths()']['respects `opts`'] = function()\n  pick_visit_paths({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['visit_paths()']['respects global source options'] = function()\n  setup_visits()\n  validate_global_source_options(pick_visit_paths, true, true)\nend\n\nT['pickers']['visit_paths()'][\"checks for present 'mini.visits'\"] = function()\n  child.lua([[\n    local require_orig = require\n    require = function(x)\n      if x == 'mini.visits' then error() end\n      require_orig(x)\n    end\n  ]])\n  expect.error(function() child.lua('MiniExtra.pickers.visit_paths()') end, '`pickers%.visit_paths`.*mini%.visits')\nend\n\nT['pickers']['visit_labels()'] = new_set({ hooks = { pre_case = setup_visits } })\n\nlocal pick_visit_labels = forward_lua_notify('MiniExtra.pickers.visit_labels')\n\nT['pickers']['visit_labels()']['works'] = function()\n  child.set_size(15, 60)\n\n  child.lua_notify('_G.return_item = MiniExtra.pickers.visit_labels()')\n  validate_picker_name('Visit labels (cwd)')\n  child.expect_screenshot()\n\n  -- Can preview label by showing paths with it\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- Should properly choose by starting picking from label paths\n  type_keys('<C-p>', '<CR>')\n  child.expect_screenshot()\n\n  -- Should properly choose path\n  type_keys('<CR>')\n  validate_buf_name(0, join_path('real-files', 'a.lua'))\n\n  -- Should return chosen path\n  eq(child.lua_get('_G.return_item'), 'real-files/a.lua')\n\n  -- Should work without set up 'mini.pick'\n  child.mini_unload('pick')\n  pick_visit_labels()\n  validate_active_picker()\nend\n\nT['pickers']['visit_labels()']['respects `local_opts.cwd`'] = function()\n  pick_visit_labels({ cwd = '' })\n  validate_picker_name('Visit labels (all)')\n  eq(get_picker_items(), { 'xxx', 'uuu', 'www', 'yyy' })\nend\n\nT['pickers']['visit_labels()']['respects `local_opts.filter`'] = function()\n  child.lua([[_G.filter = function(path_data) return string.find(path_data.path, 'xx') ~= nil end]])\n  child.lua_notify('MiniExtra.pickers.visit_labels({ filter = _G.filter })')\n  eq(get_picker_items(), { 'uuu', 'xxx' })\nend\n\nT['pickers']['visit_labels()']['respects `local_opts.path`'] = function()\n  pick_visit_labels({ path = full_path(join_path('real-files', 'a.lua')) })\n  eq(get_picker_items(), { 'yyy' })\nend\n\nT['pickers']['visit_labels()']['respects `local_opts.sort`'] = function()\n  child.set_size(15, 60)\n  child.lua([[_G.sort = function() return { { path = vim.fn.getcwd():gsub('\\\\', '/') .. '/aaa' } } end]])\n  child.lua_notify([[MiniExtra.pickers.visit_labels({ sort = _G.sort })]])\n  eq(get_picker_items(), { 'xxx', 'uuu', 'yyy' })\n\n  -- Sorting should affect both preview and after choosing\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  type_keys('<CR>')\n  eq(get_picker_items(), { 'aaa' })\nend\n\nT['pickers']['visit_labels()']['can not show icons after choosing'] = function()\n  child.set_size(15, 60)\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  pick_visit_labels()\n  type_keys('<CR>')\n  child.expect_screenshot()\nend\n\nT['pickers']['visit_labels()']['respects `opts`'] = function()\n  pick_visit_labels({}, { source = { name = 'My name' } })\n  validate_picker_name('My name')\nend\n\nT['pickers']['visit_labels()']['respects global source options'] = function()\n  setup_visits()\n  validate_global_source_options(pick_visit_labels, false, false)\nend\n\nT['pickers']['visit_labels()'][\"checks for present 'mini.visits'\"] = function()\n  child.lua([[\n    local require_orig = require\n    require = function(x)\n      if x == 'mini.visits' then error() end\n      require_orig(x)\n    end\n  ]])\n  expect.error(function() child.lua('MiniExtra.pickers.visit_labels()') end, '`pickers%.visit_labels`.*mini%.visits')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_files.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('files', config) end\nlocal unload_module = function() child.mini_unload('files') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Test paths helpers\nlocal test_dir = 'tests/dir-files'\n\nlocal normalize_path = function(p) return (p:gsub('\\\\', '/'):gsub('(.)/$', '%1')) end\nif helpers.is_windows() then\n  normalize_path = function(p) return (p:gsub('\\\\', '/'):gsub('(.)/$', '%1'):gsub('^(%a):/+([^/])', '%1://%2')) end\nend\n\nlocal join_path = function(...) return table.concat({ ... }, '/') end\nlocal full_path = function(...) return normalize_path(vim.fn.fnamemodify(join_path(...), ':p')) end\nlocal short_path = function(...) return normalize_path(vim.fn.fnamemodify(join_path(...), ':~')) end\n\nlocal make_test_path = function(...) return full_path(join_path(test_dir, ...)) end\n\nlocal make_temp_dir = function(name, children)\n  -- Make temporary directory and make sure it is removed after test is done\n  local temp_dir = make_test_path(name or 'temp')\n  vim.fn.mkdir(temp_dir, 'p')\n\n  MiniTest.finally(function() vim.fn.delete(temp_dir, 'rf') end)\n\n  -- Create children\n  for _, path in ipairs(children) do\n    local path_ext = temp_dir .. '/' .. path\n    if vim.endswith(path, '/') then\n      vim.fn.mkdir(path_ext)\n    else\n      vim.fn.writefile({}, path_ext)\n    end\n  end\n\n  return temp_dir\nend\n\n-- Common validators and helpers\nlocal validate_file_content = function(path, lines) eq(child.fn.readfile(path), lines) end\n\nlocal validate_tree = function(dir, ref_tree)\n  child.lua('_G.dir = ' .. vim.inspect(dir))\n  local tree = child.lua([[\n    local read_dir\n    read_dir = function(path, res)\n      res = res or {}\n      local fs = vim.loop.fs_scandir(path)\n      local name, fs_type = vim.loop.fs_scandir_next(fs)\n      while name do\n        local cur_path = path .. '/' .. name\n        table.insert(res, cur_path .. (fs_type == 'directory' and '/' or ''))\n        if fs_type == 'directory' then read_dir(cur_path, res) end\n        name, fs_type = vim.loop.fs_scandir_next(fs)\n      end\n      return res\n    end\n    local dir_len = _G.dir:len()\n    return vim.tbl_map(function(p) return p:sub(dir_len + 2) end, read_dir(_G.dir))\n  ]])\n  table.sort(tree)\n  local ref = vim.deepcopy(ref_tree)\n  table.sort(ref)\n  eq(tree, ref)\nend\n\nlocal validate_cur_line = function(x) eq(get_cursor()[1], x) end\n\nlocal is_explorer_active = function() return child.lua_get('MiniFiles.get_explorer_state() ~= nil') end\n\nlocal validate_n_wins = function(n) eq(#child.api.nvim_tabpage_list_wins(0), n) end\n\nlocal validate_fs_entry = function(x)\n  eq(type(x), 'table')\n  eq(x.fs_type == 'file' or x.fs_type == 'directory', true)\n  eq(type(x.name), 'string')\n  eq(type(x.path), 'string')\nend\n\nlocal validate_confirm_args = function(ref_msg_pattern, can_cancel)\n  if can_cancel == nil then can_cancel = true end\n  local args = child.lua_get('_G.confirm_args')\n  expect.match(args[1], ref_msg_pattern)\n  if args[2] ~= nil then eq(args[2], '&Yes\\n&No' .. (can_cancel and '\\n&Cancel' or '')) end\n  if args[3] ~= nil then eq(args[3], 1) end\n  if args[4] ~= nil then eq(args[4], 'Question') end\nend\n\nlocal make_plain_pattern = function(...) return table.concat(vim.tbl_map(vim.pesc, { ... }), '.*') end\n\nlocal is_file_in_buffer = function(buf_id, path)\n  local buf_name = normalize_path(child.api.nvim_buf_get_name(buf_id))\n  local path_pattern = vim.pesc(normalize_path(path)) .. '$'\n  return string.find(buf_name, path_pattern) ~= nil\nend\n\nlocal is_file_in_window = function(win_id, path) return is_file_in_buffer(child.api.nvim_win_get_buf(win_id), path) end\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal open = forward_lua('MiniFiles.open')\nlocal close = forward_lua('MiniFiles.close')\nlocal go_in = forward_lua('MiniFiles.go_in')\nlocal go_out = forward_lua('MiniFiles.go_out')\nlocal trim_left = forward_lua('MiniFiles.trim_left')\nlocal trim_right = forward_lua('MiniFiles.trim_right')\nlocal get_explorer_state = forward_lua('MiniFiles.get_explorer_state')\nlocal set_bookmark = forward_lua('MiniFiles.set_bookmark')\n\nlocal get_visible_paths = function()\n  return vim.tbl_map(function(x) return x.path end, get_explorer_state().windows)\nend\n\n-- Extmark helper\nlocal get_extmarks_hl = function()\n  local ns_id = child.api.nvim_get_namespaces()['MiniFilesHighlight']\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n  return vim.tbl_map(function(x) return x[4].hl_group end, extmarks)\nend\n\n-- Common mocks\nlocal mock_win_functions = function() child.cmd('source tests/dir-files/mock-win-functions.lua') end\n\nlocal mock_confirm = function(user_choice)\n  local lua_cmd = string.format(\n    [[vim.fn.confirm = function(...)\n        _G.confirm_args = { ... }\n        return %d\n      end]],\n    user_choice\n  )\n  child.lua(lua_cmd)\nend\n\nlocal mock_stdpath_data = function()\n  local data_dir = make_test_path('data')\n  local lua_cmd = string.format(\n    [[\n    _G.stdpath_orig = vim.fn.stpath\n    vim.fn.stdpath = function(what)\n      if what == 'data' then return %s end\n      return _G.stdpath_orig(what)\n    end]],\n    vim.inspect(data_dir)\n  )\n  child.lua(lua_cmd)\n  return data_dir\nend\n\n-- Data =======================================================================\nlocal test_dir_path = 'tests/dir-files/common'\nlocal test_file_path = 'tests/dir-files/common/a-file'\n\nlocal test_fs_entries = {\n  -- Intentionally in proper order\n  { fs_type = 'directory', name = '.a-dir', path = full_path('.a-dir') },\n  { fs_type = 'directory', name = 'a-dir', path = full_path('a-dir') },\n  { fs_type = 'directory', name = 'b-dir', path = full_path('b-dir') },\n  { fs_type = 'file', name = '.a-file', path = full_path('.a-file') },\n  { fs_type = 'file', name = 'a-file', path = full_path('a-file') },\n  { fs_type = 'file', name = 'A-file-2', path = full_path('A-file-2') },\n  { fs_type = 'file', name = 'b-file', path = full_path('b-file') },\n}\n\n-- Time constants\nlocal track_lost_focus_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      mock_win_functions()\n      child.set_size(15, 80)\n      load_module()\n\n      -- Mock `vim.notify()`\n      child.lua([[\n        _G.notify_log = {}\n        vim.notify = function(...) table.insert(_G.notify_log, { ... }) end\n      ]])\n\n      -- Make more robust screenshots\n      child.o.laststatus = 0\n      child.o.showtabline = 0\n\n      -- - Hide intro\n      child.cmd('vsplit')\n      child.cmd('quit')\n    end,\n    post_case = function() vim.fn.delete(make_test_path('data'), 'rf') end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniFiles)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniFiles'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local validate_hl_group = function(name, ref) expect.match(child.cmd_capture('hi ' .. name), ref) end\n\n  validate_hl_group('MiniFilesBorder', 'links to FloatBorder')\n  validate_hl_group('MiniFilesBorderModified', 'links to DiagnosticFloatingWarn')\n  validate_hl_group('MiniFilesCursorLine', 'links to CursorLine')\n  validate_hl_group('MiniFilesDirectory', 'links to Directory')\n  eq(child.fn.hlexists('MiniFilesFile'), 1)\n  validate_hl_group('MiniFilesNormal', 'links to NormalFloat')\n  validate_hl_group('MiniFilesTitle', 'links to FloatTitle')\n  validate_hl_group('MiniFilesTitleFocused', 'links to FloatTitle')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniFiles.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniFiles.config.' .. field), value) end\n\n  expect_config('content.filter', vim.NIL)\n  expect_config('content.highlight', vim.NIL)\n  expect_config('content.prefix', vim.NIL)\n  expect_config('content.sort', vim.NIL)\n\n  expect_config('mappings.close', 'q')\n  expect_config('mappings.go_in', 'l')\n  expect_config('mappings.go_in_plus', 'L')\n  expect_config('mappings.go_out', 'h')\n  expect_config('mappings.go_out_plus', 'H')\n  expect_config('mappings.reset', '<BS>')\n  expect_config('mappings.reveal_cwd', '@')\n  expect_config('mappings.show_help', 'g?')\n  expect_config('mappings.synchronize', '=')\n  expect_config('mappings.trim_left', '<')\n  expect_config('mappings.trim_right', '>')\n\n  expect_config('options.use_as_default_explorer', true)\n  expect_config('options.permanent_delete', true)\n\n  expect_config('windows.max_number', math.huge)\n  expect_config('windows.preview', false)\n  expect_config('windows.width_focus', 50)\n  expect_config('windows.width_nofocus', 15)\n  expect_config('windows.width_preview', 25)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ mappings = { close = 'gc' } })\n  eq(child.lua_get('MiniFiles.config.mappings.close'), 'gc')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ content = 'a' }, 'content', 'table')\n  expect_config_error({ content = { filter = 1 } }, 'content.filter', 'function')\n  expect_config_error({ content = { highlight = 1 } }, 'content.highlight', 'function')\n  expect_config_error({ content = { prefix = 1 } }, 'content.prefix', 'function')\n  expect_config_error({ content = { sort = 1 } }, 'content.sort', 'function')\n\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { close = 1 } }, 'mappings.close', 'string')\n  expect_config_error({ mappings = { go_in = 1 } }, 'mappings.go_in', 'string')\n  expect_config_error({ mappings = { go_in_plus = 1 } }, 'mappings.go_in_plus', 'string')\n  expect_config_error({ mappings = { go_out = 1 } }, 'mappings.go_out', 'string')\n  expect_config_error({ mappings = { go_out_plus = 1 } }, 'mappings.go_out_plus', 'string')\n  expect_config_error({ mappings = { reset = 1 } }, 'mappings.reset', 'string')\n  expect_config_error({ mappings = { reveal_cwd = 1 } }, 'mappings.reveal_cwd', 'string')\n  expect_config_error({ mappings = { show_help = 1 } }, 'mappings.show_help', 'string')\n  expect_config_error({ mappings = { synchronize = 1 } }, 'mappings.synchronize', 'string')\n  expect_config_error({ mappings = { trim_left = 1 } }, 'mappings.trim_left', 'string')\n  expect_config_error({ mappings = { trim_right = 1 } }, 'mappings.trim_right', 'string')\n\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { use_as_default_explorer = 1 } }, 'options.use_as_default_explorer', 'boolean')\n  expect_config_error({ options = { permanent_delete = 1 } }, 'options.permanent_delete', 'boolean')\n\n  expect_config_error({ windows = 'a' }, 'windows', 'table')\n  expect_config_error({ windows = { max_number = 'a' } }, 'windows.max_number', 'number')\n  expect_config_error({ windows = { preview = 1 } }, 'windows.preview', 'boolean')\n  expect_config_error({ windows = { width_focus = 'a' } }, 'windows.width_focus', 'number')\n  expect_config_error({ windows = { width_nofocus = 'a' } }, 'windows.width_nofocus', 'number')\n  expect_config_error({ windows = { width_preview = 'a' } }, 'windows.width_preview', 'number')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniFilesBorder'), 'links to FloatBorder')\nend\n\nT['open()'] = new_set()\n\nT['open()']['works with directory path'] = function()\n  -- Works with relative path\n  open(test_dir_path)\n  child.expect_screenshot()\n  close()\n  eq(is_explorer_active(), false)\n\n  -- Works with absolute path\n  open(vim.fn.fnamemodify(test_dir_path, ':p'))\n  child.expect_screenshot()\n  close()\n  eq(is_explorer_active(), false)\n\n  -- Works with trailing slash\n  open(test_dir_path .. '/')\n  child.expect_screenshot()\nend\n\nT['open()']['works with file path'] = function()\n  -- Works with relative path\n  open(test_file_path)\n  -- Should focus on file entry\n  child.expect_screenshot()\n  close()\n\n  -- Works with absolute path\n  open(vim.fn.fnamemodify(test_file_path, ':p'))\n  child.expect_screenshot()\nend\n\nT['open()']['works per tabpage'] = function()\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  child.cmd('tabedit')\n  open(test_dir_path .. '/a-dir')\n  child.expect_screenshot()\n\n  child.cmd('tabnext')\n  child.expect_screenshot()\nend\n\nT['open()']['handles problematic entry names'] = function()\n  local temp_dir = make_temp_dir('temp', { '%a bad-file-name', 'a bad-dir.name/' })\n\n  open(temp_dir)\n  child.expect_screenshot()\nend\n\nT['open()']['handles backslash on Unix'] = function()\n  if child.lua_get('vim.loop.os_uname().sysname') == 'Windows_NT' then MiniTest.skip('Test is not for Windows.') end\n\n  local temp_dir = make_temp_dir('temp', { '\\\\', 'hello\\\\', 'wo\\\\rld' })\n  open(temp_dir)\n  child.expect_screenshot()\nend\n\nT['open()']['handles undo just after open'] = function()\n  open(test_dir_path)\n  type_keys('u')\n  eq(#get_lines() > 1, true)\n  eq(child.cmd_capture('1messages'), 'Already at oldest change')\nend\n\nT['open()']['uses icon provider'] = function()\n  -- 'mini.icons'\n  child.lua('require(\"mini.icons\").setup()')\n  open(make_test_path('real'))\n  --stylua: ignore\n  eq(get_extmarks_hl(), {\n    'MiniIconsAzure',  'MiniFilesFile',\n    'MiniIconsYellow', 'MiniFilesFile',\n    'MiniIconsAzure',  'MiniFilesFile',\n    'MiniIconsCyan',   'MiniFilesFile',\n    'MiniIconsGrey',   'MiniFilesFile',\n    'MiniIconsGrey',   'MiniFilesFile',\n  })\n\n  go_out()\n  --stylua: ignore\n  eq(get_extmarks_hl(), {\n    'MiniIconsAzure', 'MiniFilesDirectory',\n    -- 'lua' directory has special highlighting\n    'MiniIconsBlue', 'MiniFilesDirectory',\n    'MiniIconsAzure', 'MiniFilesDirectory',\n    'MiniIconsAzure', 'MiniFilesDirectory',\n    'MiniIconsAzure', 'MiniFilesFile',\n    'MiniIconsAzure', 'MiniFilesFile',\n  })\n\n  child.expect_screenshot()\n  close()\n\n  -- Should still prefer 'mini.icons' if 'nvim-web-devicons' is available\n  -- - Mock 'nvim-web-devicons'\n  child.cmd('set rtp+=tests/dir-files')\n\n  open(make_test_path('real'))\n  child.expect_screenshot()\n  close()\n\n  -- Should fall back to 'nvim-web-devicons'\n  child.lua('_G.MiniIcons = nil')\n\n  open(make_test_path('real'))\n  child.expect_screenshot()\nend\n\nT['open()']['uses `MiniIcons.get()` with full path'] = function()\n  child.set_size(15, 60)\n  child.lua([[vim.filetype.add({ pattern = { ['.*/common/.*%-file'] = 'make' } })]])\n  child.lua('require(\"mini.icons\").setup()')\n  open(test_dir_path)\n  child.expect_screenshot()\nend\n\nT['open()']['history'] = new_set()\n\nT['open()']['history']['opens from history by default'] = function()\n  open(test_dir_path)\n  type_keys('j')\n  go_in()\n  type_keys('2j')\n  child.expect_screenshot()\n\n  close()\n  eq(is_explorer_active(), false)\n  open(test_dir_path)\n  -- Should be exactly the same, including cursors\n  child.expect_screenshot()\nend\n\nT['open()']['history']['handles external changes between calls'] = function()\n  local temp_dir = make_temp_dir('temp', { 'subdir/' })\n\n  open(temp_dir)\n  go_in()\n  child.expect_screenshot()\n\n  close()\n  child.fn.delete(join_path(temp_dir, 'subdir'), 'rf')\n  open(temp_dir)\n  child.expect_screenshot()\nend\n\nT['open()']['history']['respects `use_latest`'] = function()\n  open(test_dir_path)\n  type_keys('j')\n  go_in()\n  type_keys('2j')\n  child.expect_screenshot()\n\n  close()\n  eq(is_explorer_active(), false)\n  open(test_dir_path, false)\n  -- Should be as if opened first time\n  child.expect_screenshot()\nend\n\nT['open()']['history']['prefers global config before taking from history'] = function()\n  child.lua([[\n    _G.filter_starts_from_a = function(fs_entry) return vim.startswith(fs_entry.name, 'a') end\n    _G.filter_starts_from_b = function(fs_entry) return vim.startswith(fs_entry.name, 'b') end\n  ]])\n\n  local lua_cmd = string.format(\n    'MiniFiles.open(%s, false, { content = { filter = _G.filter_starts_from_a } })',\n    vim.inspect(test_dir_path)\n  )\n  child.lua(lua_cmd)\n  child.expect_screenshot()\n\n  close()\n  child.lua('MiniFiles.config.content.filter = _G.filter_starts_from_b')\n  open(test_dir_path, true)\n  child.expect_screenshot()\nend\n\nT['open()']['history']['stores whole branch and not only visible windows'] = function()\n  child.set_size(15, 60)\n  open(test_dir_path)\n  go_in()\n  child.expect_screenshot()\n  close()\n\n  child.set_size(15, 80)\n  -- Should show two windows\n  open(test_dir_path, true)\n  child.expect_screenshot()\nend\n\nT['open()']['history']['is shared across tabpages'] = function()\n  -- Prepare history\n  open(test_dir_path)\n  go_in()\n  child.expect_screenshot()\n  close()\n\n  -- Open in new tabpage\n  child.cmd('tabedit')\n  open(test_dir_path, true)\n  child.expect_screenshot()\n  go_out()\n  close()\n\n  child.cmd('tabnext')\n  open(test_dir_path, true)\n  child.expect_screenshot()\nend\n\nT['open()']['history']['updates target window on every call'] = function()\n  -- Prepare windows\n  local win_id_1 = child.api.nvim_get_current_win()\n  child.cmd('wincmd v')\n  local win_id_2 = child.api.nvim_get_current_win()\n  eq(win_id_1 ~= win_id_2, true)\n\n  -- Put explorer in history which opened in current window\n  open(test_file_path)\n  go_in()\n  close()\n  eq(is_file_in_window(win_id_1, test_file_path), false)\n  eq(is_file_in_window(win_id_2, test_file_path), true)\n\n  child.api.nvim_win_set_buf(win_id_2, child.api.nvim_win_get_buf(win_id_1))\n\n  -- New `open()` call should register new target window\n  child.api.nvim_set_current_win(win_id_1)\n  open(test_file_path)\n  go_in()\n  close()\n  eq(is_file_in_window(win_id_1, test_file_path), true)\n  eq(is_file_in_window(win_id_2, test_file_path), false)\nend\n\nT['open()']['focuses on file entry when opened from history'] = function()\n  local path = make_test_path('common/a-dir/ab-file')\n\n  -- If in branch, just focus on entry\n  open(path)\n  type_keys('j')\n  go_out()\n  child.expect_screenshot()\n\n  close()\n  open(path)\n  child.expect_screenshot()\n\n  -- If not in branch, reset\n  go_out()\n  trim_right()\n  child.expect_screenshot()\n  close()\n\n  open(path)\n  child.expect_screenshot()\nend\n\nT['open()']['normalizes before first refresh when focused on file'] = function()\n  -- Prepare explorer state to be opened from history\n  open(make_test_path('common'))\n  go_in()\n  eq(is_explorer_active(), true)\n  close()\n\n  -- Mock `nvim_open_win()`\n  child.lua([[\n    _G.init_nvim_open_win = vim.api.nvim_open_win\n    _G.open_win_count = 0\n    vim.api.nvim_open_win = function(...)\n      _G.open_win_count = _G.open_win_count + 1\n      return init_nvim_open_win(...)\n    end\n  ]])\n\n  -- Test. Opening file in 'common' directory makes previous two-window view\n  -- not synchronized with cursor (pointing at file while right window is for\n  -- previously opened directory). Make sure that it is made one window prior\n  -- to rendering, otherwise it might result in flickering.\n  open(make_test_path('common/a-file'))\n  child.expect_screenshot()\n  eq(child.lua_get('_G.open_win_count'), 1)\nend\n\nT['open()']['normalizes before first refresh when focused on directory with `windows.preview`'] = function()\n  -- Prepare explorer state to be opened from history\n  open(test_dir_path)\n  eq(is_explorer_active(), true)\n  close()\n\n  -- Mock `nvim_open_win()`\n  child.lua([[\n    _G.init_nvim_open_win = vim.api.nvim_open_win\n    _G.open_win_count = 0\n    vim.api.nvim_open_win = function(...)\n      _G.open_win_count = _G.open_win_count + 1\n      return init_nvim_open_win(...)\n    end\n  ]])\n\n  -- Test. It should preview right away without extra window manipulations.\n  open(test_dir_path, true, { windows = { preview = true } })\n  child.expect_screenshot()\n  eq(child.lua_get('_G.open_win_count'), 2)\nend\n\nT['open()']['respects `content.filter`'] = function()\n  child.lua([[\n    _G.filter_arg = {}\n    MiniFiles.config.content.filter = function(fs_entry)\n      _G.filter_arg = fs_entry\n\n      -- Show only directories\n      return fs_entry.fs_type == 'directory'\n    end\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\n  validate_fs_entry(child.lua_get('_G.filter_arg'))\n\n  -- Local value from argument should take precedence\n  child.lua([[_G.filter_starts_from_a = function(fs_entry) return vim.startswith(fs_entry.name, 'a') end ]])\n\n  local lua_cmd = string.format(\n    [[MiniFiles.open(%s, false, { content = { filter = _G.filter_starts_from_a } })]],\n    vim.inspect(test_dir_path)\n  )\n  child.lua(lua_cmd)\n  child.expect_screenshot()\nend\n\nT['open()']['respects `content.highlight`'] = function()\n  child.lua([[\n    _G.highlight_arg = {}\n    MiniFiles.config.content.highlight = function(fs_entry)\n      _G.highlight_arg = fs_entry\n      -- Should use 'MiniFilesNormal' as a fallback\n      return nil\n    end\n  ]])\n\n  local expect_screenshot = function()\n    -- Test only on Neovim>=0.12 because there window-local `Normal` (which is\n    -- `MiniFilesNormal` here) blends background with cursorline\n    if child.fn.has('nvim-0.12') == 1 then child.expect_screenshot() end\n  end\n\n  open(test_dir_path)\n  expect_screenshot()\n  validate_fs_entry(child.lua_get('_G.highlight_arg'))\n\n  -- Local value from argument should take precedence\n  child.lua([[_G.highlight_starts_from_a = function(fs_entry)\n    return vim.startswith(fs_entry.name, 'a') and 'String' or 'Comment'\n  end]])\n\n  local lua_cmd = string.format(\n    'MiniFiles.open(%s, false, { content = { highlight = _G.highlight_starts_from_a } })',\n    vim.inspect(test_dir_path)\n  )\n  child.lua(lua_cmd)\n  expect_screenshot()\nend\n\nT['open()']['respects `content.prefix`'] = function()\n  child.set_size(15, 60)\n\n  child.lua([[\n    _G.prefix_arg = {}\n    MiniFiles.config.content.prefix = function(fs_entry)\n      _G.prefix_arg = fs_entry\n\n      if fs_entry.fs_type == 'directory' then\n        return '-', 'Comment'\n      else\n        return '|', 'Special'\n      end\n    end\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\n  validate_fs_entry(child.lua_get('_G.prefix_arg'))\n\n  -- Local value from argument should take precedence\n  child.lua([[_G.prefix_2 = function(fs_entry) return '|', 'Special' end ]])\n\n  local lua_cmd =\n    string.format([[MiniFiles.open(%s, false, { content = { prefix = _G.prefix_2 } })]], vim.inspect(test_dir_path))\n  child.lua(lua_cmd)\n  child.expect_screenshot()\nend\n\nT['open()']['`content.prefix` can be used to not show prefix'] = function()\n  child.lua([[MiniFiles.config.content.prefix = function() return '', '' end]])\n  open(test_dir_path)\n  go_in()\n  child.expect_screenshot()\nend\n\nT['open()']['`content.prefix` can return `nil`'] = function()\n  child.set_size(15, 60)\n\n  local validate = function(return_expr)\n    local lua_cmd = string.format([[MiniFiles.config.content.prefix = function() return %s end]], return_expr)\n    child.lua(lua_cmd)\n    open(test_dir_path)\n    child.expect_screenshot()\n    close()\n  end\n\n  validate()\n  validate([['', nil]])\n  validate([[nil, '']])\nend\n\nT['open()']['`content.prefix` is called only on visible part of preview'] = function()\n  child.set_size(5, 100)\n  child.lua([[\n    MiniFiles.config.windows.preview = true\n\n    _G.log = {}\n    MiniFiles.config.content.prefix = function(fs_entry)\n      table.insert(_G.log, fs_entry.name)\n      return '-', 'Comment'\n    end\n\n    _G.scandir_log = {}\n    fs_scandir_orig = vim.loop.fs_scandir\n    vim.loop.fs_scandir = function(path)\n      table.insert(_G.scandir_log, path)\n      return fs_scandir_orig(path)\n    end\n  ]])\n\n  local validate_log = function(ref)\n    local computed_prefix = child.lua_get('_G.log')\n    table.sort(computed_prefix)\n    eq(computed_prefix, ref)\n    child.lua('_G.log = {}')\n  end\n\n  local children = { 'dir/', 'dir/subdir/' }\n  for i = 1, 6 do\n    table.insert(children, 'dir/subdir/file-' .. i)\n  end\n  local temp_dir = make_temp_dir('temp', children)\n\n  open(temp_dir .. '/dir')\n  -- Prefix should be computed only for entries that might be visible (first\n  -- vim.o.cmdheight)\n  validate_log({ 'file-1', 'file-2', 'file-3', 'file-4', 'file-5', 'subdir' })\n\n  -- Prefix should be recomputed for all entries *only* if the path is focused\n  go_out()\n  validate_log({ 'dir' })\n\n  go_in()\n  validate_log({})\n\n  -- - Synchronization should also not force recomputation on **all** entries\n  type_keys('o', 'new-file', '<Esc>', 'k')\n  mock_confirm(1)\n  child.lua('MiniFiles.synchronize()')\n  validate_log({ 'dir', 'file-1', 'file-2', 'file-3', 'file-4', 'file-5', 'new-file', 'subdir' })\n\n  child.lua('_G.scandir_log = {}')\n  go_in()\n  -- - Only focus should result into prefix recomputation on all entries\n  validate_log({ 'file-1', 'file-2', 'file-3', 'file-4', 'file-5', 'file-6' })\n  -- - Should also not result in additional disk read\n  eq(child.lua_get('_G.scandir_log'), {})\nend\n\nT['open()']['respects `content.sort`'] = function()\n  child.lua([[\n    _G.sort_arg = {}\n    MiniFiles.config.content.sort = function(fs_entries)\n      _G.sort_arg = fs_entries\n\n      -- Sort alphabetically without paying attention to file system type\n      local res = vim.deepcopy(fs_entries)\n      table.sort(res, function(a, b) return a.name < b.name end)\n      return res\n    end\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  local sort_arg = child.lua_get('_G.sort_arg')\n  eq(type(sort_arg), 'table')\n  for _, val in pairs(sort_arg) do\n    validate_fs_entry(val)\n  end\n\n  -- Local value from argument should take precedence\n  child.lua([[\n    _G.sort_rev_alpha = function(fs_entries)\n      local res = vim.deepcopy(fs_entries)\n      table.sort(res, function(a, b) return a.name > b.name end)\n      return res\n    end\n  ]])\n\n  local lua_cmd =\n    string.format([[MiniFiles.open(%s, false, { content = { sort = _G.sort_rev_alpha } })]], vim.inspect(test_dir_path))\n  child.lua(lua_cmd)\n  child.expect_screenshot()\nend\n\nT['open()']['`content.sort` can be used to also filter items'] = function()\n  child.lua([[\n    MiniFiles.config.content.sort = function(fs_entries)\n      -- Sort alphabetically without paying attention to file system type\n      local res = vim.tbl_filter(function(x) return x.fs_type == 'directory' end, fs_entries)\n      table.sort(res, function(a, b) return a.name > b.name end)\n      return res\n    end\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\nend\n\nT['open()']['respects `mappings`'] = function()\n  child.lua([[MiniFiles.config.mappings.go_in = '<CR>']])\n  open(test_dir_path)\n  type_keys('<CR>')\n  child.expect_screenshot()\n  close()\n\n  -- Local value from argument should take precedence\n  open(test_dir_path, false, { mappings = { go_in = 'K' } })\n  type_keys('K')\n  child.expect_screenshot()\nend\n\nT['open()']['does not create mapping for empty string'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('nmap ' .. lhs):find(pattern) ~= nil end\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  child.lua('MiniFiles.config.mappings.go_in = \"\"')\n  open()\n\n  eq(has_map('q', 'Close'), true)\n  eq(has_map('l', 'Go in'), false)\nend\n\nT['open()']['respects `windows.max_number`'] = function()\n  child.lua('MiniFiles.config.windows.max_number = 1')\n  open(test_dir_path)\n  go_in()\n  child.expect_screenshot()\n  close()\n\n  -- Local value from argument should take precedence\n  open(test_dir_path, false, { windows = { max_number = 2 } })\n  go_in()\n  child.expect_screenshot()\nend\n\nT['open()']['respects `windows.preview`'] = function()\n  child.lua('MiniFiles.config.windows.preview = true')\n  open(test_dir_path)\n  child.expect_screenshot()\n  close()\n\n  -- Local value from argument should take precedence\n  open(test_dir_path, false, { windows = { preview = false } })\n  child.expect_screenshot()\nend\n\nT['open()']['respects `windows.width_focus` and `windows.width_nofocus`'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 40')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  open(test_dir_path)\n  go_in()\n  child.expect_screenshot()\n  close()\n\n  -- Local value from argument should take precedence\n  open(test_dir_path, false, { windows = { width_focus = 30, width_nofocus = 20 } })\n  go_in()\n  child.expect_screenshot()\nend\n\nT['open()']['respects `windows.width_preview`'] = function()\n  child.lua('MiniFiles.config.windows.preview = true')\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  child.lua('MiniFiles.config.windows.width_preview = 15')\n\n  local test_path = make_test_path('nested')\n\n  -- Preview window is to the right of focused one (if preview is active)\n  open(test_path)\n  child.expect_screenshot()\n  go_in()\n  child.expect_screenshot()\n  go_in()\n  child.expect_screenshot()\n  go_out()\n  child.expect_screenshot()\n  go_out()\n  child.expect_screenshot()\n\n  close()\n\n  -- Local value from argument should take precedence\n  open(test_path, false, { windows = { width_focus = 20, width_preview = 30 } })\n  child.expect_screenshot()\nend\n\nT['open()']['properly closes currently opened explorer'] = function()\n  local path_1, path_2 = make_test_path('common'), make_test_path('common/a-dir')\n  open(path_1)\n  go_in()\n  eq(is_explorer_active(), true)\n\n  -- Should properly close current opened explorer (at least save to history)\n  open(path_2)\n  close()\n\n  open(path_1, true)\n  child.expect_screenshot()\nend\n\nT['open()']['properly closes currently opened explorer with pending file system actions'] = function()\n  child.cmd('au User MiniFilesExplorerClose lua _G.had_close_event = true')\n  child.set_size(100, 100)\n\n  local path_1, path_2 = make_test_path('common'), make_test_path('common/a-dir')\n  open(path_1)\n  type_keys('o', 'hello')\n\n  -- Should mention modified buffers and ask for confirmation\n  mock_confirm(1)\n  open(path_2)\n  validate_confirm_args('pending file system actions.*Close without sync', false)\n\n  -- Should trigger proper event for closing explorer\n  eq(child.lua_get('_G.had_close_event'), true)\n  close()\n  child.ensure_normal_mode()\n\n  -- Should not confirm if there are no actionable pending file system actions\n  child.lua('_G.confirm_args = nil')\n  open(path_1)\n  type_keys('o')\n  open(path_2)\n  eq(child.lua_get('_G.confirm_args'), vim.NIL)\nend\n\nT['open()']['tracks lost focus'] = function()\n  child.lua('MiniFiles.config.windows.preview = true')\n\n  local validate = function(loose_focus)\n    open(test_dir_path)\n    child.cmd('redraw')\n    loose_focus()\n    -- Tracking is done by checking every second\n    sleep(track_lost_focus_delay + small_time)\n    eq(is_explorer_active(), false)\n    eq(#child.api.nvim_list_bufs(), 1)\n  end\n\n  local init_win_id = child.api.nvim_get_current_win()\n  validate(function() child.api.nvim_set_current_win(init_win_id) end)\n\n  validate(function() child.cmd('quit') end)\n\n  validate(function()\n    go_in()\n    type_keys('ZZ')\n  end)\n\n  -- Should still be possible to open same explorer afterwards\n  open(test_dir_path)\n  eq(is_explorer_active(), true)\nend\n\nT['open()']['can display entries with newline character'] = function()\n  if helpers.is_windows() then MiniTest.skip('Newline characters in names are not supported on Windows') end\n  local temp_dir = make_temp_dir('temp', { 'di\\nr/', 'fi\\nl\\ne' })\n  open(temp_dir, true, { windows = { preview = true } })\n  child.expect_screenshot()\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['open()']['validates input'] = function()\n  -- `path` should be a real path\n  expect.error(function() open('aaa') end, 'path.*not a valid path.*aaa')\nend\n\nT['open()']['respects `vim.b.minifiles_config`'] = function()\n  child.lua([[_G.filter_starts_from_a = function(fs_entry) return vim.startswith(fs_entry.name, 'a') end ]])\n  child.lua('vim.b.minifiles_config = { content = { filter = _G.filter_starts_from_a } }')\n\n  open(test_dir_path)\n  child.expect_screenshot()\nend\n\nT['refresh()'] = new_set()\n\nlocal refresh = forward_lua('MiniFiles.refresh')\n\nT['refresh()']['works'] = function()\n  open(test_dir_path)\n  refresh({ windows = { width_focus = 30 } })\n  child.expect_screenshot()\nend\n\nT['refresh()']['preserves explorer options'] = function()\n  open(test_dir_path, false, { windows = { width_focus = 45, width_nofocus = 10 } })\n  go_in()\n  child.expect_screenshot()\n  -- Current explorer options should be preserved\n  refresh({ windows = { width_focus = 30 } })\n  child.expect_screenshot()\nend\n\nT['refresh()']['does not update buffers with `nil` `filter` and `sort`'] = function()\n  local temp_dir = make_temp_dir('temp', { 'subdir/' })\n\n  open(temp_dir)\n  local buf_id_1 = child.api.nvim_get_current_buf()\n  go_in()\n  local buf_id_2 = child.api.nvim_get_current_buf()\n  child.expect_screenshot()\n\n  local changedtick_1 = child.api.nvim_buf_get_var(buf_id_1, 'changedtick')\n  local changedtick_2 = child.api.nvim_buf_get_var(buf_id_2, 'changedtick')\n\n  -- Should not update buffers\n  refresh()\n  eq(child.api.nvim_buf_get_var(buf_id_1, 'changedtick'), changedtick_1)\n  eq(child.api.nvim_buf_get_var(buf_id_2, 'changedtick'), changedtick_2)\n\n  -- Should not update even if there are external changes (there is\n  -- `synchronize()` for that)\n  vim.fn.mkdir(join_path(temp_dir, 'subdir', 'subsubdir'))\n  refresh()\n  child.expect_screenshot()\n  eq(child.api.nvim_buf_get_var(buf_id_1, 'changedtick'), changedtick_1)\n  eq(child.api.nvim_buf_get_var(buf_id_2, 'changedtick'), changedtick_2)\nend\n\nT['refresh()']['updates buffers with non-empty `content`'] = function()\n  child.lua([[\n    _G.hide_dotfiles = function(fs_entry) return not vim.startswith(fs_entry.name, '.') end\n    _G.hide_prefix = function() return '', '' end\n    _G.sort_rev_alpha = function(fs_entries)\n      local res = vim.deepcopy(fs_entries)\n      table.sort(res, function(a, b) return a.name > b.name end)\n      return res\n    end\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  child.lua('MiniFiles.refresh({ content = { filter = _G.hide_dotfiles } })')\n  child.expect_screenshot()\n\n  child.lua('MiniFiles.refresh({ content = { prefix = _G.hide_prefix } })')\n  child.expect_screenshot()\n\n  child.lua('MiniFiles.refresh({ content = { sort = _G.sort_rev_alpha } })')\n  child.expect_screenshot()\nend\n\nT['refresh()']['handles presence of pending file system actions'] = function()\n  child.set_size(10, 60)\n  child.lua([[_G.hide_dotfiles = function(fs_entry) return not vim.startswith(fs_entry.name, '.') end ]])\n\n  local temp_dir = make_temp_dir('temp', { 'file', '.file' })\n  open(temp_dir)\n\n  -- On confirm should update buffers without synchronization\n  type_keys('o', 'new-file', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  child.lua('MiniFiles.refresh({ content = { filter = _G.hide_dotfiles }, windows = { width_focus = 30 } })')\n  child.expect_screenshot()\n\n  validate_confirm_args('pending file system actions.*Update buffers without sync', false)\n\n  -- On no confirm should not update buffers, but still apply other changes\n  type_keys('o', 'new-file-2', '<Esc>')\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  mock_confirm(2)\n  child.lua('MiniFiles.refresh({ content = { filter = function() return true end }, windows = { width_focus = 15 } })')\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  mock_confirm(1)\n  close()\n  child.ensure_normal_mode()\n\n  -- Should not confirm if there are no actionable pending file system actions\n  child.lua('_G.confirm_args = nil')\n  open(temp_dir)\n  type_keys('o')\n  refresh()\n  eq(child.lua_get('_G.confirm_args'), vim.NIL)\nend\n\nT['refresh()']['works when no explorer is opened'] = function() expect.no_error(refresh) end\n\n-- More extensive testing is done in 'File manipulation'\nT['synchronize()'] = new_set()\n\nlocal synchronize = forward_lua('MiniFiles.synchronize')\n\nT['synchronize()']['can update external file system changes'] = function()\n  local temp_dir = make_temp_dir('temp', { 'subdir/' })\n\n  open(temp_dir)\n  validate_cur_line(1)\n\n  vim.fn.mkdir(join_path(temp_dir, 'aaa'))\n  eq(synchronize(), true)\n  child.expect_screenshot()\n\n  -- Cursor should be \"sticked\" to current entry\n  validate_cur_line(2)\nend\n\nT['synchronize()']['can apply file system actions'] = function()\n  local temp_dir = make_temp_dir('temp', {})\n\n  open(temp_dir)\n  type_keys('i', 'new-file', '<Esc>')\n\n  mock_confirm(1)\n\n  validate_tree(temp_dir, {})\n  eq(synchronize(), true)\n  validate_tree(temp_dir, { 'new-file' })\nend\n\nT['synchronize()']['can cancel synchronization'] = function()\n  local temp_dir = make_temp_dir('temp', {})\n\n  open(temp_dir)\n  type_keys('i', 'new-file', '<Esc>')\n\n  child.fn.writefile({ '' }, join_path(temp_dir, 'aaa'))\n\n  mock_confirm(3)\n\n  validate_tree(temp_dir, { 'aaa' })\n  eq(synchronize(), false)\n  -- Should not apply file system changes, not sync external changes, and keep\n  -- buffers as is\n  validate_tree(temp_dir, { 'aaa' })\n  eq(get_lines(), { 'new-file' })\nend\n\nT['synchronize()']['should follow cursor on current entry path'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n\n  open(temp_dir)\n  type_keys('G', 'o', 'new-dir/', '<Esc>')\n  type_keys('k')\n\n  validate_cur_line(2)\n\n  mock_confirm(1)\n  synchronize()\n  validate_cur_line(3)\nend\n\nT['synchronize()']['should follow cursor on new path'] = function()\n  mock_confirm(1)\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  open(temp_dir)\n\n  -- File\n  type_keys('O', 'new-file', '<Esc>')\n  validate_cur_line(1)\n  synchronize()\n  validate_cur_line(2)\n\n  -- Directory\n  type_keys('o', 'new-dir/', '<Esc>')\n  validate_cur_line(3)\n  synchronize()\n  validate_cur_line(2)\n\n  -- Nested directories\n  type_keys('o', 'a/b', '<Esc>')\n  validate_cur_line(3)\n  synchronize()\n  validate_cur_line(1)\nend\n\nT['synchronize()']['works when no explorer is opened'] = function() expect.no_error(synchronize) end\n\nT['reset()'] = new_set()\n\nlocal reset = forward_lua('MiniFiles.reset')\n\nT['reset()']['works'] = function()\n  open(test_dir_path)\n  type_keys('j')\n  go_in()\n  child.expect_screenshot()\n\n  reset()\n  child.expect_screenshot()\nend\n\nT['reset()']['works when anchor is not in branch'] = function()\n  open(join_path(test_dir_path, 'a-dir'))\n  go_out()\n  type_keys('k')\n  go_in()\n  child.expect_screenshot()\n\n  reset()\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\nend\n\nT['reset()']['resets all cursors'] = function()\n  open(test_dir_path)\n  type_keys('j')\n  go_in()\n  type_keys('G')\n  validate_cur_line(3)\n\n  -- Should reset cursors in both visible and invisible buffers\n  go_out()\n  type_keys('G')\n  child.expect_screenshot()\n\n  reset()\n  child.expect_screenshot()\n  type_keys('j')\n  go_in()\n  validate_cur_line(1)\nend\n\nT['reset()']['works when no explorer is opened'] = function() expect.no_error(reset) end\n\nT['close()'] = new_set()\n\nT['close()']['works'] = function()\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  -- Should return `true` if closing was successful\n  eq(close(), true)\n  child.expect_screenshot()\n\n  -- Should close all windows and delete all buffers\n  eq(is_explorer_active(), false)\n  eq(#child.api.nvim_list_bufs(), 1)\nend\n\nT['close()']['works per tabpage'] = function()\n  open(test_dir_path)\n  child.cmd('tabedit')\n  open(test_file_path)\n\n  child.cmd('tabprev')\n  close()\n\n  -- On different tabpage explorer should still be present\n  child.cmd('tabnext')\n  child.expect_screenshot()\nend\n\nT['close()']['checks for pending file system actions'] = function()\n  child.cmd('au User MiniFilesExplorerClose lua _G.had_close_event = true')\n  open(test_dir_path)\n  type_keys('o', 'new', '<Esc>')\n  child.expect_screenshot()\n\n  -- Should confirm close and do nothing if there is none (and return `false`)\n  mock_confirm(2)\n  eq(close(), false)\n  child.expect_screenshot()\n  validate_confirm_args('pending file system actions.*Close without sync', false)\n\n  -- - Should not trigger close event (as there was no closing)\n  eq(child.lua_get('_G.had_close_event'), vim.NIL)\n\n  -- Should close if there is confirm\n  mock_confirm(1)\n  eq(close(), true)\n  child.expect_screenshot()\n\n  -- Should not confirm if there are no actionable pending file system actions\n  child.lua('_G.confirm_args = nil')\n  open(test_dir_path)\n  type_keys('o')\n  close()\n  eq(child.lua_get('_G.confirm_args'), vim.NIL)\nend\n\nT['close()']['results into focus on target window'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  child.cmd('belowright vertical split')\n  local ref_win_id = child.api.nvim_get_current_win()\n\n  open(test_dir_path)\n  close()\n  eq(child.api.nvim_get_current_win(), ref_win_id)\n\n  -- Should handle non-valid target window\n  open(test_dir_path)\n  child.api.nvim_win_close(ref_win_id, true)\n  close()\n  eq(child.api.nvim_get_current_win(), init_win_id)\nend\n\nT['close()']['closes help window'] = function()\n  open(test_dir_path)\n  child.lua('MiniFiles.show_help()')\n  validate_n_wins(3)\n  close()\n  validate_n_wins(1)\nend\n\nT['close()']['handles invalid target window'] = function()\n  child.set_size(15, 60)\n\n  child.cmd('wincmd v')\n  local target_win_id = child.api.nvim_get_current_win()\n  open(test_dir_path)\n  child.expect_screenshot()\n  eq(#child.api.nvim_list_wins(), 3)\n\n  child.api.nvim_win_close(target_win_id, true)\n  close()\n  child.expect_screenshot()\n  eq(#child.api.nvim_list_bufs(), 1)\n  eq(#child.api.nvim_list_wins(), 1)\n  eq(child.cmd('messages'), '')\nend\n\nT['close()']['works when no explorer is opened'] = function() eq(close(), vim.NIL) end\n\nT['go_in()'] = new_set()\n\nT['go_in()']['works on file'] = function()\n  open(test_dir_path)\n  type_keys('/', [[\\.a-file]], '<CR>')\n  go_in()\n  close()\n\n  expect.match(child.api.nvim_buf_get_name(0), '%.a%-file$')\n  eq(get_lines(), { '.a-file' })\n\n  -- Should open path in relative form for nicer `:buffers`\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]' .. vim.pesc(test_dir_path))\nend\n\nT['go_in()']['mimics empty buffer reuse'] = function()\n  local validate = function(ref_n_bufs)\n    open(test_dir_path)\n    type_keys('/', [[\\.a-file]], '<CR>')\n    go_in()\n    close()\n\n    eq(#child.api.nvim_list_bufs(), ref_n_bufs)\n    child.cmd('%bwipeout!')\n  end\n\n  -- Should mimic `:h buffer-reuse` similar to how `:edit` does it\n  eq(child.api.nvim_get_current_buf() == 1, true)\n  validate(1)\n\n  eq(child.api.nvim_get_current_buf() ~= 1, true)\n  validate(1)\n\n  child.cmd('tabnew')\n  validate(2)\n\n  -- Should reuse only for strict set of conditions\n  child.api.nvim_buf_set_name(0, 'named-buf')\n  validate(2)\n\n  child.bo.buftype = 'quickfix'\n  validate(2)\n\n  child.cmd('split')\n  eq(#child.fn.win_findbuf(child.api.nvim_get_current_buf()), 2)\n  validate(2)\n\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { ' ' })\n  validate(2)\n\n  child.bo.modified = true\n  validate(2)\nend\n\nT['go_in()']['respects `opts.close_on_file`'] = function()\n  open(test_dir_path)\n  type_keys('/', [[\\.a-file]], '<CR>')\n  go_in({ close_on_file = true })\n  expect.match(child.api.nvim_buf_get_name(0), '%.a%-file$')\n  eq(get_lines(), { '.a-file' })\n\n  eq(is_explorer_active(), false)\nend\n\nT['go_in()']['works on files with problematic names'] = function()\n  local bad_name = '%a bad-file-name'\n  local temp_dir = make_temp_dir('temp', { bad_name })\n  child.fn.writefile({ 'aaa' }, join_path(temp_dir, bad_name))\n\n  open(temp_dir)\n  go_in()\n  close()\n\n  eq(is_file_in_buffer(0, bad_name), true)\n  eq(get_lines(), { 'aaa' })\nend\n\nT['go_in()']['uses already opened listed buffer without `:edit`'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  local file_path = join_path(temp_dir, 'file')\n\n  child.cmd('edit ' .. vim.fn.fnameescape(file_path))\n  local buf_id = child.api.nvim_get_current_buf()\n  child.fn.writefile({ 'New changes' }, file_path)\n\n  open(temp_dir)\n  go_in()\n  -- If `:edit` was used, then content would have changed\n  eq(child.api.nvim_buf_get_lines(buf_id, 0, -1, false), { '' })\n  close(temp_dir)\n\n  -- Should make unlisted buffer become listed\n  child.cmd('bdelete ' .. buf_id)\n  eq(child.api.nvim_buf_get_option(buf_id, 'buflisted'), false)\n\n  open(temp_dir)\n  go_in()\n  eq(child.api.nvim_buf_get_option(buf_id, 'buflisted'), true)\nend\n\nT['go_in()']['uses proper target window'] = function()\n  local win_id_1 = child.api.nvim_get_current_win()\n  child.cmd('wincmd v')\n  local win_id_2 = child.api.nvim_get_current_win()\n  eq(win_id_1 ~= win_id_2, true)\n\n  open(test_file_path)\n  go_in()\n  eq(is_file_in_window(win_id_1, test_file_path), false)\n  eq(is_file_in_window(win_id_2, test_file_path), true)\nend\n\nT['go_in()']['works if target window is not valid'] = function()\n  local win_id_1 = child.api.nvim_get_current_win()\n  child.cmd('wincmd v')\n  local win_id_2 = child.api.nvim_get_current_win()\n  eq(win_id_1 ~= win_id_2, true)\n\n  open(test_file_path)\n  child.api.nvim_win_close(win_id_2, true)\n  go_in()\n  eq(is_file_in_window(win_id_1, test_file_path), true)\nend\n\nT['go_in()']['works on directory'] = function()\n  open(test_dir_path)\n\n  -- Should open if not already visible\n  go_in()\n  child.expect_screenshot()\n\n  -- Should focus if already visible\n  go_out()\n  go_in()\n  child.expect_screenshot()\nend\n\nT['go_in()']['works on file with newline character'] = function()\n  if helpers.is_windows() then MiniTest.skip('Newline characters in names are not supported on Windows') end\n  local temp_dir = make_temp_dir('temp', { 'fi\\nl\\ne' })\n  open(temp_dir)\n  go_in()\n  close()\n  expect.match(child.api.nvim_buf_get_name(0), 'fi\\nl\\ne$')\nend\n\nT['go_in()']['works when no explorer is opened'] = function() expect.no_error(go_in) end\n\nT['go_in()']['warns about paths not present on disk'] = function()\n  local validate_log = function(msg_pattern)\n    local notify_log = child.lua_get('_G.notify_log')\n    eq(#notify_log, 1)\n    expect.match(notify_log[1][1], msg_pattern)\n    eq(notify_log[1][2], child.lua_get('vim.log.levels.WARN'))\n    child.lua('_G.notify_log = {}')\n  end\n\n  open(test_dir_path)\n\n  -- Modified line without synchronization\n  type_keys('O', 'new-file', '<Esc>')\n  go_in()\n  validate_log('Line \"new%-file\".*Did you modify without synchronization%?')\n\n  -- Entry which doesn't exist on disk\n  child.lua([[\n    local get_fs_entry_orig = MiniFiles.get_fs_entry\n    MiniFiles.get_fs_entry = function(...)\n      local res = get_fs_entry_orig(...)\n      res.fs_type = nil\n      return res\n    end\n  ]])\n  type_keys('j')\n  go_in()\n  validate_log('Path .* is not present on disk%.$')\n\n  -- Entry with possibly miscreated symlink\n  child.lua('vim.fn.resolve = function() return \"miscreated-symlink\" end')\n  go_in()\n  validate_log('Path.*is not present on disk.*miscreated symlink %(resolved to miscreated%-symlink%)')\nend\n\nT['go_out()'] = new_set()\n\nT['go_out()']['works on not branch root'] = function()\n  open(test_dir_path)\n  type_keys('j')\n  go_in()\n\n  -- Should focus parent directory with cursor pointing on entry to the right\n  go_out()\n  child.expect_screenshot()\nend\n\nT['go_out()']['works on branch root'] = function()\n  local path = make_test_path('common', 'a-dir')\n  open(path)\n\n  -- Should focus parent directory with cursor pointing on entry to the right\n  -- Should also preserve visibility of current directory\n  go_out()\n  child.expect_screenshot()\nend\n\nT['go_out()']['root update reuses buffers without their update'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  local path = join_path(temp_dir, 'dir')\n\n  open(path)\n  child.fn.writefile({}, join_path(path, 'file'))\n  go_out()\n  -- Present buffer should not be updated with new file system information\n  child.expect_screenshot()\nend\n\nT['go_out()']['works when no explorer is opened'] = function() expect.no_error(go_out) end\n\nT['trim_left()'] = new_set()\n\nT['trim_left()']['works'] = function()\n  open(make_test_path('nested'))\n  go_in()\n  go_in()\n  child.expect_screenshot()\n\n  trim_left()\n  child.expect_screenshot()\nend\n\nT['trim_left()']['works when in the middle of the branch'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n\n  open(make_test_path('nested'))\n  go_in()\n  go_in()\n  go_out()\n  child.expect_screenshot()\n\n  trim_left()\n  child.expect_screenshot()\nend\n\nT['trim_left()']['works when no explorer is opened'] = function() expect.no_error(trim_left) end\n\nT['trim_right()'] = new_set()\n\nT['trim_right()']['works'] = function()\n  open(make_test_path('nested'))\n  go_in()\n  go_in()\n  go_out()\n  go_out()\n  child.expect_screenshot()\n\n  trim_right()\n  child.expect_screenshot()\nend\n\nT['trim_right()']['works when in the middle of the branch'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n\n  open(make_test_path('nested'))\n  go_in()\n  go_in()\n  go_out()\n  child.expect_screenshot()\n\n  trim_right()\n  child.expect_screenshot()\nend\n\nT['trim_right()']['works when no explorer is opened'] = function() expect.no_error(trim_right) end\n\nT['reveal_cwd()'] = new_set()\n\nlocal reveal_cwd = forward_lua('MiniFiles.reveal_cwd')\n\nT['reveal_cwd()']['works'] = function()\n  child.set_size(10, 80)\n\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  local nested_path = make_test_path('nested')\n  child.fn.chdir(nested_path)\n\n  open(nested_path)\n  go_in()\n  go_in()\n  trim_left()\n  child.expect_screenshot()\n\n  reveal_cwd()\n  child.expect_screenshot()\nend\n\nT['reveal_cwd()']['works with preview'] = function()\n  child.set_size(10, 80)\n\n  child.lua('MiniFiles.config.windows.preview = true')\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_preview = 10')\n  local nested_path = make_test_path('nested')\n  child.fn.chdir(nested_path)\n\n  open(nested_path)\n  go_in()\n  go_in()\n  trim_left()\n  child.expect_screenshot()\n\n  reveal_cwd()\n  child.expect_screenshot()\nend\n\nT['reveal_cwd()']['works when not inside cwd'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  local open_path = full_path(test_dir_path)\n  local temp_dir = make_temp_dir('temp', {})\n  child.fn.chdir(temp_dir)\n\n  open(open_path)\n  child.expect_screenshot()\n\n  reveal_cwd()\n  child.expect_screenshot()\nend\n\nT['reveal_cwd()']['works when root is already cwd'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  local open_path = full_path(test_dir_path)\n  child.fn.chdir(test_dir_path)\n\n  open(open_path)\n  child.expect_screenshot()\n\n  reveal_cwd()\n  child.expect_screenshot()\nend\n\nT['reveal_cwd()']['properly places cursors'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  local temp_dir =\n    make_temp_dir('temp', { 'dir-1/', 'dir-2/', 'dir-3/', 'dir-2/dir-21/', 'dir-2/dir-22/', 'dir-2/dir-23/' })\n  temp_dir = full_path(temp_dir)\n  child.fn.chdir(temp_dir)\n\n  open(join_path(temp_dir, 'dir-2', 'dir-23'))\n  child.expect_screenshot()\n\n  reveal_cwd()\n  child.expect_screenshot()\nend\n\nT['reveal_cwd()']['works when no explorer is opened'] = function() expect.no_error(reveal_cwd) end\n\nT['show_help()'] = new_set()\n\nlocal show_help = forward_lua('MiniFiles.show_help')\n\nT['show_help()']['works'] = function()\n  child.set_size(22, 60)\n  open(test_dir_path)\n  local win_id_explorer = child.api.nvim_get_current_win()\n\n  type_keys('2j')\n\n  show_help()\n  local buf_help = child.api.nvim_get_current_buf()\n  eq(child.api.nvim_buf_get_name(0), 'minifiles://' .. buf_help .. '/help')\n  child.expect_screenshot()\n\n  -- Should focus on help window\n  eq(child.api.nvim_get_current_win() ~= win_id_explorer, true)\n\n  -- Pressing `q` should close help window, delete buffer, and focus on\n  -- explorer at same line\n  type_keys('q')\n  eq(child.api.nvim_buf_is_valid(buf_help), false)\n  child.expect_screenshot()\nend\n\nT['show_help()']['opens relatively current window'] = function()\n  child.set_size(22, 60)\n  child.lua('MiniFiles.config.windows.width_focus = 30')\n\n  open(test_dir_path)\n  go_in()\n\n  show_help()\n  child.expect_screenshot()\nend\n\nT['show_help()']['handles non-default mappings'] = function()\n  child.set_size(22, 60)\n  child.lua('MiniFiles.config.mappings.go_in = \"\"')\n  child.lua('MiniFiles.config.mappings.go_in_plus = \"l\"')\n\n  open(test_dir_path)\n  show_help()\n  child.expect_screenshot()\nend\n\nT['show_help()']['handles mappings without description'] = function()\n  child.set_size(22, 60)\n\n  open(test_dir_path)\n  child.lua([[vim.keymap.set('n', 'g.', '<Cmd>echo 1<CR>', { buffer = vim.api.nvim_get_current_buf() })]])\n  show_help()\n  child.expect_screenshot()\nend\n\nT['show_help()']['handles bookmarks'] = function()\n  child.set_size(30, 60)\n  open(test_dir_path)\n  local root = full_path(test_dir)\n  -- Relative (should use path as is)\n  set_bookmark('a', test_dir)\n  -- With description\n  set_bookmark('b', root .. '/common', { desc = 'Desc' })\n  -- Not normalized\n  set_bookmark('~', '~')\n  child.lua([[\n    -- Function without description (should be called and use output)\n    MiniFiles.set_bookmark('c', function() return '~/' end)\n    -- Function with description\n    MiniFiles.set_bookmark('d', vim.fn.getcwd, { desc = 'Cwd' })\n  ]])\n  -- Long description\n  set_bookmark('e', root .. '/nested', { desc = 'Should use these to adjust width' })\n\n  show_help()\n  child.expect_screenshot()\nend\n\nT['show_help()']['adjusts window width'] = function()\n  child.set_size(22, 60)\n  child.lua('MiniFiles.config.mappings.go_in = \"<C-l>\"')\n\n  open(test_dir_path)\n  show_help()\n  child.expect_screenshot()\nend\n\nT['show_help()']['works when no explorer is opened'] = function() expect.no_error(show_help) end\n\nT['show_help()'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.set_size(20, 40)\n\n  local validate = function(winborder)\n    child.o.winborder = winborder\n    open(test_dir_path)\n    show_help()\n    child.expect_screenshot()\n    close()\n  end\n\n  validate('rounded')\n\n  -- Should prefer explicitly configured value over 'winborder'\n  local au_id = child.lua([[\n    return vim.api.nvim_create_autocmd('User', {\n      pattern = 'MiniFilesWindowOpen',\n      callback = function(args)\n        local win_id = args.data.win_id\n        local config = vim.api.nvim_win_get_config(win_id)\n        config.border = 'double'\n        vim.api.nvim_win_set_config(win_id, config)\n      end,\n    })\n  ]])\n  validate('rounded')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.api.nvim_del_autocmd(au_id)\n  validate('+,-,+,|,+,-,+,|')\nend\n\nT['get_fs_entry()'] = new_set()\n\nlocal get_fs_entry = forward_lua('MiniFiles.get_fs_entry')\n\nT['get_fs_entry()']['works'] = function()\n  open(test_dir_path)\n  local buf_id = child.api.nvim_get_current_buf()\n\n  -- Directory\n  local dir_res = { fs_type = 'directory', name = '.a-dir', path = full_path(test_dir_path, '.a-dir') }\n  eq(get_fs_entry(buf_id, 1), dir_res)\n\n  -- - Should use current cursor line by default\n  eq(get_fs_entry(), dir_res)\n\n  -- - Should allow 0 as buffer id\n  eq(get_fs_entry(0, 1), dir_res)\n\n  -- File\n  local file_res = { fs_type = 'file', name = '.a-file', path = full_path(test_dir_path, '.a-file') }\n  eq(get_fs_entry(buf_id, 4), file_res)\n\n  -- User modified line. Should return \"original\" entry data (as long as\n  -- entry's path id is not modified)\n  set_cursor(4, 0)\n  type_keys('A', '111', '<Esc>')\n  eq(get_fs_entry(buf_id, 4), file_res)\n\n  -- User created line\n  type_keys('o', 'new_entry', '<Esc>')\n  eq(get_fs_entry(buf_id, 5), vim.NIL)\nend\n\nT['get_fs_entry()']['validates input'] = function()\n  expect.error(function() get_fs_entry() end, 'buf_id.*opened directory buffer')\n\n  open(test_dir_path)\n  expect.error(function() get_fs_entry(0, 1000) end, 'line.*valid line number in buffer %d')\nend\n\nT['get_explorer_state()'] = new_set()\n\nT['get_explorer_state()']['works'] = function()\n  child.cmd('belowright vertical split')\n  local ref_target_win = child.api.nvim_get_current_win()\n  local anchor = full_path(test_dir_path)\n\n  open(anchor)\n  local win_1 = child.api.nvim_get_current_win()\n  local path_2 = get_fs_entry().path\n  go_in()\n  local win_2 = child.api.nvim_get_current_win()\n\n  set_bookmark('a', anchor, { desc = 'Anchor' })\n\n  local ref_branch = { anchor, path_2 }\n  local ref_windows = { { win_id = win_1, path = anchor }, { win_id = win_2, path = path_2 } }\n  local ref_state = {\n    anchor = anchor,\n    bookmarks = { a = { path = anchor, desc = 'Anchor' } },\n    branch = ref_branch,\n    depth_focus = 2,\n    target_window = ref_target_win,\n    windows = ref_windows,\n  }\n  eq(get_explorer_state(), ref_state)\nend\n\nT['get_explorer_state()']['works with preview'] = function()\n  child.lua('MiniFiles.config.windows.preview = true')\n  local ref_target_win = child.api.nvim_get_current_win()\n  local anchor = full_path(test_dir_path)\n\n  open(anchor)\n  local win_cur = child.api.nvim_get_current_win()\n  local path_preview = get_fs_entry().path\n  local win_preview\n  for _, win_id in ipairs(child.api.nvim_list_wins()) do\n    if win_id ~= ref_target_win and win_id ~= win_cur then win_preview = win_id end\n  end\n\n  -- Should show preview as window entry\n  local ref_branch = { anchor, path_preview }\n  local ref_windows = { { win_id = win_cur, path = anchor }, { win_id = win_preview, path = path_preview } }\n  local ref_state = {\n    anchor = anchor,\n    bookmarks = {},\n    branch = ref_branch,\n    depth_focus = 1,\n    target_window = ref_target_win,\n    windows = ref_windows,\n  }\n  eq(get_explorer_state(), ref_state)\nend\n\nT['get_explorer_state()']['works when explorer is opened with file path'] = function()\n  child.lua('MiniFiles.config.windows.preview = true')\n  local file_full = full_path(test_file_path)\n  local file_parent_dir = file_full:gsub('[\\\\/][^\\\\/]-$', '')\n\n  open(file_full)\n  local state = get_explorer_state()\n\n  -- Anchor is always a directory path, parent directory of a file in this case\n  eq(state.anchor, file_parent_dir)\n\n  -- Should include file path in branch\n  eq(state.branch, { file_parent_dir, file_full })\n  eq(state.depth_focus, 1)\n\n  -- Should show file preview as window entry\n  eq(vim.tbl_map(function(x) return x.path end, state.windows), { file_parent_dir, file_full })\nend\n\nT['get_explorer_state()']['works when branch is not fully visible'] = function()\n  child.set_size(10, 40)\n  child.lua('MiniFiles.config.windows.width_focus = 35')\n\n  local test_path = make_test_path('nested')\n  open(test_path)\n  go_in()\n  go_in()\n\n  local ref_branch = { test_path, test_path .. '/dir-1', test_path .. '/dir-1/dir-11' }\n  local validate = function(depth_focus)\n    local state = get_explorer_state()\n    eq(state.branch, ref_branch)\n    eq(state.depth_focus, depth_focus)\n    eq(state.windows, { { win_id = child.api.nvim_get_current_win(), path = ref_branch[depth_focus] } })\n  end\n\n  validate(3)\n  go_out()\n  validate(2)\n  go_out()\n  validate(1)\nend\n\nT['get_explorer_state()']['returns copy of data'] = function()\n  open(test_dir_path)\n  local res = child.lua([[\n    local state = MiniFiles.get_explorer_state()\n    local ref = vim.deepcopy(state)\n    state.bookmarks.a, state.branch[1], state.windows[1].win_id = -1, -1, -1\n    local new_state = MiniFiles.get_explorer_state()\n    return vim.deep_equal(new_state, ref)\n  ]])\n  eq(res, true)\nend\n\nT['get_explorer_state()']['works when no explorer is opened'] = function() eq(get_explorer_state(), vim.NIL) end\n\nT['get_explorer_state()']['ensures valid target window'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  child.cmd('belowright vertical split')\n  local ref_win_id = child.api.nvim_get_current_win()\n\n  open(test_dir_path)\n\n  eq(get_explorer_state().target_window, ref_win_id)\n\n  child.api.nvim_win_close(ref_win_id, true)\n  eq(get_explorer_state().target_window, init_win_id)\nend\n\nT['set_target_window()'] = new_set()\n\nlocal set_target_window = forward_lua('MiniFiles.set_target_window')\n\nT['set_target_window()']['works'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  child.cmd('belowright vertical split')\n  local ref_win_id = child.api.nvim_get_current_win()\n\n  open(test_file_path)\n\n  eq(get_explorer_state().target_window, ref_win_id)\n  set_target_window(init_win_id)\n  eq(get_explorer_state().target_window, init_win_id)\n\n  go_in()\n  eq(is_file_in_buffer(child.api.nvim_win_get_buf(init_win_id), test_file_path), true)\nend\n\nT['set_target_window()']['validates input'] = function()\n  open(test_dir_path)\n  expect.error(function() set_target_window(1) end, 'valid window')\nend\n\nT['set_target_window()']['works when no explorer is opened'] = function()\n  expect.no_error(function() set_target_window(child.api.nvim_get_current_win()) end)\nend\n\nT['set_branch()'] = new_set()\n\nlocal set_branch = forward_lua('MiniFiles.set_branch')\nlocal get_branch = function() return child.lua_get('(MiniFiles.get_explorer_state() or {}).branch') end\nlocal get_depth_focus = function() return (get_explorer_state() or {}).depth_focus end\n\nT['set_branch()']['works'] = function()\n  child.set_size(12, 30)\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  child.lua('MiniFiles.config.windows.width_preview = 15')\n  open()\n\n  local path = full_path(test_dir_path)\n  set_branch({ path })\n  eq(get_branch(), { path })\n  eq(get_depth_focus(), 1)\n  child.expect_screenshot()\n\n  -- More than one path\n  set_branch({ path, path .. '/a-dir' })\n  eq(get_branch(), { path, path .. '/a-dir' })\n  -- - Should set default focus on deepest directory\n  eq(get_depth_focus(), 2)\n  -- - Should set full branch although it might not be visible fully\n  child.expect_screenshot()\n\n  -- - Changing instance width should show more of branch\n  child.set_size(12, 40)\n  child.expect_screenshot()\nend\n\nT['set_branch()']['works with file path in branch'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  child.lua('MiniFiles.config.windows.width_preview = 15')\n  child.set_size(12, 40)\n  local anchor = child.fn.getcwd()\n  open(anchor)\n\n  local real_dir = make_test_path('real')\n  set_branch({ real_dir, real_dir .. '/LICENSE' })\n  -- Width of 'LICENSE' window is `width_nofocus` because preview is disabled\n  child.expect_screenshot()\n  -- - Should show file preview even though preview is not enabled\n  eq(get_branch(), { real_dir, real_dir .. '/LICENSE' })\n  -- - Should set default focus on deepest directory\n  eq(get_depth_focus(), 1)\n  -- - Should position cursor on child entry\n  eq(get_fs_entry().name, 'LICENSE')\n\n  close()\n\n  -- Should use `width_preview` when preview is enabled\n  child.lua('MiniFiles.config.windows.preview = true')\n  open(anchor, false)\n  set_branch({ real_dir, real_dir .. '/LICENSE' })\n  child.expect_screenshot()\nend\n\nT['set_branch()']['works with preview'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  child.lua('MiniFiles.config.windows.width_preview = 15')\n  child.set_size(12, 40)\n  child.lua('MiniFiles.config.windows.preview = true')\n  open()\n\n  -- Preview should be applied after setting branch\n  local path = full_path(test_dir_path)\n  set_branch({ path })\n  eq(get_branch(), { path, get_fs_entry().path })\n  eq(get_depth_focus(), 1)\n  child.expect_screenshot()\nend\n\nT['set_branch()']['works with not absolute paths'] = function()\n  open()\n\n  -- Using `~` for home directory should be allowed\n  set_branch({ '~' })\n  eq(get_explorer_state().branch, { full_path(child.loop.os_homedir()) })\n\n  -- Relative paths should be resolved against current working directory\n  local nested = make_test_path('nested')\n  child.fn.chdir(nested)\n  set_branch({ '.', './dir-1' })\n  eq(get_explorer_state().branch, { nested, nested .. '/dir-1' })\n\n  -- The \"..\" should also be resolved (but supported only on Neovim>=0.10)\n  if child.fn.has('nvim-0.10') == 1 then\n    set_branch({ '..' })\n    eq(get_explorer_state().branch, { full_path(test_dir) })\n  end\nend\n\nT['set_branch()']['sets cursors on child entries'] = function()\n  child.set_size(12, 180)\n  local root = full_path(test_dir)\n  local root_parent = child.fn.fnamemodify(root, ':h')\n\n  open(root_parent)\n  local branch = { root, root .. '/nested', root .. '/nested/dir-1', root .. '/nested/dir-1/dir-12' }\n  set_branch(branch)\n  eq(get_branch(), branch)\n  eq(get_visible_paths(), branch)\n\n  local cursor_lines = vim.tbl_map(function(x)\n    local lnum = child.api.nvim_win_get_cursor(x.win_id)[1]\n    return child.fn.getbufline(child.api.nvim_win_get_buf(x.win_id), lnum)[1]:match('[\\\\/]([^\\\\/]+)$')\n  end, get_explorer_state().windows)\n  eq(cursor_lines, { 'nested', 'dir-1', 'dir-12', 'file-121' })\nend\n\nT['set_branch()']['respects previously set cursors'] = function()\n  local nested = make_test_path('nested')\n  local path = join_path(nested, 'dir-1')\n  open(path)\n  type_keys('G')\n  eq(child.fn.line('.'), 2)\n\n  -- Inside visible window\n  go_out()\n  eq(get_visible_paths(), { nested, path })\n  set_branch({ path })\n  eq(get_branch(), { path })\n  eq(child.fn.line('.'), 2)\n\n  -- Not inside visible window\n  go_out()\n  go_out()\n  type_keys('j')\n  eq(get_visible_paths(), { full_path(test_dir) })\n  set_branch({ path })\n  eq(get_branch(), { path })\n  eq(child.fn.line('.'), 2)\nend\n\nT['set_branch()']['respects `opts.depth_focus`'] = function()\n  open()\n  local path = full_path(test_dir_path)\n  local branch = { path, path .. '/a-dir', path .. '/a-dir/aa-file' }\n\n  local validate = function(depth_focus, ref_depth_focus)\n    set_branch(branch, { depth_focus = depth_focus })\n    eq(get_branch(), branch)\n    eq(get_depth_focus(), ref_depth_focus)\n  end\n\n  validate(1, 1)\n  eq(get_fs_entry().path, path .. '/a-dir')\n\n  -- Should normalize to fit in branch\n  validate(0, 1)\n  validate(-math.huge, 1)\n\n  -- - Maximum allowed depth is the depth of deepest directory\n  validate(10, 2)\n  validate(math.huge, 2)\n\n  -- - Fractional depth are allowed\n  validate(1.99, 1)\nend\n\nT['set_branch()']['works when no explorer is opened'] = function() eq(set_branch(full_path(test_dir_path)), vim.NIL) end\n\nT['set_branch()']['validates input'] = function()\n  open()\n  local validate = function(branch, opts, err_pattern)\n    expect.error(function() set_branch(branch, opts or {}) end, err_pattern)\n  end\n\n  validate(test_dir, nil, 'array')\n  validate({}, nil, 'at least one element')\n  validate({ -1 }, nil, 'not string.*%-1')\n  validate({ test_dir, -1 }, nil, 'not string.*%-1')\n\n  validate({ test_dir .. '/absent' }, nil, 'not present path.*/absent')\n  validate({ test_dir, test_dir .. '/absent' }, nil, 'not present path.*/absent')\n\n  validate({ test_dir .. '/common', test_dir }, nil, 'parent%-child')\n  validate({ test_dir, test_dir .. '/common/a-dir', test_dir .. '/common' }, nil, 'parent%-child')\n\n  validate({ full_path(test_file_path) }, nil, 'one directory')\nend\n\nT['set_bookmark()'] = new_set()\n\nT['set_bookmark()']['works'] = function()\n  open()\n  local root = full_path(test_dir)\n  local path_a, path_A, path_b = root, root .. '/common', root .. '/lua'\n  local path_c, path_d = root .. '/nested', root .. '/real'\n\n  set_bookmark('a', path_a)\n  -- Allows different cases\n  set_bookmark('A', path_A)\n  -- Same path under different id\n  set_bookmark('x', path_a)\n  -- Allows any single character\n  set_bookmark('~', '~')\n  -- Allows description\n  set_bookmark('b', path_b, { desc = 'Path b' })\n\n  -- Allows callable path\n  child.lua([[\n    local root = vim.fn.getcwd() .. '/tests/dir-files'\n    MiniFiles.set_bookmark('c', function() return root .. '/nested' end)\n    MiniFiles.set_bookmark('d', function() return root .. '/real' end, { desc = 'Path d' })\n  ]])\n\n  local res = child.lua([[\n    local bookmarks = MiniFiles.get_explorer_state().bookmarks\n    for k, v in pairs(bookmarks) do\n      if vim.is_callable(v.path) then\n        v.path = { 'Callable', (v.path():gsub('\\\\', '/'):gsub('^(%a):/+([^/])', '%1://%2')) }\n      end\n    end\n    return bookmarks\n  ]])\n\n  local ref = {\n    a = { path = path_a },\n    A = { path = path_A },\n    ['~'] = { path = '~' },\n    b = { path = path_b, desc = 'Path b' },\n    c = { path = { 'Callable', path_c } },\n    d = { path = { 'Callable', path_d }, desc = 'Path d' },\n    x = { path = path_a },\n  }\n  eq(res, ref)\n\n  -- Can override bookmarks\n  set_bookmark('a', path_b, { desc = 'Another path b' })\n  eq(child.lua_get('MiniFiles.get_explorer_state().bookmarks.a'), { path = path_b, desc = 'Another path b' })\nend\n\nT['set_bookmark()']['preserves path as is'] = function()\n  open()\n\n  -- Relative path\n  set_bookmark('a', test_dir)\n  eq(get_explorer_state().bookmarks.a, { path = test_dir })\n\n  -- Not normalized path\n  set_bookmark('b', test_dir .. '/common/')\n  eq(get_explorer_state().bookmarks.b, { path = test_dir .. '/common/' })\n\n  -- Path with `~` for home directory\n  set_bookmark('~', '~')\n  eq(get_explorer_state().bookmarks['~'], { path = '~' })\n\n  -- Callable\n  child.lua('MiniFiles.set_bookmark(\"c\", vim.fn.getcwd)')\n  eq(child.lua_get('MiniFiles.get_explorer_state().bookmarks.c.path()'), child.fn.getcwd())\nend\n\nT['set_bookmark()']['persists across restart/reset'] = function()\n  local path = full_path(test_dir_path)\n  open(path)\n  go_in()\n  set_bookmark('a', path .. '/a-dir')\n  local ref_bookmarks = get_explorer_state().bookmarks\n  eq(ref_bookmarks.a, { path = path .. '/a-dir' })\n\n  reset()\n  eq(get_explorer_state().bookmarks, ref_bookmarks)\n\n  -- Should preserve if opening explorer from history\n  close()\n  open(path, true)\n  eq(get_explorer_state().bookmarks, ref_bookmarks)\n  close()\n\n  -- Should NOT preserve if opening fresh explorer\n  open(path, false)\n  eq(get_explorer_state().bookmarks, {})\nend\n\nT['set_bookmark()']['works when no explorer is opened'] = function() eq(set_bookmark('a', test_dir), vim.NIL) end\n\nT['set_bookmark()']['validates input'] = function()\n  open()\n  local validate = function(id, path, opts, err_pattern)\n    expect.error(function() set_bookmark(id, path, opts) end, err_pattern)\n  end\n  local path = full_path(test_dir_path)\n  local path_file = full_path(test_file_path)\n\n  validate(1, path, nil, 'id.*character')\n  validate('aa', path, nil, 'id.*single')\n  validate('a', 1, nil, 'path.*valid')\n  validate('a', path_file, nil, 'path.*directory')\n  validate('a', path, { desc = 1 }, 'description.*string')\nend\n\nT['get_latest_path()'] = new_set()\n\nlocal get_latest_path = forward_lua('MiniFiles.get_latest_path')\n\nT['get_latest_path()']['works'] = function()\n  -- Initially should return `nil`\n  eq(get_latest_path(), vim.NIL)\n\n  -- Should be updated after `open`\n  open(test_dir_path)\n  eq(get_latest_path(), full_path(test_dir_path))\n\n  -- Should work after `close`\n  close()\n  eq(get_latest_path(), full_path(test_dir_path))\n\n  -- Should work per tabpage\n  child.cmd('tabedit')\n  eq(get_latest_path(), vim.NIL)\n\n  -- Should return parent path for file path (as it is anchor path)\n  local file_path = join_path(test_dir_path, 'a-file')\n  open(file_path)\n  eq(get_latest_path(), full_path(test_dir_path))\nend\n\nT['default_filter()'] = new_set()\n\nlocal default_filter = forward_lua('MiniFiles.default_filter')\n\nT['default_filter()']['works'] = function()\n  -- Should not filter anything out\n  eq(default_filter(test_fs_entries[1]), true)\nend\n\nT['default_sort()'] = new_set()\n\nlocal default_sort = forward_lua('MiniFiles.default_sort')\n\nT['default_sort()']['works'] = function()\n  local t = test_fs_entries\n  local fs_entries_shuffled = { t[1], t[7], t[6], t[3], t[5], t[2], t[4] }\n  eq(default_sort(fs_entries_shuffled), test_fs_entries)\nend\n\n-- Integration tests ==========================================================\nT['Windows'] = new_set()\n\nT['Windows']['reuses buffers for hidden directories'] = function()\n  open(test_dir_path)\n  go_in()\n  local buf_id_ref = child.api.nvim_get_current_buf()\n\n  -- Open another directory at this depth\n  go_out()\n  type_keys('j')\n  go_in()\n\n  -- Open again initial directory at this depth. Should reuse buffer.\n  go_out()\n  type_keys('k')\n  go_in()\n\n  eq(child.api.nvim_get_current_buf(), buf_id_ref)\nend\n\nT['Windows']['does not wrap content'] = function()\n  child.set_size(10, 20)\n  child.lua('MiniFiles.config.windows.width_focus = 10')\n  local temp_dir = make_temp_dir('temp', { 'a a a a a a a a a a', 'file' })\n\n  open(temp_dir)\n  child.expect_screenshot()\nend\n\nT['Windows']['correctly computes part of branch to show'] = function()\n  child.set_size(10, 80)\n\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n\n  open(make_test_path('nested'))\n  for _ = 1, 5 do\n    go_in()\n  end\n  child.expect_screenshot()\n\n  go_out()\n  child.expect_screenshot()\n  go_out()\n  child.expect_screenshot()\n  go_out()\n  child.expect_screenshot()\n  go_out()\n  child.expect_screenshot()\n  go_out()\n  child.expect_screenshot()\nend\n\nT['Windows']['correctly computes part of branch to show with preview'] = function()\n  child.set_size(10, 80)\n\n  child.lua('MiniFiles.config.windows.preview = true')\n  child.lua('MiniFiles.config.windows.width_preview = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  open(test_dir_path)\n  go_in()\n  child.expect_screenshot()\nend\n\nT['Windows']['is in sync with cursor'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n\n  open(make_test_path('nested'))\n  go_in()\n  go_in()\n  go_in()\n\n  -- No trimming when moving left-right\n  go_out()\n  child.expect_screenshot()\n  go_out()\n  go_out()\n  go_in()\n  child.expect_screenshot()\n\n  -- Trims everything to the right when going up-down\n  type_keys('j')\n  child.expect_screenshot()\n\n  -- Also trims if cursor is moved in Insert mode\n  go_out()\n  child.expect_screenshot()\n  type_keys('o')\n  child.expect_screenshot()\nend\n\nT['Windows']['reacts on `VimResized`'] = function()\n  open(test_dir_path)\n  go_in()\n\n  -- Decreasing width\n  child.o.columns = 60\n  child.expect_screenshot()\n\n  -- Increasing width\n  child.o.columns = 80\n  child.expect_screenshot()\n\n  -- Decreasing height\n  child.o.lines = 8\n  child.expect_screenshot()\n\n  -- Increasing height\n  child.o.lines = 15\n  child.expect_screenshot()\nend\n\nT['Windows']['works with too small dimensions'] = function()\n  child.set_size(8, 15)\n  open(test_dir_path)\n  child.expect_screenshot()\nend\n\nT['Windows']['respects tabline when computing position'] = function()\n  child.o.showtabline, child.o.tabline = 2, '%#TabLineSel#My tabline%#TabLineFill#'\n  open(test_dir_path)\n  child.expect_screenshot()\nend\n\nT['Windows']['respects tabline and statusline when computing height'] = function()\n  child.set_size(8, 60)\n  child.o.tabline = '%#TabLineSel#My tabline%#TabLineFill#'\n  child.o.statusline = 'My statusline'\n\n  local validate = function()\n    open(test_dir_path)\n    child.expect_screenshot()\n    close()\n  end\n\n  child.o.showtabline, child.o.laststatus = 2, 2\n  validate()\n\n  child.o.showtabline, child.o.laststatus = 0, 2\n  validate()\n\n  child.o.showtabline, child.o.laststatus = 2, 0\n  validate()\n\n  child.o.showtabline, child.o.laststatus = 0, 0\n  validate()\nend\n\nT['Windows']['uses correct UI highlight groups'] = function()\n  local validate_winhl_match = function(win_id, from_hl, to_hl)\n    local winhl = child.api.nvim_win_get_option(win_id, 'winhighlight')\n\n    -- Make sure entry is match in full\n    local base_pattern = from_hl .. ':' .. to_hl\n    local is_matched = winhl:find(base_pattern .. ',') ~= nil or winhl:find(base_pattern .. '$') ~= nil\n    eq(is_matched, true)\n  end\n\n  open(test_dir_path)\n  local win_id_1 = child.api.nvim_get_current_win()\n  go_in()\n  local win_id_2 = child.api.nvim_get_current_win()\n\n  validate_winhl_match(win_id_1, 'NormalFloat', 'MiniFilesNormal')\n  validate_winhl_match(win_id_1, 'FloatBorder', 'MiniFilesBorder')\n  validate_winhl_match(win_id_1, 'FloatTitle', 'MiniFilesTitle')\n  validate_winhl_match(win_id_1, 'CursorLine', 'MiniFilesCursorLine')\n  validate_winhl_match(win_id_2, 'NormalFloat', 'MiniFilesNormal')\n  validate_winhl_match(win_id_2, 'FloatBorder', 'MiniFilesBorder')\n  validate_winhl_match(win_id_2, 'FloatTitle', 'MiniFilesTitleFocused')\n  validate_winhl_match(win_id_2, 'CursorLine', 'MiniFilesCursorLine')\n\n  -- Simply going in Insert mode should not add \"modified\"\n  type_keys('i')\n  validate_winhl_match(win_id_1, 'FloatBorder', 'MiniFilesBorder')\n  validate_winhl_match(win_id_2, 'FloatBorder', 'MiniFilesBorder')\n\n  type_keys('x')\n  validate_winhl_match(win_id_1, 'FloatBorder', 'MiniFilesBorder')\n  validate_winhl_match(win_id_2, 'FloatBorder', 'MiniFilesBorderModified')\nend\n\nT['Windows']['uses correct content highlight groups'] = function()\n  open(test_dir_path)\n  --stylua: ignore\n  eq(\n    get_extmarks_hl(),\n    {\n      \"MiniFilesDirectory\", \"MiniFilesDirectory\",\n      \"MiniFilesDirectory\", \"MiniFilesDirectory\",\n      \"MiniFilesDirectory\", \"MiniFilesDirectory\",\n      \"MiniFilesFile\",      \"MiniFilesFile\",\n      \"MiniFilesFile\",      \"MiniFilesFile\",\n      \"MiniFilesFile\",      \"MiniFilesFile\",\n      \"MiniFilesFile\",      \"MiniFilesFile\",\n    }\n  )\nend\n\nT['Windows']['correctly highlight content during editing'] = function()\n  open(test_dir_path)\n  type_keys('C', 'new-dir', '<Esc>')\n  -- Highlighting of typed text should be the same as directories\n  -- - Move cursor away for cursorcolumn to not obstruct the view\n  type_keys('G')\n  child.expect_screenshot()\nend\n\nT['Windows']['always show cursor line in directories'] = function()\n  child.o.cursorline = false\n  child.o.cursorlineopt = 'number'\n  open(test_dir_path, false, { windows = { preview = true } })\n  child.expect_screenshot()\n  eq(child.wo.cursorlineopt, 'number,line')\n\n  -- File preview should not show cursor line\n  type_keys('G')\n  child.expect_screenshot()\n  close()\n\n  -- Should preserve flags of 'cursorlineopt' as much as possible\n  child.o.cursorlineopt = 'screenline'\n  open(test_dir_path)\n  eq(child.wo.cursorlineopt, 'screenline')\nend\n\nT['Windows']['can be closed manually'] = function()\n  open(test_dir_path)\n  type_keys('G', '<CR>')\n  child.cmd('wincmd l | only')\n  validate_n_wins(1)\n\n  open(test_dir_path)\n  validate_n_wins(2)\n\n  close(test_dir_path)\n  validate_n_wins(1)\n\n  open(test_dir_path)\n  child.cmd('quit!')\n  validate_n_wins(1)\n\n  open(test_dir_path)\n  validate_n_wins(2)\nend\n\nT['Windows']['never shows past end of buffer'] = function()\n  mock_confirm(1)\n\n  -- Modifying buffer in Insert mode\n  open(test_dir_path)\n  type_keys('G', 'o')\n  -- - Should increase height while first line still be visible\n  child.expect_screenshot()\n\n  child.ensure_normal_mode()\n  close()\n\n  -- Modifying buffer in Normal mode\n  open(test_dir_path)\n  type_keys('yj', 'G', 'p')\n  child.expect_screenshot()\n\n  close()\n\n  -- Works when top line is not first buffer line\n  child.set_size(10, 60)\n  open(test_dir_path)\n  type_keys('yj', 'G', 'p')\n  child.expect_screenshot()\nend\n\nT['Windows']['restricts manual buffer navigation'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Window and buffer pairing is available on Neovim>=0.10') end\n  child.api.nvim_create_buf(true, false)\n  open(test_dir_path)\n  validate_n_wins(2)\n  expect.error(function() child.cmd('bnext') end)\n  -- Attempting to switch buffer should keep explorer usable\n  expect.no_error(get_fs_entry)\nend\n\nT['Windows'][\"do not evaluate 'foldexpr' too much\"] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Correct behavior is only on Neovim>=0.10') end\n\n  child.lua('MiniFiles.config.windows.preview = true')\n  child.lua([[\n    _G.n = 0\n    _G.foldexpr_count = function() _G.n = _G.n + 1; return 0 end\n    vim.o.foldmethod = 'expr'\n    vim.o.foldexpr = 'v:lua.foldexpr_count()'\n  ]])\n  open(test_dir_path)\n\n  -- There still might be evaluations after `open()` because 'foldexpr' seems\n  -- to be executed even if buffer is not shown in any window\n  child.lua('_G.n = 0')\n  type_keys('j')\n  type_keys('k')\n  go_in()\n  go_out()\n  eq(child.lua_get('_G.n'), 0)\nend\n\nT['Windows'][\"respect 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.set_size(15, 40)\n\n  local validate = function(winborder)\n    child.o.winborder = winborder\n    open(test_dir_path)\n    child.expect_screenshot()\n    close()\n  end\n\n  validate('rounded')\n\n  -- Should prefer explicitly configured value over 'winborder'\n  local au_id = child.lua([[\n    return vim.api.nvim_create_autocmd('User', {\n      pattern = 'MiniFilesWindowOpen',\n      callback = function(args)\n        local win_id = args.data.win_id\n        local config = vim.api.nvim_win_get_config(win_id)\n        config.border = 'double'\n        vim.api.nvim_win_set_config(win_id, config)\n      end,\n    })\n  ]])\n  validate('rounded')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.api.nvim_del_autocmd(au_id)\n  validate('+,-,+,|,+,-,+,|')\nend\n\nT['Preview'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua('MiniFiles.config.windows.preview = true')\n      child.lua('MiniFiles.config.windows.width_focus = 25')\n    end,\n  },\n})\n\nT['Preview']['works for directories'] = function()\n  -- Should open preview right after `open()`\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  -- Should update preview after cursor move\n  type_keys('j')\n  child.expect_screenshot()\n\n  -- Should open preview right after `go_in()`\n  go_in()\n  child.expect_screenshot()\nend\n\nT['Preview']['works for files'] = function()\n  local expect_screenshot = function()\n    -- Test only on Neovim>=0.10 because there was major tree-sitter update\n    if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n  end\n\n  open(make_test_path('real'))\n\n  -- Should preview Lua file with highlighting\n  expect_screenshot()\n\n  -- Should preview text file (also with enabled highlighting but as there is\n  -- none defined, non should be visible)\n  type_keys('j')\n  expect_screenshot()\n\n  -- Should read only maximum necessary amount of lines\n  local buffers = child.api.nvim_list_bufs()\n  local buf_id = buffers[#buffers]\n  eq(#child.api.nvim_buf_get_lines(buf_id, 0, -1, false), child.o.lines)\n\n  -- Should not set filetype\n  eq(child.api.nvim_buf_get_option(buf_id, 'filetype'), 'minifiles')\n\n  -- Should recognize binary files and show placeholder preview\n  type_keys('j')\n  expect_screenshot()\n\n  -- Should work for empty files\n  type_keys('j')\n  expect_screenshot()\n\n  -- Should fall back to built-in syntax highlighting in case of no tree-sitter\n  type_keys('j')\n  expect_screenshot()\n\n  -- Should not error on files which failed to read (looks like on Windows it\n  -- can be different from \"non-readable\" files)\n  child.lua('vim.loop.fs_open = function() return nil end')\n  type_keys('j')\n  expect_screenshot()\nend\n\nT['Preview']['works with imaginary paths'] = function()\n  child.set_size(15, 60)\n  local temp_dir = make_temp_dir('temp', {})\n  open(temp_dir)\n\n  -- Should show preview for empty line\n  child.expect_screenshot()\n\n  -- Should still show preview window for files not (yet) on disk\n  type_keys('o')\n  child.expect_screenshot()\n  type_keys('n')\n  child.expect_screenshot()\n  -- Should update title as user types\n  type_keys('e')\n  child.expect_screenshot()\n  type_keys('w/')\n\n  -- Should update the title even if popup menu is shown\n  child.o.completeopt = 'menuone,noselect'\n  type_keys('<CR>', 'n', '<C-n>')\n  eq(child.fn.pumvisible() == 1, true)\n  type_keys('e')\n  child.expect_screenshot()\n\n  -- Should treat non-empty blank line as new file name\n  type_keys('<Esc>', 'o', ' ')\n  child.expect_screenshot()\n  type_keys('<C-u>', '<Esc>')\n\n  -- Should properly update to existing file preview after synchronization\n  mock_confirm(1)\n  synchronize()\n  validate_tree(temp_dir, { 'new/', 'ne' })\n  child.expect_screenshot()\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['Preview']['does not highlight big files'] = function()\n  local big_file = make_test_path('big.lua')\n  MiniTest.finally(function() child.fn.delete(big_file, 'rf') end)\n\n  -- Has limit per line\n  child.fn.writefile({ string.format('local a = \"%s\"', string.rep('a', 1000)) }, big_file)\n  open(big_file)\n  -- NOTE: there is no visible right pad because it got truncated by Neovim,\n  -- as 'MOCK_ROOT' doesn't account for initial truncation from left\n  child.expect_screenshot()\n  close()\n\n  -- It also should have total limit, but it is not tested to not overuse file\n  -- system accesses during test\nend\n\nT['Preview']['does not trigger unnecessary events'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Implemented on in Neovim>=0.10 for convenience') end\n\n  child.lua('_G.log = {}')\n  child.cmd('au BufEnter,BufLeave * lua table.insert(_G.log, \"unnecessary\")')\n\n  open(test_dir_path)\n  child.lua('_G.log = {}')\n\n  type_keys('j')\n  eq(#get_visible_paths(), 2)\n  eq(get_fs_entry().fs_type, 'directory')\n\n  type_keys('G')\n  eq(#get_visible_paths(), 2)\n  eq(get_fs_entry().fs_type, 'file')\n\n  -- Should not trigger buffer-related events when only moving up-down\n  eq(child.lua_get('#_G.log'), 0)\n\n  -- But should still trigger when changing windows/buffers\n  type_keys('gg')\n  go_in()\n  eq(#get_visible_paths(), 3)\n  eq(child.lua_get('#_G.log') > 0, true)\nend\n\nT['Preview']['is not removed when going out'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 15')\n  child.lua('MiniFiles.config.windows.width_preview = 15')\n\n  open(test_dir_path)\n\n  -- Directory preview\n  type_keys('j')\n  go_in()\n  go_out()\n  child.expect_screenshot()\n\n  -- File preview\n  go_in()\n  go_in()\n  go_out()\n  go_out()\n  child.expect_screenshot()\nend\n\nT['Preview']['reuses buffers'] = function()\n  -- Show two previews (for directory and file) and hide them\n  open(test_dir_path)\n  type_keys('G')\n  go_out()\n  local all_buffers = child.api.nvim_list_bufs()\n  trim_left()\n\n  -- Show them again which should use same buffers\n  go_in()\n  type_keys('gg')\n  eq(all_buffers, child.api.nvim_list_bufs())\nend\n\nT['Preview']['is not shown if not enough space'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 50')\n  child.set_size(15, 60)\n  open(test_dir_path)\n  child.expect_screenshot()\nend\n\nT['Preview']['previews only one level deep'] = function()\n  child.set_size(10, 80)\n\n  open(make_test_path('nested'))\n  child.expect_screenshot()\nend\n\nT['Preview']['works after `trim_left()`'] = function()\n  child.set_size(10, 80)\n\n  open(make_test_path('nested'))\n  go_in()\n  trim_left()\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['Preview']['does not result in flicker'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 50')\n  -- Exact width is important: it is just enough to fit focused (52) and two\n  -- non-focused (17+17) windows which was the computed visible range range\n  child.set_size(10, 86)\n  child.lua([[\n    _G.get_visible_bufs = function()\n      local res = {}\n      for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do\n        table.insert(res, vim.api.nvim_win_get_buf(win_id))\n      end\n      table.sort(res)\n      return res\n    end\n  ]])\n\n  open(test_dir)\n  child.lua([[\n    MiniFiles.go_in()\n    MiniFiles.go_in()\n    _G.visible_bufs = _G.get_visible_bufs()\n  ]])\n\n  -- State shown initially should be the same as after some time has passed\n  sleep(small_time)\n  eq(child.lua_get('_G.visible_bufs'), child.lua_get('_G.get_visible_bufs()'))\nend\n\nT['Preview']['always updates with cursor'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 50')\n  -- Exact width is important: it is just enough to fit focused (52) and two\n  -- non-focused (17+17) windows which was the computed visible range range\n  child.set_size(10, 86)\n  open(test_dir)\n  go_in()\n  go_in()\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['Preview']['can work after renaming with small overall width'] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_preview = 15')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n  child.set_size(10, 54)\n\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/nested/', 'dir/nested/nested-2/', 'dir/nested/nested-2/file' })\n  open(temp_dir)\n  go_in()\n  go_in()\n  go_in()\n  type_keys('C', 'new-file', '<Esc>')\n  -- - At this point there is a preview active but for a path with soon to be\n  --   outdated basename\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\nend\n\nT['Preview'][\"respects global value of 'list' and 'listchars' option\"] = function()\n  child.lua('MiniFiles.config.windows.width_focus = 10')\n  child.lua('MiniFiles.config.windows.width_preview = 8')\n\n  local temp_dir = make_temp_dir('temp', { 'long-directory-name/', 'long-directory-name/subfile', 'file' })\n  child.fn.writefile({ '\\tTabs', '    Spaces' }, join_path(temp_dir, 'file'))\n\n  child.o.listchars = 'tab:+ ,extends:>'\n  child.o.tabstop = 4\n\n  local validate = function(list)\n    child.o.list = list\n    open(temp_dir)\n    child.expect_screenshot()\n    type_keys('<Down>')\n    child.expect_screenshot()\n    close()\n  end\n\n  validate(true)\n  validate(false)\nend\n\nT['Mappings'] = new_set()\n\nT['Mappings']['`close` works'] = function()\n  -- Default\n  open(test_dir_path)\n  eq(is_explorer_active(), true)\n  type_keys('q')\n  eq(is_explorer_active(), false)\n  close()\n\n  -- User-supplied\n  open(test_dir_path, false, { mappings = { close = 'Q' } })\n  eq(is_explorer_active(), true)\n  type_keys('Q')\n  eq(is_explorer_active(), false)\n  close()\n\n  -- Empty\n  open(test_dir_path, false, { mappings = { close = '' } })\n  eq(is_explorer_active(), true)\n  -- - Needs second `q` to unblock child process after built-in `q`\n  type_keys('q', 'q')\n  eq(is_explorer_active(), true)\nend\n\nT['Mappings']['`go_in` works'] = function()\n  -- Default\n  open(test_dir_path)\n  validate_n_wins(2)\n  type_keys('l')\n  child.expect_screenshot()\n  close()\n\n  -- User-supplied\n  open(test_dir_path, false, { mappings = { go_in = 'Q' } })\n  validate_n_wins(2)\n  type_keys('Q')\n  validate_n_wins(3)\n  close()\n\n  -- Empty\n  open(test_dir_path, false, { mappings = { go_in = '' } })\n  validate_n_wins(2)\n  type_keys('l')\n  validate_n_wins(2)\nend\n\nT['Mappings']['`go_in` works in linewise Visual mode'] = function()\n  local has_opened_buffer = function(name)\n    local path = join_path(test_dir_path, name)\n    for _, buf_id in ipairs(child.api.nvim_list_bufs()) do\n      if is_file_in_buffer(buf_id, path) then return true end\n    end\n    return false\n  end\n\n  -- Should open all files\n  open(test_dir_path)\n  set_cursor(4, 0)\n  type_keys('V', '2j')\n\n  type_keys('l')\n  eq(has_opened_buffer('.a-file'), true)\n  eq(has_opened_buffer('a-file'), true)\n  eq(has_opened_buffer('A-file-2'), true)\n  -- - Should go back in Normal mode\n  eq(child.fn.mode(), 'n')\n\n  -- Should go in only last directory with cursor moved to its entry\n  set_cursor(3, 0)\n  type_keys('V', 'k')\n  child.expect_screenshot()\n\n  type_keys('l')\n  child.expect_screenshot()\n  eq(child.fn.mode(), 'n')\n\n  -- Should work when selection contains both files and directories\n  -- Cursor in initial window still should be moved to target entry\n  close()\n  child.cmd('%bwipeout')\n\n  open(test_dir_path, false)\n  set_cursor(3, 0)\n  type_keys('V', 'j')\n\n  type_keys('l')\n  child.expect_screenshot()\n  eq(has_opened_buffer('.a-file'), true)\n  eq(child.fn.mode(), 'n')\nend\n\nT['Mappings']['`go_in` ignores non-linewise Visual mode'] = function()\n  local validate = function(mode_key)\n    open(test_dir_path, false)\n    validate_n_wins(2)\n\n    type_keys(mode_key, 'l')\n    validate_n_wins(2)\n    eq(child.fn.mode(), mode_key)\n\n    child.ensure_normal_mode()\n    close()\n  end\n\n  validate('v')\n  -- '\\22' is an escaped version of `<C-v>`\n  validate('\\22')\nend\n\nT['Mappings']['`go_in` supports <count>'] = function()\n  child.set_size(15, 60)\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n\n  open(make_test_path('nested'))\n  type_keys('2l')\n  child.expect_screenshot()\n\n  close()\n\n  -- Works with high values ending at file\n  open(test_dir_path)\n  type_keys('10l')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`go_in_plus` works'] = function()\n  -- On directories should be the same as `go_in`\n  -- Default\n  open(test_dir_path)\n  validate_n_wins(2)\n  type_keys('L')\n  child.expect_screenshot()\n  close()\n\n  -- User-supplied\n  open(test_dir_path, false, { mappings = { go_in_plus = 'Q' } })\n  validate_n_wins(2)\n  type_keys('Q')\n  validate_n_wins(3)\n  close()\n\n  -- Empty\n  open(test_dir_path, false, { mappings = { go_in_plus = '' } })\n  validate_n_wins(2)\n  type_keys('L')\n  validate_n_wins(2)\nend\n\nT['Mappings']['`go_in_plus` works on files'] = function()\n  open(test_file_path)\n  validate_n_wins(2)\n\n  -- Should open file and close explorer\n  type_keys('L')\n  validate_n_wins(1)\n  eq(is_file_in_buffer(0, test_file_path), true)\nend\n\nT['Mappings']['`go_in_plus` works on non-path entry'] = function()\n  local temp_dir = make_temp_dir('temp', {})\n  open(temp_dir)\n\n  -- Empty line\n  type_keys('L')\n  eq(child.api.nvim_get_mode().blocking, false)\n\n  -- Non-empty line\n  type_keys('i', 'new-entry', '<Esc>')\n  type_keys('L')\n  eq(child.api.nvim_get_mode().blocking, false)\nend\n\nT['Mappings']['`go_in_plus` supports <count>'] = function()\n  child.set_size(10, 50)\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n\n  open(make_test_path('nested'))\n  type_keys('2L')\n  child.expect_screenshot()\n\n  close()\n\n  -- Works with high values ending at file\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  child.fn.writefile({ 'Temp file' }, join_path(temp_dir, 'file'))\n  open(temp_dir)\n  type_keys('10L')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`go_out` works'] = function()\n  local path = make_test_path('common', 'a-dir')\n\n  -- Default\n  open(path)\n  validate_n_wins(2)\n  type_keys('h')\n  child.expect_screenshot()\n  close()\n\n  -- User-supplied\n  open(path, false, { mappings = { go_out = 'Q' } })\n  validate_n_wins(2)\n  type_keys('Q')\n  validate_n_wins(3)\n  close()\n\n  -- Empty\n  open(path, false, { mappings = { go_out = '' } })\n  validate_n_wins(2)\n  type_keys('h')\n  validate_n_wins(2)\nend\n\nT['Mappings']['`go_out` supports <count>'] = function()\n  child.set_size(10, 70)\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n\n  open(make_test_path('nested', 'dir-1', 'dir-11'))\n  go_in()\n  go_in()\n  child.expect_screenshot()\n\n  type_keys('2h')\n  child.expect_screenshot()\n  type_keys('2h')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`go_out_plus` works'] = function()\n  local path = make_test_path('common', 'a-dir')\n\n  -- Default\n  open(path)\n  validate_n_wins(2)\n  type_keys('H')\n  child.expect_screenshot()\n  close()\n\n  -- User-supplied\n  open(path, false, { mappings = { go_out_plus = 'Q' } })\n  validate_n_wins(2)\n  type_keys('Q')\n  child.expect_screenshot()\n  close()\n\n  -- Empty\n  open(path, false, { mappings = { go_out_plus = '' } })\n  validate_n_wins(2)\n  type_keys('H')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`go_out_plus` supports <count>'] = function()\n  child.set_size(10, 70)\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  child.lua('MiniFiles.config.windows.width_nofocus = 10')\n\n  open(make_test_path('nested', 'dir-1', 'dir-11'))\n  go_in()\n  go_in()\n  child.expect_screenshot()\n\n  type_keys('2H')\n  child.expect_screenshot()\n  type_keys('2H')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`mark_goto` works'] = function()\n  local validate_log = function(ref_log)\n    eq(child.lua_get('_G.notify_log'), ref_log)\n    child.lua('_G.notify_log = {}')\n  end\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n\n  local path = full_path(test_dir_path)\n  local mark_path = path .. '/a-dir'\n  open(path)\n  set_bookmark('a', mark_path)\n  go_out()\n  expect.no_equality(get_branch(), { mark_path })\n  type_keys(\"'\", 'a')\n  eq(get_branch(), { mark_path })\n  -- - Should show no notifications\n  validate_log({})\n\n  -- Warns about not existing bookmark id\n  go_out()\n  local ref_branch = get_branch()\n  type_keys(\"'\", 'x')\n  eq(get_branch(), ref_branch)\n  validate_log({ { '(mini.files) No bookmark with id \"x\"', warn_level } })\n\n  -- Does nothing (silently) after `<Esc>` or `<C-c>`\n  type_keys(\"'\", '<Esc>')\n  eq(get_branch(), ref_branch)\n  validate_log({})\n  type_keys(\"'\", '<C-c>')\n  eq(get_branch(), ref_branch)\n  validate_log({})\n\n  close()\n\n  -- User-supplied\n  open(path, false, { mappings = { mark_goto = '`' } })\n  set_bookmark('a', mark_path)\n  go_out()\n  type_keys('`', 'a')\n  eq(get_branch(), { mark_path })\n  close()\n\n  -- Empty\n  open(path, false, { mappings = { mark_goto = '' } })\n  set_bookmark('a', mark_path)\n  go_out()\n  expect.error(function() type_keys(\"'\", 'a') end, 'E20')\nend\n\nT['Mappings'][\"`mark_goto` automatically sets `'` bookmark\"] = function()\n  local get_cur_path = function()\n    local state = get_explorer_state()\n    return state.branch[state.depth_focus]\n  end\n\n  local path = full_path(test_dir_path)\n  local mark_path = path .. '/a-dir'\n  open(path)\n  set_bookmark('a', mark_path)\n\n  go_out()\n  local path_before_jump = get_cur_path()\n  eq(get_explorer_state().bookmarks[\"'\"], nil)\n  type_keys(\"'\", 'a')\n  eq(get_branch(), { mark_path })\n  eq(get_explorer_state().bookmarks[\"'\"], { desc = 'Before latest jump', path = path_before_jump })\n\n  type_keys(\"'\", \"'\")\n  eq(get_branch(), { path_before_jump })\n  eq(get_explorer_state().bookmarks[\"'\"], { desc = 'Before latest jump', path = mark_path })\nend\n\nT['Mappings']['`mark_goto` works with special paths'] = function()\n  local validate_log = function(ref_log)\n    eq(child.lua_get('_G.notify_log'), ref_log)\n    child.lua('_G.notify_log = {}')\n  end\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n  local cwd = normalize_path(child.fn.getcwd())\n\n  local path = full_path(test_dir_path)\n  open(path)\n\n  -- Relative paths (should be resolved against cwd, not currently focused)\n  local path_rel = test_dir_path .. '/a-dir'\n  set_bookmark('a', path_rel)\n  type_keys(\"'\", 'a')\n  eq(get_branch(), { full_path(path_rel) })\n\n  -- Involving '~'\n  set_bookmark('~', '~')\n  type_keys(\"'\", '~')\n  expect.no_equality(get_branch(), { full_path(path_rel) })\n  validate_log({})\n\n  -- Function paths\n  child.lua([[MiniFiles.set_bookmark('b', vim.fn.getcwd)]])\n  type_keys(\"'\", 'b')\n  eq(get_branch(), { cwd })\n\n  -- Not existing on disk\n  child.lua([[MiniFiles.set_bookmark('c', function() return vim.fn.getcwd() .. '/not-present' end)]])\n  type_keys(\"'\", 'c')\n  eq(get_branch(), { cwd })\n  validate_log({ { '(mini.files) Bookmark path should be a valid path to directory', warn_level } })\n\n  -- Not directory path\n  child.lua('_G.file_path = ' .. vim.inspect(full_path(test_file_path)))\n  child.lua([[MiniFiles.set_bookmark('d', function() return _G.file_path end)]])\n  type_keys(\"'\", 'd')\n  eq(get_branch(), { cwd })\n  validate_log({ { '(mini.files) Bookmark path should be a valid path to directory', warn_level } })\nend\n\nT['Mappings']['`mark_set` works'] = function()\n  local path = full_path(test_dir_path)\n  open(path)\n  local mark_path = get_fs_entry().path\n  go_in()\n  type_keys('m', 'a')\n  local ref_bookmarks = { a = { path = mark_path } }\n  eq(get_explorer_state().bookmarks, ref_bookmarks)\n\n  -- - Should show notification\n  local info_level = child.lua_get('vim.log.levels.INFO')\n  eq(child.lua_get('_G.notify_log'), { { '(mini.files) Bookmark \"a\" is set', info_level } })\n\n  -- Does nothing after `<Esc>` or `<C-c>`\n  type_keys('m', '<Esc>')\n  eq(get_explorer_state().bookmarks, ref_bookmarks)\n  type_keys('m', '<C-c>')\n  eq(get_explorer_state().bookmarks, ref_bookmarks)\n\n  close()\n\n  -- User-supplied\n  open(path, false, { mappings = { mark_set = 'M' } })\n  go_in()\n  type_keys('M', 'a')\n  eq(get_explorer_state().bookmarks, ref_bookmarks)\n  close()\n\n  -- Empty\n  open(path, false, { mappings = { mark_set = '' } })\n  go_in()\n  type_keys('m', 'a')\n  eq(get_explorer_state().bookmarks, {})\nend\n\nT['Mappings']['`reset` works'] = function()\n  local prepare = function(...)\n    close()\n    open(...)\n    type_keys('j')\n    go_in()\n    validate_n_wins(3)\n  end\n\n  -- Default\n  prepare(test_dir_path)\n  type_keys('<BS>')\n  child.expect_screenshot()\n\n  -- User-supplied\n  prepare(test_dir_path, false, { mappings = { reset = 'Q' } })\n  type_keys('Q')\n  child.expect_screenshot()\n\n  -- Empty\n  prepare(test_dir_path, false, { mappings = { reset = '' } })\n  type_keys('<BS>')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`reveal_cwd` works'] = function()\n  child.set_size(10, 80)\n\n  child.lua('MiniFiles.config.windows.width_focus = 20')\n  local nested_path = make_test_path('nested')\n  child.fn.chdir(nested_path)\n\n  local prepare = function(...)\n    close()\n    open(...)\n    go_in()\n    go_in()\n    trim_left()\n  end\n\n  -- Default\n  prepare(nested_path)\n  type_keys('@')\n  child.expect_screenshot()\n\n  -- User-supplied\n  prepare(nested_path, false, { mappings = { reveal_cwd = 'Q' } })\n  type_keys('Q')\n  child.expect_screenshot()\n\n  -- Empty\n  prepare(nested_path, false, { mappings = { reveal_cwd = '' } })\n  -- - Follow up `@` with register name to avoid blocking child process\n  type_keys('@', 'a')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`show_help` works'] = function()\n  child.set_size(22, 60)\n\n  -- Default\n  open(test_dir_path)\n  type_keys('g?')\n  child.expect_screenshot()\n  type_keys('q')\n  close()\n\n  -- User-supplied\n  open(test_dir_path, false, { mappings = { show_help = 'Q' } })\n  type_keys('Q')\n  child.expect_screenshot()\n  type_keys('q')\n  close()\n\n  -- Empty\n  open(test_dir_path, false, { mappings = { show_help = '' } })\n  type_keys('g?')\n  child.expect_screenshot()\nend\n\nT['Mappings']['`synchronize` works'] = function()\n  child.set_size(10, 60)\n\n  local temp_dir = make_temp_dir('temp', {})\n  local validate = function(file_name, key)\n    child.expect_screenshot()\n    child.fn.writefile({}, join_path(temp_dir, file_name))\n    type_keys(key)\n    child.expect_screenshot()\n  end\n\n  -- Default\n  open(temp_dir)\n  validate('file-1', '=')\n  close()\n\n  -- User-supplied\n  open(temp_dir, false, { mappings = { synchronize = 'Q' } })\n  validate('file-2', 'Q')\n  close()\n\n  -- Empty\n  open(temp_dir, false, { mappings = { synchronize = '' } })\n  validate('file-3', '=')\nend\n\nT['Mappings']['`trim_left` works'] = function()\n  -- Default\n  open(test_dir_path)\n  go_in()\n  validate_n_wins(3)\n  type_keys('<')\n  child.expect_screenshot()\n  close()\n\n  -- User-supplied\n  open(test_dir_path, false, { mappings = { trim_left = 'Q' } })\n  go_in()\n  validate_n_wins(3)\n  type_keys('Q')\n  validate_n_wins(2)\n  close()\n\n  -- Empty\n  open(test_dir_path, false, { mappings = { trim_left = '' } })\n  go_in()\n  validate_n_wins(3)\n  type_keys('<')\n  validate_n_wins(3)\nend\n\nT['Mappings']['`trim_right` works'] = function()\n  local path = make_test_path('common', 'a-dir')\n\n  -- Default\n  open(path)\n  go_out()\n  validate_n_wins(3)\n  type_keys('>')\n  child.expect_screenshot()\n  close()\n\n  -- User-supplied\n  open(path, false, { mappings = { trim_right = 'Q' } })\n  go_out()\n  validate_n_wins(3)\n  type_keys('Q')\n  validate_n_wins(2)\n  close()\n\n  -- Empty\n  open(path, false, { mappings = { trim_right = '' } })\n  go_out()\n  validate_n_wins(3)\n  type_keys('>')\n  validate_n_wins(3)\nend\n\nT['File manipulation'] = new_set()\n\nT['File manipulation']['can create'] = function()\n  child.set_size(10, 60)\n  local temp_dir = make_temp_dir('temp', {})\n  open(temp_dir)\n\n  set_lines({ 'new-file', 'new-dir/' })\n  set_cursor(1, 0)\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'new-file', 'new-dir/' })\n\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n  validate_confirm_args('  CREATE │ new%-file %(file%)')\n  validate_confirm_args('  CREATE │ new%-dir %(directory%)')\nend\n\nT['File manipulation']['create does not override existing entry'] = function()\n  child.set_size(10, 60)\n\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/', 'dir/subfile' })\n  local file_path = join_path(temp_dir, 'file')\n  child.fn.writefile({ 'File' }, file_path)\n\n  open(temp_dir)\n  type_keys('o', 'file', '<CR>', 'dir/', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/subfile', 'file' })\n  validate_file_content(file_path, { 'File' })\n\n  -- Should show warning\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n  local ref_log = {\n    { '(mini.files) Can not create ' .. file_path .. '. Target path already exists.', warn_level },\n    { '(mini.files) Can not create ' .. temp_dir .. '/dir/. Target path already exists.', warn_level },\n  }\n  eq(child.lua_get('_G.notify_log'), ref_log)\nend\n\nT['File manipulation']['creates files in nested directories'] = function()\n  child.set_size(10, 60)\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  open(temp_dir)\n\n  local lines = get_lines()\n  -- Should work both in present directories and new ones (creating them)\n  lines = vim.list_extend(lines, { 'dir/nested-file', 'dir-1/nested-file-1', 'dir-1/nested-file-2' })\n  set_lines(lines)\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/nested-file', 'dir-1/', 'dir-1/nested-file-1', 'dir-1/nested-file-2' })\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n\n  -- - Should show paths relative to directory where manipulation was registered\n  validate_confirm_args('  CREATE │ dir/nested%-file %(file%)')\n  validate_confirm_args('  CREATE │ dir%-1/nested%-file%-1 %(file%)')\n  validate_confirm_args('  CREATE │ dir%-1/nested%-file%-2 %(file%)')\nend\n\nT['File manipulation']['creates nested directories'] = function()\n  child.set_size(10, 60)\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  open(temp_dir)\n\n  local lines = get_lines()\n  -- Should work both in present directories and new ones (creating them)\n  lines = vim.list_extend(lines, { 'dir/nested-dir/', 'dir-1/nested-dir-1/', 'dir-1/nested-dir-2/' })\n  set_lines(lines)\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/nested-dir/', 'dir-1/', 'dir-1/nested-dir-1/', 'dir-1/nested-dir-2/' })\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n\n  -- - Should show paths relative to directory where manipulation was registered\n  validate_confirm_args('  CREATE │ dir/nested%-dir %(directory%)')\n  validate_confirm_args('  CREATE │ dir%-1/nested%-dir%-1 %(directory%)')\n  validate_confirm_args('  CREATE │ dir%-1/nested%-dir%-2 %(directory%)')\nend\n\nT['File manipulation']['can delete'] = function()\n  local entries = { 'file', 'empty-dir/', 'dir/', 'dir/file', 'dir/nested-dir/', 'dir/nested-dir/file' }\n  local temp_dir = make_temp_dir('temp', entries)\n  child.cmd('edit ' .. (temp_dir .. '/file'))\n  local buf_id = child.api.nvim_get_current_buf()\n  local buf_name = child.api.nvim_buf_get_name(buf_id)\n\n  open(temp_dir)\n\n  set_lines({})\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, {})\n  -- - Should not affect the buffer for deleted file (allows restoring it)\n  eq(child.api.nvim_buf_get_name(buf_id), buf_name)\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n\n  validate_confirm_args('  DELETE │ dir %(permanently%)')\n  validate_confirm_args('  DELETE │ empty%-dir %(permanently%)')\n  validate_confirm_args('  DELETE │ file %(permanently%)')\nend\n\nT['File manipulation']['delete respects `options.permanent_delete`'] = function()\n  child.set_size(10, 60)\n\n  -- Mock `stdpath()`\n  local data_dir = mock_stdpath_data()\n  local trash_dir = join_path(data_dir, 'mini.files', 'trash')\n\n  -- Create temporary data, open file from it, and delete it\n  child.lua('MiniFiles.config.options.permanent_delete = false')\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/', 'dir/subfile' })\n  child.cmd('edit ' .. (temp_dir .. '/file'))\n  local buf_id = child.api.nvim_get_current_buf()\n  local buf_name = child.api.nvim_buf_get_name(buf_id)\n\n  open(temp_dir)\n\n  type_keys('VGd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should move into special trash directory\n  validate_tree(temp_dir, {})\n  validate_tree(trash_dir, { 'file', 'dir/', 'dir/subfile' })\n\n  validate_confirm_args('  DELETE │ file %(to trash%)')\n  validate_confirm_args('  DELETE │ dir %(to trash%)')\n\n  -- - Should not affect the buffer for moved to trash file (similar to regular\n  --   \"delete\" action and avoids triggering autocommands).\n  eq(child.api.nvim_buf_get_name(buf_id), buf_name)\n\n  -- Deleting entries again with same name should replace previous ones\n  -- - Recreate previously deleted entries with different content\n  child.fn.writefile({ 'New file' }, join_path(temp_dir, 'file'))\n  child.fn.mkdir(join_path(temp_dir, 'dir'))\n  child.fn.writefile({ 'New subfile' }, join_path(temp_dir, 'dir', 'subfile'))\n\n  mock_confirm(1)\n  synchronize()\n\n  -- - Delete again\n  type_keys('VGd')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, {})\n  validate_tree(trash_dir, { 'dir/', 'dir/subfile', 'file' })\n\n  -- - Check that files actually were replaced\n  validate_file_content(join_path(trash_dir, 'file'), { 'New file' })\n  validate_file_content(join_path(trash_dir, 'dir', 'subfile'), { 'New subfile' })\nend\n\nT['File manipulation']['can move to trash across devices'] = function()\n  child.set_size(10, 60)\n\n  local data_dir = mock_stdpath_data()\n  local trash_dir = join_path(data_dir, 'mini.files', 'trash')\n  child.lua('MiniFiles.config.options.permanent_delete = false')\n\n  -- Mock `vim.loop.fs_rename()` not working across devices/volumes/partitions\n  child.lua('vim.loop.fs_rename = function() return nil, \"EXDEV: cross-device link not permitted:\", \"EXDEV\" end')\n\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/', 'dir/nested/', 'dir/nested/file' })\n  open(temp_dir)\n\n  -- Write lines in moved files to check \"copy-delete\" and not \"create-delete\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n  child.fn.writefile({ 'File nested' }, join_path(temp_dir, 'dir', 'nested', 'file'))\n\n  type_keys('dG')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, {})\n  validate_tree(trash_dir, { 'dir/', 'dir/nested/', 'dir/nested/file', 'file' })\n\n  validate_file_content(join_path(trash_dir, 'file'), { 'File' })\n  validate_file_content(join_path(trash_dir, 'dir', 'nested', 'file'), { 'File nested' })\nend\n\nT['File manipulation']['can rename'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/' })\n  open(temp_dir)\n\n  type_keys('C', 'new-dir', '<Esc>')\n  type_keys('j', 'A', '-new', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'file-new', 'new-dir/' })\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n\n  validate_confirm_args('  RENAME │ dir => new%-dir')\n  validate_confirm_args('  RENAME │ file => file%-new')\nend\n\nT['File manipulation']['rename does not override existing entry'] = function()\n  child.set_size(10, 60)\n\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir-2/', 'file', 'file-2' })\n  open(temp_dir)\n  child.expect_screenshot()\n\n  type_keys('A', '-2', '<Esc>')\n  type_keys('2j', 'A', '-2', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  -- Should show warning\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n  local ref_log = {\n    { '(mini.files) Can not move or rename ' .. temp_dir .. '/dir. Target path already exists.', warn_level },\n    { '(mini.files) Can not move or rename ' .. temp_dir .. '/file. Target path already exists.', warn_level },\n  }\n  eq(child.lua_get('_G.notify_log'), ref_log)\nend\n\nT['File manipulation']['rename file renames opened buffers'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file' })\n\n  local file_path_prev = join_path(temp_dir, 'file')\n  child.cmd('edit ' .. file_path_prev)\n  local buf_id = child.api.nvim_get_current_buf()\n\n  open(temp_dir)\n  type_keys('C', 'new-file', '<Esc>')\n\n  eq(is_file_in_buffer(buf_id, file_path_prev), true)\n\n  mock_confirm(1)\n  synchronize()\n  eq(is_file_in_buffer(buf_id, join_path(temp_dir, 'new-file')), true)\n\n  -- Should open path in relative form for nicer `:buffers`\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]tests/dir%-files/temp/new%-file')\nend\n\nT['File manipulation']['rename directory renames opened buffers'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/nested/', 'dir/nested/file-2' })\n\n  local file_path_prev = join_path(temp_dir, 'dir', 'file')\n  child.cmd('edit ' .. file_path_prev)\n  local file_buf_id = child.api.nvim_get_current_buf()\n\n  local descendant_path_prev = join_path(temp_dir, 'dir', 'nested', 'file-2')\n  child.cmd('edit ' .. descendant_path_prev)\n  local descendant_buf_id = child.api.nvim_get_current_buf()\n\n  open(temp_dir)\n  type_keys('C', 'new-dir', '<Esc>')\n\n  eq(is_file_in_buffer(file_buf_id, file_path_prev), true)\n  eq(is_file_in_buffer(descendant_buf_id, descendant_path_prev), true)\n\n  mock_confirm(1)\n  synchronize()\n  eq(is_file_in_buffer(file_buf_id, join_path(temp_dir, 'new-dir', 'file')), true)\n  eq(is_file_in_buffer(descendant_buf_id, join_path(temp_dir, 'new-dir', 'nested', 'file-2')), true)\nend\n\nT['File manipulation']['renames even if lines are rearranged'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file-1', 'file-2' })\n  open(temp_dir)\n\n  -- Rearrange lines\n  type_keys('dd', 'p')\n\n  type_keys('gg', 'C', 'new-file-2', '<Esc>')\n  type_keys('j^', 'C', 'new-file-1', '<Esc>')\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_confirm_args('RENAME │ file%-2 => new%-file%-2')\n  validate_confirm_args('RENAME │ file%-1 => new%-file%-1')\nend\n\nT['File manipulation']['rename works again after undo'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  open(temp_dir)\n\n  type_keys('C', 'file-new', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file-new' })\n\n  -- Validate confirmation messages\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n  validate_confirm_args('  RENAME │ file => file%-new')\n\n  -- Undo and synchronize should cleanly rename back\n  type_keys('u', 'u')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file' })\n  validate_confirm_args('  RENAME │ file%-new => file')\nend\n\nT['File manipulation']['can move file'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/' })\n  open(temp_dir)\n\n  -- Write lines in moved file to check actual move and not \"delete-create\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n\n  -- Perform manipulation\n  type_keys('G', 'dd')\n  go_in()\n  type_keys('V', 'P')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file' })\n  validate_file_content(join_path(temp_dir, 'dir', 'file'), { 'File' })\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n  -- - Target path should be relative to group directory\n  validate_confirm_args('  MOVE   │ file => dir/file')\nend\n\nT['File manipulation']['can move directory'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/nested/', 'dir/nested/file', 'dir-target/' })\n  open(temp_dir)\n\n  -- Write lines in moved file to check actual move and not \"delete-create\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n\n  type_keys('dd')\n  go_in()\n  type_keys('V', 'P')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  --stylua: ignore\n  local ref_tree = {\n    'dir-target/',\n    'dir-target/dir/', 'dir-target/dir/file',\n    'dir-target/dir/nested/', 'dir-target/dir/nested/file',\n  }\n  validate_tree(temp_dir, ref_tree)\n  validate_file_content(join_path(temp_dir, 'dir-target', 'dir', 'file'), { 'File' })\n\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n  validate_confirm_args('  MOVE   │ dir => dir%-target/dir')\nend\n\nT['File manipulation']['move can show not relative \"to\" path'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n\n  -- Perform manipulation\n  type_keys('dd')\n  go_out()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_confirm_args('  MOVE   │ file => ' .. vim.pesc(short_path(temp_dir, 'file')))\nend\n\nT['File manipulation']['move does not override existing entry'] = function()\n  child.set_size(10, 80)\n\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file', 'target-dir/', 'target-dir/dir/', 'target-dir/file' })\n  open(temp_dir)\n  child.expect_screenshot()\n\n  type_keys('dd', 'l', 'p')\n  type_keys('h', 'G', 'dd', 'l', 'p')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  -- Should show warning\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n  local ref_log = {\n    { '(mini.files) Can not move or rename ' .. temp_dir .. '/dir. Target path already exists.', warn_level },\n    { '(mini.files) Can not move or rename ' .. temp_dir .. '/file. Target path already exists.', warn_level },\n  }\n  eq(child.lua_get('_G.notify_log'), ref_log)\nend\n\nT['File manipulation']['handles move directory inside itself'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/nested/' })\n  open(temp_dir)\n\n  type_keys('yy')\n  go_in()\n  go_in()\n  type_keys('V', 'p')\n  go_out()\n  go_out()\n  type_keys('dd')\n  child.expect_screenshot()\n\n  -- Should ask for confirmation but silently not do this\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file', 'dir/nested/' })\n\n  validate_confirm_args('  MOVE   │ dir => dir/nested/dir')\nend\n\nT['File manipulation']['can move while changing basename'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/' })\n  open(temp_dir)\n\n  -- Write lines in moved file to check actual move and not \"delete-create\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n\n  -- Perform manipulation\n  type_keys('G', 'dd')\n  go_in()\n  type_keys('V', 'P')\n  -- - Rename\n  type_keys('C', 'new-file', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/new-file' })\n  validate_file_content(join_path(temp_dir, 'dir', 'new-file'), { 'File' })\n\n  validate_confirm_args('  MOVE   │ file => dir/new%-file')\nend\n\nT['File manipulation']['can move inside new directory'] = function()\n  child.set_size(10, 60)\n\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  open(temp_dir)\n\n  -- Write lines in moved file to check actual move and not \"delete-create\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n\n  -- Perform manipulation\n  type_keys('i', 'new-dir/new-subdir/', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'new-dir/', 'new-dir/new-subdir/', 'new-dir/new-subdir/file' })\n  validate_file_content(join_path(temp_dir, 'new-dir', 'new-subdir', 'file'), { 'File' })\n\n  local ref_pattern = make_plain_pattern(short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n  validate_confirm_args('  MOVE   │ file => new%-dir/new%-subdir/file')\nend\n\nT['File manipulation']['can move across devices'] = function()\n  child.set_size(10, 60)\n\n  -- Mock `vim.loop.fs_rename()` not working across devices/volumes/partitions\n  child.lua('vim.loop.fs_rename = function() return nil, \"EXDEV: cross-device link not permitted:\", \"EXDEV\" end')\n\n  local tmp_children = { 'dir/', 'dir/file', 'dir/nested/', 'dir/nested/sub/', 'dir/nested/sub/file' }\n  local temp_dir = make_temp_dir('temp', tmp_children)\n  open(temp_dir)\n\n  -- Write lines in moved files to check \"copy-delete\" and not \"create-delete\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n  child.fn.writefile({ 'File nested' }, join_path(temp_dir, 'dir', 'nested', 'sub', 'file'))\n\n  go_in()\n  type_keys('dG')\n  go_out()\n  type_keys('P')\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'file', 'nested/', 'nested/sub/', 'nested/sub/file' })\n  validate_file_content(join_path(temp_dir, 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'nested', 'sub', 'file'), { 'File nested' })\nend\n\nT['File manipulation']['move works again after undo'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/' })\n  open(temp_dir)\n\n  -- Perform manipulation\n  type_keys('G', 'dd')\n  go_in()\n  type_keys('V', 'P')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file' })\n\n  -- Validate confirmation messages\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n  validate_confirm_args('  MOVE   │ file => dir/file')\n\n  -- Undos and synchronize should cleanly move back\n  type_keys('u', 'u')\n  go_out()\n  type_keys('u', 'u')\n  -- - Clear command line\n  type_keys(':', '<Esc>')\n  -- - Highlighting is different on Neovim>=0.10\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'file' })\n  validate_confirm_args('  MOVE   │ file => ' .. vim.pesc(short_path(temp_dir, 'file')))\nend\n\nT['File manipulation']['can copy file'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/' })\n  open(temp_dir)\n\n  -- Write lines in copied file to check actual copy and not create\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n\n  -- Perform manipulation\n  type_keys('j', 'yy', 'k')\n  go_in()\n  type_keys('V', 'P')\n  -- - Should be able to copy in same directory\n  go_out()\n  type_keys('p', 'C', 'file-copy', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file', 'file', 'file-copy' })\n  validate_file_content(join_path(temp_dir, 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'dir', 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'file-copy'), { 'File' })\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n\n  -- - Target path should be relative to group directory\n  validate_confirm_args('  COPY   │ file => dir/file')\n  validate_confirm_args('  COPY   │ file => file%-copy')\nend\n\nT['File manipulation']['can copy file inside new directory'] = function()\n  child.set_size(10, 60)\n\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  open(temp_dir)\n\n  -- Write lines in moved file to check actual move and not \"delete-create\"\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n\n  -- Perform manipulation\n  type_keys('yy', 'p')\n  type_keys('i', 'new-dir/new-subdir/', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'file', 'new-dir/', 'new-dir/new-subdir/', 'new-dir/new-subdir/file' })\n  validate_file_content(join_path(temp_dir, 'new-dir', 'new-subdir', 'file'), { 'File' })\nend\n\nT['File manipulation']['can copy directory'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/nested/', 'dir-target/' })\n  open(temp_dir)\n\n  -- Write lines in copied file to check actual copy and not create\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n\n  -- Perform manipulation\n  type_keys('yy', 'j')\n  go_in()\n  type_keys('V', 'P')\n  -- - Should be able to copy in same directory\n  go_out()\n  type_keys('p', 'C', 'dir-copy', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  --stylua: ignore\n  local ref_tree = {\n    'dir/',                           'dir/file',            'dir/nested/',\n    'dir-target/', 'dir-target/dir/', 'dir-target/dir/file', 'dir-target/dir/nested/',\n    'dir-copy/',                      'dir-copy/file',       'dir-copy/nested/',\n  }\n  validate_tree(temp_dir, ref_tree)\n\n  validate_file_content(join_path(temp_dir, 'dir', 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'dir-target', 'dir', 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'dir-copy', 'file'), { 'File' })\n\n  -- Validate separately because order is not guaranteed\n  local ref_pattern = make_plain_pattern('CONFIRM FILE SYSTEM ACTIONS', short_path(temp_dir) .. '\\n')\n  validate_confirm_args(ref_pattern)\n\n  -- - Target path should be relative to group directory\n  validate_confirm_args('  COPY   │ dir => dir%-target/dir')\n  validate_confirm_args('  COPY   │ dir => dir%-copy')\nend\n\nT['File manipulation']['can copy directory inside new directory'] = function()\n  child.set_size(10, 60)\n\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/nested/' })\n  open(temp_dir)\n\n  -- Write lines in copied file to check actual copy and not create\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n\n  -- Perform manipulation\n  type_keys('yy', 'p')\n  type_keys('i', 'new-dir/new-subdir/', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  --stylua: ignore\n  local ref_tree = {\n    'dir/', 'dir/file', 'dir/nested/',\n    'new-dir/', 'new-dir/new-subdir/',\n    'new-dir/new-subdir/dir/', 'new-dir/new-subdir/dir/file', 'new-dir/new-subdir/dir/nested/',\n  }\n  validate_tree(temp_dir, ref_tree)\n\n  validate_file_content(join_path(temp_dir, 'dir', 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'new-dir', 'new-subdir', 'dir', 'file'), { 'File' })\nend\n\nT['File manipulation']['copy can show not relative \"to\" path'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n\n  -- Perform manipulation\n  type_keys('yy')\n  go_out()\n  type_keys('p')\n  mock_confirm(1)\n  synchronize()\n\n  validate_confirm_args('  COPY   │ file => ' .. vim.pesc(short_path(temp_dir, 'file')))\nend\n\nT['File manipulation']['copy does not override existing entry'] = function()\n  child.set_size(10, 80)\n\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file', 'target-dir/', 'target-dir/dir/', 'target-dir/file' })\n  open(temp_dir)\n  child.expect_screenshot()\n\n  type_keys('yy', 'j', 'l', 'p')\n  type_keys('h', 'G', 'yy', 'k', 'l', 'p')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  -- Should show warning\n  local warn_level = child.lua_get('vim.log.levels.WARN')\n  local ref_log = {\n    { '(mini.files) Can not copy ' .. temp_dir .. '/dir. Target path already exists.', warn_level },\n    { '(mini.files) Can not copy ' .. temp_dir .. '/file. Target path already exists.', warn_level },\n  }\n  eq(child.lua_get('_G.notify_log'), ref_log)\nend\n\nT['File manipulation']['can copy directory inside itself'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/nested/' })\n  open(temp_dir)\n\n  -- Write lines in copied file to check actual copy and not create\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n\n  -- Perform manipulation\n  type_keys('yy')\n  go_in()\n  type_keys('p')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/dir/', 'dir/dir/file', 'dir/dir/nested/', 'dir/file', 'dir/nested/' })\n  validate_file_content(join_path(temp_dir, 'dir', 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'dir', 'dir', 'file'), { 'File' })\n\n  validate_confirm_args('  COPY   │ dir => dir/dir')\nend\n\nT['File manipulation']['can convert file into directory'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/', 'dir/subfile' })\n  child.fn.writefile({ 'Subfile' }, join_path(temp_dir, 'dir', 'subfile'))\n  open(temp_dir)\n\n  type_keys('A', '/', '<Esc>')\n  type_keys('j', 'A', '/', '<Esc>')\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n  child.expect_screenshot()\n\n  -- Should convert file->directory but not touch directory->directory\n  validate_tree(temp_dir, { 'file/', 'dir/', 'dir/subfile' })\n  validate_file_content(join_path(temp_dir, 'dir', 'subfile'), { 'Subfile' })\n\n  validate_confirm_args('  DELETE │ file')\n  validate_confirm_args('  RENAME │ dir => dir')\n  validate_confirm_args('  CREATE │ file %(directory%)')\nend\n\nT['File manipulation']['respects modified hidden buffers'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/' })\n  open(temp_dir)\n\n  go_in()\n  type_keys('C', 'new-file', '<Esc>')\n  go_out()\n  trim_right()\n  child.expect_screenshot()\n\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/new-file', 'file' })\nend\n\nT['File manipulation']['can be not confirmed'] = function()\n  open(test_dir_path)\n  type_keys('o', 'new-file', '<Esc>')\n\n  child.expect_screenshot()\n  mock_confirm(2)\n  synchronize()\n  child.expect_screenshot()\n  eq(child.fn.filereadable(join_path(test_dir_path, 'new-file')), 0)\nend\n\nT['File manipulation']['can be not confirmed with preview'] = function()\n  child.lua('MiniFiles.config.windows.preview = true')\n  open(test_dir_path)\n  type_keys('o', 'new-file', '<Esc>')\n\n  child.expect_screenshot()\n  mock_confirm(2)\n  synchronize()\n  child.expect_screenshot()\n  eq(child.fn.filereadable(join_path(test_dir_path, 'new-file')), 0)\nend\n\nT['File manipulation']['works with problematic names'] = function()\n  local temp_dir = make_temp_dir('temp', { [[a %file-]], 'b file' })\n  open(temp_dir)\n\n  -- Perform manipulation\n  -- - Delete\n  type_keys('dd')\n  -- - Rename\n  type_keys('C', 'c file', '<Esc>')\n  -- - Create\n  type_keys('o', 'd file', '<Esc>')\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  mock_confirm(1)\n  synchronize()\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  validate_tree(temp_dir, { 'c file', 'd file' })\nend\n\nT['File manipulation']['handles backslash on Unix'] = function()\n  if child.loop.os_uname().sysname == 'Windows_NT' then MiniTest.skip('Test is not for Windows.') end\n\n  local temp_dir = make_temp_dir('temp', { '\\\\', 'hello\\\\', 'wo\\\\rld' })\n  open(temp_dir)\n\n  -- Perform manipulation\n  -- - Delete\n  type_keys('dd')\n  -- - Rename\n  type_keys('C', 'new-hello', '<Esc>')\n  -- - Create\n  type_keys('o', 'bad\\\\file', '<Esc>')\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  mock_confirm(1)\n  synchronize()\n  if child.fn.has('nvim-0.10') == 1 then child.expect_screenshot() end\n\n  validate_tree(temp_dir, { 'bad\\\\file', 'new-hello', 'wo\\\\rld' })\nend\n\nT['File manipulation']['ignores blank lines'] = function()\n  open(test_dir_path)\n  type_keys('o', '<Esc>', 'yy', 'p')\n  child.expect_screenshot()\n\n  -- Should synchronize without confirmation\n  synchronize()\n  child.expect_screenshot()\nend\n\nT['File manipulation']['ignores identical user-copied entries'] = function()\n  open(test_dir_path)\n  type_keys('yj', 'p')\n  child.expect_screenshot()\n\n  -- Should synchronize without confirmation\n  synchronize()\n  child.expect_screenshot()\nend\n\nT['File manipulation']['special cases'] = new_set()\n\nT['File manipulation']['special cases']['freed path'] = new_set()\n\nT['File manipulation']['special cases']['freed path']['delete and move other'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file-a', 'file-b' })\n  child.fn.writefile({ 'File A' }, join_path(temp_dir, 'dir', 'file-a'))\n  open(temp_dir)\n  type_keys('j', 'dd')\n  go_in()\n  type_keys('dd')\n  go_out()\n  type_keys('p', 'C', 'file-b')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'file-b' })\n  validate_file_content(join_path(temp_dir, 'file-b'), { 'File A' })\nend\n\nT['File manipulation']['special cases']['freed path']['delete and rename other'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file-a', 'file-b' })\n  child.fn.writefile({ 'File B' }, join_path(temp_dir, 'file-b'))\n  open(temp_dir)\n  type_keys('dd', 'C', 'file-a', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file-a' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File B' })\nend\n\nT['File manipulation']['special cases']['freed path']['delete and copy other'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file-a', 'file-b' })\n  child.fn.writefile({ 'File A' }, join_path(temp_dir, 'file-a'))\n  child.fn.writefile({ 'File B' }, join_path(temp_dir, 'file-b'))\n  open(temp_dir)\n  type_keys('dd', 'yy', 'p', 'C', 'file-a', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file-a', 'file-b' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File B' })\n  validate_file_content(join_path(temp_dir, 'file-b'), { 'File B' })\nend\n\nT['File manipulation']['special cases']['freed path']['delete and create'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n  open(temp_dir)\n  type_keys('dd', 'o', 'file', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file' })\n  validate_file_content(join_path(temp_dir, 'file'), {})\nend\n\nT['File manipulation']['special cases']['freed path']['move and rename other'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file-a', 'file-b' })\n  child.fn.writefile({ 'File A' }, join_path(temp_dir, 'file-a'))\n  child.fn.writefile({ 'File B' }, join_path(temp_dir, 'file-b'))\n  open(temp_dir)\n  type_keys('j', 'dd', 'k')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('j', 'C', 'file-a')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file-a', 'file-a' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File B' })\n  validate_file_content(join_path(temp_dir, 'dir', 'file-a'), { 'File A' })\nend\n\nT['File manipulation']['special cases']['freed path']['move and copy other'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file-a', 'file-b' })\n  child.fn.writefile({ 'File A' }, join_path(temp_dir, 'file-a'))\n  child.fn.writefile({ 'File B' }, join_path(temp_dir, 'file-b'))\n  open(temp_dir)\n  type_keys('j', 'dd', 'gg')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('j', 'yy', 'p', 'C', 'file-a')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file-a', 'file-a', 'file-b' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File B' })\n  validate_file_content(join_path(temp_dir, 'file-b'), { 'File B' })\n  validate_file_content(join_path(temp_dir, 'dir', 'file-a'), { 'File A' })\nend\n\nT['File manipulation']['special cases']['freed path']['move and create'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file-a' })\n  child.fn.writefile({ 'File A' }, join_path(temp_dir, 'file-a'))\n  open(temp_dir)\n  type_keys('j', 'dd', 'k')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('o', 'file-a')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file-a', 'file-a' })\n  validate_file_content(join_path(temp_dir, 'file-a'), {})\n  validate_file_content(join_path(temp_dir, 'dir', 'file-a'), { 'File A' })\nend\n\nT['File manipulation']['special cases']['freed path']['rename and move other'] = function()\n  -- NOTE: Unfortunately, this doesn't work as \"move\" is done before \"rename\".\n  -- Accounting for this seems involve even more tweaks than is currently done,\n  -- like fully computing the proper order of overlapping actions (which might\n  -- not be fully possibly due to \"cyclic renames/moves\"). So this deliberately\n  -- is left unresolved with the suggestion to split steps and sync more often.\n\n  -- local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file-a', 'file-b' })\n  -- child.fn.writefile({ 'File A' }, join_path(temp_dir, 'dir', 'file-a'))\n  -- child.fn.writefile({ 'File B' }, join_path(temp_dir, 'file-b'))\n  -- open(temp_dir)\n  -- type_keys('G', 'C', 'file-c', '<Esc>')\n  -- type_keys('gg')\n  -- go_in()\n  -- type_keys('dd')\n  -- go_out()\n  -- type_keys('p', 'C', 'file-b', '<Esc>')\n  -- mock_confirm(1)\n  -- synchronize()\n  --\n  -- validate_tree(temp_dir, { 'dir/', 'file-b', 'file-c' })\n  -- validate_file_content(join_path(temp_dir, 'file-b'), { 'File A' })\n  -- validate_file_content(join_path(temp_dir, 'file-c'), { 'File B' })\nend\n\nT['File manipulation']['special cases']['freed path']['rename and copy other'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file-a', 'file-b' })\n  child.fn.writefile({ 'File A' }, join_path(temp_dir, 'file-a'))\n  child.fn.writefile({ 'File B' }, join_path(temp_dir, 'file-b'))\n  open(temp_dir)\n  type_keys('C', 'file-c', '<Esc>')\n  type_keys('j', 'yy', 'p', 'C', 'file-a')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file-a', 'file-b', 'file-c' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File B' })\n  validate_file_content(join_path(temp_dir, 'file-b'), { 'File B' })\n  validate_file_content(join_path(temp_dir, 'file-c'), { 'File A' })\nend\n\nT['File manipulation']['special cases']['freed path']['rename and create'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n  open(temp_dir)\n  type_keys('C', 'new-file', '<Esc>')\n  type_keys('o', 'file')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file', 'new-file' })\n  validate_file_content(join_path(temp_dir, 'file'), {})\n  validate_file_content(join_path(temp_dir, 'new-file'), { 'File' })\nend\n\nT['File manipulation']['special cases']['act on same path'] = new_set()\n\nT['File manipulation']['special cases']['act on same path']['copy and rename'] = function()\n  local temp_dir = make_temp_dir('temp', { 'file' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n  open(temp_dir)\n  type_keys('yy', 'p', 'C', 'file-a', '<Esc>')\n  type_keys('k^', 'C', 'file-b', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file-a', 'file-b' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'file-b'), { 'File' })\nend\n\nT['File manipulation']['special cases']['act on same path']['copy and move'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'file'))\n  open(temp_dir)\n  type_keys('j', 'yy', 'p', 'C', 'file-a', '<Esc>')\n  type_keys('k', 'dd', 'k')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file', 'file-a' })\n  validate_file_content(join_path(temp_dir, 'file-a'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'dir', 'file'), { 'File' })\nend\n\nT['File manipulation']['special cases']['inside affected directory'] = new_set()\n\nT['File manipulation']['special cases']['inside affected directory']['delete in copied'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('dd')\n  go_out()\n  type_keys('yy', 'p', 'C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  -- \"Delete\" is done before \"copy\", so as to \"free\" space. So both directories\n  -- don't have deleted file.\n  validate_tree(temp_dir, { 'dir/', 'new-dir/' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['delete in renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('dd')\n  go_out()\n  type_keys('C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'new-dir/' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['delete in moved'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'other-dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('dd')\n  go_out()\n  type_keys('dd')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'other-dir/', 'other-dir/dir/' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['move in deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/subdir/' })\n  open(temp_dir .. '/dir')\n  type_keys('j', 'dd')\n  go_in()\n  type_keys('p')\n  go_out()\n  go_out()\n  type_keys('dd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should prefer \"delete\"\n  validate_tree(temp_dir, {})\nend\n\nT['File manipulation']['special cases']['inside affected directory']['move in renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/subdir/' })\n  open(temp_dir .. '/dir')\n  type_keys('j', 'dd')\n  go_in()\n  type_keys('p')\n  go_out()\n  go_out()\n  type_keys('C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'new-dir/', 'new-dir/subdir/', 'new-dir/subdir/file' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['move in copied'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'dir/subdir/' })\n  open(temp_dir .. '/dir')\n  type_keys('j', 'dd')\n  go_in()\n  type_keys('p')\n  go_out()\n  go_out()\n  type_keys('yy', 'p', 'C', 'new-dir')\n  mock_confirm(1)\n  synchronize()\n\n  local ref_tree = { 'dir/', 'dir/subdir/', 'dir/subdir/file', 'new-dir/', 'new-dir/subdir/', 'new-dir/subdir/file' }\n  validate_tree(temp_dir, ref_tree)\nend\n\nT['File manipulation']['special cases']['inside affected directory']['rename in deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('C', 'new-file', '<Esc>')\n  go_out()\n  type_keys('dd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should prefer \"delete\"\n  validate_tree(temp_dir, {})\nend\n\nT['File manipulation']['special cases']['inside affected directory']['rename in moved'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'other-dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('C', 'new-file', '<Esc>')\n  go_out()\n  type_keys('dd', 'G')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'other-dir/', 'other-dir/dir/', 'other-dir/dir/new-file' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['rename in copied'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('C', 'new-file', '<Esc>')\n  go_out()\n  type_keys('yy', 'p', 'C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  -- \"Rename\" is done before \"copy\", so as to \"free\" space. So both directories\n  -- have renamed file.\n  validate_tree(temp_dir, { 'dir/', 'dir/new-file', 'new-dir/', 'new-dir/new-file' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['copy in deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('yy', 'p', 'C', 'file-a', '<Esc>')\n  go_out()\n  type_keys('dd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should prefer \"delete\"\n  validate_tree(temp_dir, {})\nend\n\nT['File manipulation']['special cases']['inside affected directory']['copy in moved'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'other-dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('yy', 'p', 'C', 'file-a', '<Esc>')\n  go_out()\n  type_keys('dd')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'other-dir/', 'other-dir/dir/', 'other-dir/dir/file', 'other-dir/dir/file-a' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['copy in renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('yy', 'p', 'C', 'file-a', '<Esc>')\n  go_out()\n  type_keys('C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'new-dir/', 'new-dir/file', 'new-dir/file-a' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['create in deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('i', 'file', '<Esc>')\n  go_out()\n  type_keys('dd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should prefer \"delete\"\n  validate_tree(temp_dir, {})\nend\n\nT['File manipulation']['special cases']['inside affected directory']['create in moved'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'other-dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('i', 'file', '<Esc>')\n  go_out()\n  type_keys('dd')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'other-dir/', 'other-dir/dir/', 'other-dir/dir/file' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['create in renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('i', 'file', '<Esc>')\n  go_out()\n  type_keys('C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'new-dir/', 'new-dir/file' })\nend\n\nT['File manipulation']['special cases']['inside affected directory']['create in copied'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/' })\n  open(temp_dir .. '/dir')\n  type_keys('i', 'file', '<Esc>')\n  go_out()\n  type_keys('yy', 'p', 'C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  -- \"Create\" is done last so only in original directory. There is no special\n  -- reason for this choice other than grouping \"move\"/\"rename\"/\"copy\" seems\n  -- like a more organized choice.\n  validate_tree(temp_dir, { 'dir/', 'dir/file', 'new-dir/' })\nend\n\nT['File manipulation']['special cases']['from affected directory'] = new_set()\n\nT['File manipulation']['special cases']['from affected directory']['move from deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('dd')\n  go_out()\n  type_keys('p')\n  type_keys('gg', 'dd')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file' })\nend\n\nT['File manipulation']['special cases']['from affected directory']['move from renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('dd')\n  go_out()\n  type_keys('p')\n  type_keys('gg', 'C', 'new-dir')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file', 'new-dir/' })\nend\n\nT['File manipulation']['special cases']['from affected directory']['move from copied'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  open(temp_dir .. '/dir')\n  type_keys('dd')\n  go_out()\n  type_keys('p')\n  type_keys('gg', 'yy', 'p', 'C', 'new-dir')\n  mock_confirm(1)\n  synchronize()\n\n  -- \"Move\" is done before \"copy\", so as to \"free\" space. So no directories\n  -- have moved file.\n  validate_tree(temp_dir, { 'dir/', 'file', 'new-dir/' })\nend\n\nT['File manipulation']['special cases']['from affected directory']['copy from deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n  open(temp_dir .. '/dir')\n  type_keys('yy')\n  go_out()\n  type_keys('p')\n  type_keys('gg', 'dd')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file' })\n  validate_file_content(join_path(temp_dir, 'file'), { 'File' })\nend\n\nT['File manipulation']['special cases']['from affected directory']['copy from moved'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file', 'other-dir/' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n  open(temp_dir .. '/dir')\n  type_keys('yy')\n  go_out()\n  type_keys('p')\n  type_keys('gg', 'dd', 'G')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file', 'other-dir/', 'other-dir/dir/', 'other-dir/dir/file' })\n  validate_file_content(join_path(temp_dir, 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'other-dir', 'dir', 'file'), { 'File' })\nend\n\nT['File manipulation']['special cases']['from affected directory']['copy from renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'dir/file' })\n  child.fn.writefile({ 'File' }, join_path(temp_dir, 'dir', 'file'))\n  open(temp_dir .. '/dir')\n  type_keys('yy')\n  go_out()\n  type_keys('p')\n  type_keys('gg', 'C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file', 'new-dir/', 'new-dir/file' })\n  validate_file_content(join_path(temp_dir, 'file'), { 'File' })\n  validate_file_content(join_path(temp_dir, 'new-dir', 'file'), { 'File' })\nend\n\nT['File manipulation']['special cases']['into affected directory'] = new_set()\n\nT['File manipulation']['special cases']['into affected directory']['move into deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n  open(temp_dir)\n  type_keys('G', 'dd')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('dd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should prefer \"delete\"\n  validate_tree(temp_dir, {})\nend\n\nT['File manipulation']['special cases']['into affected directory']['move into renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n  open(temp_dir)\n  type_keys('G', 'dd')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('C', 'new-dir')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'new-dir/', 'new-dir/file' })\nend\n\nT['File manipulation']['special cases']['into affected directory']['move into copied'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n  open(temp_dir)\n  type_keys('G', 'dd')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('yy', 'p', 'C', 'new-dir')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir/', 'dir/file', 'new-dir/', 'new-dir/file' })\nend\n\nT['File manipulation']['special cases']['into affected directory']['copy into deleted'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n  open(temp_dir)\n  type_keys('G', 'yy', 'gg')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('dd')\n  mock_confirm(1)\n  synchronize()\n\n  -- Should prefer \"delete\"\n  validate_tree(temp_dir, { 'file' })\nend\n\nT['File manipulation']['special cases']['into affected directory']['copy into moved'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'other-dir/', 'file' })\n  open(temp_dir)\n  type_keys('G', 'yy', 'gg')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('dd')\n  go_in()\n  type_keys('P')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file', 'other-dir/', 'other-dir/dir/', 'other-dir/dir/file' })\nend\n\nT['File manipulation']['special cases']['into affected directory']['copy into renamed'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir/', 'file' })\n  open(temp_dir)\n  type_keys('G', 'yy', 'gg')\n  go_in()\n  type_keys('P')\n  go_out()\n  type_keys('C', 'new-dir', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'file', 'new-dir/', 'new-dir/file' })\nend\n\nT['File manipulation']['entry with newline'] = function()\n  if helpers.is_windows() then MiniTest.skip('Newline characters in names are not supported on Windows') end\n  local temp_dir = make_temp_dir('temp', { 'di\\nr/', 'fi\\nl\\ne' })\n  open(temp_dir)\n  -- NOTE: copy/move/rename *will* replace '\\n' with escaped version, though\n  type_keys('cc', 'new-dir/', '<Esc>')\n  mock_confirm(1)\n  synchronize()\n  validate_confirm_args('DELETE │ di<NL>r')\n\n  validate_tree(temp_dir, { 'new-dir/', 'fi\\nl\\ne' })\nend\n\nT['File manipulation']['special cases']['nested move'] = new_set()\n\nT['File manipulation']['special cases']['nested move']['works'] = function()\n  local temp_dir = make_temp_dir('temp', { 'dir-a/', 'dir-a/dir-b/', 'dir-a/dir-b/dir-c/', 'dir-a/dir-b/dir-c/file' })\n  open(temp_dir .. '/dir-a/dir-b')\n  type_keys('dd')\n  go_out()\n  go_out()\n  type_keys('p')\n  type_keys('gg')\n  go_in()\n  type_keys('dd')\n  go_out()\n  type_keys('p')\n  mock_confirm(1)\n  synchronize()\n\n  validate_tree(temp_dir, { 'dir-a/', 'dir-b/', 'dir-c/', 'dir-c/file' })\nend\n\nT['Cursors'] = new_set()\n\nT['Cursors']['are preserved'] = function()\n  open(test_dir_path)\n\n  -- During navigation\n  type_keys('j')\n  go_in()\n  go_in()\n  go_out()\n  validate_cur_line(1)\n  type_keys('j')\n\n  go_out()\n  validate_cur_line(2)\n\n  go_in()\n  validate_cur_line(2)\n\n  -- In hidden buffers\n  go_out()\n  trim_left()\n  go_in()\n  validate_cur_line(2)\n\n  -- When opening from history\n  close()\n  open(test_dir_path, true)\n  validate_cur_line(2)\n  go_out()\n  validate_cur_line(2)\nend\n\nT['Cursors']['not allowed to the left of the entry name'] = function()\n  open(test_dir_path)\n  local cursor = get_cursor()\n\n  -- Normal mode\n  type_keys('b')\n  eq(get_cursor(), cursor)\n  type_keys('10b')\n  eq(get_cursor(), cursor)\n  type_keys('0')\n  eq(get_cursor(), cursor)\n\n  set_cursor(cursor[1], 0)\n  eq(get_cursor(), cursor)\n\n  -- Insert mode\n  type_keys('i')\n  type_keys('<Left>')\n  eq(get_cursor(), cursor)\nend\n\nT['Cursors']['handle `content.prefix` returning different lengths'] = function()\n  child.lua([[\n    _G.cur_prefix = ''\n    MiniFiles.config.content.prefix = function()\n      local res_prefix = _G.cur_prefix\n      _G.cur_prefix = _G.cur_prefix .. '+'\n      return res_prefix, 'Comment'\n    end\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  local cur_cursor = get_cursor()\n  eq(cur_cursor, { 1, 4 })\n\n  local offset = 0\n  local validate_cursor = function()\n    type_keys('j')\n    offset = offset + 1\n    eq(get_cursor(), { cur_cursor[1] + offset, cur_cursor[2] + offset })\n  end\n\n  validate_cursor()\n  validate_cursor()\n  validate_cursor()\nend\n\nT['Cursors']['shows whole line after horizontal scroll'] = function()\n  child.set_size(10, 60)\n\n  open(test_dir_path)\n\n  type_keys('7zl')\n  child.expect_screenshot()\n\n  type_keys('2B')\n  child.expect_screenshot()\nend\n\nT['Events'] = new_set()\n\nlocal track_event = function(event_name)\n  child.lua('_G.event_name = ' .. vim.inspect(event_name))\n  local lua_cmd = [[\n    _G.callback_args_data = {}\n    local f = function(args) table.insert(_G.callback_args_data, args.data or {}) end\n    vim.api.nvim_create_autocmd('User', { pattern = _G.event_name, callback = f })\n  ]]\n  child.lua(lua_cmd)\nend\n\nlocal get_event_track = function() return child.lua_get('_G.callback_args_data') end\n\nlocal clear_event_track = function() child.lua('_G.callback_args_data = {}') end\n\nlocal validate_event_track = function(ref, do_sort)\n  local event_track = child.lua_get('_G.callback_args_data')\n\n  if do_sort then table.sort(event_track, function(a, b) return a.buf_id < b.buf_id end) end\n  eq(event_track, ref)\nend\n\nlocal validate_n_events = function(n_ref) eq(#child.lua_get('_G.callback_args_data'), n_ref) end\n\nT['Events']['`MiniFilesExplorerOpen` triggers'] = function()\n  track_event('MiniFilesExplorerOpen')\n  child.cmd('au User MiniFilesExplorerOpen lua _G.windows = vim.api.nvim_list_wins()')\n\n  open(test_dir_path)\n  validate_event_track({ {} })\n  -- Should trigger after all windows are opened\n  eq(#child.lua_get('_G.windows'), 2)\n  clear_event_track()\n\n  close()\n  validate_event_track({})\n\n  open(test_dir_path)\n  validate_event_track({ {} })\nend\n\nT['Events']['`MiniFilesExplorerClose` triggers'] = function()\n  track_event('MiniFilesExplorerClose')\n  child.cmd('au User MiniFilesExplorerClose lua _G.windows = vim.api.nvim_list_wins()')\n\n  open(test_dir_path)\n  validate_event_track({})\n  clear_event_track()\n\n  close()\n  validate_event_track({ {} })\n  -- Should trigger before all windows are closed\n  eq(#child.lua_get('_G.windows'), 2)\n  clear_event_track()\n\n  open(test_dir_path)\n  validate_event_track({})\n  clear_event_track()\n\n  close()\n  validate_event_track({ {} })\nend\n\nT['Events']['`MiniFilesBufferCreate` triggers'] = function()\n  track_event('MiniFilesBufferCreate')\n  child.lua([[\n    local f = function(args) _G.buf_name = vim.api.nvim_buf_get_name(args.data.buf_id) end\n    vim.api.nvim_create_autocmd('User', { pattern = 'MiniFilesBufferCreate', callback = f })\n  ]])\n\n  local open_path = full_path(test_dir_path)\n\n  open(open_path)\n  local buf_cur = child.api.nvim_get_current_buf()\n  validate_event_track({ { buf_id = buf_cur } })\n  -- - Should be already properly named\n  eq(child.lua_get('_G.buf_name'), 'minifiles://' .. buf_cur .. '/' .. open_path)\n  clear_event_track()\n\n  go_in()\n  buf_cur = child.api.nvim_get_current_buf()\n  validate_event_track({ { buf_id = buf_cur } })\n  eq(child.lua_get('_G.buf_name'), 'minifiles://' .. buf_cur .. '/' .. join_path(open_path, '.a-dir'))\n  clear_event_track()\n\n  -- No event should be triggered if buffer is reused\n  go_out()\n  trim_right()\n  go_in()\n\n  validate_event_track({})\nend\n\nT['Events']['`MiniFilesBufferCreate` triggers inside preview'] = function()\n  track_event('MiniFilesBufferCreate')\n\n  child.lua('MiniFiles.config.windows.preview = true')\n  open(test_dir_path)\n  validate_n_events(2)\n\n  type_keys('j')\n  validate_n_events(3)\n\n  -- No event should be triggered when going inside previewed directory (as\n  -- buffer should be reused). But should also be triggered for file previews.\n  clear_event_track()\n  type_keys('k')\n  go_in()\n  validate_n_events(1)\n\n  -- No event should trigger for imaginary path\n  clear_event_track()\n  type_keys('o')\n  validate_n_wins(3)\n  validate_n_events(0)\n\n  type_keys('imaginary-file')\n  validate_n_wins(3)\n  validate_n_events(0)\nend\n\nT['Events']['`MiniFilesBufferCreate` can be used to create buffer-local mappings'] = function()\n  child.lua([[\n    _G.n = 0\n    local rhs = function() _G.n = _G.n + 1 end\n    vim.api.nvim_create_autocmd(\n      'User',\n      {\n        pattern = 'MiniFilesBufferCreate',\n        callback = function(args) vim.keymap.set('n', 'W', rhs, { buffer = args.data.buf_id }) end,\n      }\n    )\n  ]])\n\n  type_keys('W')\n  eq(child.lua_get('_G.n'), 0)\n\n  open(test_dir_path)\n  type_keys('W')\n  eq(child.lua_get('_G.n'), 1)\n\n  go_in()\n  type_keys('W')\n  eq(child.lua_get('_G.n'), 2)\nend\n\nT['Events']['`MiniFilesBufferUpdate` triggers'] = function()\n  track_event('MiniFilesBufferUpdate')\n\n  open(test_dir_path)\n  local buf_id_1, win_id_1 = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n  -- No `win_id` on first buffer update\n  validate_event_track({ { buf_id = buf_id_1 } })\n  clear_event_track()\n\n  -- Force buffer updates\n  synchronize()\n  validate_event_track({ { buf_id = buf_id_1, win_id = win_id_1 } })\n  clear_event_track()\n\n  go_in()\n  local buf_id_2, win_id_2 = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n  validate_event_track({ { buf_id = buf_id_2 } })\n  clear_event_track()\n\n  -- Force all buffers to update\n  synchronize()\n\n  -- - Force order, as there is no order guarantee of event trigger\n  validate_event_track({ { buf_id = buf_id_1, win_id = win_id_1 }, { buf_id = buf_id_2, win_id = win_id_2 } }, true)\nend\n\nT['Events']['`MiniFilesBufferUpdate` triggers inside preview'] = function()\n  track_event('MiniFilesBufferUpdate')\n\n  child.lua('MiniFiles.config.windows.preview = true')\n  open(test_dir_path)\n  validate_n_events(2)\n\n  type_keys('j')\n  validate_n_events(3)\n\n  -- Should be triggered when going inside previewed directory (as different\n  -- buffer becomes current).\n  clear_event_track()\n  type_keys('k')\n  go_in()\n  validate_n_events(2)\n\n  -- No event should trigger for imaginary path\n  clear_event_track()\n  type_keys('o')\n  validate_n_wins(3)\n  validate_n_events(0)\n\n  type_keys('imaginary-file')\n  validate_n_wins(3)\n  validate_n_events(0)\nend\n\nT['Events']['`MiniFilesWindowOpen` triggers'] = function()\n  track_event('MiniFilesWindowOpen')\n\n  open(test_dir_path)\n  local buf_id_1, win_id_1 = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n  -- Should provide both `buf_id` and `win_id`\n  validate_event_track({ { buf_id = buf_id_1, win_id = win_id_1 } })\n  clear_event_track()\n\n  go_in()\n  local buf_id_2, win_id_2 = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n  validate_event_track({ { buf_id = buf_id_2, win_id = win_id_2 } })\n  clear_event_track()\n\n  -- Should indicate reused buffer but not window\n  go_out()\n  trim_right()\n  go_in()\n  local win_id_3 = child.api.nvim_get_current_win()\n  validate_event_track({ { buf_id = buf_id_2, win_id = win_id_3 } })\nend\n\nT['Events']['`MiniFilesWindowOpen` can be used to tweak window config'] = function()\n  child.lua([[\n    vim.api.nvim_create_autocmd('User', {\n      pattern = 'MiniFilesWindowOpen',\n      callback = function(args)\n        local win_id = args.data.win_id\n        local config = vim.api.nvim_win_get_config(win_id)\n        config.border, config.title_pos = 'double', 'right'\n        vim.api.nvim_win_set_config(win_id, config)\n      end,\n    })\n  ]])\n\n  open(test_dir_path)\n  child.expect_screenshot()\n\n  go_in()\n  child.expect_screenshot()\n\n  go_out()\n  trim_right()\n  go_in()\n  child.expect_screenshot()\nend\n\nT['Events']['`MiniFilesWindowUpdate` triggers'] = function()\n  track_event('MiniFilesWindowUpdate')\n\n  open(test_dir_path)\n  local buf_id_1, win_id_1 = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n  -- Triggered several times because `CursorMoved` also triggeres it.\n  -- Should provide both `buf_id` and `win_id`.\n  validate_event_track({ { buf_id = buf_id_1, win_id = win_id_1 }, { buf_id = buf_id_1, win_id = win_id_1 } })\n  clear_event_track()\n\n  go_in()\n  local buf_id_2, win_id_2 = child.api.nvim_get_current_buf(), child.api.nvim_get_current_win()\n\n  -- - Both windows should be updated\n  validate_event_track(\n    {\n      { buf_id = buf_id_1, win_id = win_id_1 },\n      { buf_id = buf_id_1, win_id = win_id_1 },\n      { buf_id = buf_id_2, win_id = win_id_2 },\n      { buf_id = buf_id_2, win_id = win_id_2 },\n    },\n    -- - Force order, as there is no order guarantee of event trigger\n    true\n  )\nend\n\nT['Events']['`MiniFilesWindowUpdate` is triggered after every possible window config update'] = function()\n  track_event('MiniFilesWindowUpdate')\n\n  open(test_dir_path)\n  clear_event_track()\n\n  -- Windows have to adjust configs on every cursor move if preview is set\n  child.lua('MiniFiles.config.windows.preview = true')\n\n  local validate = function(keys)\n    clear_event_track()\n    type_keys(keys)\n    eq(#get_event_track() > 0, true)\n  end\n\n  validate('j')\n  validate('<Right>')\n  validate({ 'i', '<Left>' })\n\n  -- NOTE: Currently this event also is triggered on every cursor move even if\n  -- preview is not enabled. This is to simplify code.\nend\n\nT['Events']['`MiniFilesWindowUpdate` is triggered after current buffer is set'] = function()\n  track_event('MiniFilesWindowUpdate')\n  open(test_dir_path)\n  clear_event_track()\n  go_out()\n  validate_event_track({\n    { buf_id = 2, win_id = 1004 },\n    { buf_id = 2, win_id = 1004 },\n    { buf_id = 3, win_id = 1003 },\n    { buf_id = 3, win_id = 1003 },\n  }, true)\nend\n\nT['Events']['`MiniFilesWindowUpdate` can customize internally set window config parts'] = function()\n  local expect_screenshot = child.expect_screenshot\n  if child.fn.has('nvim-0.10') == 0 then\n    local expect_orig = expect_screenshot\n    expect_screenshot = function() child.expect_screenshot({ ignore_attr = true }) end\n  end\n  child.set_size(15, 80)\n\n  load_module({\n    windows = {\n      preview = true,\n      width_focus = 40,\n      width_nofocus = 10,\n      width_preview = 20,\n    },\n  })\n\n  child.lua([[\n    vim.api.nvim_create_autocmd('User', {\n      pattern = 'MiniFilesWindowUpdate',\n      callback = function(args)\n        local config = vim.api.nvim_win_get_config(args.data.win_id)\n        -- Ensure fixed height\n        config.height = 5\n        -- Ensure title padding\n        local n = #config.title\n        config.title[1][1] = config.title[1][1]:gsub('^ ', '')\n        config.title[n][1] = config.title[n][1]:gsub(' $', '')\n        vim.api.nvim_win_set_config(args.data.win_id, config)\n      end\n    })\n  ]])\n\n  open(test_dir_path)\n  go_in()\n  expect_screenshot()\n\n  -- Works in Insert mode when number of entries is less than height\n  type_keys('o', 'a', 'b', 'c')\n  expect_screenshot()\n  child.ensure_normal_mode()\n\n  -- Works in Insert mode when number of entries is more than height\n  go_out()\n  type_keys('o', 'd', 'e', 'f')\n  expect_screenshot()\n  child.ensure_normal_mode()\n\n  -- Works when modifying below last visible line\n  type_keys('3j', 'o', 'a')\n  expect_screenshot()\n\n  -- Works even if completion menu (like from 'mini.completion') is triggered\n  child.cmd('set iskeyword+=-')\n  type_keys('<C-n>')\n  expect_screenshot()\nend\n\nT['Events']['`MiniFilesActionCreate` triggers'] = function()\n  track_event('MiniFilesActionCreate')\n\n  local validate = function(entry, inject_external_create)\n    local temp_dir = make_temp_dir('temp', {})\n    local entry_name = entry:gsub('(.)/$', '%1')\n    local entry_path = join_path(temp_dir, entry_name)\n    open(temp_dir, false)\n\n    -- Perform create\n    type_keys('i', entry, '<Esc>')\n\n    mock_confirm(1)\n    if inject_external_create then child.fn.writefile({}, entry_path) end\n    synchronize()\n\n    -- If there was external create, then action was not successful and thus\n    -- event should not trigger\n    local ref = inject_external_create and {} or { { action = 'create', to = entry_path } }\n    validate_event_track(ref)\n\n    -- Cleanup\n    close()\n    child.fn.delete(temp_dir, 'rf')\n    clear_event_track()\n  end\n\n  validate('file', false)\n  validate('file', true)\n  validate('dir/', false)\n  validate('dir/', true)\nend\n\nT['Events']['`MiniFilesActionDelete` triggers'] = function()\n  track_event('MiniFilesActionDelete')\n\n  local validate = function(entry, inject_external_delete)\n    local temp_dir = make_temp_dir('temp', { entry })\n    local entry_name = entry:gsub('(.)/$', '%1')\n    local entry_path = join_path(temp_dir, entry_name)\n    open(temp_dir, false)\n\n    -- Perform delete\n    type_keys('dd')\n\n    mock_confirm(1)\n    if inject_external_delete then child.fn.delete(entry_path, 'rf') end\n    synchronize()\n\n    -- If there was external delete, then action was not successful and thus\n    -- event should not trigger\n    local ref = inject_external_delete and {} or { { action = 'delete', from = entry_path } }\n    validate_event_track(ref)\n\n    -- Cleanup\n    close()\n    child.fn.delete(temp_dir, 'rf')\n    clear_event_track()\n  end\n\n  validate('file', false)\n  validate('file', true)\n  validate('dir/', false)\n  validate('dir/', true)\nend\n\nT['Events']['`MiniFilesActionDelete` triggers for `options.permanent_delete = false`'] = function()\n  track_event('MiniFilesActionDelete')\n\n  local data_dir = mock_stdpath_data()\n  local trash_dir = join_path(data_dir, 'mini.files', 'trash')\n  child.lua('MiniFiles.config.options.permanent_delete = false')\n  local temp_dir = make_temp_dir('temp', { 'file', 'dir/', 'dir/subfile' })\n  open(temp_dir)\n\n  type_keys('VGd')\n  mock_confirm(1)\n  synchronize()\n\n  local event_track = get_event_track()\n  table.sort(event_track, function(a, b) return a.from < b.from end)\n  -- Should also supply `to` field with path to trash\n  eq(event_track, {\n    { action = 'delete', from = join_path(temp_dir, 'dir'), to = join_path(trash_dir, 'dir') },\n    { action = 'delete', from = join_path(temp_dir, 'file'), to = join_path(trash_dir, 'file') },\n  })\nend\n\nT['Events']['`MiniFilesActionRename` triggers'] = function()\n  track_event('MiniFilesActionRename')\n\n  local validate = function(entry, inject_external_delete)\n    local temp_dir = make_temp_dir('temp', { entry })\n    local entry_name = entry:gsub('(.)/$', '%1')\n    local entry_path = join_path(temp_dir, entry_name)\n    open(temp_dir, false)\n\n    -- Perform rename\n    type_keys('A', '-new', '<Esc>')\n    local new_entry_path = join_path(temp_dir, entry_name .. '-new')\n\n    mock_confirm(1)\n    if inject_external_delete then child.fn.delete(entry_path, 'rf') end\n    synchronize()\n\n    -- If there was external delete, then action was not successful and thus\n    -- event should not trigger\n    local ref = inject_external_delete and {} or { { action = 'rename', from = entry_path, to = new_entry_path } }\n    validate_event_track(ref)\n\n    -- Cleanup\n    close()\n    child.fn.delete(temp_dir, 'rf')\n    clear_event_track()\n  end\n\n  validate('file', false)\n  validate('file', true)\n  validate('dir/', false)\n  validate('dir/', true)\nend\n\nT['Events']['`MiniFilesActionCopy` triggers'] = function()\n  track_event('MiniFilesActionCopy')\n\n  local validate = function(entry, inject_external_delete)\n    local temp_dir = make_temp_dir('temp', { entry })\n    if entry == 'dir/' then\n      -- Test on non-empty directory\n      child.fn.mkdir(join_path(temp_dir, 'dir', 'subdir'))\n      child.fn.writefile({}, join_path(temp_dir, 'dir', 'subdir', 'subfile'))\n    end\n\n    local entry_name = entry:gsub('(.)/$', '%1')\n    local entry_path = join_path(temp_dir, entry_name)\n    open(temp_dir, false)\n\n    -- Perform copy in same parent directory\n    type_keys('yy', 'p', 'A', '-new', '<Esc>')\n    local new_entry_path = join_path(temp_dir, entry_name .. '-new')\n\n    mock_confirm(1)\n    if inject_external_delete then child.fn.delete(entry_path, 'rf') end\n    synchronize()\n\n    -- If there was external delete, then action was not successful and thus\n    -- event should not trigger\n    local ref = inject_external_delete and {} or { { action = 'copy', from = entry_path, to = new_entry_path } }\n    validate_event_track(ref)\n\n    -- Cleanup\n    close()\n    child.fn.delete(temp_dir, 'rf')\n    clear_event_track()\n  end\n\n  validate('file', false)\n  validate('file', true)\n  validate('dir/', false)\n  validate('dir/', true)\nend\n\nT['Events']['`MiniFilesActionMove` triggers'] = function()\n  track_event('MiniFilesActionMove')\n\n  local validate = function(entry, inject_external_delete)\n    local temp_dir = make_temp_dir('temp', { entry, 'a-dir/' })\n    local entry_name = entry:gsub('(.)/$', '%1')\n    local entry_path = join_path(temp_dir, entry_name)\n    open(temp_dir, false)\n\n    -- Perform move\n    type_keys('j', 'dd', 'l', 'p')\n    local new_entry_path = join_path(temp_dir, 'a-dir', entry_name)\n\n    mock_confirm(1)\n    if inject_external_delete then child.fn.delete(entry_path, 'rf') end\n    synchronize()\n\n    -- If there was external delete, then action was not successful and thus\n    -- event should not trigger\n    local ref = inject_external_delete and {} or { { action = 'move', from = entry_path, to = new_entry_path } }\n    validate_event_track(ref)\n\n    -- Cleanup\n    close()\n    child.fn.delete(temp_dir, 'rf')\n    clear_event_track()\n  end\n\n  validate('file', false)\n  validate('file', true)\n  validate('dir/', false)\n  validate('dir/', true)\nend\n\nT['Default explorer'] = new_set()\n\nT['Default explorer']['works on startup'] = function()\n  vim.loop.os_setenv('USE_AS_DEFAULT_EXPLORER', 'true')\n  child.restart({ '-u', make_test_path('init-default-explorer.lua'), '--', test_dir_path })\n  child.expect_screenshot()\n\n  -- Should hide scratch buffer on file open\n  type_keys('G')\n  go_in()\n  close()\n  eq(#child.api.nvim_list_bufs(), 1)\nend\n\nT['Default explorer']['respects `options.use_as_default_explorer`'] = function()\n  vim.loop.os_setenv('USE_AS_DEFAULT_EXPLORER', 'false')\n  child.restart({ '-u', make_test_path('init-default-explorer.lua'), '--', test_dir_path })\n  eq(child.bo.filetype, 'netrw')\nend\n\nT['Default explorer']['works in `:edit .`'] = function()\n  child.cmd('edit ' .. test_dir_path)\n  child.expect_screenshot()\nend\n\nT['Default explorer']['works in `:vsplit .`'] = function()\n  child.cmd('vsplit ' .. test_dir_path)\n  child.expect_screenshot()\n\n  type_keys('G')\n  go_in()\n  close()\n  child.expect_screenshot()\n  eq(#child.api.nvim_list_bufs(), 2)\nend\n\nT['Default explorer']['works in `:tabfind .`'] = function()\n  child.set_size(15, 60)\n  child.o.showtabline = 0\n  child.o.laststatus = 0\n\n  child.cmd('tabfind ' .. test_dir_path)\n  child.expect_screenshot()\n\n  type_keys('G')\n  go_in()\n  close()\n  child.expect_screenshot()\n  eq(#child.api.nvim_list_bufs(), 2)\n  eq(#child.api.nvim_list_tabpages(), 2)\n  eq(child.cmd('messages'), '')\nend\n\nT['Default explorer']['handles close without opening file'] = function()\n  local validate = function()\n    local buf_name = child.api.nvim_buf_get_name(0)\n    child.cmd('edit ' .. test_dir_path)\n    eq(is_explorer_active(), true)\n    close()\n    eq(is_explorer_active(), false)\n    eq(child.api.nvim_buf_get_name(0), buf_name)\n    eq(#child.api.nvim_list_bufs(), 1)\n  end\n\n  -- Should hide \"directory buffer\" if there is no alternative buffer\n  validate()\n\n  -- Should smartly (preserving layout) delete \"directory buffer\"\n  local win_id_other = child.api.nvim_get_current_win()\n  child.cmd('wincmd v')\n  local win_id = child.api.nvim_get_current_win()\n  local buf_id = child.api.nvim_get_current_buf()\n\n  eq(child.fn.win_findbuf(buf_id), { win_id, win_id_other })\n  validate()\n  eq(child.fn.win_findbuf(buf_id), { win_id, win_id_other })\nend\n\nT['Default explorer']['handles forcing other window as current'] = function()\n  child.cmd('edit ' .. test_file_path)\n  local init_win_id = child.api.nvim_get_current_win()\n\n  child.cmd('edit ' .. test_dir_path)\n  expect.no_error(function() child.api.nvim_set_current_win(init_win_id) end)\n  if child.fn.has('nvim-0.10') == 1 then eq(child.api.nvim_get_current_win(), init_win_id) end\nend\n\nT['Internal helpers'] = new_set()\n\nT['Internal helpers']['path normalization works'] = function()\n  child.lua([[\n    local name, helpers = debug.getupvalue(MiniFiles.open, 1)\n    if name ~= 'H' then error('Something went wrong when trying to get local `H` table') end\n    _G.fs_normalize_path = helpers.fs_normalize_path\n  ]])\n  local validate = function(path, ref) eq(child.lua_get('_G.fs_normalize_path(...)', { path }), ref) end\n\n  if helpers.is_windows() then\n    validate('C://dir//file/', 'C://dir/file')\n    validate([[C:\\\\dir\\\\file\\]], 'C://dir/file')\n\n    -- Normalizing pure drive prefix as `C:/` while inside full path as `C://`\n    -- makes it aligned as `C:/` + `/` + <relative path>. It also fixes issues\n    -- with some system files (`C://swapfile.sys`) work only in the \"double\n    -- slash\" form. The `vim.uv.fs_stat('C:/swapfile.sys')` returns `nil`,\n    -- while `C://swapfile.sys` works.\n    validate('C:///', 'C:/')\n    validate('C://', 'C:/')\n    validate('C:/', 'C:/')\n    validate([[C:\\\\\\]], 'C:/')\n    validate([[C:\\\\]], 'C:/')\n    validate([[C:\\]], 'C:/')\n\n    validate('C:///file', 'C://file')\n    validate('C://file', 'C://file')\n    validate('C:/file', 'C://file')\n    validate([[C:\\\\\\file]], 'C://file')\n    validate([[C:\\\\file]], 'C://file')\n    validate([[C:\\file]], 'C://file')\n\n    -- UNC paths\n    validate('//?/wow', '//?/wow')\n    validate('//?/wow/', '//?/wow')\n    validate([[\\\\?\\wow]], '//?/wow')\n    validate([[\\\\?\\wow\\]], '//?/wow')\n    validate('//server/share', '//server/share')\n    validate([[\\server\\share]], '/server/share')\n    validate([[\\\\system07\\C$\\]], '//system07/C$')\n    validate([[\\\\.\\C:\\Test\\Foo.txt]], '//./C:/Test/Foo.txt')\n  else\n    validate('//many///slashes/', '/many/slashes')\n    validate('//', '/')\n    validate('/', '/')\n  end\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_fuzzy.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('fuzzy', config) end\nlocal unload_module = function() child.mini_unload('fuzzy') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\n--stylua: ignore end\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniFuzzy)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniFuzzy.config)'), 'table')\n\n  -- Check default values\n  eq(child.lua_get('MiniFuzzy.config.cutoff'), 100)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ cutoff = 300 })\n  eq(child.lua_get('MiniFuzzy.config.cutoff'), 300)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ cutoff = 'a' }, 'cutoff', 'number')\n  expect_config_error({ cutoff = 0 }, 'cutoff', 'not less than 1')\nend\n\nT['match()'] = new_set()\n\nT['match()']['works'] = function()\n  eq(\n    child.lua_get([[MiniFuzzy.match('gettime', 'get_cur_time')]]),\n    { positions = { 1, 2, 3, 9, 10, 11, 12 }, score = 1201 }\n  )\n  eq(child.lua_get([[MiniFuzzy.match('gettime', 'time_get')]]), { score = -1 })\nend\n\nT['match()']['handles cases when match is impossible'] = function()\n  -- Smaller candidate\n  eq(child.lua_get([[MiniFuzzy.match('a', '')]]), { score = -1 })\n  eq(child.lua_get([[MiniFuzzy.match('ab', 'a')]]), { score = -1 })\n\n  -- Empty word\n  eq(child.lua_get([[MiniFuzzy.match('', 'abc')]]), { positions = {}, score = -1 })\nend\n\nlocal validate_match = function(word, candidate, positions)\n  local output = child.lua_get('MiniFuzzy.match(...)', { word, candidate })\n  eq(output.positions, positions)\nend\n\nT['match()']['uses smart case'] = function()\n  validate_match('ab', 'aB', { 1, 2 })\n  validate_match('ab', 'Ab', { 1, 2 })\n  validate_match('ab', 'AB', { 1, 2 })\n\n  validate_match('Ab', 'ab', nil)\n  validate_match('Ab', 'Ab', { 1, 2 })\n  validate_match('Ab', 'AB', nil)\nend\n\nT['match()']['respects order of letters'] = function() validate_match('abc', 'bcacbac', { 3, 5, 7 }) end\n\nT['match()']['handles special characters'] = function()\n  validate_match('(.+*%-)', 'a(a.a+a*a%a-a)', { 2, 4, 6, 8, 10, 12, 14 })\nend\n\nT['match()']['finds best match in presence of many'] = function()\n  validate_match('ab', 'a__b_a__b_ab', { 11, 12 })\n  validate_match('ab', 'a__b_ab_a__b', { 6, 7 })\n  validate_match('ab', 'ab_a__b_a__b', { 1, 2 })\n\n  validate_match('ab', 'ab__ab', { 1, 2 })\nend\n\nT['match()']['has allowed limitations'] = function()\n  -- Output may be unintuitive if there are several optimal matches with same\n  -- score (same width and start position)\n  validate_match('abc', 'abbbc', { 1, 4, 5 })\nend\n\nlocal validate_score = function(word, candidate, score)\n  local output = child.lua_get('MiniFuzzy.match(...)', { word, candidate })\n  eq(output.score, score)\nend\n\nT['match()']['computes correct score'] = function()\n  validate_score('a', 'a', 101)\n  validate_score('a', '_a', 102)\n  validate_score('a', '__a', 103)\n\n  validate_score('ab', 'ab_', 201)\n  validate_score('ab', '_ab', 202)\n  validate_score('ab', 'a_b', 301)\n\n  validate_score('abc', 'abc__', 301)\n  validate_score('abc', '_abc_', 302)\n  validate_score('abc', '__abc', 303)\n  validate_score('abc', 'a_bc_', 401)\n  validate_score('abc', 'ab_c_', 401)\n  validate_score('abc', '_a_bc', 402)\n  validate_score('abc', '_ab_c', 402)\n  validate_score('abc', 'a__bc', 501)\n  validate_score('abc', 'a_b_c', 501)\n  validate_score('abc', 'ab__c', 501)\n\n  -- No match\n  validate_score('a', 'bcd', -1)\n  validate_score('ab', 'ba', -1)\nend\n\nT['match()']['respects `config.cutoff`'] = function()\n  child.lua('MiniFuzzy.config.cutoff = 10')\n  validate_score('ab', 'ab_', 21)\n\n  -- Should also use buffer local config\n  child.b.minifuzzy_config = { cutoff = 5 }\n  validate_score('ab', 'ab_', 11)\nend\n\nT['match()']['treats features bigger than `config.cutoff` the same'] = function()\n  reload_module({ cutoff = 4 })\n\n  validate_score('a', '__a', 7)\n  validate_score('a', '___a', 8)\n  validate_score('a', '____a', 8)\n\n  validate_score('ab', 'a_b', 13)\n  validate_score('ab', 'a__b', 17)\n  validate_score('ab', 'a___b', 17)\nend\n\nT['filtersort()'] = new_set()\n\nlocal filtersort = function(...) return child.lua_get('{ MiniFuzzy.filtersort(...) }', { ... }) end\n\nlocal validate_filtersort = function(word, candidate_array, matched_candidates)\n  local output = filtersort(word, candidate_array)\n  eq(output[1], matched_candidates)\nend\n\nT['filtersort()']['works'] = function()\n  eq(filtersort('a', { '_a', '__a', 'b', 'a' }), { { 'a', '_a', '__a' }, { 4, 1, 2 } })\n  eq(filtersort('a', {}), { {}, {} })\nend\n\nT['filtersort()']['uses smart case'] = function()\n  validate_filtersort('ab', { 'ab', 'aB', 'Ab', 'AB' }, { 'ab', 'aB', 'Ab', 'AB' })\n  validate_filtersort('Ab', { 'ab', 'aB', 'Ab', 'AB' }, { 'Ab' })\nend\n\nT['filtersort()']['preserves original order with equal matching score'] = function()\n  validate_filtersort(\n    'abc',\n    { 'ab__c', 'a__bc', 'a_b_c', '__abc', 'abc__' },\n    { 'abc__', '__abc', 'ab__c', 'a__bc', 'a_b_c' }\n  )\nend\n\nT['filtersort()']['works with empty arguments'] = function()\n  validate_filtersort('', { 'a', 'b', '_a' }, { 'a', 'b', '_a' })\n  validate_filtersort('a', {}, {})\nend\n\nT['process_lsp_items()'] = new_set()\n\nlocal new_item = function(filterText, label, newText, insertText)\n  return { filterText = filterText, label = label, textEdit = { newText = newText }, insertText = insertText }\nend\n\nlocal process_lsp_items = function(...) return child.lua_get('MiniFuzzy.process_lsp_items(...)', { ... }) end\n\nT['process_lsp_items()']['works'] = function()\n  local validate = function(items) eq(process_lsp_items(items, 'a'), { items[3], items[2], items[1] }) end\n  validate({ new_item('___a'), new_item('__a'), new_item('_a') })\n  validate({ new_item(nil, '___a'), new_item(nil, '__a'), new_item(nil, '_a') })\n\n  -- Should match all as is for empty string `base`\n  local items = { new_item(nil, '___a'), new_item(nil, '__a'), new_item(nil, '_a') }\n  eq(process_lsp_items(items, ''), items)\nend\n\nT['process_lsp_items()']['correctly extracts candidate from fields'] = function()\n  -- filterText > label; no other fields should matter\n  local validate = function(items) eq(process_lsp_items(items, 'a'), { items[2], items[1] }) end\n\n  validate({ new_item('__a', '_a'), new_item('_a', '__a') })\n  validate({ new_item('__a', nil, '_a'), new_item('_a', nil, '__a') })\n  validate({ new_item(nil, '__a', '_a'), new_item(nil, '_a', '__a') })\n  validate({ new_item('__a', nil, nil, '_a'), new_item('_a', nil, nil, '__a') })\n  validate({ new_item(nil, '__a', nil, '_a'), new_item(nil, '_a', nil, '__a') })\nend\n\nT['get_telescope_sorter()'] = new_set()\n\nT['get_telescope_sorter()']['is present'] = function() eq(child.lua_get('MiniFuzzy.get_telescope_sorter ~= nil'), true) end\n\nreturn T\n"
  },
  {
    "path": "tests/test_git.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('git', config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\nlocal new_buf = function() return child.api.nvim_create_buf(true, false) end\nlocal new_scratch_buf = function() return child.api.nvim_create_buf(false, true) end\nlocal get_buf = function() return child.api.nvim_get_current_buf() end\nlocal set_buf = function(buf_id) child.api.nvim_set_current_buf(buf_id) end\nlocal get_win = function() return child.api.nvim_get_current_win() end\n--stylua: ignore end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nlocal islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nlocal path_sep = package.config:sub(1, 1)\nlocal test_dir = 'tests/dir-git'\nlocal test_dir_absolute = vim.fn.fnamemodify(test_dir, ':p'):gsub('(.)[\\\\/]$', '%1')\nlocal test_file_absolute = test_dir_absolute .. path_sep .. 'file'\n\nlocal git_root_dir = test_dir_absolute .. path_sep .. 'git-repo'\nlocal git_repo_dir = git_root_dir .. path_sep .. '.git-dir'\nlocal git_dir_path = git_root_dir .. path_sep .. 'dir-in-git'\nlocal git_file_path = git_root_dir .. path_sep .. 'file-in-git'\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\n-- Time constants\nlocal repo_watch_delay = 50\nlocal small_time = helpers.get_time_const(10)\nlocal micro_time = 1\n\n-- Common wrappers\nlocal edit = function(path)\n  child.cmd('edit ' .. child.fn.fnameescape(path))\n  -- Slow context needs a small delay to get things up to date\n  if helpers.is_slow() then sleep(small_time) end\nend\n\nlocal log_calls = function(fun_name)\n  --stylua: ignore\n  local lua_cmd = string.format(\n    [[local orig = %s\n      _G.call_log = _G.call_log or {}\n      %s = function(...) table.insert(_G.call_log, { %s, ... }); return orig(...) end]],\n    fun_name, fun_name, vim.inspect(fun_name)\n  )\n  child.lua(lua_cmd)\nend\n\nlocal validate_calls = function(ref) eq(child.lua_get('_G.call_log'), ref) end\n\nlocal get_buf_data = forward_lua('require(\"mini.git\").get_buf_data')\n\nlocal is_buf_enabled = function(buf_id) return get_buf_data(buf_id) ~= vim.NIL end\n\nlocal make_minigit_name = function(buf_id, name)\n  if buf_id == 0 then buf_id = get_buf() end\n  return 'minigit://' .. buf_id .. '/' .. name\nend\n\nlocal validate_minigit_name = function(buf_id, ref_name)\n  eq(child.api.nvim_buf_get_name(buf_id), make_minigit_name(buf_id, ref_name))\nend\n\n-- Common mocks\n-- - Git mocks\nlocal mock_change_git_index = function()\n  local index_path = git_repo_dir .. '/index'\n  child.fn.writefile({}, index_path .. '.lock')\n  sleep(micro_time)\n  child.fn.delete(index_path)\n  child.loop.fs_rename(index_path .. '.lock', index_path)\nend\n\nlocal mock_executable = function()\n  child.lua([[\n    _G.orig_executable = vim.fn.executable\n    vim.fn.executable = function(exec) return exec == 'git' and 1 or _G.orig_executable(exec) end\n  ]])\nend\n\nlocal mock_init_track_stdio_queue = function()\n  child.lua([[\n    _G.init_track_stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', '?? file-in-git' } },   -- Get file status data\n    }\n  ]])\nend\n\nlocal mock_spawn = function()\n  local mock_file = test_dir_absolute .. '/mocks/spawn.lua'\n  local lua_cmd = string.format('dofile(%s)', vim.inspect(mock_file))\n  child.lua(lua_cmd)\nend\n\nlocal get_spawn_log = function() return child.lua_get('_G.spawn_log') end\n\nlocal validate_git_spawn_log = function(ref_log)\n  local spawn_log = get_spawn_log()\n\n  local n = math.max(#spawn_log, #ref_log)\n  for i = 1, n do\n    local real, ref = spawn_log[i], ref_log[i]\n    if real == nil then\n      eq('Real spawn log does not have entry for present reference log entry', ref)\n    elseif ref == nil then\n      eq(real, 'Reference does not have entry for present spawn log entry')\n    elseif islist(ref) then\n      eq(real, { executable = 'git', options = { args = ref, cwd = real.options.cwd } })\n    else\n      eq(real, { executable = 'git', options = ref })\n    end\n  end\nend\n\nlocal clear_spawn_log = function() child.lua('_G.spawn_log = {}') end\n\n-- - Notifications\nlocal mock_notify = function()\n  child.lua([[\n    _G.notify_log = {}\n    vim.notify = function(...) table.insert(_G.notify_log, { ... }) end\n  ]])\nend\n\nlocal get_notify_log = function() return child.lua_get('_G.notify_log') end\n\nlocal validate_notifications = function(ref_log, msg_pattern)\n  local notify_log = get_notify_log()\n  local n = math.max(#notify_log, #ref_log)\n  for i = 1, n do\n    local real, ref = notify_log[i], ref_log[i]\n    if real == nil then\n      eq('Real notify log does not have entry for present reference log entry', ref)\n    elseif ref == nil then\n      eq(real, 'Reference does not have entry for present notify log entry')\n    else\n      local expect_msg = msg_pattern and expect.match or eq\n      expect_msg(real[1], ref[1])\n      eq(real[2], child.lua_get('vim.log.levels.' .. ref[2]))\n    end\n  end\nend\n\nlocal clear_notify_log = function() return child.lua('_G.notify_log = {}') end\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      child.set_size(10, 15)\n      mock_spawn()\n      mock_notify()\n      mock_executable()\n\n      -- Populate child with frequently used paths\n      child.lua('_G.git_root_dir, _G.git_repo_dir = ' .. vim.inspect(git_root_dir) .. ', ' .. vim.inspect(git_repo_dir))\n      child.lua([[_G.rev_parse_track = _G.git_repo_dir .. '\\n' .. _G.git_root_dir]])\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniGit)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniGit'), 1)\n\n  -- User command\n  eq(child.fn.exists(':Git'), 2)\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n\n  eq(child.lua_get('type(_G.MiniGit.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniGit.config.' .. field), value) end\n\n  expect_config('job.git_executable', 'git')\n  expect_config('job.timeout', 30000)\n  expect_config('command.split', 'auto')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  load_module({ command = { split = 'vertical' } })\n  eq(child.lua_get('MiniGit.config.command.split'), 'vertical')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ job = 'a' }, 'job', 'table')\n  expect_config_error({ job = { git_executable = 1 } }, 'job.git_executable', 'string')\n  expect_config_error({ job = { timeout = 'a' } }, 'job.timeout', 'number')\n\n  expect_config_error({ command = 'a' }, 'command', 'table')\n  expect_config_error({ command = { split = 1 } }, 'command.split', 'one of')\n  expect_config_error({ command = { split = 'xxx' } }, 'command.split', 'one of')\nend\n\nT['setup()']['warns about missing executable'] = function()\n  load_module({ job = { git_executable = 'no-git-is-available' } })\n  validate_notifications({ { '(mini.git) There is no `no-git-is-available` executable', 'WARN' } })\nend\n\nT['setup()']['auto enables in all existing loaded buffers'] = function()\n  mock_init_track_stdio_queue()\n  child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n\n  local buf_id_bad_1 = new_scratch_buf()\n\n  edit(git_root_dir .. '/file-in-git_symlink-source')\n  local buf_id_bad_2 = get_buf()\n\n  edit(git_root_dir .. '/dir-in-git/file-in-dir-in-git')\n  local buf_id_other_normal = get_buf()\n\n  edit(git_file_path)\n  local buf_id_cur_normal = get_buf()\n\n  -- Make enable-able buffer normal+listed but unloaded\n  child.api.nvim_buf_delete(buf_id_bad_2, { unload = true })\n  eq(child.api.nvim_buf_is_loaded(buf_id_bad_2), false)\n  child.api.nvim_set_option_value('buflisted', true, { buf = buf_id_bad_2 })\n\n  load_module()\n  eq(is_buf_enabled(buf_id_cur_normal), true)\n  eq(is_buf_enabled(buf_id_other_normal), true)\n  eq(is_buf_enabled(buf_id_bad_1), false)\n  eq(is_buf_enabled(buf_id_bad_2), false)\n\n  -- Should not force load unloaded buffers\n  eq(child.api.nvim_buf_is_loaded(buf_id_bad_2), false)\nend\n\nT['show_at_cursor()'] = new_set({ hooks = { pre_case = load_module } })\n\nlocal show_at_cursor = forward_lua('MiniGit.show_at_cursor')\n\nT['show_at_cursor()']['works on commit'] = function()\n  local buf_id = get_buf()\n  set_lines({ 'abc1234.def' })\n  set_cursor(1, 0)\n  child.lua([[_G.stdio_queue = { { { 'out', 'commit abc123456\\nHello' } } }]])\n\n  show_at_cursor()\n\n  local ref_args = { '--no-pager', 'show', '--stat', '--patch', 'abc1234' }\n  local ref_git_spawn_log = { { args = ref_args, cwd = child.fn.getcwd() } }\n  validate_git_spawn_log(ref_git_spawn_log)\n  clear_spawn_log()\n\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(get_lines(), { 'commit abc123456', 'Hello' })\n  eq(child.o.filetype, 'git')\n\n  -- Should use `<cword>`\n  set_buf(buf_id)\n  set_cursor(1, 0)\n  child.bo.iskeyword = child.bo.iskeyword .. ',.'\n  show_at_cursor()\n  -- - No `git show` calls because \"abc1234.def\" does not match commit pattern\n  validate_git_spawn_log({})\nend\n\nT['show_at_cursor()']['uses correct pattern to match commit'] = function()\n  log_calls('MiniGit.show_at_cursor')\n\n  set_lines({ 'abc1234', 'abc123', 'abC1234', 'abc123x' })\n\n  local validate = function(cword, ref_is_commit)\n    set_lines({ cword })\n    set_cursor(1, 0)\n    clear_spawn_log()\n\n    show_at_cursor()\n    local ref_args = { '--no-pager', 'show', '--stat', '--patch', cword }\n    local spawn_log = get_spawn_log()\n    local is_commit = spawn_log[1] ~= nil and vim.deep_equal(spawn_log[1].options.args, ref_args)\n    eq(is_commit, ref_is_commit)\n  end\n\n  validate('abc1234', true)\n  validate('abc123', false)\n  validate('abC1234', false)\n  validate('abc123x', false)\n  validate('abc1234x', false)\nend\n\nT['show_at_cursor()']['uses `opts` on commit'] = function()\n  set_lines({ 'abc1234' })\n  child.lua([[_G.stdio_queue = { { { 'out', 'commit abc123456\\nHello' } } }]])\n\n  local init_win_id = get_win()\n  show_at_cursor({ split = 'vertical' })\n\n  eq(child.api.nvim_tabpage_get_number(0), 1)\n  eq(child.fn.winlayout(), { 'row', { { 'leaf', get_win() }, { 'leaf', init_win_id } } })\n  eq(get_lines(), { 'commit abc123456', 'Hello' })\n  eq(child.o.filetype, 'git')\nend\n\nT['show_at_cursor()'][\"works in 'mini.deps' confirmation buffer\"] = function()\n  local deps_buf_id = new_scratch_buf()\n  set_buf(deps_buf_id)\n  local lines = child.fn.readfile(test_dir_absolute .. '/deps-confirm')\n  set_lines(lines)\n  child.bo.filetype = 'minideps-confirm'\n  child.api.nvim_buf_set_name(0, 'mini-deps://confirm-update')\n\n  local validate_no_show = function(l_num)\n    -- Assume not existing `cwd` (because it should be called during checking\n    -- if the buffer's directory is inside git repo, which is not)\n    child.lua([[vim.fn.isdirectory = function() return 0 end]])\n\n    -- Should not depend on column\n    set_cursor(l_num, l_num % 13)\n    show_at_cursor()\n\n    eq(get_buf(), deps_buf_id)\n    eq(#child.api.nvim_list_tabpages(), 1)\n\n    -- A spawn log as if nothing is detected at \"show commit\" step (entries\n    -- come from the next steps)\n    validate_git_spawn_log({})\n    clear_spawn_log()\n    validate_notifications({ { '(mini.git) Nothing Git-related to show at cursor', 'WARN' } })\n    clear_notify_log()\n  end\n\n  local validate_show = function(l_num, commit, plugin_name)\n    -- Prepare spawn mocks data\n    mock_spawn()\n    child.lua([[_G.stdio_queue = { { { 'out', 'commit abc123456\\nHello' } } }]])\n    -- Assume `cwd` always exists (for easier `deps-confirm` mock text)\n    child.lua([[vim.fn.isdirectory = function() return 1 end]])\n\n    set_cursor(l_num, l_num % 13)\n    show_at_cursor()\n\n    -- Should show in commit info in separate tabpage\n    expect.no_equality(get_buf(), deps_buf_id)\n    eq(child.bo.filetype, 'git')\n    eq(get_lines(), { 'commit abc123456', 'Hello' })\n    eq(#child.api.nvim_list_tabpages(), 2)\n    eq(child.api.nvim_tabpage_get_number(0), 2)\n    eq(#child.api.nvim_tabpage_list_wins(0), 1)\n\n    local ref_git_spawn_log = {\n      {\n        args = { '--no-pager', 'show', '--stat', '--patch', commit },\n        cwd = '/home/user/.local/share/nvim/site/pack/deps/opt/' .. plugin_name,\n      },\n    }\n    validate_git_spawn_log(ref_git_spawn_log)\n    clear_spawn_log()\n    validate_notifications({})\n    clear_notify_log()\n\n    -- Clean up\n    child.cmd('quit')\n  end\n\n  for i = 1, 11 do\n    validate_no_show(i)\n  end\n  validate_show(12, 'aa339f6ab611da07183a7fe44daa482605392502', 'plugin_b')\n  validate_show(13, '093b29f2b409278e2ed69a90462fee54714b5a84', 'plugin_b')\n  validate_show(14, '093b29f2b409278e2ed69a90462fee54714b5a84', 'plugin_b')\n  validate_show(15, '093b29f2b409278e2ed69a90462fee54714b5a84', 'plugin_b')\n  validate_show(16, '093b29f2', 'plugin_b')\n  validate_show(17, '093b29f2', 'plugin_b')\n  validate_show(18, '093b29f2', 'plugin_b')\n  validate_show(19, 'bfe74a48', 'plugin_b')\n  validate_show(20, 'bfe74a48', 'plugin_b')\n  validate_show(21, 'bfe74a48', 'plugin_b')\n  validate_show(22, '3826d0c4', 'plugin_b')\n  validate_show(23, '3826d0c4', 'plugin_b')\n  validate_show(24, '3826d0c4', 'plugin_b')\n  validate_no_show(25)\n  validate_no_show(26)\n  validate_no_show(27)\n  validate_show(28, '3a3c6244553f13fdd92d312c82722b57ce6c4bec', 'plugin_c')\n  validate_show(29, 'fe3deb7f67ce0cc4ebfe2ea6c1c7ae1c7a939d73', 'plugin_c')\n  validate_show(30, 'fe3deb7f67ce0cc4ebfe2ea6c1c7ae1c7a939d73', 'plugin_c')\n  validate_show(31, 'fe3deb7f67ce0cc4ebfe2ea6c1c7ae1c7a939d73', 'plugin_c')\n  validate_show(32, 'fe3deb7', 'plugin_c')\n  validate_show(33, 'fe3deb7', 'plugin_c')\n  validate_show(34, 'fe3deb7', 'plugin_c')\n  validate_no_show(35)\n  validate_no_show(36)\n  validate_no_show(37)\n  validate_show(38, 'd231729b13da28fd1625c3d85f2315886ddeb05d', 'plugin_d')\nend\n\nT['show_at_cursor()'][\"uses `opts` in 'mini.deps' confirmation buffer\"] = function()\n  local deps_buf_id = new_scratch_buf()\n  set_buf(deps_buf_id)\n  local lines = child.fn.readfile(test_dir_absolute .. '/deps-confirm')\n  set_lines(lines)\n  child.bo.filetype = 'minideps-confirm'\n  child.api.nvim_buf_set_name(0, 'mini-deps://confirm-update')\n\n  child.lua([[vim.fn.isdirectory = function() return 1 end]])\n  child.lua([[_G.stdio_queue = { { { 'out', 'commit abc123456\\nHello' } } }]])\n\n  local init_win_id = get_win()\n  set_cursor(16, 0)\n  show_at_cursor({ split = 'vertical' })\n\n  expect.no_equality(get_buf(), deps_buf_id)\n  eq(child.api.nvim_tabpage_get_number(0), 1)\n  eq(child.fn.winlayout(), { 'row', { { 'leaf', get_win() }, { 'leaf', init_win_id } } })\n  eq(get_lines(), { 'commit abc123456', 'Hello' })\n  eq(child.o.filetype, 'git')\nend\n\nT['show_at_cursor()']['shows message if can not find commit'] = function()\n  local lines = child.fn.readfile(test_dir_absolute .. '/deps-confirm')\n  set_lines(lines)\n  set_cursor(16, 2)\n\n  -- Commit at cursor\n  show_at_cursor()\n  validate_notifications({ { '(mini.git) Can not show commit 093b29f2 in repo ' .. child.fn.getcwd(), 'WARN' } })\n  clear_notify_log()\n\n  -- 'mini.deps' confirmation buffer\n  child.bo.filetype = 'minideps-confirm'\n  child.api.nvim_buf_set_name(0, 'mini-deps://confirm-update')\n\n  show_at_cursor()\n  local path = '/home/user/.local/share/nvim/site/pack/deps/opt/plugin_b'\n  validate_notifications({ { '(mini.git) Can not show commit 093b29f2 in repo ' .. path, 'WARN' } })\nend\n\nT['show_at_cursor()']['works for diff source'] = function()\n  child.lua('MiniGit.show_diff_source = function() end')\n  log_calls('MiniGit.show_diff_source')\n\n  local log_output = child.fn.readfile(test_dir_absolute .. '/log-output')\n  set_lines(log_output)\n  set_cursor(17, 0)\n\n  local opts = { split = 'vertical', target = 'both' }\n  show_at_cursor(opts)\n  validate_calls({ { 'MiniGit.show_diff_source', opts } })\nend\n\nT['show_at_cursor()']['works for range history in tracked file'] = function()\n  child.lua('MiniGit.show_range_history = function() end')\n  log_calls('MiniGit.show_range_history')\n\n  mock_init_track_stdio_queue()\n  child.lua([[_G.stdio_queue = _G.init_track_stdio_queue]])\n  edit(git_file_path)\n  eq(is_buf_enabled(), true)\n\n  clear_spawn_log()\n  local opts = { line_start = 1, line_end = 2, split = 'vertical', log_args = { '--oneline' } }\n  show_at_cursor(opts)\n  validate_calls({ { 'MiniGit.show_range_history', opts } })\n  -- Should not use spawn to check if buffer is in repo (it is already tracked)\n  validate_git_spawn_log({})\nend\n\nT['show_at_cursor()']['works for range history in not tracked file'] = function()\n  child.lua('MiniGit.show_range_history = function() end')\n  log_calls('MiniGit.show_range_history')\n\n  -- Mock real path presence\n  child.lua([[\n    vim.loop.fs_realpath = function() return \"/home/user/repo-root/source/of/symlink\" end\n    vim.fn.isdirectory = function() return 1 end\n  ]])\n  child.lua([[_G.stdio_queue = { { { 'out', '/home/user/repo-root' } } }]])\n  set_lines({ 'Line 1' })\n\n  -- Should try to find Git root at symlink's source\n  show_at_cursor()\n  validate_git_spawn_log({\n    { args = { '--no-pager', 'rev-parse', '--show-toplevel' }, cwd = '/home/user/repo-root/source/of' },\n  })\n  validate_calls({ { 'MiniGit.show_range_history' } })\nend\n\nT['show_at_cursor()']['works for range history in `show_diff_source()` output'] = function()\n  child.lua('MiniGit.show_range_history = function() end')\n  log_calls('MiniGit.show_range_history')\n\n  child.lua([[_G.stdio_queue = { { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } } }]])\n  local log_output = child.fn.readfile(test_dir_absolute .. '/log-output')\n  set_lines(log_output)\n  set_cursor(17, 0)\n  child.lua('MiniGit.show_diff_source()')\n\n  local opts = { line_start = 1, line_end = 2, split = 'vertical', log_args = { '--oneline' } }\n  show_at_cursor(opts)\n  validate_calls({ { 'MiniGit.show_range_history', opts } })\nend\n\nT['show_at_cursor()']['works on nothing'] = function()\n  expect.no_error(show_at_cursor)\n  validate_notifications({ { '(mini.git) Nothing Git-related to show at cursor', 'WARN' } })\n  clear_notify_log()\n\n  -- Should work in non-path buffers\n  set_buf(new_scratch_buf())\n  child.api.nvim_buf_set_name(0, 'minigit://2/git show')\n  clear_spawn_log()\n  expect.no_error(show_at_cursor)\n  validate_notifications({ { '(mini.git) Nothing Git-related to show at cursor', 'WARN' } })\n  -- - Should not try to find git directory in \"show range history\" stage\n  validate_git_spawn_log({})\nend\n\nT['show_diff_source()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Show log output\n      local log_output = child.fn.readfile(test_dir_absolute .. '/log-output')\n      set_lines(log_output)\n\n      load_module()\n    end,\n  },\n})\n\nlocal show_diff_source = forward_lua('MiniGit.show_diff_source')\n\nT['show_diff_source()']['works'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }, -- Diff source\n  }]])\n\n  -- Show diff source\n  set_cursor(17, 0)\n  show_diff_source()\n\n  local ref_git_spawn_log = {\n    {\n      args = { '--no-pager', 'show', '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dir/file-after' },\n      cwd = child.fn.getcwd(),\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  eq(#child.api.nvim_list_tabpages(), 2)\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n\n  validate_minigit_name(0, 'show 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dir/file-after')\n  eq(get_lines(), { 'Line 1', 'Current line 2', 'Line 3' })\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['show_diff_source()']['works in not diff file'] = function()\n  set_lines({ 'Not', 'a', 'patch' })\n  set_cursor(3, 0)\n  expect.no_error(show_diff_source)\n  validate_notifications({\n    { '(mini.git) Could not find diff source. Ensure that cursor is inside a valid diff lines of git log.', 'WARN' },\n  })\nend\n\nT['show_diff_source()']['correctly identifies source'] = function()\n  local log_output = child.fn.readfile(test_dir_absolute .. '/log-output')\n  child.lua([[\n    _G.source_lines = {}\n    for i = 1, 500 do\n      table.insert(_G.source_lines, 'Line ' .. i)\n    end\n    _G.show_out = table.concat(_G.source_lines, '\\n')\n  ]])\n  local source_lines = child.lua_get('_G.source_lines')\n\n  local validate_ok = function(lnum, ref_commit, ref_path, ref_lnum)\n    mock_spawn()\n    child.lua([[_G.stdio_queue = { { { 'out', _G.show_out } } }]])\n    set_lines(log_output)\n    set_cursor(lnum, 0)\n\n    show_diff_source()\n    local ref_git_spawn_log =\n      { { args = { '--no-pager', 'show', ref_commit .. ':' .. ref_path }, cwd = child.fn.getcwd() } }\n    validate_git_spawn_log(ref_git_spawn_log)\n\n    eq(get_lines(), source_lines)\n    eq(get_cursor(), { ref_lnum, 0 })\n    validate_minigit_name(0, 'show ' .. ref_commit .. ':' .. ref_path)\n\n    -- Clean up\n    child.cmd('%bwipeout!')\n  end\n\n  local validate_no_ok = function(lnum)\n    mock_spawn()\n    set_lines(log_output)\n    set_cursor(lnum, 0)\n\n    expect.no_error(show_diff_source)\n    eq(get_spawn_log(), {})\n    validate_notifications({\n      { '(mini.git) Could not find diff source. Ensure that cursor is inside a valid diff lines of git log.', 'WARN' },\n    })\n    clear_notify_log()\n  end\n\n  local commit_after = '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2'\n  local commit_before = commit_after .. '~'\n\n  -- Cursor should be placed inside valid hunk\n  validate_no_ok(1)\n  validate_no_ok(2)\n  validate_no_ok(3)\n  validate_no_ok(10)\n  validate_no_ok(11)\n\n  -- Should place on the first line for lines showing target files\n  validate_ok(12, commit_before, 'dir/file-before', 1)\n  validate_ok(13, commit_after, 'dir/file-after', 1)\n\n  -- Should work inside hunks and place cursor on the corresponding line.\n  -- Should (with default `target = 'auto'`) pick \"before\" if on the deleted\n  -- line, \"after\" otherwise.\n  validate_ok(14, commit_after, 'dir/file-after', 1)\n  validate_ok(15, commit_after, 'dir/file-after', 1)\n  validate_ok(16, commit_before, 'dir/file-before', 2)\n  validate_ok(17, commit_after, 'dir/file-after', 2)\n  validate_ok(18, commit_after, 'dir/file-after', 3)\n\n  validate_ok(19, commit_after, 'dir/file-after', 316)\n  validate_ok(20, commit_after, 'dir/file-after', 317)\n  validate_ok(21, commit_after, 'dir/file-after', 318)\n  validate_ok(22, commit_after, 'dir/file-after', 319)\n  validate_ok(23, commit_after, 'dir/file-after', 320)\n\n  validate_no_ok(24)\n  validate_no_ok(25)\n\n  -- Should get proper (nearest from above) file\n  validate_ok(26, commit_before, 'file', 1)\n  validate_ok(27, commit_after, 'file', 1)\n\n  validate_ok(28, commit_after, 'file', 282)\n  validate_ok(29, commit_after, 'file', 283)\n  validate_ok(30, commit_before, 'file', 284)\n  validate_ok(31, commit_before, 'file', 285)\n  validate_ok(32, commit_after, 'file', 284)\n\n  -- - Between log entries is also not a valid diff line\n  validate_no_ok(33)\n\n  validate_no_ok(34)\n  validate_no_ok(35)\n\n  -- Should get proper (nearest from above) commit\n  -- Should also work with `diff.mnemonicPrefix=true` Git config setting, which\n  -- can have source and destination prefixes be not only `a/` and `b/`\n  local commit_after_2 = '7264474d3bda16d0098a7f89a4143fe4db3d82cf'\n  local commit_before_2 = commit_after_2 .. '~'\n  validate_ok(42, commit_before_2, 'dir/file1', 1)\n  validate_ok(43, commit_after_2, 'dir/file1', 1)\n  validate_ok(44, commit_after_2, 'dir/file1', 246)\n  validate_ok(45, commit_before_2, 'dir/file1', 247)\n  validate_ok(46, commit_after_2, 'dir/file1', 247)\nend\n\nT['show_diff_source()']['correctly identifies source for `:Git diff` output'] = function()\n  local diff_output = {\n    'diff --git a/file b/file',\n    'index a357c5c..7ec2b3c 100644',\n    '--- a/file',\n    '+++ b/file',\n    '@@ -1,2 +1,2 @@',\n    ' aaa',\n    '-uuu',\n    '+UUU',\n  }\n  child.lua('_G.diff_lines = ' .. vim.inspect(table.concat(diff_output, '\\n')))\n\n  child.lua([[\n    _G.stdio_queue = {\n      -- Mock initial spawns for gathering subcommand data\n      { { 'out', 'diff\\nshow' } }, { { 'out', 'diff\\nshow' } }, { { 'out', '' } },\n\n      { { 'out', _G.diff_lines } }, -- :Git diff\n      { { 'out', 'aaa\\nuuu' } },    -- \"Before\" state\n                                    -- No spawn for \"after\"\n\n      { { 'out', _G.diff_lines } }, -- :Git diff --cached\n      { { 'out', 'aaa\\nuuu' } },    -- \"Before\" state\n      { { 'out', 'aaa\\nUUU' } },    -- \"After\" state\n\n      { { 'out', _G.diff_lines } }, -- :Git diff abc1234\n      { { 'out', 'aaa\\nuuu' } },    -- \"Before\" state\n                                    -- No spawn for \"after\"\n    }\n  ]])\n\n  child.fn.chdir(test_dir_absolute)\n  local diff_win_id\n\n  local validate = function(lnum, ref_git_spawn_log, ref_lines, ref_cursor)\n    clear_spawn_log()\n    child.api.nvim_set_current_win(diff_win_id)\n    set_cursor(lnum, 0)\n\n    show_diff_source()\n\n    validate_git_spawn_log(ref_git_spawn_log)\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n\n    child.cmd('bwipeout!')\n  end\n\n  -- Compare index (before) and work tree (after)\n  child.cmd('Git diff')\n  diff_win_id = get_win()\n\n  -- - \"Before\"\n  validate(7, { { '--no-pager', 'show', ':0:file' } }, { 'aaa', 'uuu' }, { 2, 0 })\n  -- - \"After\"\n  validate(8, {}, { 'aaa', 'uuu', '', 'xxx' }, { 2, 0 })\n\n  -- Compare HEAD (before) and index (after)\n  child.cmd('Git diff --cached')\n  diff_win_id = get_win()\n\n  -- - \"Before\"\n  validate(7, { { '--no-pager', 'show', 'HEAD:file' } }, { 'aaa', 'uuu' }, { 2, 0 })\n  -- - \"After\"\n  validate(8, { { '--no-pager', 'show', ':0:file' } }, { 'aaa', 'UUU' }, { 2, 0 })\n\n  -- Compare commit (before) and work tree (after)\n  child.cmd('Git diff abc1234')\n  diff_win_id = get_win()\n\n  -- - \"Before\"\n  validate(7, { { '--no-pager', 'show', 'abc1234:file' } }, { 'aaa', 'uuu' }, { 2, 0 })\n  -- - \"After\"\n  validate(8, {}, { 'aaa', 'uuu', '', 'xxx' }, { 2, 0 })\nend\n\nT['show_diff_source()']['works when there is no \"before\" file'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }, -- Diff source\n  }]])\n  set_lines({\n    'commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2',\n    'Author: Neo McVim <neo.mcvim@gmail.com>',\n    'Date:   Sat May 4 16:24:15 2024 +0300',\n    '',\n    'Add file with relative path \"dev/null\".',\n    '',\n    'diff --git a/dev/null b/dev/null',\n    'new file mode 100644',\n    'index 0000000..f9264f7',\n    '--- /dev/null',\n    '+++ b/dev/null',\n    '@@ -0,0 +1,2 @@',\n    '+Hello',\n    '+World',\n  })\n\n  -- Target \"before\" should do nothing while showing notification\n  local init_buf_id = get_buf()\n  set_cursor(13, 0)\n\n  show_diff_source({ target = 'before' })\n  eq(get_buf(), init_buf_id)\n  eq(child.api.nvim_buf_get_name(0), '')\n\n  validate_git_spawn_log({})\n  clear_spawn_log()\n  validate_notifications({ { '(mini.git) No \"before\" as file was created', 'WARN' } })\n  clear_notify_log()\n\n  -- Target \"both\" should show only \"after\" in a specified split\n  set_cursor(13, 0)\n  show_diff_source({ target = 'both' })\n\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\n  validate_minigit_name(0, 'show 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dev/null')\n\n  validate_notifications({ { '(mini.git) No \"before\" as file was created', 'WARN' } })\nend\n\nT['show_diff_source()']['works when there is no \"after\" file'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }, -- Diff source\n  }]])\n  set_lines({\n    'commit 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2',\n    'Author: Neo McVim <neo.mcvim@gmail.com>',\n    'Date:   Sat May 4 16:24:15 2024 +0300',\n    '',\n    'Remove file with relative path \"dev/null\".',\n    '',\n    'diff --git a/dev/null b/dev/null',\n    'new file mode 100644',\n    'index 0000000..f9264f7',\n    '--- a/dev/null',\n    '+++ /dev/null',\n    '@@ -2 +0,0 @@',\n    '-Hello',\n    '-World',\n  })\n\n  -- Target \"after\" should do nothing while showing notification\n  local init_buf_id = get_buf()\n  set_cursor(13, 0)\n\n  show_diff_source({ target = 'after' })\n  eq(get_buf(), init_buf_id)\n  eq(child.api.nvim_buf_get_name(0), '')\n\n  validate_git_spawn_log({})\n  clear_spawn_log()\n  validate_notifications({ { '(mini.git) No \"after\" as file was deleted', 'WARN' } })\n  clear_notify_log()\n\n  -- Target \"both\" should show only \"before\" in a specified split\n  set_cursor(13, 0)\n  show_diff_source({ target = 'both' })\n\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\n  validate_minigit_name(0, 'show 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2~:dev/null')\n\n  validate_notifications({ { '(mini.git) No \"after\" as file was deleted', 'WARN' } })\nend\n\nT['show_diff_source()']['does not depend on cursor column'] = function()\n  local buf_id = get_buf()\n  for i = 0, 10 do\n    set_buf(buf_id)\n    set_cursor(17, i)\n    show_diff_source()\n    eq(get_cursor(), { 2, 0 })\n  end\nend\n\nT['show_diff_source()']['tries to infer and set filetype'] = function()\n  child.lua([[_G.stdio_queue = { { { 'out', 'local a = 1\\n-- This is a Lua comment' } } }]])\n  set_cursor(57, 0)\n  show_diff_source()\n\n  validate_minigit_name(0, 'show 7264474d3bda16d0098a7f89a4143fe4db3d82cf:file.lua')\n  eq(get_lines(), { 'local a = 1', '-- This is a Lua comment' })\n  eq(get_cursor(), { 1, 0 })\n  eq(child.bo.filetype, 'lua')\n  eq(child.wo.foldlevel, 0)\nend\n\nT['show_diff_source()']['respects `opts.split`'] = new_set(\n  { parametrize = { { 'horizontal' }, { 'vertical' }, { 'tab' } } },\n  {\n    test = function(split)\n      child.lua([[_G.stdio_queue = {\n        { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }, -- Diff source\n      }]])\n      set_cursor(17, 0)\n\n      local init_win_id = get_win()\n      show_diff_source({ split = split })\n      local cur_win_id = get_win()\n\n      local ref_git_spawn_log = {\n        {\n          args = { '--no-pager', 'show', '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dir/file-after' },\n          cwd = child.fn.getcwd(),\n        },\n      }\n      validate_git_spawn_log(ref_git_spawn_log)\n\n      validate_minigit_name(0, 'show 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dir/file-after')\n\n      -- Validate proper split\n      eq(#child.api.nvim_list_tabpages(), split == 'tab' and 2 or 1)\n      eq(child.api.nvim_tabpage_get_number(0), split == 'tab' and 2 or 1)\n\n      local ref_layout = ({\n        horizontal = { 'col', { { 'leaf', cur_win_id }, { 'leaf', init_win_id } } },\n        vertical = { 'row', { { 'leaf', cur_win_id }, { 'leaf', init_win_id } } },\n        tab = { 'leaf', cur_win_id },\n      })[split]\n      eq(child.fn.winlayout(), ref_layout)\n    end,\n  }\n)\n\nT['show_diff_source()']['works with `opts.split = \"auto\"`'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }, -- Diff source\n    { { 'out', 'Line 4\\nCurrent line 5\\nLine 6' } }, -- Diff source\n  }]])\n\n  local init_buf_id, init_win_id = get_buf(), get_win()\n\n  -- Should open in new tabpage if there is a non-minigit buffer visible\n  child.cmd('vertical split')\n  local buf_id = new_scratch_buf()\n  set_buf(buf_id)\n  child.api.nvim_buf_set_name(buf_id, make_minigit_name(buf_id, 'some mini.git buffer'))\n  eq(child.fn.winlayout()[1], 'row')\n\n  child.api.nvim_set_current_win(init_win_id)\n  set_cursor(17, 0)\n  show_diff_source({ split = 'auto' })\n  local win_id_1 = get_win()\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(child.fn.winlayout(), { 'leaf', win_id_1 })\n\n  -- Should split vertically if there are only minigit buffers visible\n  set_buf(init_buf_id)\n  child.api.nvim_buf_set_name(0, make_minigit_name(0, 'log -L1,1:file'))\n  set_cursor(17, 0)\n  show_diff_source({ split = 'auto' })\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(child.fn.winlayout(), { 'row', { { 'leaf', get_win() }, { 'leaf', win_id_1 } } })\nend\n\nT['show_diff_source()']['respects `opts.target`'] = function()\n  child.lua([[\n    local item = { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }\n    _G.stdio_queue = {\n      item, -- 'before'\n      item, -- 'before'\n      item, -- 'after'\n      item, -- 'after'\n      item, item, -- 'both'\n      item, item, -- 'both'\n      item, item, -- 'both'\n      item, item, -- 'both'\n    }]])\n\n  local init_lines = get_lines()\n  local commit_after = '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2'\n  local commit_before = commit_after .. '~'\n  local name_after = 'show ' .. commit_after .. ':dir/file-after'\n  local name_before = 'show ' .. commit_before .. ':dir/file-before'\n\n  local validate = function(target, lnum, layout_type, name, cursor)\n    child.cmd('%bwipeout!')\n    set_lines(init_lines)\n\n    set_cursor(lnum, 0)\n    show_diff_source({ target = target, split = 'tab' })\n\n    local layout = child.fn.winlayout()\n    eq(layout[1], layout_type)\n    validate_minigit_name(0, name)\n    eq(get_cursor(), cursor)\n\n    if layout_type == 'row' then\n      -- Current window with \"after\" file should be on the right\n      local all_wins, cur_win = child.api.nvim_tabpage_list_wins(0), get_win()\n      local other_win = all_wins[1] == cur_win and all_wins[2] or all_wins[1]\n      eq(layout, { 'row', { { 'leaf', other_win }, { 'leaf', cur_win } } })\n\n      -- Other window should contain \"before\" file\n      local other_buf = child.api.nvim_win_get_buf(other_win)\n      validate_minigit_name(other_buf, name_before)\n    end\n  end\n\n  -- \"Before\" should always show \"before\" file\n  validate('before', 17, 'leaf', name_before, { 2, 0 })\n  -- - Even when cursor is on \"+++ b/yyy\" line\n  validate('before', 13, 'leaf', name_before, { 1, 0 })\n\n  -- \"After\" should always show \"after\" file\n  validate('after', 16, 'leaf', name_after, { 1, 0 })\n  -- - Even when cursor is on \"--- a/xxx\" line\n  validate('after', 12, 'leaf', name_after, { 1, 0 })\n\n  -- \"Both\" should always show vertical split with \"after\" to the right\n  validate('both', 16, 'row', name_after, { 1, 0 })\n  validate('both', 17, 'row', name_after, { 2, 0 })\n  validate('both', 12, 'row', name_after, { 1, 0 })\n  validate('both', 13, 'row', name_after, { 1, 0 })\nend\n\nT['show_diff_source()']['uses correct working directory'] = function()\n  local root, repo = test_dir_absolute, git_repo_dir\n  local rev_parse_track = repo .. '\\n' .. root\n  child.lua('_G.rev_parse_track = ' .. vim.inspect(rev_parse_track))\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'A  log-output' } },    -- Get file status data\n\n      { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } } -- Show diff source\n    }\n  ]])\n\n  edit(test_dir_absolute .. '/log-output')\n  child.fn.chdir(git_dir_path)\n\n  set_cursor(17, 0)\n  show_diff_source()\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = test_dir_absolute,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = root,\n    },\n    {\n      args = {\n        '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n        '--', 'log-output'\n      },\n      cwd = root,\n    },\n    -- Should prefer buffer's Git root over Neovim's cwd. This is relevant if,\n    -- for some reason, log output is tracked in Git repo.\n    {\n      args = { '--no-pager', 'show', '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dir/file-after' },\n      cwd = root,\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['show_diff_source()']['validates arguments'] = function()\n  local validate = function(opts, error_pattern)\n    expect.error(function() show_diff_source(opts) end, error_pattern)\n  end\n\n  validate({ split = 'a' }, 'opts%.split.*one of')\n  validate({ target = 'a' }, 'opts%.target.*one of')\nend\n\nT['show_range_history()'] = new_set({\n  hooks = {\n    pre_case = function()\n      load_module()\n      set_lines({ 'aaa', 'bbb', 'ccc' })\n      child.fn.chdir(git_root_dir)\n      child.api.nvim_buf_set_name(0, git_root_dir .. '/dir/tmp-file')\n      child.lua('vim.loop.fs_realpath = function(path) return path end')\n      child.lua([[_G.stdio_queue = {\n        { { 'out', '' } },                           -- No uncommitted changes\n        { { 'out', 'commit abc1234\\nLog output' } }, -- Asked logs\n      }]])\n    end,\n  },\n})\n\nlocal show_range_history = forward_lua('MiniGit.show_range_history')\n\nT['show_range_history()']['works in Normal mode'] = function()\n  show_range_history()\n\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file' }, cwd = git_root_dir },\n    { args = { '--no-pager', 'log', '-L1,1:dir/tmp-file', 'HEAD' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should show in a new tabpage (with default `opts.split`) in proper buffer\n  eq(#child.api.nvim_list_tabpages(), 2)\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n\n  validate_minigit_name(0, 'log -L1,1:dir/tmp-file HEAD')\n  eq(child.bo.filetype, 'git')\n  eq(get_lines(), { 'commit abc1234', 'Log output' })\nend\n\nT['show_range_history()']['works in Visual mode'] = function()\n  set_cursor(2, 0)\n  type_keys('vj')\n\n  show_range_history()\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file' }, cwd = git_root_dir },\n    -- Should use lines of Visual selection\n    { args = { '--no-pager', 'log', '-L2,3:dir/tmp-file', 'HEAD' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  validate_minigit_name(0, 'log -L2,3:dir/tmp-file HEAD')\nend\n\nT['show_range_history()']['works in output of `show_diff_source()`'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', 'Line 1\\nCurrent line 2\\nLine 3' } }, -- Diff source\n    -- Should not ask for presence of uncommitted changes\n    { { 'out', 'commit abc1234\\nLog output' } },    -- Asked logs\n  }]])\n\n  -- Show diff source\n  local log_output = child.fn.readfile(test_dir_absolute .. '/log-output')\n  set_lines(log_output)\n  set_cursor(17, 0)\n\n  show_diff_source()\n  eq(get_lines(), { 'Line 1', 'Current line 2', 'Line 3' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Should properly parse file name and commit\n  show_range_history()\n\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'show', '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2:dir/file-after' }, cwd = git_root_dir },\n    {\n      args = { '--no-pager', 'log', '-L2,2:dir/file-after', '5ed8432441b495fa9bd4ad2e4f635bae64e95cc2' },\n      cwd = git_root_dir,\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  validate_minigit_name(0, 'log -L2,2:dir/file-after 5ed8432441b495fa9bd4ad2e4f635bae64e95cc2')\nend\n\nT['show_range_history()']['works with `diff_foldexpr`'] = function()\n  child.cmd('au FileType git setlocal foldmethod=expr foldexpr=v:lua.MiniGit.diff_foldexpr()')\n  show_range_history()\n  eq(child.wo.foldmethod, 'expr')\n  eq(child.wo.foldexpr, 'v:lua.MiniGit.diff_foldexpr()')\nend\n\nT['show_range_history()']['respects `opts.line_start` and `opts.line_end`'] = function()\n  show_range_history({ line_start = 2, line_end = 3 })\n\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file' }, cwd = git_root_dir },\n    { args = { '--no-pager', 'log', '-L2,3:dir/tmp-file', 'HEAD' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  validate_minigit_name(0, 'log -L2,3:dir/tmp-file HEAD')\nend\n\nT['show_range_history()']['respects `opts.log_args`'] = function()\n  show_range_history({ log_args = { '--oneline', '--topo-order' } })\n\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file' }, cwd = git_root_dir },\n    { args = { '--no-pager', 'log', '-L1,1:dir/tmp-file', 'HEAD', '--oneline', '--topo-order' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  validate_minigit_name(0, 'log -L1,1:dir/tmp-file HEAD --oneline --topo-order')\nend\n\nT['show_range_history()']['respects `opts.split`'] = new_set(\n  { parametrize = { { 'horizontal' }, { 'vertical' }, { 'tab' } } },\n  {\n    test = function(split)\n      local init_win_id = get_win()\n      show_range_history({ split = split })\n      local cur_win_id = get_win()\n\n      local ref_git_spawn_log = {\n        { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file' }, cwd = git_root_dir },\n        { args = { '--no-pager', 'log', '-L1,1:dir/tmp-file', 'HEAD' }, cwd = git_root_dir },\n      }\n      validate_git_spawn_log(ref_git_spawn_log)\n\n      validate_minigit_name(0, 'log -L1,1:dir/tmp-file HEAD')\n\n      -- Validate proper split\n      eq(#child.api.nvim_list_tabpages(), split == 'tab' and 2 or 1)\n      eq(child.api.nvim_tabpage_get_number(0), split == 'tab' and 2 or 1)\n\n      local ref_layout = ({\n        horizontal = { 'col', { { 'leaf', cur_win_id }, { 'leaf', init_win_id } } },\n        vertical = { 'row', { { 'leaf', cur_win_id }, { 'leaf', init_win_id } } },\n        tab = { 'leaf', cur_win_id },\n      })[split]\n      eq(child.fn.winlayout(), ref_layout)\n    end,\n  }\n)\n\nT['show_range_history()']['works with `opts.split = \"auto\"`'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', '' } },                           -- No uncommitted changes\n    { { 'out', 'commit abc1234\\nLog output' } }, -- Asked logs\n    { { 'out', '' } },                           -- No uncommitted changes\n    { { 'out', 'commit def4321\\nSomething' } },  -- Asked logs\n  }]])\n\n  -- Should open in new tabpage if there is a non-minigit buffer visible\n  child.cmd('vertical split')\n  local buf_id = new_scratch_buf()\n  set_buf(buf_id)\n  child.api.nvim_buf_set_name(buf_id, make_minigit_name(buf_id, 'some mini.git buffer'))\n  eq(child.fn.winlayout()[1], 'row')\n\n  show_range_history({ split = 'auto' })\n  local win_id_1 = get_win()\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(child.fn.winlayout(), { 'leaf', win_id_1 })\n\n  -- Should split vertically if there are only minigit buffers visible\n  show_range_history({ split = 'auto' })\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(child.fn.winlayout(), { 'row', { { 'leaf', get_win() }, { 'leaf', win_id_1 } } })\nend\n\nT['show_range_history()']['does nothing in presence of uncommitted changes'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', 'diff --git aaa bbb\\nSomething' } }, -- There are uncommitted changes\n  }]])\n\n  show_range_history()\n\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  validate_notifications({\n    { '(mini.git) Current file has uncommitted lines. Commit or stash before exploring history.', 'WARN' },\n  })\nend\n\nT['show_range_history()']['uses correct working directory'] = function()\n  mock_init_track_stdio_queue()\n  child.lua([[_G.stdio_queue = {\n    _G.init_track_stdio_queue[1],\n    _G.init_track_stdio_queue[2],\n    _G.init_track_stdio_queue[3],\n\n    { { 'out', '' } },                           -- No uncommitted changes\n    { { 'out', 'commit abc1234\\nLog output' } }, -- Asked logs\n  }]])\n\n  edit(git_root_dir .. '/dir-in-git/file-in-dir-in-git')\n  child.fn.chdir(test_dir_absolute)\n\n  show_range_history()\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir .. '/dir-in-git',\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = git_root_dir,\n    },\n    {\n      args = {\n        '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n        '--', 'dir-in-git/file-in-dir-in-git'\n      },\n      cwd = git_root_dir,\n    },\n    -- Should prefer buffer's Git root over Neovim's cwd\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir-in-git/file-in-dir-in-git' }, cwd = git_root_dir },\n    { args = { '--no-pager', 'log', '-L1,1:dir-in-git/file-in-dir-in-git', 'HEAD' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['show_range_history()']['resolves symlinks'] = function()\n  child.lua('vim.loop.fs_realpath = function(path) return path .. \"_symlink-source\" end')\n  show_range_history()\n\n  local ref_git_spawn_log = {\n    { args = { '--no-pager', 'diff', '-U0', 'HEAD', '--', 'dir/tmp-file_symlink-source' }, cwd = git_root_dir },\n    { args = { '--no-pager', 'log', '-L1,1:dir/tmp-file_symlink-source', 'HEAD' }, cwd = git_root_dir },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['show_range_history()']['validates arguments'] = function()\n  local validate = function(opts, error_pattern)\n    expect.error(function() show_range_history(opts) end, error_pattern)\n  end\n\n  validate({ line_start = 'a' }, 'line_start.*number')\n  validate({ line_end = 'a' }, 'line_end.*number')\n  -- - Supplying only one line means that the other won't be inferred\n  validate({ line_start = 1 }, 'number')\n  validate({ line_end = 1 }, 'number')\n  validate({ line_start = 2, line_end = 1 }, 'non%-decreasing')\n  validate({ log_args = 1 }, 'log_args.*array')\n  validate({ log_args = { a = 1 } }, 'log_args.*array')\n  validate({ split = 'a' }, 'opts%.split.*one of')\nend\n\nT['diff_foldexpr()'] = new_set({ hooks = { pre_case = load_module } })\n\nT['diff_foldexpr()']['works in `git log` output'] = function()\n  child.set_size(70, 50)\n  child.o.laststatus = 0\n  edit(test_dir_absolute .. '/log-output')\n  child.cmd('setlocal foldmethod=expr foldexpr=v:lua.MiniGit.diff_foldexpr()')\n\n  -- Should be one line per patch\n  child.o.foldlevel = 0\n  child.expect_screenshot()\n\n  -- Should be one line per patched file\n  child.o.foldlevel = 1\n  child.expect_screenshot()\n\n  -- Should be one line per hunk\n  child.o.foldlevel = 2\n  child.expect_screenshot()\n\n  -- Should be no folds\n  child.o.foldlevel = 3\n  child.expect_screenshot()\nend\n\nT['diff_foldexpr()']['works in diff patch'] = function()\n  child.set_size(25, 50)\n  child.o.laststatus = 0\n  edit(test_dir_absolute .. '/diff-output')\n  child.cmd('setlocal foldmethod=expr foldexpr=v:lua.MiniGit.diff_foldexpr()')\n\n  -- Should be one line per patch\n  child.o.foldlevel = 0\n  child.expect_screenshot()\n\n  -- Should be one line per patched file\n  child.o.foldlevel = 1\n  child.expect_screenshot()\n\n  -- Should be one line per hunk\n  child.o.foldlevel = 2\n  child.expect_screenshot()\n\n  -- Should be no folds\n  child.o.foldlevel = 3\n  child.expect_screenshot()\nend\n\nT['diff_foldexpr()']['accepts optional line number'] = function()\n  edit(test_dir_absolute .. '/log-output')\n  eq(child.lua_get('MiniGit.diff_foldexpr(1)'), 0)\n  eq(child.lua_get('MiniGit.diff_foldexpr(2)'), '=')\nend\n\nT['enable()'] = new_set({\n  hooks = {\n    pre_case = function()\n      mock_init_track_stdio_queue()\n      child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n      load_module()\n\n      -- Set up enableable buffer which is not yet enabled\n      child.g.minigit_disable = true\n      edit(git_file_path)\n      child.g.minigit_disable = nil\n    end,\n  },\n})\n\nlocal enable = forward_lua('MiniGit.enable')\n\nT['enable()']['works'] = function()\n  enable()\n  if helpers.is_slow() then sleep(small_time) end\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n      cwd = git_root_dir,\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  local summary = {\n    head = 'abc1234',\n    head_name = 'main',\n    in_progress = '',\n    repo = git_repo_dir,\n    root = git_root_dir,\n    status = '??',\n  }\n  eq(get_buf_data(), summary)\n  eq(child.b.minigit_summary, summary)\n  eq(child.b.minigit_summary_string, 'main (??)')\n\n  -- Should not re-enable alreaady enabled buffer\n  enable()\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Makes buffer disabled when deleted\n  log_calls('MiniGit.disable')\n  local buf_id = get_buf()\n  child.api.nvim_buf_delete(buf_id, { force = true })\n  validate_calls({ { 'MiniGit.disable', buf_id } })\nend\n\nT['enable()']['works in not normal buffer'] = function()\n  child.bo.buftype = 'acwrite'\n  enable()\n  eq(is_buf_enabled(), true)\nend\n\nT['enable()']['works in not current buffer'] = function()\n  local buf_id = get_buf()\n  set_buf(new_scratch_buf())\n  enable(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n  eq(get_buf() ~= buf_id, true)\nend\n\nT['enable()']['does not work in non-file buffer'] = function()\n  set_buf(new_buf())\n  enable()\n  eq(is_buf_enabled(), false)\n  validate_git_spawn_log({})\nend\n\nT['enable()']['resolves symlinks'] = function()\n  child.lua('vim.loop.fs_realpath = function(path) return path .. \"_symlink-source\" end')\n\n  child.lua([[\n    _G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } },              -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },                 -- Get HEAD data\n      { { 'out', '?? file-in-git_symlink-source' } }, -- Get file status data\n    }\n  ]])\n  enable()\n\n  -- Should run Git CLI with data *after* resolving symlink\n  local status_args = get_spawn_log()[3].options.args\n  eq({ status_args[4], status_args[#status_args] }, { 'status', 'file-in-git_symlink-source' })\n  eq(get_buf_data().status, '??')\n  eq(child.b.minigit_summary_string, 'main (??)')\nend\n\nT['enable()']['normalizes input buffer'] = function()\n  enable(0)\n  eq(is_buf_enabled(), true)\nend\n\nT['enable()']['makes buffer reset on rename'] = function()\n  enable()\n  local buf_id = get_buf()\n  log_calls('MiniGit.enable')\n  log_calls('MiniGit.disable')\n\n  child.api.nvim_buf_set_name(0, child.fn.fnamemodify(git_file_path, ':h') .. '/new-file')\n  validate_calls({ { 'MiniGit.disable', buf_id }, { 'MiniGit.enable', buf_id } })\nend\n\nT['enable()']['properly formats buffer-local summary string'] = function()\n  child.lua([[_G.stdio_queue = {\n    -- Initial tracking\n    { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n    { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n    { { 'out', '?? file-in-git' } },   -- Get file status data\n\n    -- No diff (should not be shown in summary string)\n    { { 'out', _G.rev_parse_track } },\n    { { 'out', 'abc1234\\nmain-1' } },\n    { { 'out', '   file-in-git' } },\n\n    -- Space as second character\n    { { 'out', _G.rev_parse_track } },\n    { { 'out', 'abc1234\\nmain-2' } },\n    { { 'out', 'A  file-in-git' } },\n\n    -- Space as first character\n    { { 'out', _G.rev_parse_track } },\n    { { 'out', 'abc1234\\nmain-3' } },\n    { { 'out', ' M file-in-git' } },\n  }]])\n\n  local validate = function(ref_summary_string) eq(child.b.minigit_summary_string, ref_summary_string) end\n\n  edit(git_file_path)\n  validate('main (??)')\n\n  edit('')\n  child.poke_eventloop()\n  validate('main-1')\n\n  edit('')\n  child.poke_eventloop()\n  validate('main-2 (A )')\n\n  edit('')\n  child.poke_eventloop()\n  validate('main-3 ( M)')\nend\n\nT['enable()']['validates arguments'] = function()\n  expect.error(function() enable({}) end, '`buf_id`.*valid buffer id')\nend\n\nT['enable()']['respects `vim.{g,b}.minigit_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local buf_id = new_buf()\n    if var_type == 'b' then child.api.nvim_buf_set_var(buf_id, 'minigit_disable', true) end\n    if var_type == 'g' then child.api.nvim_set_var('minigit_disable', true) end\n    enable(buf_id)\n    eq(is_buf_enabled(buf_id), false)\n    validate_git_spawn_log({})\n  end,\n})\n\nT['disable()'] = new_set({\n  hooks = {\n    pre_case = function()\n      mock_init_track_stdio_queue()\n      child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n      load_module()\n\n      -- Set up enabled buffer\n      edit(git_file_path)\n      eq(is_buf_enabled(), true)\n    end,\n  },\n})\n\nlocal disable = forward_lua('MiniGit.disable')\n\nT['disable()']['works'] = function()\n  local buf_id = get_buf()\n  clear_spawn_log()\n\n  disable()\n  eq(is_buf_enabled(buf_id), false)\n  validate_git_spawn_log({})\n  eq(child.api.nvim_get_autocmds({ buffer = buf_id }), {})\n  eq(child.b.minigit_summary, vim.NIL)\n  eq(child.b.minigit_summary_string, vim.NIL)\nend\n\nT['disable()']['works in not current buffer'] = function()\n  local buf_id = get_buf()\n  set_buf(new_scratch_buf())\n  disable(buf_id)\n  eq(is_buf_enabled(buf_id), false)\nend\n\nT['disable()']['works in not enabled buffer'] = function()\n  set_buf(new_scratch_buf())\n  eq(is_buf_enabled(), false)\n  expect.no_error(disable)\nend\n\nT['disable()']['normalizes input buffer'] = function()\n  local buf_id = get_buf()\n  disable(0)\n  eq(is_buf_enabled(buf_id), false)\nend\n\nT['disable()']['validates arguments'] = function()\n  expect.error(function() disable('a') end, '`buf_id`.*valid buffer id')\nend\n\nT['toggle()'] = new_set({ hooks = { pre_case = load_module } })\n\nlocal toggle = forward_lua('MiniGit.toggle')\n\nT['toggle()']['works'] = function()\n  mock_init_track_stdio_queue()\n  child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n  log_calls('MiniGit.enable')\n  log_calls('MiniGit.disable')\n\n  edit(git_file_path)\n  local buf_id = get_buf()\n  eq(is_buf_enabled(buf_id), true)\n  validate_calls({ { 'MiniGit.enable', buf_id } })\n\n  toggle()\n  eq(is_buf_enabled(buf_id), false)\n  validate_calls({ { 'MiniGit.enable', buf_id }, { 'MiniGit.disable', buf_id } })\n\n  toggle(buf_id)\n  eq(is_buf_enabled(buf_id), true)\n  validate_calls({ { 'MiniGit.enable', buf_id }, { 'MiniGit.disable', buf_id }, { 'MiniGit.enable', buf_id } })\nend\n\nT['get_buf_data()'] = new_set({\n  hooks = {\n    pre_case = function()\n      mock_init_track_stdio_queue()\n      child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n      load_module()\n\n      -- Set up enabled buffer\n      edit(git_file_path)\n      eq(is_buf_enabled(), true)\n    end,\n  },\n})\n\nT['get_buf_data()']['works'] = function()\n  local buf_id = get_buf()\n  local summary = {\n    head = 'abc1234',\n    head_name = 'main',\n    in_progress = '',\n    repo = git_repo_dir,\n    root = git_root_dir,\n    status = '??',\n  }\n  eq(get_buf_data(), summary)\n  eq(get_buf_data(0), summary)\n  eq(get_buf_data(buf_id), summary)\n\n  -- Works on not enabled buffer\n  set_buf(new_scratch_buf())\n  eq(is_buf_enabled(), false)\n  eq(get_buf_data(), vim.NIL)\n\n  -- Works on not current buffer\n  eq(get_buf_data(buf_id), summary)\nend\n\nT['get_buf_data()']['works for file not in repo'] = function()\n  mock_spawn()\n  child.lua('_G.process_mock_data = { { exit_code = 1 } }')\n  edit(test_file_absolute)\n  eq(get_buf_data(), {})\nend\n\nT['get_buf_data()']['validates arguments'] = function()\n  expect.error(function() get_buf_data('a') end, '`buf_id`.*valid buffer id')\nend\n\nT['get_buf_data()']['returns copy of underlying data'] = function()\n  local out = child.lua([[\n    local buf_data = MiniGit.get_buf_data()\n    buf_data.head = 'aaa'\n    return MiniGit.get_buf_data().head ~= 'aaa'\n  ]])\n  eq(out, true)\nend\n\nT['get_buf_data()']['works with several actions in progress'] = function()\n  child.fn.writefile({ '' }, git_repo_dir .. '/MERGE_HEAD')\n  child.fn.writefile({ '' }, git_repo_dir .. '/REVERT_HEAD')\n  MiniTest.finally(function()\n    child.fn.delete(git_repo_dir .. '/MERGE_HEAD')\n    child.fn.delete(git_repo_dir .. '/REVERT_HEAD')\n  end)\n\n  mock_spawn()\n  child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n  edit('')\n  eq(get_buf_data().in_progress, 'merge,revert')\nend\n\n-- Integration tests ==========================================================\nT['Auto enable'] = new_set({ hooks = { pre_case = load_module } })\n\nT['Auto enable']['works'] = function()\n  mock_init_track_stdio_queue()\n  child.lua([[_G.stdio_queue = {\n      _G.init_track_stdio_queue[1],\n      _G.init_track_stdio_queue[2],\n      _G.init_track_stdio_queue[3],\n\n      _G.init_track_stdio_queue[1],\n      _G.init_track_stdio_queue[2],\n      _G.init_track_stdio_queue[3],\n\n      _G.init_track_stdio_queue[1],\n      _G.init_track_stdio_queue[2],\n      _G.init_track_stdio_queue[3],\n    }\n  ]])\n\n  edit(git_file_path)\n  local buf_id = get_buf()\n  sleep(small_time)\n  eq(get_buf_data(buf_id).status, '??')\n\n  -- Should try auto enable in `BufEnter`\n  set_buf(new_scratch_buf())\n  disable(buf_id)\n  eq(is_buf_enabled(buf_id), false)\n  set_buf(buf_id)\n  sleep(small_time)\n  eq(get_buf_data(buf_id).status, '??')\n\n  -- Should auto enable only in listed buffers\n  set_buf(new_scratch_buf())\n  disable(buf_id)\n  child.api.nvim_buf_set_option(buf_id, 'buflisted', false)\n  set_buf(buf_id)\n  sleep(small_time)\n  eq(is_buf_enabled(buf_id), false)\nend\n\nT['Auto enable']['does not enable in not proper buffers'] = function()\n  -- Has set `vim.b.minigit_disable`\n  local buf_id_disabled = new_buf()\n  child.api.nvim_buf_set_name(buf_id_disabled, git_file_path)\n  child.api.nvim_buf_set_var(buf_id_disabled, 'minigit_disable', true)\n  set_buf(buf_id_disabled)\n  eq(is_buf_enabled(buf_id_disabled), false)\n\n  -- Is not normal\n  set_buf(new_scratch_buf())\n  eq(is_buf_enabled(), false)\n\n  -- Is not file buffer\n  set_buf(new_buf())\n  eq(is_buf_enabled(), false)\n\n  -- Should not error if buffer is not valid\n  expect.no_error(function()\n    child.lua([[\n      local buf_id = vim.api.nvim_create_buf(true, false)\n      vim.api.nvim_set_current_buf(buf_id)\n      vim.api.nvim_buf_delete(buf_id, { force = true })\n    ]])\n    eq(child.cmd_capture('1messages'), '')\n  end)\n\n  -- Should infer all above cases without CLI runs\n  validate_git_spawn_log({})\nend\n\nT['Auto enable']['works after `:edit`'] = function()\n  mock_init_track_stdio_queue()\n  child.lua([[_G.stdio_queue = {\n      _G.init_track_stdio_queue[1],\n      _G.init_track_stdio_queue[2],\n      _G.init_track_stdio_queue[3],\n\n      _G.init_track_stdio_queue[1],\n      _G.init_track_stdio_queue[2],\n      _G.init_track_stdio_queue[3],\n    }\n  ]])\n\n  edit(git_file_path)\n  local buf_id = get_buf()\n  eq(is_buf_enabled(buf_id), true)\n\n  log_calls('MiniGit.enable')\n  log_calls('MiniGit.disable')\n\n  edit('')\n  validate_calls({ { 'MiniGit.disable', buf_id }, { 'MiniGit.enable', buf_id } })\n  eq(get_buf_data(buf_id).root, git_root_dir)\nend\n\nT['Tracking'] = new_set({\n  hooks = {\n    pre_case = function()\n      load_module()\n      -- Ensure proper separators when dealing with paths\n      if helpers.is_windows() then child.lua('vim.loop.fs_realpath = function(path) return path end') end\n    end,\n  },\n})\n\nT['Tracking']['works outside of Git repo'] = function()\n  child.lua('_G.process_mock_data = { { exit_code = 1 } }')\n  edit(test_file_absolute)\n  eq(get_buf_data().repo, nil)\nend\n\nT['Tracking']['updates all buffers from same repo on repo change'] = function()\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo for first file\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data for first file\n      { { 'out', 'MM file-in-git' } },   -- Get file status data for first file\n\n      { { 'out', _G.rev_parse_track } },                 -- Get path to root and repo for second file\n      { { 'out', 'abc1234/main' } },                     -- Get HEAD data for second file\n      { { 'out', '?? dir-in-git/file-in-dir-in-git' } }, -- Get file status data for second file\n\n      -- Reaction to repo change\n      { { 'out', 'abc1234\\nmain' } },\n      { { 'out', 'MM file-in-git\\0A  dir-in-git/file-in-dir-in-git' } },\n    }\n  ]])\n\n  edit(git_file_path)\n  local buf_id_1 = get_buf()\n  sleep(small_time)\n\n  edit(git_root_dir .. '/dir-in-git/file-in-dir-in-git')\n  local buf_id_2 = get_buf()\n  sleep(small_time)\n\n  child.lua([[\n    _G.event_log = {}\n    local callback = function(data)\n      table.insert(_G.event_log, { event = data.event, data_buf = data.buf, cur_buf = vim.api.nvim_get_current_buf() })\n    end\n    vim.api.nvim_create_autocmd('User', { pattern = 'MiniGitUpdated', callback = callback })\n    vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWinEnter', 'WinEnter' }, { callback = callback })\n  ]])\n\n  -- Make change in '.git' directory\n  mock_change_git_index()\n  sleep(repo_watch_delay + small_time)\n\n  eq(get_buf_data(buf_id_1).status, 'MM')\n  eq(get_buf_data(buf_id_2).status, 'A ')\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = git_root_dir,\n    },\n    {\n      args = {\n        '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n        '--', 'file-in-git'\n      },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir .. '/dir-in-git',\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = git_root_dir,\n    },\n    {\n      args = {\n        '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n        '--', 'dir-in-git/file-in-dir-in-git'\n      },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = git_root_dir,\n    },\n    {\n      args = {\n        '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n        '--', 'file-in-git', 'dir-in-git/file-in-dir-in-git'\n      },\n      cwd = git_root_dir,\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  -- Should trigger 'MiniGitUpdated' event with target buffer being current\n  -- while not triggering other commong buffer-window events\n  local triggered_buffers = {}\n  for _, t in ipairs(child.lua_get('_G.event_log')) do\n    eq(t.data_buf, t.cur_buf)\n    eq(t.event, 'User')\n    triggered_buffers[t.data_buf] = true\n  end\n  eq(triggered_buffers, { [buf_id_1] = true, [buf_id_2] = true })\nend\n\nT['Tracking']['reacts to content change outside of current session'] = function()\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'M  file-in-git' } },   -- Get file status data\n\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data second time\n      { { 'out', 'MM file-in-git' } },   -- Get file status data second time\n    }\n  ]])\n\n  edit(git_file_path)\n  vim.fn.writefile({ '' }, git_file_path)\n  child.cmd('checktime')\n  sleep(small_time)\n\n  local summary =\n    { head = 'abc1234', head_name = 'main', in_progress = '', repo = git_repo_dir, root = git_root_dir, status = 'MM' }\n  eq(get_buf_data(), summary)\n  eq(child.b.minigit_summary, summary)\n  eq(child.b.minigit_summary_string, 'main (MM)')\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir,\n    },\n    { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n    { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n    { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n    { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['Tracking']['reacts to buffer rename'] = function()\n  -- This is the chosen way to track change in root/repo.\n  -- Rely on manual `:edit` otherwise.\n  local new_root, new_repo = child.fn.getcwd(), test_dir_absolute\n  local file_rel = 'tests' .. path_sep .. 'dir-git' .. path_sep .. 'file'\n  child.lua('_G.file_rel = ' .. vim.inspect(file_rel))\n  local new_rev_parse_track = new_repo .. '\\n' .. new_root\n  child.lua('_G.new_rev_parse_track = ' .. vim.inspect(new_rev_parse_track))\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- First get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- First get HEAD data\n      { { 'out', 'M  file-in-git' } },   -- First get file status data\n\n      { { 'out', _G.new_rev_parse_track } }, -- Second get path to root and repo\n      { { 'out', 'def4321\\ntmp' } },         -- Second get HEAD data\n      { { 'out', 'MM ' .. _G.file_rel } },   -- Second get file status data\n    }\n  ]])\n\n  edit(git_file_path)\n  sleep(small_time)\n\n  child.api.nvim_buf_set_name(0, test_file_absolute)\n  sleep(small_time)\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n      cwd = git_root_dir,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = test_dir_absolute,\n    },\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n      cwd = new_root,\n    },\n    {\n      args = { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', file_rel },\n      cwd = new_root,\n    },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\n\n  local summary = {\n    head = 'def4321',\n    head_name = 'tmp',\n    in_progress = '',\n    repo = new_repo,\n    root = new_root,\n    status = 'MM',\n  }\n  eq(get_buf_data(), summary)\n  eq(child.b.minigit_summary, summary)\n  eq(child.b.minigit_summary_string, 'tmp (MM)')\nend\n\nT['Tracking']['reacts to moving to not Git repo'] = function()\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'M  file-in-git' } },   -- Get file status data\n    }\n    _G.process_mock_data = { [4] = { exit_code = 1 } }\n  ]])\n\n  edit(git_file_path)\n  eq(is_buf_enabled(), true)\n  child.api.nvim_buf_set_name(0, test_file_absolute)\n  eq(get_buf_data(), {})\n  eq(#get_spawn_log(), 4)\nend\n\nT['Tracking']['reacts to staging'] = function()\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'MM file-in-git' } },   -- Get file status data\n\n      -- Emulate staging file\n      { { 'out', 'abc1234\\nmain' } },  -- Get HEAD data\n      { { 'out', 'M  file-in-git' } }, -- Get file status data\n    }\n  ]])\n\n  edit(git_file_path)\n  sleep(small_time)\n\n  -- Should react to change in index\n  eq(get_buf_data().status, 'MM')\n  mock_change_git_index()\n\n  -- - Reaction to change in '.git' directory is debouned with delay of 50 ms\n  sleep(repo_watch_delay - small_time)\n  eq(get_buf_data().status, 'MM')\n  eq(#get_spawn_log(), 3)\n\n  sleep(2 * small_time)\n  eq(get_buf_data().status, 'M ')\n  eq(#get_spawn_log(), 5)\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir,\n    },\n    { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n    { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n    { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n    { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['Tracking']['reacts to change in HEAD'] = function()\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'MM file-in-git' } },   -- Get file status data\n\n      -- Emulate changing branch\n      { { 'out', 'def4321\\ntmp' } },   -- Get HEAD data\n      { { 'out', '?? file-in-git' } }, -- Get file status data\n    }\n  ]])\n\n  edit(git_file_path)\n  sleep(small_time)\n\n  -- Should react to change of HEAD\n  eq(get_buf_data().head_name, 'main')\n  child.fn.writefile({ 'ref: refs/heads/tmp' }, git_repo_dir .. '/HEAD')\n\n  sleep(repo_watch_delay - small_time)\n  eq(get_buf_data().head_name, 'main')\n  eq(#get_spawn_log(), 3)\n\n  sleep(2 * small_time)\n  eq(get_buf_data().head_name, 'tmp')\n  eq(#get_spawn_log(), 5)\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      args = { '-c', 'gc.auto=0', 'rev-parse', '--path-format=absolute', '--git-dir', '--show-toplevel' },\n      cwd = git_root_dir,\n    },\n    { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n    { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n    { '-c', 'gc.auto=0', 'rev-parse', 'HEAD', '--abbrev-ref', 'HEAD' },\n    { '-c', 'gc.auto=0', '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z', '--', 'file-in-git' },\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT['Tracking']['detects action in progress immediately'] = function()\n  mock_init_track_stdio_queue()\n  child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n\n  child.fn.writefile({ '' }, git_repo_dir .. '/BISECT_LOG')\n  MiniTest.finally(function() child.fn.delete(git_repo_dir .. '/BISECT_LOG') end)\n\n  edit(git_file_path)\n  sleep(small_time)\n  eq(get_buf_data().in_progress, 'bisect')\nend\n\nT['Tracking']['reacts to new action in progress'] = function()\n  child.lua([[_G.stdio_queue = {\n    -- Initial tracking\n    { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n    { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n    { { 'out', '?? file-in-git' } },   -- Get file status data\n\n    { { 'out', 'abc1234\\nmain-1' } },\n    { { 'out', '   file-in-git' } },\n    { { 'out', 'abc1234\\nmain-2' } },\n    { { 'out', 'A  file-in-git' } },\n    { { 'out', 'abc1234\\nmain-3' } },\n    { { 'out', 'AM file-in-git' } },\n    { { 'out', 'abc1234\\nmain-4' } },\n    { { 'out', 'MM file-in-git' } },\n    { { 'out', 'abc1234\\nmain-5' } },\n    { { 'out', 'M  file-in-git' } },\n    { { 'out', 'abc1234\\nmain-6' } },\n    { { 'out', '!! file-in-git' } },\n  }]])\n  edit(git_file_path)\n\n  local action_files = { 'BISECT_LOG', 'CHERRY_PICK_HEAD', 'MERGE_HEAD', 'REVERT_HEAD', 'rebase-apply', 'rebase-merge' }\n  local output_in_progress = {}\n  local summary_strings = {}\n\n  for _, name in ipairs(action_files) do\n    local path = git_repo_dir .. '/' .. name\n    child.fn.writefile({ '' }, path)\n    sleep(repo_watch_delay + small_time)\n    output_in_progress[name] = get_buf_data().in_progress\n    summary_strings[name] = child.b.minigit_summary_string\n    child.fn.delete(path)\n  end\n\n  local ref_in_progress = {\n    BISECT_LOG = 'bisect',\n    CHERRY_PICK_HEAD = 'cherry-pick',\n    MERGE_HEAD = 'merge',\n    REVERT_HEAD = 'revert',\n    ['rebase-apply'] = 'apply',\n    ['rebase-merge'] = 'rebase',\n  }\n  eq(output_in_progress, ref_in_progress)\n\n  local ref_summary_strings = {\n    BISECT_LOG = 'main-1|bisect',\n    CHERRY_PICK_HEAD = 'main-2|cherry-pick (A )',\n    MERGE_HEAD = 'main-3|merge (AM)',\n    REVERT_HEAD = 'main-4|revert (MM)',\n    ['rebase-apply'] = 'main-5|apply (M )',\n    ['rebase-merge'] = 'main-6|rebase (!!)',\n  }\n  eq(summary_strings, ref_summary_strings)\nend\n\nT['Tracking']['does not react to \".lock\" files in repo directory'] = function()\n  mock_init_track_stdio_queue()\n  child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n  edit(git_file_path)\n  sleep(small_time)\n  eq(#get_spawn_log(), 3)\n\n  child.fn.writefile({ '' }, git_repo_dir .. '/tmp.lock')\n  MiniTest.finally(function() child.fn.delete(git_repo_dir .. '/tmp.lock') end)\n  sleep(repo_watch_delay + small_time)\n  eq(#get_spawn_log(), 3)\nend\n\nT['Tracking']['redraws statusline when summary is updated'] = function()\n  child.set_size(10, 30)\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'MM file-in-git' } },   -- Get file status data\n\n      -- Emulate staging file\n      { { 'out', 'abc1234\\nmain' } },  -- Get HEAD data\n      { { 'out', 'M  file-in-git' } }, -- Get file status data\n\n      -- Emulate writing a file\n      { { 'out', 'AM file-in-git' } }, -- Get file status data\n\n      -- Emulate changing branch\n      { { 'out', 'def4321\\ntmp' } },   -- Get HEAD data\n      { { 'out', '?? file-in-git' } }, -- Get file status data\n\n      -- Emulate \"in progress\"\n      { { 'out', 'ghi5678\\ntmp-2' } }, -- Get HEAD data\n      { { 'out', '!! file-in-git' } }, -- Get file status data\n    }\n  ]])\n\n  edit(git_file_path)\n  sleep(small_time)\n\n  child.o.laststatus = 2\n  child.o.statusline = '%!b:minigit_summary_string'\n  child.expect_screenshot()\n\n  -- Status change\n  mock_change_git_index()\n  sleep(repo_watch_delay + small_time)\n  child.expect_screenshot()\n\n  -- File content change\n  child.cmd('silent write')\n  sleep(small_time)\n  child.expect_screenshot()\n\n  -- Branch change\n  child.fn.writefile({ 'ref: refs/heads/tmp' }, git_repo_dir .. '/HEAD')\n  sleep(repo_watch_delay + small_time)\n  child.expect_screenshot()\n\n  -- \"In progress\" change\n  local path = git_repo_dir .. '/BISECT_LOG'\n  child.fn.writefile({ '' }, path)\n  MiniTest.finally(function() child.fn.delete(path) end)\n  sleep(repo_watch_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Tracking']['event is triggered'] = function()\n  child.lua([[\n    -- Should be able to override buffer-local variables\n    local override = function(data)\n      vim.b[data.buf].minigit_summary_string = vim.b[data.buf].minigit_summary_string ..\n      ' ' .. vim.tbl_count(vim.b[data.buf].minigit_summary)\n    end\n    local opts = { pattern = 'MiniGitUpdated', callback = override }\n    vim.api.nvim_create_autocmd('User', opts)\n  ]])\n\n  mock_init_track_stdio_queue()\n  child.lua('_G.stdio_queue = _G.init_track_stdio_queue')\n  edit(git_file_path)\n  sleep(small_time)\n  eq(child.b.minigit_summary_string, 'main (??) 6')\nend\n\nT['Tracking']['event is properly triggered on buffer write'] = function()\n  child.lua([[_G.stdio_queue = {\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo for first file\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data for first file\n      { { 'out', 'MM file-in-git' } },   -- Get file status data for first file\n\n      { { 'out', _G.rev_parse_track } },                 -- Get path to root and repo for second file\n      { { 'out', 'abc1234/main' } },                     -- Get HEAD data for second file\n      { { 'out', '?? dir-in-git/file-in-dir-in-git' } }, -- Get file status data for second file\n\n      -- Reaction to buffer write\n      { { 'out', 'A  dir-in-git/file-in-dir-in-git' } },\n    }\n  ]])\n\n  edit(git_file_path)\n  sleep(small_time)\n  edit(git_root_dir .. '/dir-in-git/file-in-dir-in-git')\n  sleep(small_time)\n  clear_spawn_log()\n\n  -- Should be triggered only for actually written buffer\n  child.lua([[\n    _G.event_log = {}\n    local callback = function(data)\n      table.insert(_G.event_log, data.buf)\n    end\n    vim.api.nvim_create_autocmd('User', { pattern = 'MiniGitUpdated', callback = callback })\n  ]])\n\n  child.cmd('write')\n  for _, buf_id in ipairs(child.lua_get('_G.event_log')) do\n    eq(buf_id, get_buf())\n  end\n\n  --stylua: ignore\n  local ref_git_spawn_log = {\n    {\n      '-c', 'gc.auto=0',\n      '--no-optional-locks', 'status', '--verbose', '--untracked-files=all', '--ignored', '--porcelain', '-z',\n      '--', 'dir-in-git/file-in-dir-in-git'\n    }\n  }\n  validate_git_spawn_log(ref_git_spawn_log)\nend\n\nT[':Git'] = new_set({\n  hooks = {\n    pre_case = function()\n      load_module()\n\n      -- Mock initial spawns for gathering subcommand data\n      child.lua([[\n        _G.stdio_queue = {\n          -- Get supported subcommands\n          { { 'out', 'add\\nblame\\ndiff\\nhelp\\nlog\\npush\\npull\\nshow\\nreflog\\nl' } },\n          -- Get \"info showing\" subcommands\n          { { 'out', 'blame\\ndiff\\nhelp\\nlog\\nshow' } },\n          -- Get aliases\n          { { 'out', 'alias.l log -5' } },\n        }\n      ]])\n    end,\n  },\n})\n\n--stylua: ignore\nlocal validate_command_init_setup = function(log_index, executable, cwd)\n  log_index = log_index or 1\n  executable = executable or 'git'\n  cwd = cwd or child.fn.getcwd()\n\n  local spawn_log = get_spawn_log()\n\n  -- Get supported subcommands\n  local supported_lists = table.concat({\n    'list-mainporcelain',\n    'list-ancillarymanipulators', 'list-ancillaryinterrogators',\n    'list-foreignscminterface',\n    'list-plumbingmanipulators', 'list-plumbinginterrogators',\n    'others', 'alias',\n  }, ',')\n  eq(\n    spawn_log[log_index],\n    { executable = executable, options = {  args = { '--no-pager', '--list-cmds=' .. supported_lists }, cwd = cwd } }\n  )\n\n  -- Get \"info showing\" subcommands\n  local info_lists = table.concat({ 'list-info', 'list-ancillaryinterrogators', 'list-plumbinginterrogators' }, ',')\n  eq(\n    spawn_log[log_index + 1],\n    { executable = executable, options = { args = { '--no-pager', '--list-cmds=' .. info_lists }, cwd = cwd } }\n  )\n\n  -- Get aliases\n  eq(\n    spawn_log[log_index + 2],\n    { executable = executable, options = { args = { '--no-pager', 'config','--get-regexp','alias.*', }, cwd = cwd } }\n  )\nend\n\nlocal validate_spawn_env = function(log_index, ref_env)\n  local log_entry = get_spawn_log()[log_index]\n\n  local out_env = {}\n  for _, env_pair in ipairs(log_entry.options.env) do\n    local var, val = string.match(env_pair, '^([^=]+)=(.*)$')\n    local ref_val = ref_env[var]\n    if ref_val ~= nil then out_env[var] = ref_val == true and true or val end\n  end\n\n  eq(out_env, ref_env)\nend\n\nlocal validate_command_call = function(log_index, args, executable, cwd)\n  executable = executable or 'git'\n  cwd = cwd or child.fn.getcwd()\n\n  local log_entry = get_spawn_log()[log_index]\n\n  eq(log_entry.executable, executable)\n  eq(log_entry.options.args, args)\n  eq(log_entry.options.cwd, cwd)\n\n  local ref_env = { GIT_EDITOR = true, GIT_SEQUENCE_EDITOR = true, GIT_PAGER = '', NO_COLOR = '1' }\n  validate_spawn_env(log_index, ref_env)\nend\n\nT[':Git']['works'] = function()\n  child.lua('_G.dur = ' .. (10 * small_time))\n  child.lua([[\n    -- Command stdout\n    table.insert(_G.stdio_queue, { { 'out', 'abc1234 Hello\\ndef4321 World' } })\n\n    -- Mock non-trivial command execution time\n    _G.process_mock_data = { [4] = { duration = _G.dur } }\n  ]])\n\n  -- Should execute command synchronously\n  local start_time = vim.loop.hrtime()\n  child.cmd('Git log --oneline')\n  local duration = 0.000001 * (vim.loop.hrtime() - start_time)\n  eq(10 * small_time <= duration and duration <= 14 * small_time, true)\n\n  -- Should properly gather subcommand data before executing command\n  local spawn_log = get_spawn_log()\n  validate_command_init_setup()\n  validate_command_call(4, { 'log', '--oneline' })\n  eq(#spawn_log, 4)\n\n  -- Should in some way show the output\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(get_lines(), { 'abc1234 Hello', 'def4321 World' })\n  eq(child.bo.filetype, 'git')\n  eq(child.bo.buflisted, false)\n  eq(child.bo.swapfile, false)\n  eq(child.wo.foldlevel, 0)\nend\n\nT[':Git']['works asynchronously with bang modifier'] = function()\n  child.lua([[\n    -- Command stdout\n    table.insert(_G.stdio_queue, { { 'out', 'abc1234 Hello\\ndef4321 World' } })\n\n    -- Mock non-trivial command execution time\n    _G.process_mock_data = { [4] = { duration = 50 } }\n  ]])\n\n  -- Should execute command asynchronously\n  local start_time = vim.loop.hrtime()\n  child.cmd('Git! log')\n  local duration = 0.000001 * (vim.loop.hrtime() - start_time)\n  eq(duration <= small_time, true)\n\n  -- Should properly gather subcommand data before executing command\n  eq(#get_spawn_log(), 4)\n\n  -- Should in some way show the output when the process is done\n  eq(child.bo.filetype == 'git', false)\n  sleep(repo_watch_delay - small_time)\n  eq(child.bo.filetype == 'git', false)\n  sleep(2 * small_time)\n  eq(child.bo.filetype == 'git', true)\nend\n\nT[':Git']['respects command modifiers'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'abc1234 Hello\\ndef4321 World' } })]])\n  local init_win_id = get_win()\n  -- Should also work with abbreviated versions\n  child.cmd('vertical bel Git log')\n  eq(child.bo.filetype, 'git')\n  eq(child.fn.winlayout(), { 'row', { { 'leaf', init_win_id }, { 'leaf', get_win() } } })\nend\n\nT[':Git']['works for subcommands which were not recognized as supported'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Success' } })]])\n  child.cmd('Git doesnotexist --hello')\n  validate_command_init_setup()\n  validate_command_call(4, { 'doesnotexist', '--hello' })\n  validate_notifications({ { '(mini.git) Success', 'INFO' } })\n  eq(#child.api.nvim_list_tabpages(), 1)\nend\n\nT[':Git']['output'] = new_set()\n\nT[':Git']['output']['in buffer when explicitly asked'] = function()\n  local validate = function(modifier)\n    child.cmd('%bwipeout')\n    eq(get_lines(), { '' })\n    local init_buf_id = get_buf()\n\n    child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Pushed successfully' } })]])\n    child.cmd(modifier .. ' Git push')\n    eq(get_buf() == init_buf_id, false)\n    eq(get_lines(), { 'Pushed successfully' })\n    validate_notifications({})\n  end\n\n  validate('tab')\n  validate('vertical')\n  validate('vert')\n\n  validate('horizontal')\n  validate('hor')\nend\n\nT[':Git']['output']['in notifications when not in buffer'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Pushed successfully' } })]])\n  local init_buf_id = get_buf()\n  child.cmd('Git push')\n  eq(get_buf() == init_buf_id, true)\n  eq(get_lines(), { '' })\n  validate_notifications({ { '(mini.git) Pushed successfully', 'INFO' } })\nend\n\nT[':Git']['output']['is omitted if no or empty `stdout` was given'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', '' } })]])\n  child.cmd('Git log')\n  eq(child.bo.filetype == 'git', false)\n  validate_notifications({})\nend\n\nT[':Git']['output']['sets filetype for common subcommands'] = function()\n  child.lua([[\n    table.insert(_G.stdio_queue, { { 'out', 'abc1234 Neo McVim' } })     -- blame\n    table.insert(_G.stdio_queue, { { 'out', 'commit abcd1234' } })       -- diff\n    table.insert(_G.stdio_queue, { { 'out', 'commit abc1234\\nHello' } }) -- log\n    table.insert(_G.stdio_queue, { { 'out', 'Help output' } })           -- help\n\n    table.insert(_G.stdio_queue, { { 'out', 'local a = 1' } })           -- show file content\n    local file_diff = 'commit: ' .. string.rep('abc12345', 40) .. '\\nHello'\n    table.insert(_G.stdio_queue, { { 'out', file_diff } })               -- show file diff\n  ]])\n\n  local validate = function(command, filetype)\n    child.cmd('%bwipeout')\n    local cur_buf_id = get_buf()\n    child.cmd(command)\n    eq(cur_buf_id == get_buf(), false)\n    eq(child.bo.filetype, filetype)\n    -- Should unfold only if no filetype is inferred\n    eq(child.wo.foldlevel, filetype == '' and 999 or 0)\n  end\n\n  validate('Git blame -- %', 'git')\n  validate('Git diff', 'diff')\n  validate('Git log', 'git')\n  validate('Git help commit', '')\n\n  child.cmd('au FileType lua,git setlocal foldlevel=0')\n  validate('Git show HEAD:file.lua', 'lua')\n  validate('Git show HEAD file.lua', 'git')\nend\n\nT[':Git']['output']['respects `:silent` modifier'] = function()\n  local validate = function(command)\n    child.cmd('%bwipeout')\n    child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Hello' } })]])\n    local init_buf_id = get_buf()\n    child.cmd(command)\n    eq(get_buf() == init_buf_id, true)\n    eq(get_lines(), { '' })\n    validate_notifications({})\n  end\n\n  -- Should show nothing in buffer\n  validate('silent Git log')\n\n  -- Should show no notifications\n  validate('silent Git push')\n\n  -- Should prefer `:silent` over explicit split modifiers\n  validate('silent vertical Git log')\nend\n\nT[':Git']['output']['respects `:unsilent` modifier'] = function()\n  local validate = function(command)\n    child.cmd('%bwipeout')\n    child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Hello' } })]])\n    local init_buf_id = get_buf()\n    child.cmd(command)\n    eq(get_buf() == init_buf_id, false)\n    eq(get_lines(), { 'Hello' })\n  end\n\n  -- Should prefer `:unsilent` over `:silent`\n  validate('silent unsilent Git log')\n  validate('unsilent silent Git log')\nend\n\nT[':Git']['output']['defines proper window/buffer cleanup'] = function()\n  -- Should delete buffer when window is closed\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Hello' } })]])\n  child.cmd('vertical Git log')\n\n  local buf_id_1 = get_buf()\n  eq(child.bo.filetype, 'git')\n  eq(get_lines(), { 'Hello' })\n\n  child.cmd('quit')\n  eq(child.api.nvim_buf_is_valid(buf_id_1), false)\n\n  -- Should close window when buffer is deleted\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'World' } })]])\n  child.cmd('vertical Git log')\n  local buf_id_2, win_id_2 = get_buf(), get_win()\n  set_buf(new_scratch_buf())\n  eq(#child.api.nvim_tabpage_list_wins(0), 2)\n  child.api.nvim_buf_delete(buf_id_2, { force = true })\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\n  eq(get_win() == win_id_2, false)\nend\n\nT[':Git']['output']['respects aliases'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Commit abc12345\\nHello' } })]])\n  -- The `l` is a an alias for `log -5` according to initial command setup\n  -- Thus should show output in a split (because 'log' does)\n  child.cmd('Git l')\n  eq(get_lines(), { 'Commit abc12345', 'Hello' })\n  eq(child.bo.filetype, 'git')\nend\n\nT[':Git']['can show process errors'] = function()\n  child.lua([[\n    table.insert(_G.stdio_queue, { { 'out', 'Extra info' }, { 'err', 'Error!' } })\n    _G.process_mock_data = { [4] = { exit_code = 1 } }\n  ]])\n\n  child.cmd('Git log')\n  eq(child.api.nvim_tabpage_get_number(0), 1)\n  eq(child.bo.filetype == 'git', false)\n  eq(get_lines(), { '' })\n\n  validate_notifications({ { '(mini.git) Error!\\nExtra info', 'ERROR' } })\nend\n\nT[':Git']['can show process warnings'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Hello' }, { 'err', 'Diagnostic' } })]])\n\n  child.cmd('Git log')\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(child.bo.filetype, 'git')\n  eq(get_lines(), { 'Hello' })\n\n  validate_notifications({ { '(mini.git) Diagnostic', 'WARN' } })\nend\n\nT[':Git']['preserves environment variables'] = function()\n  child.loop.os_setenv('HELLO', 'WORLD')\n\n  child.cmd('Git log')\n  local environ = get_spawn_log()[4].options.env\n  local has_var = false\n  for _, env_pair in ipairs(environ) do\n    if env_pair == 'HELLO=WORLD' then has_var = true end\n  end\n  eq(has_var, true)\nend\n\nT[':Git']['opens Git editor in current instance'] = new_set(\n  { parametrize = { { 'GIT_EDITOR' }, { 'GIT_SEQUENCE_EDITOR' } } },\n  {\n    test = function(env_var)\n      child.lua('_G.target_env_var = ' .. vim.inspect(env_var))\n\n      -- Should ignore timeout\n      child.lua('MiniGit.config.job.timeout = 5')\n\n      -- Set up content of edit message file\n      local editmsg_path = git_repo_dir .. path_sep .. 'COMMIT_EDITMSG'\n      child.lua('_G.editmsg_path = ' .. vim.inspect(editmsg_path))\n      local cur_lines = vim.fn.readfile(editmsg_path)\n      MiniTest.finally(function() vim.fn.writefile(cur_lines, editmsg_path) end)\n\n      -- Mock Git calling its editor\n      child.lua([[\n        table.insert(_G.stdio_queue, { { 'out', '' } }) -- `commit` output\n        table.insert(_G.stdio_queue, { { 'out', '' } }) -- tracking for editor buffer\n\n        local mock_git_editor = function(_, options)\n          -- Find value of target environment variable\n          local git_editor\n          local pattern = string.format('^%s=(.*)$', _G.target_env_var)\n          for _, env_pair in ipairs(options.env) do\n            git_editor = string.match(env_pair, pattern)\n            if git_editor ~= nil then break end\n          end\n\n          -- Mock Git calling its editor and waiting for editing being done in\n          -- the current process\n          local command = git_editor .. ' -- ' .. _G.editmsg_path\n          local on_exit = function()\n            _G.editmsg_lines = vim.fn.readfile(_G.editmsg_path)\n          end\n          _G.channel = vim.fn.jobstart(command, { on_exit = on_exit })\n        end\n        _G.process_mock_data = {\n          [4] = { action = mock_git_editor },\n          [5] = { exit_code = 1 }, -- tracking for editor buffer\n        }\n      ]])\n\n      local init_win_id = get_win()\n      child.cmd(':belowright vert Git commit --amend')\n\n      sleep(3 * small_time)\n      eq(child.api.nvim_buf_get_name(0), editmsg_path)\n      eq(get_lines(), { '', '# This is a mock of Git template for its `GIT_EDITOR`' })\n      eq(child.fn.winlayout(), { 'row', { { 'leaf', init_win_id }, { 'leaf', get_win() } } })\n      eq(child.bo.filetype, 'gitcommit')\n      eq(child.fn.mode(), 'n')\n      eq(child.wo.foldlevel, 0)\n\n      -- Should not stop due to timeout\n      local is_job_active = function() return child.lua_get('pcall(vim.fn.jobpid, _G.channel)') end\n      eq(is_job_active(), true)\n      sleep(repo_watch_delay)\n      eq(is_job_active(), true)\n\n      -- Should wait until editing is done (window is closed)\n      eq(child.lua_get('_G.editmsg_lines'), vim.NIL)\n      type_keys('i', 'My important text', '<Esc>')\n      child.cmd('write')\n      child.cmd('close')\n\n      sleep(small_time)\n      eq(is_job_active(), false)\n      eq(\n        child.lua_get('_G.editmsg_lines'),\n        { 'My important text', '# This is a mock of Git template for its `GIT_EDITOR`' }\n      )\n\n      -- Should produce no notifications\n      validate_notifications({})\n    end,\n  }\n)\n\nT[':Git']['uses correct working directory'] = function()\n  local root, repo = test_dir_absolute, git_repo_dir\n  local rev_parse_track = repo .. '\\n' .. root\n  child.lua('_G.rev_parse_track = ' .. vim.inspect(rev_parse_track))\n  child.lua([[_G.stdio_queue = {\n      -- File tracking\n      { { 'out', _G.rev_parse_track } }, -- Get path to root and repo\n      { { 'out', 'abc1234\\nmain' } },    -- Get HEAD data\n      { { 'out', 'M  file-in-git' } },   -- Get file status data\n\n      -- Command initial setup\n      { { 'out', 'add\\nblame\\ndiff\\nlog\\npush\\npull\\nshow\\nl' } }, -- Get supported subcommands\n      { { 'out', 'blame\\ndiff\\nlog\\nshow' } },                     -- Get \"info showing\" subcommands\n      { { 'out', 'alias.l log -5' } },                             -- Get aliases\n\n      -- Command output\n      { { 'out', 'commit abc1234\\nHello' } },\n      { { 'out', 'commit def4321\\nWorld' } },\n    }\n  ]])\n\n  edit(git_file_path)\n  eq(get_buf_data().root, root)\n  local cwd = git_dir_path\n  child.fn.chdir(cwd)\n\n  -- Actual command should be run in file's Git root\n  child.cmd('Git log')\n  validate_command_init_setup(4, 'git', cwd)\n  validate_command_call(7, { 'log' }, 'git', root)\n\n  -- Should recognize `<cwd>` as current working directory\n  child.cmd('Git -C <cwd> log')\n  validate_command_call(8, { '-C', cwd, 'log' }, 'git', cwd)\nend\n\nT[':Git']['caches subcommand data'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Hello' } })]])\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'World' } })]])\n\n  child.cmd('Git log --one')\n  child.cmd('Git log --two')\n  child.cmd('Git log --three')\n\n  -- Should collect helper subcommand data only once\n  validate_command_init_setup()\n  validate_command_call(4, { 'log', '--one' })\n  validate_command_call(5, { 'log', '--two' })\n  validate_command_call(6, { 'log', '--three' })\n  eq(#get_spawn_log(), 6)\nend\n\nT[':Git']['works with no initial subcommand data'] = function()\n  child.lua([[_G.stdio_queue = {\n    { { 'out', '' } },                          -- Not successful `--list-cmds` for supported commands\n    { { 'out', ''}, { 'err', 'What\\nError' } }, -- Not successful `--list-cmds` for info commands\n    { { 'out', '' }, { 'err', 'Error' } },      -- Not successful alias data gathering\n\n    { {'out', 'Hello'} } -- Command output\n  }]])\n\n  -- Should use some defaults. Like \"log\" should still show output in buffer.\n  child.cmd('Git log')\n  eq(child.api.nvim_tabpage_get_number(0), 2)\n  eq(child.bo.filetype, 'git')\nend\n\nT[':Git']['checks for present executable'] = function()\n  child.lua('vim.fn.executable = function() return 0 end')\n  load_module()\n  validate_notifications({ { '(mini.git) There is no `git` executable', 'WARN' } })\n  clear_notify_log()\n\n  child.cmd('Git log')\n  eq(#get_spawn_log(), 0)\n  validate_notifications({ { '(mini.git) There is no `git` executable', 'ERROR' } })\nend\n\nT[':Git']['respects `job.git_executable`'] = function()\n  child.lua('vim.fn.executable = function() return 1 end')\n  load_module({ job = { git_executable = 'my_git' } })\n\n  child.cmd('Git log')\n  eq(get_spawn_log()[4].executable, 'my_git')\nend\n\nT[':Git']['respects `job.timeout`'] = function()\n  child.lua('_G.duration = ' .. (5 * small_time))\n  child.lua([[\n    table.insert(_G.stdio_queue, { { 'out', 'Hello' } })\n\n    _G.process_mock_data = { [4] = { duration = _G.duration } }\n  ]])\n\n  child.lua('MiniGit.config.job.timeout = ' .. (2 * small_time))\n\n  local start_time = vim.loop.hrtime()\n  child.cmd('Git log')\n  local duration = 0.000001 * (vim.loop.hrtime() - start_time)\n  eq((1.5 * small_time) <= duration and duration <= (2.5 * small_time), true)\n\n  local ref_notify_log = {\n    { '(mini.git) PROCESS REACHED TIMEOUT', 'WARN' },\n    -- Should still process `stdout`/`stderr` which was already supplied\n    -- Shown as error because timeout is treated same as error\n    { '(mini.git) \\nHello', 'ERROR' },\n  }\n  validate_notifications(ref_notify_log)\nend\n\nT[':Git']['respects `command.split`'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'Hello' } })]])\n  child.lua([[MiniGit.config.command.split = 'vertical']])\n\n  local init_win_id = get_win()\n  child.cmd('Git log')\n  eq(child.bo.filetype, 'git')\n  eq(child.fn.winlayout(), { 'row', { { 'leaf', get_win() }, { 'leaf', init_win_id } } })\nend\n\nT[':Git']['completion'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.fn.chdir(test_dir_absolute)\n      child.lua([[_G.help_lines = vim.fn.readfile('help-output')]])\n      child.lua([[_G.help_output = { { 'out', table.concat(_G.help_lines, '\\n') } }]])\n\n      child.set_size(17, 32)\n      child.o.cmdheight = 2\n      child.o.laststatus = 0\n    end,\n  },\n})\n\nlocal validate_command_completion = function(line, col)\n  local line_len = vim.api.nvim_strwidth(line)\n  col = col or (line_len + 1)\n  if col < 0 then col = line_len + 1 + col end\n\n  type_keys('<C-c>', line)\n  for _ = line_len, col, -1 do\n    type_keys('<Left>')\n  end\n  type_keys('<Tab>')\n  child.expect_screenshot()\nend\n\nT[':Git']['completion']['works with subcommands'] = function()\n  validate_command_completion(':Git ')\n  validate_command_completion(':Git l')\n\n  -- Should work if there is text afterwards\n  validate_command_completion(':Git  -v', -3)\n\n  -- Should also work with two word subcommands\n  validate_command_completion(':Git reflog')\n  validate_command_completion(':Git reflog -v', -3)\n  validate_command_completion(':Git reflog\\\\ ')\nend\n\nT[':Git']['collects data about available subcommands'] = function()\n  type_keys(':Git ', '<Tab>')\n  validate_command_init_setup()\n\n  -- Should cache result and do this only once\n  type_keys('<C-c>', ':Git ', '<Tab>')\n  eq(#get_spawn_log(), 3)\nend\n\nT[':Git']['completion']['works with options'] = function()\n  child.set_size(20, 40)\n  child.lua('table.insert(_G.stdio_queue, _G.help_output)')\n\n  -- Should get output by making CLI call\n  validate_command_completion(':Git push -')\n\n  local spawn_log = get_spawn_log()\n  eq(#spawn_log, 4)\n  eq(spawn_log[4].options.args, { '--no-pager', 'help', '--man', 'push' })\n  eq(spawn_log[4].options.cwd, child.fn.getcwd())\n  validate_spawn_env(4, { MANPAGER = 'cat', NO_COLOR = '1', PAGER = 'cat' })\n\n  -- Should work several times\n  type_keys(' --', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should pre-filter candidates\n  validate_command_completion(':Git push --')\n  validate_command_completion(':Git push --no')\n\n  -- Should work when there is text afterwards\n  validate_command_completion(':Git push -- origin', -7)\n\n  -- Should cache option candidates for particular subcommand\n  eq(get_spawn_log(), spawn_log)\n\n  -- Works with aliases\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', '' } })]])\n  validate_command_completion(':Git l -')\n\n  spawn_log = get_spawn_log()\n  eq(#spawn_log, 5)\n  -- - Should try to parse help page for the command it is aliased to\n  eq(spawn_log[5].options.args, { '--no-pager', 'help', '--man', 'log' })\n  eq(spawn_log[5].options.cwd, child.fn.getcwd())\n  validate_spawn_env(5, { MANPAGER = 'cat', NO_COLOR = '1', PAGER = 'cat' })\n  eq(#spawn_log, 5)\n\n  -- Works with \"old\" forced formatting in output\n  child.set_size(10, 30)\n  child.lua([[\n    local old_format_lines = {\n      'N\\bNA\\bAM\\bME\\bE', 'add', '',\n      'O\\bOP\\bPT\\bTI\\bIO\\bON\\bNS\\bS', '',\n      '       --all',\n      '       -v, --verbose',\n    }\n    table.insert(_G.stdio_queue, { { 'out', table.concat(old_format_lines, '\\n') } })\n  ]])\n  validate_command_completion(':Git add -')\nend\n\nT[':Git']['completion']['works with explicit paths'] = function()\n  child.set_size(15, 50)\n\n  -- Should incrementally suggest paths relative to root after explicit \" -- \"\n  type_keys(':Git add -- ', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should allow pressing \"/\" to continue completion immediately\n  type_keys('/', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should not error if there is no present paths to complete from\n  type_keys('aa', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should work multiple times\n  type_keys(' f', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should respect explicit '\\ ' and treat it as part of completion base\n  validate_command_completion(':Git add -- git-repo/\\\\ ')\nend\n\nT[':Git']['completion']['uses correct working directory for paths'] = function()\n  child.set_size(15, 40)\n  mock_init_track_stdio_queue()\n  child.lua([[_G.stdio_queue = {\n    _G.init_track_stdio_queue[1],\n    _G.init_track_stdio_queue[2],\n    _G.init_track_stdio_queue[3],\n\n    -- Get initial data about subcommands\n    { { 'out', 'add\\nblame\\ndiff\\nlog\\npush\\npull\\nshow\\nreflog\\nl' } },\n    { { 'out', 'blame\\ndiff\\nlog\\nshow' } },\n    { { 'out', 'alias.l log -5' } },\n  }]])\n\n  child.fn.chdir(test_dir_absolute)\n  edit(git_file_path)\n  validate_command_completion(':Git add -- ')\nend\n\n--stylua: ignore\nT[':Git']['completion']['works with subcommand targets'] = function()\n  child.set_size(15, 40)\n  child.lua([[\n    _G.subcommands_with_special_targets = {\n      'add', 'mv', 'restore', 'rm',\n      'diff', 'grep', 'log', 'show',\n      'branch', 'commit', 'merge', 'rebase', 'reset', 'switch', 'tag',\n      'fetch', 'push', 'pull',\n      'checkout', 'config', 'help'\n    }\n    _G.supported = table.concat(_G.subcommands_with_special_targets, '\\n')\n\n    _G.stdio_queue = {\n      -- Get initial data about subcommands\n      { { 'out', _G.supported .. '\\nl' } },\n      { { 'out', 'blame\\ndiff\\nlog\\nshow' } },\n      { { 'out', 'alias.l log -5' } },\n\n      -- Mock calls for getting completion candidates\n      { {'out', 'main\\nv0.1.0'} },              -- log\n      { {'out', 'main\\nv0.2.0'} },              -- show\n      { {'out', 'main\\ntmp'} },                 -- branch\n      { {'out', 'main\\ntmp2'} },                -- merge\n      { {'out', 'main\\ntmp3'} },                -- rebase\n      { {'out', 'main\\nv0.3.0'} },              -- reset\n      { {'out', 'main\\ntmp4'} },                -- switch\n      { {'out', 'v0.1.0\\nv0.2.0'} },            -- tag\n      { {'out', 'origin\\nupstream'} },          -- remote\n      { {'out', 'origin\\nupstream2'} },         -- push\n      { {'out', 'origin\\norigin2'} },           -- push 2\n      { {'out', 'main\\nv0.4.0'} },              -- push 3\n      { {'out', 'main\\nv0.4.0'} },              -- push 4\n      { {'out', 'main\\nv0.4.0'} },              -- push 5\n      { {'out', 'origin\\nupstream3'} },         -- pull\n      { {'out', 'origin\\norigin3'} },           -- pull 2\n      { {'out', 'main\\nv0.5.0'} },              -- pull 3\n      { {'out', 'main\\nv0.5.0'} },              -- pull 4\n      { {'out', 'main\\nv0.5.0'} },              -- pull 5\n      { {'out', 'main\\nv0.6.0'} },              -- checkout\n      { {'out', 'author.email\\nauthor.name'} }, -- config\n      { {'out', 'main\\nv0.1.0'} },              -- l (`log` alias)\n    }]])\n\n  local validate_latest_spawn_args = function(ref_args)\n    local spawn_log = get_spawn_log()\n    eq(spawn_log[#spawn_log].options.args, ref_args)\n  end\n\n  validate_command_completion(':Git add ')     -- path\n  validate_command_completion(':Git mv ')      -- path\n  validate_command_completion(':Git restore ') -- path\n  validate_command_completion(':Git rm ')      -- path\n  validate_command_completion(':Git diff ')    -- path\n  validate_command_completion(':Git grep ')    -- path\n\n  validate_command_completion(':Git log ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n\n  validate_command_completion(':Git show ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n\n  validate_command_completion(':Git branch ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches' })\n\n  validate_command_completion(':Git commit ') -- path\n\n  validate_command_completion(':Git merge ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches' })\n\n  validate_command_completion(':Git rebase ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches' })\n\n  validate_command_completion(':Git reset ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n\n  validate_command_completion(':Git switch ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches' })\n\n  validate_command_completion(':Git tag ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--tags' })\n\n  validate_command_completion(':Git fetch ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'remote' })\n\n  validate_command_completion(':Git push ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'remote' })\n  validate_command_completion(':Git push origin')\n  validate_latest_spawn_args({ '--no-pager', 'remote' })\n  validate_command_completion(':Git push origin ')\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n  validate_command_completion(':Git push origin v')\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n  validate_command_completion(':Git push origin main ')\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n\n  validate_command_completion(':Git pull ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'remote' })\n  validate_command_completion(':Git pull origin')\n  validate_latest_spawn_args({ '--no-pager', 'remote' })\n  validate_command_completion(':Git pull origin ')\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n  validate_command_completion(':Git pull origin v')\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n  validate_command_completion(':Git pull origin main ')\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\n\n  validate_command_completion(':Git checkout ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags', '--remotes' })\n\n  validate_command_completion(':Git config ') -- CLI\n  validate_latest_spawn_args({ '--no-pager', 'help', '--config-for-completion' })\n\n  child.set_size(30, 30)\n  validate_command_completion(':Git help ') -- Supported commands plus a bit\n\n  -- Should also work with aliases\n  child.set_size(10, 30)\n  validate_command_completion(':Git l ') -- CLI, same as log\n  validate_latest_spawn_args({ '--no-pager', 'rev-parse', '--symbolic', '--branches', '--tags' })\nend\n\nT[':Git']['completion']['works with not supported command'] = function()\n  child.set_size(17, 40)\n  -- Should suggest commands\n  type_keys(':Git doesnotexist ', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should suggest nothing\n  type_keys('<C-w>', '-', '<Tab>')\n  child.expect_screenshot()\n\n  -- Should suggest paths\n  type_keys('- ', '<Tab>')\n  child.expect_screenshot()\nend\n\nT[':Git']['completion']['works with present command modifiers'] = function()\n  type_keys(':vert silent Git ', '<Tab>')\n  child.expect_screenshot()\nend\n\nT[':Git']['events are triggered'] = function()\n  child.lua([[\n    -- Command stdout\n    table.insert(_G.stdio_queue, { { 'out', 'abc1234 Hello\\ndef4321 World' } })\n    table.insert(_G.stdio_queue, { { 'out', '' }, { 'err', 'There was error' } })\n\n    _G.process_mock_data = { [#_G.stdio_queue] = { exit_code = 1 }}\n  ]])\n\n  child.lua([[\n    _G.au_log = {}\n    local track = function(data) table.insert(_G.au_log, data) end\n    local opts = { pattern = { 'MiniGitCommandDone', 'MiniGitCommandSplit' }, callback = track }\n    vim.api.nvim_create_autocmd('User', opts)\n  ]])\n\n  local init_win_id = get_win()\n  child.cmd(':vertical Git log')\n  child.cmd(':Git push origin main')\n\n  local au_log = child.lua_get('_G.au_log')\n  local events = vim.tbl_map(function(t) return t.match end, au_log)\n  eq(events, { 'MiniGitCommandDone', 'MiniGitCommandSplit', 'MiniGitCommandDone' })\n\n  local log_done = au_log[1].data\n  eq(type(log_done.cmd_input), 'table')\n  eq(log_done.cmd_input.fargs, { 'log' })\n  log_done.cmd_input = nil\n  eq(log_done, {\n    cwd = child.fn.getcwd(),\n    exit_code = 0,\n    git_command = { 'git', 'log' },\n    git_subcommand = 'log',\n    stderr = '',\n    stdout = 'abc1234 Hello\\ndef4321 World',\n  })\n\n  local log_split = au_log[2].data\n  eq(log_split.git_command, { 'git', 'log' })\n  eq(log_split.win_source, init_win_id)\n  eq(log_split.win_stdout, get_win())\n\n  local push_err = au_log[3].data\n  push_err.cmd_input = nil\n  eq(push_err, {\n    cwd = child.fn.getcwd(),\n    exit_code = 1,\n    git_command = { 'git', 'push', 'origin', 'main' },\n    git_subcommand = 'push',\n    stderr = 'There was error',\n    stdout = '',\n  })\nend\n\nT[':Git']['event `MiniGitCommandSplit` can be used to tweak window-local options'] = function()\n  child.lua([[table.insert(_G.stdio_queue, { { 'out', 'abc1234 Hello\\ndef4321 World' } })]])\n  child.lua([[\n    local modify_win_opts = function(data)\n      local win_source, win_stdout = data.data.win_source, data.data.win_stdout\n      vim.wo[win_source].scrollbind = true\n      vim.wo[win_stdout].scrollbind = true\n      vim.wo[win_stdout].foldlevel = 0\n    end\n    local opts = { pattern = 'MiniGitCommandSplit', callback = modify_win_opts }\n    vim.api.nvim_create_autocmd('User', opts)\n  ]])\n\n  local init_win_id = get_win()\n  child.cmd(':Git log')\n  eq(child.api.nvim_win_get_option(init_win_id, 'scrollbind'), true)\n  eq(child.wo.scrollbind, true)\n  eq(child.wo.foldlevel, 0)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_hipatterns.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('hipatterns', config) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\n--stylua: ignore end\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\n-- Module helpers\nlocal get_hi_namespaces = function()\n  local res = {}\n  for name, ns_id in pairs(child.api.nvim_get_namespaces()) do\n    local hi_name = name:match('^MiniHipatterns%-(.*)$')\n    if hi_name ~= nil then res[hi_name] = ns_id end\n  end\n  return res\nend\n\nlocal get_hipatterns_extmarks = function(buf_id, hi_names)\n  local hi_namespaces = get_hi_namespaces()\n  hi_names = hi_names or vim.tbl_keys(hi_namespaces)\n\n  local full_extmarks = {}\n  for _, hi_name in ipairs(hi_names) do\n    vim.list_extend(\n      full_extmarks,\n      child.api.nvim_buf_get_extmarks(buf_id, hi_namespaces[hi_name], 0, -1, { details = true })\n    )\n  end\n\n  return vim.tbl_map(\n    function(ext)\n      return { line = ext[2] + 1, from_col = ext[3] + 1, to_col = ext[4].end_col, hl_group = ext[4].hl_group }\n    end,\n    full_extmarks\n  )\nend\n\nlocal validate_hl_group = function(name, pattern) expect.match(child.cmd_capture('hi ' .. name), pattern) end\n\n-- Data =======================================================================\nlocal test_lines = { 'abcd abcd', 'Abcd ABCD', 'abcdaabcd' }\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\n\n-- Test config\nlocal test_config = {\n  highlighters = { abcd = { pattern = 'abcd', group = 'Error' } },\n  delay = { text_change = 5 * small_time, scroll = 2 * small_time },\n}\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      child.set_size(10, 15)\n\n      child.lua('_G.test_config = ' .. vim.inspect(test_config))\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniHipatterns)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniHipatterns'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  child.cmd('hi DiagnosticError guifg=#ff0000 ctermfg=9')\n  child.cmd('hi DiagnosticWarn  guifg=#ffff00 ctermfg=11')\n  child.cmd('hi DiagnosticInfo  guifg=#0000ff ctermfg=14')\n  child.cmd('hi DiagnosticHint  guifg=#00ffff ctermfg=12')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniHipatternsFixme', 'cterm=bold,reverse ctermfg=9 gui=bold,reverse guifg=#ff0000')\n  has_highlight('MiniHipatternsHack', 'cterm=bold,reverse ctermfg=11 gui=bold,reverse guifg=#ffff00')\n  has_highlight('MiniHipatternsTodo', 'cterm=bold,reverse ctermfg=14 gui=bold,reverse guifg=#0000ff')\n  has_highlight('MiniHipatternsNote', 'cterm=bold,reverse ctermfg=12 gui=bold,reverse guifg=#00ffff')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n\n  eq(child.lua_get('type(_G.MiniHipatterns.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniHipatterns.config.' .. field), value) end\n\n  expect_config('highlighters', {})\n  expect_config('delay.text_change', 200)\n  expect_config('delay.scroll', 50)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  load_module({ delay = { text_change = 20 } })\n  eq(child.lua_get('MiniHipatterns.config.delay.text_change'), 20)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ highlighters = 'a' }, 'highlighters', 'table')\n  expect_config_error({ delay = 'a' }, 'delay', 'table')\n  expect_config_error({ delay = { text_change = 'a' } }, 'delay.text_change', 'number')\n  expect_config_error({ delay = { scroll = 'a' } }, 'delay.scroll', 'number')\nend\n\nT['setup()']['ensures colors'] = function()\n  load_module()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniHipatternsFixme'), 'gui=bold,reverse')\nend\n\nT['setup()']['auto enables in all visible buffers'] = function()\n  child.set_size(10, 30)\n  child.o.winwidth = 1\n\n  local buf_id_1 = child.api.nvim_get_current_buf()\n  set_lines(test_lines)\n  child.cmd('wincmd v')\n\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { '22abcd22' })\n\n  local buf_id_3 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_id_3)\n  set_lines({ '33abcd33' })\n\n  -- Should enable in all proper buffers currently shown in some window\n  load_module(test_config)\n  sleep(small_time)\n  child.expect_screenshot()\n  eq(child.lua_get('MiniHipatterns.get_enabled_buffers()'), { buf_id_1, buf_id_3 })\n\n  child.api.nvim_set_current_buf(buf_id_2)\n  sleep(small_time)\n  child.expect_screenshot()\n  eq(child.lua_get('MiniHipatterns.get_enabled_buffers()'), { buf_id_1, buf_id_2, buf_id_3 })\nend\n\nT['Auto enable'] = new_set()\n\nT['Auto enable']['works'] = function()\n  load_module(test_config)\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, false, { '22abcd22' })\n  child.api.nvim_set_current_buf(buf_id)\n  sleep(small_time)\n  child.expect_screenshot()\n  eq(child.lua_get('MiniHipatterns.get_enabled_buffers()'), { init_buf_id, buf_id })\nend\n\nT['Auto enable']['does not enable in not proper buffers'] = function()\n  load_module(test_config)\n\n  -- Should not load for not normal buffers\n  local scratch_buf_id = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(scratch_buf_id)\n  set_lines(test_lines)\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  -- Should not load for not loaded buffers\n  local unloaded_buf_id = child.lua([[\n    local unloaded_buf_id = vim.api.nvim_create_buf(true, false)\n    vim.api.nvim_set_current_buf(unloaded_buf_id)\n    vim.api.nvim_buf_delete(unloaded_buf_id, { unload = true })\n    return unloaded_buf_id\n  ]])\n  local enabled_buffers = child.lua_get('MiniHipatterns.get_enabled_buffers()')\n  eq(vim.tbl_contains(enabled_buffers, unloaded_buf_id), false)\n\n  -- Should not error if buffer is not valid\n  expect.no_error(function()\n    child.lua([[\n      local buf_id = vim.api.nvim_create_buf(true, false)\n      vim.api.nvim_set_current_buf(buf_id)\n      vim.api.nvim_buf_delete(buf_id, { force = true })\n    ]])\n    eq(child.cmd_capture('1messages'), '')\n  end)\nend\n\nT['Auto enable']['makes `:edit` work'] = function()\n  load_module(test_config)\n\n  local test_file = 'tests/hipatterns_file'\n  MiniTest.finally(function() vim.fn.delete(test_file) end)\n\n  child.cmd('edit ' .. test_file)\n  set_lines(test_lines)\n  child.cmd('write')\n\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  child.cmd('edit')\n  child.expect_screenshot()\nend\n\nT['Autocommands'] = new_set()\n\nT['Autocommands']['resets on color scheme change'] = function()\n  child.set_size(10, 30)\n  child.o.winwidth = 1\n\n  child.lua([[_G.new_hl_group_highlighter = {\n    pattern = 'aaa',\n    group = function()\n      vim.cmd('hi AAA cterm=underline')\n      return 'AAA'\n    end,\n  }]])\n  child.lua([[require('mini.hipatterns').setup({\n    highlighters = { aaa = _G.new_hl_group_highlighter },\n    delay = _G.test_config.delay,\n  })]])\n\n  set_lines({ 'aaa' })\n  child.cmd('wincmd v | enew')\n  set_lines({ 'xxaaaxx' })\n\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  -- After `:hi clear` highlighting disappears as highlight group is cleared\n  child.cmd('hi clear')\n  child.expect_screenshot({ ignore_attr = { child.o.lines } })\n\n  -- `ColorScheme` event which should lead to highlight reevaluation of all\n  -- enabled buffers\n  child.cmd('doautocmd ColorScheme')\n  child.expect_screenshot({ ignore_attr = { child.o.lines } })\nend\n\nT['enable()'] = new_set()\n\nlocal enable = forward_lua([[require('mini.hipatterns').enable]])\nlocal get_enabled_buffers = forward_lua([[require('mini.hipatterns').get_enabled_buffers]])\n\nT['enable()']['works'] = function()\n  set_lines(test_lines)\n  enable(0, test_config)\n\n  -- Should register buffer as enabled\n  eq(get_enabled_buffers(), { child.api.nvim_get_current_buf() })\n\n  -- Should add highlights immediately\n  child.expect_screenshot()\n\n  -- Should disable on buffer detach\n  child.ensure_normal_mode()\n  child.cmd('bdelete!')\n  eq(get_enabled_buffers(), {})\nend\n\nT['enable()']['works with defaults'] = function()\n  child.b.minihipatterns_config = test_config\n  set_lines(test_lines)\n  enable()\n  child.expect_screenshot()\nend\n\nT['enable()']['works in not normal buffer'] = function()\n  local scratch_buf_id = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(scratch_buf_id)\n\n  set_lines({ 'xxabcdxx' })\n  enable(scratch_buf_id, test_config)\n  child.expect_screenshot()\nend\n\nT['enable()']['works in not current buffer'] = function()\n  local new_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(new_buf_id, 0, -1, false, { 'xxabcdxx' })\n\n  enable(new_buf_id, test_config)\n\n  child.api.nvim_set_current_buf(new_buf_id)\n  child.expect_screenshot()\nend\n\nT['enable()']['reacts to text change'] = function()\n  -- Should enable debounced auto highlight on text change\n  enable(0, test_config)\n\n  -- Interactive text change\n  type_keys('i', 'abc')\n  sleep(test_config.delay.text_change - small_time)\n  type_keys('d')\n\n  -- - No highlights should be shown as delay was smaller than in config\n  child.expect_screenshot()\n\n  -- - Still no highlights should be shown\n  sleep(test_config.delay.text_change - small_time)\n  child.expect_screenshot()\n\n  -- - Now there should be highlights\n  sleep(2 * small_time)\n  child.expect_screenshot()\n\n  -- Not interactive text change\n  set_lines({ 'ABCD', 'abcd' })\n\n  child.expect_screenshot()\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['enable()']['does not flicker during text insert'] = function()\n  enable(0, test_config)\n\n  -- Interactive text change\n  type_keys('i', 'abcd')\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  type_keys(' abcd')\n  child.expect_screenshot()\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['enable()']['reacts to buffer enter'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  enable(init_buf_id, { highlighters = test_config.highlighters })\n\n  local other_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(other_buf_id)\n\n  -- On buffer enter it should update config and highlighting (after delay)\n  local lua_cmd =\n    string.format('vim.b[%d].minihipatterns_config = { delay = { text_change = %d } }', init_buf_id, 2 * small_time)\n  child.lua(lua_cmd)\n  child.api.nvim_buf_set_lines(init_buf_id, 0, -1, false, { 'abcd' })\n\n  child.api.nvim_set_current_buf(init_buf_id)\n\n  child.expect_screenshot()\n  sleep(2 * small_time + small_time)\n  child.expect_screenshot()\nend\n\nT['enable()']['reacts to filetype change'] = function()\n  child.lua([[_G.hipatterns_config = {\n    highlighters = {\n      abcd_ft = {\n        pattern = function(buf_id)\n          if vim.bo[buf_id].filetype == 'aaa' then return nil end\n          return 'abcd'\n        end,\n        group = 'Error'\n      },\n    },\n    delay = _G.test_config.delay,\n  }]])\n\n  set_lines({ 'xxabcdxx' })\n  child.lua([[require('mini.hipatterns').enable(0, _G.hipatterns_config)]])\n  child.expect_screenshot()\n\n  -- Should update highlighting after delay\n  child.cmd('set filetype=aaa')\n  child.expect_screenshot()\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['enable()']['reacts to window scroll'] = function()\n  enable(0, test_config)\n\n  -- Change same line each before `delay.text_change`. This creates a situation\n  -- when only one line will be highlighted while others - don't (but should).\n  set_lines({ 'xxabcdxx' })\n  type_keys('yy')\n  for _ = 1, 15 do\n    type_keys('P')\n  end\n\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  -- Scroll should update highlighting inside view with `delay.scroll` debounce\n  type_keys('<C-e>')\n  sleep(0.5 * test_config.delay.scroll)\n  type_keys('<C-e>')\n  sleep(test_config.delay.scroll + small_time)\n  child.expect_screenshot()\n\n  -- Update should be done only on the final view\n  type_keys('<C-y>')\n  child.expect_screenshot()\n  type_keys('2<C-e>')\n  child.expect_screenshot()\nend\n\nT['enable()']['reacts to delete of line with match'] = function()\n  set_lines({ 'abcd', 'xxx', 'xxx', 'abcd', 'xxx', 'xxx', 'abcd' })\n\n  local hi_abcd = {\n    pattern = 'abcd',\n    group = '',\n    extmark_opts = { virt_text = { { 'Hello', 'Error' } }, virt_text_pos = 'right_align' },\n  }\n  local config = { highlighters = { abcd = hi_abcd }, delay = test_config.delay }\n  enable(0, config)\n\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  local validate = function(line_to_delete)\n    child.api.nvim_win_set_cursor(0, { line_to_delete, 0 })\n    type_keys('dd')\n    sleep(test_config.delay.text_change + small_time)\n    child.expect_screenshot()\n  end\n\n  validate(1)\n  validate(3)\n  validate(5)\nend\n\nT['Highlighters'] = new_set()\n\nT['Highlighters']['silently skips wrong entries'] = function()\n  local highlighters = {\n    correct = { pattern = 'abcd', group = 'Error' },\n    pattern_absent = { group = 'Error' },\n    pattern_wrong_type = { pattern = 1, group = 'Error' },\n    group_absent = { pattern = 'aaa' },\n    group_wrong_type = { pattern = 'aaa', group = 1 },\n    priority_wrong_type = { pattern = 'aaa', group = 'Error', extmark_opts = 'a' },\n  }\n  enable(0, { highlighters = highlighters, delay = test_config.delay })\n\n  set_lines({ 'xxabcd', 'aaa' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlighters']['allows submatch in `pattern`'] = function()\n  set_lines({ 'abcd', 'xabcd', 'xxabcd', 'xxabcdxx' })\n\n  local validate = function(pattern)\n    child.lua('require(\"mini.hipatterns\").disable()')\n    local config = {\n      highlighters = { abcd = { pattern = pattern, group = 'Error' } },\n      delay = test_config.delay,\n    }\n    enable(0, config)\n\n    sleep(test_config.delay.text_change + small_time)\n    child.expect_screenshot()\n  end\n\n  validate('xx()ab()cd')\n  validate('()ab()cd')\n  validate('ab()cd()')\n\n  -- One capture `()` should also work treating it as start and inferring end\n  -- as full match's end\n  validate('()abcd')\n\n  -- Third an more captures should be ignored\n  validate('xx()ab()c()d()')\nend\n\nT['Highlighters']['works with overlapping matches'] = function()\n  local validate = function(pattern, ref_ranges)\n    child.lua('require(\"mini.hipatterns\").disable()')\n    local config = {\n      highlighters = { x = { pattern = pattern, group = 'Error' } },\n      delay = test_config.delay,\n    }\n    enable(0, config)\n\n    sleep(test_config.delay.text_change + small_time)\n    local ranges = vim.tbl_map(function(e) return { e.from_col, e.to_col } end, get_hipatterns_extmarks(0, { 'x' }))\n    eq(ranges, ref_ranges)\n  end\n\n  set_lines({ string.rep('x', 7) })\n\n  -- Should behave similarly to how `/` with `\\zs` and `\\ze` works\n  validate('xxx', { { 1, 3 }, { 4, 6 } })\n  validate('()xx()x', { { 1, 2 }, { 3, 4 }, { 5, 6 } })\n  validate('x()xx()', { { 2, 3 }, { 5, 6 } })\n  validate('x()x()x', { { 2, 2 }, { 4, 4 }, { 6, 6 } })\nend\n\nT['Highlighters']['allows frontier pattern in `pattern`'] = function()\n  local config = {\n    highlighters = { abcd = { pattern = '%f[%w]abcd%f[%W]', group = 'Error' } },\n    delay = test_config.delay,\n  }\n  enable(0, config)\n\n  set_lines({ 'abcd', 'xabcd', 'abcdx', 'xabcdx', ' abcd ' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlighters']['allows callable `pattern`'] = function()\n  child.lua([[_G.hi_callable_pattern = {\n    pattern = function(...)\n      _G.args = { ... }\n      return 'abcd'\n    end,\n    group = 'Error'\n  }]])\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { test = _G.hi_callable_pattern }, delay = _G.test_config.delay }\n  )]])\n\n  set_lines({ 'xxabcd' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n  -- Should be called with correct signature\n  eq(child.lua_get('_G.args'), { child.api.nvim_get_current_buf() })\nend\n\nT['Highlighters']['allows return `nil` `pattern` to not highlight'] = function()\n  child.lua([[_G.hi_conditional_pattern = {\n    pattern = function(buf_id)\n      if vim.b[buf_id].not_highlight then return nil end\n      return 'abcd'\n    end,\n    group = 'Error'\n  }]])\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { test = _G.hi_conditional_pattern }, delay = _G.test_config.delay }\n  )]])\n\n  set_lines({ 'xxabcd' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  child.b.not_highlight = true\n  set_lines({ 'xxabcd' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlighters']['allows array `pattern`'] = function()\n  -- Should allow both string and callable elements\n  child.lua([[_G.hi_array = {\n    pattern = {\n      'abcd',\n      function(buf_id)\n        if vim.b[buf_id].not_highlight then return nil end\n        return 'efgh'\n      end\n    } ,\n    group = 'Error'\n  }]])\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { array = _G.hi_array }, delay = _G.test_config.delay }\n  )]])\n\n  set_lines({ 'xxabcd', 'xxefgh' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n\n  child.b.not_highlight = true\n  set_lines({ 'xxabcd', 'xxefgh' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlighters']['allows callable `group`'] = function()\n  child.lua([[_G.hi_callable_group = {\n    pattern = 'abcd',\n    group = function(...)\n      _G.args = vim.deepcopy({ ... })\n      return 'Error'\n    end,\n  }]])\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { test = _G.hi_callable_group }, delay = _G.test_config.delay }\n  )]])\n\n  set_lines({ 'xxabcd' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\n  -- Should be called with correct signature\n  eq(child.lua_get('_G.args'), { 1, 'abcd', { full_match = 'abcd', line = 1, from_col = 3, to_col = 6 } })\n\n  -- Check arguments with submatch\n  local validate_submatch = function(pattern, ref_args)\n    child.lua('_G.args = nil')\n    child.lua('_G.hi_callable_group.pattern = ' .. vim.inspect(pattern))\n    set_lines({ 'abcd' })\n    sleep(test_config.delay.text_change + small_time)\n    eq(child.lua_get('_G.args'), ref_args)\n  end\n\n  validate_submatch('()ab()cd', { 1, 'ab', { full_match = 'abcd', line = 1, from_col = 1, to_col = 2 } })\n  validate_submatch('a()bc()d', { 1, 'bc', { full_match = 'abcd', line = 1, from_col = 2, to_col = 3 } })\n  validate_submatch('ab()cd()', { 1, 'cd', { full_match = 'abcd', line = 1, from_col = 3, to_col = 4 } })\n\n  validate_submatch('a()bcd', { 1, 'bcd', { full_match = 'abcd', line = 1, from_col = 2, to_col = 4 } })\nend\n\nT['Highlighters']['allows return `nil` `group` to not highlight'] = function()\n  child.lua([[_G.hi_conditional_group = {\n    pattern = 'abcd',\n    group = function(buf_id, match, data)\n      -- Don't highlight on even lines\n      if data.line % 2 == 0 then return nil end\n      return 'Error'\n    end,\n  }]])\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { test = _G.hi_conditional_group }, delay = _G.test_config.delay }\n  )]])\n\n  set_lines({ 'xxabcd', 'xxabcd', 'xxabcd', 'xxabcd', 'xxabcd' })\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlighters']['respects `extmark_opts.priority`'] = function()\n  local config = { highlighters = { abcd = { pattern = 'abcd', group = 'Error' } } }\n  set_lines({ 'abcd', 'abcd', 'abcd' })\n  enable(0, config)\n  child.expect_screenshot()\n\n  local ns_id = child.api.nvim_create_namespace('test')\n  local set_extmark = function(line, priority)\n    child.api.nvim_buf_set_extmark(0, ns_id, line - 1, 0, { end_col = 4, hl_group = 'Visual', priority = priority })\n  end\n\n  -- Default priority should be 200\n  set_extmark(1, 199)\n  set_extmark(3, 201)\n  child.expect_screenshot()\n\n  -- Should respect extmark_opts.priority in `highlighters` entry\n  child.lua([[require('mini.hipatterns').disable(0)]])\n  config.highlighters.abcd.extmark_opts = { priority = 202 }\n  enable(0, config)\n  child.expect_screenshot()\nend\n\nT['Highlighters']['respects `extmark_opts`'] = function()\n  child.lua([[_G.hi_abcd = { pattern = 'abcd', group = 'Error', extmark_opts = { priority = 100 } }]])\n  child.lua([[_G.hi_efgh = {\n    pattern = 'efgh',\n    group = function() return 'Comment' end,\n    extmark_opts = function(buf_id, match, data)\n      _G.extmark_args = { buf_id = buf_id, match = match, data = vim.deepcopy(data) }\n      return { hl_group = data.hl_group, end_row = data.line - 1, end_col = data.to_col - 2 }\n    end,\n  }]])\n\n  set_lines({ 'abcd', 'efgh' })\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { abcd = _G.hi_abcd, efgh = _G.hi_efgh } }\n  )]])\n\n  child.expect_screenshot()\n\n  -- Check actual extmark details\n  local validate_full_extmark = function(extmark, row, col, details)\n    eq({ row = extmark[2], col = extmark[3] }, { row = row, col = col })\n    local real_details = {}\n    for key, _ in pairs(details) do\n      real_details[key] = extmark[4][key]\n    end\n    eq(real_details, details)\n  end\n\n  local hi_namespaces = get_hi_namespaces()\n\n  -- As table (should set options needed for highlighting region)\n  local abcd_extmarks = child.api.nvim_buf_get_extmarks(0, hi_namespaces['abcd'], 0, -1, { details = true })\n  eq(#abcd_extmarks, 1)\n  validate_full_extmark(abcd_extmarks[1], 0, 0, { priority = 100, hl_group = 'Error', end_row = 0, end_col = 4 })\n\n  -- As callable\n  local efgh_extmarks = child.api.nvim_buf_get_extmarks(0, hi_namespaces['efgh'], 0, -1, { details = true })\n  eq(#efgh_extmarks, 1)\n  validate_full_extmark(efgh_extmarks[1], 1, 0, { hl_group = 'Comment', end_row = 1, end_col = 2 })\n\n  -- - Should be called with correct arguments\n  eq(child.lua_get('_G.extmark_args'), {\n    buf_id = child.api.nvim_get_current_buf(),\n    match = 'efgh',\n    data = { from_col = 1, full_match = 'efgh', hl_group = 'Comment', line = 2, to_col = 4 },\n  })\nend\n\nT['enable()']['validates arguments'] = function()\n  expect.error(function() enable('a', {}) end, '`buf_id`.*valid buffer id')\n  expect.error(function() enable(child.api.nvim_get_current_buf(), 'a') end, '`config`.*table')\nend\n\nT['enable()']['respects `vim.{g,b}.minihipatterns_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minihipatterns_disable = true\n\n    set_lines(test_lines)\n    enable(0, test_config)\n    sleep(test_config.delay.text_change + small_time)\n    child.expect_screenshot()\n  end,\n})\n\nT['enable()']['respects global config after `setup()`'] = function()\n  set_lines(test_lines)\n  load_module(test_config)\n  enable(0)\n\n  child.expect_screenshot()\nend\n\nT['enable()']['respects `vim.b.minihipatterns_config`'] = function()\n  set_lines(test_lines)\n  child.b.minihipatterns_config = test_config\n  enable(0)\n\n  child.expect_screenshot()\n\n  -- Delay should also be respected\n  set_lines({ 'abcd' })\n  sleep(test_config.delay.text_change - small_time)\n  child.expect_screenshot()\n  sleep(2 * small_time)\n  child.expect_screenshot()\nend\n\nT['disable()'] = new_set()\n\nlocal disable = forward_lua([[require('mini.hipatterns').disable]])\n\nT['disable()']['works'] = function()\n  local cur_buf_id = child.api.nvim_get_current_buf()\n  set_lines(test_lines)\n  enable(0, test_config)\n  child.expect_screenshot()\n\n  -- By default should disable current buffer\n  disable()\n  child.expect_screenshot()\n  eq(get_enabled_buffers(), {})\n\n  -- Allows 0 as alias for current buffer\n  enable(0, test_config)\n  eq(get_enabled_buffers(), { cur_buf_id })\n  disable(0)\n  eq(get_enabled_buffers(), {})\nend\n\nT['disable()']['works in not current buffer'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n  set_lines(test_lines)\n  enable(0, test_config)\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n  disable(init_buf_id)\n  child.api.nvim_set_current_buf(init_buf_id)\n  sleep(test_config.delay.text_change + small_time)\n  child.expect_screenshot()\nend\n\nT['disable()']['works on not enabled buffer'] = function()\n  expect.no_error(function() disable(0) end)\nend\n\nT['disable()']['validates arguments'] = function()\n  expect.error(function() disable('a') end, '`buf_id`.*valid buffer id')\nend\n\nT['toggle()'] = new_set()\n\nlocal toggle = forward_lua([[require('mini.hipatterns').toggle]])\n\nT['toggle()']['works'] = function()\n  local cur_buf_id = child.api.nvim_get_current_buf()\n  set_lines(test_lines)\n\n  -- By default should disable current buffer\n  child.lua('_G.test_config = ' .. vim.inspect(test_config))\n  child.lua([[require('mini.hipatterns').toggle(nil, test_config)]])\n  child.expect_screenshot()\n  eq(get_enabled_buffers(), { cur_buf_id })\n\n  toggle()\n  child.expect_screenshot()\n  eq(get_enabled_buffers(), {})\n\n  -- Allows 0 as alias for current buffer\n  toggle(0, test_config)\n  eq(get_enabled_buffers(), { cur_buf_id })\n\n  toggle(0)\n  eq(get_enabled_buffers(), {})\nend\n\nT['toggle()']['validates arguments'] = function()\n  expect.error(function() toggle('a', {}) end, '`buf_id`.*valid buffer id')\n  expect.error(function() toggle(child.api.nvim_get_current_buf(), 'a') end, '`config`.*table')\nend\n\nT['update()'] = new_set()\n\nlocal update = forward_lua([[require('mini.hipatterns').update]])\n\nT['update()']['works'] = function()\n  child.lua([[_G.hi_conditional_pattern = {\n    pattern = function(buf_id)\n      if vim.b[buf_id].not_highlight then return nil end\n      return 'abcd'\n    end,\n    group = 'Error'\n  }]])\n  child.lua([[require('mini.hipatterns').enable(\n    0,\n    { highlighters = { test = _G.hi_conditional_pattern }, delay = { text_change = 20 } }\n  )]])\n\n  local lines = { 'xxabcd', 'xxabcd', 'xxabcd', 'xxabcd' }\n  set_lines(lines)\n  sleep(test_config.delay.text_change + small_time)\n\n  child.expect_screenshot()\n\n  -- Should update immediately to not highlight only lines 2 and 3\n  child.b.not_highlight = true\n  update(0, 2, 3)\n  child.expect_screenshot()\n\n  -- Should work for single lines\n  child.b.not_highlight = true\n  update(0, 1, 1)\n  child.expect_screenshot()\n\n  -- `from_line` should be inferred as 1\n  child.b.not_highlight = false\n  child.lua([[require('mini.hipatterns').update(0, nil, 3)]])\n  child.expect_screenshot()\n\n  -- `to_line` should be inferred as last line\n  child.b.not_highlight = true\n  child.lua([[require('mini.hipatterns').update(0, 2, nil)]])\n  child.expect_screenshot()\n\n  -- Works on not current buffer\n  local init_buf_id = child.api.nvim_get_current_buf()\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n\n  child.api.nvim_buf_set_var(init_buf_id, 'not_highlight', false)\n  update(init_buf_id, 2, 3)\n  child.api.nvim_set_current_buf(init_buf_id)\n  child.expect_screenshot()\nend\n\nT['update()']['does not work in not enabled buffer'] = function()\n  local cur_buf_id = child.api.nvim_get_current_buf()\n  set_lines(test_lines)\n\n  expect.error(function() update(cur_buf_id, 1, 2) end, 'Buffer ' .. cur_buf_id .. ' is not enabled')\nend\n\nT['update()']['validates arguments'] = function()\n  enable(0)\n\n  expect.error(function() update('a', 1, 2) end, '`buf_id`.*valid buffer id')\n  expect.error(function() update(0, 'a', 2) end, '`from_line`.*number')\n  expect.error(function() update(0, 1, 'a') end, '`to_line`.*number')\nend\n\nT['get_enabled_buffers()'] = new_set()\n\nT['get_enabled_buffers()']['works'] = function()\n  local create_buf = function() return child.api.nvim_create_buf(true, false) end\n  local buf_id_1 = create_buf()\n  create_buf()\n  local buf_id_3 = create_buf()\n  local buf_id_4 = create_buf()\n\n  enable(buf_id_3)\n  enable(buf_id_1)\n  enable(buf_id_4)\n  eq(get_enabled_buffers(), { buf_id_1, buf_id_3, buf_id_4 })\n\n  disable(buf_id_3)\n  eq(get_enabled_buffers(), { buf_id_1, buf_id_4 })\n\n  -- Does not return invalid buffers\n  child.api.nvim_buf_delete(buf_id_4, {})\n  eq(get_enabled_buffers(), { buf_id_1 })\nend\n\nT['get_matches()'] = new_set()\n\nlocal get_matches = forward_lua([[require('mini.hipatterns').get_matches]])\n\nT['get_matches()']['works'] = function()\n  local buf_id_1 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id_1, 0, -1, false, { 'aaa bbb', '  aaa', '  bbb' })\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n\n  child.lua([[require('mini.hipatterns').setup({\n    highlighters = {\n      -- Common highlighter\n      aaa = { pattern = 'aaa', group = 'Comment' },\n      -- Highlighter with non-string name and callable `extmark_opts` without\n      -- `end_row`/`end_col`\n      [10] = {\n        pattern = 'bbb',\n        group = '',\n        extmark_opts = function(_, _, data)\n          return { virt_text = { { 'xxx', 'Error' } }, virt_text_pos = 'overlay' }\n        end,\n      },\n    },\n    delay = _G.test_config.delay,\n  })]])\n\n  enable(buf_id_1)\n  sleep(test_config.delay.text_change + small_time)\n  local matches = get_matches(buf_id_1)\n\n  -- Order should be guaranteed (as tostring(10) is less than 'aaa')\n  eq(matches, {\n    { bufnr = 2, highlighter = 10, lnum = 1, col = 5 },\n    { bufnr = 2, highlighter = 10, lnum = 3, col = 3 },\n    { bufnr = 2, highlighter = 'aaa', lnum = 1, col = 1, end_lnum = 1, end_col = 4, hl_group = 'Comment' },\n    { bufnr = 2, highlighter = 'aaa', lnum = 2, col = 3, end_lnum = 2, end_col = 6, hl_group = 'Comment' },\n  })\n\n  -- Should return empty table if disabled\n  disable(buf_id_1)\n  eq(get_matches(buf_id_1), {})\n\n  -- Should return empty table if no matches\n  enable(buf_id_2)\n  sleep(test_config.delay.text_change + small_time)\n  eq(get_matches(buf_id_2), {})\nend\n\nT['get_matches()']['respects `buf_id` argument'] = function()\n  local buf_id = child.api.nvim_get_current_buf()\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, false, { 'bbb aaa' })\n  child.lua([[require('mini.hipatterns').setup({\n    highlighters = {  aaa = { pattern = 'aaa', group = 'Error' }  },\n    delay = _G.test_config.delay,\n  })]])\n  enable(buf_id)\n  sleep(test_config.delay.text_change + small_time)\n\n  -- Should allow both `nil` and `0` to mean current buffer\n  local ref_output =\n    { { bufnr = buf_id, highlighter = 'aaa', hl_group = 'Error', lnum = 1, col = 5, end_lnum = 1, end_col = 8 } }\n  eq(get_matches(), ref_output)\n  eq(get_matches(0), ref_output)\nend\n\nT['get_matches()']['respects `highlighters` argument'] = function()\n  local buf_id = child.api.nvim_get_current_buf()\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, false, { 'bbb AAA aaa' })\n  child.lua([[require('mini.hipatterns').setup({\n    highlighters = {\n      -- Should respect `pattern` array\n      aaa = { pattern = { 'aaa', 'AAA' }, group = 'Error' },\n      bbb = { pattern = 'bbb', group = 'Comment' },\n    },\n    delay = _G.test_config.delay,\n  })]])\n  enable(buf_id)\n  sleep(test_config.delay.text_change + small_time)\n\n  -- Should respect order of `highlighters` in output and discard any not\n  -- present highlighter identifiers\n  eq(get_matches(buf_id, { 'bbb', 'xxx', 'aaa' }), {\n    { bufnr = buf_id, highlighter = 'bbb', hl_group = 'Comment', lnum = 1, col = 1, end_lnum = 1, end_col = 4 },\n    { bufnr = buf_id, highlighter = 'aaa', hl_group = 'Error', lnum = 1, col = 5, end_lnum = 1, end_col = 8 },\n    { bufnr = buf_id, highlighter = 'aaa', hl_group = 'Error', lnum = 1, col = 9, end_lnum = 1, end_col = 12 },\n  })\nend\n\nT['get_matches()']['validates arguments'] = function()\n  expect.error(function() get_matches('a') end, '`buf_id`.*not valid')\n  expect.error(function() get_matches(child.api.nvim_get_current_buf(), 1) end, '`highlighters`.*array')\nend\n\nT['gen_highlighter'] = new_set()\n\nT['gen_highlighter']['hex_color()'] = new_set()\n\nlocal enable_hex_color = function(...)\n  child.lua(\n    [[_G.hipatterns = require('mini.hipatterns')\n      _G.hipatterns.setup({\n        highlighters = { hex_color = _G.hipatterns.gen_highlighter.hex_color(...) },\n      })]],\n    { ... }\n  )\n  sleep(small_time)\nend\n\nT['gen_highlighter']['hex_color()']['works'] = function()\n  set_lines({\n    -- Should be highlighted\n    '#000000 #ffffff',\n    '#FffFFf',\n\n    -- Should not be highlighted\n    '#00000 #0000000',\n    '#00000g',\n  })\n\n  enable_hex_color()\n\n  child.expect_screenshot()\n\n  -- Should use correct highlight groups\n  --stylua: ignore\n  eq(get_hipatterns_extmarks(0), {\n    { line = 1, from_col = 1, to_col = 7,  hl_group = 'MiniHipatterns_000000_bg' },\n    { line = 1, from_col = 9, to_col = 15, hl_group = 'MiniHipatterns_ffffff_bg' },\n    { line = 2, from_col = 1, to_col = 7,  hl_group = 'MiniHipatterns_ffffff_bg' },\n  })\n  expect.match(child.cmd_capture('hi MiniHipatterns_000000_bg'), 'guifg=#ffffff guibg=#000000')\n  expect.match(child.cmd_capture('hi MiniHipatterns_ffffff_bg'), 'guifg=#000000 guibg=#ffffff')\nend\n\nT['gen_highlighter']['hex_color()'][\"works with style '#'\"] = function()\n  set_lines({ '#000000 #ffffff' })\n\n  enable_hex_color({ style = '#' })\n\n  child.expect_screenshot()\n\n  -- Should use correct highlight groups\n  eq(get_hipatterns_extmarks(0), {\n    { line = 1, from_col = 1, to_col = 1, hl_group = 'MiniHipatterns_000000_bg' },\n    { line = 1, from_col = 9, to_col = 9, hl_group = 'MiniHipatterns_ffffff_bg' },\n  })\n  expect.match(child.cmd_capture('hi MiniHipatterns_000000_bg'), 'guifg=#ffffff guibg=#000000')\n  expect.match(child.cmd_capture('hi MiniHipatterns_ffffff_bg'), 'guifg=#000000 guibg=#ffffff')\nend\n\nT['gen_highlighter']['hex_color()'][\"works with style 'line'\"] = function()\n  set_lines({ '#000000 #ffffff' })\n\n  enable_hex_color({ style = 'line' })\n\n  child.expect_screenshot()\n\n  -- Should use correct highlight groups\n  --stylua: ignore\n  eq(get_hipatterns_extmarks(0), {\n    { line = 1, from_col = 1, to_col = 7,  hl_group = 'MiniHipatterns_000000_line' },\n    { line = 1, from_col = 9, to_col = 15, hl_group = 'MiniHipatterns_ffffff_line' },\n  })\n  expect.match(child.cmd_capture('hi MiniHipatterns_000000_line'), 'gui=underline guisp=#000000')\n  expect.match(child.cmd_capture('hi MiniHipatterns_ffffff_line'), 'gui=underline guisp=#ffffff')\nend\n\nT['gen_highlighter']['hex_color()'][\"works with style 'inline'\"] = function()\n  if child.fn.has('nvim-0.10') == 0 then\n    expect.error(function() enable_hex_color({ style = 'inline' }) end, '\"inline\".*hex_color.*0%.10')\n    return\n  end\n\n  child.set_size(5, 25)\n  set_lines({ '#000000 #ffffff' })\n\n  enable_hex_color({ style = 'inline' })\n  child.expect_screenshot()\n\n  -- Should use correct highlight groups\n  expect.match(child.cmd_capture('hi MiniHipatterns_000000_fg'), 'guifg=#000000')\n  expect.match(child.cmd_capture('hi MiniHipatterns_ffffff_fg'), 'guifg=#ffffff')\nend\n\nT['gen_highlighter']['hex_color()']['correctly computes highlight group'] = function()\n  set_lines({ '#767676 #777777', '#098777 #178d7c' })\n\n  enable_hex_color()\n  sleep(2 * small_time)\n\n  --stylua: ignore\n  eq(get_hipatterns_extmarks(0), {\n    { line = 1, from_col = 1, to_col = 7,  hl_group = 'MiniHipatterns_767676_bg' },\n    { line = 1, from_col = 9, to_col = 15, hl_group = 'MiniHipatterns_777777_bg' },\n    { line = 2, from_col = 1, to_col = 7,  hl_group = 'MiniHipatterns_098777_bg' },\n    { line = 2, from_col = 9, to_col = 15, hl_group = 'MiniHipatterns_178d7c_bg' },\n  })\n\n  validate_hl_group('MiniHipatterns_767676_bg', 'guifg=#ffffff guibg=#767676')\n  validate_hl_group('MiniHipatterns_777777_bg', 'guifg=#000000 guibg=#777777')\n  validate_hl_group('MiniHipatterns_098777_bg', 'guifg=#ffffff guibg=#098777')\n  validate_hl_group('MiniHipatterns_178d7c_bg', 'guifg=#000000 guibg=#178d7c')\nend\n\nT['gen_highlighter']['hex_color()']['is present after color scheme change'] = function()\n  set_lines({ '#000000 #ffffff' })\n  enable_hex_color()\n  sleep(2 * small_time)\n\n  child.cmd('hi clear')\n  child.cmd('colorscheme blue')\n\n  sleep(2 * small_time)\n  --stylua: ignore\n  eq(get_hipatterns_extmarks(0), {\n    { line = 1, from_col = 1, to_col = 7,  hl_group = 'MiniHipatterns_000000_bg' },\n    { line = 1, from_col = 9, to_col = 15, hl_group = 'MiniHipatterns_ffffff_bg' },\n  })\n  expect.match(child.cmd_capture('hi MiniHipatterns_000000_bg'), 'guifg=#ffffff guibg=#000000')\n  expect.match(child.cmd_capture('hi MiniHipatterns_ffffff_bg'), 'guifg=#000000 guibg=#ffffff')\nend\n\nT['gen_highlighter']['hex_color()']['respects `opts.priority`'] = function()\n  set_lines({ '#000000', '#000000', '#000000' })\n  enable_hex_color()\n  sleep(2 * small_time)\n\n  child.expect_screenshot()\n\n  local ns_id = child.api.nvim_create_namespace('test')\n  child.cmd('hi Temp guifg=#aaaaaa')\n  local set_extmark = function(line, priority)\n    child.api.nvim_buf_set_extmark(0, ns_id, line - 1, 0, { end_col = 7, hl_group = 'Temp', priority = priority })\n  end\n\n  -- Default priority should be 200\n  set_extmark(1, 199)\n  set_extmark(3, 201)\n  child.expect_screenshot()\n\n  -- Should respect priority in `highlighters` entry\n  disable(0)\n  enable_hex_color({ priority = 202 })\n  child.expect_screenshot()\nend\n\nT['gen_highlighter']['hex_color()']['respects `opts.filter`'] = function()\n  set_lines({ '#000000 #ffffff' })\n\n  child.lua([[\n    _G.hipatterns = require('mini.hipatterns')\n    _G.filter = function(buf_id) return vim.b[buf_id].do_highlight end\n    _G.hipatterns.enable(0, {\n      highlighters = {\n        hex_color = _G.hipatterns.gen_highlighter.hex_color({ filter = _G.filter }),\n      },\n    })\n  ]])\n\n  -- Should not highlight\n  child.b.do_highlight = false\n  update(0)\n  child.expect_screenshot()\n\n  -- Should highlight\n  child.b.do_highlight = true\n  update(0)\n  child.expect_screenshot()\nend\n\nT['compute_hex_color_group()'] = new_set()\n\nlocal compute_hex_color_group = forward_lua([[require('mini.hipatterns').compute_hex_color_group]])\n\nT['compute_hex_color_group()']['works'] = function()\n  eq(compute_hex_color_group('#000000', 'bg'), 'MiniHipatterns_000000_bg')\n  eq(compute_hex_color_group('#ffffff', 'bg'), 'MiniHipatterns_ffffff_bg')\n  eq(compute_hex_color_group('#767676', 'bg'), 'MiniHipatterns_767676_bg')\n  eq(compute_hex_color_group('#777777', 'bg'), 'MiniHipatterns_777777_bg')\n  eq(compute_hex_color_group('#098777', 'bg'), 'MiniHipatterns_098777_bg')\n  eq(compute_hex_color_group('#178d7c', 'bg'), 'MiniHipatterns_178d7c_bg')\n\n  validate_hl_group('MiniHipatterns_000000_bg', 'guifg=#ffffff guibg=#000000')\n  validate_hl_group('MiniHipatterns_ffffff_bg', 'guifg=#000000 guibg=#ffffff')\n  validate_hl_group('MiniHipatterns_767676_bg', 'guifg=#ffffff guibg=#767676')\n  validate_hl_group('MiniHipatterns_777777_bg', 'guifg=#000000 guibg=#777777')\n  validate_hl_group('MiniHipatterns_098777_bg', 'guifg=#ffffff guibg=#098777')\n  validate_hl_group('MiniHipatterns_178d7c_bg', 'guifg=#000000 guibg=#178d7c')\n\n  -- Should use cache per `hex_color` and `style` combination\n  eq(compute_hex_color_group('#767676', 'line'), 'MiniHipatterns_767676_line')\n  validate_hl_group('MiniHipatterns_767676_line', 'gui=underline guisp=#767676')\nend\n\nT['compute_hex_color_group()']['respects `style` argument'] = function()\n  eq(compute_hex_color_group('#000000', 'line'), 'MiniHipatterns_000000_line')\n  validate_hl_group('MiniHipatterns_000000_line', 'gui=underline guisp=#000000')\n  eq(compute_hex_color_group('#aaaaaa', 'fg'), 'MiniHipatterns_aaaaaa_fg')\n  validate_hl_group('MiniHipatterns_aaaaaa_fg', 'guifg=#aaaaaa')\nend\n\nT['compute_hex_color_group()']['persists after `:colorscheme`'] = function()\n  -- Needs `setup()` call to create `ColorScheme` autocommand\n  load_module()\n\n  eq(compute_hex_color_group('#000000', 'bg'), 'MiniHipatterns_000000_bg')\n  validate_hl_group('MiniHipatterns_000000_bg', 'guifg=#ffffff guibg=#000000')\n\n  child.cmd('colorscheme blue')\n  eq(compute_hex_color_group('#000000', 'line'), 'MiniHipatterns_000000_line')\n  validate_hl_group('MiniHipatterns_000000_line', 'gui=underline guisp=#000000')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_hues.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('hues', config) end\nlocal unload_module = function() child.mini_unload('hues') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\n--stylua: ignore end\n\nlocal validate_hl_group = function(group_name, target)\n  eq(child.cmd_capture('highlight ' .. group_name):gsub(' +', ' '), group_name .. ' xxx ' .. target)\nend\n\n-- Data =======================================================================\nlocal bg = '#11262d'\nlocal fg = '#c0c8cc'\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Undo the color scheme applied for all tests\n      child.cmd('hi clear')\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module({ background = bg, foreground = fg })\n\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniHues)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module({ background = bg, foreground = fg })\n\n  eq(child.lua_get('type(_G.MiniHues.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniHues.config.' .. field), value) end\n\n  expect_config('n_hues', 8)\n  expect_config('saturation', 'medium')\n  expect_config('accent', 'bg')\n  expect_config('autoadjust', true)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  load_module({ background = '#000000', foreground = '#ffffff' })\n  eq(child.lua_get('MiniHues.config.background'), '#000000')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({}, 'setup', 'both `background` and `foreground`')\n\n  expect_config_error({ background = 1, foreground = fg }, 'background', 'string')\n  expect_config_error({ background = '000000', foreground = fg }, 'background', '#rrggbb')\n\n  expect_config_error({ background = bg, foreground = 1 }, 'foreground', 'string')\n  expect_config_error({ background = bg, foreground = 'ffffff' }, 'foreground', '#rrggbb')\n\n  expect_config_error({ background = bg, foreground = fg, n_hues = '1' }, 'n_hues', 'number')\n  expect_config_error({ background = bg, foreground = fg, n_hues = -1 }, 'n_hues', '0')\n  expect_config_error({ background = bg, foreground = fg, n_hues = 9 }, 'n_hues', '8')\n\n  expect_config_error({ background = bg, foreground = fg, saturation = 'aaa' }, 'saturation', 'one of')\n\n  expect_config_error({ background = bg, foreground = fg, accent = 'aaa' }, 'accent', 'one of')\n\n  expect_config_error({ background = bg, foreground = fg, autoadjust = 1 }, 'autoadjust', 'boolean')\nend\n\nT['setup()']['defines builtin highlight groups'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd' })\n\n  validate_hl_group('Normal', 'guifg=#dddddd guibg=#222222')\n  validate_hl_group('Cursor', 'guifg=#222222 guibg=#dddddd')\n\n  validate_hl_group('Comment', 'guifg=#9a9a9a')\n  validate_hl_group('Error', 'guibg=#3e0c20')\n  validate_hl_group('Special', 'guifg=#a1efdf')\n  validate_hl_group('Bold', 'cterm=bold gui=bold')\n\n  validate_hl_group('DiagnosticError', 'guifg=#ffc7da')\n  validate_hl_group('DiagnosticWarn', 'guifg=#f2dca0')\n  validate_hl_group('DiagnosticInfo', 'guifg=#c0d2ff')\n  validate_hl_group('DiagnosticOk', 'guifg=#c7eab5')\n  validate_hl_group('DiagnosticHint', 'guifg=#a1efdf')\nend\n\nT['setup()']['defines tree-sitter groups'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd' })\n  validate_hl_group('@variable', 'guifg=#dddddd')\nend\n\nT['setup()']['defines LSP semantic token highlights'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd' })\n  validate_hl_group('@lsp.type.variable', 'links to @variable')\nend\n\nT['setup()']['defines terminal colors'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd' })\n\n  eq(child.g.terminal_color_0, '#080808')\n  eq(child.g.terminal_color_1, '#ffc7da')\n  eq(child.g.terminal_color_2, '#c7eab5')\n  eq(child.g.terminal_color_3, '#f2dca0')\n  eq(child.g.terminal_color_4, '#a5e6ff')\n  eq(child.g.terminal_color_5, '#f2ceff')\n  eq(child.g.terminal_color_6, '#a1efdf')\n  eq(child.g.terminal_color_7, '#9a9a9a')\n\n  eq(child.g.terminal_color_8, '#5c5c5c')\n  eq(child.g.terminal_color_9, '#ffc7da')\n  eq(child.g.terminal_color_10, '#c7eab5')\n  eq(child.g.terminal_color_11, '#f2dca0')\n  eq(child.g.terminal_color_12, '#a5e6ff')\n  eq(child.g.terminal_color_13, '#f2ceff')\n  eq(child.g.terminal_color_14, '#a1efdf')\n  eq(child.g.terminal_color_15, '#f4f4f4')\n\n  -- Properly sets black and white for light color scheme\n  load_module({ background = '#dddddd', foreground = '#222222' })\n  eq(child.g.terminal_color_0, '#080808')\n  eq(child.g.terminal_color_7, '#9a9a9a')\n  eq(child.g.terminal_color_8, '#5c5c5c')\n  eq(child.g.terminal_color_15, '#f4f4f4')\nend\n\nT['setup()']['clears previous colorscheme'] = function()\n  child.cmd('colorscheme blue')\n  load_module({ background = '#222222', foreground = '#dddddd' })\n  validate_hl_group('Normal', 'guifg=#dddddd guibg=#222222')\nend\n\nT['setup()']['respects `config.n_hues`'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd', n_hues = 1 })\n\n  validate_hl_group('DiagnosticError', 'guifg=#ffc7da')\n  validate_hl_group('DiagnosticHint', 'guifg=#ffc7da')\nend\n\nT['setup()']['respects `config.saturation`'] = function()\n  local validate = function(saturation, ref_error_fg)\n    load_module({ background = '#222222', foreground = '#dddddd', saturation = saturation })\n    validate_hl_group('DiagnosticError', 'guifg=' .. ref_error_fg)\n  end\n\n  validate('low', '#f5d3dc')\n  validate('lowmedium', '#ffcddb')\n  validate('medium', '#ffc7da')\n  validate('mediumhigh', '#ffb5cf')\n  validate('high', '#ffa8c6')\n\n  expect.error(\n    function() load_module({ background = '#222222', foreground = '#dddddd', saturation = 'aaa' }) end,\n    'one of.*\"high\"'\n  )\nend\n\nT['setup()']['respects `config.accent`'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd', accent = 'red' })\n\n  validate_hl_group('WinSeparator', 'guifg=#ffc7da')\n\n  expect.error(\n    function() load_module({ background = '#222222', foreground = '#dddddd', accent = 'aaa' }) end,\n    'one of.*\"bg\"'\n  )\nend\n\nT['setup()']['respects `config.plugins`'] = function()\n  load_module({ background = '#222222', foreground = '#dddddd' })\n\n  local clear_highlight = function()\n    child.cmd('highlight clear')\n    expect.match(child.cmd_capture('hi MiniCursorword'), 'cleared')\n  end\n\n  -- By default it should load plugin integrations\n  clear_highlight()\n  load_module({ background = '#222222', foreground = '#dddddd' })\n  validate_hl_group('MiniCursorword', 'cterm=underline gui=underline')\n\n  -- If supplied `false`, should not load plugin integration\n  clear_highlight()\n  reload_module({\n    background = '#222222',\n    foreground = '#dddddd',\n    plugins = { ['nvim-mini/mini.nvim'] = false, ['echasnovski/mini.nvim'] = false },\n  })\n  expect.match(child.cmd_capture('hi MiniCursorword'), 'cleared')\n\n  -- Should allow loading only chosen integrations\n  clear_highlight()\n  reload_module({\n    background = '#222222',\n    foreground = '#dddddd',\n    plugins = { default = false, ['echasnovski/mini.nvim'] = true },\n  })\n  validate_hl_group('MiniCursorword', 'cterm=underline gui=underline')\n  expect.match(child.cmd_capture('hi GitSignsAdd'), 'cleared')\nend\n\nT['setup()']['respects `config.autoadjust`'] = function()\n  -- By default it should autoadjust\n  child.cmd('highlight clear')\n  child.o.fillchars = 'msgsep:-'\n  load_module({ background = '#222222', foreground = '#dddddd' })\n  -- - Should also initially pick proper attributes\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd')\n\n  child.o.fillchars = 'msgsep: '\n  validate_hl_group('MsgSeparator', 'guibg=#3e3e3e')\n  child.o.fillchars = 'msgsep:-'\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd')\n\n  -- Should not autoadjust if `autoadjust = false`\n  child.cmd('highlight clear')\n  child.api.nvim_del_augroup_by_name('MiniHuesAdjust')\n  child.o.fillchars = 'msgsep:-'\n  load_module({ background = '#222222', foreground = '#dddddd', autoadjust = false })\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd guibg=#3e3e3e')\n  child.o.fillchars = 'msgsep: '\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd guibg=#3e3e3e')\n\n  -- Should autoadjust `Pmenu` based on 'pumborder'\n  if child.fn.has('nvim-0.12') == 1 then\n    child.cmd('highlight clear')\n    child.o.pumborder = 'single'\n    load_module({ background = '#222222', foreground = '#dddddd' })\n    validate_hl_group('Pmenu', 'links to NormalFloat')\n\n    child.o.pumborder = 'none'\n    validate_hl_group('Pmenu', 'guifg=#dddddd guibg=#3e3e3e')\n  end\nend\n\nT['make_palette()'] = new_set()\n\nlocal make_palette = function(...) return child.lua_get([[require('mini.hues').make_palette(...)]], { ... }) end\n\n--stylua: ignore\nlocal validate_nonbase_colors = function(config, ref_colors)\n  local palette = make_palette(config)\n  eq(\n    {\n      red    = palette.red,\n      orange = palette.orange,\n      yellow = palette.yellow,\n      green  = palette.green,\n      cyan   = palette.cyan,\n      azure  = palette.azure,\n      blue   = palette.blue,\n      purple = palette.purple,\n    },\n    ref_colors\n  )\nend\n\n--stylua: ignore\nT['make_palette()']['works'] = function()\n  eq(\n  make_palette({ background = '#222222', foreground = '#dddddd' }),\n  {\n    bg_edge2  = '#080808',\n    bg_edge   = '#161616',\n    bg        = '#222222',\n    bg_mid    = '#3e3e3e',\n    bg_mid2   = '#5c5c5c',\n    fg_edge2  = '#f4f4f4',\n    fg_edge   = '#e8e8e8',\n    fg        = '#dddddd',\n    fg_mid    = '#bbbbbb',\n    fg_mid2   = '#9a9a9a',\n    red       = '#ffc7da',\n    red_bg    = '#3e0c20',\n    orange    = '#ffcbb1',\n    orange_bg = '#431700',\n    yellow    = '#f2dca0',\n    yellow_bg = '#453500',\n    green     = '#c7eab5',\n    green_bg  = '#122d00',\n    cyan      = '#a1efdf',\n    cyan_bg   = '#004940',\n    azure     = '#a5e6ff',\n    azure_bg  = '#004053',\n    blue      = '#c0d2ff',\n    blue_bg   = '#141d48',\n    purple    = '#f2ceff',\n    purple_bg = '#30133c',\n    accent    = '#dddddd',\n    accent_bg = '#222222',\n  })\n\n  eq(\n  make_palette({ background = '#dddddd', foreground = '#222222' }),\n  {\n    bg_edge2  = '#f4f4f4',\n    bg_edge   = '#e8e8e8',\n    bg        = '#dddddd',\n    bg_mid    = '#bbbbbb',\n    bg_mid2   = '#9a9a9a',\n    fg_edge2  = '#080808',\n    fg_edge   = '#161616',\n    fg        = '#222222',\n    fg_mid    = '#3e3e3e',\n    fg_mid2   = '#5c5c5c',\n    red       = '#3e0c20',\n    red_bg    = '#ffc7da',\n    orange    = '#431700',\n    orange_bg = '#ffcbb1',\n    yellow    = '#453500',\n    yellow_bg = '#f2dca0',\n    green     = '#122d00',\n    green_bg  = '#c7eab5',\n    cyan      = '#004940',\n    cyan_bg   = '#a1efdf',\n    azure     = '#004053',\n    azure_bg  = '#a5e6ff',\n    blue      = '#141d48',\n    blue_bg   = '#c0d2ff',\n    purple    = '#30133c',\n    purple_bg = '#f2ceff',\n    accent    = '#222222',\n    accent_bg = '#dddddd',\n  })\nend\n\nT['make_palette()']['correctly shifts hue of non-base colors'] = function()\n  -- Chromatic background, gray foreground\n  local validate_bg = function(input_bg, ref_red)\n    eq(make_palette({ background = input_bg, foreground = '#dddddd' }).red, ref_red)\n  end\n\n  validate_bg('#2e1c24', '#ffc6cb')\n  validate_bg('#2f1c22', '#ffc7c4')\n  validate_bg('#2f1c1f', '#ffc8e8')\n  validate_bg('#2f1d1c', '#ffc7d9')\n  validate_bg('#2f1d1a', '#ffc6d2')\n\n  -- Gray background, chromatic foreground\n  local validate_fg = function(input_fg, ref_red)\n    eq(make_palette({ background = '#dddddd', foreground = input_fg }).red, ref_red)\n  end\n\n  validate_fg('#2e1c24', '#400c16')\n  validate_fg('#2f1c22', '#410d10')\n  validate_fg('#2f1c1f', '#3b0e2a')\n  validate_fg('#2f1d1c', '#3f0d21')\n  validate_fg('#2f1d1a', '#400c1b')\n\n  -- Chromatic background, chromatic foreground\n  local validate_both = function(input_fg, ref_red)\n    eq(make_palette({ background = '#2f1c22', foreground = input_fg }).red, ref_red)\n  end\n\n  validate_both('#d8bfc6', '#f7b2b0')\n  validate_both('#d9bfc2', '#ecb2d5')\n  validate_both('#f7b2b1', '#eeb2d1')\n  validate_both('#f6b3a7', '#f5b1b6')\n  validate_both('#f5b59f', '#f6b2b1')\n  validate_both('#f2b897', '#ebb3d7')\nend\n\n--stylua: ignore\nT['make_palette()']['respects `config.n_hues`'] = function()\n  -- Works in general\n  validate_nonbase_colors(\n    { background = '#2f1c22', foreground = '#d8bfc6', n_hues = 8 },\n    {\n      red  = '#f7b2b0', orange = '#ebbd8f', yellow = '#c8cc90', green  = '#9cd7b2',\n      cyan = '#85d7dc', azure  = '#9cccf8', blue   = '#c7bef7', purple = '#e9b3da',\n    }\n  )\n  validate_nonbase_colors(\n    { background = '#2f1c22', foreground = '#d8bfc6', n_hues = 6 },\n    {\n      red  = '#f6b3a9', orange = '#f6b3a9', yellow = '#dbc58a', green  = '#a3d6ab',\n      cyan = '#86d5e3', azure  = '#86d5e3', blue   = '#b1c5fc', purple = '#e4b4e0',\n    }\n  )\n  validate_nonbase_colors(\n    { background = '#2f1c22', foreground = '#d8bfc6', n_hues = 4 },\n    {\n      red  = '#f4b79d', orange = '#f4b79d', yellow = '#b1d39e', green  = '#b1d39e',\n      cyan = '#8cd2ed', azure  = '#8cd2ed', blue   = '#dab8eb', purple = '#dab8eb',\n    }\n  )\n  validate_nonbase_colors(\n    { background = '#2f1c22', foreground = '#d8bfc6', n_hues = 2 },\n    {\n      red  = '#dbc58a', orange = '#dbc58a', yellow = '#dbc58a', green  = '#dbc58a',\n      cyan = '#b1c5fc', azure  = '#b1c5fc', blue   = '#b1c5fc', purple = '#b1c5fc',\n    }\n  )\n  validate_nonbase_colors(\n    { background = '#2f1c22', foreground = '#d8bfc6', n_hues = 0 },\n    {\n      red  = '#c6c6c6', orange = '#c6c6c6', yellow = '#c6c6c6', green  = '#c6c6c6',\n      cyan = '#c6c6c6', azure  = '#c6c6c6', blue   = '#c6c6c6', purple = '#c6c6c6',\n    }\n  )\n\n  -- Properly shifts initial equidistant grid\n  validate_nonbase_colors(\n    { background = '#2f1e16', foreground = '#d8c1b7', n_hues = 2 },\n    {\n      red  = '#dbb7ea', orange = '#dbb7ea', yellow = '#b0d39f', green  = '#b0d39f',\n      cyan = '#b0d39f', azure  = '#b0d39f', blue   = '#dbb7ea', purple = '#dbb7ea',\n    }\n  )\nend\n\n--stylua: ignore\nT['make_palette()']['respects `config.saturation`'] = function()\n  validate_nonbase_colors(\n    { background = '#222222', foreground = '#dddddd', saturation = 'low' },\n    {\n      red  = '#f5d3dc', orange = '#f5d6c8', yellow = '#e7ddc0', green  = '#d2e4c9',\n      cyan = '#c2e6de', azure  = '#c2e3f1', blue   = '#d3ddf9', purple = '#e7d6f0',\n    }\n  )\n  validate_nonbase_colors(\n    { background = '#222222', foreground = '#dddddd', saturation = 'high' },\n    {\n      red  = '#ffa8c6', orange = '#ffb28d', yellow = '#ffd863', green  = '#aef585',\n      cyan = '#1dffe1', azure  = '#82ddff', blue   = '#9cb6ff', purple = '#ebb2ff',\n    }\n  )\nend\n\n--stylua: ignore\nT['make_palette()']['respects `config.accent`'] = function()\n  local validate = function(accent, ref_colors)\n    local palette = make_palette({ background = '#222222', foreground = '#d8c1b7', accent = accent })\n    eq({ accent_bg = palette.accent_bg, accent = palette.accent }, ref_colors)\n  end\n\n  validate('bg',     { accent_bg = '#222222', accent = '#c6c6c6' })\n  validate('fg',     { accent_bg = '#431600', accent = '#d8c1b7' })\n  validate('red',    { accent_bg = '#410c0f', accent = '#f6b2af' })\n  validate('orange', { accent_bg = '#492a00', accent = '#eabd8f' })\n  validate('yellow', { accent_bg = '#343700', accent = '#c7cc90' })\n  validate('green',  { accent_bg = '#003a20', accent = '#9bd7b2' })\n  validate('cyan',   { accent_bg = '#004b50', accent = '#85d6dd' })\n  validate('azure',  { accent_bg = '#002a4b', accent = '#9dccf8' })\n  validate('blue',   { accent_bg = '#241844', accent = '#c7bef7' })\n  validate('purple', { accent_bg = '#390f2f', accent = '#e9b3d9' })\nend\n\nT['make_palette()']['validates arguments'] = function()\n  expect.error(function() make_palette({ background = 1 }) end, '`background`.*#rrggbb')\n  expect.error(function() make_palette({ background = bg, foreground = 1 }) end, '`foreground`.*#rrggbb')\n\n  expect.error(function() make_palette({ background = bg, foreground = fg, n_hues = 'a' }) end, '`n_hues`.*number')\n  expect.error(function() make_palette({ background = bg, foreground = fg, n_hues = -1 }) end, '0')\n  expect.error(function() make_palette({ background = bg, foreground = fg, n_hues = 9 }) end, '8')\n\n  expect.error(function() make_palette({ background = bg, foreground = fg, saturation = 'aaa' }) end, 'one of.*\"high\"')\n\n  expect.error(function() make_palette({ background = bg, foreground = fg, accent = 'aaa' }) end, 'one of.*\"bg\"')\nend\n\nT['apply_palette()'] = new_set()\n\nlocal apply_palette = function(...) return child.lua_get([[require('mini.hues').apply_palette(...)]], { ... }) end\n\nT['apply_palette()']['works'] = function()\n  child.cmd('hi Normal guifg=#eeeeee')\n  child.cmd('hi String guifg=#00ff00')\n\n  local palette = make_palette({ background = '#222222', foreground = '#dddddd' })\n  palette.fg = '#aaaaaa'\n  apply_palette(palette)\n\n  validate_hl_group('Normal', 'guifg=#aaaaaa guibg=#222222')\n  validate_hl_group('String', 'guifg=#c7eab5')\n  validate_hl_group('@variable', 'guifg=#aaaaaa')\n  validate_hl_group('MiniCursorword', 'cterm=underline gui=underline')\n  validate_hl_group('WhichKey', 'guifg=#a1efdf')\n  validate_hl_group('@lsp.type.variable', 'links to @variable')\n  eq(child.g.terminal_color_0, '#080808')\nend\n\nT['apply_palette()']['respects `plugins`'] = function()\n  local palette = make_palette({ background = '#222222', foreground = '#dddddd' })\n  apply_palette(palette, { default = false, ['echasnovski/mini.nvim'] = true })\n  validate_hl_group('MiniCursorword', 'cterm=underline gui=underline')\n  validate_hl_group('WhichKey', 'cleared')\n\n  -- Uses the one from `config` by default\n  child.cmd('hi clear')\n  child.lua([[require('mini.hues').setup({\n    background = '#222222',\n    foreground = '#dddddd',\n    plugins = { default = true, [\"nvim-mini/mini.nvim\"] = false, [\"echasnovski/mini.nvim\"] = false },\n  })]])\n  apply_palette(palette)\n  validate_hl_group('MiniCursorword', 'cleared')\n  validate_hl_group('WhichKey', 'guifg=#a1efdf')\nend\n\nT['apply_palette()']['respects `opts.autoadjust`'] = function()\n  local palette = make_palette({ background = '#222222', foreground = '#dddddd' })\n\n  -- By default it should follow `config.autoadjust`\n  child.lua('MiniHues.config.autoadjust = false')\n  child.cmd('highlight clear')\n  child.o.fillchars = 'msgsep:-'\n\n  apply_palette(palette)\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd guibg=#3e3e3e')\n\n  child.o.fillchars = 'msgsep: '\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd guibg=#3e3e3e')\n\n  -- Should respect `opts.autoadjust` value\n  child.o.fillchars = 'msgsep: '\n  apply_palette(palette, {}, { autoadjust = true })\n  validate_hl_group('MsgSeparator', 'guibg=#3e3e3e')\n\n  child.o.fillchars = 'msgsep:-'\n  validate_hl_group('MsgSeparator', 'guifg=#dddddd')\nend\n\nT['apply_palette()']['clears highlight groups'] = function()\n  child.cmd('hi AAA guifg=#cccccc')\n  local palette = make_palette({ background = '#222222', foreground = '#dddddd' })\n\n  -- Should execute `:hi clear` only if there was previous color scheme applied\n  apply_palette(palette)\n  validate_hl_group('AAA', 'guifg=#cccccc')\n\n  child.g.colors_name = 'some_colorscheme'\n  apply_palette(palette)\n  validate_hl_group('AAA', 'cleared')\nend\n\nT['apply_palette()']['clears `g:colors_name`'] = function()\n  child.g.colors_name = 'hello'\n  local palette = make_palette({ background = '#222222', foreground = '#dddddd' })\n  apply_palette(palette)\n  eq(child.g.colors_name, vim.NIL)\nend\n\nT['apply_palette()']['validates input'] = function()\n  expect.error(function() apply_palette('a') end, '`palette`.*table')\n\n  local palette = make_palette({ background = '#222222', foreground = '#dddddd' })\n  expect.error(function() apply_palette(palette, 'a') end, '`plugins`.*table')\nend\n\nT['get_palette()'] = new_set()\n\nT['get_palette()']['works'] = function()\n  local res = child.lua([[\n    local palette = MiniHues.make_palette({ background = '#222222', foreground = '#dddddd' })\n    palette.fg = '#aaaaaa'\n    MiniHues.apply_palette(palette)\n\n    local res_palette = MiniHues.get_palette()\n    local is_same = vim.deep_equal(palette, res_palette)\n\n    -- Should not be affected by change in applied palette\n    palette.bg = '#000000'\n    local is_same_1 = vim.deep_equal(palette, res_palette)\n\n    -- Should return copy\n    res_palette.bg = '#000000'\n    local is_same_2 = vim.deep_equal(MiniHues.get_palette(), res_palette)\n\n    return { is_same, is_same_1, is_same_2 }\n  ]])\n\n  eq(res, { true, false, false })\nend\n\nT['gen_random_base_colors()'] = new_set()\n\nT['gen_random_base_colors()']['works'] = function()\n  -- With dark background\n  child.o.background = 'dark'\n  child.lua('math.randomseed(20230504)')\n  eq(\n    child.lua_get([[require('mini.hues').gen_random_base_colors()]]),\n    { background = '#292111', foreground = '#c9c6c0' }\n  )\n\n  -- With lightness background\n  child.o.background = 'light'\n  child.lua('math.randomseed(20230504)')\n  eq(\n    child.lua_get([[require('mini.hues').gen_random_base_colors()]]),\n    { background = '#e5e2db', foreground = '#302e29' }\n  )\nend\n\nT['gen_random_base_colors()']['respects `opts.gen_hue`'] = function()\n  child.o.background = 'dark'\n  for _ = 1, 2 do\n    eq(\n      child.lua_get([[require('mini.hues').gen_random_base_colors({ gen_hue = function() return 0 end })]]),\n      { background = '#2f1c22', foreground = '#cdc4c6' }\n    )\n  end\n\n  eq(\n    child.lua_get([[require('mini.hues').gen_random_base_colors({ gen_hue = function() return 720 end })]]),\n    { background = '#2f1c22', foreground = '#cdc4c6' }\n  )\nend\n\nT['gen_random_base_colors()']['validates arguments'] = function()\n  expect.error(\n    function() child.lua([[require('mini.hues').gen_random_base_colors({ gen_hue = 1 })]]) end,\n    '`gen_hue`.*callable'\n  )\nend\n\nT['Bundled color schemes'] = new_set()\n\nT['Bundled color schemes']['works'] = function()\n  -- randomhue\n  expect.no_error(function() child.cmd('colorscheme randomhue') end)\n  eq(child.fn.hlexists('MiniCursorword'), 1)\n\n  local validate_lightness = function()\n    local hl = child.api.nvim_get_hl(0, { name = 'Normal' })\n    -- NOTE: This is not 100% proper solution, but at least it is something\n    if child.o.background == 'dark' then eq(hl.fg > hl.bg, true) end\n    if child.o.background == 'light' then eq(hl.fg < hl.bg, true) end\n  end\n\n  child.o.background = 'dark'\n  validate_lightness()\n  child.o.background = 'light'\n  validate_lightness()\n\n  -- Four seasons\n  local validate = function(cs_name, ref_bg)\n    expect.no_error(function() child.cmd('colorscheme ' .. cs_name) end)\n    expect.match(child.cmd_capture('hi Normal'), 'guibg=' .. ref_bg)\n  end\n\n  child.o.background = 'dark'\n  validate('miniwinter', '#11262d')\n  validate('minispring', '#1c2617')\n  validate('minisummer', '#27211e')\n  validate('miniautumn', '#262029')\n\n  child.o.background = 'light'\n  validate('miniwinter', '#dce4e8')\n  validate('minispring', '#e0e4de')\n  validate('minisummer', '#e9e1dd')\n  validate('miniautumn', '#e5e1e7')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_icons.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq, no_eq = helpers.expect, helpers.expect.equality, helpers.expect.no_equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('icons', config) end\nlocal unload_module = function() child.mini_unload('icons') end\n--stylua: ignore end\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal get = function(...) return child.lua_get('{ MiniIcons.get(...) }', { ... }) end\nlocal list = forward_lua('MiniIcons.list')\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniIcons)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniIcons'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniIconsAzure', 'links to Function')\n  has_highlight('MiniIconsBlue', 'links to DiagnosticInfo')\n  has_highlight('MiniIconsCyan', 'links to DiagnosticHint')\n  has_highlight('MiniIconsGreen', 'links to DiagnosticOk')\n  has_highlight('MiniIconsGrey', child.fn.has('nvim-0.10') == 1 and 'cleared' or 'cterm= gui=')\n  has_highlight('MiniIconsOrange', 'links to DiagnosticWarn')\n  has_highlight('MiniIconsPurple', 'links to Constant')\n  has_highlight('MiniIconsRed', 'links to DiagnosticError')\n  has_highlight('MiniIconsYellow', 'links to DiagnosticWarn')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniIcons.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniIcons.config.' .. field), value) end\n\n  expect_config('style', 'glyph')\n\n  expect_config('default', {})\n  expect_config('directory', {})\n  expect_config('extension', {})\n  expect_config('file', {})\n  expect_config('filetype', {})\n  expect_config('lsp', {})\n  expect_config('os', {})\n  eq(child.lua_get('type(MiniIcons.config.use_file_extension)'), 'function')\n  eq(child.lua_get('MiniIcons.config.use_file_extension()'), true)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ style = 'ascii' })\n  eq(child.lua_get('MiniIcons.config.style'), 'ascii')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ style = 1 }, 'style', 'string')\n  expect_config_error({ default = 1 }, 'default', 'table')\n  expect_config_error({ directory = 1 }, 'directory', 'table')\n  expect_config_error({ extension = 1 }, 'extension', 'table')\n  expect_config_error({ file = 1 }, 'file', 'table')\n  expect_config_error({ filetype = 1 }, 'filetype', 'table')\n  expect_config_error({ lsp = 1 }, 'lsp', 'table')\n  expect_config_error({ os = 1 }, 'os', 'table')\n  expect_config_error({ use_file_extension = 1 }, 'use_file_extension', 'function')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniIconsAzure'), 'links to Function')\nend\n\nT['setup()']['can customize icons'] = function()\n  -- Both override existing and provide new ones\n  load_module({\n    default = {\n      -- Can provide only customized attributes\n      extension = { glyph = 'E' },\n      file = { hl = 'AAA' },\n    },\n    directory = {\n      my_dir = { glyph = 'D', hl = 'Directory' },\n    },\n  })\n\n  eq(get('default', 'extension')[1], 'E')\n  eq(get('default', 'file')[2], 'AAA')\n  eq(get('directory', 'my_dir'), { 'D', 'Directory', false })\nend\n\nT['setup()']['customization respects `vim.filetype.match()` fallback'] = function()\n  child.lua([[vim.filetype.add({ extension = { myext = 'extinguisher' } })]])\n\n  load_module({\n    filetype = { extinguisher = { glyph = '󰻲', hl = 'MiniIconsRed' } },\n    extension = { myext = { hl = 'Special' } },\n    file = { ['hello.myext'] = { hl = 'String' } },\n  })\n  eq(get('file', 'hello.myext'), { '󰻲', 'String', false })\n  eq(get('extension', 'myext'), { '󰻲', 'Special', false })\n  eq(get('filetype', 'extinguisher'), { '󰻲', 'MiniIconsRed', false })\nend\n\nT['setup()']['respects `config.style` when customizing icons'] = function()\n  load_module({\n    style = 'ascii',\n    default = { default = { glyph = '-', hl = 'Comment' } },\n    extension = { ext = { glyph = '󰻲', hl = 'MiniIconsRed' } },\n  })\n\n  eq(get('default', 'default'), { 'D', 'Comment', false })\n  eq(get('extension', 'ext'), { 'E', 'MiniIconsRed', false })\nend\n\nT['get()'] = new_set()\n\nT['get()']['works with \"default\" category'] = function()\n  local validate = function(name, icon, hl, is_default) eq(get('default', name), { icon, hl, is_default }) end\n\n  validate('default', '󰟢', 'MiniIconsGrey', false)\n  validate('directory', '󰉋', 'MiniIconsAzure', false)\n  validate('extension', '󰈔', 'MiniIconsGrey', false)\n  validate('file', '󰈔', 'MiniIconsGrey', false)\n  validate('filetype', '󰈔', 'MiniIconsGrey', false)\n  validate('lsp', '󰞋', 'MiniIconsRed', false)\n  validate('os', '󰟀', 'MiniIconsPurple', false)\n\n  -- Can be customized\n  load_module({\n    default = {\n      file = { glyph = '󱁂', hl = 'Comment' },\n    },\n  })\n  validate('file', '󱁂', 'Comment', false)\n\n  -- Validates not supported category\n  expect.error(function() get('default', 'aaa') end, 'aaa.*not.*category')\nend\n\nT['get()']['works with \"directory\" category'] = function()\n  load_module({\n    default = { directory = { glyph = 'D', hl = 'Comment' } },\n    directory = { mydir = { glyph = '󱁂', hl = 'AA' } },\n  })\n\n  local validate = function(name, icon, hl, is_default) eq(get('directory', name), { icon, hl, is_default }) end\n\n  validate('.git', '', 'MiniIconsOrange', false)\n  validate('mydir', '󱁂', 'AA', false)\n  validate('should-be-default', 'D', 'Comment', true)\n\n  -- Works with full paths\n  validate('/home/user/.git', '', 'MiniIconsOrange', false)\n  validate('/home/user/mydir', '󱁂', 'AA', false)\n  validate('/home/user/should-be-default', 'D', 'Comment', true)\nend\n\nT['get()']['works with \"extension\" category'] = function()\n  load_module({\n    default = { extension = { glyph = 'E', hl = 'Comment' } },\n    extension = {\n      myext = { glyph = '󱁂', hl = 'AA' },\n      ['my.ext'] = { glyph = '󰻲', hl = 'MiniIconsRed' },\n      ['my.other.ext'] = { glyph = 'O', hl = 'Error' },\n      ['my.lua'] = { glyph = 'L', hl = 'String' },\n    },\n    filetype = { squirrel = { glyph = 'S', hl = 'Special' } },\n  })\n  local validate = function(name, icon, hl, is_default) eq(get('extension', name), { icon, hl, is_default }) end\n\n  validate('lua', '󰢱', 'MiniIconsAzure', false)\n  validate('my.lua', 'L', 'String', false)\n\n  validate('myext', '󱁂', 'AA', false)\n  validate('my.ext', '󰻲', 'MiniIconsRed', false)\n  validate('my.other.ext', 'O', 'Error', false)\n\n  validate('xpm', '󰍹', 'MiniIconsYellow', false)\n  validate('nut', 'S', 'Special', false)\n\n  validate('should-be-default', 'E', 'Comment', true)\n\n  -- Properly resolves complex extensions\n  validate('hello.lua', '󰢱', 'MiniIconsAzure', false)\n  validate('hello.my.lua', 'L', 'String', false)\n  validate('hello.world.mp4', '󰈫', 'MiniIconsAzure', false)\n  validate('hello.myext', '󱁂', 'AA', false)\n  validate('hello.my.ext', '󰻲', 'MiniIconsRed', false)\n  validate('hello.my.other.ext', 'O', 'Error', false)\nend\n\nT['get()']['works with \"file\" category'] = function()\n  load_module({\n    default = { file = { glyph = 'F', hl = 'Comment' } },\n    file = {\n      myfile = { glyph = '󱁂', hl = 'AA' },\n      ['init.lua'] = { glyph = 'V' },\n    },\n    filetype = { gitignore = { glyph = 'G', hl = 'Ignore' } },\n    extension = {\n      py = { glyph = 'PY', hl = 'String' },\n      ['my.py'] = { glyph = 'MY', hl = 'Comment' },\n      ext = { glyph = 'E', hl = 'Comment' },\n      ['my.ext'] = { glyph = '󰻲', hl = 'MiniIconsRed' },\n    },\n  })\n\n  local validate = function(name, icon, hl, is_default) eq(get('file', name), { icon, hl, is_default }) end\n\n  -- Works with different sources of resolution\n  -- - Exact basename\n  validate('LICENSE', '', 'MiniIconsCyan', false)\n  -- - Extension\n  validate('hello.lua', '󰢱', 'MiniIconsAzure', false)\n  -- - `vim.filetype.match()`\n  validate('Cargo.lock', '', 'MiniIconsOrange', false)\n  -- - `vim.filetype.match()` which relies on supplied `buf`\n  validate('hello.xpm', '󰍹', 'MiniIconsYellow', false)\n  -- - `vim.filetype.match()` with recognizable extension\n  validate('build.xml', '󰫮', 'MiniIconsRed', false)\n  -- - Default\n  validate('should-be-default', 'F', 'Comment', true)\n\n  -- Can use customizations\n  validate('myfile', '󱁂', 'AA', false)\n  validate('init.lua', 'V', 'MiniIconsGreen', false)\n  validate('hello.py', 'PY', 'String', false)\n  validate('.gitignore', 'G', 'Ignore', false)\n\n  -- Can use complex \"extension\"\n  validate('hello.ext', 'E', 'Comment', false)\n  validate('hello.my.ext', '󰻲', 'MiniIconsRed', false)\n  validate('hello.extra.dot.my.ext', '󰻲', 'MiniIconsRed', false)\n  validate('hello.my.py', 'MY', 'Comment', false)\n  validate('hello.extra.dot.my.py', 'MY', 'Comment', false)\n\n  -- Works with full paths\n  local validate_full = function(name) eq(get('file', name), get('file', name:match('/([^/]+)$'))) end\n  validate_full('/home/user/LICENSE')\n  validate_full('/home/user/init.lua')\n  validate_full('/home/user/world.lua')\n  validate_full('/home/user/myfile')\n  validate_full('/home/user/world.py')\n  validate_full('/home/user/world.ext')\n  validate_full('/home/user/world.my.ext')\n  validate_full('/home/user/should-be-default')\n\n  -- Should use full name in `vim.filetype.match()`\n  validate('/etc/group', '󰫴', 'MiniIconsCyan', false)\n  child.lua([[vim.filetype.add({ pattern = { ['.*/dir/conf'] = 'conf' } })]])\n  validate('/home/user/dir/conf', '󰒓', 'MiniIconsGrey', false)\n\n  -- Cached data for basename should not affect full path resolution\n  eq(get('file', 'gshadow'), { 'F', 'Comment', true })\n  validate('/etc/gshadow', '󰫴', 'MiniIconsCyan', false)\n\n  -- Should override some confusing `vim.filetype.match()` results\n  validate('.dockerignore', '󰡨', 'MiniIconsOrange', false)\nend\n\nT['get()']['respects `config.use_file_extension`'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniIcons.setup({\n      extension = {\n        ['my.ext'] = { glyph = 'M', hl = 'Comment' },\n      },\n      use_file_extension = function(ext, file, ...)\n        table.insert(_G.log, { ext, file, ... })\n        if ext == 'yml' then return nil end\n        if vim.endswith(ext, 'scm') then return false end\n        return true\n      end\n    })\n  ]])\n\n  -- Should be called only once with proper arguments\n  child.lua('_G.log = {}')\n  eq(get('file', 'hello.woRld.My.Ext'), { 'M', 'Comment', false })\n  eq(child.lua_get('_G.log'), { { 'world.my.ext', 'hello.woRld.My.Ext' } })\n\n  -- Should allow skipping extensions if returns not `true`\n  child.lua([[vim.filetype.add({ pattern = { ['.*/roles/.*/tasks/.*%.ya?ml'] = 'yaml.ansible' } })]])\n  eq(get('file', '/home/user/roles/a/tasks/hello.yml'), { '󱂚', 'MiniIconsGrey', false })\n  eq(get('file', '/home/user/roles/a/tasks/hello.yaml'), { '', 'MiniIconsPurple', false })\n  eq(get('file', '/hello.yml'), { '', 'MiniIconsPurple', false })\n  eq(get('file', '/extra.dots.yml'), { '', 'MiniIconsPurple', false })\n\n  -- - '/queries/.*%.scm' pattern should be built-in\n  eq(get('file', './queries/lua.scm'), { '󰐅', 'MiniIconsGreen', false })\n  eq(get('file', './queries/extra.dots.scm'), { '󰐅', 'MiniIconsGreen', false })\n  eq(get('file', 'lua.scm'), { '󰘧', 'MiniIconsGrey', false })\n\n  -- Should not be called if there is no extension\n  child.lua('_G.log = {}')\n  get('file', 'file-without-extension')\n  eq(child.lua_get('_G.log'), {})\nend\n\nT['get()']['works with \"filetype\" category'] = function()\n  load_module({\n    default = { filetype = { glyph = 'F', hl = 'Comment' } },\n    filetype = { myfiletype = { glyph = '󱁂', hl = 'AA' } },\n  })\n\n  local validate = function(name, icon, hl, is_default) eq(get('filetype', name), { icon, hl, is_default }) end\n\n  validate('help', '󰋖', 'MiniIconsPurple', false)\n  validate('myfiletype', '󱁂', 'AA', false)\n  validate('should-be-default', 'F', 'Comment', true)\nend\n\nT['get()']['works with \"lsp\" category'] = function()\n  load_module({\n    default = { lsp = { glyph = 'L', hl = 'Comment' } },\n    lsp = { mylsp = { glyph = '󱁂', hl = 'AA' } },\n  })\n\n  local validate = function(name, icon, hl, is_default) eq(get('lsp', name), { icon, hl, is_default }) end\n\n  validate('array', '', 'MiniIconsOrange', false)\n  validate('mylsp', '󱁂', 'AA', false)\n  validate('should-be-default', 'L', 'Comment', true)\nend\n\nT['get()']['works with \"os\" category'] = function()\n  load_module({\n    default = { os = { glyph = 'O', hl = 'Comment' } },\n    os = { myos = { glyph = '󱁂', hl = 'AA' } },\n  })\n\n  local validate = function(name, icon, hl, is_default) eq(get('os', name), { icon, hl, is_default }) end\n\n  validate('arch', '󰣇', 'MiniIconsAzure', false)\n  validate('myos', '󱁂', 'AA', false)\n  validate('should-be-default', 'O', 'Comment', true)\nend\n\nT['get()']['caches output'] = function()\n  local durations = child.lua([[\n    local file = 'complex.file.name.which.should.fall.back.to.vim.filetype.match'\n    local bench = function()\n      local start_time = vim.loop.hrtime()\n      MiniIcons.get('file', file)\n      return vim.loop.hrtime() - start_time\n    end\n\n    local dur_no_cache = bench()\n    local dur_cache = bench()\n\n    -- Calling `setup()` should reset cache\n    MiniIcons.setup()\n    local dur_no_cache_2 = bench()\n\n    return { no_cache = dur_no_cache, cache = dur_cache, no_cache_2 = dur_no_cache_2 }\n  ]])\n\n  eq(durations.cache <= 0.02 * durations.no_cache, true)\n  eq(durations.cache <= 0.02 * durations.no_cache_2, true)\nend\n\nT['get()']['adds to cache resolved output in its original category'] = function()\n  -- NOTES:\n  -- - There should also be caching of both \"file\" and \"extension\" category\n  --   resolving to \"filetype\", but as \"filetype\" is already very fast without\n  --   caching, the benchmarking is not stable.\n  local durations = child.lua([[\n    local bench = function(category, name)\n      local start_time = vim.loop.hrtime()\n      MiniIcons.get(category, name)\n      return vim.loop.hrtime() - start_time\n    end\n\n    -- \"file\" category resolving to manually tracked \"extension\"\n    local ext_manual_no_cache = bench('extension', 'lua')\n    MiniIcons.get('file', 'hello.py')\n    local ext_manual_cache = bench('extension', 'py')\n\n    -- \"file\" category resolving to known (i.e. not fallback) \"extension\"\n    local ext_known_no_cache = bench('extension', 'txt')\n    MiniIcons.get('file', 'hello.yml')\n    local ext_known_cache = bench('extension', 'yml')\n\n    -- \"file\" category resolving to unknown \"extension\"\n    local ext_unknown_no_cache = bench('extension', 'myext')\n    MiniIcons.get('file', 'hello.myotherext')\n    local ext_unknown_cache = bench('extension', 'myotherext')\n\n    return {\n      ext_manual_no_cache = ext_manual_no_cache,\n      ext_manual_cache = ext_manual_cache,\n      ext_known_no_cache = ext_known_no_cache,\n      ext_known_cache = ext_known_cache,\n      ext_unknown_no_cache = ext_unknown_no_cache,\n      ext_unknown_cache = ext_unknown_cache,\n    }\n  ]])\n\n  -- Resolution with manually tracked data is usually fast, hence higher coeff\n  eq(durations.ext_manual_cache < 0.7 * durations.ext_manual_no_cache, true)\n\n  -- There is a full effect of caching for not manually tracked\n  eq(durations.ext_known_cache < 0.1 * durations.ext_known_no_cache, true)\n  eq(durations.ext_unknown_cache < 0.1 * durations.ext_unknown_no_cache, true)\nend\n\nT['get()']['uses cached extension during \"file\" resolution'] = function()\n  local durations = child.lua([[\n    local bench = function(category, name)\n      local start_time = vim.loop.hrtime()\n      MiniIcons.get(category, name)\n      return vim.loop.hrtime() - start_time\n    end\n\n    -- Known extension (i.e. not falling back to default)\n    local file_known_ext_no_cache = bench('file', 'hello.txt')\n    MiniIcons.get('extension', 'yml')\n    local file_known_ext_cache = bench('file', 'world.yml')\n\n    -- Unknown extension (i.e. falling back to default)\n    local file_unknown_ext_no_cache = bench('file', 'hello.myext')\n    MiniIcons.get('file', 'hello.myotherext')\n    local file_unknown_ext_cache = bench('file', 'world.myotherext')\n\n    return {\n      file_known_ext_no_cache = file_known_ext_no_cache,\n      file_known_ext_cache = file_known_ext_cache,\n      file_unknown_ext_no_cache = file_unknown_ext_no_cache,\n      file_unknown_ext_cache = file_unknown_ext_cache,\n    }\n  ]])\n\n  -- Known extensions are used as output resulting in no `vim.filetype.match()`\n  -- call for file name itself\n  eq(durations.file_known_ext_cache < 0.1 * durations.file_known_ext_no_cache, true)\n\n  -- Unknown extensions are NOT used as output, but they are still cached which\n  -- results in no extra `vim.filetype.match()` call to resolve itself inside\n  -- \"extension\" category\n  eq(durations.file_unknown_ext_cache < 0.7 * durations.file_unknown_ext_no_cache, true)\nend\n\nT['get()']['prefers user configured data over `vim.filetype.match()`'] = function()\n  load_module({\n    extension = {\n      ['complex.extension.which.user.configured.to.not.fall.back.to.vim.filetype.match'] = { glyph = 'E' },\n      ['complex.extension.two.which.user.configured.to.not.fall.back.to.vim.filetype.match'] = { glyph = 'e' },\n    },\n    file = { ['complex.file.name.which.user.configured.to.not.fall.back.to.vim.filetype.match'] = { glyph = 'C' } },\n  })\n\n  local durations = child.lua([[\n    local bench = function(category, name)\n      local start_time = vim.loop.hrtime()\n      MiniIcons.get(category, name)\n      return vim.loop.hrtime() - start_time\n    end\n\n    local ext_fallback = bench('extension', 'not-supported-extension')\n    local ext_ext = bench('extension', 'complex.extension.which.user.configured.to.not.fall.back.to.vim.filetype.match')\n\n    local file_fallback = bench('file', 'not-supported-file')\n    local file_file = bench('file', 'complex.file.name.which.user.configured.to.not.fall.back.to.vim.filetype.match')\n    local file_ext = bench('file', 'FILENAME.complex.extension.two.which.user.configured.to.not.fall.back.to.vim.filetype.match')\n\n    return {\n      ext_fallback = ext_fallback,\n      ext_ext = ext_ext,\n\n      file_fallback = file_fallback,\n      file_file = file_file,\n      file_ext = file_ext,\n    }\n  ]])\n\n  eq(durations.ext_ext < 0.1 * durations.ext_fallback, true)\n  eq(durations.file_file < 0.1 * durations.file_fallback, true)\n  eq(durations.file_ext < 0.1 * durations.file_fallback, true)\nend\n\nT['get()']['respects `config.style`'] = function()\n  load_module({\n    style = 'ascii',\n    default = { file = { glyph = '󱁂' } },\n    extension = { myext = { glyph = '󰻲', hl = 'MiniIconsRed' } },\n  })\n\n  -- ASCII style is upper variant of the first byte of the resolved name\n  eq(get('default', 'directory'), { 'D', 'MiniIconsAzure', false })\n\n  -- - 'init.lua' is explicitly tracked\n  eq(get('file', 'init.lua'), { 'I', 'MiniIconsGreen', false })\n  -- - 'hello.lua' is resolved to use \"lua\" extension\n  eq(get('file', 'hello.lua'), { 'L', 'MiniIconsAzure', false })\n  -- - 'Cargo.lock' is resolved to use \"toml\" filetype\n  eq(get('file', 'Cargo.lock'), { 'T', 'MiniIconsOrange', false })\n  -- - 'not-supported' is resolved to use \"file\" default\n  eq(get('file', 'not-supported'), { 'F', 'MiniIconsGrey', true })\n\n  -- Should work with full paths\n  eq(get('file', '/home/user/LICENSE'), { 'L', 'MiniIconsCyan', false })\n  eq(get('file', '/home/user/world.lua'), { 'L', 'MiniIconsAzure', false })\n  eq(get('file', '/home/user/Cargo.lock'), { 'T', 'MiniIconsOrange', false })\n  eq(get('file', '/home/user/not-supported-2'), { 'F', 'MiniIconsGrey', true })\n\n  -- Should work with all categories\n  eq(get('default', 'lsp')[1], 'L')\n  eq(get('directory', 'nvim')[1], 'N')\n  eq(get('extension', 'lua')[1], 'L')\n  eq(get('filetype', 'help')[1], 'H')\n  eq(get('lsp', 'array')[1], 'A')\n  eq(get('os', 'arch')[1], 'A')\n\n  -- Should work with customized icons\n  eq(get('default', 'directory')[1], 'D')\n  eq(get('extension', 'myext')[1], 'M')\n  eq(get('file', 'hello.myext')[1], 'M')\n\n  -- Should properly return if output is fallback (even if icons are the same)\n  eq(get('directory', 'dir-not-supported'), { 'D', 'MiniIconsAzure', true })\n  eq(get('extension', 'ext-not-supported'), { 'E', 'MiniIconsGrey', true })\n  eq(get('file', 'file-not-supported'), { 'F', 'MiniIconsGrey', true })\n  eq(get('filetype', 'filetype-not-supported'), { 'F', 'MiniIconsGrey', true })\n  eq(get('lsp', 'lsp-not-supported'), { 'L', 'MiniIconsRed', true })\n  eq(get('os', 'os-not-supported'), { 'O', 'MiniIconsPurple', true })\nend\n\nT['get()']['respects multibyte characters with \"ascii\" style'] = function()\n  load_module({\n    style = 'ascii',\n    directory = { ['й_dir'] = { glyph = 'M' } },\n    extension = { ['й_ext'] = { glyph = 'M' } },\n    file = { ['й_file'] = { glyph = 'M' } },\n    filetype = { ['й_filetype'] = { glyph = 'M' } },\n    lsp = { ['й_lsp'] = { glyph = 'M' } },\n    os = { ['й_os'] = { glyph = 'M' } },\n  })\n\n  -- Currently matched without making  it upper case to save speed for\n  -- overwhelmingly common single byte case (because `vim.fn.toupper()` is\n  -- *much* slower than `string.upper()`)\n  eq(get('directory', 'й_dir')[1], 'Й')\n  eq(get('extension', 'й_ext')[1], 'Й')\n  eq(get('file', 'й_file')[1], 'Й')\n  eq(get('filetype', 'й_filetype')[1], 'Й')\n  eq(get('lsp', 'й_lsp')[1], 'Й')\n  eq(get('os', 'й_os')[1], 'Й')\n\n  -- Default stil should match with category's first letter\n  eq(get('directory', 'й_default_dir')[1], 'D')\n  eq(get('extension', 'й_default_ext')[1], 'E')\n  eq(get('file', 'й_default_file')[1], 'F')\n  eq(get('filetype', 'й_default_filetype')[1], 'F')\n  eq(get('lsp', 'й_default_lsp')[1], 'L')\n  eq(get('os', 'й_default_os')[1], 'O')\nend\n\nT['get()']['respects customizations in config'] = function()\n  load_module({\n    default = { directory = { glyph = '󱁂', hl = 'Directory' } },\n    directory = { mydir = { glyph = 'A', hl = 'Comment' } },\n    extension = { myext = { glyph = 'B' } },\n    file = { myfile = { hl = 'String' } },\n    filetype = { myfiletype = { glyph = 'D' } },\n    lsp = { mylsp = { glyph = 'E' } },\n    os = { myos = { glyph = 'F' } },\n  })\n\n  eq(get('default', 'directory'), { '󱁂', 'Directory', false })\n  eq(get('directory', 'mydir'), { 'A', 'Comment', false })\n  eq(get('extension', 'myext'), { 'B', 'MiniIconsGrey', false })\n  eq(get('file', 'myfile'), { '󰈔', 'String', false })\n  eq(get('filetype', 'myfiletype'), { 'D', 'MiniIconsGrey', false })\n  eq(get('lsp', 'mylsp'), { 'E', 'MiniIconsRed', false })\n  eq(get('os', 'myos'), { 'F', 'MiniIconsPurple', false })\nend\n\nT['get()']['handles different casing'] = function()\n  load_module({\n    directory = { mydir = { glyph = 'A' } },\n    extension = { myext = { glyph = 'B' } },\n    file = { myfile = { glyph = 'C' } },\n    filetype = { myfiletype = { glyph = 'D' } },\n    lsp = { mylsp = { glyph = 'E' } },\n    os = { myos = { glyph = 'F' } },\n  })\n\n  -- Should match exactly for \"file\" and \"directory\"\n  no_eq(get('directory', 'nvim'), get('directory', 'Nvim'))\n  no_eq(get('directory', 'mydir'), get('directory', 'MyDir'))\n\n  -- - 'Cargo.lock' is matched as 'toml' in `vim.filetype.match()`\n  no_eq(get('file', 'Cargo.lock'), get('file', 'cargo.lock'))\n  no_eq(get('file', 'myfile'), get('file', 'MyFile'))\n\n  -- Others - ignoring case\n  eq(get('default', 'file'), get('default', 'FILE'))\n\n  eq(get('extension', 'lua'), get('extension', 'LUA'))\n  eq(get('file', 'hello.R'), get('file', 'hello.r'))\n\n  eq(get('extension', 'MyExT')[1], 'B')\n  eq(get('file', 'hello.MyExT')[1], 'B')\n\n  eq(get('filetype', 'help'), get('filetype', 'Help'))\n  eq(get('filetype', 'myfiletype'), get('filetype', 'MyFileType'))\n\n  eq(get('lsp', 'array'), get('lsp', 'Array'))\n  eq(get('lsp', 'mylsp'), get('lsp', 'MyLsp'))\n\n  eq(get('os', 'arch'), get('os', 'Arch'))\n  eq(get('os', 'myos'), get('os', 'MyOs'))\nend\n\nT['get()']['can be used without `setup()`'] = function()\n  unload_module()\n  eq(child.lua_get('{ require(\"mini.icons\").get(\"default\", \"file\") }'), { '󰈔', 'MiniIconsGrey', false })\nend\n\nT['get()']['can be used after deleting all buffers'] = function()\n  -- As `vim.filetype.match()` requries a buffer to be more useful, make sure\n  -- that this cached buffer is persistent\n  eq(get('file', 'hello.xpm'), { '󰍹', 'MiniIconsYellow', false })\n  -- The helper scratch buffer should be properly named\n  eq(child.api.nvim_buf_get_name(2), 'miniicons://2/filetype-match-scratch')\n\n  child.cmd('%bwipeout')\n  eq(get('file', 'hello.tcsh'), { '', 'MiniIconsAzure', false })\n  eq(child.api.nvim_buf_get_name(3), 'miniicons://3/filetype-match-scratch')\nend\n\nT['get()']['uses width one glyphs'] = function()\n  local bad_glyphs = {}\n  for _, cat in ipairs(list('default')) do\n    for _, name in ipairs(list(cat)) do\n      local icon = get(cat, name)[1]\n      if vim.fn.strdisplaywidth(icon) > 1 then table.insert(bad_glyphs, { cat, name, icon }) end\n    end\n  end\n  eq(bad_glyphs, {})\nend\n\nT['get()']['validates arguments'] = function()\n  expect.error(function() get(1, 'lua') end, 'category.*string')\n  expect.error(function() get('file', 1) end, 'name.*string')\n\n  expect.error(function() get('aaa', 'lua') end, 'aaa.*not.*category')\nend\n\nT['list()'] = new_set()\n\nT['list()']['works'] = function()\n  local islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n  local validate = function(category, ref_present_entry)\n    local res = list(category)\n    eq(islist(res), true)\n    eq(vim.tbl_contains(res, ref_present_entry), true)\n  end\n\n  eq(list('default'), { 'default', 'directory', 'extension', 'file', 'filetype', 'lsp', 'os' })\n  validate('directory', 'nvim')\n  validate('extension', 'h')\n  validate('file', 'init.lua')\n  validate('filetype', 'lua')\n  validate('lsp', 'array')\n  validate('os', 'arch')\n\n  -- Should not add cached but not explicitly supported items\n  local validate_no = function(category, name)\n    get(category, name)\n    eq(vim.tbl_contains(list(category), name), false)\n  end\n\n  validate_no('directory', 'mydir')\n  validate_no('extension', 'myext')\n  validate_no('file', 'myfile')\n  validate_no('filetype', 'myfiletype')\n  validate_no('lsp', 'mylsp')\n  validate_no('os', 'myos')\nend\n\nT['list()']['uses lowercase icon names for categories which ignore case'] = function()\n  -- Otherwise `get()` will not match names with uppercase letter\n  local validate = function(category)\n    local not_lowercase = vim.tbl_filter(function(name) return name ~= name:lower() end, list(category))\n    eq(not_lowercase, {})\n  end\n  validate('default')\n  validate('extension')\n  validate('filetype')\n  validate('lsp')\n  validate('os')\nend\n\nT['list()']['validates arguments'] = function()\n  expect.error(function() list(1) end, '1.*not.*category')\n  expect.error(function() list('aaa') end, 'aaa.*not.*category')\nend\n\nT['mock_nvim_web_devicons()'] = new_set()\n\nT['mock_nvim_web_devicons()']['works'] = function()\n  load_module({\n    default = {\n      file = { glyph = 'f', hl = 'Comment' },\n      filetype = { glyph = 't', hl = 'Comment' },\n      extension = { glyph = 'e', hl = 'Comment' },\n    },\n    extension = { myext = { glyph = 'E', hl = 'Constant' } },\n    file = { myfile = { glyph = 'F', hl = 'String' } },\n    filetype = { myfiletype = { glyph = 'T', hl = 'Special' } },\n    os = { myos = { glyph = 'O', hl = 'Delimiter' } },\n  })\n  child.api.nvim_set_hl(0, 'Comment', { fg = '#aaaaaa', ctermfg = 248 })\n  child.api.nvim_set_hl(0, 'Constant', { fg = '#e0e060', ctermfg = 185 })\n  child.api.nvim_set_hl(0, 'String', { fg = '#60e060', ctermfg = 77 })\n  child.api.nvim_set_hl(0, 'Special', { fg = '#e060e0', ctermfg = 170 })\n  child.api.nvim_set_hl(0, 'Delimiter', { fg = '#60e0e0', ctermfg = 80 })\n\n  expect.error(function() child.lua('require(\"nvim-web-devicons\")') end, 'nvim%-web%-devicons.*not found')\n  child.lua('MiniIcons.mock_nvim_web_devicons()')\n  expect.no_error(function() child.lua('require(\"nvim-web-devicons\")') end)\n\n  child.lua('_G.devicons = require(\"nvim-web-devicons\")')\n\n  -- Should reasonable mock at least common functions which return something\n  eq(child.lua_get('{ devicons.get_icon(\"init.lua\", nil) }'), { '', 'MiniIconsGreen' })\n  eq(child.lua_get('{ devicons.get_icon(nil, \"lua\") }'), { '󰢱', 'MiniIconsAzure' })\n  eq(child.lua_get('{ devicons.get_icon(\"hello.py\", \"lua\", {}) }'), { '󰌠', 'MiniIconsYellow' })\n  eq(child.lua_get('{ devicons.get_icon(\"init.lua\", \"lua\", {}) }'), { '', 'MiniIconsGreen' })\n  eq(child.lua_get('{ devicons.get_icon(\"xxx\", nil, {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon(nil, \"xxx\", {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon(\"xxx\", nil, { default = true }) }'), { 'f', 'Comment' })\n  eq(child.lua_get('{ devicons.get_icon(nil, \"xxx\", { default = true }) }'), { 'e', 'Comment' })\n  expect.error(function() child.lua('devicons.get_icon(1, nil, {})') end)\n  expect.error(function() child.lua('devicons.get_icon(nil, 1, {})') end)\n\n  local get_icon_by_filetype = function(...) return child.lua_get('{ devicons.get_icon_by_filetype(...) }', { ... }) end\n  eq(get_icon_by_filetype('help', {}), { '󰋖', 'MiniIconsPurple' })\n  eq(get_icon_by_filetype('xxx', {}), {})\n  eq(get_icon_by_filetype('xxx', { default = true }), { 't', 'Comment' })\n\n  eq(child.lua_get('{ devicons.get_icon_color(\"myfile\", nil, {}) }'), { 'F', '#60e060' })\n  eq(child.lua_get('{ devicons.get_icon_color(\"xxx\", nil, {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon_color(\"xxx\", nil, { default = true }) }'), { 'f', '#aaaaaa' })\n\n  eq(child.lua_get('{ devicons.get_icon_cterm_color(\"myfile\", nil, {}) }'), { 'F', 77 })\n  eq(child.lua_get('{ devicons.get_icon_cterm_color(\"xxx\", nil, {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon_cterm_color(\"xxx\", nil, { default = true }) }'), { 'f', 248 })\n\n  eq(child.lua_get('{ devicons.get_icon_colors(\"myfile\", nil, {}) }'), { 'F', '#60e060', 77 })\n  eq(child.lua_get('{ devicons.get_icon_colors(\"xxx\", nil, {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon_colors(\"xxx\", nil, { default = true }) }'), { 'f', '#aaaaaa', 248 })\n\n  eq(child.lua_get('{ devicons.get_icon_color_by_filetype(\"myfiletype\", {}) }'), { 'T', '#e060e0' })\n  eq(child.lua_get('{ devicons.get_icon_color_by_filetype(\"xxx\", {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon_color_by_filetype(\"xxx\", { default = true }) }'), { 't', '#aaaaaa' })\n\n  eq(child.lua_get('{ devicons.get_icon_cterm_color_by_filetype(\"myfiletype\", {}) }'), { 'T', 170 })\n  eq(child.lua_get('{ devicons.get_icon_cterm_color_by_filetype(\"xxx\", {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon_cterm_color_by_filetype(\"xxx\", { default = true }) }'), { 't', 248 })\n\n  eq(child.lua_get('{ devicons.get_icon_colors_by_filetype(\"myfiletype\", {}) }'), { 'T', '#e060e0', 170 })\n  eq(child.lua_get('{ devicons.get_icon_colors_by_filetype(\"xxx\", {}) }'), {})\n  eq(child.lua_get('{ devicons.get_icon_colors_by_filetype(\"xxx\", { default = true }) }'), { 't', '#aaaaaa', 248 })\n\n  eq(child.lua_get('devicons.get_icon_name_by_filetype(\"myfiletype\")'), 'myfiletype')\n\n  local ref_default_icon = { color = '#aaaaaa', cterm_color = '248', icon = 'f', name = 'Default' }\n  eq(child.lua_get('devicons.get_default_icon()'), ref_default_icon)\n\n  local ref_all = {\n    default = ref_default_icon,\n    myext = { color = '#e0e060', cterm_color = '185', icon = 'E', name = 'myext' },\n    myfile = { color = '#60e060', cterm_color = '77', icon = 'F', name = 'myfile' },\n    myos = { color = '#60e0e0', cterm_color = '80', icon = 'O', name = 'myos' },\n  }\n  local out_all = child.lua([[\n    local t = devicons.get_icons()\n    return {\n      default = t[1],\n      myext = t.myext,\n      myfile = t.myfile,\n      myos = t.myos,\n      -- Should not be present, i.e. should be `nil`\n      myfiletype = t.myfiletype,\n    }\n  ]])\n  eq(out_all, ref_all)\n\n  eq(child.lua_get('devicons.get_icons_by_desktop_environment()'), {})\n  eq(child.lua_get('{ myext = devicons.get_icons_by_extension().myext }'), { myext = ref_all.myext })\n  eq(child.lua_get('{ myfile = devicons.get_icons_by_filename().myfile }'), { myfile = ref_all.myfile })\n  eq(child.lua_get('{ myos = devicons.get_icons_by_operating_system().myos }'), { myos = ref_all.myos })\n  eq(child.lua_get('devicons.get_icons_by_window_manager()'), {})\n\n  -- Should have others at least present\n  local present =\n    { 'has_loaded', 'refresh', 'set_default_icon', 'set_icon', 'set_icon_by_filetype', 'set_up_highlights', 'setup' }\n  for _, method in ipairs(present) do\n    eq(child.lua_get('type(devicons.' .. method .. ')'), 'function')\n  end\n\n  -- Should set global variable which is set in 'plugin/nvim-web-devicons.vim'\n  eq(child.g.nvim_web_devicons, 1)\nend\n\nT['tweak_lsp_kind()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua([[MiniIcons.setup({\n        default = { lsp = { glyph = 'L' } },\n        lsp = {\n          text = { glyph = 'T' },\n          file = { glyph = 'F' },\n          somethingnew = { glyph = 'S' },\n        }\n      })]])\n    end,\n  },\n})\n\nlocal setup_lsp_protocol = function()\n  child.lua([[\n    vim.lsp.protocol = {\n      CompletionItemKind = {\n        [1] = 'Text',         Text = 1,\n        [2] = 'Method',       Method = 2,\n        [3] = 'SomethingNew', SomethingNew = 3,\n        [4] = 'Fallback',     Fallback = 4,\n      },\n      SymbolKind = {\n        [1] = 'File',         File = 1,\n        [2] = 'Module',       Module = 2,\n        [3] = 'SomethingNew', SomethingNew = 3,\n        [4] = 'Fallback',     Fallback = 4,\n      },\n    }\n  ]])\n  return {\n    CompletionItemKind = { Text = 1, Method = 2, SomethingNew = 3, Fallback = 4 },\n    SymbolKind = { File = 1, Module = 2, SomethingNew = 3, Fallback = 4 },\n  }\nend\n\nlocal validate_lsp_protocol = function(mode, field, ref_arr)\n  local init_map = setup_lsp_protocol()\n  child.lua('MiniIcons.tweak_lsp_kind(...)', { mode })\n\n  child.lua('_G.tbl = vim.lsp.protocol.' .. field)\n  child.lua([=[\n    _G.arr, _G.map = {}, {}\n    for k, v in pairs(_G.tbl) do\n      if type(k) == 'number' then _G.arr[k] = v else _G.map[k] = v end\n    end\n    ]=])\n\n  -- Should modify only \"array\" part (i.e. only \"number -> kind\" map) in order\n  -- to preserve original info\n  eq(child.lua_get('_G.arr'), ref_arr)\n  eq(child.lua_get('_G.map'), init_map[field])\nend\n\nT['tweak_lsp_kind()']['works'] = function()\n  -- By default should prepend icon\n  validate_lsp_protocol(nil, 'CompletionItemKind', { 'T Text', ' Method', 'S SomethingNew', 'L Fallback' })\n  validate_lsp_protocol(nil, 'SymbolKind', { 'F File', ' Module', 'S SomethingNew', 'L Fallback' })\nend\n\nT['tweak_lsp_kind()']['respects `mode` argument'] = function()\n  validate_lsp_protocol('append', 'CompletionItemKind', { 'Text T', 'Method ', 'SomethingNew S', 'Fallback L' })\n  validate_lsp_protocol('append', 'SymbolKind', { 'File F', 'Module ', 'SomethingNew S', 'Fallback L' })\n\n  validate_lsp_protocol('prepend', 'CompletionItemKind', { 'T Text', ' Method', 'S SomethingNew', 'L Fallback' })\n  validate_lsp_protocol('prepend', 'SymbolKind', { 'F File', ' Module', 'S SomethingNew', 'L Fallback' })\n\n  validate_lsp_protocol('replace', 'CompletionItemKind', { 'T', '', 'S', 'L' })\n  validate_lsp_protocol('replace', 'SymbolKind', { 'F', '', 'S', 'L' })\nend\n\nT['tweak_lsp_kind()']['validates arguments'] = function()\n  expect.error(function() child.lua('MiniIcons.tweak_lsp_kind(\"aa\")') end, '`mode`.*one of')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_indentscope.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('indentscope', config) end\nlocal unload_module = function() child.mini_unload('indentscope') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\n--stylua: ignore end\n\n-- Data =======================================================================\n-- Reference text\n-- aa\n--\n--     aa\n--\n--     aa\n--\n--   aa\nlocal example_lines = {\n  'aa',\n  '',\n  '    aa',\n  '',\n  '    aa',\n  '',\n  '  aa',\n}\n\n-- Reference text\n-- aa\n--  aa\n--   aa\n--    aa\n--    aa\n--    aa\n--   aa\n--  aa\n-- aa\nlocal example_lines_nested = { 'aa', ' aa', '  aa', '   aa', '   aa', '   aa', '  aa', ' aa', 'aa' }\n\n-- Time constants\nlocal default_draw_delay = 100\nlocal default_animation_step = 20\nlocal small_time = helpers.get_time_const(10)\nlocal micro_time = 1\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniIndentscope)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniIndentscope'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniIndentscopeSymbol'), 'links to Delimiter')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniIndentscope.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniIndentscope.config.' .. field), value) end\n\n  expect_config('draw.delay', 100)\n  eq(child.lua_get('type(_G.MiniIndentscope.config.draw.animation)'), 'function')\n  eq(child.lua_get('type(_G.MiniIndentscope.config.draw.predicate)'), 'function')\n  expect_config('draw.priority', 2)\n  expect_config('mappings.goto_bottom', ']i')\n  expect_config('mappings.goto_top', '[i')\n  expect_config('mappings.object_scope', 'ii')\n  expect_config('mappings.object_scope_with_border', 'ai')\n  expect_config('options.border', 'both')\n  expect_config('options.indent_at_cursor', true)\n  expect_config('options.n_lines', 10000)\n  expect_config('options.try_as_border', false)\n  expect_config('symbol', '╎')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ symbol = 'a' })\n  eq(child.lua_get('MiniIndentscope.config.symbol'), 'a')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ draw = 'a' }, 'draw', 'table')\n  expect_config_error({ draw = { delay = 'a' } }, 'draw.delay', 'number')\n  expect_config_error({ draw = { animation = 'a' } }, 'draw.animation', 'function')\n  expect_config_error({ draw = { predicate = 'a' } }, 'draw.predicate', 'function')\n  expect_config_error({ draw = { priority = 'a' } }, 'draw.priority', 'number')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { object_scope = 1 } }, 'mappings.object_scope', 'string')\n  expect_config_error({ mappings = { object_scope_with_border = 1 } }, 'mappings.object_scope_with_border', 'string')\n  expect_config_error({ mappings = { goto_top = 1 } }, 'mappings.goto_top', 'string')\n  expect_config_error({ mappings = { goto_bottom = 1 } }, 'mappings.goto_bottom', 'string')\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { border = 1 } }, 'options.border', 'string')\n  expect_config_error({ options = { indent_at_cursor = 1 } }, 'options.indent_at_cursor', 'boolean')\n  expect_config_error({ options = { n_lines = 'a' } }, 'options.n_lines', 'number')\n  expect_config_error({ options = { try_as_border = 1 } }, 'options.try_as_border', 'boolean')\n  expect_config_error({ symbol = 1 }, 'symbol', 'string')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('nmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('[i', 'indent scope'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('n', '[i')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { goto_top = '' } })\n  eq(has_map('[i', 'indent scope'), false)\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniIndentscopeSymbol'), 'links to Delimiter')\nend\n\nT['get_scope()'] = new_set({\n  hooks = {\n    pre_case = function() set_lines(example_lines) end,\n  },\n})\n\nlocal get_scope = function(...) return child.lua_get('MiniIndentscope.get_scope(...)', { ... }) end\nlocal get_cursor_scope = function(opts) return child.lua_get('MiniIndentscope.get_scope(nil, nil, ...)', { opts }) end\n\nT['get_scope()']['returns correct structure'] = function()\n  set_cursor(3, 4)\n  eq(get_scope(), {\n    body = { top = 2, bottom = 6, indent = 4 },\n    border = { top = 1, bottom = 7, indent = 2 },\n    buf_id = child.api.nvim_win_get_buf(0),\n    reference = { line = 3, column = 5, indent = 4 },\n  })\nend\n\nT['get_scope()']['uses \"indent at cursor\" by default'] = function()\n  set_cursor(3, 0)\n  eq(get_scope().reference.indent, 1)\nend\n\nT['get_scope()']['respects `line` and `col` arguments'] = function()\n  set_cursor(3, 4)\n  local scope_from_cursor = get_scope()\n  set_cursor(1, 0)\n  local scope_from_args = get_scope(3, 5)\n  eq(scope_from_cursor, scope_from_args)\nend\n\nT['get_scope()']['respects `opts.border`'] = function()\n  set_cursor(3, 4)\n\n  local scope_both = get_cursor_scope({ border = 'both' })\n  eq(scope_both.body, { top = 2, bottom = 6, indent = 4 })\n  eq(scope_both.border, { top = 1, bottom = 7, indent = 2 })\n\n  local scope_bottom = get_cursor_scope({ border = 'bottom' })\n  eq(scope_bottom.body, { top = 3, bottom = 6, indent = 4 })\n  eq(scope_bottom.border, { bottom = 7, indent = 2 })\n\n  local scope_top = get_cursor_scope({ border = 'top' })\n  eq(scope_top.body, { top = 2, bottom = 5, indent = 4 })\n  eq(scope_top.border, { top = 1, indent = 0 })\n\n  local scope_none = get_cursor_scope({ border = 'none' })\n  eq(scope_none.body, { top = 3, bottom = 5, indent = 4 })\n  eq(scope_none.border, {})\nend\n\nT['get_scope()']['respects `opts.indent_at_cursor`'] = function()\n  set_cursor(3, 1)\n  eq(get_cursor_scope({ indent_at_cursor = false }), get_scope(3, math.huge))\nend\n\nT['get_scope()']['respects `opts.n_lines`'] = function()\n  set_lines({ 'aa', '  bb', '  bb', '  bb', '  bb', '  bb', 'aa' })\n  local scope = get_scope(4, 1, { n_lines = 1 })\n  eq(scope.body, { top = 3, bottom = 5, is_incomplete = true, indent = 2 })\n  eq(scope.border, { top = 2, bottom = 6, indent = 2 })\n\n  -- Should still set `is_incomplete` even if only one side is incomplete\n  eq(get_scope(2, 1, { n_lines = 2 }).body, { top = 2, bottom = 4, is_incomplete = true, indent = 2 })\n  eq(get_scope(6, 1, { n_lines = 2 }).body, { top = 4, bottom = 6, is_incomplete = true, indent = 2 })\n\n  -- Setting `math.huge` should be allowed\n  local many_lines = { 'aa' }\n  for _ = 1, 10002 do\n    table.insert(many_lines, '  bb')\n  end\n  table.insert(many_lines, 'aa')\n  set_lines(many_lines)\n\n  eq(get_scope(2, 1).body, { top = 2, bottom = 10002, is_incomplete = true, indent = 2 })\n  eq(get_scope(2, 1, { n_lines = math.huge }).body, { top = 2, bottom = 10003, indent = 2 })\n\n  child.lua('MiniIndentscope.config.options.n_lines = math.huge')\n  eq(get_scope(2, 1).body, { top = 2, bottom = 10003, indent = 2 })\n\n  -- Default value should be taken from `config.options.n_lines`\n  child.lua('MiniIndentscope.config.options.n_lines = 2')\n  eq(get_scope(2, 1).body, { top = 2, bottom = 4, is_incomplete = true, indent = 2 })\n\n  child.b.miniindentscope_config = { options = { n_lines = 3 } }\n  eq(get_scope(2, 1).body, { top = 2, bottom = 5, is_incomplete = true, indent = 2 })\nend\n\nT['get_scope()']['respects `opts.try_as_border`'] = function()\n  -- Border should be recognized only if `opts.border` is appropriate\n  set_cursor(1, 0)\n  eq(get_cursor_scope({ border = 'both', try_as_border = true }).body.top, 2)\n  eq(get_cursor_scope({ border = 'bottom', try_as_border = true }).body.top, 1)\n  eq(get_cursor_scope({ border = 'top', try_as_border = true }).body.top, 2)\n  eq(get_cursor_scope({ border = 'none', try_as_border = true }).body.top, 1)\n\n  set_cursor(7, 2)\n  eq(get_cursor_scope({ border = 'both', try_as_border = true }).body.bottom, 6)\n  eq(get_cursor_scope({ border = 'bottom', try_as_border = true }).body.bottom, 6)\n  eq(get_cursor_scope({ border = 'top', try_as_border = true }).body.bottom, 7)\n  eq(get_cursor_scope({ border = 'none', try_as_border = true }).body.bottom, 7)\n\n  -- If ambiguous, prefer next scope\n  set_lines({ '  aa', 'aa', '  aa' })\n  set_cursor(2, 1)\n  eq(get_cursor_scope({ border = 'both', try_as_border = true }).body, { top = 3, bottom = 3, indent = 2 })\nend\n\nT['get_scope()']['works on empty lines'] = function()\n  -- By default it should result in reference indent as if from previous\n  -- non-blank line\n  set_cursor(3, 4)\n  local scope_nonblank = get_scope()\n  child.cmd('normal! j')\n  local scope_blank = get_scope()\n  eq(scope_blank.reference.indent, scope_nonblank.reference.indent)\n  eq(scope_blank.body, scope_nonblank.body)\nend\n\nT['get_scope()']['uses correct config source'] = function()\n  set_cursor(3, 4)\n\n  -- Global > buffer-local > argument\n  child.lua([[MiniIndentscope.config.options.border = 'bottom']])\n  eq(get_cursor_scope().border, { top = nil, bottom = 7, indent = 2 })\n\n  child.b.miniindentscope_config = { options = { border = 'top' } }\n  eq(get_cursor_scope().border, { top = 1, bottom = nil, indent = 0 })\n\n  eq(get_cursor_scope({ border = 'none' }).border, {})\nend\n\nT['gen_animation'] = new_set()\n\nlocal expect_animation = function(family, target, opts, tolerance)\n  opts = opts or {}\n  tolerance = tolerance or 0.1\n  local lua_cmd = string.format('_G.f = MiniIndentscope.gen_animation.%s(...)', family)\n  child.lua(lua_cmd, { opts })\n\n  local f = function(...) return child.lua_get('_G.f(...)', { ... }) end\n  for i, _ in ipairs(target) do\n    -- Expect approximate equality\n    eq(math.abs(f(i, #target) - target[i]) <= tolerance, true)\n  end\n\n  child.lua('_G.f = nil')\nend\n\n--stylua: ignore\nT['gen_animation']['respects `opts.easing` argument'] = function()\n  expect_animation('none',        { 0,    0,    0,    0,    0 })\n  expect_animation('linear',      { 20,   20,   20,   20,   20 })\n  expect_animation('quadratic',   { 33.3, 26.7, 20,   13.3, 6.7 },  { easing = 'in' })\n  expect_animation('quadratic',   { 6.7,  13.3, 20,   26.7, 33.3 }, { easing = 'out' })\n  expect_animation('quadratic',   { 27.3, 18.2, 9,    18.2, 27.3 }, { easing = 'in-out' })\n  expect_animation('cubic',       { 45.5, 29.1, 16.4, 7.2,  1.8 },  { easing = 'in' })\n  expect_animation('cubic',       { 1.8,  7.2,  16.4, 29.1, 45.5 }, { easing = 'out' })\n  expect_animation('cubic',       { 33.3, 14.8, 3.8,  14.8, 33.3 }, { easing = 'in-out' })\n  expect_animation('quartic',     { 55.5, 28.5, 12,   3.5,  0.5 },  { easing = 'in' })\n  expect_animation('quartic',     { 0.5,  3.5,  12,   28.5, 55.5 }, { easing = 'out' })\n  expect_animation('quartic',     { 38,   11.3, 1.4,  11.3, 38 },   { easing = 'in-out' })\n  expect_animation('exponential', { 60.9, 24.2, 9.6,  3.8,  1.5 },  { easing = 'in' })\n  expect_animation('exponential', { 1.5,  3.8,  9.6,  24.2, 60.9 }, { easing = 'out' })\n  expect_animation('exponential', { 38.4, 10.2, 2.8,  10.2, 38.4 }, { easing = 'in-out' })\n\n  -- 'in-out' variants should be always symmetrical\n  expect_animation('quadratic',   { 30,   20,   10,  10,  20,   30 },   { easing = 'in-out' })\n  expect_animation('cubic',       { 38.6, 17.1, 4.3, 4.3, 17.1, 38.6 }, { easing = 'in-out' })\n  expect_animation('quartic',     { 45,   13.3, 1.7, 1.7, 13.3, 45 },   { easing = 'in-out' })\n  expect_animation('exponential', { 45.5, 11.6, 2.9, 2.9, 11.6, 45.5 }, { easing = 'in-out' })\nend\n\nT['gen_animation']['respects `opts` other arguments'] = function()\n  expect_animation('linear', { 10, 10 }, { unit = 'total' })\n  expect_animation('linear', { 100, 100 }, { duration = 100 })\n  expect_animation('linear', { 50, 50 }, { unit = 'total', duration = 100 })\nend\n\nT['gen_animation']['validates `opts` values'] = function()\n  local validate = function(opts, err_pattern)\n    expect.error(function() child.lua('MiniIndentscope.gen_animation.linear(...)', { opts }) end, err_pattern)\n  end\n\n  validate({ easing = 'a' }, 'one of')\n  validate({ duration = 'a' }, 'number')\n  validate({ duration = -1 }, 'positive')\n  validate({ unit = 'a' }, 'one of')\nend\n\n--stylua: ignore\nT['gen_animation']['handles `n_steps=1` for all progression families and `opts.easing`'] = function()\n  expect_animation('none',        { 0 })\n  expect_animation('linear',      { 20 })\n  expect_animation('quadratic',   { 20 }, { easing = 'in' })\n  expect_animation('quadratic',   { 20 }, { easing = 'out' })\n  expect_animation('quadratic',   { 20 }, { easing = 'in-out' })\n  expect_animation('cubic',       { 20 }, { easing = 'in' })\n  expect_animation('cubic',       { 20 }, { easing = 'out' })\n  expect_animation('cubic',       { 20 }, { easing = 'in-out' })\n  expect_animation('quartic',     { 20 }, { easing = 'in' })\n  expect_animation('quartic',     { 20 }, { easing = 'out' })\n  expect_animation('quartic',     { 20 }, { easing = 'in-out' })\n  expect_animation('exponential', { 20 }, { easing = 'in' })\n  expect_animation('exponential', { 20 }, { easing = 'out' })\n  expect_animation('exponential', { 20 }, { easing = 'in-out' })\nend\n\nT['move_cursor()'] = new_set({\n  hooks = {\n    pre_case = function() set_lines(example_lines_nested) end,\n  },\n})\n\nlocal move_cursor = function(...) child.lua('MiniIndentscope.move_cursor(...)', { ... }) end\n\nT['move_cursor()']['works'] = function()\n  set_cursor(5, 4)\n  move_cursor('top')\n  eq(get_cursor(), { 4, 3 })\n\n  set_cursor(5, 4)\n  move_cursor('bottom')\n  eq(get_cursor(), { 6, 3 })\nend\n\nT['move_cursor()']['respects `use_border` argument'] = function()\n  set_cursor(5, 4)\n  move_cursor('top', true)\n  eq(get_cursor(), { 3, 2 })\n\n  set_cursor(5, 4)\n  move_cursor('bottom', true)\n  eq(get_cursor(), { 7, 2 })\nend\n\nT['move_cursor()']['respects `scope` argument'] = function()\n  set_cursor(2, 1)\n  local scope = child.lua_get('MiniIndentscope.get_scope()')\n\n  set_cursor(5, 4)\n  move_cursor('top', false, scope)\n  eq(get_cursor(), { 2, 1 })\n\n  set_cursor(5, 4)\n  move_cursor('bottom', false, scope)\n  eq(get_cursor(), { 8, 1 })\nend\n\nT['move_cursor()']['handles moving to \"out of buffer\" border lines'] = function()\n  set_cursor(1, 1)\n  move_cursor('top', true)\n  eq(get_cursor(), { 1, 0 })\n\n  set_cursor(1, 1)\n  move_cursor('bottom', true)\n  eq(get_cursor(), { 9, 0 })\nend\n\n-- Integration tests ==========================================================\nT['draw()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Virtually disable autodrawing\n      child.lua('MiniIndentscope.config.draw.delay = 100000')\n      set_lines(example_lines_nested)\n      child.set_size(15, 12)\n    end,\n  },\n})\n\nT['draw()']['works'] = function()\n  set_cursor(6, 1)\n  child.lua('MiniIndentscope.draw()')\n\n  -- Should be single symbol at cursor line\n  child.expect_screenshot()\n\n  sleep(default_animation_step)\n  child.expect_screenshot()\n  sleep(default_animation_step)\n  child.expect_screenshot()\n  sleep(default_animation_step)\n  child.expect_screenshot()\nend\n\nlocal validate_hl_group = function(hl_group)\n  local ns_id = child.api.nvim_get_namespaces()['MiniIndentscope']\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n\n  local all_correct_hl_group = true\n  for _, e_mark in ipairs(extmarks) do\n    if e_mark[4].virt_text[1][2] ~= hl_group then all_correct_hl_group = false end\n  end\n\n  eq(all_correct_hl_group, true)\nend\n\nT['draw()']['uses correct highlight groups'] = new_set(\n  { parametrize = { { 2, 'MiniIndentscopeSymbol' }, { 3, 'MiniIndentscopeSymbolOff' } } },\n  {\n    test = function(shiftwidth, hl_group)\n      child.o.shiftwidth = shiftwidth\n      set_lines({ '  aa', '    aa', '  aa' })\n      set_cursor(2, 4)\n\n      child.lua('MiniIndentscope.draw()')\n      sleep(default_animation_step)\n\n      validate_hl_group(hl_group)\n    end,\n  }\n)\n\nT['draw()']['respects `config.draw.animation`'] = function()\n  local validate = function(duration)\n    set_cursor(5, 4)\n    child.lua('MiniIndentscope.draw()')\n\n    sleep(duration - small_time)\n    -- Should still be one symbol\n    child.expect_screenshot()\n    sleep(small_time + small_time)\n    -- Should be two symbols\n    child.expect_screenshot()\n  end\n\n  local duration = 2 * small_time\n  local command = string.format('MiniIndentscope.config.draw.animation = function() return %d end', duration)\n  child.lua(command)\n  validate(duration)\n\n  -- Should also use buffer local config\n  set_cursor(1, 0)\n  local other_duration = 3 * small_time\n  local other_command =\n    string.format('vim.b.miniindentscope_config = { draw = { animation = function() return %d end } }', other_duration)\n  child.lua(other_command)\n  validate(other_duration)\nend\n\nT['draw()']['respects `config.draw.priority`'] = function()\n  local ns_id = child.api.nvim_create_namespace('indentscope-test')\n  child.api.nvim_buf_set_extmark(0, ns_id, 4, 0, { virt_text_pos = 'overlay', virt_text = { { '+' } }, priority = 5 })\n\n  set_cursor(5, 0)\n  child.lua('MiniIndentscope.draw()')\n  sleep(default_animation_step)\n  child.expect_screenshot()\n\n  child.lua('MiniIndentscope.undraw()')\n\n  child.lua('MiniIndentscope.config.draw.priority = 6')\n  child.lua('MiniIndentscope.draw()')\n  sleep(default_animation_step)\n  child.expect_screenshot()\nend\n\nT['draw()']['respects `config.symbol`'] = function()\n  child.lua([[MiniIndentscope.config.symbol = '-']])\n  set_cursor(5, 4)\n  child.lua('MiniIndentscope.draw()')\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  set_cursor(1, 0)\n  child.b.miniindentscope_config = { symbol = '+' }\n  set_cursor(5, 4)\n  child.lua('MiniIndentscope.draw()')\n  child.expect_screenshot()\nend\n\nT['draw()'][\"does not overshadow 'listchars'\"] = function()\n  child.o.list = true\n  child.o.listchars = 'space:.'\n\n  set_cursor(5, 4)\n  child.lua('MiniIndentscope.config.draw.animation = function() return 0 end')\n  child.lua('MiniIndentscope.draw()')\n  child.expect_screenshot()\nend\n\nT['draw()']['does not round time of every animation step'] = function()\n  helpers.skip_if_slow()\n\n  local fractional_step = 0.99 * default_animation_step\n  child.lua('_G.fractional_step = ' .. fractional_step)\n  child.lua('MiniIndentscope.config.draw.animation = function() return _G.fractional_step end')\n\n  set_cursor(6, 0)\n  child.lua('MiniIndentscope.draw()')\n\n  sleep(2 * fractional_step)\n  child.expect_screenshot()\nend\n\nT['draw()']['shows symbols on wrapped lines without overlapping'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('virt_text_repeat_linebreak is supported for Neovim>=0.10') end\n\n  child.set_size(10, 15)\n  child.lua('MiniIndentscope.config.draw.animation = function() return 0 end')\n  set_lines({ 'aa', '  aa', '  ' .. string.rep('a ', 15), '  aa', 'aa' })\n  set_cursor(2, 1)\n\n  local validate = function()\n    child.lua('MiniIndentscope.draw()')\n    child.expect_screenshot()\n    child.lua('MiniIndentscope.undraw()')\n  end\n\n  -- Should try to not overlap text\n  child.wo.breakindent = false\n  validate()\n\n  -- Should show symbols on empty space\n  child.wo.breakindent = true\n  child.wo.breakindentopt = 'min:0'\n  validate()\n\n  -- Should try to not overlap 'showbreak'\n  child.wo.breakindent = true\n  child.wo.breakindentopt = 'sbr'\n  child.wo.showbreak = 'x'\n  validate()\nend\n\nT['undraw()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Virtually disable autodrawing\n      child.lua('MiniIndentscope.config.draw.delay = 100000')\n      set_lines(example_lines_nested)\n      child.set_size(15, 12)\n    end,\n  },\n})\n\nT['undraw()']['works'] = function()\n  set_cursor(5, 4)\n  child.lua('MiniIndentscope.draw()')\n  child.expect_screenshot()\n\n  child.lua('MiniIndentscope.undraw()')\n  child.expect_screenshot()\nend\n\nT['Auto drawing'] = new_set({\n  hooks = {\n    pre_case = function()\n      set_lines(example_lines_nested)\n      child.set_size(15, 12)\n    end,\n  },\n})\n\nT['Auto drawing']['works in Normal mode'] = function()\n  set_cursor(5, 4)\n  sleep(default_draw_delay - small_time)\n  -- Nothing should yet be shown\n  child.expect_screenshot()\n\n  sleep(small_time)\n  -- Symbol at cursor line should be drawn immediately\n  child.expect_screenshot()\n\n  sleep(default_animation_step)\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['respects common events'] = new_set({\n  parametrize = { { 'CursorMoved' }, { 'CursorMovedI' }, { 'TextChanged' }, { 'TextChangedI' }, { 'TextChangedP' } },\n}, {\n  test = function(event_name)\n    set_cursor(5, 4)\n    child.lua('MiniIndentscope.undraw()')\n    sleep(small_time)\n\n    child.cmd('doautocmd ' .. event_name)\n    sleep(default_draw_delay + default_animation_step + small_time)\n    child.expect_screenshot()\n  end,\n})\n\nT['Auto drawing']['respects ModeChanged event'] = function()\n  child.set_size(15, 15)\n\n  -- Add disabling in Insert mode\n  child.cmd([[\n      augroup InsertDisable\n        au!\n        au ModeChanged *:i lua vim.b.miniindentscope_disable = true\n        au ModeChanged i:* lua vim.b.miniindentscope_disable = false\n      augroup END\n    ]])\n  -- Needs reloading to register ModeChanged autocommands *after* previous ones\n  child.lua([[require('mini.indentscope').setup({ draw = { delay = 0, animation = function() return 0 end } })]])\n\n  set_cursor(5, 4)\n  sleep(small_time)\n  child.expect_screenshot()\n\n  type_keys('i')\n  sleep(small_time)\n  child.expect_screenshot()\n\n  type_keys('<Esc>')\n  sleep(small_time)\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['respects `config.draw.delay`'] = function()\n  child.lua('MiniIndentscope.config.draw.delay = ' .. (0.5 * default_draw_delay))\n  set_cursor(5, 4)\n\n  sleep(0.5 * default_draw_delay)\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  set_cursor(1, 0)\n  child.b.miniindentscope_config = { draw = { delay = 2 * default_draw_delay } }\n  set_cursor(5, 4)\n  sleep(2 * default_draw_delay)\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['implements debounce-style delay'] = function()\n  set_cursor(5, 4)\n  sleep(default_draw_delay - small_time)\n  set_cursor(2, 0)\n  sleep(default_draw_delay - small_time)\n\n  -- Should draw nothing\n  child.expect_screenshot()\n  sleep(small_time)\n  -- Should start drawing\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['by default is not done for incomplete scope'] = function()\n  set_lines({ 'aa', '  bb', '  bb', '  bb', '  bb', '  bb', 'aa' })\n  child.lua('MiniIndentscope.config.options.n_lines = 2')\n  child.lua('MiniIndentscope.config.draw.delay = ' .. small_time)\n  child.lua('MiniIndentscope.config.draw.animation = function() return 0 end')\n\n  -- Should draw if scope computation is complete\n  set_cursor(4, 0)\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  -- Should undraw immediately if scope is incomplete and never draw\n  set_cursor(3, 0)\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  type_keys('l')\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  -- Should still draw later for complete scope\n  type_keys('j')\n  sleep(small_time + small_time)\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['respects `config.draw.predicate`'] = function()\n  set_lines({ 'aa', '  bb', 'aa' })\n  child.lua('MiniIndentscope.config.draw.delay = ' .. small_time)\n  child.lua('MiniIndentscope.config.draw.animation = function() return 0 end')\n\n  child.lua([[MiniIndentscope.config.draw.predicate = function(scope)\n    return (scope.body.bottom - scope.body.top + 1) >= _G.min_scope_height\n  end]])\n\n  -- Should not draw as actual height is too low\n  child.lua('_G.min_scope_height = 2')\n  set_cursor(2, 0)\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  child.lua('_G.min_scope_height = 1')\n  type_keys('jk')\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  -- Should respect buffer-local config (and not draw in this case)\n  child.lua('vim.b.miniindentscope_config = { draw = { predicate = function() return false end } }')\n  type_keys('jk')\n  sleep(small_time + small_time)\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['respects `vim.{g,b}.miniindentscope_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child.lua('MiniIndentscope.config.draw.delay = 0')\n    child[var_type].miniindentscope_disable = true\n    set_cursor(5, 4)\n    -- Nothing should be shown\n    child.expect_screenshot()\n\n    child[var_type].miniindentscope_disable = false\n    set_cursor(5, 3)\n    -- Something should be shown\n    child.expect_screenshot()\n  end,\n})\n\nT['Auto drawing']['works in Insert mode'] = function()\n  child.set_size(15, 15)\n\n  set_cursor(5, 4)\n  type_keys('i')\n\n  sleep(default_draw_delay - small_time)\n  -- Nothing yet should be shown\n  child.expect_screenshot()\n\n  sleep(small_time)\n  -- Show only on cursor line\n  child.expect_screenshot()\n\n  sleep(default_animation_step)\n  -- One new step should be drawn\n  child.expect_screenshot()\nend\n\nT['Auto drawing']['updates immediately when scopes intersect'] = function()\n  child.set_size(15, 15)\n\n  set_cursor(5, 4)\n  sleep(default_draw_delay + default_animation_step + small_time)\n  -- Full scope should be shown\n  child.expect_screenshot()\n\n  type_keys('o')\n  -- Should be update immediately\n  child.expect_screenshot()\nend\n\nT['Motion'] = new_set({\n  hooks = {\n    pre_case = function() set_lines(example_lines_nested) end,\n  },\n})\n\nT['Motion']['works in Normal mode'] = new_set({\n  parametrize = {\n    -- `goto_top`\n    { '[i', { 3, 2 } },\n    { '2[i', { 2, 1 } },\n    { '100[i', { 1, 0 } },\n    -- `goto_bottom`\n    { ']i', { 7, 2 } },\n    { '2]i', { 8, 1 } },\n    { '100]i', { 9, 0 } },\n  },\n}, {\n  test = function(keys, final_cursor_pos)\n    set_cursor(5, 4)\n    type_keys(keys)\n    eq(get_cursor(), final_cursor_pos)\n  end,\n})\n\nT['Motion']['works in Visual mode'] = new_set({\n  parametrize = {\n    -- `goto_top`\n    { 'v[i', { 3, 2 } },\n    { 'v2[i', { 2, 1 } },\n    { 'v100[i', { 1, 0 } },\n    -- `goto_bottom`\n    { 'v]i', { 7, 2 } },\n    { 'v2]i', { 8, 1 } },\n    { 'v100]i', { 9, 0 } },\n  },\n}, {\n  test = function(keys, final_cursor_pos)\n    set_cursor(5, 4)\n    type_keys(keys)\n    eq(get_cursor(), final_cursor_pos)\n    eq(child.fn.mode(1), 'v')\n  end,\n})\n\n-- NOTE: for some reason it seems to be very important to do cases for\n-- Operator-pending mode in parametrized form, because this way child process\n-- is restarted every time. Otherwise it will lead to hanging process somewhere\nT['Motion']['works in Operator-pending mode'] = new_set({\n  parametrize = {\n    -- Use `dv` instead of `d` for deleting to make motion 'inclusive'\n    -- `goto_top`\n    { 'dv[i', 'v[id' },\n    { '2dv[i', 'v2[id' },\n    { 'dv2[i', 'v2[id' },\n    { 'dv100[i', 'v100[id' },\n    -- `goto_bottom`\n    { 'dv]i', 'v]id' },\n    { '2dv]i', 'v2]id' },\n    { 'dv2]i', 'v2]id' },\n    { 'dv100]i', 'v100]id' },\n  },\n}, {\n  test = function(keys_to_try, keys_reference)\n    local lines = get_lines()\n    set_cursor(5, 4)\n    type_keys(keys_to_try)\n    local data_tried = { cursor = get_cursor(), lines = get_lines() }\n\n    set_lines(lines)\n    set_cursor(5, 4)\n    type_keys(keys_reference)\n    local data_ref = { cursor = get_cursor(), lines = get_lines() }\n\n    eq(data_tried, data_ref)\n  end,\n})\n\nT['Motion']['works with different mappings'] = function()\n  reload_module({ mappings = { goto_top = '[I', goto_bottom = ']I' } })\n\n  -- `goto_top`\n  set_cursor(5, 4)\n  type_keys('[I')\n  eq(get_cursor(), { 3, 2 })\n\n  -- `goto_bottom`\n  set_cursor(5, 4)\n  type_keys(']I')\n  eq(get_cursor(), { 7, 2 })\n\n  reload_module()\nend\n\nT['Motion']['allows not immediate dot-repeat'] = function()\n  -- `goto_top`\n  set_cursor(5, 4)\n  type_keys('dv', '[i')\n  set_cursor(2, 2)\n  type_keys('.')\n\n  eq(get_cursor(), { 1, 0 })\n  eq(child.api.nvim_buf_line_count(0), 6)\n\n  set_lines(example_lines_nested)\n\n  -- `goto_bottom`\n  set_cursor(5, 4)\n  type_keys('dv', ']i')\n  set_cursor(6, 2)\n  type_keys('.')\n\n  eq(get_cursor(), { 6, 2 })\n  eq(child.api.nvim_buf_line_count(0), 6)\n\n  set_lines(example_lines_nested)\nend\n\nT['Motion']['respects `config.options.border`'] = function()\n  -- Should move to respective body edge if border is not present\n  child.lua([[MiniIndentscope.config.options.border = 'bottom']])\n  set_cursor(5, 4)\n  type_keys('[i')\n  eq(get_cursor(), { 4, 3 })\n\n  child.lua([[MiniIndentscope.config.options.border = 'top']])\n  set_cursor(5, 4)\n  type_keys(']i')\n  eq(get_cursor(), { 6, 3 })\n\n  child.lua([[MiniIndentscope.config.options.border = 'none']])\n  set_cursor(5, 4)\n  type_keys('[i')\n  eq(get_cursor(), { 4, 3 })\n  set_cursor(5, 4)\n  type_keys(']i')\n  eq(get_cursor(), { 6, 3 })\n\n  -- Should also use buffer local config\n  child.b.miniindentscope_config = { options = { border = 'bottom' } }\n  set_cursor(5, 4)\n  type_keys('[i')\n  eq(get_cursor(), { 4, 3 })\nend\n\nT['Motion']['handles `v:count` when `try_as_border=true`'] = function()\n  reload_module({ options = { try_as_border = true } })\n  set_cursor(5, 4)\n  type_keys('100[i')\n  eq(get_cursor(), { 1, 0 })\n\n  reload_module()\nend\n\nT['Motion']['updates jumplist only in Normal mode'] = function()\n  -- Normal mode\n  set_cursor(5, 4)\n  type_keys(']i')\n  type_keys('<C-o>')\n  eq(get_cursor(), { 5, 4 })\n\n  -- Visual mode\n  set_cursor(2, 1)\n  type_keys('v', ']i', '<Esc>')\n  type_keys('<C-o>')\n  expect.no_equality(get_cursor(), { 2, 1 })\nend\n\nT['Textobject'] = new_set({\n  hooks = {\n    pre_case = function() set_lines(example_lines_nested) end,\n  },\n})\n\nT['Textobject']['works in Visual mode'] = new_set({\n  parametrize = {\n    -- `object_scope`\n    { 'vii', 4, 6 },\n    { 'v2ii', 4, 6 },\n    -- `object_scope_with_border`\n    { 'vai', 3, 7 },\n    { 'v2ai', 2, 8 },\n    { 'v100ai', 1, 9 },\n  },\n}, {\n  test = function(keys, start_line, end_line)\n    set_cursor(5, 4)\n    type_keys(keys)\n    child.expect_visual_marks(start_line, end_line)\n  end,\n})\n\nT['Textobject']['works in Operator-pending mode'] = new_set({\n  parametrize = {\n    { 'dii', 'viid' },\n    { '2dii', 'v2iid' },\n    { 'd2ii', 'viid' },\n    { 'dai', 'vaid' },\n    { '2dai', 'v2aid' },\n    { 'd2ai', 'v2aid' },\n    { 'd100ai', 'v100aid' },\n  },\n}, {\n  test = function(keys_to_try, keys_reference)\n    local lines = get_lines()\n    set_cursor(5, 4)\n    type_keys(keys_to_try)\n    local data_tried = { cursor = get_cursor(), lines = get_lines() }\n\n    set_lines(lines)\n    set_cursor(5, 4)\n    type_keys(keys_reference)\n    local data_ref = { cursor = get_cursor(), lines = get_lines() }\n\n    eq(data_tried, data_ref)\n  end,\n})\n\nT['Textobject']['works with different mappings'] = function()\n  reload_module({ mappings = { object_scope = 'II', object_scope_with_border = 'AI' } })\n\n  -- `object_scope`\n  set_cursor(5, 4)\n  type_keys('v', 'II', '<Esc>')\n  child.expect_visual_marks(4, 6)\n\n  -- `object_scope_with_border`\n  set_cursor(5, 4)\n  type_keys('v', 'AI', '<Esc>')\n  child.expect_visual_marks(3, 7)\n\n  reload_module()\nend\n\nT['Textobject']['allows not immediate dot-repeat'] = function()\n  -- `object_scope`\n  set_cursor(5, 4)\n  type_keys('d', 'ii')\n  set_cursor(2, 2)\n  type_keys('.')\n\n  eq(child.api.nvim_buf_line_count(0), 2)\n\n  set_lines(example_lines_nested)\n\n  -- `object_scope_with_border`\n  set_cursor(5, 4)\n  type_keys('d', 'ai')\n  set_cursor(2, 2)\n  type_keys('.')\n\n  eq(get_lines(), { '' })\n\n  set_lines(example_lines_nested)\nend\n\nT['Textobject']['respects `config.options.border`'] = function()\n  -- Should select up to respective body edge if border is not present\n  child.lua([[MiniIndentscope.config.options.border = 'bottom']])\n  set_cursor(5, 4)\n  type_keys('v', 'ai', '<Esc>')\n  child.expect_visual_marks(4, 7)\n\n  child.lua([[MiniIndentscope.config.options.border = 'top']])\n  set_cursor(5, 4)\n  type_keys('v', 'ai', '<Esc>')\n  child.expect_visual_marks(3, 6)\n\n  child.lua([[MiniIndentscope.config.options.border = 'none']])\n  set_cursor(5, 4)\n  type_keys('v', 'ai', '<Esc>')\n  child.expect_visual_marks(4, 6)\n\n  -- Should also use buffer local config\n  child.b.miniindentscope_config = { options = { border = 'bottom' } }\n  set_cursor(5, 4)\n  type_keys('v', 'ai', '<Esc>')\n  child.expect_visual_marks(4, 7)\nend\n\nT['Textobject']['handles `v:count` when `try_as_border=true`'] = function()\n  reload_module({ options = { try_as_border = true } })\n  set_cursor(5, 4)\n  type_keys('v', '100ai', '<Esc>')\n  child.expect_visual_marks(1, 9)\n\n  reload_module()\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_jump.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('jump', config) end\nlocal unload_module = function() child.mini_unload('jump') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\n--stylua: ignore end\n\n-- Data =======================================================================\nlocal example_lines = {\n  'Lorem ipsum dolor sit amet,',\n  'consectetur adipiscing elit, sed do eiusmod tempor',\n  'incididunt ut labore et dolore magna aliqua.',\n  '`!@#$%^&*()_+=.,1234567890',\n}\n\n-- Time constants\nlocal default_highlight_delay = 250\nlocal reminder_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniJump)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniJump'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniJump'), 'links to SpellRare')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniJump.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniJump.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('delay.highlight', 250)\n  expect_config('delay.idle_stop', 10000000)\n  expect_config('mappings.forward', 'f')\n  expect_config('mappings.backward', 'F')\n  expect_config('mappings.forward_till', 't')\n  expect_config('mappings.backward_till', 'T')\n  expect_config('mappings.repeat_jump', ';')\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ delay = { highlight = 500 } })\n  eq(child.lua_get('MiniJump.config.delay.highlight'), 500)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ delay = 'a' }, 'delay', 'table')\n  expect_config_error({ delay = { highlight = 'a' } }, 'delay.highlight', 'number')\n  expect_config_error({ delay = { idle_stop = 'a' } }, 'delay.idle_stop', 'number')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { forward = 1 } }, 'mappings.forward', 'string')\n  expect_config_error({ mappings = { backward = 1 } }, 'mappings.backward', 'string')\n  expect_config_error({ mappings = { forward_till = 1 } }, 'mappings.forward_till', 'string')\n  expect_config_error({ mappings = { backward_till = 1 } }, 'mappings.backward_till', 'string')\n  expect_config_error({ mappings = { repeat_jump = 1 } }, 'mappings.repeat_jump', 'string')\n  expect_config_error({ silent = 1 }, 'silent', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniJump'), 'links to SpellRare')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('nmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('f', 'Jump'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('n', 'f')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { forward = '' } })\n  eq(has_map('f', 'Jump'), false)\nend\n\nT['state'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua('MiniJump.stop_jumping()')\n      set_lines({ '1e2e3e4e' })\n      set_cursor(1, 0)\n    end,\n  },\n})\n\nlocal get_state = function() return child.lua_get('MiniJump.state') end\n\nT['state']['has correct initial values'] = function()\n  eq(get_state(), {\n    target = nil,\n    backward = false,\n    till = false,\n    n_times = 1,\n    mode = nil,\n    jumping = false,\n  })\nend\n\nT['state']['updates `target`'] = function()\n  type_keys('f', 'e')\n  eq(get_state().target, 'e')\n\n  child.lua('MiniJump.stop_jumping()')\n  child.lua([[MiniJump.jump('3e')]])\n  eq(get_state().target, '3e')\nend\n\nT['state']['updates `backward`'] = function()\n  set_cursor(1, 7)\n  type_keys('F', 'e')\n  eq(get_state().backward, true)\n\n  type_keys('f')\n  eq(get_state().backward, false)\nend\n\nT['state']['updates `till`'] = function()\n  type_keys('t', 'e')\n  eq(get_state().till, true)\n\n  type_keys('f')\n  eq(get_state().till, false)\nend\n\nT['state']['updates `n_times`'] = function()\n  type_keys('2f', 'e')\n  eq(get_state().n_times, 2)\nend\n\nT['state']['updates `mode`'] = function()\n  type_keys('t', 'e')\n  eq(get_state().mode, 'n')\n  child.lua('MiniJump.stop_jumping()')\n\n  type_keys('V', 't', 'e')\n  eq(get_state().mode, 'V')\n  child.ensure_normal_mode()\n\n  type_keys('d', 't', 'e')\n  eq(get_state().mode, 'nov')\n\n  -- Ensure dot-repeat does not update mode after the jump\n  type_keys('V', 't', 'e')\n  eq(get_state().mode, 'V')\n  child.ensure_normal_mode()\n  type_keys('.')\n  eq(get_state().mode, 'V')\nend\n\nT['state']['updates `jumping`'] = function()\n  type_keys('f', 'e')\n  eq(get_state().jumping, true)\n\n  child.lua('MiniJump.stop_jumping()')\n  eq(get_state().jumping, false)\nend\n\nT['jump()'] = new_set({\n  hooks = {\n    pre_case = function()\n      set_lines(example_lines)\n      set_cursor(1, 0)\n    end,\n  },\n})\n\nlocal validate_jump = function(args, final_cursor_pos)\n  -- Usage of string arguments is needed because there seems to be no way to\n  -- correctly transfer to `child` `nil` values between non-`nil` onces. Like\n  -- `child.lua('MiniJump.jump(...)', {'m', nil, true})`. Gives `Cannot\n  -- convert given lua table` error.\n  child.lua(('MiniJump.jump(%s)'):format(args))\n  eq(get_cursor(), final_cursor_pos)\nend\n\nT['jump()']['respects `target` argument'] = function()\n  -- Can not jump by default without recent target\n  expect.match(child.cmd_capture('lua MiniJump.jump()'), 'no recent `target`')\n\n  -- Jump to one letter target\n  validate_jump([['m']], { 1, 4 })\n\n  -- By default uses latest used value\n  validate_jump('', { 1, 10 })\n\n  -- Accepts more than one letter\n  validate_jump([['sit']], { 1, 18 })\n\n  -- Accepts non-letters\n  validate_jump([['!']], { 4, 1 })\n  validate_jump([['1']], { 4, 16 })\nend\n\nT['jump()']['respects `backward` argument'] = function()\n  -- Jumps forward by default at first jump\n  validate_jump([['d']], { 1, 12 })\n\n  -- Can jump backward\n  validate_jump([['m', true]], { 1, 10 })\n\n  -- By default uses latest used value\n  validate_jump([['m']], { 1, 4 })\nend\n\nT['jump()']['respects `till` argument'] = function()\n  -- Jumps on target by default at first jump\n  validate_jump([['m']], { 1, 4 })\n\n  -- Can jump till\n  validate_jump([['m', nil, true]], { 1, 9 })\n\n  -- By default uses latest used value\n  validate_jump([['m']], { 1, 22 })\nend\n\nT['jump()']['respects `n_times` argument'] = function()\n  -- Jumps once by default at first jump\n  validate_jump([['m']], { 1, 4 })\n\n  -- Can jump multiple times\n  validate_jump([['m', nil, nil, 2]], { 1, 23 })\n\n  -- By default uses latest used value\n  validate_jump([['m']], { 2, 46 })\nend\n\nT['jump()']['allows matches at end of line when `till=true`'] = function()\n  set_lines({ 'aaa', 'b', 'aaa' })\n\n  local validate_t = function(start_pos, end_pos)\n    set_cursor(unpack(start_pos))\n    validate_jump([['b', false, true, 1]], end_pos)\n  end\n  local validate_T = function(start_pos, end_pos)\n    set_cursor(unpack(start_pos))\n    validate_jump([['b', true, true, 1]], end_pos)\n  end\n\n  -- Normal mode when not allowed to put cursor on end of line\n  validate_t({ 1, 0 }, { 1, 2 })\n  validate_T({ 3, 2 }, { 2, 0 })\n\n  -- Visual mode (allowed to put cursor on end of line)\n  type_keys('v')\n  validate_t({ 1, 0 }, { 1, 3 })\n  child.ensure_normal_mode()\n\n  type_keys('v')\n  validate_T({ 3, 2 }, { 2, 1 })\n  child.ensure_normal_mode()\n\n  -- Normal mode when allowed to put cursor on end of line\n  child.o.virtualedit = 'onemore'\n  validate_t({ 1, 0 }, { 1, 3 })\n  validate_T({ 3, 2 }, { 2, 1 })\nend\n\nT['jump()']['does not jump if there is no place to jump'] = function() validate_jump([['x']], { 1, 0 }) end\n\nT['jump()']['opens enough folds'] = function()\n  set_lines({ 'a', 'b', 'c', 'd' })\n\n  -- Manually create two nested closed folds\n  set_cursor(3, 0)\n  type_keys('zf', 'G')\n  type_keys('zf', 'gg')\n  eq(child.fn.foldlevel(1), 1)\n  eq(child.fn.foldlevel(3), 2)\n  eq(child.fn.foldclosed(2), 1)\n  eq(child.fn.foldclosed(3), 1)\n\n  -- Jumping should open just enough folds\n  set_cursor(1, 0)\n  validate_jump([['b']], { 2, 0 })\n  eq(child.fn.foldclosed(2), -1)\n  eq(child.fn.foldclosed(3), 3)\nend\n\nT['smart_jump()'] = new_set({\n  hooks = {\n    pre_case = function() set_lines(example_lines) end,\n  },\n})\n\nT['smart_jump()']['works'] = function()\n  child.lua_notify('MiniJump.smart_jump()')\n  child.poke_eventloop()\n  type_keys('m')\n  eq(get_cursor(), { 1, 4 })\nend\n\n-- Integration tests ==========================================================\nT['Jumping with f/t/F/T'] = new_set()\n\nT['Jumping with f/t/F/T']['works in Normal and Visual modes'] = new_set({\n  parametrize = {\n    { 'Normal', 'f', { { 1, 2 }, { 1, 5 }, { 2, 5 }, { 3, 2 } } },\n    { 'Normal', 't', { { 1, 1 }, { 1, 4 }, { 2, 4 }, { 3, 1 } } },\n    { 'Normal', 'F', { { 3, 5 }, { 3, 2 }, { 2, 2 }, { 1, 5 } } },\n    { 'Normal', 'T', { { 3, 6 }, { 3, 3 }, { 2, 3 }, { 1, 6 } } },\n\n    { 'Visual', 'f', { { 1, 2 }, { 1, 5 }, { 2, 5 }, { 3, 2 } } },\n    { 'Visual', 't', { { 1, 1 }, { 1, 4 }, { 2, 4 }, { 3, 1 } } },\n    { 'Visual', 'F', { { 3, 5 }, { 3, 2 }, { 2, 2 }, { 1, 5 } } },\n    { 'Visual', 'T', { { 3, 6 }, { 3, 3 }, { 2, 3 }, { 1, 6 } } },\n  },\n}, {\n  test = function(test_mode, key, positions)\n    set_lines({ '11e22e__', '33e44e__', '55e66e__' })\n\n    local start_pos = key == key:lower() and { 1, 0 } or { 3, 7 }\n    set_cursor(unpack(start_pos))\n\n    if test_mode == 'Visual' then\n      type_keys('v')\n      eq(child.fn.mode(), 'v')\n    end\n\n    -- First time should jump and start \"jumping\" mode\n    type_keys(key, 'e')\n    eq(get_cursor(), positions[1])\n\n    -- Typing same key should repeat jump\n    type_keys(key)\n    eq(get_cursor(), positions[2])\n\n    -- Prepending with `count` should work\n    type_keys('2', key)\n    eq(get_cursor(), positions[3])\n\n    -- Typing same key should ignore previous `count`\n    type_keys(key)\n    eq(get_cursor(), positions[4])\n  end,\n})\n\n-- NOTE: for some reason it seems to be very important to do cases for\n-- Operator-pending mode in parametrized form, because this way child process\n-- is restarted every time. Otherwise it will lead to hanging process somewhere.\nT['Jumping with f/t/F/T']['works in Operator-pending mode'] = new_set({\n  parametrize = {\n    { 'f', { '2e3e4e5e_ ', '4e5e_ ', '_ ' } },\n    { 't', { 'e2e3e4e5e_ ', 'e4e5e_ ', 'e_ ' } },\n    { 'F', { ' 1e2e3e4e5', ' 1e2e3', ' 1' } },\n    { 'T', { ' 1e2e3e4e5e', ' 1e2e3e', ' 1e' } },\n  },\n}, {\n  test = function(key, line_seq)\n    set_lines({ ' 1e2e3e4e5e_ ' })\n\n    local start_col = key == key:lower() and 0 or 12\n    set_cursor(1, start_col)\n\n    -- Apply once\n    type_keys('d', key, 'e')\n    eq(get_lines(), { line_seq[1] })\n\n    -- Prepending with `count` should work\n    type_keys('2d', key, 'e')\n    eq(get_lines(), { line_seq[2] })\n\n    -- Another prepending with `count` should work\n    type_keys('d', '2', key, 'e')\n    eq(get_lines(), { line_seq[3] })\n\n    -- Just typing `key` shouldn't repeat motion\n    local cur_pos = get_cursor()\n    type_keys(key)\n    eq(get_cursor(), cur_pos)\n    -- Stop asking for user input\n    type_keys('<Esc>')\n  end,\n})\n\nT['Jumping with f/t/F/T']['allows dot-repeat'] = new_set({\n  parametrize = { { 'f' }, { 't' }, { 'F' }, { 'T' } },\n}, {\n  test = function(key)\n    -- Start with two equal lines (with enough targets) to check equal effect\n    set_lines({ ' 1e2e3e4e_ ', ' 1e2e3e4e_ ' })\n\n    local lines = get_lines()\n    local start_col = key == key:lower() and 0 or lines[1]:len()\n    set_cursor(1, start_col)\n\n    type_keys('2d', key, 'e')\n\n    -- Immediate dot-repeat\n    type_keys('.')\n\n    -- Not immediate dot-repeat\n    set_cursor(2, start_col)\n    type_keys('.', '.')\n\n    -- Check equal effect\n    lines = get_lines()\n    eq(lines[1], lines[2])\n  end,\n})\n\nT['Jumping with f/t/F/T']['stops jumping when non-jump movement is done'] = function()\n  set_lines({ 'TF', ' 1e2e3e ', 'ft' })\n\n  -- General idea: move once, make non-jump movement 'l', test typing `key`\n  -- twice. Can't test once because it should ask for user input and make an\n  -- actual movement to `key` letter.\n  set_cursor(2, 0)\n  type_keys('f', 'e', 'l', 'f', 'f')\n  eq(get_cursor(), { 3, 0 })\n\n  set_cursor(2, 0)\n  type_keys('t', 'e', 'l', 't', 't')\n  eq(get_cursor(), { 3, 0 })\n\n  set_cursor(2, 7)\n  type_keys('F', 'e', 'l', 'F', 'F')\n  eq(get_cursor(), { 1, 1 })\n\n  set_cursor(2, 7)\n  type_keys('T', 'e', 'l', 'T', 'T')\n  eq(get_cursor(), { 1, 1 })\nend\n\nT['Jumping with f/t/F/T']['stops jumping when leaving buffer'] = function()\n  -- Set up windows and buffers\n  local buf_id_other = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_id_other)\n  child.lua('_G.buf_id_other = ' .. buf_id_other)\n\n  child.cmd('vsplit')\n  local buf_id_cur = child.api.nvim_create_buf(true, false)\n  child.api.nvim_set_current_buf(buf_id_cur)\n  set_lines({ '1e2e3e4e' })\n\n  -- Should stop if `BufLeave` is for current buffer\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n  eq(child.lua_get('MiniJump.state.jumping'), true)\n\n  child.api.nvim_set_current_buf(buf_id_other)\n  eq(child.lua_get('MiniJump.state.jumping'), false)\n\n  -- Should not stop if `BufLeave` is for non-current buffer\n  child.api.nvim_set_current_buf(buf_id_cur)\n  type_keys('f', 'e')\n  eq(child.lua_get('MiniJump.state.jumping'), true)\n\n  child.lua('vim.api.nvim_buf_call(_G.buf_id_other, function() vim.cmd(\"doautocmd BufLeave\") end)')\n  eq(child.lua_get('MiniJump.state.jumping'), true)\nend\n\nT['Jumping with f/t/F/T']['works with different mappings'] = function()\n  for _, key in ipairs({ 'f', 't', 'F', 'T' }) do\n    child.api.nvim_del_keymap('n', key)\n  end\n  reload_module({ mappings = { forward = 'gf', backward = 'gF', forward_till = 'gt', backward_till = 'gT' } })\n  set_lines({ ' 1e2e3e_ ' })\n\n  set_cursor(1, 0)\n  type_keys('gf', 'e')\n  eq(get_cursor(), { 1, 2 })\n\n  set_cursor(1, 0)\n  type_keys('gt', 'e')\n  eq(get_cursor(), { 1, 1 })\n\n  set_cursor(1, 8)\n  type_keys('gF', 'e')\n  eq(get_cursor(), { 1, 6 })\n\n  set_cursor(1, 8)\n  type_keys('gT', 'e')\n  eq(get_cursor(), { 1, 7 })\nend\n\nT['Jumping with f/t/F/T']['allows changing direction during jumping'] = function()\n  set_lines({ ' 1e2e3e_ ' })\n\n  -- After typing either one of ftFt, it should enter \"jumping\" mode, in\n  -- which typing any of the five jump keys (including `;`) jumps around\n  -- present targets.\n  set_cursor(1, 0)\n  type_keys('f', 'e', 't')\n  eq(get_cursor(), { 1, 3 })\n\n  set_cursor(1, 0)\n  type_keys('2f', 'e', 'F')\n  eq(get_cursor(), { 1, 2 })\n\n  set_cursor(1, 8)\n  type_keys('F', 'e', 'T')\n  eq(get_cursor(), { 1, 5 })\n\n  set_cursor(1, 8)\n  type_keys('2F', 'e', 't')\n  eq(get_cursor(), { 1, 5 })\n\n  set_cursor(1, 0)\n  type_keys('f', 'e', 'f', 'T', 't', 'F')\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['Jumping with f/t/F/T']['enters jumping mode even if first jump is impossible'] = function()\n  set_lines({ '1e2e3e' })\n  set_cursor(1, 0)\n\n  -- There is no target in backward direction...\n  type_keys('F', 'e')\n\n  -- ...but it still should enter jumping mode because target is present\n  type_keys('f', 'f')\n  eq(get_cursor(), { 1, 3 })\nend\n\nT['Jumping with f/t/F/T']['does nothing if there is no place to jump'] = function()\n  local validate_single = function(keys, start_line, start_col, ref_mode)\n    set_lines({ start_line })\n    set_cursor(1, start_col)\n\n    type_keys(keys, 'd')\n\n    -- It shouldn't move anywhere and should not modify text\n    eq(get_cursor(), { 1, start_col })\n    eq(get_lines(), { start_line })\n    eq(child.fn.mode(), ref_mode)\n\n    -- The above applies to subsequent dot-repeats as well\n    type_keys('.')\n    eq(get_cursor(), { 1, start_col })\n    eq(get_lines(), { start_line })\n    eq(child.fn.mode(), ref_mode)\n\n    -- Ensure there is no jumping\n    child.lua('MiniJump.stop_jumping()')\n    child.ensure_normal_mode()\n  end\n\n  local validate = function(line)\n    validate_single('f', line, 4, 'n')\n    validate_single('t', line, 4, 'n')\n    validate_single('F', line, 2, 'n')\n    validate_single('T', line, 2, 'n')\n\n    validate_single('vf', line, 4, 'v')\n    validate_single('vt', line, 4, 'v')\n    validate_single('vF', line, 2, 'v')\n    validate_single('vT', line, 2, 'v')\n\n    validate_single('df', line, 4, 'n')\n    validate_single('dt', line, 4, 'n')\n    validate_single('dF', line, 2, 'n')\n    validate_single('dT', line, 2, 'n')\n  end\n\n  -- Target is present but not reachable\n  validate('abcdefg')\n\n  -- Target is not present\n  validate('abcxefg')\nend\n\nT['Jumping with f/t/F/T']['can be dot-repeated if did not jump at first'] = function()\n  -- Normal mode\n  local validate = function(keys, col_1, col_2, line_2)\n    set_lines({ 'abcdefg' })\n    set_cursor(1, col_1)\n\n    type_keys(keys, 'd')\n    eq(get_cursor(), { 1, col_1 })\n    eq(get_lines(), { 'abcdefg' })\n\n    set_cursor(1, col_2)\n    type_keys('.')\n    eq(get_lines(), { line_2 })\n\n    -- Ensure there is no jumping\n    child.lua('MiniJump.stop_jumping()')\n    child.ensure_normal_mode()\n  end\n\n  validate('df', 5, 1, 'aefg')\n  validate('dt', 5, 1, 'adefg')\n  validate('dF', 1, 5, 'abcg')\n  validate('dT', 1, 5, 'abcdg')\nend\n\nT['Jumping with f/t/F/T']['inside dot-repeat is not affected by regular jumping'] = function()\n  local validate = function(keys, key_antagonist, result)\n    local line = '_xdxdx1x1xdxdx_'\n    local tests_forward = key_antagonist == string.upper(key_antagonist)\n\n    set_lines({ line })\n    set_cursor(1, tests_forward and 0 or (string.len(line) - 1))\n\n    type_keys(keys)\n    type_keys(tests_forward and '$' or '^')\n    type_keys(key_antagonist, '1')\n    type_keys('.')\n    eq(get_lines(), { result })\n\n    -- Ensure there is no jumping\n    child.lua('MiniJump.stop_jumping()')\n    child.ensure_normal_mode()\n  end\n\n  validate('2dfd', 'T', 'x1x1x_')\n  validate('2dtd', 'F', 'dx1xdx_')\n  validate('2dFd', 't', '_x1x1x')\n  validate('2dTd', 'f', '_xdx1xd')\nend\n\nT['Jumping with f/t/F/T']['stops prompting for target if hit `<Esc>` or `<C-c>`'] = new_set({\n  parametrize = {\n    { 'f', '<Esc>' },\n    { 't', '<Esc>' },\n    { 'F', '<Esc>' },\n    { 'T', '<Esc>' },\n    { 'f', '<C-c>' },\n    { 't', '<C-c>' },\n    { 'F', '<C-c>' },\n    { 'T', '<C-c>' },\n  },\n}, {\n  test = function(key, test_key)\n    set_lines({ 'oooo' })\n    set_cursor(1, 0)\n    -- Here 'o' should act just like Normal mode 'o'\n    -- Wait after every key to poke eventloop\n    type_keys(1, key, test_key, 'o')\n    eq(get_lines(), { 'oooo', '' })\n\n    child.ensure_normal_mode()\n\n    -- Should also work in Operator-pending mode\n    set_lines({ 'oooo' })\n    set_cursor(1, 0)\n    type_keys(1, 'd', key, test_key, 'o')\n    eq(get_lines(), { 'oooo', '' })\n  end,\n})\n\nT['Jumping with f/t/F/T']['ignores current position if it is acceptable target'] = new_set({\n  parametrize = { { 'f' }, { 't' }, { 'F' }, { 'T' } },\n}, {\n  test = function(key)\n    set_lines({ 'xxxx' })\n    local start_col, finish_col = 0, 1\n    if key ~= key:lower() then\n      start_col, finish_col = 3, 2\n    end\n    set_cursor(1, start_col)\n\n    type_keys(key, 'x')\n    eq(get_cursor(), { 1, finish_col })\n  end,\n})\n\nT['Jumping with f/t/F/T']['for t/T allows matches on end of line'] = function()\n  set_lines({ 'aaa', 'b', 'aaa' })\n\n  local validate_t = function(start_pos, end_pos)\n    set_cursor(unpack(start_pos))\n    type_keys('t', 'b')\n    eq(get_cursor(), end_pos)\n  end\n  local validate_T = function(start_pos, end_pos)\n    set_cursor(unpack(start_pos))\n    type_keys('T', 'b')\n    eq(get_cursor(), end_pos)\n  end\n\n  -- Normal mode when not allowed to put cursor on end of line\n  validate_t({ 1, 0 }, { 1, 2 })\n  validate_T({ 3, 2 }, { 2, 0 })\n\n  -- Visual mode (allowed to put cursor on end of line)\n  type_keys('v')\n  validate_t({ 1, 0 }, { 1, 3 })\n  child.ensure_normal_mode()\n\n  type_keys('v')\n  validate_T({ 3, 2 }, { 2, 1 })\n  child.ensure_normal_mode()\n\n  -- Normal mode when allowed to put cursor on end of line\n  child.o.virtualedit = 'onemore'\n  validate_t({ 1, 0 }, { 1, 3 })\n  validate_T({ 3, 2 }, { 2, 1 })\nend\n\nT['Jumping with f/t/F/T']['shows reminder after one idle second'] = function()\n  child.set_size(10, 40)\n\n  -- Execute one time to test if 'needs help message' flag is set per call\n  set_lines(example_lines)\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n  sleep(0.5 * reminder_delay)\n\n  -- Start another jump\n  type_keys('h', 'f')\n  sleep(reminder_delay + small_time)\n  -- Should show colored helper message without adding it to `:messages` and\n  -- causing hit-enter-prompt\n  child.expect_screenshot()\n  eq(child.cmd_capture('1messages'), '')\n\n  -- Should clean command line after starting jumping\n  type_keys('m')\n  child.expect_screenshot()\nend\n\nT['Jumping with f/t/F/T']['stops jumping if no target is found'] = function()\n  set_lines('ooo')\n\n  -- General idea: there was a bug which didn't reset jumping state if target\n  -- was not found by `vim.fn.search()`. In that case, next typing of jumping\n  -- key wouldn't make effect, but it should.\n  -- Related test case: 'Enters jumping mode even if first jump is impossible'\n  for _, key in ipairs({ 'f', 't', 'F', 'T' }) do\n    local start_col = key == key:lower() and 0 or 3\n    set_cursor(1, start_col)\n    type_keys(key, 'e', key, 'o')\n    eq(get_cursor(), { 1, 1 })\n    -- Ensure no jumping mode\n    child.lua('MiniJump.stop_jumping()')\n  end\nend\n\nT['Jumping with f/t/F/T']['jumps as far as it can with big `count`'] = function()\n  set_lines({ ' 1e2e3e4e_ ' })\n\n  set_cursor(1, 0)\n  type_keys('10f', 'e')\n  eq(get_cursor(), { 1, 8 })\n\n  set_cursor(1, 0)\n  type_keys('10t', 'e')\n  eq(get_cursor(), { 1, 7 })\n\n  set_cursor(1, 10)\n  type_keys('10F', 'e')\n  eq(get_cursor(), { 1, 2 })\n\n  set_cursor(1, 10)\n  type_keys('10T', 'e')\n  eq(get_cursor(), { 1, 3 })\nend\n\nT['Jumping with f/t/F/T']['respects `vim.{g,b}.minijump_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minijump_disable = true\n    set_lines({ '1e2e3e4e' })\n    set_cursor(1, 0)\n    type_keys('f', 'e')\n    -- `f` does nothing, while `e` jumps to end of word (otherwise it would\n    -- have been `{1, 1}`)\n    eq(get_cursor(), { 1, 7 })\n  end,\n})\n\nT['Jumping with f/t/F/T']['respects `config.silent`'] = function()\n  child.lua('MiniJump.config.silent = true')\n  child.set_size(10, 20)\n\n  -- Execute one time to test if 'needs help message' flag is set per call\n  set_lines({ '1e2e3e4e' })\n  set_cursor(1, 0)\n  type_keys('f')\n  sleep(reminder_delay + small_time)\n\n  -- Should not show helper message\n  child.expect_screenshot()\nend\n\nT['Jumping with f/t/F/T'][\"respects 'ignorecase'\"] = function()\n  child.o.ignorecase = true\n  set_lines({ ' 1e2E3E4e_ ' })\n\n  set_cursor(1, 0)\n  type_keys('2f', 'E')\n  eq(get_cursor(), { 1, 4 })\n\n  set_cursor(1, 0)\n  type_keys('2t', 'E')\n  eq(get_cursor(), { 1, 3 })\n\n  set_cursor(1, 10)\n  type_keys('2F', 'E')\n  eq(get_cursor(), { 1, 6 })\n\n  set_cursor(1, 10)\n  type_keys('2T', 'E')\n  eq(get_cursor(), { 1, 7 })\nend\n\nT['Jumping with f/t/F/T'][\"respects 'smartcase'\"] = function()\n  child.o.ignorecase = true\n  child.o.smartcase = true\n  set_lines({ ' 1e2E3E4e_ ' })\n\n  set_cursor(1, 0)\n  type_keys('2f', 'E')\n  eq(get_cursor(), { 1, 6 })\n\n  set_cursor(1, 0)\n  type_keys('2t', 'E')\n  eq(get_cursor(), { 1, 5 })\n\n  set_cursor(1, 10)\n  type_keys('2F', 'E')\n  eq(get_cursor(), { 1, 4 })\n\n  set_cursor(1, 10)\n  type_keys('2T', 'E')\n  eq(get_cursor(), { 1, 5 })\nend\n\nT['Jumping with f/t/F/T'][\"respects 'selection=exclusive'\"] = function()\n  child.o.selection = 'exclusive'\n  set_lines({ ' 1e2e' })\n\n  set_cursor(1, 0)\n  type_keys('v', 'f', 'e')\n  eq({ child.fn.col('v'), child.fn.col('.') }, { 1, 4 })\n\n  type_keys('d')\n  eq(get_lines(), { '2e' })\nend\n\nT['Jumping with f/t/F/T']['can be used with `:normal-range`'] = function()\n  -- Basically, it should check that jumping state is restarted even outside of\n  -- `CursorMoved` event (which is not issued in this case)\n  set_lines({ '11e22e', '11e22e', '11e22e' })\n  set_cursor(1, 0)\n  type_keys('vip', ':normal fefx<CR>')\n  eq(get_lines(), { '11e22', '11e22', '11e22' })\nend\n\nT['Repeat jump with ;'] = new_set()\n\nT['Repeat jump with ;']['works'] = function()\n  set_lines({ ' 1e2e3e4e_ ' })\n\n  set_cursor(1, 0)\n  type_keys('f', 'e', ';')\n  eq(get_cursor(), { 1, 4 })\n\n  set_cursor(1, 0)\n  type_keys('t', 'e', ';')\n  eq(get_cursor(), { 1, 3 })\n\n  set_cursor(1, 10)\n  type_keys('F', 'e', ';')\n  eq(get_cursor(), { 1, 6 })\n\n  set_cursor(1, 10)\n  type_keys('T', 'e', ';')\n  eq(get_cursor(), { 1, 7 })\nend\n\n-- Other tests are done with 'f' in hope that others keys act the same\nT['Repeat jump with ;']['works in Normal and Visual mode'] = new_set({\n  parametrize = { { 'Normal' }, { 'Visual' } },\n}, {\n  test = function(test_mode)\n    set_lines({ '1e2e3e4e' })\n\n    if test_mode == 'Visual' then\n      type_keys('v')\n      eq(child.fn.mode(), 'v')\n    end\n\n    -- Repeats simple motion\n    set_cursor(1, 0)\n    type_keys('f', 'e', ';')\n    eq(get_cursor(), { 1, 3 })\n\n    -- Repeats not immediately\n    set_cursor(1, 0)\n    type_keys(';')\n    eq(get_cursor(), { 1, 1 })\n\n    -- Repeats with `count`\n    set_cursor(1, 0)\n    type_keys('2f', 'e', ';')\n    eq(get_cursor(), { 1, 7 })\n  end,\n})\n\nT['Repeat jump with ;']['works after jump in Operator-pending mode'] = function()\n  -- It doesn't repeat actual operation, just performs same jump\n  set_lines({ '1e2e3e4e5e' })\n  set_cursor(1, 0)\n\n  type_keys('d', 'f', 'e', ';')\n  eq(get_lines(), { '2e3e4e5e' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- It jumps preserving `count`\n  set_lines({ '1e2e3e4e5e' })\n  set_cursor(1, 0)\n\n  type_keys('d', '2f', 'e', ';')\n  eq(get_lines(), { '3e4e5e' })\n  eq(get_cursor(), { 1, 3 })\n\n  -- Should not use the latest dot repeat (like in `nvim --clean`)\n  set_lines({ '1e2e__3e4e5e6e' })\n  set_cursor(1, 0)\n\n  type_keys('d', '2f', 'e')\n  eq(get_lines(), { '__3e4e5e6e' })\n  eq(get_cursor(), { 1, 0 })\n\n  type_keys('$', 'T', '_')\n  eq(get_lines(), { '__3e4e5e6e' })\n  eq(get_cursor(), { 1, 2 })\n\n  -- - Should reuse initial Operator-pending mode state and not the latest one\n  type_keys('.')\n  eq(get_lines(), { '__5e6e' })\n  eq(get_cursor(), { 1, 2 })\n\n  -- - The latest one should still be preserved for regular jumping\n  type_keys(';')\n  eq(get_lines(), { '__5e6e' })\n  eq(get_cursor(), { 1, 1 })\nend\n\nT['Repeat jump with ;']['works in Operator-pending mode'] = function()\n  set_lines({ '1e2e3e4e5e_' })\n  set_cursor(1, 0)\n\n  -- Should repeat without asking for target\n  type_keys('f', 'e', 'd', ';')\n  eq(get_lines(), { '13e4e5e_' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- Should work with dot-repeat as in `nvim --clean`, i.e. use target from the\n  -- latest jump, as `;` is exactly for that\n  type_keys('.')\n  eq(get_lines(), { '14e5e_' })\n  eq(get_cursor(), { 1, 1 })\n\n  type_keys('f', '_', '^')\n  type_keys('.')\n  eq(get_lines(), { '' })\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Repeat jump with ;']['works with different mapping'] = function()\n  child.api.nvim_del_keymap('n', ';')\n  reload_module({ mappings = { repeat_jump = 'g;' } })\n\n  set_lines({ '1e2e' })\n  type_keys('f', 'e', 'g;')\n  eq(get_cursor(), { 1, 3 })\nend\n\nT['Repeat jump with ;']['works not immediately after failed first jump'] = function()\n  set_lines({ 'aaa' })\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n  eq(get_cursor(), { 1, 0 })\n\n  set_lines({ 'aaa', 'eee' })\n  set_cursor(1, 0)\n  type_keys(';')\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['Repeat jump with ;']['respects `vim.{g,b}.minijump_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    set_lines({ '1e2e3e4e' })\n    set_cursor(1, 0)\n    type_keys('f', 'e')\n\n    child[var_type].minijump_disable = true\n    type_keys(';')\n    eq(get_cursor(), { 1, 1 })\n  end,\n})\n\nT['Delayed highlighting'] = new_set({\n  hooks = {\n    pre_case = function()\n      set_lines({ '1e2e', 'e4e5e_' })\n      child.set_size(5, 12)\n    end,\n  },\n})\n\n-- NOTE: Don't use `'f', 't', 'F', 'T'` as parameters because this will lead to\n-- conflicting file names for reference screenshots in case-insensitive OS\nT['Delayed highlighting']['works'] = new_set(\n  { parametrize = { { 'forward' }, { 'forward_till' }, { 'backward' }, { 'backward_till' } } },\n  {\n    test = function(direction)\n      local key = vim.endswith(direction, '_till') and 't' or 'f'\n      key = vim.startswith(direction, 'backward') and key:upper() or key\n\n      set_cursor(1, key == key:lower() and 0 or 3)\n      type_keys(key, 'e')\n\n      sleep(default_highlight_delay - small_time)\n      -- Nothing should yet be shown\n      child.expect_screenshot()\n      sleep(small_time)\n      -- Everything should be shown\n      child.expect_screenshot()\n    end,\n  }\n)\n\nT['Delayed highlighting']['respects `config.delay.highlight`'] = new_set(\n  { parametrize = { { 'forward' }, { 'forward_till' }, { 'backward' }, { 'backward_till' } } },\n  {\n    test = function(direction)\n      local key = vim.endswith(direction, '_till') and 't' or 'f'\n      key = vim.startswith(direction, 'backward') and key:upper() or key\n\n      local new_highlight_delay = 5 * small_time\n      child.lua('MiniJump.config.delay.highlight = ' .. new_highlight_delay)\n\n      set_cursor(1, key == key:lower() and 0 or 3)\n      type_keys(key, 'e')\n\n      sleep(new_highlight_delay - small_time)\n      -- Nothing should yet be shown\n      child.expect_screenshot()\n      sleep(small_time)\n      -- Everything should be shown\n      child.expect_screenshot()\n    end,\n  }\n)\n\nT['Delayed highlighting']['respects `vim.b.minijump_config`'] = function()\n  child.lua('MiniJump.config.delay.highlight = ' .. (5 * small_time))\n  local new_highlight_delay = 3 * small_time\n  child.b.minijump_config = { delay = { highlight = new_highlight_delay } }\n\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n\n  sleep(new_highlight_delay - small_time)\n  -- Nothing should yet be shown\n  child.expect_screenshot()\n  sleep(small_time)\n  -- Everything should be shown\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting']['implements debounce-style delay'] = function()\n  set_lines('1e2e3e')\n  set_cursor(1, 0)\n\n  type_keys('f', 'e')\n  sleep(default_highlight_delay - small_time)\n  -- Nothing should yet be shown\n  child.expect_screenshot()\n\n  type_keys('f')\n  sleep(default_highlight_delay - small_time)\n  -- Nothing should yet be shown (because debounce-style)\n  child.expect_screenshot()\n\n  sleep(small_time)\n  -- Everything should be shown\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting']['stops immediately when not jumping'] = function()\n  type_keys('f', 'e')\n  sleep(default_highlight_delay)\n  -- Should be highlighted\n  child.expect_screenshot()\n\n  type_keys('l')\n  -- Should stop highlighting immediately\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting']['updates immediately within same jumping'] = function()\n  set_lines({ 'e1e2', 'ee' })\n\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n\n  sleep(default_highlight_delay)\n  child.expect_screenshot()\n  type_keys('t')\n  child.expect_screenshot()\n  type_keys('T')\n  -- Last `T` match is highlighted because there is an end of line after it\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting']['never highlights in Insert mode'] = function()\n  child.set_size(5, 15)\n\n  set_lines({ '1e2f' })\n\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n\n  sleep(default_highlight_delay)\n  child.expect_screenshot()\n\n  type_keys('ct', 'f')\n  sleep(default_highlight_delay + small_time)\n  -- Shouldn't start highlighting\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting']['done only if actually jumping'] = function()\n  child.lua('MiniJump.config.delay.highlight = 0')\n\n  -- Mock conditions for automatically stopping jumping\n  child.lua([[\n    local force_jump_stop = vim.schedule_wrap(function(ev) vim.cmd('doautocmd BufLeave') end)\n    vim.api.nvim_create_autocmd('CursorMoved', { once = true, callback = force_jump_stop })\n  ]])\n\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n\n  eq(child.lua_get('MiniJump.state.jumping'), false)\n  -- Nothing should be shown\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting'][\"respects 'ignorecase'\"] = function()\n  child.o.ignorecase = true\n  set_lines({ '1e2E' })\n\n  set_cursor(1, 0)\n  type_keys('f', 'e')\n\n  sleep(default_highlight_delay)\n  -- Should highlight both 'e'and 'E'\n  child.expect_screenshot()\nend\n\nT['Delayed highlighting'][\"respects 'smartcase'\"] = function()\n  child.o.ignorecase = true\n  child.o.smartcase = true\n  set_lines({ '1e2E3e4E' })\n\n  set_cursor(1, 0)\n  type_keys('f', 'E')\n\n  sleep(default_highlight_delay)\n  -- Should highlight only 'E'\n  child.expect_screenshot()\nend\n\nT['Stop jumping after idle'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua('MiniJump.config.delay.idle_stop = ' .. (default_highlight_delay + 2 * small_time))\n      set_lines({ '1e2e3e4e', 'ff' })\n      set_cursor(1, 0)\n      child.set_size(5, 12)\n    end,\n  },\n})\n\nT['Stop jumping after idle']['works'] = function()\n  local idle_stop_delay = child.lua_get('MiniJump.config.delay.idle_stop')\n  type_keys('f', 'e')\n  eq(get_cursor(), { 1, 1 })\n\n  -- It works\n  sleep(idle_stop_delay - small_time)\n  type_keys('f')\n  eq(get_cursor(), { 1, 3 })\n  -- Should highlight (as idle delay is bigger than highlight delay)\n  child.expect_screenshot()\n\n  -- It implements debounce-style delay\n  sleep(idle_stop_delay + small_time)\n  -- It should have stopped jumping and this should initiate new jump\n  type_keys('f', 'f')\n  eq(get_cursor(), { 2, 0 })\n  -- Should also stop highlighting\n  child.expect_screenshot()\nend\n\nT['Stop jumping after idle']['works if should be done before target highlighting'] = function()\n  child.lua('MiniJump.config.delay.idle_stop = ' .. (default_highlight_delay - small_time))\n\n  type_keys('f', 'e')\n  eq(get_cursor(), { 1, 1 })\n  sleep(default_highlight_delay + small_time)\n  -- Should also not trigger highlighting\n  child.expect_screenshot()\nend\n\nT['Stop jumping after idle']['respects `vim.b.minijump_config`'] = function()\n  local idle_stop_delay = child.lua_get('MiniJump.config.delay.idle_stop')\n  local new_idle_stop_delay = idle_stop_delay - 2 * small_time\n  child.b.minijump_config = { delay = { idle_stop = new_idle_stop_delay } }\n  type_keys('f', 'e')\n  sleep(new_idle_stop_delay)\n\n  -- It should have stopped jumping and this should initiate new jump\n  type_keys('f', 'f')\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['Events'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua([[\n        _G.log = {}\n        local pattern = { 'MiniJumpGetTarget', 'MiniJumpStart', 'MiniJumpJump', 'MiniJumpStop' }\n        local add_to_log = function(ev)\n          table.insert(_G.log, { event = ev.match, data = ev.data, state = vim.deepcopy(MiniJump.state) })\n        end\n        vim.api.nvim_create_autocmd('User', { pattern = pattern, callback = add_to_log })\n      ]])\n\n      set_lines({ '11e22e__', '33e44e__', '55e66e__' })\n    end,\n  },\n})\n\nlocal validate_log_and_clean = function(ref_log)\n  eq(child.lua_get('_G.log'), ref_log)\n  child.lua('_G.log = {}')\nend\n\nT['Events']['work'] = function()\n  local state = { mode = 'n', jumping = false, backward = false, till = false, n_times = 1 }\n  type_keys('f')\n  validate_log_and_clean({ { event = 'MiniJumpGetTarget', state = state } })\n\n  type_keys('e')\n  state.jumping, state.target = true, 'e'\n  validate_log_and_clean({\n    { event = 'MiniJumpStart', state = state },\n    { event = 'MiniJumpJump', state = state },\n  })\n\n  local validate_key = function(keys, ref_backward, ref_till)\n    state.backward, state.till = ref_backward, ref_till\n    type_keys(keys)\n    validate_log_and_clean({ { event = 'MiniJumpJump', state = state } })\n  end\n  validate_key('f', false, false)\n  validate_key('F', true, false)\n  validate_key('t', false, true)\n  validate_key('T', true, true)\n\n  state.backward, state.till, state.n_times = false, false, 2\n  type_keys('2f')\n  validate_log_and_clean({ { event = 'MiniJumpJump', state = state } })\n\n  child.lua('MiniJump.stop_jumping()')\n  state.jumping = false\n  validate_log_and_clean({ { event = 'MiniJumpStop', state = state } })\nend\n\nT['Events']['work in Visual and Operator-pending modes'] = function()\n  local validate = function(mode, ref_init_target)\n    local state = { mode = mode, jumping = false, backward = false, till = false, n_times = 1 }\n    state.target = ref_init_target\n\n    local mode_key = mode == 'v' and 'v' or 'd'\n    type_keys(mode_key, 'f')\n    validate_log_and_clean({ { event = 'MiniJumpGetTarget', state = state } })\n\n    type_keys('e')\n    state.mode = mode == 'v' and 'v' or 'nov'\n    state.jumping, state.target = true, 'e'\n    validate_log_and_clean({\n      { event = 'MiniJumpStart', state = state },\n      { event = 'MiniJumpJump', state = state },\n    })\n\n    child.lua('MiniJump.stop_jumping()')\n    state.jumping = false\n    validate_log_and_clean({ { event = 'MiniJumpStop', state = state } })\n\n    type_keys('<Esc>')\n  end\n\n  -- Visual mode\n  validate('v', nil)\n\n  -- Operator-pending mode. In `state` target is preserved as it is cached for\n  -- possible future `;`.\n  validate('no', 'e')\nend\n\nT['Events']['work for automatic jump stop'] = function()\n  -- Moving cursor outside of jumping\n  type_keys('f', 'e')\n  child.lua('_G.log = {}')\n\n  type_keys('l')\n  local state = { target = 'e', mode = 'n', jumping = false, backward = false, till = false, n_times = 1 }\n  validate_log_and_clean({ { event = 'MiniJumpStop', state = state } })\n\n  -- Enter Insert mode\n  type_keys('f', 'e')\n  child.lua('_G.log = {}')\n\n  type_keys('i')\n  validate_log_and_clean({ { event = 'MiniJumpStop', state = state } })\n  type_keys('<Esc>')\n\n  -- Idle stop\n  local idle_stop = 10 * small_time\n  child.lua('MiniJump.config.delay.idle_stop = ' .. idle_stop)\n  type_keys('f', 'e')\n  child.lua('_G.log = {}')\n\n  sleep(idle_stop - small_time)\n  validate_log_and_clean({})\n  sleep(small_time + small_time)\n  validate_log_and_clean({ { event = 'MiniJumpStop', state = state } })\nend\n\nT['Events']['have up to date state before asking for target'] = function()\n  local validate = function(keys, ref_state)\n    type_keys(keys)\n    validate_log_and_clean({ { event = 'MiniJumpGetTarget', state = ref_state } })\n    type_keys('<Esc>', '<Esc>')\n  end\n\n  local state = { mode = 'n', jumping = false, backward = false, till = false, n_times = 1 }\n  validate('f', state)\n\n  state.n_times = 2\n  validate('2f', state)\n  state.n_times = 1\n\n  state.mode, state.backward, state.till = 'v', true, false\n  validate('vF', state)\n\n  state.mode, state.backward, state.till = 'no', false, true\n  validate('dt', state)\nend\n\nT['Events']['work during repeat with `;`'] = function()\n  type_keys('f', 'e')\n  child.lua('MiniJump.stop_jumping()')\n  child.lua('_G.log = {}')\n\n  eq(child.lua_get('MiniJump.state.jumping'), false)\n\n  local state = { mode = 'n', jumping = true, target = 'e', backward = false, till = false, n_times = 1 }\n  type_keys(';')\n  validate_log_and_clean({\n    { event = 'MiniJumpStart', state = state },\n    { event = 'MiniJumpJump', state = state },\n  })\n\n  type_keys(';')\n  validate_log_and_clean({ { event = 'MiniJumpJump', state = state } })\n\n  type_keys('T')\n  state.backward, state.till = true, true\n  validate_log_and_clean({ { event = 'MiniJumpJump', state = state } })\n\n  type_keys(';')\n  validate_log_and_clean({ { event = 'MiniJumpJump', state = state } })\nend\n\nT['Events']['work with dot-repeat'] = function()\n  type_keys('df', 'e')\n  child.lua('MiniJump.stop_jumping()')\n  child.lua('_G.log = {}')\n\n  type_keys('.')\n  local state = { mode = 'nov', jumping = true, target = 'e', backward = false, till = false, n_times = 1 }\n  validate_log_and_clean({\n    { event = 'MiniJumpStart', state = state },\n    { event = 'MiniJumpJump', state = state },\n  })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_jump2d.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('jump2d', config) end\nlocal unload_module = function() child.mini_unload('jump2d') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n--stylua: ignore end\n\n-- Make helpers\n-- Window setups\nlocal setup_windows = function()\n  -- Current tabpage. Create four windows.\n  local win_topleft = child.api.nvim_get_current_win()\n\n  child.cmd('rightbelow split')\n  local win_bottomleft = child.api.nvim_get_current_win()\n\n  child.api.nvim_set_current_win(win_topleft)\n  child.cmd('rightbelow vsplit')\n  local win_topright = child.api.nvim_get_current_win()\n\n  child.api.nvim_set_current_win(win_bottomleft)\n  child.cmd('rightbelow vsplit')\n  local win_bottomright = child.api.nvim_get_current_win()\n\n  -- Other tabpage\n  child.cmd('tabedit')\n  local win_other_tabpage = child.api.nvim_get_current_win()\n\n  -- Construct window table\n  child.api.nvim_set_current_win(win_topleft)\n  local wins = {\n    topleft = win_topleft,\n    bottomleft = win_bottomleft,\n    topright = win_topright,\n    bottomright = win_bottomright,\n    other_tabpage = win_other_tabpage,\n  }\n\n  -- Ensure different buffers with text tailored to buffer id\n  for _, name in ipairs({ 'topleft', 'bottomleft', 'topright', 'bottomright', 'other_tabpage' }) do\n    local win_id = wins[name]\n    local buf_id = child.api.nvim_create_buf(true, false)\n    child.api.nvim_win_set_buf(win_id, buf_id)\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, true, { 'xx' .. buf_id .. 'xx' })\n  end\n\n  return wins\nend\n\nlocal setup_two_windows = function()\n  local win_left = child.api.nvim_get_current_win()\n  child.cmd('rightbelow vsplit aaa')\n  local win_right = child.api.nvim_get_current_win()\n\n  child.api.nvim_set_current_win(win_left)\n  local wins = { left = win_left, right = win_right }\n\n  for _, win_name in ipairs({ 'left', 'right' }) do\n    local buf_id = child.api.nvim_create_buf(true, false)\n    local l = 'xx' .. buf_id .. 'xx'\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, true, { l, l, l })\n\n    local win_id = wins[win_name]\n    child.api.nvim_win_set_buf(win_id, buf_id)\n    child.api.nvim_win_set_cursor(win_id, { 2, 0 })\n  end\n\n  return wins\nend\n\n-- Time constants\nlocal reminder_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n\n      -- Make `start()` non-blocking to be able to execute tests. Otherwise it\n      -- will block child state waiting for `getcharstr()` to finish.\n      child.lua('MiniJump2d.start = vim.schedule_wrap(MiniJump2d.start)')\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniJump2d)'), 'table')\n\n  -- Autocommand group (with default config)\n  eq(child.fn.exists('#MiniJump2d'), 1)\n\n  -- Highlight groups, depending on background\n  child.cmd('hi clear')\n  child.o.background = 'dark'\n  reload_module()\n  expect.match(child.cmd_capture('hi MiniJump2dSpot'), 'gui=bold,nocombine guifg=[Ww]hite guibg=[Bb]lack')\n\n  child.cmd('hi clear MiniJump2dSpot')\n\n  child.o.background = 'light'\n  reload_module()\n  expect.match(child.cmd_capture('hi MiniJump2dSpot'), 'gui=bold,nocombine guifg=[Bb]lack guibg=[Ww]hite')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniJump2d.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniJump2d.config.' .. field), value) end\n\n  expect_config('spotter', vim.NIL)\n  expect_config('labels', 'abcdefghijklmnopqrstuvwxyz')\n  expect_config('view', { dim = false, n_steps_ahead = 0 })\n  expect_config(\n    'allowed_lines',\n    { blank = true, cursor_before = true, cursor_at = true, cursor_after = true, fold = true }\n  )\n  expect_config('allowed_windows', { current = true, not_current = true })\n  expect_config('hooks', { before_start = nil, after_jump = nil })\n  expect_config('mappings', { start_jumping = '<CR>' })\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ labels = 'a' })\n  eq(child.lua_get('MiniJump2d.config.labels'), 'a')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ spotter = 'a' }, 'spotter', 'function')\n  expect_config_error({ labels = 1 }, 'labels', 'string')\n  expect_config_error({ view = 1 }, 'view', 'table')\n  expect_config_error({ view = { dim = 'a' } }, 'view.dim', 'boolean')\n  expect_config_error({ view = { n_steps_ahead = 'a' } }, 'view.n_steps_ahead', 'number')\n  expect_config_error({ allowed_lines = 'a' }, 'allowed_lines', 'table')\n  expect_config_error({ allowed_lines = { blank = 1 } }, 'allowed_lines.blank', 'boolean')\n  expect_config_error({ allowed_lines = { cursor_before = 1 } }, 'allowed_lines.cursor_before', 'boolean')\n  expect_config_error({ allowed_lines = { cursor_at = 1 } }, 'allowed_lines.cursor_at', 'boolean')\n  expect_config_error({ allowed_lines = { cursor_after = 1 } }, 'allowed_lines.cursor_after', 'boolean')\n  expect_config_error({ allowed_lines = { fold = 1 } }, 'allowed_lines.fold', 'boolean')\n  expect_config_error({ allowed_windows = 'a' }, 'allowed_windows', 'table')\n  expect_config_error({ allowed_windows = { current = 'a' } }, 'allowed_windows.current', 'boolean')\n  expect_config_error({ allowed_windows = { not_current = 'a' } }, 'allowed_windows.not_current', 'boolean')\n  expect_config_error({ hooks = 'a' }, 'hooks', 'table')\n  expect_config_error({ hooks = { before_start = 1 } }, 'hooks.before_start', 'function')\n  expect_config_error({ hooks = { after_jump = 1 } }, 'hooks.after_jump', 'function')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { start_jumping = 1 } }, 'mappings.start_jumping', 'string')\n  expect_config_error({ silent = 'a' }, 'silent', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniJump2dSpot'), 'gui=bold,nocombine guifg=[Ww]hite guibg=[Bb]lack')\nend\n\nT['setup()']['applies `config.mappings`'] = function()\n  child.set_size(5, 12)\n  set_lines({ 'xxxx', 'xxxx' })\n  type_keys('<CR>')\n  child.expect_screenshot()\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('nmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('<CR>', '2d'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('n', '<CR>')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { start_jumping = '' } })\n  eq(has_map('<CR>', '2d'), false)\nend\n\nT['setup()']['resets <CR> mapping in quickfix window'] = function()\n  child.set_size(20, 50)\n  set_lines({ 'Hello World' })\n  child.cmd([[cexpr ['Hello', 'Quickfix'] | copen]])\n  -- Should create not remappable buffer-local mapping\n  expect.match(child.cmd_capture('nmap <CR>'), '%*@<CR>')\nend\n\nT['setup()']['resets <CR> mapping in command-line window'] = function()\n  type_keys([[:call append(0, 'Hello')<CR>]])\n  set_lines({})\n  type_keys('q:')\n  set_cursor(1, 0)\n  type_keys('<CR>')\n  eq(child.get_lines(), { 'Hello', '' })\nend\n\nT['start()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Reference lines:\n      -- xxxx\n      --\n      -- xxxx\n      set_lines({ 'xxxx', '', 'xxxx' })\n      child.set_size(5, 12)\n    end,\n  },\n})\n\nlocal start = function(...)\n  child.lua('MiniJump2d.start(...)', { ... })\n  child.poke_eventloop()\nend\n\nT['start()']['works'] = function()\n  local init_curpos = get_cursor()\n\n  start()\n  child.expect_screenshot()\n  type_keys('e')\n  eq(get_cursor(), { 3, 3 })\n  child.expect_screenshot()\n\n  -- Adds previous position to jumplist\n  type_keys('<C-o>')\n  eq(get_cursor(), init_curpos)\nend\n\nT['start()']['works in Visual mode'] = function()\n  child.set_size(5, 40)\n  child.o.showcmd = false\n\n  type_keys('v')\n\n  start()\n  child.expect_screenshot()\n  type_keys('d')\n  eq(get_cursor(), { 3, 0 })\n  child.expect_screenshot()\n\n  eq(child.api.nvim_get_mode().mode, 'v')\nend\n\nT['start()']['works in Operator-pending mode'] = function()\n  -- Reload module to revert `start()` to being blocking\n  reload_module()\n\n  type_keys('d')\n  -- Use default mapping to fully imitate Operator-pending mode (and it doesn't\n  -- work otherwise)\n  type_keys('<CR>')\n  child.expect_screenshot()\n  type_keys('b')\n\n  child.cmd('redrawstatus')\n  child.expect_screenshot()\n\n  -- Allows dot-repeat\n  type_keys('.')\n  child.expect_screenshot()\n  type_keys('c')\n  child.expect_screenshot()\nend\n\nT['start()']['highlights unique labels with different highlight group'] = function()\n  child.cmd('hi MiniJump2dSpotUnique guifg=Green')\n  start({ labels = 'jk' })\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['start()']['uses only visible lines'] = function()\n  -- Check this only on Neovim>=0.11, as there is a slight change in\n  -- highlighting command line area\n  if child.fn.has('nvim-0.11') == 0 then return end\n\n  set_lines({ '1xxx', '2xxx', '3xxx', '4xxx' })\n\n  -- Make window show only lines 2 and 3\n  child.api.nvim_win_set_height(0, 2)\n  set_cursor(2, 0)\n  type_keys('zt')\n  child.expect_screenshot()\n\n  -- Validate\n  start()\n  child.expect_screenshot()\n  type_keys('d')\n  eq(get_cursor(), { 3, 3 })\nend\n\nT['start()']['ignores cursor position during label computation'] = new_set({\n  parametrize = { { 1, 1 }, { 2, 0 }, { 3, 0 }, { 3, 3 } },\n}, {\n  test = function(line, col)\n    child.api.nvim_win_set_cursor(0, { line, col })\n    start()\n    -- All screenshots should have same labels and spots\n    child.expect_screenshot()\n  end,\n})\n\nT['start()']['uses `<CR>` to jump to first available spot'] = function()\n  child.set_size(5, 20)\n  local win_width = child.fn.winwidth(0)\n  local line = string.rep('- ', math.floor(0.5 * win_width))\n  set_lines(vim.fn['repeat']({ line }, child.fn.winheight(0)))\n\n  -- On first step\n  set_cursor(1, 9)\n  start()\n  type_keys('<CR>')\n  eq(get_cursor(), { 1, 0 })\n\n  -- On later steps\n  set_cursor(1, 9)\n  start()\n  -- Spots should be labeled `a a b b c c ...`\n  child.expect_screenshot()\n  type_keys(1, 'b', '<CR>')\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['start()']['jumps immediately to single spot'] = function()\n  set_lines({ '  x' })\n  set_cursor(1, 0)\n\n  start()\n  eq(get_cursor(), { 1, 2 })\n  -- No spots should be shown\n  child.expect_screenshot()\nend\n\nT['start()']['shows reminder after one idle second'] = function()\n  -- Helps create hit-enter-prompt\n  child.set_size(5, 60)\n\n  child.lua([[MiniJump2d.config.labels = 'jk']])\n\n  start()\n  sleep(reminder_delay + small_time)\n\n  -- Should show helper message without adding it to `:messages` and causing\n  -- hit-enter-prompt\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\n\n  -- Should clean afterwards\n  type_keys('j')\n  sleep(small_time)\n  child.expect_screenshot()\n\n  -- Should show message for every key in sequence\n  sleep(reminder_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['start()']['stops jumping if not label was typed'] = new_set({\n  -- <C-c> shouldn't result into error\n  parametrize = { { '<Down>' }, { '<Esc>' }, { '<C-c>' } },\n}, {\n  test = function(key)\n    set_cursor(1, 0)\n    start()\n\n    type_keys(key)\n\n    -- Cursor shouldn't move\n    eq(get_cursor(), { 1, 0 })\n    -- No highlighting should be shown\n    child.expect_screenshot()\n  end,\n})\n\nT['start()']['ignores current window during label computation'] = new_set({\n  parametrize = { { 'topright' }, { 'bottomleft' } },\n}, {\n  test = function(window_name)\n    child.set_size(10, 50)\n    local wins = setup_windows()\n    child.api.nvim_set_current_win(wins[window_name])\n\n    start()\n    -- Should have same labels even with different current windows\n    child.expect_screenshot()\n  end,\n})\n\nT['start()']['uses only all visible windows by default'] = function()\n  child.set_size(10, 50)\n  setup_windows()\n\n  local cur_win_id, cur_pos = child.api.nvim_get_current_win(), child.api.nvim_win_get_cursor(0)\n  start()\n  child.expect_screenshot()\n\n  -- There should be labels from 'a' to 'h'. Typing `i` should not take effect.\n  type_keys('i')\n  eq(child.api.nvim_get_current_win(), cur_win_id)\n  eq(child.api.nvim_win_get_cursor(0), cur_pos)\nend\n\nT['start()']['traverses visible \"regular\" windows based on their layout'] = function()\n  child.set_size(10, 50)\n  local wins = setup_windows()\n\n  -- Make topright window be \"on the right\" of bottomright\n  child.api.nvim_set_current_win(wins.topright)\n  child.cmd('vertical resize -1')\n  child.api.nvim_set_current_win(wins.topleft)\n\n  start()\n  -- Order should be top to bottom, left to right\n  -- Topright is on the right of bottomright, so labels are processed later\n  child.expect_screenshot()\nend\n\nT['start()']['traverses floating windows at the end'] = function()\n  -- Set up windows and buffers\n  local buf_regular = child.api.nvim_get_current_buf()\n  local win_regular = child.api.nvim_get_current_win()\n  local buf_floating = child.api.nvim_create_buf(true, false)\n  local win_floating = child.api.nvim_open_win(\n    buf_floating,\n    false,\n    { relative = 'win', win = win_regular, width = 4, height = 1, row = 0, col = 0 }\n  )\n\n  child.api.nvim_buf_set_lines(buf_regular, 0, -1, true, { 'xxxx', 'xxxx' })\n  child.api.nvim_buf_set_lines(buf_floating, 0, -1, true, { 'xxxx' })\n\n  -- Both windows have same \"positions\" but different \"zindex\"\n  eq(child.api.nvim_win_get_position(win_regular), child.api.nvim_win_get_position(win_floating))\n\n  start()\n  child.expect_screenshot()\nend\n\nT['start()']['overrides `config` from `opts` argument'] = function()\n  child.lua([[MiniJump2d.config.labels = 'jk']])\n  start({ allowed_lines = { blank = false } })\n  child.expect_screenshot()\nend\n\nT['start()']['respects `spotter`'] = function()\n  child.lua('MiniJump2d.start({ spotter = function() return { 1 } end })')\n  child.expect_screenshot()\n\n  child.lua('MiniJump2d.stop()')\n  child.lua('vim.b.minijump2d_config = { spotter = function() return { 2 } end }')\n  child.lua('MiniJump2d.start()')\n  child.expect_screenshot()\nend\n\nT['start()']['uses `spotter` with correct arguments'] = function()\n  child.set_size(5, 40)\n\n  -- Set up windows and buffers. One with empty line, other - with fold\n  local win_init, buf_init = child.api.nvim_get_current_win(), child.api.nvim_get_current_buf()\n  child.api.nvim_buf_set_lines(buf_init, 0, -1, true, { 'xxxx', '', 'xxxx' })\n\n  child.cmd('rightbelow vsplit aaa')\n  local win_other, buf_other = child.api.nvim_get_current_win(), child.api.nvim_get_current_buf()\n  child.api.nvim_buf_set_lines(buf_other, 0, -1, true, { 'yyyy', 'yyyy', 'yyyy' })\n\n  set_cursor(2, 0)\n  type_keys('zf', 'j')\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n  set_cursor(1, 0)\n\n  child.api.nvim_set_current_win(win_init)\n\n  -- Validate. `spotter` should be called with signature:\n  -- `<line number>, {win_id = <number>, win_id_init = <number>}`\n  -- Shouldn't be called on blank and fold lines\n  child.lua('_G.args_history = {}')\n  child.lua([[\n    MiniJump2d.start({\n      labels = 'jk',\n      spotter = function(...) table.insert(_G.args_history, { ... }); return { 1 } end\n    })]])\n  eq(child.lua_get('_G.args_history'), {\n    { 1, { win_id = win_init, win_id_init = win_init } },\n    -- Line 2 is blank, shouldn't be called\n    { 3, { win_id = win_init, win_id_init = win_init } },\n    { 1, { win_id = win_other, win_id_init = win_init } },\n    -- Lines 2 and 3 are folded, shouldn't be called\n  })\n  child.expect_screenshot()\n\n  -- Should call `spotter` only on jumped start, not on every step\n  child.lua('_G.args_history = {}')\n  type_keys(1, 'j', '<CR>')\n  eq(child.lua_get('_G.args_history'), {})\nend\n\nT['start()']['respects `labels`'] = function()\n  set_cursor(1, 0)\n  start({ labels = 'jk' })\n  child.expect_screenshot()\n  type_keys('j', 'k')\n  eq(get_cursor(), { 2, 0 })\n\n  -- Should also use buffer local config\n  child.lua('MiniJump2d.stop()')\n  child.b.minijump2d_config = { labels = 'ab' }\n  start()\n  child.expect_screenshot()\nend\n\nT['start()']['respects `view.dim`'] = function()\n  -- In argument\n  start({ labels = 'jk', view = { dim = true } })\n\n  type_keys('j')\n  -- Whole lines with at least one jump spot should be highlighted differently\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\n  child.lua('MiniJump2d.stop()')\n\n  -- In global config\n  child.lua('MiniJump2d.config.view.dim = true')\n  start({ labels = 'jk' })\n  type_keys('j', 'j')\n  child.expect_screenshot()\nend\n\nT['start()']['respects `view.n_steps_ahead`'] = function()\n  -- In argument\n  start({ labels = 'jk', view = { n_steps_ahead = 1 } })\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\n\n  type_keys('k')\n  eq(get_cursor(), { 1, 3 })\n\n  -- In global config\n  child.lua('MiniJump2d.config.view.n_steps_ahead = 2')\n  start({ labels = 'jk' })\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['start()']['handles very big `view.n_steps_ahead`'] = function()\n  start({ labels = 'jk', view = { n_steps_ahead = math.huge } })\n  child.expect_screenshot()\n  child.lua('MiniJump2d.stop()')\n\n  start({ labels = 'hjkl', view = { n_steps_ahead = math.huge } })\n  child.expect_screenshot()\nend\n\nT['start()']['handles overlapping multi-step labels'] = function()\n  child.lua([[MiniJump2d.config.spotter = MiniJump2d.gen_spotter.pattern('.')]])\n  start({ labels = 'jk', view = { n_steps_ahead = 2 } })\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\n\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['start()']['respects `allowed_lines.blank`'] = function()\n  start({ allowed_lines = { blank = false } })\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  child.lua('MiniJump2d.stop()')\n  child.b.minijump2d_config = { allowed_lines = { blank = true } }\n  start()\n  child.expect_screenshot()\nend\n\nT['start()']['respects `allowed_lines.cursor_*`'] = new_set({\n  parametrize = { { 'cursor_before' }, { 'cursor_at' }, { 'cursor_after' } },\n}, {\n  test = function(option_name)\n    child.set_size(5, 40)\n\n    -- Should affect all allowed windows and their cursor position\n    setup_two_windows()\n\n    local opts = { allowed_lines = {} }\n    opts.allowed_lines[option_name] = false\n    start(opts)\n    child.expect_screenshot()\n\n    -- Should also use buffer local config\n    child.lua('MiniJump2d.stop()')\n    opts.allowed_lines[option_name] = true\n    child.b.minijump2d_config = opts\n    start()\n    child.expect_screenshot()\n  end,\n})\n\nT['start()']['respects folds'] = function()\n  -- Make fold on lines 2-3\n  set_cursor(2, 0)\n  type_keys('zf', 'j')\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n  set_cursor(1, 0)\n\n  -- Validate\n  start()\n  child.expect_screenshot()\n\n  -- Folds should still be present\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n\n  -- After jump should open enough folds to show cursor\n  type_keys('c')\n  child.expect_screenshot()\n  eq(get_cursor(), { 2, 0 })\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { -1, -1 })\nend\n\nT['start()']['respects `allowed_lines.fold`'] = function()\n  -- Make fold on lines 2-3\n  set_cursor(2, 0)\n  type_keys('zf', 'j')\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n  set_cursor(1, 0)\n\n  -- Validate\n  start({ allowed_lines = { fold = false } })\n  child.expect_screenshot()\n\n  -- Should also use buffer local config\n  child.lua('MiniJump2d.stop()')\n  child.b.minijump2d_config = { allowed_lines = { fold = true } }\n  start()\n  child.expect_screenshot()\nend\n\nT['start()']['respects `allowed_windows`'] = new_set({\n  parametrize = { { { current = false } }, { { not_current = false } }, { { current = false, not_current = false } } },\n}, {\n  test = function(allowed_windows_opts)\n    -- Check this only on Neovim>=0.11, as there is a slight change in\n    -- highlighting command line area\n    if child.fn.has('nvim-0.11') == 0 then return end\n\n    child.set_size(6, 40)\n    -- Make all showed messages full width\n    child.o.cmdheight = 2\n\n    local wins = setup_two_windows()\n    child.api.nvim_set_current_win(wins.left)\n\n    start({ allowed_windows = allowed_windows_opts })\n    child.expect_screenshot()\n\n    -- Shouldn't error in this case\n    if allowed_windows_opts.current == false and allowed_windows_opts.not_current == false then\n      eq(get_latest_message(), '(mini.jump2d) No spots to show.')\n    end\n\n    -- Should also use buffer local config\n    child.lua('MiniJump2d.stop()')\n    local opts = vim.deepcopy(allowed_windows_opts)\n    opts.current, opts.not_current = not opts.current, not opts.not_current\n    child.b.minijump2d_config = opts\n    start()\n    child.expect_screenshot()\n  end,\n})\n\nT['start()']['ignores not focusable windows'] = function()\n  child.set_size(6, 40)\n\n  local create_float = function(focusable, col)\n    local buf_id = child.api.nvim_create_buf(false, true)\n    local l = 'xx' .. buf_id .. 'xx'\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, true, { l, l, l })\n    local config = { relative = 'editor', row = 0, col = col, height = 3, width = 10, focusable = focusable }\n    child.api.nvim_open_win(buf_id, false, config)\n  end\n\n  setup_two_windows()\n  create_float(false, 9)\n  create_float(true, 29)\n\n  start({ allowed_windows = { current = true, not_current = true } })\n  child.expect_screenshot()\nend\n\nT['start()']['respects `hooks`'] = function()\n  child.lua('_G.n_before_start = 0; _G.n_after_jump = 0')\n\n  child.lua([[MiniJump2d.start({\n      hooks = {\n        before_start = function() _G.n_before_start = _G.n_before_start + 1 end,\n        after_jump = function() _G.n_after_jump = _G.n_after_jump + 1 end,\n      },\n    })]])\n  eq(child.lua_get('{ _G.n_before_start, _G.n_after_jump }'), { 1, 0 })\n  type_keys('<CR>')\n  eq(child.lua_get('{ _G.n_before_start, _G.n_after_jump }'), { 1, 1 })\n\n  child.lua('MiniJump2d.stop()')\n  child.lua([[vim.b.minijump2d_config = {\n    hooks = { before_start = function() _G.n_before_start = _G.n_before_start + 10 end }\n  }]])\n  start()\n  eq(child.lua_get('{ _G.n_before_start, _G.n_after_jump }'), { 11, 1 })\n  type_keys('<CR>')\n  eq(child.lua_get('{ _G.n_before_start, _G.n_after_jump }'), { 11, 1 })\nend\n\nT['start()']['allows `hook.before_start` to modify spotter'] = function()\n  child.lua('_G.opts = { spotter = function() return { 1 } end }')\n  child.lua([[_G.opts.hooks = {\n      before_start = function()\n        _G.opts.spotter = function() return { 2 } end\n      end\n    }]])\n\n  set_lines({ 'xxxx', 'xxxx' })\n  child.lua('MiniJump2d.start(_G.opts)')\n  child.expect_screenshot()\nend\n\nT['start()']['does not call `hook.after_jump` on jump cancel'] = new_set({\n  parametrize = {\n    { function() child.lua('MiniJump2d.stop()') end },\n    { function() type_keys('<Esc>') end },\n    { function() type_keys('<C-c>') end },\n  },\n}, {\n  test = function(cancel_action)\n    child.lua('_G.n_after_jump = 0')\n\n    child.lua([[\n      MiniJump2d.start({\n        hooks = { after_jump = function() _G.n_after_jump = _G.n_after_jump + 1 end },\n      })]])\n\n    eq(child.lua_get('_G.n_after_jump'), 0)\n    cancel_action()\n    eq(child.lua_get('_G.n_after_jump'), 0)\n  end,\n})\n\nlocal validate_hl_group = function(hl_group, hl_group_ahead)\n  local ns_id = child.api.nvim_get_namespaces()['MiniJump2dSpots']\n  local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n\n  local all_correct, all_correct_ahead = true, true\n  for _, e_mark in ipairs(extmarks) do\n    local virt_text = e_mark[4].virt_text\n    if virt_text[1][2] ~= hl_group then all_correct = false end\n    if virt_text[2] ~= nil and virt_text[2][2] ~= hl_group_ahead then all_correct_ahead = false end\n  end\n\n  eq(all_correct, true)\n  eq(all_correct_ahead, true)\nend\n\nT['start()']['uses `MiniJump2dSpot` highlight group for next step by default'] = function()\n  start({ labels = 'jk' })\n  validate_hl_group('MiniJump2dSpot')\nend\n\nT['start()']['respects `opts.hl_group`'] = function()\n  start({ labels = 'jk', hl_group = 'Search' })\n  validate_hl_group('Search')\nend\n\nT['start()']['uses `MiniJump2dSpotAhead` highlight group by default'] = function()\n  start({ labels = 'jk', view = { n_steps_ahead = 1 } })\n  validate_hl_group('MiniJump2dSpot', 'MiniJump2dSpotAhead')\nend\n\nT['start()']['respects `opts.hl_group_ahead`'] = function()\n  start({ labels = 'jk', view = { n_steps_ahead = 1 }, hl_group_ahead = 'Search' })\n  validate_hl_group('MiniJump2dSpot', 'Search')\nend\n\nT['start()']['uses `MiniJump2dSpotUnique` highlight group for spots with unique next step'] = function()\n  start()\n  validate_hl_group('MiniJump2dSpotUnique')\nend\n\nT['start()']['respects `opts.hl_group_unique`'] = function()\n  start({ hl_group_unique = 'Search' })\n  validate_hl_group('Search')\nend\n\nT['start()']['uses `MiniJump2dDim` highlight group by default'] = function()\n  local validate = function(line_numbers)\n    local ns_id = child.api.nvim_get_namespaces()['MiniJump2dDim']\n    local extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })\n\n    for i, e_mark in ipairs(extmarks) do\n      eq(e_mark[2], line_numbers[i] - 1)\n    end\n  end\n\n  start({ labels = 'jk', view = { dim = true } })\n  validate({ 1, 2, 3 })\n\n  type_keys('j')\n  validate({ 1, 2 })\n\n  type_keys('j')\n  validate({ 1 })\nend\n\nT['start()']['respects `opts.hl_group_dim`'] = function()\n  -- At the moment, `nvim_buf_get_extmarks(..., { details = true })` doesn't\n  -- return highlight group specified via `opts.line_hl_group`. So instead test\n  -- directly by comparing highlighting in screenshot (should be different).\n  local ns_id = child.api.nvim_create_namespace('test-dim')\n  --stylua: ignore\n  child.api.nvim_buf_set_extmark(\n    0, ns_id, 2, 0,\n    { hl_mode = 'combine', virt_text_pos = 'overlay', virt_text = { { 'dim', 'MiniJump2dDim' } } }\n  )\n\n  start({ labels = 'jk', view = { dim = true }, hl_group_dim = 'Search' })\n  type_keys('j', 'j')\n\n  -- Highlighting for first and second whole lines and first three columns of\n  -- third line should be different: first is 'Search', second is 'Normal',\n  -- third is 'MiniJump2dDim'.\n  child.expect_screenshot()\nend\n\nT['start()']['respects `vim.{g,b}.minijump2d_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minijump2d_disable = true\n\n    start()\n    -- No spots should be shown\n    child.expect_screenshot()\n  end,\n})\n\nT['start()']['respects `config.silent`'] = function()\n  child.lua('MiniJump2d.config.silent = true')\n  child.set_size(10, 20)\n\n  start()\n  sleep(reminder_delay + small_time)\n\n  -- Should not show helper message\n  child.expect_screenshot()\nend\n\nT['stop()'] = new_set()\n\nT['stop()']['works'] = function()\n  child.set_size(10, 12)\n\n  set_lines({ 'xxxx', 'xxxx' })\n  child.lua('MiniJump2d.start()')\n  child.expect_screenshot()\n\n  child.lua('MiniJump2d.stop()')\n  child.expect_screenshot()\nend\n\nT['stop()']['clears all highlighting'] = function()\n  child.set_size(6, 12)\n\n  set_lines({ 'xxxx', 'xxxx', '' })\n  start({ view = { dim = true, n_steps_ahead = 1 }, allowed_lines = { blank = false } })\n  child.expect_screenshot()\n\n  child.lua('MiniJump2d.stop()')\n  child.expect_screenshot()\nend\n\nT['stop()']['works even if not jumping'] = function()\n  -- Shouldn't move\n  local init_cursor = get_cursor()\n  expect.no_error(function() child.lua('MiniJump2d.stop()') end)\n  eq(get_cursor(), init_cursor)\nend\n\nT['gen_spotter'] = new_set()\n\nT['gen_spotter']['pattern()'] = new_set({\n  hooks = {\n    pre_case = function()\n      set_lines({ 'xxx x_x x.x xxx' })\n      child.set_size(5, 20)\n    end,\n  },\n})\n\nlocal start_gen_pattern = function(pattern, side)\n  local command = string.format(\n    [[MiniJump2d.start({ spotter = MiniJump2d.gen_spotter.pattern(%s, %s) })]],\n    vim.inspect(pattern),\n    vim.inspect(side)\n  )\n  child.lua(command)\nend\n\nT['gen_spotter']['pattern()']['works'] = function()\n  start_gen_pattern(nil, nil)\n  -- By default it matches group of non-whitespace non-punctuation\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['pattern()']['respects `pattern` argument'] = function()\n  start_gen_pattern('%s', nil)\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['pattern()']['respects `side` argument'] = new_set({\n  parametrize = { { '%S+', 'start' }, { '%S+', 'end' }, { '.().', 'none' } },\n}, {\n  test = function(pattern, side)\n    start_gen_pattern(pattern, side)\n    child.expect_screenshot()\n  end,\n})\n\nT['gen_spotter']['pattern()']['handles patterns with \"^\" and \"$\"'] = new_set({\n  parametrize = {\n    { '^...', 'start' },\n    { '^...', 'end' },\n    { '^.()..', 'none' },\n    { '...$', 'start' },\n    { '...$', 'end' },\n    { '.()..$', 'none' },\n  },\n}, {\n  test = function(pattern, side)\n    set_lines({ 'xxx xxx', '', 'xx' })\n    start_gen_pattern(pattern, side)\n    child.expect_screenshot()\n  end,\n})\n\nT['gen_spotter']['pattern()']['works with multibyte characters'] = function()\n  set_lines({ 'ы ыыы ы_ы ыы' })\n  start_gen_pattern('%S')\n  child.expect_screenshot()\n\n  child.lua('MiniJump2d.stop()')\n\n  -- It should also work with three and four byte characters\n  set_lines({ '███ 🬤🬤🬤 🬤█🬤 █🬤🬤🬤█' })\n  start_gen_pattern('%S')\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['pattern()']['works in edge cases'] = function()\n  start_gen_pattern('.%f[%W]')\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['vimpattern'] = new_set({\n  hooks = {\n    pre_case = function()\n      set_lines({ 'x x xx_xx xx.xx xxx' })\n      child.set_size(5, 20)\n    end,\n  },\n})\n\nlocal start_gen_vimpattern = function(pattern)\n  local command =\n    string.format([[MiniJump2d.start({ spotter = MiniJump2d.gen_spotter.vimpattern(%s) })]], vim.inspect(pattern))\n  child.lua(command)\nend\n\nT['gen_spotter']['vimpattern']['works'] = function()\n  start_gen_vimpattern()\n  child.expect_screenshot()\n  child.lua('MiniJump2d.stop()')\n\n  child.o.iskeyword = child.o.iskeyword .. ',.'\n  start_gen_vimpattern()\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['vimpattern']['respects `pattern` argument'] = function()\n  start_gen_vimpattern('\\\\k*\\\\zs\\\\k')\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['vimpattern']['works with multibyte characters'] = function()\n  set_lines({ 'ы ыыы ы_ы ыы.ыы ыы' })\n  start_gen_vimpattern()\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['vimpattern']['works with anchored patterns'] = function()\n  child.set_size(7, 20)\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { 'xxx xxx', 'xxx xxx', 'xx' })\n\n  local validate = function(pattern)\n    start_gen_vimpattern(pattern)\n    child.expect_screenshot()\n    child.lua('MiniJump2d.stop()')\n  end\n\n  validate('^')\n  validate('$')\n  validate('^...\\\\zs')\n  validate('\\\\zs...$')\nend\n\nT['gen_spotter']['union()'] = new_set()\n\nT['gen_spotter']['union()']['works'] = function()\n  child.set_size(5, 25)\n\n  child.lua([[\n    local nonblank_start = MiniJump2d.gen_spotter.pattern('%S+', 'start')\n    _G.args_log = {}\n    _G.spotter_1 = function(...)\n      table.insert(_G.args_log, { ... })\n      return nonblank_start(...)\n    end\n\n    local word_start = MiniJump2d.gen_spotter.pattern('%w+', 'start')\n    _G.spotter_2 = function(...)\n      table.insert(_G.args_log, { ... })\n      return word_start(...)\n    end\n\n    _G.union_spotter = MiniJump2d.gen_spotter.union(_G.spotter_1, _G.spotter_2)\n  ]])\n\n  set_lines({ 'xxx x_x x_x xxx' })\n  child.lua('MiniJump2d.start({spotter = _G.union_spotter})')\n  child.expect_screenshot()\nend\n\nT['gen_spotter']['union()']['validates arguments'] = function()\n  expect.error(\n    function() child.lua('MiniJump2d.gen_spotter.union(function() end, 1, function() end)') end,\n    'All.*callable'\n  )\nend\n\nT['gen_spotter']['union()']['works with no arguments'] = function()\n  child.lua('_G.spotter = MiniJump2d.gen_spotter.union()')\n\n  set_lines({ 'xxx x_x x_x xxx' })\n  eq(child.lua_get('_G.spotter(1, {})'), {})\nend\n\nT['default_spotter()'] = new_set({\n  hooks = {\n    pre_case = function() child.set_size(5, 25) end,\n  },\n})\n\nlocal start_default_spotter = function() child.lua('MiniJump2d.start({ spotter = MiniJump2d.default_spotter })') end\n\nT['default_spotter()']['works'] = function()\n  set_lines({ 'xxx x_x (x) xXXx xXXX' })\n  start_default_spotter()\n  child.expect_screenshot()\nend\n\nT['default_spotter()']['spots start and end of words'] = function()\n  set_lines({ 'x xx xxx' })\n  start_default_spotter()\n  child.expect_screenshot()\nend\n\nT['default_spotter()']['spots before and after punctuation'] = function()\n  set_lines({ 'xxx_____xxx (x)' })\n  start_default_spotter()\n  child.expect_screenshot()\nend\n\nT['default_spotter()']['spots first capital letter'] = function()\n  set_lines({ 'XxxXXxxXXXx' })\n  start_default_spotter()\n  child.expect_screenshot()\nend\n\nT['default_spotter()']['correctly merges \"overlapping\" spots'] = function()\n  set_lines({ 'XX () X_X' })\n  start_default_spotter()\n  child.expect_screenshot()\nend\n\nT['default_spotter()']['works (almost) with multibyte character'] = function()\n  set_lines({ 'ы ыы ыыы ы_ы ыЫыы' })\n  start_default_spotter()\n  -- NOTE: ideally it should end with 'hi j' but 'Ы' is not recognized as\n  -- capital letter in Lua patterns (because of different locale)\n  child.expect_screenshot()\nend\n\nT['builtin_opts.line_start'] = new_set({ hooks = { pre_case = function() child.set_size(5, 12) end } })\n\nT['builtin_opts.line_start']['works'] = function()\n  set_lines({ 'xxx', '  xxx', '' })\n  child.lua('MiniJump2d.start(MiniJump2d.builtin_opts.line_start)')\n  child.expect_screenshot()\n\n  -- It should jump to first non-blank character\n  type_keys('b')\n  eq(get_cursor(), { 2, 2 })\nend\n\nT['builtin_opts.word_start'] = new_set({ hooks = { pre_case = function() child.set_size(5, 20) end } })\n\nT['builtin_opts.word_start']['works'] = function()\n  set_lines({ 'x xx xx.xx _xx' })\n  child.lua('MiniJump2d.start(MiniJump2d.builtin_opts.word_start)')\n  child.expect_screenshot()\n  child.lua('MiniJump2d.stop()')\n\n  -- Should respect 'iskeyword' when computing word boundaries\n  child.o.iskeyword = child.o.iskeyword .. ',.'\n  child.lua('MiniJump2d.start(MiniJump2d.builtin_opts.word_start)')\n  child.expect_screenshot()\nend\n\nT['builtin_opts.word_start']['works with multibyte characters'] = function()\n  set_lines({ 'ы ыы ыы.ыы _ыы' })\n  child.lua('MiniJump2d.start(MiniJump2d.builtin_opts.word_start)')\n  child.expect_screenshot()\nend\n\n-- NOTE: For some reason, testing with screenshots is flaky when user input is\n-- involved. Test with moving cursor instead.\nT['builtin_opts.single_character'] = new_set()\n\nlocal start_single_char = function() child.lua_notify('MiniJump2d.start(MiniJump2d.builtin_opts.single_character)') end\n\nT['builtin_opts.single_character']['works'] = function()\n  set_lines({ 'x_x y_y yyy' })\n  start_single_char()\n  type_keys(10, 'y', 'b')\n  eq(get_cursor(), { 1, 6 })\nend\n\nT['builtin_opts.single_character']['works multibyte characters'] = function()\n  set_lines({ 'xx ыы' })\n\n  start_single_char()\n  type_keys(10, 'ы', 'b')\n  -- Here 5 is a byte column for second 'ы'\n  eq(get_cursor(), { 1, 5 })\nend\n\nT['builtin_opts.single_character']['works with problematic characters'] = new_set({\n  parametrize = { { '.' }, { '%' } },\n}, {\n  test = function(key)\n    set_lines({ 'xxx ' .. key .. key })\n    start_single_char()\n    type_keys(10, key, 'b')\n    eq(get_cursor(), { 1, 5 })\n  end,\n})\n\nT['builtin_opts.single_character']['notifies if there is no spots'] = function()\n  set_cursor(1, 0)\n  set_lines({ 'xxx' })\n  start_single_char()\n  type_keys(10, 'y')\n\n  eq(get_cursor(), { 1, 0 })\n  eq(get_latest_message(), '(mini.jump2d) No spots to show.')\nend\n\nT['builtin_opts.single_character']['handles special user input'] = new_set({\n  parametrize = { { '<C-c>' }, { '<Esc>' }, { '<CR>' } },\n}, {\n  test = function(key)\n    set_cursor(1, 0)\n    set_lines({ 'x_x y_y zzz' })\n    start_single_char()\n    type_keys(10, key)\n\n    eq(get_cursor(), { 1, 0 })\n    eq(get_latest_message(), '(mini.jump2d) No spots to show.')\n  end,\n})\n\nT['builtin_opts.single_character']['shows reminder after one idle second'] = function()\n  -- Helps create hit-enter-prompt\n  child.set_size(5, 50)\n\n  start_single_char()\n  eq(get_latest_message(), '')\n  sleep(reminder_delay - small_time)\n  eq(get_latest_message(), '')\n  sleep(small_time + small_time)\n\n  -- Should show helper message without adding it to `:messages` and causing\n  -- hit-enter-prompt\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\nend\n\n-- NOTE: For some reason, testing with screenshots is flaky when user input is\n-- involved. Test with moving cursor instead.\nT['builtin_opts.query'] = new_set()\n\nlocal start_query = function() child.lua_notify('MiniJump2d.start(MiniJump2d.builtin_opts.query)') end\n\nT['builtin_opts.query']['works'] = function()\n  set_lines({ 'xyzxy' })\n\n  start_query()\n  type_keys(10, 'xy<CR>', 'b')\n  eq(get_cursor(), { 1, 3 })\nend\n\nT['builtin_opts.query']['works multibyte characters'] = function()\n  set_lines({ 'xx ыы ыы' })\n\n  start_query()\n  type_keys(10, 'ыы<CR>', 'b')\n  -- Here 8 is a byte column for second 'ыы'\n  eq(get_cursor(), { 1, 8 })\nend\n\nT['builtin_opts.query']['works with problematic characters'] = new_set({\n  parametrize = { { '..' }, { '%%' } },\n}, {\n  test = function(keys)\n    set_lines({ 'xxx ' .. keys .. keys })\n    start_query()\n    type_keys(10, keys, '<CR>', 'b')\n    eq(get_cursor(), { 1, 6 })\n  end,\n})\n\nT['builtin_opts.query']['notifies if there is no spots'] = function()\n  set_lines({ 'xyz' })\n  set_cursor(1, 0)\n\n  start_query()\n  type_keys(10, 'yy', '<CR>')\n  eq(get_cursor(), { 1, 0 })\n  eq(get_latest_message(), '(mini.jump2d) No spots to show.')\nend\n\nT['builtin_opts.query']['handles special user input'] = new_set({\n  parametrize = { { '<C-c>' }, { '<Esc>' } },\n}, {\n  test = function(key)\n    set_lines({ 'xyz' })\n    set_cursor(1, 0)\n\n    start_query()\n    type_keys(10, key, '<CR>')\n    eq(get_cursor(), { 1, 0 })\n    eq(get_latest_message(), '(mini.jump2d) No spots to show.')\n  end,\n})\n\nT['builtin_opts.query']['matches all cells after immediate <CR> user input'] = function()\n  set_lines({ 'xxxyyy' })\n\n  start_query()\n  type_keys(10, '<CR>', 'f')\n  eq(get_cursor(), { 1, 5 })\nend\n\nT['builtin_opts.query']['works in edge cases'] = function()\n  set_lines({ 'aaaaaa' })\n\n  start_query()\n  -- Should add only 3 spots\n  type_keys(10, 'aa<CR>', 'c')\n  eq(get_cursor(), { 1, 4 })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_keymap.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq, no_eq = helpers.expect, helpers.expect.equality, helpers.expect.no_equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('keymap', config) end\nlocal unload_module = function() child.mini_unload('keymap') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\nlocal test_dir = 'tests/dir-keymap'\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal mock_plugin = function(name) child.cmd('noautocmd set rtp+=tests/dir-keymap/mock-plugins/' .. name) end\n\nlocal mock_test_steps = function(method_name)\n  child.lua([[\n    -- Action returns nothing\n    _G.step_1 = {\n      condition = function() table.insert(_G.log, 'cond 1'); return _G.step_1_cond end,\n      action = function() table.insert(_G.log, 'action 1') end,\n    }\n\n    -- Action returns string keys to be emulated as if typed\n    _G.step_2 = {\n      condition = function() table.insert(_G.log, 'cond 2'); return _G.step_2_cond end,\n      action = function() table.insert(_G.log, 'action 2'); return 'dd' end,\n    }\n\n    -- Action returns `<Cmd>...<CR>` string to be executed\n    _G.step_3 = {\n      condition = function() table.insert(_G.log, 'cond 3'); return _G.step_3_cond end,\n      action = function()\n        table.insert(_G.log, 'action 3')\n        return '<Cmd>lua vim.api.nvim_buf_set_lines(0, 0, -1, false, { \"From step 3\" })<CR>'\n      end,\n    }\n\n    -- Action returns `false` to indicate \"keep processing next steps\"\n    _G.step_4 = {\n      condition = function() table.insert(_G.log, 'cond 4'); return _G.step_4_cond end,\n      action = function() table.insert(_G.log, 'action 4'); return false end,\n    }\n\n    -- Action returns callable to be executed later\n    _G.step_5 = {\n      condition = function() table.insert(_G.log, 'cond 5'); return _G.step_5_cond end,\n      action = function()\n        table.insert(_G.log, 'action 5')\n        local upvalue = 'From step 5 with upvalue'\n        return function() vim.api.nvim_buf_set_lines(0, 0, -1, false, { upvalue }) end\n      end,\n    }\n\n    _G.steps = { _G.step_1, _G.step_2, _G.step_3, _G.step_4, _G.step_5 }\n  ]])\nend\n\nlocal validate_log_and_clean = function(ref)\n  eq(child.lua_get('_G.log'), ref)\n  child.lua('_G.log = {}')\nend\n\nlocal validate_edit = function(lines_before, cursor_before, keys, lines_after, cursor_after)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n\n  child.ensure_normal_mode()\nend\n\nlocal validate_edit1d = function(line_before, col_before, keys, line_after, col_after)\n  validate_edit({ line_before }, { 1, col_before }, keys, { line_after }, { 1, col_after })\nend\n\nlocal validate_jumps = function(key, ref_pos_seq)\n  -- Should keep initial mode (relevant for Insert mode)\n  local start_mode = child.fn.mode()\n  for _, ref_pos in ipairs(ref_pos_seq) do\n    type_keys(key)\n    eq(get_cursor(), ref_pos)\n    eq(child.fn.mode(), start_mode)\n  end\n  child.ensure_normal_mode()\nend\n\nlocal is_pumvisible = function() return child.fn.pumvisible() == 1 end\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\nlocal term_mode_wait = helpers.get_time_const(50)\n-- - Use custom combo delay for more robust tests on slower systems\nlocal default_combo_delay = 200\nlocal test_combo_delay = 3 * small_time\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      child.lua('_G.log = {}')\n    end,\n    post_once = child.stop,\n    n_retry = helpers.get_n_retry(2),\n  },\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  load_module()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniKeymap)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  load_module()\n  eq(child.lua_get('type(_G.MiniKeymap.config)'), 'table')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\nend\n\nT['map_multistep()'] = new_set()\n\nlocal map_multistep = forward_lua('require(\"mini.keymap\").map_multistep')\n\nT['map_multistep()']['works'] = function()\n  mock_test_steps()\n  child.lua('require(\"mini.keymap\").map_multistep(\"i\", \"<Tab>\", _G.steps)')\n\n  type_keys('i')\n\n  -- Can pass through\n  type_keys('<Tab>')\n  validate_log_and_clean({ 'cond 1', 'cond 2', 'cond 3', 'cond 4', 'cond 5' })\n  -- - Act as if unmapped\n  eq(get_lines(), { '\\t' })\n\n  -- Can handle an action returning nothing\n  child.lua('_G.step_1_cond = true')\n  type_keys('<Tab>')\n  validate_log_and_clean({ 'cond 1', 'action 1' })\n  -- - Do nothing\n  eq(get_lines(), { '\\t' })\n  child.lua('_G.step_1_cond = false')\n\n  -- Can emulate returned keys\n  child.lua('_G.step_2_cond = true')\n  type_keys('<Tab>')\n  validate_log_and_clean({ 'cond 1', 'cond 2', 'action 2' })\n  -- - Emulate pressing returned keys\n  eq(get_lines(), { '\\tdd' })\n  child.lua('_G.step_2_cond = false')\n\n  -- Can execute `<Cmd>...<CR>` string\n  child.lua('_G.step_3_cond = true')\n  type_keys('<Tab>')\n  validate_log_and_clean({ 'cond 1', 'cond 2', 'cond 3', 'action 3' })\n  -- - Execute `<Cmd>...<CR>` string\n  eq(get_lines(), { 'From step 3' })\n  child.lua('_G.step_3_cond = false')\n\n  -- Respects action returning `false` to indicate processing further steps\n  child.lua('_G.step_4_cond = true')\n  set_cursor(1, 11)\n  type_keys('<Tab>')\n  validate_log_and_clean({ 'cond 1', 'cond 2', 'cond 3', 'cond 4', 'action 4', 'cond 5' })\n  -- - Respect `false` action return as \"pass through\"\n  eq(get_lines(), { 'From step 3\\t' })\n  child.lua('_G.step_4_cond = false')\n\n  -- Can execute callable returned from action\n  child.lua('_G.step_5_cond = true')\n  type_keys('<Tab>')\n  validate_log_and_clean({ 'cond 1', 'cond 2', 'cond 3', 'cond 4', 'cond 5', 'action 5' })\n  -- - Execute callable returned from action\n  eq(get_lines(), { 'From step 5 with upvalue' })\n  child.lua('_G.step_5_cond = false')\n  -- - Should not create side effects\n  eq(child.lua_get('type(_G.MiniKeymap)'), 'nil')\nend\n\nT['map_multistep()']['works with empty steps'] = function()\n  map_multistep('i', '<Tab>', {})\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\nend\n\nT['map_multistep()']['respects `opts`'] = function()\n  local validate_mapping = function(is_buffer_local, ref_desc)\n    local info = child.lua([[\n      local map_info = vim.fn.maparg('<Tab>', 'i', false, true)\n      return { is_buffer_local = map_info.buffer == 1, desc = map_info.desc }\n    ]])\n    eq(info, { is_buffer_local = is_buffer_local, desc = ref_desc })\n  end\n\n  mock_test_steps()\n\n  child.lua('require(\"mini.keymap\").map_multistep(\"i\", \"<Tab>\", { _G.step_3 })')\n  validate_mapping(false, 'Multi <Tab>')\n\n  -- Should create a separate buffer-local mapping with custom description\n  child.lua([[require('mini.keymap').map_multistep(\n    'i',\n    '<Tab>',\n    { _G.step_5 },\n    { buffer = 0, desc = 'My multi', expr = false, replace_keycodes = false }\n  )]])\n  validate_mapping(true, 'My multi')\n\n  -- Should be independent and actually use only buffer-local mapping\n  child.lua('_G.step_3_cond, _G.step_5_cond = true, true')\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { 'From step 5 with upvalue' })\n  eq(child.lua_get('_G.log'), { 'cond 5', 'action 5' })\n  child.lua('_G.log = {}')\n\n  child.cmd('iunmap <buffer> <Tab>')\n  type_keys('<Tab>')\n  eq(get_lines(), { 'From step 3' })\n  eq(child.lua_get('_G.log'), { 'cond 3', 'action 3' })\nend\n\nT['map_multistep()']['respects `vim.{g,b}.minikeymap_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    mock_test_steps()\n    child.lua('require(\"mini.keymap\").map_multistep(\"i\", \"<Tab>\", _G.steps)')\n    type_keys('i')\n\n    child[var_type].minikeymap_disable = true\n    type_keys('<Tab>')\n    eq(get_lines(), { '\\t' })\n    validate_log_and_clean({})\n\n    child[var_type].minikeymap_disable = false\n    type_keys('<Tab>')\n    eq(get_lines(), { '\\t\\t' })\n    validate_log_and_clean({ 'cond 1', 'cond 2', 'cond 3', 'cond 4', 'cond 5' })\n  end,\n})\n\nT['map_multistep()']['validates input'] = function()\n  expect.error(function() map_multistep('a', '<Tab>', {}) end, 'mode')\n  expect.error(function() map_multistep('i', 1, {}) end, '`lhs`.*string')\n  expect.error(function() map_multistep('i', '<Tab>', { 'a' }) end, '`steps`.*valid steps.*not')\n  expect.error(function() map_multistep('i', '<Tab>', { {} }) end, '`steps`.*valid steps.*not')\n  expect.error(function() map_multistep('i', '<Tab>', { { condition = 'a' } }) end, '`steps`.*valid steps.*not')\n  local lua_cmd = 'require(\"mini.keymap\").map_multistep(\"i\", \"<Tab>\", { { condition = function() end, action = \"a\" } })'\n  expect.error(function() child.lua(lua_cmd) end, '`steps`.*valid steps.*not')\nend\n\nT['map_multistep()']['built-in steps'] = new_set()\n\nT['map_multistep()']['built-in steps']['pmenu_next'] = function()\n  child.o.completeopt = 'menuone,noselect'\n  map_multistep('i', '<Tab>', { 'pmenu_next' })\n\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  type_keys('aa ab ', '<C-n>')\n  eq(is_pumvisible(), true)\n\n  -- Should act as pressing `<C-n>`\n  type_keys('<Tab>')\n  eq(is_pumvisible(), true)\n  eq(get_lines(), { '\\taa ab aa' })\n\n  type_keys('<C-e>')\n  eq(is_pumvisible(), false)\n  eq(get_lines(), { '\\taa ab ' })\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\taa ab \\t' })\nend\n\nT['map_multistep()']['built-in steps']['pmenu_prev'] = function()\n  child.o.completeopt = 'menuone,noselect'\n  map_multistep('i', '<S-Tab>', { 'pmenu_prev' })\n\n  type_keys('i', '<S-Tab>')\n  eq(get_lines(), { '\\t' })\n  type_keys('aa ab ', '<C-n>')\n  eq(is_pumvisible(), true)\n\n  -- Should act as pressing `<C-p>`\n  type_keys('<S-Tab>')\n  eq(is_pumvisible(), true)\n  eq(get_lines(), { '\\taa ab ab' })\n\n  type_keys('<C-e>')\n  eq(is_pumvisible(), false)\n  eq(get_lines(), { '\\taa ab ' })\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\taa ab \\t' })\nend\n\nT['map_multistep()']['built-in steps']['pmenu_accept'] = function()\n  child.o.completeopt = 'menuone,noselect'\n  map_multistep('i', '<CR>', { 'pmenu_accept' })\n\n  type_keys('i', '<CR>')\n  eq(get_lines(), { '', '' })\n\n  -- Should accept selected (and only selected) item, i.e. act like `<C-y>`\n  type_keys('aa ab ', '<C-n>', '<C-n>')\n  eq(is_pumvisible(), true)\n  eq(get_lines(), { '', 'aa ab aa' })\n\n  type_keys('<CR>')\n  eq(is_pumvisible(), false)\n  eq(get_lines(), { '', 'aa ab aa' })\nend\n\nT['map_multistep()']['built-in steps']['minisnippets_next'] = function()\n  map_multistep('i', '<Tab>', { 'minisnippets_next' })\n\n  -- Should work if 'mini.snippets' is not set up\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n\n  child.lua('require(\"mini.snippets\").setup()')\n\n  -- Should pass through if there is no active session\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\t' })\n\n  child.lua('MiniSnippets.default_insert({ prefix = \"ab\", body = \"Snippet $1 ${2:placeholder} ab$0\" })')\n  eq(get_lines(), { '\\t\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 10 })\n\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 11 })\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 25 })\nend\n\nT['map_multistep()']['built-in steps']['minisnippets_prev'] = function()\n  -- child.lua([[require(\"mini.snippets\").setup({\n  --   snippets = { { prefix = 'ab', body = 'Snippet $1 ab$0', desc = 'Test snippet' } },\n  -- })]])\n  map_multistep('i', '<S-Tab>', { 'minisnippets_prev' })\n\n  -- Should work if 'mini.snippets' is not set up\n  type_keys('i', '<S-Tab>')\n  eq(get_lines(), { '\\t' })\n\n  child.lua('require(\"mini.snippets\").setup()')\n\n  -- Should pass through if there is no active session\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\t\\t' })\n\n  child.lua('MiniSnippets.default_insert({ prefix = \"ab\", body = \"Snippet $1 ${2:placeholder} ab$0\" })')\n  eq(get_lines(), { '\\t\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 10 })\n\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\t\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 25 })\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\t\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 11 })\nend\n\nT['map_multistep()']['built-in steps']['minisnippets_expand'] = function()\n  map_multistep('i', '<Tab>', { 'minisnippets_next', 'minisnippets_expand' })\n\n  -- Should work if 'mini.snippets' is not set up\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n\n  child.lua(\n    'require(\"mini.snippets\").setup({ snippets = { { prefix = \"ab\", body = \"Snippet $1 ${2:placeholder} ab$0\" } } })'\n  )\n\n  -- Should expand if no active session\n  type_keys('ab', '<Tab>')\n  eq(get_lines(), { '\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 9 })\n\n  -- Should jump if there is active session\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 10 })\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\tSnippet  placeholder ab' })\n  eq(get_cursor(), { 1, 24 })\nend\n\nT['map_multistep()']['built-in steps']['minipairs_cr'] = function()\n  map_multistep('i', '<CR>', { 'minipairs_cr' })\n\n  -- Should work if 'mini.pairs' is not set up\n  type_keys('i', '<CR>')\n  eq(get_lines(), { '', '' })\n\n  child.lua('require(\"mini.pairs\").setup()')\n\n  -- Should respect pairs\n  type_keys('(')\n  eq(get_lines(), { '', '()' })\n  type_keys('<CR>')\n  eq(get_lines(), { '', '(', '', ')' })\nend\n\nT['map_multistep()']['built-in steps']['minipairs_bs'] = function()\n  map_multistep('i', '<BS>', { 'minipairs_bs' })\n\n  -- Should work if 'mini.pairs' is not set up\n  type_keys('i', '()', '<Left>', '<BS>')\n  eq(get_lines(), { ')' })\n\n  child.lua('require(\"mini.pairs\").setup()')\n\n  -- Should respect pairs\n  set_lines({ 'a()' })\n  set_cursor(1, 2)\n  eq(get_lines(), { 'a()' })\n  type_keys('<BS>')\n  eq(get_lines(), { 'a' })\nend\n\nT['map_multistep()']['built-in steps']['jump_after_tsnode'] = function()\n  map_multistep({ 'i', 'n', 'x' }, '<Tab>', { 'jump_after_tsnode' })\n\n  -- Should work if there is no tree-sitter parser\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  child.ensure_normal_mode()\n\n  child.cmd('edit ' .. test_dir .. '/tree-sitter-tests.lua')\n\n  -- Insert mode\n  type_keys('i')\n  set_cursor(3, 4)\n  validate_jumps('<Tab>', {\n    -- Should jump just after the end of current node\n    { 3, 6 },\n    -- Should be possible to \"chain\" jumps and place cursor after end of line\n    { 5, 3 },\n    { 6, 3 },\n    { 8, 16 },\n    -- Should be possible to call at end of buffer without movement\n    { 8, 16 },\n  })\n\n  -- Normal mode\n  set_cursor(3, 4)\n  validate_jumps('<Tab>', {\n    { 3, 6 },\n    -- Should be possible to chain, although not possible to place after EOL\n    { 5, 2 },\n    { 6, 2 },\n    { 8, 15 },\n    -- Should be possible to call at end of buffer without movement\n    { 8, 15 },\n  })\n\n  -- - Should place after line end if possible\n  child.o.virtualedit = 'onemore'\n  set_cursor(3, 4)\n  validate_jumps('<Tab>', { { 3, 6 }, { 5, 3 }, { 6, 3 }, { 8, 16 }, { 8, 16 } })\n  child.o.virtualedit = ''\n\n  -- Visual mode\n  set_cursor(3, 4)\n  type_keys('v')\n  validate_jumps('<Tab>', { { 3, 6 }, { 5, 3 }, { 6, 3 }, { 8, 16 }, { 8, 16 } })\n\n  set_cursor(3, 4)\n  type_keys('V')\n  validate_jumps('<Tab>', { { 3, 6 }, { 5, 3 }, { 6, 3 }, { 8, 16 }, { 8, 16 } })\n\n  set_cursor(3, 4)\n  type_keys('<C-v>')\n  validate_jumps('<Tab>', { { 3, 6 }, { 5, 3 }, { 6, 3 }, { 8, 16 }, { 8, 16 } })\n\n  -- Should hide possibly visible popup menu\n  set_cursor(3, 4)\n  type_keys('i', '<C-n>')\n  eq(is_pumvisible(), true)\n  type_keys('<Tab>')\n  eq(is_pumvisible(), false)\nend\n\nT['map_multistep()']['built-in steps']['jump_before_tsnode'] = function()\n  map_multistep({ 'i', 'n', 'x' }, '<S-Tab>', { 'jump_before_tsnode' })\n\n  -- Should work if there is no tree-sitter parser\n  type_keys('i', '<S-Tab>')\n  eq(get_lines(), { '\\t' })\n  child.ensure_normal_mode()\n\n  child.cmd('edit ' .. test_dir .. '/tree-sitter-tests.lua')\n\n  -- Insert mode\n  type_keys('i')\n  set_cursor(3, 5)\n  validate_jumps('<S-Tab>', {\n    -- Should jump just at the start of current node (as in Insert mode cursor\n    -- will be just before the node) while keeping Insert mode\n    { 3, 4 },\n    -- Should be possible to \"chain\" jumps (although cursor is in the same node)\n    { 2, 9 },\n    { 2, 2 },\n    { 1, 0 },\n    -- Should be possible to call at end of buffer without movement\n    { 1, 0 },\n  })\n\n  -- Normal mode\n  set_cursor(3, 5)\n  validate_jumps('<S-Tab>', { { 3, 4 }, { 2, 9 }, { 2, 2 }, { 1, 0 }, { 1, 0 } })\n\n  -- Visual mode\n  set_cursor(3, 5)\n  type_keys('v')\n  validate_jumps('<S-Tab>', { { 3, 4 }, { 2, 9 }, { 2, 2 }, { 1, 0 }, { 1, 0 } })\n\n  set_cursor(3, 5)\n  type_keys('V')\n  validate_jumps('<S-Tab>', { { 3, 4 }, { 2, 9 }, { 2, 2 }, { 1, 0 }, { 1, 0 } })\n\n  set_cursor(3, 5)\n  type_keys('<C-v>')\n  validate_jumps('<S-Tab>', { { 3, 4 }, { 2, 9 }, { 2, 2 }, { 1, 0 }, { 1, 0 } })\n\n  -- Should hide possibly visible popup menu\n  set_cursor(3, 4)\n  type_keys('i', '<C-n>')\n  eq(is_pumvisible(), true)\n  type_keys('<S-Tab>')\n  eq(is_pumvisible(), false)\nend\n\nT['map_multistep()']['built-in steps']['jump_after_close'] = function()\n  map_multistep('i', '<Tab>', { 'jump_after_close' })\n\n  set_lines({ [=[([{\"'` x `'\"}])]=], '', ')', ']', '}', '\"', \"'\", '`' })\n  set_cursor(1, 7)\n  type_keys('i')\n\n  validate_jumps('<Tab>', {\n    -- Should put cursor on the right of closing character\n    { 1, 10 },\n\n    -- Should be able to \"chain\" to work with consecutive characters\n    { 1, 11 },\n    { 1, 12 },\n    { 1, 13 },\n    { 1, 14 },\n    -- - Should be possible to put cursor after end of line\n    { 1, 15 },\n\n    -- Should work across multiple lines and with not necessarily balanced pairs\n    { 3, 1 },\n    { 4, 1 },\n    { 5, 1 },\n    { 6, 1 },\n    { 7, 1 },\n    { 8, 1 },\n\n    -- Should do nothing if there is no search matches\n    { 8, 1 },\n  })\n  eq(get_lines()[8], '`')\n\n  -- Does not adjust cursor when not needed\n  set_lines({ 'x)xxx' })\n  set_cursor(1, 0)\n  type_keys('i')\n  validate_jumps('<Tab>', { { 1, 2 }, { 1, 2 } })\n\n  -- Should hide possibly visible popup menu\n  set_lines({ 'xx ( yy )' })\n  set_cursor(1, 5)\n  type_keys('i', '<C-n>')\n  eq(is_pumvisible(), true)\n  type_keys('<Tab>')\n  eq(is_pumvisible(), false)\nend\n\nT['map_multistep()']['built-in steps']['jump_before_open'] = function()\n  map_multistep('i', '<S-Tab>', { 'jump_before_open' })\n\n  set_lines({ '`', \"'\", '\"', '{', '[', '(', '', [=[([{\"'` x `'\"}])]=] })\n  set_cursor(8, 7)\n  type_keys('i')\n\n  validate_jumps('<S-Tab>', {\n    -- Should put cursor on the left of closing character\n    { 8, 5 },\n\n    -- Should be able to \"chain\" to work with consecutive characters\n    { 8, 4 },\n    { 8, 3 },\n    { 8, 2 },\n    { 8, 1 },\n    -- - Should be possible to put cursor at first column\n    { 8, 0 },\n\n    -- Should work across multiple lines and with not necessarily balanced pairs\n    { 6, 0 },\n    { 5, 0 },\n    { 4, 0 },\n    { 3, 0 },\n    { 2, 0 },\n    { 1, 0 },\n\n    -- Should do nothing if there is no search matches\n    { 1, 0 },\n  })\n  eq(get_lines()[1], '`')\n\n  -- Does not adjust cursor when not needed\n  set_lines({ 'xxx(x' })\n  set_cursor(1, 4)\n  type_keys('i')\n  validate_jumps('<S-Tab>', { { 1, 3 }, { 1, 3 } })\n\n  -- Should hide possibly visible popup menu\n  set_lines({ 'xx ( yy )' })\n  set_cursor(1, 5)\n  type_keys('i', '<C-n>')\n  eq(is_pumvisible(), true)\n  type_keys('<S-Tab>')\n  eq(is_pumvisible(), false)\nend\n\nT['map_multistep()']['built-in steps']['increase_indent'] = function()\n  map_multistep({ 'n', 'i', 'x' }, '<Tab>', { 'increase_indent' })\n\n  -- Should work as with built-in keys, i.e. respecting relevant options\n  child.bo.expandtab = true\n  child.bo.shiftwidth = 2\n  child.bo.tabstop = 4\n\n  --  Should only work when inside indent (even empty)\n  -- - Insert mode (cursor can be \"just after indent\", i.e. on next cell)\n  validate_edit1d('abc', 0, 'i<Tab>', '  abc', 2)\n  validate_edit1d('abc', 1, 'i<Tab>', 'a   bc', 4)\n  validate_edit1d('  abc', 0, 'i<Tab>', '    abc', 2)\n  validate_edit1d('  abc', 2, 'i<Tab>', '    abc', 4)\n  validate_edit1d('  abc', 3, 'i<Tab>', '  a bc', 4)\n\n  -- - Normal mode (cursor should be exactly on indent)\n  validate_edit1d('abc', 0, '<Tab>', 'abc', 0)\n  validate_edit1d('abc', 1, '<Tab>', 'abc', 1)\n  validate_edit1d('  abc', 0, '<Tab>', '    abc', 0)\n  validate_edit1d('  abc', 1, '<Tab>', '    abc', 1)\n  validate_edit1d('  abc', 2, '<Tab>', '  abc', 2)\n\n  -- - Visual mode (cursor should be exactly on indent)\n  local validate_vis_mode = function(key, before_line, before_col, after_line, after_col)\n    validate_edit1d(before_line, before_col, key .. '<Tab>', after_line, after_col)\n    eq(child.fn.mode(), 'n')\n  end\n\n  validate_vis_mode('v', 'abc', 0, 'abc', 0)\n  validate_vis_mode('v', 'abc', 1, 'abc', 1)\n  validate_vis_mode('v', '  abc', 0, '    abc', 0)\n  validate_vis_mode('v', '  abc', 1, '    abc', 1)\n  validate_vis_mode('v', '  abc', 2, '  abc', 2)\n\n  validate_vis_mode('V', 'abc', 0, 'abc', 0)\n  validate_vis_mode('V', 'abc', 1, 'abc', 1)\n  validate_vis_mode('V', '  abc', 0, '    abc', 0)\n  validate_vis_mode('V', '  abc', 1, '    abc', 1)\n  validate_vis_mode('V', '  abc', 2, '  abc', 2)\n\n  -- - Is not well defined for blockwise visual selection\nend\n\nT['map_multistep()']['built-in steps']['decrease_indent'] = function()\n  map_multistep({ 'n', 'i', 'x' }, '<S-Tab>', { 'decrease_indent' })\n\n  -- Should work as with built-in keys, i.e. respecting relevant options\n  child.bo.expandtab = true\n  child.bo.shiftwidth = 2\n  child.bo.tabstop = 4\n\n  --  Should only work when inside indent (even empty)\n  -- - Insert mode (cursor can be \"just after indent\", i.e. on next cell)\n  validate_edit1d('abc', 0, 'i<S-Tab>', 'abc', 0)\n  validate_edit1d('abc', 1, 'i<S-Tab>', 'a   bc', 4)\n  validate_edit1d('  abc', 0, 'i<S-Tab>', 'abc', 0)\n  validate_edit1d('  abc', 2, 'i<S-Tab>', 'abc', 0)\n  validate_edit1d('  abc', 3, 'i<S-Tab>', '  a bc', 4)\n\n  -- - Normal mode (cursor should be exactly on indent)\n  validate_edit1d('abc', 0, '<S-Tab>', 'abc', 0)\n  validate_edit1d('abc', 1, '<S-Tab>', 'abc', 1)\n  validate_edit1d('  abc', 0, '<S-Tab>', 'abc', 0)\n  validate_edit1d('  abc', 1, '<S-Tab>', 'abc', 1)\n  validate_edit1d('  abc', 2, '<S-Tab>', '  abc', 2)\n\n  -- - Visual mode (cursor should be exactly on indent)\n  local validate_vis_mode = function(key, before_line, before_col, after_line, after_col)\n    validate_edit1d(before_line, before_col, key .. '<S-Tab>', after_line, after_col)\n    eq(child.fn.mode(), 'n')\n  end\n\n  validate_vis_mode('v', 'abc', 0, 'abc', 0)\n  validate_vis_mode('v', 'abc', 1, 'abc', 1)\n  validate_vis_mode('v', '  abc', 0, 'abc', 0)\n  validate_vis_mode('v', '  abc', 1, 'abc', 1)\n  validate_vis_mode('v', '  abc', 2, '  abc', 2)\n\n  validate_vis_mode('V', 'abc', 0, 'abc', 0)\n  validate_vis_mode('V', 'abc', 1, 'abc', 1)\n  validate_vis_mode('V', '  abc', 0, 'abc', 0)\n  validate_vis_mode('V', '  abc', 1, 'abc', 1)\n  validate_vis_mode('V', '  abc', 2, '  abc', 2)\n\n  -- - Is not well defined for blockwise visual selection\nend\n\nT['map_multistep()']['built-in steps']['hungry_bs'] = function()\n  map_multistep({ 'n', 'i', 'x' }, '<BS>', { 'hungry_bs', 'minipairs_bs' })\n\n  -- Should delete all consecutive whitespace before cursor\n  validate_edit1d('', 0, 'i<BS>', '', 0)\n  validate_edit1d('   ', 1, 'i<BS>', '  ', 0)\n  validate_edit1d('   ', 2, 'a<BS>', '', 0)\n\n  validate_edit1d('\\t\\t\\t', 2, 'a<BS>', '', 0)\n  validate_edit1d(' \\t ', 2, 'a<BS>', '', 0)\n\n  validate_edit1d(' a  bc', 0, 'i<BS>', ' a  bc', 0)\n  validate_edit1d(' a  bc', 1, 'i<BS>', 'a  bc', 0)\n  validate_edit1d(' a  bc', 2, 'i<BS>', '   bc', 1)\n  validate_edit1d(' a  bc', 3, 'i<BS>', ' a bc', 2)\n  validate_edit1d(' a  bc', 4, 'i<BS>', ' abc', 2)\n  validate_edit1d(' a  bc', 5, 'i<BS>', ' a  c', 4)\n  validate_edit1d(' a  bc', 6, 'a<BS>', ' a  b', 5)\n\n  -- Should not span across line\n  validate_edit({ 'a  ', '  b' }, { 2, 2 }, 'i<BS>', { 'a  ', 'b' }, { 2, 0 })\n  validate_edit({ '  ', '  b' }, { 2, 2 }, 'i<BS>', { '  ', 'b' }, { 2, 0 })\n  validate_edit({ '', '  b' }, { 2, 2 }, 'i<BS>', { '', 'b' }, { 2, 0 })\n\n  -- Should work in all modes (but cursor should be exactly on whitespace)\n  -- - Normal (unmapped <BS> moves cursor to the left)\n  validate_edit1d(' a  bc', 0, '<BS>', 'a  bc', 0)\n  validate_edit1d(' a  bc', 1, '<BS>', ' a  bc', 0)\n  validate_edit1d(' a  bc', 2, '<BS>', ' a bc', 2)\n  validate_edit1d(' a  bc', 3, '<BS>', ' abc', 2)\n  validate_edit1d(' a  bc', 4, '<BS>', ' a  bc', 3)\n  validate_edit1d(' a  bc', 5, '<BS>', ' a  bc', 4)\n\n  local validate_vis_mode = function(key, before_line, before_col, after_line, after_col)\n    set_lines({ before_line })\n    set_cursor(1, before_col)\n    type_keys(key .. '<BS>')\n    eq(get_lines(), { after_line })\n    eq(get_cursor(), { 1, after_col })\n\n    local ref_mode = key == '<C-v>' and '\\22' or key\n    eq(child.fn.mode(), ref_mode)\n    child.ensure_normal_mode()\n  end\n\n  validate_vis_mode('v', ' a  bc', 0, 'a  bc', 0)\n  validate_vis_mode('v', ' a  bc', 1, ' a  bc', 0)\n  validate_vis_mode('v', ' a  bc', 2, ' a bc', 2)\n  validate_vis_mode('v', ' a  bc', 3, ' abc', 2)\n  validate_vis_mode('v', ' a  bc', 4, ' a  bc', 3)\n  validate_vis_mode('v', ' a  bc', 5, ' a  bc', 4)\n\n  -- - Is not well defined for linewise and blockwise visual selection\n\n  -- Should work well with 'mini.pairs'\n  child.lua('require(\"mini.pairs\").setup()')\n  validate_edit1d('(   )', 4, 'i<BS><BS>', '', 0)\nend\n\nT['map_multistep()']['built-in steps']['vimsnippet_next'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`vim.snippet` is available only on Neovim>=0.10') end\n\n  -- Make sure to not test built-in <Tab> mappings from Neovim>=0.11\n  pcall(child.cmd, 'iunmap <Tab>')\n  pcall(child.cmd, 'sunmap <Tab>')\n\n  map_multistep({ 'i', 's' }, '<Tab>', { 'vimsnippet_next' })\n\n  -- Should pass through if there is no active session\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  set_lines({})\n\n  -- Should jump to next tabstop\n  child.lua('vim.snippet.expand(\"Snippet $1 ${2:placeholder} ab$0\")')\n  eq(get_lines(), { 'Snippet  placeholder ab' })\n  eq(get_cursor(), { 1, 8 })\n  eq(child.fn.mode(), 'i')\n\n  type_keys('<Tab>')\n  eq(get_lines(), { 'Snippet  placeholder ab' })\n  eq(get_cursor(), { 1, 9 })\n  eq(child.fn.mode(), 's')\n\n  type_keys('<Tab>')\n  eq(get_lines(), { 'Snippet  placeholder ab' })\n  eq(get_cursor(), { 1, 23 })\n  eq(child.fn.mode(), 'i')\nend\n\nT['map_multistep()']['built-in steps']['vimsnippet_prev'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`vim.snippet` is available only on Neovim>=0.10') end\n\n  -- Make sure to not test built-in <Tab> mappings from Neovim>=0.11\n  pcall(child.cmd, 'iunmap <S-Tab>')\n  pcall(child.cmd, 'sunmap <S-Tab>')\n\n  map_multistep({ 'i', 's' }, '<S-Tab>', { 'vimsnippet_prev' })\n\n  -- Should pass through if there is no active session\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  set_lines({})\n\n  -- Should jump to next tabstop\n  child.lua('vim.snippet.expand(\"Snippet $1 ${2:placeholder} $3ab$0\")')\n  child.lua('vim.snippet.jump(1)')\n  child.lua('vim.snippet.jump(1)')\n  eq(get_lines(), { 'Snippet  placeholder ab' })\n  eq(get_cursor(), { 1, 21 })\n  eq(child.fn.mode(), 'i')\n\n  type_keys('<S-Tab>')\n  eq(get_lines(), { 'Snippet  placeholder ab' })\n  eq(get_cursor(), { 1, 9 })\n  eq(child.fn.mode(), 's')\n\n  type_keys('<S-Tab>')\n  eq(get_lines(), { 'Snippet  placeholder ab' })\n  eq(get_cursor(), { 1, 8 })\n  eq(child.fn.mode(), 'i')\nend\n\nT['map_multistep()']['built-in steps']['cmp_next'] = function()\n  map_multistep('i', '<Tab>', { 'cmp_next' })\n\n  -- Should work if 'cmp' module is not present\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('nvim-cmp')\n\n  -- Should pass through if there is no visible nvim-cmp menu\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'cmp.visible' })\n\n  child.lua('_G.cmp_visible_res = true')\n  type_keys('<Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'cmp.visible', 'cmp.select_next_item' })\nend\n\nT['map_multistep()']['built-in steps']['cmp_prev'] = function()\n  map_multistep('i', '<S-Tab>', { 'cmp_prev' })\n\n  -- Should work if 'cmp' module is not present\n  type_keys('i', '<S-Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('nvim-cmp')\n\n  -- Should pass through if there is no visible nvim-cmp menu\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'cmp.visible' })\n\n  child.lua('_G.cmp_visible_res = true')\n  type_keys('<S-Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'cmp.visible', 'cmp.select_prev_item' })\nend\n\nT['map_multistep()']['built-in steps']['cmp_accept'] = function()\n  map_multistep('i', '<CR>', { 'cmp_accept' })\n\n  -- Should work if 'cmp' module is not present\n  type_keys('i', '<CR>')\n  eq(get_lines(), { '', '' })\n  validate_log_and_clean({})\n\n  mock_plugin('nvim-cmp')\n\n  -- Should pass through if there is no selected nvim-cmp item\n  type_keys('<CR>')\n  eq(get_lines(), { '', '', '' })\n  validate_log_and_clean({ 'cmp.get_selected_entry' })\n\n  child.lua('_G.cmp_get_selected_entry_res = {}')\n  type_keys('<CR>')\n  -- - Should not modify text\n  eq(get_lines(), { '', '', '' })\n  validate_log_and_clean({ 'cmp.get_selected_entry', 'cmp.confirm' })\nend\n\nT['map_multistep()']['built-in steps']['blink_next'] = function()\n  map_multistep('i', '<Tab>', { 'blink_next' })\n\n  -- Should work if 'blink.cmp' module is not present\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('blink.cmp')\n\n  -- Should pass through if there is no visible blink menu\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'blink.is_menu_visible' })\n\n  child.lua('_G.blink_is_menu_visible_res = true')\n  type_keys('<Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'blink.is_menu_visible', 'blink.select_next' })\nend\n\nT['map_multistep()']['built-in steps']['blink_prev'] = function()\n  map_multistep('i', '<S-Tab>', { 'blink_prev' })\n\n  -- Should work if 'blink.cmp' module is not present\n  type_keys('i', '<S-Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('blink.cmp')\n\n  -- Should pass through if there is no visible blink.cmp menu\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'blink.is_menu_visible' })\n\n  child.lua('_G.blink_is_menu_visible_res = true')\n  type_keys('<S-Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'blink.is_menu_visible', 'blink.select_prev' })\nend\n\nT['map_multistep()']['built-in steps']['blink_accept'] = function()\n  map_multistep('i', '<CR>', { 'blink_accept' })\n\n  -- Should work if 'blink.mp' module is not present\n  type_keys('i', '<CR>')\n  eq(get_lines(), { '', '' })\n  validate_log_and_clean({})\n\n  mock_plugin('blink.cmp')\n\n  -- Should pass through if there is no selected blink.cmp item\n  child.lua('_G.blink_is_menu_visible_res = true')\n  type_keys('<CR>')\n  eq(get_lines(), { '', '', '' })\n  validate_log_and_clean({ 'blink.is_menu_visible', 'blink.get_selected_item' })\n\n  child.lua('_G.blink_get_selected_item_res = {}')\n  type_keys('<CR>')\n  -- - Should not modify text\n  eq(get_lines(), { '', '', '' })\n  validate_log_and_clean({ 'blink.is_menu_visible', 'blink.get_selected_item', 'blink.accept' })\nend\n\nT['map_multistep()']['built-in steps']['luasnip_next'] = function()\n  map_multistep('i', '<Tab>', { 'luasnip_next' })\n\n  -- Should work if 'luasnip' module is not present\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('luasnip')\n\n  -- Should pass through if there is no active session\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable' })\n\n  child.lua('_G.luasnip_jumpable_res = true')\n  type_keys('<Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable', 'luasnip.jump 1' })\nend\n\nT['map_multistep()']['built-in steps']['luasnip_prev'] = function()\n  map_multistep('i', '<S-Tab>', { 'luasnip_prev' })\n\n  -- Should work if 'luasnip' module is not present\n  type_keys('i', '<S-Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('luasnip')\n\n  -- Should pass through if there is no active session\n  type_keys('<S-Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable' })\n\n  child.lua('_G.luasnip_jumpable_res = true')\n  type_keys('<S-Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable', 'luasnip.jump -1' })\nend\n\nT['map_multistep()']['built-in steps']['luasnip_expand'] = function()\n  map_multistep('i', '<Tab>', { 'luasnip_next', 'luasnip_expand' })\n\n  -- Should work if 'luasnip' module is not present\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n  validate_log_and_clean({})\n\n  mock_plugin('luasnip')\n\n  -- Should pass through if there is no active session or expandable prefix\n  type_keys('<Tab>')\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable', 'luasnip.expandable' })\n\n  child.lua('_G.luasnip_expandable_res = true')\n  type_keys('<Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable', 'luasnip.expandable', 'luasnip.expand' })\n\n  child.lua('_G.luasnip_jumpable_res = true')\n  type_keys('<Tab>')\n  -- - Should not modify text\n  eq(get_lines(), { '\\t\\t' })\n  validate_log_and_clean({ 'luasnip.jumpable', 'luasnip.jump 1' })\nend\n\nT['map_multistep()']['built-in steps']['nvimautopairs_cr'] = function()\n  map_multistep('i', '<CR>', { 'nvimautopairs_cr' })\n\n  -- Should work if 'nvim-autopairs' module is not present\n  type_keys('i', '<CR>')\n  eq(get_lines(), { '', '' })\n\n  mock_plugin('nvim-autopairs')\n\n  -- Should respect pairs\n  type_keys('()', '<Left>')\n  eq(get_lines(), { '', '()' })\n  type_keys('<CR>')\n  eq(get_lines(), { '', '(', '', ')' })\nend\n\nT['map_multistep()']['built-in steps']['nvimautopairs_bs'] = function()\n  map_multistep('i', '<BS>', { 'nvimautopairs_bs' })\n\n  -- Should work if 'nvim-autopairs' module is not present\n  type_keys('i', '()', '<Left>', '<BS>')\n  eq(get_lines(), { ')' })\n\n  mock_plugin('nvim-autopairs')\n\n  -- Should respect pairs\n  set_lines({ 'a()' })\n  set_cursor(1, 2)\n  eq(get_lines(), { 'a()' })\n  type_keys('<BS>')\n  eq(get_lines(), { 'a' })\nend\n\nT['gen_step'] = new_set()\n\nT['gen_step']['search_pattern()'] = new_set()\n\nT['gen_step']['search_pattern()']['works'] = function()\n  child.lua([=[\n    local keymap = require('mini.keymap')\n    local step = keymap.gen_step.search_pattern([[[(\\[{]\\+]], 'bW')\n    keymap.map_multistep({ 'i', 'n', 'x' }, '<S-Tab>', { step })\n  ]=])\n\n  set_lines({ 'xx[_{(_[[[', '[_(' })\n\n  -- Insert mode\n  set_cursor(2, 1)\n  local ref_jumps = {\n    -- Should respect pattern and flags (search backward, no wrapping)\n    { 2, 0 },\n    { 1, 7 },\n    { 1, 4 },\n    { 1, 2 },\n\n    -- Should silently do nothing if can not jump\n    { 1, 2 },\n  }\n  type_keys('i')\n  validate_jumps('<S-Tab>', ref_jumps)\n\n  -- Normal mode\n  set_cursor(2, 1)\n  validate_jumps('<S-Tab>', ref_jumps)\n\n  -- Visual mode\n  set_cursor(2, 1)\n  type_keys('v')\n  validate_jumps('<S-Tab>', ref_jumps)\n\n  set_cursor(2, 1)\n  type_keys('V')\n  validate_jumps('<S-Tab>', ref_jumps)\n\n  set_cursor(2, 1)\n  type_keys('<C-v>')\n  validate_jumps('<S-Tab>', ref_jumps)\nend\n\nT['gen_step']['search_pattern()']['respects `opts.side`'] = function()\n  child.lua([=[\n    local keymap = require('mini.keymap')\n    local step = keymap.gen_step.search_pattern([[[)\\]}]\\+]], 'ceW', { side = 'after' })\n    keymap.map_multistep('i', '<Tab>', { step })\n  ]=])\n\n  set_lines({ ']_)', ']_})_]]]xx' })\n  set_cursor(1, 1)\n  type_keys('i')\n\n  validate_jumps('<Tab>', {\n    -- Should respect pattern and flags (search forward, no wrapping) and put\n    -- cursor to the right\n    { 1, 3 },\n    { 2, 1 },\n    { 2, 4 },\n    { 2, 8 },\n\n    -- Should silently do nothing if can not jump\n    { 2, 8 },\n  })\nend\n\nT['gen_step']['search_pattern()']['respects `opts.stopline`'] = function()\n  child.lua([=[\n    local keymap = require('mini.keymap')\n    local step_num = keymap.gen_step.search_pattern(')', 'W', { stopline = 1 })\n    keymap.map_multistep('n', '<Tab>', { step_num })\n    local step_fun = keymap.gen_step.search_pattern('(', 'bW', { stopline = function() return vim.fn.line('.') end })\n    keymap.map_multistep('n', '<S-Tab>', { step_fun })\n  ]=])\n\n  set_lines({ '()', '()' })\n  set_cursor(1, 0)\n  validate_jumps('<Tab>', { { 1, 1 }, { 1, 1 } })\n  set_cursor(2, 1)\n  validate_jumps('<S-Tab>', { { 2, 0 }, { 2, 0 } })\nend\n\nT['gen_step']['search_pattern()']['respects `opts.timeout` and `opts.skip`'] = function()\n  child.lua([[\n    local search_orig = vim.fn.search\n    vim.fn.search = function(...)\n      _G.args = { ... }\n      return search_orig(...)\n    end\n    local keymap = require('mini.keymap')\n    local step = keymap.gen_step.search_pattern(')', 'W', { timeout = 1, skip = 'a' })\n    keymap.map_multistep('n', '<Tab>', { step })\n  ]])\n\n  type_keys('<Tab>')\n  eq(child.lua_get('vim.deep_equal(_G.args, { \")\", \"W\", nil, 1, \"a\" })'), true)\nend\n\nT['gen_step']['search_pattern()']['validates input'] = function()\n  local validate = function(args, ref_pattern)\n    expect.error(function() child.lua('require(\"mini.keymap\").gen_step.search_pattern(...)', args) end, ref_pattern)\n  end\n  validate({ 1, '' }, '`pattern`.*string')\n  validate({ 'a', 1 }, '`flags`.*string')\n  validate({ 'a', '', { side = 1 } }, '`opts.side`.*one of')\nend\n\nT['gen_step']['search_pattern()']['hides pmenu'] = function()\n  child.lua([[\n    local keymap = require('mini.keymap')\n    local step = keymap.gen_step.search_pattern(')')\n    keymap.map_multistep({ 'i' }, '<Tab>', { step })\n  ]])\n\n  set_lines({ 'xx ( yy )' })\n  set_cursor(1, 5)\n  type_keys('i', '<C-n>')\n  eq(is_pumvisible(), true)\n  type_keys('<Tab>')\n  eq(is_pumvisible(), false)\nend\n\nT['map_combo()'] = new_set({ n_retry = helpers.get_n_retry(5) })\n\nlocal map_combo = forward_lua('require(\"mini.keymap\").map_combo')\n\nT['map_combo()']['works with string RHS'] = function()\n  map_combo('i', 'jk', '<BS><BS><Esc>')\n\n  -- Should be emulated as if pressing keys\n  type_keys('i')\n  -- - Key should be processed immediately\n  type_keys('j')\n  eq(get_lines(), { 'j' })\n  sleep(default_combo_delay - small_time)\n  type_keys('k')\n  eq(get_lines(), { '' })\n  eq(child.fn.mode(), 'n')\n\n  -- Can use full key name in LHS\n  map_combo('i', '<BS><CR>', 'hello', { delay = test_combo_delay })\n  type_keys('i', 'ab', '<BS>')\n  eq(get_lines(), { 'a' })\n  sleep(small_time)\n  type_keys('<CR>')\n  eq(get_lines(), { 'a', 'hello' })\n\n  set_lines({ '' })\n  child.ensure_normal_mode()\n\n  -- Can use more than two keys\n  map_combo('i', 'asdf', ' world', { delay = test_combo_delay })\n  type_keys('i', 'a')\n  eq(get_lines(), { 'a' })\n\n  sleep(small_time)\n  type_keys('s')\n  eq(get_lines(), { 'as' })\n\n  sleep(small_time)\n  type_keys('d')\n  eq(get_lines(), { 'asd' })\n\n  sleep(small_time)\n  type_keys('f')\n  eq(get_lines(), { 'asdf world' })\nend\n\nT['map_combo()']['works with callable RHS'] = function()\n  child.lua('_G.delay = ' .. test_combo_delay)\n  -- Output string should be mimicked as if supplied as right hand side\n  child.lua([[\n    local rhs = function() table.insert(_G.log, \"rhs\"); return 'yy' end\n    require(\"mini.keymap\").map_combo(\"i\", \"xx\", rhs, { delay = _G.delay })\n  ]])\n\n  -- Should be executed while intermediate keys immediately processed as usual\n  type_keys('i', 'x')\n  eq(get_lines(), { 'x' })\n  sleep(small_time)\n  type_keys('x')\n  eq(get_lines(), { 'xxyy' })\n  eq(child.fn.mode(), 'i')\n  validate_log_and_clean({ 'rhs' })\nend\n\nT['map_combo()']['allows RHS to change mode and operate in it'] = function()\n  map_combo('i', 'jk', '<Esc>viwUo', { delay = test_combo_delay })\n  type_keys('i')\n  type_keys(small_time, 'j', 'k')\n  eq(get_lines(), { 'JK', '' })\nend\n\nT['map_combo()']['works with array LHS'] = function()\n  map_combo('i', { 'ы', '<Space>', '半' }, '<Tab>', { delay = test_combo_delay })\n\n  type_keys('i', 'ы')\n  sleep(small_time)\n  type_keys(' ')\n  sleep(small_time)\n  type_keys('半')\n  eq(get_lines(), { 'ы 半\\t' })\n  eq(child.fn.mode(), 'i')\nend\n\nT['map_combo()']['resets if typed above delay'] = function()\n  map_combo('i', 'jk', 'hello', { delay = test_combo_delay })\n  map_combo('i', 'asd', 'world', { delay = test_combo_delay })\n\n  type_keys('i', 'j')\n  sleep(test_combo_delay + small_time)\n  type_keys('k')\n  eq(get_lines(), { 'jk' })\n\n  -- Should stop on any step\n  type_keys(small_time, 'a', 's')\n  sleep(test_combo_delay + small_time)\n  type_keys('d')\n  eq(get_lines(), { 'jkasd' })\nend\n\nT['map_combo()']['works in different modes'] = function()\n  map_combo({ 'n', 'x', 'c', 't' }, 'jj', 'll', { delay = test_combo_delay })\n\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  set_cursor(1, 0)\n\n  -- Normal mode\n  type_keys(small_time, 'j', 'j')\n  eq(get_cursor(), { 3, 2 })\n\n  -- Visual mode\n  local validate_visual = function(mode_key_raw)\n    set_cursor(1, 0)\n    type_keys(small_time, mode_key_raw, 'j', 'j')\n    eq(get_cursor(), { 3, 2 })\n    eq(child.fn.mode(), mode_key_raw)\n    child.ensure_normal_mode()\n  end\n\n  validate_visual('v')\n  validate_visual('V')\n  validate_visual('\\22')\n\n  -- Command-line mode\n  type_keys(small_time, ':', 'j', 'j')\n  eq(child.fn.getcmdline(), 'jjll')\n  child.ensure_normal_mode()\n\n  -- Terminal mode\n  helpers.skip_on_windows('Terminal emulator testing is not robust/easy on Windows')\n  helpers.skip_on_macos('Terminal emulator testing is not robust/easy on MacOS')\n\n  -- Setup\n  child.cmd('terminal! bash --noprofile --norc')\n  -- Wait for terminal to get active\n  sleep(term_mode_wait)\n  child.cmd('startinsert')\n\n  -- Need to wait after each keystroke to allow shell to process it\n  type_keys(small_time, 'j', 'j')\n  sleep(5 * small_time)\n  expect.match(get_lines()[1], 'jjll$')\nend\n\nT['map_combo()']['takes user mappings into account when executing RHS'] = function()\n  map_combo('n', 'jj', 'll', { delay = test_combo_delay })\n  child.cmd('nnoremap ll <Cmd>lua table.insert(_G.log, \"custom ll\")<CR>')\n\n  type_keys(small_time, 'j', 'j')\n  validate_log_and_clean({ 'custom ll' })\nend\n\nT['map_combo()']['not recursive during RHS keys execution'] = function()\n  map_combo('i', 'jk', 'jk', { delay = test_combo_delay })\n  type_keys('i')\n  type_keys(small_time, 'j', 'k')\n  eq(get_lines(), { 'jkjk' })\n\n  type_keys(small_time, 'j', 'k')\n  eq(get_lines(), { 'jkjkjkjk' })\nend\n\nT['map_combo()']['ignores RHS keys in tracking'] = function()\n  map_combo('n', 'll', 'ww', { delay = test_combo_delay })\n  map_combo('n', 'ww', 'dd', { delay = test_combo_delay })\n  map_combo('n', 'lll', '$', { delay = test_combo_delay })\n\n  set_lines({ 'aaaaa bbbbb ccccc ddddd eeeee' })\n  set_cursor(1, 0)\n  type_keys(small_time, 'l', 'l')\n  eq(get_cursor(), { 1, 12 })\n  type_keys('l')\n  eq(get_cursor(), { 1, 28 })\nend\n\nT['map_combo()']['detecting combo does not depend on preceding keys'] = function()\n  map_combo('i', 'jk', 'xy', { delay = test_combo_delay })\n  type_keys('i')\n  type_keys(small_time, 'j', 'j', 'k', 'j')\n  eq(get_lines(), { 'jjkxyj' })\n  set_lines({ '' })\n  child.ensure_normal_mode()\n\n  map_combo('i', 'jj', 'XY', { delay = test_combo_delay })\n  type_keys('i', 'j')\n  sleep(test_combo_delay + small_time)\n  type_keys(small_time, 'j', 'j')\n  eq(get_lines(), { 'jjjXY' })\nend\n\nT['map_combo()']['works when typing already mapped keys'] = function()\n  -- On Neovim>=0.11 for a `jk` LHS. On Neovim<0.11 for a `gjgk` LHS.\n  child.cmd('xnoremap j gj', { delay = test_combo_delay })\n\n  -- Neovim<0.11 doesn't have functionality to truly track \"keys as typed\",\n  -- only after \"mappings are applied\" (see `:h vim.on_key()`)\n  local lhs = child.fn.has('nvim-0.11') == 1 and 'jj' or 'gjgj'\n  map_combo('x', lhs, 'll', { delay = test_combo_delay })\n  set_lines({ 'aaa', 'bbb', 'ccc' })\n  type_keys('v')\n  type_keys(small_time, 'j', 'j')\n  eq(get_cursor(), { 3, 2 })\nend\n\nT['map_combo()']['works with tricky LHS'] = function()\n  -- Should recognise LHS as three keys (`<`, `\\t`, `>`)\n  map_combo('i', '<<Tab>>', 'hello', { delay = test_combo_delay })\n  type_keys('i')\n  type_keys(small_time, '<', '\\t', '>')\n  eq(get_lines(), { '<\\t>hello' })\nend\n\nT['map_combo()']['creates namespaces with informative names'] = function()\n  map_combo('i', 'jk', '<BS><BS><Esc>')\n  map_combo('i', 'jk', 'hello')\n  map_combo({ 'n', 'x' }, '<Space>\\t', 'hello')\n  local namespaces = child.api.nvim_get_namespaces()\n  eq(namespaces['MiniKeymap-combo-0-i-jk'] ~= nil, true)\n  eq(namespaces['MiniKeymap-combo-1-i-jk'] ~= nil, true)\n  eq(namespaces['MiniKeymap-combo-2-nx-<Space><Tab>'] ~= nil, true)\nend\n\nT['map_combo()']['separate combos act independently'] = function()\n  child.lua('_G.delay = ' .. test_combo_delay)\n  child.lua([[\n    local combo = function(lhs, rhs)\n      require(\"mini.keymap\").map_combo('i', lhs, rhs, { delay = _G.delay })\n    end\n    _G.n1, _G.n2, _G.n3, _G.n4 = 0, 0, 0, 0\n    combo('jk',  function() _G.n1 = _G.n1 + 1 end)\n    combo('jjk', function() _G.n2 = _G.n2 + 1 end)\n    combo('kj',  function() _G.n3 = _G.n3 + 1 end)\n    combo('kjj', function() _G.n4 = _G.n4 + 1 end)\n  ]])\n\n  type_keys('i')\n  type_keys(small_time, 'j', 'j', 'k', 'j', 'j')\n  eq(child.lua_get('{ _G.n1, _G.n2, _G.n3, _G.n4 }'), { 1, 1, 1, 1 })\nend\n\nT['map_combo()']['allows several combos for the same mode-lhs pair'] = function()\n  child.lua('_G.delay = ' .. test_combo_delay)\n  child.lua([[\n    local combo = function(lhs, rhs)\n      require(\"mini.keymap\").map_combo('i', lhs, rhs, { delay = _G.delay })\n    end\n    _G.n1, _G.n2 = 0, 0\n    combo('jk', function() _G.n1 = _G.n1 + 1 end)\n    combo('jk', function() _G.n2 = _G.n2 + 1 end)\n  ]])\n\n  type_keys('i')\n  type_keys(small_time, 'j', 'k')\n  eq(child.lua_get('{ _G.n1, _G.n2 }'), { 1, 1 })\nend\n\nT['map_combo()']['works inside macros'] = function()\n  map_combo('i', 'jk', '<BS><BS><Esc>', { delay = test_combo_delay })\n\n  type_keys('q', 'q', 'i')\n  type_keys(small_time, 'j', 'j', 'k')\n  type_keys('yy', 'p')\n  type_keys('q')\n  eq(get_lines(), { 'j', 'j' })\n  eq(get_cursor(), { 2, 0 })\n  eq(child.fn.mode(), 'n')\n\n  type_keys('@', 'q')\n  eq(get_lines(), { 'j', 'jj', 'jj' })\n  eq(get_cursor(), { child.fn.has('nvim-0.11') == 1 and 3 or 2, 0 })\n  eq(child.fn.mode(), 'n')\nend\n\nT['map_combo()']['respects `opts.delay`'] = function()\n  map_combo('i', 'jk', 'xy', { delay = 1.5 * default_combo_delay + 2 * small_time })\n  type_keys('i', 'j')\n  sleep(1.5 * default_combo_delay)\n  type_keys('k')\n  eq(get_lines(), { 'jkxy' })\nend\n\nT['map_combo()']['validates input'] = function()\n  expect.error(function() map_combo(1, 'jk', '<Esc>') end, '`mode`.*string or array of strings')\n  expect.error(function() map_combo('i', 1, '<Esc>') end, '`lhs`.*string or array of strings')\n  expect.error(function() map_combo('i', 'jk', 1) end, '`action`.*string.*callable')\n  expect.error(function() map_combo('i', 'jk', 'xy', { delay = 'a' }) end, '`opts%.delay`.*number')\n  expect.error(function() map_combo('i', 'jk', 'xy', { delay = 0 }) end, '`opts%.delay`.*positive')\n  expect.error(function() map_combo('i', 'jk', 'xy', { delay = -1 }) end, '`opts%.delay`.*positive')\nend\n\nT['map_combo()']['respects `vim.{g,b}.minikeymap_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    map_combo('i', 'jk', 'hello', { delay = test_combo_delay })\n    type_keys('i')\n\n    child[var_type].minikeymap_disable = true\n    type_keys(small_time, 'j', 'k')\n    eq(get_lines(), { 'jk' })\n\n    child[var_type].minikeymap_disable = false\n    type_keys(small_time, 'j', 'k')\n    eq(get_lines(), { 'jkjkhello' })\n  end,\n})\n\n-- Integration tests ==========================================================\nreturn T\n"
  },
  {
    "path": "tests/test_map.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('map', config) end\nlocal unload_module = function() child.mini_unload('map') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Main function wrappers\nlocal map_open = function(opts) child.lua('MiniMap.open(...)', { opts }) end\n\nlocal map_refresh = function(opts, parts) child.lua('MiniMap.refresh(...)', { opts, parts }) end\n\nlocal map_close = function() child.lua('MiniMap.close()') end\n\n-- Helpers related to 'mini.map'\nlocal get_resolution_test_file = function(id) return 'tests/dir-map/resolution_' .. id end\n\nlocal get_map_win_id = function() return child.lua_get('MiniMap.current.win_data[vim.api.nvim_get_current_tabpage()]') end\n\nlocal get_map_win_side = function()\n  local win_config = child.api.nvim_win_get_config(get_map_win_id())\n  if win_config.anchor == 'NE' and win_config.col == child.o.columns then return 'right' end\n  if win_config.anchor == 'NW' and win_config.col == 0 then return 'left' end\n  return 'something is wrong'\nend\n\nlocal get_current = function() return child.lua_get('MiniMap.current') end\n\nlocal get_map_width = function() return child.api.nvim_win_get_width(get_map_win_id()) end\n\nlocal disable_map_updates = function()\n  child.cmd([[\n    augroup MiniMap\n      au!\n    augroup END\n  ]])\nend\n\nlocal mock_diagnostic = function() child.cmd('source tests/dir-map/mock-diagnostic.lua') end\n\nlocal mock_gitsigns = function() child.cmd('set rtp+=tests/dir-map') end\n\nlocal mock_diff = function()\n  child.lua([[\n    local diff = require('mini.diff')\n    diff.setup({ source = diff.gen_source.none(), options = { linematch = 0 } })\n    local buf_text = { 'uuu', 'vvv', 'aaa', 'bbb', 'ddd', 'EEE', 'FFF', 'GGG', 'HHH', 'III', 'JJJ', 'KKK', 'LLL' }\n    local ref_text = { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' }\n\n    vim.api.nvim_buf_set_lines(0, 0, -1, false, buf_text)\n    vim.api.nvim_win_set_cursor(0, { 1, 0 })\n    diff.set_ref_text(0, ref_text)\n  ]])\nend\n\nlocal source_test_integration = function() child.cmd('source tests/dir-map/src-test-integration.lua') end\n\nlocal mock_test_integration = function()\n  source_test_integration()\n\n  child.lua([[\n    local integrations = MiniMap.config.integrations or {}\n    table.insert(integrations, _G.test_integration)\n    MiniMap.config.integrations = integrations\n  ]])\nend\n\nlocal source_test_encode_symbols = function()\n  child.lua([[_G.test_encode_symbols = { '1', '2', '3', '4', resolution = { row = 1, col = 2 } }]])\nend\n\n-- Various utilities\nlocal tbl_repeat = function(x, n)\n  local res = {}\n  for _ = 1, n do\n    table.insert(res, x)\n  end\n  return res\nend\n\nlocal eq_keys = function(tbl, ref_keys)\n  local test_keys = vim.tbl_keys(tbl)\n  local ref_keys_copy = vim.deepcopy(ref_keys)\n\n  table.sort(test_keys)\n  table.sort(ref_keys_copy)\n  eq(test_keys, ref_keys_copy)\nend\n\nlocal get_n_shown_windows = function() return #child.api.nvim_tabpage_list_wins(0) end\n\n-- Output test set\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Data =======================================================================\n-- All possible encodings of '3x2' resolution\nlocal example_lines = {\n  '  a  aaa  a  aaa',\n  '        a a a a ',\n  '                ',\n  '  a  aaa  a  aaa',\n  ' a a a aaaaaaaaa',\n  '                ',\n  '  a  aaa  a  aaa',\n  '        a a a a ',\n  'a a a a a a a a ',\n  '  a  aaa  a  aaa',\n  ' a a a aaaaaaaaa',\n  'a a a a a a a a ',\n  '  a  aaa  a  aaa',\n  '        a a a a ',\n  ' a a a a a a a a',\n  '  a  aaa  a  aaa',\n  ' a a a aaaaaaaaa',\n  ' a a a a a a a a',\n  '  a  aaa  a  aaa',\n  '        a a a a ',\n  'aaaaaaaaaaaaaaaa',\n  '  a  aaa  a  aaa',\n  ' a a a aaaaaaaaa',\n  'aaaaaaaaaaaaaaaa',\n}\n\nlocal extended_example_lines = vim.deepcopy(example_lines)\nvim.list_extend(extended_example_lines, example_lines)\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniMap)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniMap'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniMapNormal', 'links to NormalFloat')\n  has_highlight('MiniMapSymbolCount', 'links to Special')\n  has_highlight('MiniMapSymbolLine', 'links to Title')\n  has_highlight('MiniMapSymbolView', 'links to Delimiter')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniMap.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniMap.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('integrations', vim.NIL)\n\n  expect_config('symbols.encode', vim.NIL)\n  expect_config('symbols.scroll_line', '█')\n  expect_config('symbols.scroll_view', '┃')\n\n  expect_config('window.focusable', false)\n  expect_config('window.side', 'right')\n  expect_config('window.show_integration_count', true)\n  expect_config('window.width', 10)\n  expect_config('window.winblend', 25)\n  expect_config('window.zindex', 10)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ window = { width = 1 } })\n  eq(child.lua_get('MiniMap.config.window.width'), 1)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  local expect_all_encode_symbols_check = function()\n    local expect_bad_config = function(err_pattern)\n      expect.error(function() child.lua([[MiniMap.setup(_G.bad_config)]]) end, err_pattern)\n    end\n\n    child.lua('_G.bad_config = { symbols = { encode = { resolution = { col = 2, row = 2 } } } }')\n    for i = 1, 4 do\n      expect_bad_config('symbols%.encode%[' .. i .. '%].*string')\n      child.lua(string.format('_G.bad_config.symbols.encode[%d] = \"%d\"', i, i))\n    end\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ integrations = 'a' }, 'integrations', 'array')\n  expect_config_error({ integrations = { 'a' } }, 'integrations', 'callable')\n\n  expect_config_error({ symbols = 'a' }, 'symbols', 'table')\n  expect_config_error({ symbols = { encode = 'a' } }, 'symbols.encode', 'table')\n\n  expect_config_error({ symbols = { encode = { resolution = 'a' } } }, 'symbols.encode.resolution', 'table')\n  expect_config_error(\n    { symbols = { encode = { resolution = { col = 'a' } } } },\n    'symbols.encode.resolution.col',\n    'number'\n  )\n  expect_config_error(\n    { symbols = { encode = { resolution = { col = 2, row = 'a' } } } },\n    'symbols.encode.resolution.row',\n    'number'\n  )\n  expect_all_encode_symbols_check()\n\n  expect_config_error({ symbols = { scroll_line = 1 } }, 'symbols.scroll_line', 'string')\n  expect_config_error({ symbols = { scroll_view = 1 } }, 'symbols.scroll_view', 'string')\n\n  expect_config_error({ window = 'a' }, 'window', 'table')\n  expect_config_error({ window = { focusable = 1 } }, 'window.focusable', 'boolean')\n  expect_config_error({ window = { side = 1 } }, 'window.side', 'one of')\n  expect_config_error({ window = { side = 'a' } }, 'window.side', 'one of')\n  expect_config_error({ window = { show_integration_count = 1 } }, 'window.show_integration_count', 'boolean')\n  expect_config_error({ window = { width = 'a' } }, 'window.width', 'number')\n  expect_config_error({ window = { winblend = 'a' } }, 'window.winblend', 'number')\n  expect_config_error({ window = { zindex = 'a' } }, 'window.zindex', 'number')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniMapNormal'), 'links to NormalFloat')\nend\n\nlocal encode_strings = function(strings, opts)\n  local cmd = string.format('MiniMap.encode_strings(%s, %s)', vim.inspect(strings), vim.inspect(opts))\n  return child.lua_get(cmd)\nend\n\nT['encode_strings()'] = new_set()\n\nT['encode_strings()']['works'] = function() eq(encode_strings({ 'aa', 'aa', 'aa' }), { '█' }) end\n\nT['encode_strings()']['validates `strings` argument'] = function()\n  expect.error(function() encode_strings('a') end, 'array')\n  expect.error(function() encode_strings({ 1, 'a' }) end, 'strings')\nend\n\nT['encode_strings()']['respects `strings` argument'] = function() eq(encode_strings({ 'aa' }), { '🬂' }) end\n\nT['encode_strings()']['respects `opts.n_rows`'] = function()\n  local strings = tbl_repeat('aa', 3 * 3)\n  eq(encode_strings(strings), { '█', '█', '█' })\n  eq(encode_strings(strings, { n_rows = 1 }), { '█' })\n  -- Very big values are trimmed to minimum necessary needed\n  eq(encode_strings(strings, { n_rows = 1000 }), { '█', '█', '█' })\n\n  -- Rescaling should be done via \"output is non-empty if at least one cell is\n  -- non-empty; empty if all empty\"\n  eq(encode_strings({ 'a', ' ', ' ', ' ', ' ', 'a', 'a', 'a', ' ', ' ', ' ' }, { n_rows = 2 }), { '🬐', '🬀' })\nend\n\nT['encode_strings()']['respects `opts.n_cols`'] = function()\n  local strings = tbl_repeat('aaaaaa', 3)\n  eq(encode_strings(strings), { '███' })\n  eq(encode_strings(strings, { n_cols = 1 }), { '█' })\n  -- Very big values are trimmed to minimum necessary needed\n  eq(encode_strings(strings, { n_cols = 1000 }), { '███' })\n\n  -- Rescaling should be done via \"output is non-empty if at least one cell is\n  -- non-empty; empty if all empty\"\n  eq(encode_strings({ 'a  a  aa' }, { n_cols = 2 }), { '🬂🬁' })\nend\n\nT['encode_strings()']['respects `opts.symbols`'] = function()\n  source_test_encode_symbols()\n  eq(\n    child.lua_get([[MiniMap.encode_strings({ '  aa', 'a  a' }, { symbols = _G.test_encode_symbols })]]),\n    { '14', '23' }\n  )\nend\n\nT['encode_strings()']['works with empty strings'] = function()\n  eq(encode_strings({ 'aaaa', '', 'aaaa', '' }), { '🬰🬰', '  ' })\nend\n\nT['encode_strings()']['correctly computes default dimensions'] = function()\n  eq(encode_strings({ 'a', 'aa', 'aaa', 'aaaa', 'aaaaa', '' }), { '🬺🬏 ', '🬎🬎🬃' })\nend\n\nT['encode_strings()']['does not trim whitespace'] = function()\n  eq(encode_strings({ ' ' }), { ' ' })\n  eq(encode_strings({ 'aa  ', 'aa  ', 'aa  ' }), { '█ ' })\nend\n\nT['encode_strings()']['works with multibyte strings'] = function()\n  eq(encode_strings({ 'ыыыыыы', 'ыыыы', 'ыы', 'aaaaaa', 'aaaa', 'aa' }), { '█🬎🬂', '█🬎🬂' })\nend\n\nT['encode_strings()']['correctly rescales in edge cases'] = function()\n  -- There were cases with more straightforward rescaling when certain middle\n  -- output row was not affected by any input row, leaving it empty. This was\n  -- because rescaling coefficient was more than 1.\n  local strings = tbl_repeat('aa', 37)\n  local ref_output = tbl_repeat('█', 12)\n  table.insert(ref_output, '🬂')\n  eq(encode_strings(strings), ref_output)\nend\n\nT['encode_strings()']['can work with input dimensions being not multiple of resolution'] = function()\n  eq(encode_strings({ 'a' }), { '🬀' })\n  eq(encode_strings({ 'aaa' }), { '🬂🬀' })\n  eq(encode_strings({ 'a', 'a' }), { '🬄' })\n  eq(encode_strings({ 'a', 'a', 'a', 'a' }), { '▌', '🬀' })\nend\n\nT['encode_strings()']['expands tabs'] = function()\n  eq(encode_strings({ '\\taa' }), { '    🬂' })\n\n  child.o.tabstop = 4\n  eq(encode_strings({ '\\taa' }), { '  🬂' })\nend\n\nT['open()'] = new_set({ hooks = { pre_case = function() child.set_size(30, 30) end } })\n\nT['open()']['works'] = function()\n  set_lines(example_lines)\n  set_cursor(15, 0)\n  mock_test_integration()\n\n  map_open()\n\n  child.expect_screenshot()\nend\n\nT['open()']['sets important map buffer options'] = function()\n  local init_buf = child.api.nvim_get_current_buf()\n  map_open()\n  local all_bufs = child.api.nvim_list_bufs()\n  eq(#all_bufs, 2)\n  local map_buf_id = all_bufs[1] == init_buf and all_bufs[2] or all_bufs[1]\n\n  eq(child.api.nvim_buf_get_name(map_buf_id), 'minimap://' .. map_buf_id .. '/content')\n\n  local validate_option = function(name, value) eq(child.api.nvim_buf_get_option(map_buf_id, name), value) end\n\n  validate_option('filetype', 'minimap')\n\n  validate_option('buftype', 'nofile')\n  validate_option('buflisted', false)\n  validate_option('swapfile', false)\nend\n\nT['open()']['sets important window options'] = function()\n  local init_win = child.api.nvim_get_current_win()\n  map_open()\n  local all_wins = child.api.nvim_tabpage_list_wins(0)\n  eq(#all_wins, 2)\n  local map_win_id = all_wins[1] == init_win and all_wins[2] or all_wins[1]\n\n  local validate_option = function(name, value) eq(child.api.nvim_win_get_option(map_win_id, name), value) end\n\n  validate_option('foldcolumn', '0')\n  validate_option('signcolumn', 'auto')\n  validate_option('wrap', false)\nend\n\nT['open()']['correctly computes window config'] = function()\n  child.set_size(30, 20)\n  map_open()\n  local win_id = get_map_win_id()\n\n  local hide, mouse, border, style\n  if child.fn.has('nvim-0.10') == 1 then hide = false end\n  if child.fn.has('nvim-0.11') == 1 then mouse = false end\n  if child.fn.has('nvim-0.12') == 1 then\n    border = 'none'\n    style = 'minimal'\n  end\n  eq(child.api.nvim_win_get_config(win_id), {\n    anchor = 'NE',\n    border = border,\n    col = 20,\n    external = false,\n    focusable = false,\n    height = 28,\n    hide = hide,\n    mouse = mouse,\n    relative = 'editor',\n    row = 0,\n    style = style,\n    width = 10,\n    zindex = 10,\n  })\n  eq(child.api.nvim_win_get_option(win_id, 'winblend'), child.lua_get('MiniMap.config.window.winblend'))\nend\n\nT['open()']['respects `opts.integrations` argument'] = function()\n  set_lines(example_lines)\n  source_test_integration()\n  child.lua('MiniMap.open({ integrations = { _G.test_integration } })')\n  child.expect_screenshot()\n\n  -- Updates current data accordingly\n  eq(child.lua_get('MiniMap.current.opts.integrations[1] == _G.test_integration'), true)\nend\n\nT['open()']['respects `opts.symbols` argument'] = function()\n  set_lines(example_lines)\n  source_test_encode_symbols()\n  child.lua([[MiniMap.open({\n    symbols = { encode = _G.test_encode_symbols, scroll_line = '>', scroll_view = '+' },\n  })]])\n\n  child.expect_screenshot()\n\n  -- Can have empty strings as scrollbar characters, virtually disabling it\n  map_close()\n  map_open({ symbols = { scroll_line = '', scroll_view = '' } })\n  child.expect_screenshot()\nend\n\nT['open()']['allows more than single character in scroll symbols'] = function()\n  set_lines(example_lines)\n  source_test_encode_symbols()\n  map_open({ symbols = { scroll_line = '>|<', scroll_view = '||' } })\n  child.expect_screenshot()\nend\n\nT['open()']['respects `opts.window` argument'] = function()\n  set_lines(example_lines)\n  --stylua: ignore\n  local opts = {\n    window = { focusable = true, side = 'left', show_integration_count = false, width = 15, winblend = 50, zindex = 20 },\n  }\n  map_open(opts)\n\n  child.expect_screenshot()\n  eq(child.api.nvim_win_get_option(get_map_win_id(), 'winblend'), 50)\n  eq(child.api.nvim_win_get_config(get_map_win_id()).zindex, 20)\n\n  -- Map window should be focusable\n  child.cmd('wincmd w')\n  eq(child.api.nvim_get_current_win(), get_map_win_id())\n\n  -- Updates current data accordingly\n  eq(child.lua_get('MiniMap.current.opts.window'), opts.window)\nend\n\nT['open()']['respects `MiniMap.config`'] = function()\n  child.lua('MiniMap.config.window.width = 20')\n  map_open()\n  eq(child.api.nvim_win_get_width(get_map_win_id()), 20)\n  eq(child.lua_get('MiniMap.current.opts.window.width'), 20)\nend\n\nT['open()']['respects `MiniMap.current`'] = function()\n  child.lua([[MiniMap.current.opts = { window = { side = 'left' } }]])\n  map_open()\n  eq(get_map_win_side(), 'left')\nend\n\nT['open()']['correctly updates `MiniMap.current`'] = function()\n  map_open()\n  local current = get_current()\n\n  eq_keys(current, { 'buf_data', 'opts', 'win_data' })\n\n  eq_keys(current.buf_data, { 'map', 'source' })\n  eq(current.buf_data.source, child.api.nvim_get_current_buf())\n\n  eq(current.opts, child.lua_get('MiniMap.config'))\n\n  eq_keys(current.win_data, { child.api.nvim_get_current_tabpage() })\nend\n\nT['open()']['respects important options when computing window height'] = function()\n  local validate = function(options, row, height)\n    local default_opts = { showtabline = 1, laststatus = 2, cmdheight = 1 }\n    options = vim.tbl_deep_extend('force', default_opts, options)\n    for name, value in pairs(options) do\n      child.o[name] = value\n    end\n\n    map_open()\n    local config = child.api.nvim_win_get_config(get_map_win_id())\n    eq(config.row, row)\n    eq(config.height, height)\n    map_close()\n\n    for name, value in pairs(default_opts) do\n      child.o[name] = value\n    end\n  end\n\n  validate({ showtabline = 0, laststatus = 0, cmdheight = 1 }, 0, 29)\n\n  -- Tabline. Should make space for it if it is actually shown\n  validate({ showtabline = 2, laststatus = 0 }, 1, 28)\n\n  validate({ showtabline = 1, laststatus = 0 }, 0, 29)\n  child.cmd('tabedit')\n  validate({ showtabline = 2, laststatus = 0 }, 1, 28)\n  child.cmd('tabclose')\n\n  -- Statusline\n  validate({ showtabline = 0, laststatus = 1 }, 0, 28)\n  validate({ showtabline = 0, laststatus = 2 }, 0, 28)\n  validate({ showtabline = 0, laststatus = 3 }, 0, 28)\n\n  -- Command line\n  validate({ showtabline = 0, laststatus = 0, cmdheight = 4 }, 0, 26)\n  validate({ showtabline = 0, laststatus = 0, cmdheight = 0 }, 0, 30)\nend\n\nT['open()']['can be used with already opened window'] = function()\n  map_open()\n  local current = get_current()\n  expect.no_error(map_open)\n  eq(current, get_current())\nend\n\nT['open()']['can be used in multiple tabpages'] = function()\n  local init_tabpage = child.api.nvim_get_current_tabpage()\n  map_open()\n  child.cmd('tabedit')\n  local second_tabpage = child.api.nvim_get_current_tabpage()\n\n  -- Shouldn't be open in new tabpage\n  eq(get_map_win_id(), vim.NIL)\n\n  -- Should open window and register it as second opened\n  map_open()\n  eq(#get_current().win_data, 2)\n  eq(get_map_win_id() ~= nil, true)\n\n  -- Should be independently closed\n  child.api.nvim_set_current_tabpage(init_tabpage)\n  map_close()\n  eq(child.lua_get('vim.tbl_count(MiniMap.current.win_data)'), 1)\n  eq(get_map_win_id(), vim.NIL)\n\n  child.api.nvim_set_current_tabpage(second_tabpage)\n  eq(get_map_win_id() ~= nil, true)\nend\n\nT['open()']['can open pure scrollbar'] = function()\n  set_lines(example_lines)\n  set_cursor(15, 0)\n  child.cmd('normal! zz')\n  map_open({ window = { width = 1 } })\n  child.expect_screenshot()\nend\n\nT['open()']['works after previous window was closed manually'] = function()\n  map_open()\n  eq(#child.api.nvim_tabpage_list_wins(0), 2)\n  child.api.nvim_win_close(get_map_win_id(), true)\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\n\n  expect.no_error(map_open)\n  eq(#child.api.nvim_tabpage_list_wins(0), 2)\nend\n\nT['open()']['shows appropriate integration counts'] = function()\n  child.lua([[_G.integration_many_matches = function()\n    local res = {}\n    for i = 1, 11 do\n      for j = 1, i do\n        table.insert(res, { line = i, hl_group = 'Operator' })\n      end\n    end\n    return res\n  end]])\n\n  set_lines(example_lines)\n  child.lua([[MiniMap.open({\n    integrations = { _G.integration_many_matches },\n    symbols = { encode = { ' ', '█', resolution = { row = 1, col = 1 } } }\n  })]])\n  child.expect_screenshot()\nend\n\nT['open()']['respects `MiniMapNormal` highlight group'] = function()\n  set_lines(example_lines)\n  child.cmd('hi MiniMapNormal ctermfg=black')\n  map_open({ window = { winblend = 0 } })\n\n  -- Open separate floating window for comparison\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, true, tbl_repeat('bbbbb', 10))\n  child.api.nvim_open_win(buf_id, false, {\n    relative = 'editor',\n    anchor = 'NW',\n    row = 0,\n    col = 0,\n    width = 5,\n    height = 10,\n  })\n\n  -- Highlighting of map and other floating window should differ\n  child.expect_screenshot()\nend\n\nT['open()']['respects `vim.{g,b}.minimap_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minimap_disable = true\n\n    map_open()\n    eq(#child.api.nvim_tabpage_list_wins(0), 1)\n  end,\n})\n\nT['refresh()'] =\n  new_set({ hooks = {\n    pre_case = function()\n      child.set_size(30, 30)\n      disable_map_updates()\n    end,\n  } })\n\nT['refresh()']['works'] = function()\n  map_open()\n\n  set_lines(example_lines)\n  set_cursor(15, 0)\n  mock_test_integration()\n  child.expect_screenshot()\n\n  map_refresh()\n  child.expect_screenshot()\nend\n\nT['refresh()']['works without opened map'] = function() expect.no_error(map_refresh) end\n\nT['refresh()']['respects `opts.integrations` argument'] = function()\n  set_lines(example_lines)\n  map_open()\n\n  source_test_integration()\n  child.lua('MiniMap.refresh({ integrations = { _G.test_integration } })')\n  child.expect_screenshot()\n\n  -- Updates current data accordingly\n  eq(child.lua_get('MiniMap.current.opts.integrations[1] == _G.test_integration'), true)\nend\n\nT['refresh()']['respects `opts.symbols` argument'] = function()\n  set_lines(example_lines)\n  source_test_encode_symbols()\n\n  map_open()\n\n  child.lua([[MiniMap.refresh({\n    symbols = { encode = _G.test_encode_symbols, scroll_line = '>', scroll_view = '+' },\n  })]])\n  child.expect_screenshot()\n\n  -- Updates current data accordingly\n  eq(child.lua_get('MiniMap.current.opts.symbols.scroll_line'), '>')\nend\n\nT['refresh()']['respects `opts.window` argument'] = function()\n  set_lines(example_lines)\n  map_open()\n\n  --stylua: ignore\n  local opts = {\n    window = { focusable = true, side = 'left', show_integration_count = false, width = 15, winblend = 50, zindex = 20 },\n  }\n  map_refresh(opts)\n\n  child.expect_screenshot()\n  eq(child.api.nvim_win_get_option(get_map_win_id(), 'winblend'), 50)\n  eq(child.api.nvim_win_get_config(get_map_win_id()).zindex, 20)\n\n  -- Updates current data accordingly\n  eq(child.lua_get('MiniMap.current.opts.window'), opts.window)\nend\n\nT['refresh()']['respects `parts` argument'] = function()\n  map_open()\n  child.expect_screenshot()\n\n  set_lines(tbl_repeat('aa aa aa', #example_lines))\n  set_cursor(15, 0)\n  mock_test_integration()\n\n  -- Nothing should have changed in map window\n  map_refresh({}, { integrations = false, lines = false, scrollbar = false })\n  child.expect_screenshot()\n\n  -- Only lines should have changed in map window\n  map_refresh({}, { integrations = false, lines = true, scrollbar = false })\n  child.expect_screenshot()\n\n  -- Only scrollbar should have changed in map window\n  set_lines(example_lines)\n  map_refresh({}, { integrations = false, lines = false, scrollbar = true })\n  child.expect_screenshot()\n\n  -- Only integration highlights should have changed in map window\n  set_cursor(1, 0)\n  map_refresh({}, { integrations = true, lines = false, scrollbar = false })\n  child.expect_screenshot()\nend\n\nT['refresh()']['is not affected by `MiniMap.config.window`'] = function()\n  child.lua('MiniMap.config.window.width = 10')\n\n  map_open()\n  eq(get_map_width(), 10)\n\n  child.lua('MiniMap.config.window.width = 20')\n  map_refresh()\n  eq(get_map_width(), 10)\nend\n\nT['refresh()']['updates `MiniMap.current`'] = function()\n  child.lua('MiniMap.config.window.width = 20')\n  map_open()\n  eq(child.api.nvim_win_get_width(get_map_win_id()), 20)\n  eq(child.lua_get('MiniMap.current.opts.window.width'), 20)\nend\n\nT['refresh()']['respects `MiniMap.current`'] = function()\n  -- Check that any interactive refresh keeps all windows with synced options\n  map_open()\n  child.lua([[MiniMap.current.opts.window.side = 'left']])\n\n  eq(get_map_win_side(), 'right')\n  map_refresh()\n  eq(get_map_win_side(), 'left')\nend\n\nT['refresh()']['respects `vim.{g,b}.minimap_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    disable_map_updates()\n    map_open()\n\n    child[var_type].minimap_disable = true\n    set_lines(example_lines)\n    map_refresh()\n    -- Shouldn't show any map lines\n    child.expect_screenshot()\n  end,\n})\n\nT['close()'] = new_set()\n\nT['close()']['works'] = function()\n  map_open()\n  eq(#child.api.nvim_tabpage_list_wins(0), 2)\n  map_close()\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\nend\n\nT['close()']['resets `MiniMap.current.opts` after closing last map window'] = function()\n  local is_current_opts_reset = function() return child.lua_get('vim.tbl_count(MiniMap.current.opts)') == 0 end\n\n  map_open()\n  local init_tabpage = child.api.nvim_get_current_tabpage()\n  child.cmd('tabedit')\n  local second_tabpage = child.api.nvim_get_current_tabpage()\n  map_open()\n\n  eq(#child.api.nvim_list_wins(), 4)\n  eq(is_current_opts_reset(), false)\n\n  child.api.nvim_set_current_tabpage(init_tabpage)\n  map_close()\n  eq(#child.api.nvim_list_wins(), 3)\n  eq(is_current_opts_reset(), false)\n\n  child.api.nvim_set_current_tabpage(second_tabpage)\n  map_close()\n  eq(#child.api.nvim_list_wins(), 2)\n  eq(is_current_opts_reset(), true)\nend\n\nT['close()']['does not error if window was closed manually'] = function()\n  map_open()\n  eq(#child.api.nvim_tabpage_list_wins(0), 2)\n  child.api.nvim_win_close(get_map_win_id(), true)\n  eq(#child.api.nvim_tabpage_list_wins(0), 1)\n\n  -- Should not error and make proper clean up\n  eq(#get_current().win_data, 1)\n  expect.no_error(map_close)\n  eq(#get_current().win_data, 0)\nend\n\nT['close()']['disrespects `vim.{g,b}.minimap_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    map_open()\n    eq(get_n_shown_windows(), 2)\n    child[var_type].minimap_disable = true\n\n    map_close()\n    eq(get_n_shown_windows(), 1)\n  end,\n})\n\nT['toggle()'] = new_set()\n\nT['toggle()']['works'] = function()\n  eq(get_n_shown_windows(), 1)\n\n  child.lua('MiniMap.toggle()')\n  eq(get_n_shown_windows(), 2)\n  eq(vim.tbl_count(get_current().win_data), 1)\n\n  child.lua('MiniMap.toggle()')\n  eq(get_n_shown_windows(), 1)\n  eq(vim.tbl_count(get_current().win_data), 0)\nend\n\nT['toggle_focus()'] = new_set()\n\nT['toggle_focus()']['works'] = function()\n  set_lines(example_lines)\n  set_cursor(15, 10)\n\n  local init_win = child.api.nvim_get_current_win()\n  map_open()\n  eq(child.api.nvim_get_current_win(), init_win)\n\n  -- Should move focus to map window\n  child.lua('MiniMap.toggle_focus()')\n  eq(child.api.nvim_get_current_win(), get_map_win_id())\n\n  -- Moving cursor in map window should move cursor in previous window (line -\n  -- first one encoded by the current map line; column - first non-blank)\n  -- More tests in integration tests\n  set_cursor(1, 0)\n  child.lua('MiniMap.toggle_focus()')\n  eq(child.api.nvim_get_current_win(), init_win)\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['toggle_focus()']['respects `use_previous_cursor`'] = function()\n  set_lines(example_lines)\n  set_cursor(15, 10)\n  map_open()\n\n  child.lua('MiniMap.toggle_focus()')\n  set_cursor(1, 0)\n  child.lua('MiniMap.toggle_focus(true)')\n  eq(get_cursor(), { 15, 10 })\nend\n\nT['toggle_focus()']['does not move to first non-blank in source if no movement in map'] = function()\n  set_lines(example_lines)\n  set_cursor(15, 10)\n  local init_win = child.api.nvim_get_current_win()\n\n  map_open()\n  child.lua('MiniMap.toggle_focus()')\n  eq(child.api.nvim_get_current_win(), get_map_win_id())\n\n  child.lua('MiniMap.toggle_focus()')\n  eq(child.api.nvim_get_current_win(), init_win)\n  eq(get_cursor(), { 15, 10 })\nend\n\nT['toggle_side()'] = new_set()\n\nT['toggle_side()']['works'] = function()\n  -- Can be used without opened window\n  expect.no_error(function() child.lua('MiniMap.toggle_side()') end)\n\n  map_open()\n  eq(get_map_win_side(), 'right')\n  child.lua('MiniMap.toggle_side()')\n  eq(get_map_win_side(), 'left')\n  child.lua('MiniMap.toggle_side()')\n  eq(get_map_win_side(), 'right')\nend\n\nT['current'] = new_set()\n\nT['current']['has initial value'] = function()\n  eq(get_current(), {\n    buf_data = {},\n    opts = {},\n    win_data = {},\n  })\nend\n\nT['current']['has correct `buf_data` structure'] = function()\n  local init_buf = child.api.nvim_get_current_buf()\n  map_open()\n  local all_bufs = child.api.nvim_list_bufs()\n  eq(#all_bufs, 2)\n  local map_buf_id = all_bufs[1] == init_buf and all_bufs[2] or all_bufs[1]\n\n  eq(child.lua_get('MiniMap.current.buf_data'), { source = init_buf, map = map_buf_id })\nend\n\nT['current']['has correct `opts` structure'] = function()\n  map_open()\n  eq(child.lua_get('vim.deep_equal(MiniMap.current.opts, MiniMap.config)'), true)\nend\n\nT['current']['has correct `win_data` structure'] = function()\n  map_open()\n  local init_tabpage = child.api.nvim_get_current_tabpage()\n  child.cmd('tabedit')\n  local second_tabpage = child.api.nvim_get_current_tabpage()\n  map_open()\n\n  local opts_win_data = child.lua_get('MiniMap.current.win_data')\n  eq_keys(opts_win_data, { init_tabpage, second_tabpage })\n\n  local buf_1 = child.api.nvim_win_get_buf(opts_win_data[init_tabpage])\n  eq(child.api.nvim_buf_get_option(buf_1, 'filetype'), 'minimap')\n\n  local buf_2 = child.api.nvim_win_get_buf(opts_win_data[init_tabpage])\n  eq(child.api.nvim_buf_get_option(buf_2, 'filetype'), 'minimap')\nend\n\nlocal validate_gen_encode_symbols = function(field, id)\n  child.lua(string.format([[_G.symbols = MiniMap.gen_encode_symbols['%s']('%s')]], field, id))\n\n  local cmd = string.format(\n    [[MiniMap.encode_strings(vim.fn.readfile('%s'), { symbols = _G.symbols })]],\n    get_resolution_test_file(id)\n  )\n\n  eq(child.lua_get(cmd), child.lua_get('{ table.concat(_G.symbols) }'))\nend\n\nT['gen_encode_symbols'] = new_set()\n\nT['gen_encode_symbols']['can be used as `MiniMap.config.symbols.encode`'] = function()\n  child.set_size(30, 30)\n  unload_module()\n  child.lua([[_G.map = require('mini.map')]])\n  child.lua([[_G.map.setup({ symbols = { encode = _G.map.gen_encode_symbols.block('1x2') } })]])\n\n  set_lines(example_lines)\n  map_open()\n  child.expect_screenshot()\nend\n\nT['gen_encode_symbols']['can be used as part of `opts.symbols.encode`'] = function()\n  child.set_size(30, 30)\n\n  set_lines(example_lines)\n  child.lua([[MiniMap.open({ symbols = { encode = MiniMap.gen_encode_symbols.block('1x2') } })]])\n  child.expect_screenshot()\nend\n\nT['gen_encode_symbols']['block()'] = function()\n  validate_gen_encode_symbols('block', '1x2')\n  validate_gen_encode_symbols('block', '2x1')\n  validate_gen_encode_symbols('block', '2x2')\n  validate_gen_encode_symbols('block', '3x2')\nend\n\nT['gen_encode_symbols']['dot()'] = function()\n  validate_gen_encode_symbols('dot', '3x2')\n  validate_gen_encode_symbols('dot', '4x2')\nend\n\nT['gen_encode_symbols']['shade()'] = function()\n  validate_gen_encode_symbols('shade', '1x2')\n  validate_gen_encode_symbols('shade', '2x1')\nend\n\nlocal map_open_with_integration = function(integration)\n  local cmd = string.format('MiniMap.open({ integrations = { MiniMap.gen_integration.%s() } })', integration)\n  child.lua(cmd)\nend\n\nT['gen_integration'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(30, 30)\n      set_lines(example_lines)\n      set_cursor(15, 0)\n    end,\n  },\n})\n\nT['gen_integration']['builtin_search()'] = new_set()\n\nT['gen_integration']['builtin_search()']['works'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 1 and {} or { ignore_text = { 30 }, ignore_attr = { 30 } }\n  map_open_with_integration('builtin_search')\n\n  -- It should show counts for actual matches, not matched lines\n  type_keys('/', ' a', '<CR>')\n  child.expect_screenshot(screen_opts)\n\n  -- Should not affect cursor\n  local cur_pos = get_cursor()\n  map_refresh()\n  eq(get_cursor(), cur_pos)\n\n  -- Should respect 'hlsearch' option\n  child.o.hlsearch = false\n  map_refresh()\n  child.expect_screenshot(screen_opts)\nend\n\nT['gen_integration']['builtin_search()']['respects `hl_groups` argument'] = function()\n  map_open_with_integration('builtin_search')\n\n  child.lua([[MiniMap.config.integrations = {\n    MiniMap.gen_integration.builtin_search({ search = 'MiniMapSymbolLine' })\n  }]])\n  type_keys('/', ' a', '<CR>')\n\n  local output = child.lua_get('MiniMap.config.integrations[1]()')\n  for _, v in ipairs(output) do\n    eq(v.hl_group, 'MiniMapSymbolLine')\n  end\nend\n\nT['gen_integration']['builtin_search()']['updates when appropriate'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 1 and {} or { ignore_text = { 30 }, ignore_attr = { 30 } }\n  map_open_with_integration('builtin_search')\n\n  type_keys('/', ' a', '<CR>')\n  child.expect_screenshot(screen_opts)\n\n  -- Should update when 'hlsearch' option is changed\n  child.o.hlsearch = false\n  child.expect_screenshot(screen_opts)\n\n  child.o.hlsearch = true\n  child.expect_screenshot(screen_opts)\n\n  -- Should update when `v:hlsearch` is changed (like `\\h` in 'mini.basics')\n  if child.fn.has('nvim-0.10') == 0 then return end\n\n  child.v.hlsearch = false\n  child.expect_screenshot(screen_opts)\n\n  child.v.hlsearch = true\n  child.expect_screenshot(screen_opts)\n\n  -- Ideally, it should also update when starting highlight search after\n  -- `n/N/*`, etc.), but it currently doesn't seem possible\n  -- See https://github.com/neovim/neovim/issues/18879\nend\n\nT['gen_integration']['builtin_search()']['respects documented keymaps'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 1 and {} or { ignore_text = { 30 }, ignore_attr = { 30 } }\n  map_open_with_integration('builtin_search')\n\n  child.lua([[\n    for _, key in ipairs({ 'n', 'N', '*', '#' }) do\n      vim.keymap.set(\n        'n',\n        key,\n        key ..\n          '<Cmd>lua MiniMap.refresh({}, {lines = false, scrollbar = false})<CR>'\n      )\n    end]])\n\n  local validate = function(key)\n    type_keys('/', ' a', '<CR>')\n    child.cmd('nohlsearch')\n\n    -- Should update map highlighting\n    type_keys(key)\n    child.expect_screenshot(screen_opts)\n  end\n\n  validate('n')\n  validate('N')\n  validate('*')\n  validate('#')\nend\n\nT['gen_integration']['diagnostic()'] = new_set()\n\nT['gen_integration']['diagnostic()']['works'] = function()\n  mock_diagnostic()\n  map_open_with_integration('diagnostic')\n  child.expect_screenshot()\nend\n\nT['gen_integration']['diagnostic()']['respects `hl_groups` argument'] = function()\n  mock_diagnostic()\n\n  local validate = function(hl_groups)\n    map_close()\n    local cmd = string.format(\n      [[MiniMap.open({ integrations = { MiniMap.gen_integration.diagnostic(%s) } })]],\n      vim.inspect(hl_groups)\n    )\n    child.lua(cmd)\n\n    child.expect_screenshot()\n\n    map_close()\n  end\n\n  -- Each valid non-nil entry results into showing that diagnostic severity\n  validate({ warn = 'DiagnosticFloatingWarn' })\n  validate({ info = 'DiagnosticFloatingInfo' })\n  validate({ hint = 'DiagnosticFloatingHint' })\n\n  -- Higher severity should have higher priority\n  validate({\n    error = 'DiagnosticFloatingError',\n    warn = 'DiagnosticFloatingWarn',\n    info = 'DiagnosticFloatingInfo',\n    hint = 'DiagnosticFloatingHint',\n  })\nend\n\nT['gen_integration']['diagnostic()']['updates when appropriate'] = function()\n  map_open()\n\n  mock_diagnostic()\n  child.lua('MiniMap.current.opts.integrations = { MiniMap.gen_integration.diagnostic() }')\n  child.expect_screenshot()\n  child.cmd('doautocmd DiagnosticChanged')\n  child.expect_screenshot()\nend\n\nT['gen_integration']['gitsigns()'] = new_set()\n\nT['gen_integration']['gitsigns()']['works'] = function()\n  mock_gitsigns()\n  map_open_with_integration('gitsigns')\n  child.expect_screenshot()\n\n  --stylua: ignore\n  eq(\n    child.lua_get('MiniMap.current.opts.integrations[1]()'),\n    {\n      { line = 1,    hl_group = 'GitSignsAdd' },\n      { line = 2,    hl_group = 'GitSignsAdd' },\n      { line = 4,    hl_group = 'GitSignsDelete' },\n      { line = 7,    hl_group = 'GitSignsChange' },\n      { line = 8,    hl_group = 'GitSignsChange' },\n      { line = 9,    hl_group = 'GitSignsAdd' },\n      { line = 10,   hl_group = 'GitSignsAdd' },\n      { line = 11,   hl_group = 'GitSignsAdd' },\n      { line = 12,   hl_group = 'GitSignsAdd' },\n      { line = 0,    hl_group = 'GitSignsDelete' },\n      { line = 1000, hl_group = 'GitSignsAdd' },\n    }\n  )\nend\n\nT['gen_integration']['gitsigns()']['respects `hl_groups` argument'] = function()\n  mock_gitsigns()\n  child.lua([[MiniMap.open({\n    integrations = { MiniMap.gen_integration.gitsigns({ delete = 'Special' }) }\n  })]])\n  child.expect_screenshot()\n\n  eq(\n    child.lua_get('MiniMap.current.opts.integrations[1]()'),\n    { { line = 4, hl_group = 'Special' }, { line = 0, hl_group = 'Special' } }\n  )\nend\n\nT['gen_integration']['gitsigns()']['updates when appropriate'] = function()\n  map_open()\n\n  mock_gitsigns()\n  child.lua('MiniMap.current.opts.integrations = { MiniMap.gen_integration.gitsigns() }')\n  child.expect_screenshot()\n  child.cmd('doautocmd User GitSignsUpdate')\n  child.expect_screenshot()\nend\n\nT['gen_integration']['gitsigns()']['works if no \"gitsigns\" is detected'] = function()\n  eq(child.lua_get('MiniMap.gen_integration.gitsigns()()'), {})\nend\n\nT['gen_integration']['diff()'] = new_set()\n\nT['gen_integration']['diff()']['works'] = function()\n  child.set_size(20, 30)\n  mock_diff()\n  map_open_with_integration('diff')\n  child.expect_screenshot()\n\n  --stylua: ignore\n  eq(\n    child.lua_get('MiniMap.current.opts.integrations[1]()'),\n    {\n      { line = 1 , hl_group = 'MiniDiffSignAdd'    },\n      { line = 2 , hl_group = 'MiniDiffSignAdd'    },\n      { line = 4 , hl_group = 'MiniDiffSignDelete' },\n      { line = 6 , hl_group = 'MiniDiffSignChange' },\n      { line = 7 , hl_group = 'MiniDiffSignChange' },\n      { line = 8 , hl_group = 'MiniDiffSignAdd'    },\n      { line = 9 , hl_group = 'MiniDiffSignAdd'    },\n      { line = 10, hl_group = 'MiniDiffSignAdd'     },\n      { line = 11, hl_group = 'MiniDiffSignAdd'     },\n      { line = 12, hl_group = 'MiniDiffSignAdd'     },\n      { line = 13, hl_group = 'MiniDiffSignAdd'    },\n    }\n  )\nend\n\nT['gen_integration']['diff()']['respects `hl_groups` argument'] = function()\n  mock_diff()\n  child.lua([[MiniMap.open({\n    integrations = { MiniMap.gen_integration.diff({ delete = 'Special' }) }\n  })]])\n  eq(child.lua_get('MiniMap.current.opts.integrations[1]()'), { { line = 4, hl_group = 'Special' } })\nend\n\nT['gen_integration']['diff()']['updates when appropriate'] = function()\n  map_open()\n\n  mock_diff()\n  child.lua([[\n    local refresh_orig = MiniMap.refresh\n    MiniMap.refresh = function(...)\n      _G.n = (_G.n or 0) + 1\n      refresh_orig(...)\n    end\n  ]])\n  child.lua('MiniMap.current.opts.integrations = { MiniMap.gen_integration.diff() }')\n  child.lua('_G.n = 0')\n  child.cmd('doautocmd User MiniDiffUpdated')\n  eq(child.lua_get('_G.n'), 1)\nend\n\nT['gen_integration']['diff()']['works if no diff data is found'] = function()\n  -- Not enabled buffer\n  mock_diff()\n  child.lua('MiniDiff.disable(0)')\n  eq(child.lua_get('MiniDiff.get_buf_data(0)'), vim.NIL)\n  eq(child.lua_get('MiniMap.gen_integration.diff()()'), {})\n\n  -- No 'mini.diff'\n  child.lua([[\n    MiniDiff = nil\n    package.loaded['mini.diff'] = nil\n    require = function() error() end\n  ]])\n  eq(child.lua_get('MiniMap.gen_integration.diff()()'), {})\nend\n\n-- Integration tests ==========================================================\nT['Window'] = new_set()\n\nT['Window']['fully updates on buffer enter'] = function()\n  child.set_size(30, 30)\n  mock_test_integration()\n\n  local buf_1 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_1, 0, -1, true, { 'aa', 'aa', 'aa', '   aa', '   aa' })\n\n  local buf_2 = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_2, 0, -1, true, example_lines)\n\n  child.api.nvim_set_current_buf(buf_1)\n  map_open()\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_buf(buf_2)\n  child.expect_screenshot()\nend\n\nT['Window']['fully updates on buffer write'] = function()\n  child.set_size(15, 20)\n  mock_test_integration()\n  child.o.autoindent = false\n\n  map_open()\n  type_keys('i', 'aaa<CR>', '   aa<CR>', '   aa')\n\n  child.expect_screenshot()\n  child.cmd('doautocmd BufWritePost')\n  child.expect_screenshot()\nend\n\nT['Window']['fully updates on text change in Normal mode'] = function()\n  child.set_size(15, 20)\n  mock_test_integration()\n\n  set_lines({ 'aaa', '   aa', '   aa' })\n  set_cursor(3, 0)\n  map_open()\n\n  child.expect_screenshot()\n  type_keys('d', 'k')\n  child.expect_screenshot()\nend\n\nT['Window']['fully updates on vim resize'] = function()\n  child.set_size(30, 30)\n  mock_test_integration()\n\n  set_lines(extended_example_lines)\n  map_open()\n  child.expect_screenshot()\n  child.o.lines = 15\n  child.expect_screenshot()\nend\n\nT['Window']['fully updates on mode change to Normal'] = function()\n  child.set_size(15, 20)\n  mock_test_integration()\n  child.o.autoindent = false\n  set_lines({ 'aa', '   aa', '   aa' })\n  set_cursor(1, 0)\n\n  map_open()\n  type_keys('i', '   bb<CR>', '   bb<CR>', 'bb<CR>')\n  child.expect_screenshot()\n  type_keys('<Esc>')\n  child.expect_screenshot()\nend\n\nT['Window']['implements buffer local mappings'] = function()\n  set_lines(example_lines)\n  map_open()\n\n  local validate = function(key, ref_cursor)\n    set_cursor(15, 10)\n    child.lua('MiniMap.toggle_focus()')\n    set_cursor(1, 0)\n    type_keys(key)\n    eq(get_cursor(), ref_cursor)\n  end\n\n  -- `<CR>` should accept currently showed line in source buffer and put on\n  -- first non-blank character in line\n  validate('<CR>', { 1, 2 })\n\n  -- `<Esc>` should return to exact previous cursor position\n  validate('<Esc>', { 15, 10 })\nend\n\nT['Window']['has options in sync across all opened windows'] = function()\n  map_open()\n  child.cmd('tabedit')\n  map_open()\n\n  type_keys('1gt')\n  map_refresh({ window = { side = 'left' } })\n  eq(get_map_win_side(), 'left')\n\n  type_keys('2gt')\n  eq(get_map_win_side(), 'left')\nend\n\nT['Window']['does not account for folds'] = function()\n  child.set_size(30, 30)\n  set_lines(extended_example_lines)\n\n  map_open()\n  child.expect_screenshot()\n\n  -- Make fold\n  set_cursor(7, 0)\n  type_keys('zf', '24j')\n\n  -- Should treat top and bottom visible lines as is\n  set_cursor(1, 0)\n  type_keys('7G')\n  child.expect_screenshot()\n  type_keys('j')\n  child.expect_screenshot()\nend\n\nT['Window']['is not focusable by default'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  set_lines(example_lines)\n  map_open()\n\n  child.cmd('wincmd w')\n  eq(child.api.nvim_get_current_win(), init_win_id)\nend\n\nT['Window']['can be made focusable by mouse with `window.focusable = true`'] = function()\n  set_lines(example_lines)\n  map_open({ window = { focusable = true, side = 'left' } })\n\n  -- Ensure drawn floating window (github.com/neovim/neovim/issues/25643)\n  child.cmd('redraw')\n  child.api.nvim_input_mouse('left', 'press', '', 0, 5, 5)\n  eq(child.api.nvim_get_current_win(), get_map_win_id())\nend\n\nT['Window']['ensures target window is valid'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  child.cmd('wincmd s')\n  local target_win_id = child.api.nvim_get_current_win()\n  map_open()\n  child.lua('MiniMap.toggle_focus()')\n\n  -- Closing target window should result into recomputing new target window\n  child.api.nvim_win_close(target_win_id, true)\n  child.lua('MiniMap.toggle_focus()')\n  eq(child.api.nvim_get_current_win(), init_win_id)\nend\n\nT['Window'][\"does not respect 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.set_size(15, 20)\n  child.o.winborder = 'rounded'\n  map_open()\n  child.expect_screenshot()\nend\n\nT['Scrollbar'] = new_set()\n\nT['Scrollbar']['updates on cursor movement'] = function()\n  child.set_size(30, 30)\n  set_lines(example_lines)\n  map_open()\n  local init_integration_update_count = child.lua_get('_G.n_test_integration_calls')\n\n  set_cursor(1, 0)\n  child.expect_screenshot()\n  type_keys('3j')\n  child.expect_screenshot()\n  type_keys('5l')\n  child.expect_screenshot()\n  type_keys('G')\n  child.expect_screenshot()\n\n  -- Integrations shouldn't be called on cursor movement\n  eq(child.lua_get('_G.n_test_integration_calls'), init_integration_update_count)\nend\n\nT['Scrollbar']['updates on source window scrolling'] = function()\n  child.set_size(30, 30)\n  set_lines(example_lines)\n  map_open()\n  local init_integration_update_count = child.lua_get('_G.n_test_integration_calls')\n\n  set_cursor(21, 0)\n  child.expect_screenshot()\n  type_keys('zz')\n  child.expect_screenshot()\n\n  -- Integrations shouldn't be called on window scroll\n  eq(child.lua_get('_G.n_test_integration_calls'), init_integration_update_count)\nend\n\nT['Pure scrollbar'] = new_set()\n\nT['Pure scrollbar']['works'] = function()\n  child.set_size(30, 30)\n  set_lines(example_lines)\n  map_open({ window = { width = 1, show_integration_count = false } })\n\n  -- Should try to span all height in case of few lines\n  child.expect_screenshot()\n  type_keys('G')\n  child.expect_screenshot()\nend\n\nT['Pure scrollbar']['is active when width is lower than offset'] = function()\n  child.set_size(30, 30)\n  set_lines(example_lines)\n\n  -- Still should be pure scrollbar because integration count is shown\n  map_open({ window = { width = 2, show_integration_count = true } })\n  child.expect_screenshot()\n\n  -- Still should be pure scrollbar because scroll symbols are wider\n  map_refresh({ symbols = { scroll_line = '><' }, window = { width = 3 } })\n  child.expect_screenshot()\n\n  -- Should stop being pure scrollbar ones actual encoding can be shown\n  map_refresh({ window = { width = 4 } })\n  child.expect_screenshot()\nend\n\nT['Cursor in map window'] = new_set()\n\nT['Cursor in map window']['moves cursor in source window'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  local validate_source_cursor = function(ref_cursor) eq(child.api.nvim_win_get_cursor(init_win_id), ref_cursor) end\n  set_lines(example_lines)\n  set_cursor(2, 10)\n  map_open()\n  child.lua('MiniMap.toggle_focus()')\n\n  -- It shouldn't move just after focusing\n  eq(get_cursor(), { 1, 2 })\n  validate_source_cursor({ 2, 10 })\n\n  type_keys('l')\n  validate_source_cursor({ 1, 0 })\n\n  type_keys('j')\n  validate_source_cursor({ 4, 0 })\n\n  -- It puts source cursor on the first source line which is encoded as current\n  -- map line\n  type_keys('G')\n  validate_source_cursor({ 22, 0 })\nend\n\nT['Cursor in map window']['opens enough folds in source window'] = function()\n  child.set_size(30, 30)\n  set_lines(example_lines)\n\n  -- Make fold\n  set_cursor(4, 0)\n  type_keys('zf', '2j')\n  set_cursor(1, 0)\n\n  map_open()\n  child.expect_screenshot()\n  child.lua('MiniMap.toggle_focus()')\n  type_keys('2G')\n  child.expect_screenshot()\nend\n\nT['Cursor in map window']['can not move on scrollbar or integration counts'] = function()\n  set_lines(example_lines)\n  set_cursor(1, 0)\n\n  map_open()\n  child.lua('MiniMap.toggle_focus()')\n  eq(get_cursor(), { 1, 2 })\n\n  type_keys('h')\n  eq(get_cursor(), { 1, 2 })\n\n  type_keys('0')\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['Cursor in map window']['is properly set outside of `MiniMap.toggle_focus()`'] = function()\n  set_lines(example_lines)\n  set_cursor(15, 0)\n\n  map_open({ window = { focusable = true } })\n  type_keys('<C-w><C-w>')\n  eq(child.api.nvim_get_current_win(), get_map_win_id())\n  eq(get_cursor(), { 5, 2 })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_misc.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\nlocal project_root = vim.fs.normalize(vim.fn.fnamemodify(vim.fn.getcwd(), ':p'))\nlocal dir_misc_path = project_root .. '/tests/dir-misc'\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('misc', config) end\nlocal unload_module = function() child.mini_unload('misc') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal make_path = function(...) return vim.fs.normalize(table.concat({...}, '/')) end\nlocal make_abspath = function(...) return make_path(project_root, ...) end\nlocal getcwd = function() return child.fs.normalize(child.fn.getcwd()) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal edit = function(x) child.cmd('edit ' .. x) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\nlocal get_filetype = function(buf_id)\n  if buf_id == nil or buf_id == 0 then buf_id = child.api.nvim_get_current_buf() end\n  return child.api.nvim_get_option_value('filetype', { buf = buf_id })\nend\n\nlocal set_filetype = function(buf_id, value)\n  if buf_id == nil or buf_id == 0 then buf_id = child.api.nvim_get_current_buf() end\n  return child.api.nvim_set_option_value('filetype', value, { buf = buf_id })\nend\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\nlocal micro_time = 1\nlocal no_term_response_delay = 1000\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniMisc)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniMisc.config)'), 'table')\n\n  eq(child.lua_get('MiniMisc.config.make_global'), { 'put', 'put_text' })\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ make_global = { 'put' } })\n  eq(child.lua_get('MiniMisc.config.make_global'), { 'put' })\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ make_global = 'a' }, 'make_global', 'table')\n  expect_config_error({ make_global = { 'a' } }, 'make_global', \"exported 'mini.misc' methods\")\nend\n\nT['setup()']['creates global functions'] = function()\n  eq(child.lua_get('type(_G.put)'), 'function')\n  eq(child.lua_get('type(_G.put_text)'), 'function')\nend\n\nT['bench_time()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua('_G.small_time = ' .. small_time)\n      child.lua('_G.f = function(ms) ms = ms or _G.small_time; vim.loop.sleep(ms); return ms end')\n    end,\n  },\n})\n\nlocal bench_time = function(...) return unpack(child.lua_get('{ MiniMisc.bench_time(_G.f, ...) }', { ... })) end\n\n-- Validate that benchmark is within tolerable error from target. This is\n-- needed due to random nature of benchmarks.\nlocal validate_benchmark = function(time_tbl, target)\n  helpers.skip_if_slow()\n\n  local s, n = 0, 0\n  for _, x in ipairs(time_tbl) do\n    s, n = s + x, n + 1\n  end\n\n  local error = 0.2\n  eq(n * target * (1 - error) < s, true)\n  eq(s < target * (1 + error) * n, true)\nend\n\nT['bench_time()']['works'] = function()\n  local b, res = bench_time()\n  -- By default should run function once\n  eq(#b, 1)\n  validate_benchmark(b, 0.001 * small_time)\n  -- Second value is function output\n  eq(res, small_time)\nend\n\nT['bench_time()']['respects `n` argument'] = function()\n  local b, _ = bench_time(5)\n  -- By default should run function once\n  eq(#b, 5)\n  validate_benchmark(b, 0.001 * small_time)\nend\n\nT['bench_time()']['respects `...` as benched time arguments'] = function()\n  local b, res = bench_time(1, 5 * small_time)\n  validate_benchmark(b, 0.001 * 5 * small_time)\n  -- Second value is function output\n  eq(res, 5 * small_time)\nend\n\nT['get_gutter_width()'] = new_set()\n\nT['get_gutter_width()']['works'] = function()\n  -- By default there is no gutter ('sign column')\n  eq(child.lua_get('MiniMisc.get_gutter_width()'), 0)\n\n  -- This setting indeed makes gutter with width of two columns\n  child.wo.signcolumn = 'yes:1'\n  eq(child.lua_get('MiniMisc.get_gutter_width()'), 2)\nend\n\nT['get_gutter_width()']['respects `win_id` argument'] = function()\n  child.cmd('split')\n  local windows = child.api.nvim_list_wins()\n\n  child.api.nvim_win_set_option(windows[1], 'signcolumn', 'yes:1')\n  eq(child.lua_get('MiniMisc.get_gutter_width(...)', { windows[2] }), 0)\nend\n\nT['log_add()'] = new_set()\n\nlocal validate_log = function(ref_log)\n  local log = child.lua_get('MiniMisc.log_get()')\n  eq(#log, #ref_log)\n\n  -- Validate timestamp and non-timestamp data separately\n  local log_small, prev_timestamp = {}, 0\n  for i, l in ipairs(log) do\n    log_small[i] = vim.deepcopy(l)\n    log_small[i].timestamp = nil\n\n    eq(type(l.timestamp), 'number')\n    eq(prev_timestamp < l.timestamp, true)\n    prev_timestamp = l.timestamp\n  end\n  eq(log_small, ref_log)\nend\n\nT['log_add()']['works'] = function()\n  child.lua([[\n    local t = { a = 1 }\n    MiniMisc.log_add('before', t)\n    MiniMisc.log_add('before nodeepcopy', t, { deepcopy = false })\n    t.a = t.a + 1\n    MiniMisc.log_add('after', t)\n\n    MiniMisc.log_add('types 1', { 1, 'text', { x = true } })\n    MiniMisc.log_add('types 2', true)\n    MiniMisc.log_add('types 3', nil)\n\n    MiniMisc.log_add(1, 'number desc')\n    MiniMisc.log_add(nil, 'no desc')\n  ]])\n\n  validate_log({\n    { desc = 'before', state = { a = 1 } },\n    { desc = 'before nodeepcopy', state = { a = 2 } },\n    { desc = 'after', state = { a = 2 } },\n    { desc = 'types 1', state = { 1, 'text', { x = true } } },\n    { desc = 'types 2', state = true },\n    { desc = 'types 3' },\n    { desc = 1, state = 'number desc' },\n    { state = 'no desc' },\n  })\n\n  -- Should allow function in log entry\n  local fun_in_log = child.lua([[\n    MiniMisc.log_add('func 1', function() return 1 end)\n    MiniMisc.log_add('func 2', { f = function() return 2 end })\n\n    local log = MiniMisc.log_get()\n    return { log[#log - 1].state(), log[#log].state.f() }\n  ]])\n  eq(fun_in_log, { 1, 2 })\n\n  -- Should properly set timestamps\n  child.lua('_G.small_time = ' .. vim.inspect(small_time))\n  local diff = child.lua([[\n    MiniMisc.log_add('ts 1', 1)\n    vim.loop.sleep(10 * _G.small_time)\n    MiniMisc.log_add('ts 2', 2)\n\n    local log = MiniMisc.log_get()\n    return log[#log].timestamp - log[#log - 1].timestamp\n  ]])\n  eq((9 * small_time) < diff and diff < (11 * small_time), true)\nend\n\nT['log_get()'] = new_set()\n\nT['log_get()']['works'] = function()\n  -- Most of the testing is done in tests for other functions\n  local log = child.lua([[\n    MiniMisc.log_add('desc', { a = 1 })\n    return MiniMisc.log_get()\n  ]])\n  eq(type(log), 'table')\n  eq(vim.tbl_count(log), 1)\n  local entry_names = vim.tbl_keys(log[1])\n\n  table.sort(entry_names)\n  eq(entry_names, { 'desc', 'state', 'timestamp' })\n\n  eq(log[1].desc, 'desc')\n  eq(log[1].state, { a = 1 })\n  eq(type(log[1].timestamp), 'number')\n  eq(log[1].timestamp > 0, true)\nend\n\nT['log_show()'] = new_set()\n\nT['log_show()']['works'] = function()\n  -- Set up windows\n  local buf_id_other = child.api.nvim_get_current_buf()\n  local win_id_other = child.api.nvim_get_current_win()\n  child.cmd('vert split')\n  local win_id = child.api.nvim_get_current_win()\n\n  -- Should start showing log in a new scratch buffer in the current window\n  child.lua('MiniMisc.log_add(\"desc\", { a = 1 })')\n  child.lua('MiniMisc.log_show()')\n  local buf_id_log = child.api.nvim_get_current_buf()\n  eq(child.api.nvim_buf_get_name(buf_id_log), 'minimisc://' .. buf_id_log .. '/log')\n\n  local validate_wins = function()\n    eq(child.api.nvim_win_get_buf(win_id), buf_id_log)\n    eq(child.api.nvim_win_get_buf(win_id_other), buf_id_other)\n    eq(child.api.nvim_get_current_win(), win_id)\n    eq(buf_id_log == buf_id_other, false)\n  end\n\n  local validate_lines = function(ref_lines)\n    local log_lines = child.api.nvim_buf_get_lines(buf_id_log, 0, -1, false)\n    local mock_ts = 12.33\n    for i = 1, #log_lines do\n      log_lines[i] = log_lines[i]:gsub('timestamp = %d+%.%d+', function()\n        mock_ts = mock_ts + 0.01\n        return 'timestamp = ' .. mock_ts\n      end)\n    end\n    eq(log_lines, ref_lines)\n  end\n\n  validate_wins()\n\n  local ref_lines = {\n    '{ {',\n    '    desc = \"desc\",',\n    '    state = {',\n    '      a = 1',\n    '    },',\n    '    timestamp = 12.34',\n    '  } }',\n  }\n  validate_lines(ref_lines)\n\n  -- Should reuse buffer and window\n  child.api.nvim_set_current_win(win_id_other)\n  child.lua('MiniMisc.log_add(\"desc\", { b = 2 })')\n  child.lua('MiniMisc.log_show()')\n  validate_wins()\n\n  ref_lines = {\n    '{ {',\n    '    desc = \"desc\",',\n    '    state = {',\n    '      a = 1',\n    '    },',\n    '    timestamp = 12.34',\n    '  }, {',\n    '    desc = \"desc\",',\n    '    state = {',\n    '      b = 2',\n    '    },',\n    '    timestamp = 12.35',\n    '  } }',\n  }\n  validate_lines(ref_lines)\nend\n\nT['log_clear()'] = new_set()\n\nT['log_clear()']['works'] = function()\n  child.lua('_G.notify_log = {}; vim.notify = function(...) table.insert(_G.notify_log, { ... }) end')\n  child.lua('_G.small_time = ' .. vim.inspect(small_time))\n  local log = child.lua([[\n    MiniMisc.log_add('desc 1', 1)\n    vim.loop.sleep(10 * _G.small_time)\n    MiniMisc.log_add('desc 2', 2)\n\n    MiniMisc.log_clear()\n    MiniMisc.log_add('after clear', 3)\n\n    return MiniMisc.log_get()\n  ]])\n\n  validate_log({ { desc = 'after clear', state = 3 } })\n  -- Should restart start value for timestamps\n  eq(log[1].timestamp < small_time, true)\n\n  eq(child.lua_get('_G.notify_log'), { { '(mini.misc) Cleared log' } })\nend\n\nlocal validate_put = {\n  put = function(args, reference_output)\n    local capture = child.cmd_capture(('lua MiniMisc.put(%s)'):format(args))\n    eq(capture, table.concat(reference_output, '\\n'))\n  end,\n\n  put_text = function(args, reference_output)\n    set_lines({})\n    child.lua(('MiniMisc.put_text(%s)'):format(args))\n\n    -- Insert text under current line\n    table.insert(reference_output, 1, '')\n    eq(get_lines(), reference_output)\n  end,\n}\n\nT['put()/put_text()'] = new_set({\n  parametrize = { { 'put' }, { 'put_text' } },\n})\n\nT['put()/put_text()']['works'] = function(put_name)\n  local validate = validate_put[put_name]\n\n  validate('{ a = 1, b = true }', { '{', '  a = 1,', '  b = true', '}' })\nend\n\nT['put()/put_text()']['allows several arguments'] = function(put_name)\n  local validate = validate_put[put_name]\n\n  child.lua('_G.a = 1; _G.b = true')\n  validate('_G.a, _G.b', { '1', 'true' })\nend\n\nT['put()/put_text()']['handles tuple function output'] = function(put_name)\n  local validate = validate_put[put_name]\n\n  child.lua('_G.f = function() return 1, true end')\n  validate('_G.f()', { '1', 'true' })\nend\n\nT['put()/put_text()']['prints `nil` values'] = function(put_name)\n  local validate = validate_put[put_name]\n\n  validate('nil', { 'nil' })\n  validate('1, nil', { '1', 'nil' })\n  validate('nil, 2', { 'nil', '2' })\n  validate('1, nil, 2', { '1', 'nil', '2' })\nend\n\nlocal resize_initial_width, resize_win_id\nT['resize_window()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Prepare two windows\n      resize_initial_width = child.api.nvim_win_get_width(0)\n      child.cmd('vsplit')\n      resize_win_id = child.api.nvim_list_wins()[1]\n    end,\n  },\n})\n\nT['resize_window()']['works'] = function()\n  local target_width = math.floor(0.25 * resize_initial_width)\n  -- This sets gutter width to 4\n  child.api.nvim_win_set_option(resize_win_id, 'signcolumn', 'yes:2')\n\n  child.lua('MiniMisc.resize_window(...)', { resize_win_id, target_width })\n  eq(child.api.nvim_win_get_width(resize_win_id), target_width + 4)\nend\n\nT['resize_window()']['correctly computes default `text_width` argument'] = function()\n  child.wo.signcolumn = 'yes:2'\n\n  -- min(vim.o.columns, 79) < textwidth < colorcolumn\n  child.o.columns = 160\n  child.lua('MiniMisc.resize_window(0)')\n  eq(child.api.nvim_win_get_width(0), 79 + 4)\n\n  child.o.columns = 60\n  child.lua('MiniMisc.resize_window(0)')\n  -- Should set to maximum available width, which is less than `columns` by 1\n  -- (window separator) and 'winminwidth'\n  eq(child.api.nvim_win_get_width(0), 60 - 1 - child.o.winminwidth)\n\n  child.bo.textwidth = 50\n  child.lua('MiniMisc.resize_window(0)')\n  eq(child.api.nvim_win_get_width(0), 50 + 4)\n\n  child.wo.colorcolumn = '+2,-2'\n  child.lua('MiniMisc.resize_window(0)')\n  eq(child.api.nvim_win_get_width(0), 52 + 4)\n\n  child.wo.colorcolumn = '-2,+2'\n  child.lua('MiniMisc.resize_window(0)')\n  eq(child.api.nvim_win_get_width(0), 48 + 4)\n\n  child.wo.colorcolumn = '40,-2'\n  child.lua('MiniMisc.resize_window(0)')\n  eq(child.api.nvim_win_get_width(0), 40 + 4)\nend\n\nT['safely()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Create a log to track execution\n      child.lua('_G.log = {}')\n\n      -- Mock `vim.notify()`\n      child.lua([[\n        _G.notify_log = {}\n        local inverse_levels = {}\n        for k, v in pairs(vim.log.levels) do\n          inverse_levels[v] = k\n        end\n        vim.notify = function(msg, lvl, opts)\n          table.insert(_G.notify_log, { msg, inverse_levels[lvl], opts })\n        end\n      ]])\n    end,\n  },\n})\n\nlocal safely = function(when, f_string)\n  local lua_cmd = string.format('MiniMisc.safely(%s, %s)', vim.inspect(when), f_string)\n  child.lua(lua_cmd)\nend\n\nlocal validate_notify_log = function(ref_log)\n  local log = child.lua_get('_G.notify_log')\n  eq(#log, #ref_log)\n  for i = 1, #log do\n    -- Validate notification message by pattern matching\n    expect.match(log[i][1], ref_log[i][1])\n    eq(log[i][2], ref_log[i][2])\n    eq(log[i][3], ref_log[i][3])\n  end\n\n  child.lua('_G.notify_log = {}')\nend\n\nlocal validate_log = function(ref_log)\n  eq(child.lua_get('_G.log'), ref_log)\n  child.lua('_G.log = {}')\nend\n\n-- Helper for populating functions that use `safely` to test proper traceback\nlocal populate_nested_funs = function(safely_when)\n  child.lua('_G.safely_when = ' .. vim.inspect(safely_when))\n  child.lua([[\n    _G.inner_fun = function(arg) error('My custom error') end\n    _G.outer_fun = function()\n      MiniMisc.safely(_G.safely_when, function(...)\n        table.insert(_G.log, { _G.safely_when, ... }); _G.inner_fun()\n      end)\n    end\n  ]])\nend\n\nT['safely()']['works with \"now\"'] = function()\n  populate_nested_funs('now')\n  child.lua([[\n    _G.outer_fun()\n    table.insert(_G.log, 'Should be still executed')\n  ]])\n\n  -- Should execute, report error as a warning with useful traceback\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n\n  -- Should not block next code\n  validate_log({ { 'now' }, 'Should be still executed' })\nend\n\nT['safely()']['works with \"later\"'] = function()\n  populate_nested_funs('later')\n  child.lua([[\n    _G.outer_fun()\n    table.insert(_G.log, 'Should be executed first')\n  ]])\n\n  sleep(micro_time)\n\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ 'Should be executed first', { 'later' } })\nend\n\nT['safely()']['clears \"later\" queue between different event loops'] = function()\n  child.lua([[\n    _G.f = function() table.insert(_G.log, 'later') end\n    MiniMisc.safely('later', _G.f)\n    _G.immediate_log = vim.deepcopy(_G.log)\n  ]])\n  eq(child.lua_get('_G.immediate_log'), {})\n  sleep(micro_time)\n  validate_log({ 'later' })\n\n  child.lua('MiniMisc.safely(\"later\", _G.f)')\n  sleep(2 * micro_time)\n  -- If it did not clear the queue, it would have been 2 new elements\n  validate_log({ 'later' })\nend\n\nT['safely()']['works with \"delay\"'] = function()\n  local delay = 5 * small_time\n  populate_nested_funs('delay:' .. delay)\n  child.lua('_G.outer_fun()')\n\n  sleep(delay - small_time)\n  validate_notify_log({})\n  sleep(2 * small_time)\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ { 'delay:' .. delay } })\nend\n\nT['safely()']['works with \"event\" without patterns'] = function()\n  populate_nested_funs('event:InsertEnter,CmdlineEnter')\n  child.lua('_G.outer_fun()')\n  validate_notify_log({})\n\n  -- Should execute exactly once on whichever event triggers first\n  type_keys('i')\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ { 'event:InsertEnter,CmdlineEnter' } })\n\n  type_keys('<Esc>', ':')\n  validate_notify_log({})\n\n  -- Should not block triggering other events (even nested) inside callback\n  child.lua([[\n    _G.log = {}\n    vim.cmd('au BufEnter * lua table.insert(_G.log, \"BufEnter\")')\n    vim.cmd('au FileType * lua table.insert(_G.log, vim.bo.filetype)')\n    vim.cmd('au User Test lua table.insert(_G.log, \"Test\")')\n    MiniMisc.safely('event:BufEnter', function()\n      vim.bo.filetype = 'my-filetype'\n      vim.api.nvim_exec_autocmds('User', { pattern = 'Test' })\n\n      -- Although triggers `BufEnter`, should *not* execute this function\n      vim.api.nvim_set_current_buf(vim.api.nvim_create_buf(false, true))\n    end)\n  ]])\n  local buf_id = child.api.nvim_create_buf(false, true)\n  validate_log({})\n  child.api.nvim_set_current_buf(buf_id)\n  validate_log({ 'BufEnter', 'my-filetype', 'Test', 'BufEnter' })\nend\n\nT['safely()']['works with \"event\" with patterns'] = function()\n  local setup = function(when)\n    populate_nested_funs(when)\n    child.lua('_G.outer_fun()')\n    validate_notify_log({})\n  end\n\n  -- Should execute exactly once on whichever combo triggers first\n  local when_cmdline = 'event:CmdlineEnter,CmdlineLeave~:,/'\n  setup(when_cmdline)\n  type_keys(':')\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ { when_cmdline } })\n  type_keys('<Esc>')\n  validate_notify_log({})\n  validate_log({})\n\n  setup(when_cmdline)\n  type_keys('/')\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ { when_cmdline } })\n  type_keys('<Esc>')\n  validate_notify_log({})\n  validate_log({})\n\n  -- Order of events in `when` should not matter\n  local when_cmdline_2 = 'event:CmdlineLeave,CmdlineEnter~/,:'\n  setup(when_cmdline_2)\n  type_keys(':')\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ { when_cmdline_2 } })\n  type_keys('<Esc>')\n  validate_notify_log({})\n  validate_log({})\nend\n\nT['safely()']['works with \"filetype\"'] = function()\n  populate_nested_funs('filetype:aaa,bbb')\n  child.lua('_G.outer_fun()')\n  validate_notify_log({})\n\n  local buf_id = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(buf_id)\n  validate_notify_log({})\n\n  -- Should execute exactly once and only on relevant filetypes\n  child.bo.filetype = 'xxx'\n  validate_notify_log({})\n\n  child.bo.filetype = 'aaa'\n  validate_notify_log({ { 'My custom error.*inner_fun.*safely.*outer_fun', 'WARN' } })\n  validate_log({ { 'filetype:aaa,bbb' } })\n\n  child.bo.filetype = 'bbb'\n  validate_notify_log({})\n  validate_log({})\nend\n\nT['safely()']['with \"filetype\" redetects filetype'] = function()\n  edit(make_path(dir_misc_path, 'lang.aaa'))\n  child.bo.filetype = 'aaa'\n  local buf_aaa_1 = child.api.nvim_get_current_buf()\n\n  edit(make_path(dir_misc_path, 'dir', 'lang.aaa'))\n  child.bo.filetype = 'aaa'\n  local buf_aaa_2 = child.api.nvim_get_current_buf()\n\n  edit(make_path(dir_misc_path, 'dir', 'subdir', 'lang.aaa'))\n  local buf_lang_aaa = child.api.nvim_get_current_buf()\n  -- As file name matches 'ftdetect', it should be redetected even if filetype\n  -- does not match one from `when`\n  child.bo.filetype = 'xxx'\n\n  edit('not-aaa')\n  local buf_not_aaa = child.api.nvim_get_current_buf()\n  child.bo.filetype = 'yyy'\n\n  -- Should redetect in current and non-current loaded buffers\n  child.api.nvim_buf_delete(buf_aaa_1, { unload = true })\n  eq(child.api.nvim_buf_is_loaded(buf_aaa_1), false)\n\n  child.o.packpath = child.o.packpath .. ',' .. dir_misc_path\n  child.lua('MiniMisc.safely(\"filetype:aaa\", function() vim.cmd(\"packadd mocked-lang-plugin\") end)')\n\n  edit(make_path(dir_misc_path, 'dir', 'subdir-2', 'lang.aaa'))\n  local buf_aaa_3 = child.api.nvim_get_current_buf()\n  eq(child.lua_get('_G.lang_plugin_ftdetect'), vim.NIL)\n\n  child.bo.filetype = 'aaa'\n  eq(child.lua_get('_G.lang_plugin_ftdetect'), { 'ftdetect/aaa.lua' })\n\n  eq(child.api.nvim_buf_is_loaded(buf_aaa_1), false)\n  eq(get_filetype(buf_aaa_2), 'lang-aaa')\n  eq(child.bo.filetype, 'lang-aaa')\n\n  eq(get_filetype(buf_lang_aaa), 'lang-aaa')\n\n  eq(get_filetype(buf_not_aaa), 'yyy')\n\n  -- Should also source proper ftplugins after redetection\n  local ref_ftplugin_history = {\n    [tostring(buf_aaa_2)] = true,\n    [tostring(buf_lang_aaa)] = true,\n    [tostring(buf_aaa_3)] = true,\n    ['ftplugin/lang-aaa.lua'] = 3,\n  }\n  eq(child.lua_get('_G.lang_plugin_ftplugin'), ref_ftplugin_history)\nend\n\nT['safely()']['with \"filetype\" resources filetype scripts'] = function()\n  local buf_aaa_1 = child.api.nvim_create_buf(true, false)\n  set_filetype(buf_aaa_1, 'aaa')\n  child.api.nvim_buf_delete(buf_aaa_1, { unload = true })\n  eq(child.api.nvim_buf_is_loaded(buf_aaa_1), false)\n\n  local buf_aaa_2 = child.api.nvim_create_buf(true, false)\n  set_filetype(buf_aaa_2, 'aaa')\n\n  local buf_not_aaa = child.api.nvim_create_buf(true, false)\n  set_filetype(buf_not_aaa, 'xxx')\n\n  child.o.packpath = child.o.packpath .. ',' .. dir_misc_path\n  child.lua('MiniMisc.safely(\"filetype:aaa\", function() vim.cmd(\"packadd mocked-lang-plugin\") end)')\n\n  local buf_aaa_3 = child.api.nvim_create_buf(true, false)\n  eq(child.lua_get('_G.lang_plugin_ftplugin'), vim.NIL)\n\n  set_filetype(buf_aaa_3, 'aaa')\n  local ref_ftplugin_history = {\n    [tostring(buf_aaa_2)] = true,\n    [tostring(buf_aaa_3)] = true,\n    ['ftplugin/aaa.lua'] = 2,\n  }\n  eq(child.lua_get('_G.lang_plugin_ftplugin'), ref_ftplugin_history)\n\n  eq(child.api.nvim_buf_is_loaded(buf_aaa_1), false)\n  eq(get_filetype(buf_aaa_2), 'aaa')\n  eq(get_filetype(buf_aaa_3), 'aaa')\n  eq(get_filetype(buf_not_aaa), 'xxx')\nend\n\nT['safely()']['with \"filetype\" skips redetect if no filetype detection'] = function()\n  child.cmd('filetype off')\n\n  child.o.packpath = child.o.packpath .. ',' .. dir_misc_path\n  child.lua('MiniMisc.safely(\"filetype:aaa\", function() vim.cmd(\"packadd mocked-lang-plugin\") end)')\n\n  local buf_aaa_1 = child.api.nvim_create_buf(true, false)\n  set_filetype(buf_aaa_1, 'aaa')\n  eq(child.lua_get('_G.lang_plugin_ftdetect'), vim.NIL)\n  eq(child.lua_get('_G.lang_plugin_ftplugin'), vim.NIL)\nend\n\nT['safely()']['with \"filetype\" skips redetect if function errored'] = function()\n  child.o.packpath = child.o.packpath .. ',' .. dir_misc_path\n  child.lua([[MiniMisc.safely(\"filetype:aaa\", function()\n    vim.cmd(\"packadd mocked-lang-plugin\")\n    error('Unexpected error after adding a plugin')\n  end)]])\n\n  edit(make_path(dir_misc_path, 'lang.aaa'))\n  set_filetype(0, 'aaa')\n\n  -- 'ftdetect/' scripts are run by `:packadd`, but their rules should not be\n  -- re-applied on existing buffers (even if filetype matches)\n  eq(child.lua_get('_G.lang_plugin_ftdetect'), { 'ftdetect/aaa.lua' })\n  eq(get_filetype(0), 'aaa')\n\n  eq(child.lua_get('_G.lang_plugin_ftplugin'), vim.NIL)\nend\n\nT['safely()']['can be nested'] = function()\n  local delay = 5 * small_time\n  child.lua('_G.delay = ' .. delay)\n  child.lua([[\n    MiniMisc.safely('now', function()\n      table.insert(_G.log, 'now 1')\n\n      MiniMisc.safely('delay:' .. _G.delay, function() table.insert(_G.log, 'delay 1') end)\n      MiniMisc.safely('event:User~Test', function() table.insert(_G.log, 'event 1') end)\n      MiniMisc.safely('filetype:aaa', function() table.insert(_G.log, 'filetype 1') end)\n\n      MiniMisc.safely('now', function()\n        vim.api.nvim_exec_autocmds('User', { pattern = 'Test' })\n        table.insert(_G.log, 'now 2')\n      end)\n\n      MiniMisc.safely('later', function()\n        table.insert(_G.log, 'later 1')\n\n        MiniMisc.safely('later', function()\n          table.insert(_G.log, 'later 2')\n          vim.bo.filetype = 'aaa'\n        end)\n        MiniMisc.safely('now', function() table.insert(_G.log, 'now 3') end)\n      end)\n    end)\n  ]])\n\n  sleep(delay + small_time)\n  validate_log({ 'now 1', 'event 1', 'now 2', 'later 1', 'now 3', 'later 2', 'filetype 1', 'delay 1' })\nend\n\nT['safely()']['validates input'] = function()\n  expect.error(function() safely(1, 'function() end') end, '`when`.*string')\n  expect.error(function() safely('xxx', 'function() end') end, 'Could not parse `when`')\n  expect.error(function() safely('now', '1') end, '`f`.*callable')\nend\n\nlocal git_repo_path = make_abspath('tests/dir-misc/mocked-git-repo')\nlocal git_path = make_abspath('tests/dir-misc/mocked-git-repo/.git')\nlocal test_file_makefile = make_abspath('tests/dir-misc/aaa.lua')\nlocal test_file_git = make_abspath('tests/dir-misc/mocked-git-repo/bbb.lua')\n\nlocal init_mock_git = function(git_type)\n  if git_type == 'file' then\n    -- File '.git' is used inside submodules\n    child.fn.writefile({ '' }, git_path)\n  else\n    child.fn.mkdir(git_path)\n  end\nend\n\nlocal cleanup_mock_git = function() child.fn.delete(git_path, 'rf') end\n\nT['setup_auto_root()'] = new_set({ hooks = { post_case = cleanup_mock_git } })\n\nlocal setup_auto_root = function(...) child.lua('MiniMisc.setup_auto_root(...)', { ... }) end\n\nT['setup_auto_root()']['works'] = function()\n  eq(getcwd(), project_root)\n  child.o.autochdir = true\n\n  setup_auto_root()\n\n  -- Resets 'autochdir'\n  eq(child.o.autochdir, false)\n\n  -- Creates autocommand\n  eq(child.lua_get([[#vim.api.nvim_get_autocmds({ group = 'MiniMiscAutoRoot' })]]) > 0, true)\n\n  -- Respects 'Makefile'\n  child.cmd('edit ' .. test_file_makefile)\n  eq(getcwd(), dir_misc_path)\n\n  -- Respects '.git' directory and file\n  for _, git_type in ipairs({ 'directory', 'file' }) do\n    init_mock_git(git_type)\n    child.cmd('edit ' .. test_file_git)\n    eq(getcwd(), git_repo_path)\n    cleanup_mock_git()\n  end\nend\n\nT['setup_auto_root()']['validates input'] = function()\n  expect.error(function() setup_auto_root('a') end, '`names`.*array')\n  expect.error(function() setup_auto_root({ 1 }) end, '`names`.*string')\n  expect.error(function() setup_auto_root({ '.git' }, 1) end, '`fallback`.*callable')\nend\n\nT['setup_auto_root()']['respects `names` argument'] = function()\n  init_mock_git('directory')\n  setup_auto_root({ 'Makefile' })\n\n  -- Should not stop on git repo directory, but continue going up\n  child.cmd('edit ' .. test_file_git)\n  eq(getcwd(), dir_misc_path)\nend\n\nT['setup_auto_root()']['allows callable `names`'] = function()\n  init_mock_git('directory')\n  child.lua([[_G.find_aaa = function(x) return x == 'aaa.lua' end]])\n  child.lua('MiniMisc.setup_auto_root(_G.find_aaa)')\n\n  -- Should not stop on git repo directory, but continue going up\n  child.cmd('edit ' .. test_file_git)\n  eq(child.lua_get('MiniMisc.find_root(0, _G.find_aaa)'), dir_misc_path)\n  eq(getcwd(), dir_misc_path)\nend\n\nT['setup_auto_root()']['respects `fallback` argument'] = function()\n  -- Should return and cache fallback result if not found root by going up\n  -- NOTE: More tests are done in `find_root()`\n  local lua_cmd = string.format(\n    [[MiniMisc.setup_auto_root({ 'non-existing' }, function(path) _G.path_arg = path; return %s end)]],\n    vim.inspect(dir_misc_path)\n  )\n  child.lua(lua_cmd)\n\n  child.cmd('edit ' .. test_file_git)\n  eq(child.lua_get('_G.path_arg'), child.fs.normalize(child.api.nvim_buf_get_name(0)))\n  eq(getcwd(), dir_misc_path)\nend\n\nT['setup_auto_root()']['works in buffers without path'] = function()\n  setup_auto_root()\n\n  local scratch_buf_id = child.api.nvim_create_buf(false, true)\n\n  local cur_dir = getcwd()\n  child.api.nvim_set_current_buf(scratch_buf_id)\n  eq(getcwd(), cur_dir)\nend\n\nT['setup_auto_root()']['works only for current buffer'] = function()\n  setup_auto_root()\n  init_mock_git('file')\n\n  child.lua('_G.log = {}')\n  child.lua('_G.path_1 = ' .. vim.inspect(test_file_makefile))\n  child.lua('_G.path_2 = ' .. vim.inspect(test_file_git))\n  child.cmd('autocmd DirChanged * lua table.insert(_G.log, vim.fn.getcwd())')\n\n  child.lua([[\n    vim.cmd('edit ' .. vim.fn.fnameescape(_G.path_1))\n    local buf_id_1 = vim.api.nvim_get_current_buf()\n    vim.cmd('edit ' .. vim.fn.fnameescape(_G.path_2))\n    vim.api.nvim_buf_delete(buf_id_1, { force = true })\n  ]])\n  local log = vim.tbl_map(child.fs.normalize, child.lua_get('_G.log'))\n  eq(log, { git_repo_path })\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['setup_auto_root()']['triggers nested autocommands'] = function()\n  setup_auto_root()\n  child.cmd('au DirChanged * lua _G.hello = \"world\"')\n  child.cmd('edit ' .. test_file_makefile)\n  eq(child.lua_get('_G.hello'), 'world')\nend\n\nT['find_root()'] = new_set({ hooks = { post_case = cleanup_mock_git } })\n\nlocal find_root = function(...) return child.lua_get('MiniMisc.find_root(...)', { ... }) end\n\nT['find_root()']['works'] = function()\n  -- Respects 'Makefile'\n  child.cmd('edit ' .. test_file_makefile)\n  eq(find_root(), dir_misc_path)\n  child.cmd('%bwipeout')\n\n  -- Respects '.git' directory and file\n  for _, git_type in ipairs({ 'directory', 'file' }) do\n    init_mock_git(git_type)\n    child.cmd('edit ' .. test_file_git)\n    eq(find_root(), git_repo_path)\n    child.cmd('%bwipeout')\n    cleanup_mock_git()\n  end\nend\n\nT['find_root()']['validates arguments'] = function()\n  expect.error(function() find_root('a') end, '`buf_id`.*buffer id')\n  expect.error(function() find_root(-1) end, '`buf_id`.*buffer id')\n  expect.error(function() find_root(0, 1) end, '`names`.*string')\n  expect.error(function() find_root(0, '.git') end, '`names`.*array')\n  expect.error(function() find_root(0, { '.git' }, 1) end, '`fallback`.*callable')\nend\n\nT['find_root()']['respects `buf_id` argument'] = function()\n  init_mock_git('directory')\n\n  child.cmd('edit ' .. test_file_makefile)\n  local init_buf_id = child.api.nvim_get_current_buf()\n  child.cmd('edit ' .. test_file_git)\n  eq(child.api.nvim_get_current_buf() ~= init_buf_id, true)\n\n  eq(find_root(init_buf_id), dir_misc_path)\nend\n\nT['find_root()']['respects `names` argument'] = function()\n  init_mock_git('directory')\n\n  -- Should not stop on git repo directory, but continue going up\n  child.cmd('edit ' .. test_file_git)\n  eq(find_root(0, { 'aaa.lua' }), dir_misc_path)\nend\n\nT['find_root()']['allows callable `names`'] = function()\n  init_mock_git('directory')\n  child.cmd('edit ' .. test_file_git)\n\n  child.lua([[_G.find_aaa = function(x) return x == 'aaa.lua' end]])\n  eq(child.lua_get('MiniMisc.find_root(0, _G.find_aaa)'), dir_misc_path)\nend\n\nT['find_root()']['respects `fallback` argument'] = function()\n  local validate = function(fallback_output, ref)\n    local lua_cmd = string.format(\n      [[MiniMisc.find_root(\n        0,\n        { 'non-existing' },\n        function(path) _G.path_arg = path; return %s end\n      )]],\n      vim.inspect(fallback_output)\n    )\n    eq(child.lua_get(lua_cmd), ref)\n\n    -- Fallback should be called with buffer path\n    eq(child.lua_get('_G.path_arg'), child.fs.normalize(child.api.nvim_buf_get_name(0)))\n\n    -- Cleanup\n    child.lua('_G.path_arg = nil')\n  end\n\n  child.cmd('edit ' .. test_file_git)\n\n  -- Should handle incorrect fallback return without setting it to cache\n  validate(nil, vim.NIL)\n  validate(1, vim.NIL)\n  validate('non-existing', vim.NIL)\n\n  -- Should return and cache fallback result if not found root by going up\n  validate(dir_misc_path, dir_misc_path)\n\n  local after_cache = child.lua_get([[MiniMisc.find_root(0, { 'non-existing' }, function() _G.been_here = true end)]])\n  eq(after_cache, dir_misc_path)\n  eq(child.lua_get('_G.been_here'), vim.NIL)\nend\n\nT['find_root()']['works in buffers without path'] = function()\n  local scratch_buf_id = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(scratch_buf_id)\n  eq(find_root(), vim.NIL)\nend\n\nT['find_root()']['uses cache'] = function()\n  child.cmd('edit ' .. test_file_git)\n  -- Returns root based on 'Makefile' as there is no git root\n  eq(find_root(), dir_misc_path)\n\n  -- Later creation of git root should not affect output as it should be cached\n  -- from first call\n  init_mock_git('directory')\n  eq(find_root(), dir_misc_path)\nend\n\nT['setup_termbg_sync()'] = new_set({\n  hooks = {\n    pre_case = function()\n      if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`setup_termbg_sync()` works only on Neovim>=0.10') end\n\n      child.lua([[\n        -- Mock `io.stdout:write` used to send control sequences to terminal emulator\n        _G.log = {}\n        io.stdout = { write = function(self, ...) table.insert(_G.log, { ... }) end }\n\n        -- Mock attached UI\n        vim.api.nvim_list_uis = function() return { { stdout_tty = true } } end\n      ]])\n    end,\n  },\n})\n\nlocal validate_termbg_augroup = function(ref)\n  local has_augroup = pcall(child.api.nvim_get_autocmds, { group = 'MiniMiscTermbgSync', event = 'TermResponse' })\n  eq(has_augroup, ref)\nend\n\nT['setup_termbg_sync()']['works'] = new_set(\n  -- Neovim=0.10 uses string sequence as response, while Neovim>=0.11 sets it\n  -- in `sequence` table field\n  { parametrize = { { '\\027]11;rgb:1111/2626/2d2d' }, { { sequence = '\\027]11;rgb:1111/2626/2d2d' } } } },\n  {\n    test = function(response_data)\n      local eq_log = function(ref_log)\n        eq(child.lua_get('_G.log'), ref_log)\n        child.lua('_G.log = {}')\n      end\n\n      child.cmd('hi Normal guifg=#222222 guibg=#dddddd')\n      child.lua('MiniMisc.setup_termbg_sync()')\n\n      -- Should first ask if terminal emulator supports the feature\n      eq_log({ { '\\027]11;?\\007' } })\n\n      -- Mock typical response assuming '#11262d' as background color\n      child.api.nvim_exec_autocmds('TermResponse', { data = response_data })\n\n      -- Should sync immediately\n      eq_log({ { '\\027]11;#dddddd\\007' } })\n\n      -- Should sync on appropriate events\n      local validate_event = function(event, log_entry)\n        child.api.nvim_exec_autocmds(event, {})\n        eq_log({ { log_entry } })\n      end\n      validate_event('VimResume', '\\027]11;#dddddd\\007')\n      validate_event('ColorScheme', '\\027]11;#dddddd\\007')\n      validate_event('VimLeavePre', '\\027]111\\027\\\\')\n      validate_event('VimSuspend', '\\027]111\\027\\\\')\n    end,\n  }\n)\n\nT['setup_termbg_sync()']['can be called multiple times'] = function()\n  child.cmd('hi Normal guifg=#222222 guibg=#dddddd')\n  child.lua('MiniMisc.setup_termbg_sync()')\n  child.api.nvim_exec_autocmds('TermResponse', { data = '\\027]11;rgb:1111/2626/2d2d' })\n  eq(child.lua_get('_G.log'), { { '\\027]11;?\\a' }, { '\\027]11;#dddddd\\a' } })\n  child.lua('_G.log = {}')\n\n  -- If called second time, the terminal background color is already synced\n  child.lua('MiniMisc.setup_termbg_sync()')\n  child.api.nvim_exec_autocmds('TermResponse', { data = '\\027]11;rgb:dddd/dddd/dddd' })\n  eq(child.lua_get('_G.log'), { { '\\027]11;?\\a' }, { '\\027]11;#dddddd\\a' } })\n  child.lua('_G.log = {}')\n\n  -- Should reset to the color from the very first call\n  child.api.nvim_exec_autocmds('VimLeavePre', {})\n  eq(child.lua_get('_G.log'), { { '\\027]111\\027\\\\' } })\nend\n\nT['setup_termbg_sync()']['does nothing if there is no proper stdout'] = function()\n  local validate = function()\n    child.lua('MiniMisc.setup_termbg_sync()')\n    child.api.nvim_create_augroup('MiniMiscTermbgSync', { clear = false })\n    eq(child.lua_get('#vim.api.nvim_get_autocmds({ group = \"MiniMiscTermbgSync\" })'), 0)\n  end\n\n  -- No UI\n  child.lua('vim.api.nvim_list_uis = function() return {} end')\n  validate()\n\n  -- UI without stdout (like GUI)\n  child.lua('vim.api.nvim_list_uis = function() return { { stdout_tty = false } } end')\n  validate()\nend\n\nT['setup_termbg_sync()']['handles no response from terminal emulator'] = function()\n  child.lua('_G.notify_log = {}; vim.notify = function(...) table.insert(_G.notify_log, { ... }) end')\n  child.lua('MiniMisc.setup_termbg_sync()')\n  validate_termbg_augroup(true)\n\n  -- If there is no response from terminal emulator for 1s, delete autocmd\n  child.loop.sleep(no_term_response_delay + small_time)\n  validate_termbg_augroup(false)\n\n  -- Should show informative notification\n  local ref_notify = {\n    '(mini.misc) `setup_termbg_sync()` did not get proper response from terminal emulator',\n    child.lua_get('vim.log.levels.WARN'),\n  }\n  eq(child.lua_get('_G.notify_log'), { ref_notify })\nend\n\nT['setup_termbg_sync()']['handles bad response from terminal emulator'] = function()\n  child.lua('_G.notify_log = {}; vim.notify = function(...) table.insert(_G.notify_log, { ... }) end')\n  child.lua('MiniMisc.setup_termbg_sync()')\n\n  -- Should not delete augroup/autocommand or show notification yet, because\n  -- proper response might comer later\n  child.api.nvim_exec_autocmds('TermResponse', { data = 'something-bad' })\n  validate_termbg_augroup(true)\n  eq(child.lua_get('_G.notify_log'), {})\n\n  child.api.nvim_exec_autocmds('TermResponse', { data = 'other-bad' })\n  validate_termbg_augroup(true)\n  eq(child.lua_get('_G.notify_log'), {})\n\n  -- After timeout delay it should cleanup and show all bad responses\n  child.loop.sleep(no_term_response_delay + small_time)\n  validate_termbg_augroup(false)\n  local ref_notify = {\n    '(mini.misc) `setup_termbg_sync()` did not get proper response from terminal emulator,'\n      .. ' only these: { \"something-bad\", \"other-bad\" }',\n    child.lua_get('vim.log.levels.WARN'),\n  }\n  eq(child.lua_get('_G.notify_log'), { ref_notify })\nend\n\nT['setup_termbg_sync()']['handles parallel unrelated `TermResponse` events'] = function()\n  child.lua('_G.notify_log = {}; vim.notify = function(...) table.insert(_G.notify_log, { ... }) end')\n  child.lua('MiniMisc.setup_termbg_sync()')\n\n  local validate_n_termresponse = function(ref_n)\n    eq(#child.api.nvim_get_autocmds({ group = 'MiniMiscTermbgSync', event = 'TermResponse' }), ref_n)\n  end\n\n  -- After receiving bad response should still wait for possible proper one\n  child.api.nvim_exec_autocmds('TermResponse', { data = 'something-bad' })\n  validate_termbg_augroup(true)\n  validate_n_termresponse(1)\n  eq(child.lua_get('_G.notify_log'), {})\n\n  -- After receiving proper response should immediately stop waiting for it and\n  -- set up proper `termbg` autocommands\n  local seq = '\\027]11;rgb:1111/2626/2d2d'\n  local data = child.fn.has('nvim-0.11') == 1 and { sequence = seq } or seq\n  child.api.nvim_exec_autocmds('TermResponse', { data = data })\n  validate_termbg_augroup(true)\n  validate_n_termresponse(0)\n  eq(#child.api.nvim_get_autocmds({ group = 'MiniMiscTermbgSync' }) > 0, true)\n  eq(child.lua_get('_G.notify_log'), {})\nend\n\nT['setup_termbg_sync()']['handles different color formats'] = function()\n  local validate = function(term_response_color)\n    -- Mock clean start to overcome that color is parsed only once per session\n    child.lua('package.loaded[\"mini.misc\"] = nil')\n    child.lua('require(\"mini.misc\").setup_termbg_sync()')\n    child.api.nvim_exec_autocmds('TermResponse', { data = '\\027]11;' .. term_response_color })\n\n    -- Should properly parse initial background and use it to reset on exit\n    child.lua('_G.log = {}')\n    child.api.nvim_exec_autocmds('VimLeavePre', {})\n    eq(child.lua_get('_G.log'), { { '\\027]111\\027\\\\' } })\n\n    -- Clean up\n    child.lua('_G.log = {}')\n    child.api.nvim_create_augroup('MiniMiscTermbgSync', { clear = true })\n  end\n\n  validate('rgb:1234/5678/9abc', '#12569a')\n  validate('rgb:213/546/879', '#215487')\n  validate('rgb:31/75/b9', '#3175b9')\n  validate('rgb:4/8/c', '#4488cc')\n  validate('rgb:1/23/456', '#112345')\n\n  validate('rgba:1234/5678/9abc/1234', '#12569a')\n  validate('rgba:213/546/879/1234', '#215487')\n  validate('rgba:31/75/b9/1234', '#3175b9')\n  validate('rgba:4/8/c/1234', '#4488cc')\n  validate('rgba:1/23/456/1234', '#112345')\nend\n\nT['setup_termbg_sync()']['handles transparent `Normal` background'] = function()\n  child.cmd('hi Normal guifg=#222222 guibg=#dddddd')\n  child.lua('MiniMisc.setup_termbg_sync()')\n  child.api.nvim_exec_autocmds('TermResponse', { data = '\\027]11;rgb:1111/2626/2d2d' })\n  child.lua('_G.log = {}')\n\n  -- When syncing with \"transparent\" `Normal`, should restore the original\n  -- terminal background\n  child.cmd('hi Normal guifg=#222222 guibg=NONE')\n  child.api.nvim_exec_autocmds('ColorScheme', {})\n  eq(child.lua_get('_G.log'), { { '\\027]111\\027\\\\' } })\nend\n\nT['setup_termbg_sync()']['respects `opts.explicit_reset`'] = function()\n  child.cmd('hi Normal guifg=#222222 guibg=#dddddd')\n  child.lua('MiniMisc.setup_termbg_sync({ explicit_reset = true })')\n  child.api.nvim_exec_autocmds('TermResponse', { data = '\\027]11;rgb:1111/2626/2d2d' })\n  child.lua('_G.log = {}')\n\n  -- Should still sync on appropriate events\n  local validate_event = function(event, log_entry)\n    child.api.nvim_exec_autocmds(event, {})\n    eq(child.lua_get('_G.log'), { { log_entry } })\n    child.lua('_G.log = {}')\n  end\n  validate_event('VimResume', '\\027]11;#dddddd\\007')\n  validate_event('ColorScheme', '\\027]11;#dddddd\\007')\n  -- - Should reset by setting initial color explicitly\n  validate_event('VimLeavePre', '\\027]11;#11262d\\007')\n  validate_event('VimSuspend', '\\027]11;#11262d\\007')\n\n  -- Should reset with explicit bg color on transparent `Normal` background\n  child.cmd('hi Normal guifg=#222222 guibg=NONE')\n  child.api.nvim_exec_autocmds('ColorScheme', {})\n  eq(child.lua_get('_G.log'), { { '\\027]11;#11262d\\a' } })\nend\n\nlocal restore_cursor_test_file = make_path(dir_misc_path, 'restore-cursor.lua')\nlocal restore_cursor_init_file = make_path(dir_misc_path, 'init-restore-cursor.lua')\nlocal restore_cursor_shada_path = make_path(dir_misc_path, 'restore-cursor.shada')\n\nlocal cursor_set_test_type = function(x)\n  vim.env.RESTORE_CURSOR_TEST_TYPE = x\n  MiniTest.finally(function() vim.env.RESTORE_CURSOR_TEST_TYPE = '' end)\nend\n\nT['setup_restore_cursor()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Ensure that shada file is correctly set\n      child.o.shadafile = restore_cursor_shada_path\n    end,\n    post_case = function()\n      -- Don't save new shada file on child stop\n      child.o.shadafile = 'NONE'\n\n      -- Clean up\n      child.fn.delete(restore_cursor_shada_path)\n    end,\n  },\n})\n\nT['setup_restore_cursor()']['works'] = function()\n  edit(restore_cursor_test_file)\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  eq(get_cursor(), { 10, 3 })\n  -- Should center by default\n  eq(child.fn.line('w0'), 7)\nend\n\nT['setup_restore_cursor()']['validates input'] = function()\n  local setup_restore_cursor = function(...) child.lua('MiniMisc.setup_restore_cursor(...)', { ... }) end\n\n  expect.error(function() setup_restore_cursor({ center = 1 }) end, '`opts.center`.*boolean')\n  expect.error(function() setup_restore_cursor({ ignore_filetype = 1 }) end, '`opts.ignore_filetype`.*array')\nend\n\nT['setup_restore_cursor()']['respects `opts.center`'] = function()\n  edit(restore_cursor_test_file)\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n\n  cursor_set_test_type('not-center')\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  eq(get_cursor(), { 10, 3 })\n  -- Should not center line\n  eq(child.fn.line('w$'), 10)\nend\n\nT['setup_restore_cursor()']['respects `opts.ignore_filetype`'] = function()\n  edit(restore_cursor_test_file)\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n\n  cursor_set_test_type('ignore-lua')\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['setup_restore_cursor()']['restores only in normal buffer'] = function()\n  edit(restore_cursor_test_file)\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n\n  cursor_set_test_type('set-not-normal-buftype')\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['setup_restore_cursor()']['does not restore if position is already set'] = function()\n  edit(restore_cursor_test_file)\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n\n  cursor_set_test_type('set-position')\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  eq(get_cursor(), { 4, 0 })\n\n  -- Double check that `setup_restore_cursor()` was run\n  expect.match(child.cmd_capture('au MiniMiscRestoreCursor'), 'BufRead')\nend\n\nT['setup_restore_cursor()']['does not restore if position is outdated'] = function()\n  edit(restore_cursor_test_file)\n\n  -- Ensure that file content won't change even on test case error\n  local true_lines = get_lines()\n  MiniTest.finally(function() vim.fn.writefile(true_lines, restore_cursor_test_file) end)\n\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n  child.cmd('bwipeout')\n\n  -- Modify file so that position will appear outdated\n  child.fn.writefile({ '-- bbb', '-- bbb' }, restore_cursor_test_file)\n\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  eq(get_cursor(), { 1, 0 })\n\n  -- Double check that `setup_restore_cursor()` was run\n  expect.match(child.cmd_capture('au MiniMiscRestoreCursor'), 'BufRead')\nend\n\nT['setup_restore_cursor()']['opens just enough folds'] = function()\n  edit(restore_cursor_test_file)\n  set_cursor(10, 3)\n  child.cmd('wshada!')\n\n  cursor_set_test_type('make-folds')\n  child.restart({ '-u', restore_cursor_init_file, '--', restore_cursor_test_file })\n\n  -- Should open only needed folds\n  eq(get_cursor(), { 10, 3 })\n\n  eq({ child.fn.foldclosed(2), child.fn.foldclosed(3) }, { 2, 2 })\n  eq({ child.fn.foldclosed(9), child.fn.foldclosed(10) }, { -1, -1 })\n\n  -- Double check that `setup_restore_cursor()` was run\n  expect.match(child.cmd_capture('au MiniMiscRestoreCursor'), 'BufRead')\nend\n\nlocal stat_summary = function(...) return child.lua_get('MiniMisc.stat_summary({ ... })', { ... }) end\n\nT['stat_summary()'] = new_set()\n\nT['stat_summary()']['works'] = function()\n  eq(stat_summary(10, 4, 3, 2, 1), { minimum = 1, mean = 4, median = 3, maximum = 10, n = 5, sd = math.sqrt(50 / 4) })\nend\n\nT['stat_summary()']['validates input'] = function()\n  expect.error(function() stat_summary('a') end, 'array')\n  expect.error(function() stat_summary({ a = 1 }) end, 'array')\n  expect.error(function() stat_summary({ 'a' }) end, 'numbers')\nend\n\nT['stat_summary()']['works with one number'] = function()\n  eq(stat_summary(10), { minimum = 10, mean = 10, median = 10, maximum = 10, n = 1, sd = 0 })\nend\n\nT['stat_summary()']['handles even/odd number of elements for `median`'] = function()\n  eq(stat_summary(1, 2).median, 1.5)\n  eq(stat_summary(3, 1, 2).median, 2)\nend\n\nT['tbl_head()/tbl_tail()'] = new_set({\n  parametrize = { { 'tbl_head' }, { 'tbl_tail' } },\n})\n\nT['tbl_head()/tbl_tail()']['works'] = function(fun_name)\n  local example_table = { a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7 }\n\n  local validate = function(n)\n    local output = child.lua_get(('MiniMisc.%s(...)'):format(fun_name), { example_table, n })\n    local reference = math.min(vim.tbl_count(example_table), n or 5)\n    eq(vim.tbl_count(output), reference)\n  end\n\n  -- The exact values vary greatly and so seem to be untestable\n  validate(nil)\n  validate(3)\n  validate(0)\nend\n\nlocal comments_option\nT['use_nested_comments()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n      comments_option = child.bo.comments\n    end,\n  },\n})\n\nT['use_nested_comments()']['works'] = function()\n  child.bo.commentstring = '# %s'\n  child.lua('MiniMisc.use_nested_comments()')\n  eq(child.bo.comments, 'n:#,' .. comments_option)\nend\n\nT['use_nested_comments()'][\"ignores 'commentstring' with two parts\"] = function()\n  child.bo.commentstring = '/*%s*/'\n  child.lua('MiniMisc.use_nested_comments()')\n  eq(child.bo.comments, comments_option)\nend\n\nT['use_nested_comments()']['respects `buf_id` argument'] = function()\n  local new_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_option(new_buf_id, 'commentstring', '# %s')\n\n  child.lua('MiniMisc.use_nested_comments(...)', { new_buf_id })\n\n  eq(child.bo.comments, comments_option)\n  eq(child.api.nvim_buf_get_option(new_buf_id, 'comments'), 'n:#,' .. comments_option)\nend\n\nT['zoom()'] = new_set()\n\nlocal get_floating_windows = function()\n  return vim.tbl_filter(\n    function(x) return child.api.nvim_win_get_config(x).relative ~= '' end,\n    child.api.nvim_list_wins()\n  )\nend\n\nlocal validate_dims = function(win_id, height, width)\n  local config = child.api.nvim_win_get_config(win_id)\n  eq({ config.height, config.width }, { height, width })\nend\n\nT['zoom()']['works'] = function()\n  child.set_size(5, 20)\n  set_lines({ 'aaa', 'bbb' })\n  child.o.statusline = 'Statusline should not be visible in floating window'\n  child.o.winblend = 50\n\n  local buf_id = child.api.nvim_get_current_buf()\n  eq(child.lua_get('MiniMisc.zoom()'), true)\n  local floating_wins = get_floating_windows()\n\n  eq(#floating_wins, 1)\n  local win_id = floating_wins[1]\n  eq(child.api.nvim_win_get_buf(win_id), buf_id)\n  validate_dims(win_id, 4, 20)\n  eq(child.api.nvim_win_get_option(win_id, 'winblend'), 0)\n\n  -- No statusline should be present\n  child.expect_screenshot()\n\n  -- Should toggle between zoom in and out\n  eq(child.lua_get('MiniMisc.zoom()'), false)\n  eq(#get_floating_windows(), 0)\nend\n\nT['zoom()']['respects `buf_id` argument'] = function()\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.lua('MiniMisc.zoom(...)', { buf_id })\n  local floating_wins = get_floating_windows()\n\n  eq(#floating_wins, 1)\n  eq(child.api.nvim_win_get_buf(floating_wins[1]), buf_id)\nend\n\nT['zoom()']['respects `config` argument'] = function()\n  child.set_size(5, 30)\n\n  local validate = function(config, ref_height, ref_width)\n    child.lua('MiniMisc.zoom(...)', { 0, config })\n    local floating_wins = get_floating_windows()\n\n    eq(#floating_wins, 1)\n    validate_dims(floating_wins[1], ref_height, ref_width)\n    child.expect_screenshot()\n\n    child.cmd('quit')\n  end\n\n  validate({ width = 20 }, 4, 20)\n\n  -- Should adjust in reaction to border\n  validate({ border = 'double' }, 2, 28)\n\n  -- Should truncate possible title\n  validate({ width = 20, border = 'single', title = 'Custom title to check truncation' }, 2, 20)\n\n  -- Should work with different border types\n  validate({ border = { '', 'x', '', '', '', 'x', '', '' } }, 2, 30)\n  validate({ border = { '', '', '', 'x', '', '', '', 'x' } }, 4, 28)\n  validate({ border = { '!', 'x', '', '', '', '', '', 'x' } }, 3, 29)\n  validate({ border = { '', '', '', 'x' } }, 4, 28)\n  validate({ border = { '!', 'x' } }, 2, 28)\n  validate({ border = { 'x' } }, 2, 28)\nend\n\nT['zoom()'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n  child.set_size(5, 30)\n\n  local validate = function(winborder, border_arg)\n    child.o.winborder = winborder\n    local lua_cmd = string.format('MiniMisc.zoom(0, { border = %s })', vim.inspect(border_arg))\n    child.lua(lua_cmd)\n    child.expect_screenshot()\n    child.lua('MiniMisc.zoom()')\n  end\n\n  validate('rounded', nil)\n\n  -- Should prefer explicitly configured value over 'winborder'\n  validate('rounded', 'double')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  validate('+,-,+,|,+,-,+,|', nil)\nend\n\nT['zoom()']['reacts to relevant UI changes'] = function()\n  child.set_size(5, 30)\n  child.lua('MiniMisc.zoom()')\n  local win_id = get_floating_windows()[1]\n\n  validate_dims(win_id, 4, 30)\n  child.o.lines = 10\n  validate_dims(win_id, 9, 30)\n  child.o.columns = 20\n  validate_dims(win_id, 9, 20)\n  child.o.cmdheight = 0\n  validate_dims(win_id, 10, 20)\n  child.o.cmdheight = 3\n  validate_dims(win_id, 7, 20)\nend\n\nT['zoom()']['can be safely closed manually'] = function()\n  child.set_size(5, 30)\n  child.lua('MiniMisc.zoom()')\n  child.cmd('quit')\n\n  expect.no_error(function() child.cmd_capture('au MiniMiscZoom') end)\n  child.o.lines = 10\n  expect.error(function() child.cmd_capture('au MiniMiscZoom') end, 'No such group')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_move.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('move', config) end\nlocal unload_module = function() child.mini_unload('move') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\nlocal get_fold_range = function(line_num) return { child.fn.foldclosed(line_num), child.fn.foldclosedend(line_num) } end\n\nlocal setup_registers = function()\n  local reginfo_arr = {\n    { reg = '0', info = { regcontents = { '0', '0', '0' }, regtype = '\\0221' } },\n    { reg = '1', info = { regcontents = { '111', '111' }, regtype = 'V' } },\n    { reg = '2', info = { regcontents = { '222', '222' }, regtype = 'V' } },\n    { reg = '9', info = { regcontents = { '999', '999' }, regtype = 'V' } },\n    { reg = '-', info = { regcontents = { '---' }, regtype = 'v' } },\n    { reg = 'z', info = { regcontents = { 'zzz' }, regtype = 'v' } },\n    { reg = '\"', info = { points_to = 'z' } },\n  }\n  local ref = {}\n  for _, data in ipairs(reginfo_arr) do\n    child.fn.setreg(data.reg, data.info)\n    ref[data.reg] = child.fn.getreginfo(data.reg)\n  end\n  -- Make sure that 'z' register has proper `isunnamed` field\n  ref['z'] = child.fn.getreginfo('z')\n\n  return ref\nend\n\nlocal validate_state = function(lines, selection)\n  eq(get_lines(), lines)\n  eq({ { child.fn.line('v'), child.fn.col('v') }, { child.fn.line('.'), child.fn.col('.') } }, selection)\nend\n\nlocal validate_state1d = function(line, range) validate_state({ line }, { { 1, range[1] }, { 1, range[2] } }) end\n\nlocal validate_line_state = function(lines, cursor)\n  eq(get_lines(), lines)\n  eq(get_cursor(), cursor)\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniMove)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniMove.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniMove.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('mappings.left', '<M-h>')\n  expect_config('mappings.right', '<M-l>')\n  expect_config('mappings.down', '<M-j>')\n  expect_config('mappings.up', '<M-k>')\n  expect_config('mappings.line_left', '<M-h>')\n  expect_config('mappings.line_right', '<M-l>')\n  expect_config('mappings.line_down', '<M-j>')\n  expect_config('mappings.line_up', '<M-k>')\n  expect_config('options.reindent_linewise', true)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ make_global = { 'put' } })\n  eq(child.lua_get('MiniMove.config.make_global'), { 'put' })\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { left = 1 } }, 'mappings.left', 'string')\n  expect_config_error({ mappings = { down = 1 } }, 'mappings.down', 'string')\n  expect_config_error({ mappings = { up = 1 } }, 'mappings.up', 'string')\n  expect_config_error({ mappings = { right = 1 } }, 'mappings.right', 'string')\n  expect_config_error({ mappings = { line_left = 1 } }, 'mappings.line_left', 'string')\n  expect_config_error({ mappings = { line_right = 1 } }, 'mappings.line_right', 'string')\n  expect_config_error({ mappings = { line_down = 1 } }, 'mappings.line_down', 'string')\n  expect_config_error({ mappings = { line_up = 1 } }, 'mappings.line_up', 'string')\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { reindent_linewise = 1 } }, 'options.reindent_linewise', 'boolean')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_map = function(lhs, pattern) return child.cmd_capture('xmap ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('<M-h>', 'MiniMove'), true)\n\n  unload_module()\n  child.api.nvim_del_keymap('x', '<M-h>')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  load_module({ mappings = { left = '' } })\n  eq(has_map('<M-h>', 'MiniMove'), false)\nend\n\nT['move_selection()'] = new_set()\n\nlocal move = function(direction, opts) child.lua('MiniMove.move_selection(...)', { direction, opts }) end\n\nT['move_selection()']['works charwise horizontally'] = function()\n  -- Test for this many moves because there can be special cases when movement\n  -- involves second or second to last character\n  set_lines({ 'XXabcd' })\n  set_cursor(1, 0)\n  type_keys('vl')\n  validate_state1d('XXabcd', { 1, 2 })\n\n  move('right')\n  validate_state1d('aXXbcd', { 2, 3 })\n  move('right')\n  validate_state1d('abXXcd', { 3, 4 })\n  move('right')\n  validate_state1d('abcXXd', { 4, 5 })\n  move('right')\n  validate_state1d('abcdXX', { 5, 6 })\n  -- Should allow to try to move past line end without error\n  move('right')\n  validate_state1d('abcdXX', { 5, 6 })\n\n  move('left')\n  validate_state1d('abcXXd', { 4, 5 })\n  move('left')\n  validate_state1d('abXXcd', { 3, 4 })\n  move('left')\n  validate_state1d('aXXbcd', { 2, 3 })\n  move('left')\n  validate_state1d('XXabcd', { 1, 2 })\n  -- Should allow to try to move past line start without error\n  move('left')\n  validate_state1d('XXabcd', { 1, 2 })\nend\n\nT['move_selection()']['respects `opts.n_times` charwise horizontally'] = function()\n  set_lines({ 'XXabcd' })\n  set_cursor(1, 0)\n  type_keys('vl')\n  validate_state1d('XXabcd', { 1, 2 })\n\n  move('right', { n_times = 3 })\n  validate_state1d('abcXXd', { 4, 5 })\n  move('left', { n_times = 2 })\n  validate_state1d('aXXbcd', { 2, 3 })\nend\n\nT['move_selection()']['works charwise vertically'] = function()\n  set_lines({ '1XXx', '2a', '3b', '4c', '5d' })\n  set_cursor(1, 1)\n  type_keys('vl')\n  validate_state({ '1XXx', '2a', '3b', '4c', '5d' }, { { 1, 2 }, { 1, 3 } })\n\n  move('down')\n  validate_state({ '1x', '2XXa', '3b', '4c', '5d' }, { { 2, 2 }, { 2, 3 } })\n  move('down')\n  validate_state({ '1x', '2a', '3XXb', '4c', '5d' }, { { 3, 2 }, { 3, 3 } })\n  move('down')\n  validate_state({ '1x', '2a', '3b', '4XXc', '5d' }, { { 4, 2 }, { 4, 3 } })\n  move('down')\n  validate_state({ '1x', '2a', '3b', '4c', '5XXd' }, { { 5, 2 }, { 5, 3 } })\n  -- Should allow to try to move past last line without error\n  move('down')\n  validate_state({ '1x', '2a', '3b', '4c', '5XXd' }, { { 5, 2 }, { 5, 3 } })\n\n  move('up')\n  validate_state({ '1x', '2a', '3b', '4XXc', '5d' }, { { 4, 2 }, { 4, 3 } })\n  move('up')\n  validate_state({ '1x', '2a', '3XXb', '4c', '5d' }, { { 3, 2 }, { 3, 3 } })\n  move('up')\n  validate_state({ '1x', '2XXa', '3b', '4c', '5d' }, { { 2, 2 }, { 2, 3 } })\n  move('up')\n  validate_state({ '1XXx', '2a', '3b', '4c', '5d' }, { { 1, 2 }, { 1, 3 } })\n  -- Should allow to try to move past first line without error\n  move('up')\n  validate_state({ '1XXx', '2a', '3b', '4c', '5d' }, { { 1, 2 }, { 1, 3 } })\nend\n\nT['move_selection()']['respects `opts.n_times` charwise vertically'] = function()\n  set_lines({ '1XXx', '2a', '3b', '4c', '5d' })\n  set_cursor(1, 1)\n  type_keys('vl')\n  validate_state({ '1XXx', '2a', '3b', '4c', '5d' }, { { 1, 2 }, { 1, 3 } })\n\n  move('down', { n_times = 3 })\n  validate_state({ '1x', '2a', '3b', '4XXc', '5d' }, { { 4, 2 }, { 4, 3 } })\n  move('up', { n_times = 2 })\n  validate_state({ '1x', '2XXa', '3b', '4c', '5d' }, { { 2, 2 }, { 2, 3 } })\nend\n\nT['move_selection()']['works with folds charwise'] = function()\n  local setup_folds = function()\n    child.ensure_normal_mode()\n    set_lines({ '1XX', '2aa', '3bb', '4cc', '5YY' })\n\n    -- Create fold\n    type_keys('zE')\n    set_cursor(2, 0)\n    type_keys('zf', '2j')\n  end\n\n  -- Down\n  setup_folds()\n  set_cursor(1, 1)\n  type_keys('vl')\n  validate_state({ '1XX', '2aa', '3bb', '4cc', '5YY' }, { { 1, 2 }, { 1, 3 } })\n  eq(get_fold_range(2), { 2, 4 })\n\n  -- - When moving \"into fold\", it should open it\n  move('down')\n  validate_state({ '1', '2XXaa', '3bb', '4cc', '5YY' }, { { 2, 2 }, { 2, 3 } })\n  eq(get_fold_range(2), { -1, -1 })\n\n  -- Up\n  setup_folds()\n  set_cursor(5, 1)\n  type_keys('vl')\n  validate_state({ '1XX', '2aa', '3bb', '4cc', '5YY' }, { { 5, 2 }, { 5, 3 } })\n  eq(get_fold_range(2), { 2, 4 })\n\n  -- - When moving \"into fold\", it should open it. But it happens only after\n  --   entering fold, so cursor is at the start of fold. Would be nice to\n  --   change so that fold is opened before movement, but it requires some\n  --   extra non-trivial steps.\n  move('up')\n  validate_state({ '1XX', '2YYaa', '3bb', '4cc', '5' }, { { 2, 2 }, { 2, 3 } })\n  eq(get_fold_range(2), { -1, -1 })\nend\n\nT['move_selection()']['works charwise vertically on line start/end'] = function()\n  -- Line start\n  set_lines({ 'XXx', 'a', 'b' })\n  set_cursor(1, 0)\n  type_keys('vl')\n  validate_state({ 'XXx', 'a', 'b' }, { { 1, 1 }, { 1, 2 } })\n\n  move('down')\n  validate_state({ 'x', 'XXa', 'b' }, { { 2, 1 }, { 2, 2 } })\n  move('down')\n  validate_state({ 'x', 'a', 'XXb' }, { { 3, 1 }, { 3, 2 } })\n  move('up')\n  validate_state({ 'x', 'XXa', 'b' }, { { 2, 1 }, { 2, 2 } })\n  move('up')\n  validate_state({ 'XXx', 'a', 'b' }, { { 1, 1 }, { 1, 2 } })\n\n  child.ensure_normal_mode()\n\n  -- Line end\n  set_lines({ 'xXX', 'a', 'b' })\n  set_cursor(1, 1)\n  type_keys('vl')\n  validate_state({ 'xXX', 'a', 'b' }, { { 1, 2 }, { 1, 3 } })\n\n  move('down')\n  validate_state({ 'x', 'aXX', 'b' }, { { 2, 2 }, { 2, 3 } })\n  move('down')\n  validate_state({ 'x', 'a', 'bXX' }, { { 3, 2 }, { 3, 3 } })\n  move('up')\n  validate_state({ 'x', 'aXX', 'b' }, { { 2, 2 }, { 2, 3 } })\n  move('up')\n  validate_state({ 'xXX', 'a', 'b' }, { { 1, 2 }, { 1, 3 } })\n\n  child.ensure_normal_mode()\n\n  -- Whole line (but in charwise mode)\n  set_lines({ 'XX', '', '' })\n  set_cursor(1, 0)\n  type_keys('vl')\n  validate_state({ 'XX', '', '' }, { { 1, 1 }, { 1, 2 } })\n\n  move('down')\n  validate_state({ '', 'XX', '' }, { { 2, 1 }, { 2, 2 } })\n  move('down')\n  validate_state({ '', '', 'XX' }, { { 3, 1 }, { 3, 2 } })\n  move('up')\n  validate_state({ '', 'XX', '' }, { { 2, 1 }, { 2, 2 } })\n  move('up')\n  validate_state({ 'XX', '', '' }, { { 1, 1 }, { 1, 2 } })\nend\n\nT['move_selection()']['works blockwise horizontally'] = function()\n  set_lines({ 'XXabcd', 'XXabcd' })\n  set_cursor(1, 0)\n  type_keys('<C-v>', 'lj')\n  validate_state({ 'XXabcd', 'XXabcd' }, { { 1, 1 }, { 2, 2 } })\n\n  move('right')\n  validate_state({ 'aXXbcd', 'aXXbcd' }, { { 1, 2 }, { 2, 3 } })\n  move('right')\n  validate_state({ 'abXXcd', 'abXXcd' }, { { 1, 3 }, { 2, 4 } })\n  move('right')\n  validate_state({ 'abcXXd', 'abcXXd' }, { { 1, 4 }, { 2, 5 } })\n  move('right')\n  validate_state({ 'abcdXX', 'abcdXX' }, { { 1, 5 }, { 2, 6 } })\n  -- Should allow to try to move past line end without error\n  move('right')\n  validate_state({ 'abcdXX', 'abcdXX' }, { { 1, 5 }, { 2, 6 } })\n\n  move('left')\n  validate_state({ 'abcXXd', 'abcXXd' }, { { 1, 4 }, { 2, 5 } })\n  move('left')\n  validate_state({ 'abXXcd', 'abXXcd' }, { { 1, 3 }, { 2, 4 } })\n  move('left')\n  validate_state({ 'aXXbcd', 'aXXbcd' }, { { 1, 2 }, { 2, 3 } })\n  move('left')\n  validate_state({ 'XXabcd', 'XXabcd' }, { { 1, 1 }, { 2, 2 } })\n  -- Should allow to try to move past line start without error\n  move('left')\n  validate_state({ 'XXabcd', 'XXabcd' }, { { 1, 1 }, { 2, 2 } })\nend\n\nT['move_selection()']['respects `opts.n_times` blockwise horizontally'] = function()\n  set_lines({ 'XXabcd', 'XXabcd' })\n  set_cursor(1, 0)\n  type_keys('<C-v>', 'lj')\n  validate_state({ 'XXabcd', 'XXabcd' }, { { 1, 1 }, { 2, 2 } })\n\n  move('right', { n_times = 3 })\n  validate_state({ 'abcXXd', 'abcXXd' }, { { 1, 4 }, { 2, 5 } })\n  move('left', { n_times = 2 })\n  validate_state({ 'aXXbcd', 'aXXbcd' }, { { 1, 2 }, { 2, 3 } })\nend\n\nT['move_selection()']['works blockwise vertically'] = function()\n  set_lines({ '1XXa', '2YYb', '3c', '4d', '5e' })\n  set_cursor(1, 1)\n  type_keys('<C-v>', 'lj')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\n\n  move('down')\n  validate_state({ '1a', '2XXb', '3YYc', '4d', '5e' }, { { 2, 2 }, { 3, 3 } })\n  move('down')\n  validate_state({ '1a', '2b', '3XXc', '4YYd', '5e' }, { { 3, 2 }, { 4, 3 } })\n  move('down')\n  validate_state({ '1a', '2b', '3c', '4XXd', '5YYe' }, { { 4, 2 }, { 5, 3 } })\n  -- Should allow to try to move past last line without error and not\n  -- going outside of buffer lines\n  move('down')\n  validate_state({ '1a', '2b', '3c', '4XXd', '5YYe' }, { { 4, 2 }, { 5, 3 } })\n\n  move('up')\n  validate_state({ '1a', '2b', '3XXc', '4YYd', '5e' }, { { 3, 2 }, { 4, 3 } })\n  move('up')\n  validate_state({ '1a', '2XXb', '3YYc', '4d', '5e' }, { { 2, 2 }, { 3, 3 } })\n  move('up')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\n  -- Should allow to try to move past first line without error\n  move('up')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\nend\n\nT['move_selection()']['respects `opts.n_times` blockwise vertically'] = function()\n  set_lines({ '1XXa', '2YYb', '3c', '4d', '5e' })\n  set_cursor(1, 1)\n  type_keys('<C-v>', 'lj')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\n\n  move('down', { n_times = 3 })\n  validate_state({ '1a', '2b', '3c', '4XXd', '5YYe' }, { { 4, 2 }, { 5, 3 } })\n  move('up', { n_times = 2 })\n  validate_state({ '1a', '2XXb', '3YYc', '4d', '5e' }, { { 2, 2 }, { 3, 3 } })\nend\n\nT['move_selection()']['works with folds blockwise'] = function()\n  local setup_folds = function()\n    child.ensure_normal_mode()\n    set_lines({ '1XX', '2YY', '3aa', '4bb', '5cc', '6XX', '7YY' })\n\n    -- Create fold\n    type_keys('zE')\n    set_cursor(3, 0)\n    type_keys('zf', '2j')\n  end\n\n  -- Down\n  setup_folds()\n  set_cursor(1, 1)\n  type_keys('<C-v>', 'jl')\n  validate_state({ '1XX', '2YY', '3aa', '4bb', '5cc', '6XX', '7YY' }, { { 1, 2 }, { 2, 3 } })\n  eq(get_fold_range(3), { 3, 5 })\n\n  -- - When moving \"into fold\", it should open it, but this is determined by\n  --   top-left corner of selection. So in this case whole fold is selected.\n  move('down')\n  validate_state({ '1', '2XX', '3YYaa', '4bb', '5cc', '6XX', '7YY' }, { { 2, 2 }, { 5, 4 } })\n  eq(get_fold_range(3), { 3, 5 })\n\n  -- Up\n  setup_folds()\n  set_cursor(6, 1)\n  type_keys('<C-v>', 'jl')\n  validate_state({ '1XX', '2YY', '3aa', '4bb', '5cc', '6XX', '7YY' }, { { 6, 2 }, { 7, 3 } })\n  eq(get_fold_range(3), { 3, 5 })\n\n  -- - When moving \"into fold\", it should open it. But it happens only after\n  --   entering fold, so cursor is at the start of fold. Would be nice to\n  --   change so that fold is opened before movement, but it requires some\n  --   extra non-trivial steps.\n  move('up')\n  validate_state({ '1XX', '2YY', '3XXaa', '4YYbb', '5cc', '6', '7' }, { { 3, 2 }, { 4, 3 } })\n  eq(get_fold_range(2), { -1, -1 })\nend\n\nT['move_selection()']['works linewise horizontally'] = function()\n  -- Should be the same as indent (`>`) and dedent (`<`)\n  set_lines({ 'aa', '  bb' })\n  set_cursor(1, 0)\n  type_keys('Vj')\n  validate_state({ 'aa', '  bb' }, { { 1, 1 }, { 2, 1 } })\n\n  -- Should also move cursor along selection\n  move('right')\n  validate_state({ '\\taa', '\\t  bb' }, { { 1, 1 }, { 2, 2 } })\n  move('right')\n  validate_state({ '\\t\\taa', '\\t\\t  bb' }, { { 1, 1 }, { 2, 3 } })\n\n  move('left')\n  validate_state({ '\\taa', '\\t  bb' }, { { 1, 1 }, { 2, 2 } })\n  move('left')\n  validate_state({ 'aa', '  bb' }, { { 1, 1 }, { 2, 1 } })\n  move('left')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 2, 1 } })\n  -- Should allow to try impossible dedent without error\n  move('left')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 2, 1 } })\nend\n\nT['move_selection()']['respects `opts.n_times` linewise horizontally'] = function()\n  set_lines({ 'aa', '  bb' })\n  set_cursor(1, 0)\n  type_keys('Vj')\n  validate_state({ 'aa', '  bb' }, { { 1, 1 }, { 2, 1 } })\n\n  move('right', { n_times = 3 })\n  validate_state({ '\\t\\t\\taa', '\\t\\t\\t  bb' }, { { 1, 1 }, { 2, 4 } })\n  move('left', { n_times = 2 })\n  validate_state({ '\\taa', '\\t  bb' }, { { 1, 1 }, { 2, 2 } })\nend\n\nT['move_selection()']['linewise horizontally moves cursor along selection in edge cases'] = function()\n  -- Empty line\n  set_lines({ 'aa', '' })\n  set_cursor(1, 0)\n  type_keys('Vj')\n  validate_state({ 'aa', '' }, { { 1, 1 }, { 2, 1 } })\n\n  move('right')\n  validate_state({ '\\taa', '' }, { { 1, 1 }, { 2, 1 } })\n  move('left')\n  validate_state({ 'aa', '' }, { { 1, 1 }, { 2, 1 } })\n\n  child.ensure_normal_mode()\n\n  -- Past line end with default 'virtualedit'\n  set_lines({ 'aa', 'bb' })\n  set_cursor(1, 0)\n  type_keys('Vj$')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 2, 3 } })\n\n  move('right')\n  validate_state({ '\\taa', '\\tbb' }, { { 1, 1 }, { 2, 4 } })\n  move('left')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 2, 3 } })\n\n  child.ensure_normal_mode()\n\n  -- Extreme past line end with non-default 'virtualedit'\n  child.o.virtualedit = 'all'\n  set_lines({ 'aa', 'bb' })\n  set_cursor(1, 0)\n  type_keys('Vj10l')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 2, 3 } })\n  eq(child.fn.getcurpos(), { 0, 2, 3, 8, 11 })\n\n  move('right')\n  validate_state({ '\\taa', '\\tbb' }, { { 1, 1 }, { 2, 4 } })\n  eq(child.fn.getcurpos(), { 0, 2, 4, 8, 12 })\nend\n\nT['move_selection()']['works linewise vertically'] = function()\n  set_lines({ 'XX', 'YY', 'aa', 'bb', 'cc' })\n  set_cursor(1, 0)\n  type_keys('Vjl')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 2 } })\n\n  -- Should also preserve cursor column\n  move('down')\n  validate_state({ 'aa', 'XX', 'YY', 'bb', 'cc' }, { { 2, 1 }, { 3, 2 } })\n  move('down')\n  validate_state({ 'aa', 'bb', 'XX', 'YY', 'cc' }, { { 3, 1 }, { 4, 2 } })\n  move('down')\n  validate_state({ 'aa', 'bb', 'cc', 'XX', 'YY' }, { { 4, 1 }, { 5, 2 } })\n  -- Should allow to try to move past last line without error\n  move('down')\n  validate_state({ 'aa', 'bb', 'cc', 'XX', 'YY' }, { { 4, 1 }, { 5, 2 } })\n\n  move('up')\n  validate_state({ 'aa', 'bb', 'XX', 'YY', 'cc' }, { { 3, 1 }, { 4, 2 } })\n  move('up')\n  validate_state({ 'aa', 'XX', 'YY', 'bb', 'cc' }, { { 2, 1 }, { 3, 2 } })\n  move('up')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 2 } })\n  -- Should allow to try to move past first line without error\n  move('up')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 2 } })\nend\n\nT['move_selection()']['respects `opts.n_times` linewise vertically'] = function()\n  set_lines({ 'XX', 'YY', 'aa', 'bb', 'cc' })\n  set_cursor(1, 0)\n  type_keys('Vjl')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 2 } })\n\n  move('down', { n_times = 3 })\n  validate_state({ 'aa', 'bb', 'cc', 'XX', 'YY' }, { { 4, 1 }, { 5, 2 } })\n  move('up', { n_times = 2 })\n  validate_state({ 'aa', 'XX', 'YY', 'bb', 'cc' }, { { 2, 1 }, { 3, 2 } })\nend\n\nT['move_selection()']['works with folds linewise'] = function()\n  local setup_folds = function()\n    child.ensure_normal_mode()\n    set_lines({ '1XX', '2YY', '3aa', '4bb', '5cc', '6XX', '7YY' })\n\n    -- Create fold\n    type_keys('zE')\n    set_cursor(3, 0)\n    type_keys('zf', '2j')\n  end\n\n  -- Down\n  setup_folds()\n  set_cursor(1, 0)\n  type_keys('Vj')\n  validate_state({ '1XX', '2YY', '3aa', '4bb', '5cc', '6XX', '7YY' }, { { 1, 1 }, { 2, 1 } })\n  eq(get_fold_range(3), { 3, 5 })\n\n  -- - Folds should be moved altogether\n  move('down')\n  validate_state({ '3aa', '4bb', '5cc', '1XX', '2YY', '6XX', '7YY' }, { { 4, 1 }, { 5, 1 } })\n  eq(get_fold_range(3), { 1, 3 })\n\n  -- Up\n  setup_folds()\n  set_cursor(6, 0)\n  type_keys('Vj')\n  validate_state({ '1XX', '2YY', '3aa', '4bb', '5cc', '6XX', '7YY' }, { { 6, 1 }, { 7, 1 } })\n  eq(get_fold_range(3), { 3, 5 })\n\n  -- - Folds should be moved altogether\n  move('up')\n  validate_state({ '1XX', '2YY', '6XX', '7YY', '3aa', '4bb', '5cc' }, { { 3, 1 }, { 4, 1 } })\n  eq(get_fold_range(5), { 5, 7 })\nend\n\n--stylua: ignore\nT['move_selection()']['reindents linewise vertically'] = function()\n  set_lines({ 'XX', 'YY', 'aa', '\\tbb', '\\t\\tcc', '\\tdd', 'ee' })\n  set_cursor(1, 0)\n  type_keys('Vjl')\n  validate_state({ 'XX', 'YY',   'aa',     '\\tbb',   '\\t\\tcc', '\\tdd', 'ee' }, { { 1, 1 }, { 2, 2 } })\n\n  -- Should also move cursor along selection\n  move('down')\n  validate_state({ 'aa', 'XX',   'YY',     '\\tbb',   '\\t\\tcc', '\\tdd', 'ee' }, { { 2, 1 }, { 3, 2 } })\n  move('down')\n  validate_state({ 'aa', '\\tbb', '\\tXX',   '\\tYY',   '\\t\\tcc', '\\tdd', 'ee' }, { { 3, 1 }, { 4, 3 } })\n  move('down')\n  validate_state({ 'aa', '\\tbb', '\\t\\tcc', '\\t\\tXX', '\\t\\tYY', '\\tdd', 'ee' }, { { 4, 1 }, { 5, 4 } })\n  move('down')\n  validate_state({ 'aa', '\\tbb', '\\t\\tcc', '\\tdd',   '\\tXX',   '\\tYY', 'ee' }, { { 5, 1 }, { 6, 3 } })\n  move('down')\n  validate_state({ 'aa', '\\tbb', '\\t\\tcc', '\\tdd',   'ee',     'XX',   'YY' }, { { 6, 1 }, { 7, 2 } })\nend\n\nT['move_selection()']['respects `opts.reindent_linewise`'] = function()\n  set_lines({ 'XX', '\\taa' })\n  set_cursor(1, 0)\n  type_keys('V')\n  validate_state({ 'XX', '\\taa' }, { { 1, 1 }, { 1, 1 } })\n\n  -- `false` as argument\n  move('down', { reindent_linewise = false })\n  validate_state({ '\\taa', 'XX' }, { { 2, 1 }, { 2, 1 } })\n\n  -- `true` as argument\n  move('up')\n  validate_state({ 'XX', '\\taa' }, { { 1, 1 }, { 1, 1 } })\n  move('down', { reindent_linewise = true })\n  validate_state({ '\\taa', '\\tXX' }, { { 2, 1 }, { 2, 2 } })\n\n  -- `false` as global\n  move('up')\n  validate_state({ 'XX', '\\taa' }, { { 1, 1 }, { 1, 1 } })\n\n  child.lua('MiniMove.config.options.reindent_linewise = false')\n  move('down')\n  validate_state({ '\\taa', 'XX' }, { { 2, 1 }, { 2, 1 } })\nend\n\nT['move_selection()']['linewise vertically moves cursor along selection in edge cases'] = function()\n  -- Empty line\n  set_lines({ 'aa', '', 'bb' })\n  set_cursor(1, 0)\n  type_keys('Vj')\n  validate_state({ 'aa', '', 'bb' }, { { 1, 1 }, { 2, 1 } })\n\n  move('down')\n  validate_state({ 'bb', 'aa', '' }, { { 2, 1 }, { 3, 1 } })\n\n  child.ensure_normal_mode()\n\n  -- Past line end with default 'virtualedit'\n  set_lines({ 'aa', 'bb' })\n  set_cursor(1, 0)\n  type_keys('V$')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 1, 3 } })\n\n  move('down')\n  validate_state({ 'bb', 'aa' }, { { 2, 1 }, { 2, 3 } })\n\n  child.ensure_normal_mode()\n\n  -- Extreme past line end non-default 'virtualedit'\n  child.o.virtualedit = 'all'\n  set_lines({ 'aa', 'bb' })\n  set_cursor(1, 0)\n  type_keys('V10l')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 1, 3 } })\n  eq(child.fn.getcurpos(), { 0, 1, 3, 8, 11 })\n\n  move('down')\n  validate_state({ 'bb', 'aa' }, { { 2, 1 }, { 2, 3 } })\n  eq(child.fn.getcurpos(), { 0, 2, 3, 8, 11 })\nend\n\nT['move_selection()']['linewise vertically respects cursor side of selection'] = function()\n  set_lines({ 'aa', 'bb', 'cc' })\n  set_cursor(2, 0)\n  type_keys('Vkl')\n  validate_state({ 'aa', 'bb', 'cc' }, { { 2, 1 }, { 1, 2 } })\n\n  -- It should put cursor at top line of selection, as it is initially\n  move('down')\n  validate_state({ 'cc', 'aa', 'bb' }, { { 3, 1 }, { 2, 2 } })\nend\n\nT['move_selection()']['moves cursor respecting initial `curswant`'] = function()\n  set_lines({ 'aaX', 'aa', 'a', '', 'a', 'aa', 'aa' })\n  set_cursor(1, 2)\n  type_keys('v')\n  validate_state({ 'aaX', 'aa', 'a', '', 'a', 'aa', 'aa' }, { { 1, 3 }, { 1, 3 } })\n\n  move('down')\n  validate_state({ 'aa', 'aaX', 'a', '', 'a', 'aa', 'aa' }, { { 2, 3 }, { 2, 3 } })\n  move('down')\n  validate_state({ 'aa', 'aa', 'aX', '', 'a', 'aa', 'aa' }, { { 3, 2 }, { 3, 2 } })\n  move('down')\n  validate_state({ 'aa', 'aa', 'a', 'X', 'a', 'aa', 'aa' }, { { 4, 1 }, { 4, 1 } })\n  move('down')\n  validate_state({ 'aa', 'aa', 'a', '', 'aX', 'aa', 'aa' }, { { 5, 2 }, { 5, 2 } })\n  move('down')\n  validate_state({ 'aa', 'aa', 'a', '', 'a', 'aaX', 'aa' }, { { 6, 3 }, { 6, 3 } })\n  move('down')\n  validate_state({ 'aa', 'aa', 'a', '', 'a', 'aa', 'aaX' }, { { 7, 3 }, { 7, 3 } })\n\n  move('up')\n  validate_state({ 'aa', 'aa', 'a', '', 'a', 'aaX', 'aa' }, { { 6, 3 }, { 6, 3 } })\n  move('up')\n  validate_state({ 'aa', 'aa', 'a', '', 'aX', 'aa', 'aa' }, { { 5, 2 }, { 5, 2 } })\n  move('up')\n  validate_state({ 'aa', 'aa', 'a', 'X', 'a', 'aa', 'aa' }, { { 4, 1 }, { 4, 1 } })\n  move('up')\n  validate_state({ 'aa', 'aa', 'aX', '', 'a', 'aa', 'aa' }, { { 3, 2 }, { 3, 2 } })\n  move('up')\n  validate_state({ 'aa', 'aaX', 'a', '', 'a', 'aa', 'aa' }, { { 2, 3 }, { 2, 3 } })\n  move('up')\n  validate_state({ 'aaX', 'aa', 'a', '', 'a', 'aa', 'aa' }, { { 1, 3 }, { 1, 3 } })\n\n  -- Single horizontal move should reset `curswant`\n  move('down')\n  validate_state({ 'aa', 'aaX', 'a', '', 'a', 'aa', 'aa' }, { { 2, 3 }, { 2, 3 } })\n  move('left')\n  validate_state({ 'aa', 'aXa', 'a', '', 'a', 'aa', 'aa' }, { { 2, 2 }, { 2, 2 } })\n  move('up')\n  validate_state({ 'aXa', 'aa', 'a', '', 'a', 'aa', 'aa' }, { { 1, 2 }, { 1, 2 } })\nend\n\nT['move_selection()']['computes `curswant` based on left side'] = function()\n  set_lines({ 'aaXXa', '', 'aaaaa' })\n  set_cursor(1, 2)\n  type_keys('vl')\n  validate_state({ 'aaXXa', '', 'aaaaa' }, { { 1, 3 }, { 1, 4 } })\n\n  move('down')\n  validate_state({ 'aaa', 'XX', 'aaaaa' }, { { 2, 1 }, { 2, 2 } })\n  move('down')\n  validate_state({ 'aaa', '', 'aaXXaaa' }, { { 3, 3 }, { 3, 4 } })\nend\n\nT['move_selection()']['updates `curswant` when moving horizontally'] = function()\n  -- Charwise\n  set_lines({ 'abXcd', 'efgh' })\n  set_cursor(1, 2)\n  type_keys('v')\n  validate_state({ 'abXcd', 'efgh' }, { { 1, 3 }, { 1, 3 } })\n\n  move('right')\n  validate_state({ 'abcXd', 'efgh' }, { { 1, 4 }, { 1, 4 } })\n  move('down')\n  validate_state({ 'abcd', 'efgXh' }, { { 2, 4 }, { 2, 4 } })\n  move('left')\n  validate_state({ 'abcd', 'efXgh' }, { { 2, 3 }, { 2, 3 } })\n  move('up')\n  validate_state({ 'abXcd', 'efgh' }, { { 1, 3 }, { 1, 3 } })\nend\n\nT['move_selection()']['works with multibyte characters'] = function()\n  set_lines({ 'ыыXXы', '', 'ыыыыы' })\n  set_cursor(1, 4)\n  type_keys('vl')\n  validate_state({ 'ыыXXы', '', 'ыыыыы' }, { { 1, 5 }, { 1, 6 } })\n\n  move('down')\n  validate_state({ 'ыыы', 'XX', 'ыыыыы' }, { { 2, 1 }, { 2, 2 } })\n  move('down')\n  validate_state({ 'ыыы', '', 'ыыXXыыы' }, { { 3, 5 }, { 3, 6 } })\nend\n\nT['move_selection()']['works in small buffers'] = function()\n  local validate = function(line_before, vis_mode, direction, line_after)\n    child.ensure_normal_mode()\n    set_lines({ line_before })\n    set_cursor(1, 1)\n    type_keys(vis_mode)\n    move(direction)\n    eq(get_lines(), { line_after or line_before })\n  end\n\n  -- Should do nothing in empty buffer\n  for _, vis_mode in ipairs({ 'v', 'V', '<C-v>' }) do\n    for _, direction in ipairs({ 'up', 'down', 'left', 'right' }) do\n      validate('', vis_mode, direction)\n    end\n  end\n\n  -- Should work only horizontally in single line buffer\n  validate('abc', 'v', 'up', 'abc')\n  validate('abc', 'v', 'down', 'abc')\n  validate('abc', 'V', 'up', 'abc')\n  validate('abc', 'V', 'down', 'abc')\n  validate('abc', '<C-v>', 'up', 'abc')\n  validate('abc', '<C-v>', 'down', 'abc')\n\n  validate('abc', 'v', 'left', 'bac')\n  validate('abc', 'v', 'right', 'acb')\n  validate('\\tabc', 'V', 'left', 'abc')\n  validate('abc', 'V', 'right', '\\tabc')\n  validate('abc', '<C-v>', 'left', 'bac')\n  validate('abc', '<C-v>', 'right', 'acb')\nend\n\nT['move_selection()']['has no side effects'] = function()\n  set_lines({ 'aaa', 'bbb' })\n\n  -- Shouldn't modify any possibly affected registers\n  local reginfo_ref = setup_registers()\n\n  -- Shouldn't modify 'virtualedit'\n  child.o.virtualedit = 'block,insert'\n\n  -- Shouldn't affect yank history from 'mini.bracketed'\n  child.cmd('au TextYankPost * lua if not vim.b.minibracketed_disable then _G.been_here = true end')\n\n  local validate = function()\n    for reg, info in pairs(reginfo_ref) do\n      eq(child.fn.getreginfo(reg), info)\n    end\n    eq(child.o.virtualedit, 'block,insert')\n    eq(child.lua_get('_G.been_here'), vim.NIL)\n    eq(child.lua_get('vim.b.minibracketed_disable'), vim.NIL)\n  end\n\n  -- Perform linewise move\n  set_cursor(1, 0)\n  type_keys('V')\n  move('down')\n  validate_state({ 'bbb', 'aaa' }, { { 2, 1 }, { 2, 1 } })\n  validate()\n  child.ensure_normal_mode()\n\n  -- Perform charwise move\n  set_cursor(1, 1)\n  type_keys('v')\n  move('down')\n  validate_state({ 'bb', 'abaa' }, { { 2, 2 }, { 2, 2 } })\n  validate()\nend\n\nT['move_selection()']['works with `virtualedit=all`'] = function()\n  child.o.virtualedit = 'all'\n\n  set_lines({ 'abX', '' })\n  set_cursor(1, 2)\n  type_keys('v')\n\n  move('right')\n  validate_state({ 'ab X', '' }, { { 1, 4 }, { 1, 4 } })\n  move('down')\n  validate_state({ 'ab ', '   X' }, { { 2, 4 }, { 2, 4 } })\nend\n\nT['move_selection()']['works silently'] = function()\n  -- Horizontal movement should not add \"x lines >ed y times\" message\n  set_lines({ 'aa', 'bb', 'cc' })\n  set_cursor(1, 0)\n  type_keys('V2j')\n  validate_state({ 'aa', 'bb', 'cc' }, { { 1, 1 }, { 3, 1 } })\n\n  child.cmd('messages clear')\n  move('right')\n  validate_state({ '\\taa', '\\tbb', '\\tcc' }, { { 1, 1 }, { 3, 2 } })\n  eq(child.cmd_capture('messages'), '')\n\n  move('left')\n  validate_state({ 'aa', 'bb', 'cc' }, { { 1, 1 }, { 3, 1 } })\n  eq(child.cmd_capture('messages'), '')\n\n  child.ensure_normal_mode()\n  child.cmd('messages clear')\n\n  -- Reindent when moving vertically linewise should not add \"x lines to\n  -- indent\" messages\n  set_lines({ 'aa', 'bb', 'cc', '\\tdd' })\n  set_cursor(1, 0)\n  type_keys('V2j')\n  validate_state({ 'aa', 'bb', 'cc', '\\tdd' }, { { 1, 1 }, { 3, 1 } })\n\n  move('down')\n  validate_state({ '\\tdd', '\\taa', '\\tbb', '\\tcc' }, { { 2, 1 }, { 4, 2 } })\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['move_selection()']['undos all movements at once'] = function()\n  set_lines({ 'aXbc', 'defg' })\n  set_cursor(1, 1)\n  type_keys('v')\n  validate_state({ 'aXbc', 'defg' }, { { 1, 2 }, { 1, 2 } })\n\n  move('down')\n  move('right')\n  move('right')\n  move('up')\n  move('left')\n  validate_state({ 'abXc', 'defg' }, { { 1, 3 }, { 1, 3 } })\n\n  type_keys('<Esc>', 'u')\n  validate_state({ 'aXbc', 'defg' }, { { 1, 2 }, { 1, 2 } })\nend\n\nT['move_selection()']['starts separate undo block on outer cursor move'] = function()\n  set_lines({ 'aXbc', 'defg' })\n  set_cursor(1, 1)\n  type_keys('v')\n  validate_state({ 'aXbc', 'defg' }, { { 1, 2 }, { 1, 2 } })\n\n  move('down')\n  validate_state({ 'abc', 'dXefg' }, { { 2, 2 }, { 2, 2 } })\n  type_keys('l')\n  validate_state({ 'abc', 'dXefg' }, { { 2, 2 }, { 2, 3 } })\n  move('right')\n  validate_state({ 'abc', 'dfXeg' }, { { 2, 3 }, { 2, 4 } })\n\n  type_keys('<Esc>', 'u')\n  validate_state({ 'abc', 'dXefg' }, { { 2, 2 }, { 2, 2 } })\n  type_keys('u')\n  validate_state({ 'aXbc', 'defg' }, { { 1, 2 }, { 1, 2 } })\nend\n\nT['move_selection()']['does not create unnecessary jumps'] = function()\n  set_lines({ '1Xa', '2b', '3c', '4d' })\n  set_cursor(1, 1)\n  type_keys('m`')\n  type_keys('v')\n\n  move('down')\n  move('down')\n  move('down')\n  validate_state({ '1a', '2b', '3c', '4Xd' }, { { 4, 2 }, { 4, 2 } })\n\n  -- In jump list there should be only single entry\n  eq(#child.fn.getjumplist()[1], 1)\nend\n\nT['move_selection()'][\"silently respects 'nomodifiable'\"] = function()\n  set_lines({ 'aa', '  bb', 'cc' })\n  set_cursor(2, 0)\n  type_keys('V')\n\n  local validate = function()\n    validate_state({ 'aa', '  bb', 'cc' }, { { 2, 1 }, { 2, 1 } })\n    eq(child.cmd_capture('messages'), '')\n  end\n  validate()\n\n  child.o.modifiable = false\n\n  move('left')\n  validate()\n  move('right')\n  validate()\n  move('up')\n  validate()\n  move('down')\n  validate()\nend\n\nT['move_selection()']['respects `vim.{g,b}.minimove_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minimove_disable = true\n\n    set_lines({ 'aaa', 'bbb' })\n    set_cursor(1, 0)\n    type_keys('V')\n    validate_state({ 'aaa', 'bbb' }, { { 1, 1 }, { 1, 1 } })\n\n    move('down')\n    validate_state({ 'aaa', 'bbb' }, { { 1, 1 }, { 1, 1 } })\n\n    child[var_type].minimove_disable = false\n    move('down')\n    validate_state({ 'bbb', 'aaa' }, { { 2, 1 }, { 2, 1 } })\n  end,\n})\n\nT['move_line()'] = new_set()\n\nlocal move_line = function(direction, opts) child.lua('MiniMove.move_line(...)', { direction, opts }) end\n\nT['move_line()']['works vertically'] = function()\n  set_lines({ 'XX', 'aa', 'bb', 'cc' })\n  set_cursor(1, 1)\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\n\n  -- Should also preserve cursor column\n  move_line('down')\n  validate_line_state({ 'aa', 'XX', 'bb', 'cc' }, { 2, 1 })\n  move_line('down')\n  validate_line_state({ 'aa', 'bb', 'XX', 'cc' }, { 3, 1 })\n  move_line('down')\n  validate_line_state({ 'aa', 'bb', 'cc', 'XX' }, { 4, 1 })\n  -- Should allow to try to move_line past last line without error\n  move_line('down')\n  validate_line_state({ 'aa', 'bb', 'cc', 'XX' }, { 4, 1 })\n\n  move_line('up')\n  validate_line_state({ 'aa', 'bb', 'XX', 'cc' }, { 3, 1 })\n  move_line('up')\n  validate_line_state({ 'aa', 'XX', 'bb', 'cc' }, { 2, 1 })\n  move_line('up')\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\n  -- Should allow to try to move_line past first line without error\n  move_line('up')\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\nend\n\nT['move_line()']['respects `opts.n_times` vertically'] = function()\n  set_lines({ 'XX', 'aa', 'bb', 'cc' })\n  set_cursor(1, 1)\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\n\n  move_line('down', { n_times = 3 })\n  validate_line_state({ 'aa', 'bb', 'cc', 'XX' }, { 4, 1 })\n  move_line('up', { n_times = 2 })\n  validate_line_state({ 'aa', 'XX', 'bb', 'cc' }, { 2, 1 })\nend\n\nT['move_line()']['works vertically with folds'] = function()\n  local setup_folds = function()\n    child.ensure_normal_mode()\n    set_lines({ '1XX', '2aa', '3bb', '4cc', '5XX' })\n\n    -- Create fold\n    type_keys('zE')\n    set_cursor(2, 0)\n    type_keys('zf', '2j')\n  end\n\n  -- Down\n  setup_folds()\n  set_cursor(1, 0)\n  validate_line_state({ '1XX', '2aa', '3bb', '4cc', '5XX' }, { 1, 0 })\n  eq(get_fold_range(2), { 2, 4 })\n\n  -- - Folds should be moved altogether\n  move_line('down')\n  validate_line_state({ '2aa', '3bb', '4cc', '1XX', '5XX' }, { 4, 0 })\n  eq(get_fold_range(1), { 1, 3 })\n\n  -- Up\n  setup_folds()\n  set_cursor(5, 0)\n  validate_line_state({ '1XX', '2aa', '3bb', '4cc', '5XX' }, { 5, 0 })\n  eq(get_fold_range(2), { 2, 4 })\n\n  -- - Folds should be moved altogether\n  move_line('up')\n  validate_line_state({ '1XX', '5XX', '2aa', '3bb', '4cc' }, { 2, 0 })\n  eq(get_fold_range(3), { 3, 5 })\nend\n\n--stylua: ignore\nT['move_line()']['reindents while moving cursor along'] = function()\n  set_lines({ 'XX', 'aa', '\\tbb', '\\t\\tcc', '\\tdd', 'ee' })\n  set_cursor(1, 1)\n  -- As `get_cursor()` treats '\\t' as single character, use 1 and 2 instead of\n  -- relying on computing visible cursor position with 'shiftwidth'\n  validate_line_state({ 'XX', 'aa',   '\\tbb',   '\\t\\tcc', '\\tdd', 'ee' }, { 1, 1 })\n\n  -- Should also move cursor along selection\n  move_line('down')\n  validate_line_state({ 'aa', 'XX',   '\\tbb',   '\\t\\tcc', '\\tdd', 'ee' }, { 2, 1 })\n  move_line('down')\n  validate_line_state({ 'aa', '\\tbb', '\\tXX',   '\\t\\tcc', '\\tdd', 'ee' }, { 3, 2 })\n  move_line('down')\n  validate_line_state({ 'aa', '\\tbb', '\\t\\tcc', '\\t\\tXX', '\\tdd', 'ee' }, { 4, 3 })\n  move_line('down')\n  validate_line_state({ 'aa', '\\tbb', '\\t\\tcc', '\\tdd',   '\\tXX', 'ee' }, { 5, 2 })\n  move_line('down')\n  validate_line_state({ 'aa', '\\tbb', '\\t\\tcc', '\\tdd',   'ee',   'XX' }, { 6, 1 })\nend\n\nT['move_line()']['respects `opts.reindent_linewise`'] = function()\n  set_lines({ 'XX', '\\taa' })\n  set_cursor(1, 1)\n  validate_line_state({ 'XX', '\\taa' }, { 1, 1 })\n\n  -- `false` as argument\n  move_line('down', { reindent_linewise = false })\n  validate_line_state({ '\\taa', 'XX' }, { 2, 1 })\n\n  -- `true` as argument\n  move_line('up')\n  validate_line_state({ 'XX', '\\taa' }, { 1, 1 })\n  move_line('down', { reindent_linewise = true })\n  validate_line_state({ '\\taa', '\\tXX' }, { 2, 2 })\n\n  -- `false` as global\n  move_line('up')\n  validate_line_state({ 'XX', '\\taa' }, { 1, 1 })\n\n  child.lua('MiniMove.config.options.reindent_linewise = false')\n  move_line('down')\n  validate_line_state({ '\\taa', 'XX' }, { 2, 1 })\nend\n\nT['move_line()']['works horizontally'] = function()\n  -- Should be the same as indent (`>`) and dedent (`<`)\n  set_lines({ '  aa' })\n  set_cursor(1, 1)\n  validate_line_state({ '  aa' }, { 1, 1 })\n\n  -- Should also move cursor along selection\n  move_line('right')\n  validate_line_state({ '\\t  aa' }, { 1, 2 })\n  move_line('right')\n  validate_line_state({ '\\t\\t  aa' }, { 1, 3 })\n\n  move_line('left')\n  validate_line_state({ '\\t  aa' }, { 1, 2 })\n  move_line('left')\n  validate_line_state({ '  aa' }, { 1, 1 })\n  move_line('left')\n  validate_line_state({ 'aa' }, { 1, 0 })\n  -- Should allow to try impossible dedent without error\n  move_line('left')\n  validate_line_state({ 'aa' }, { 1, 0 })\nend\n\nT['move_line()']['respects `opts.n_times` horizontally'] = function()\n  set_lines({ 'aa' })\n  set_cursor(1, 0)\n  validate_line_state({ 'aa' }, { 1, 0 })\n\n  move_line('right', { n_times = 3 })\n  validate_line_state({ '\\t\\t\\taa' }, { 1, 3 })\n  move_line('left', { n_times = 2 })\n  validate_line_state({ '\\taa' }, { 1, 1 })\nend\n\nT['move_line()']['works in small buffers'] = function()\n  local validate = function(line_before, direction, line_after)\n    set_lines({ line_before })\n    set_cursor(1, 0)\n    move_line(direction)\n    eq(get_lines(), { line_after or line_before })\n  end\n\n  -- Should do nothing in empty buffer\n  validate('', 'up', '')\n  validate('', 'down', '')\n  validate('', 'left', '')\n  validate('', 'right', '')\n\n  -- Should work only horizontally in single line buffer\n  validate('abc', 'up', 'abc')\n  validate('abc', 'down', 'abc')\n  validate('\\tabc', 'left', 'abc')\n  validate('abc', 'right', '\\tabc')\nend\n\nT['move_line()']['has no side effects'] = function()\n  set_lines({ 'aaa', 'bbb' })\n\n  -- Shouldn't modify any possibly affected registers\n  local reginfo_ref = setup_registers()\n\n  -- Shouldn't affect yank history from 'mini.bracketed'\n  child.cmd('au TextYankPost * lua if not vim.b.minibracketed_disable then _G.been_here = true end')\n\n  -- Perform move\n  set_cursor(1, 0)\n  move_line('down')\n  validate_line_state({ 'bbb', 'aaa' }, { 2, 0 })\n\n  -- Check\n  for reg, info in pairs(reginfo_ref) do\n    eq(child.fn.getreginfo(reg), info)\n  end\n  eq(child.lua_get('_G.been_here'), vim.NIL)\n  eq(child.lua_get('vim.b.minibracketed_disable'), vim.NIL)\nend\n\nT['move_line()']['works silently'] = function()\n  -- Although at the moment single line moves don't produce messages, test it\n  -- to align with 'move_selection()'\n\n  -- Horizontal movement should not add \"x lines >ed y times\" message\n  set_lines({ 'aa' })\n  set_cursor(1, 0)\n  validate_line_state({ 'aa' }, { 1, 0 })\n\n  child.cmd('messages clear')\n  move_line('right')\n  validate_line_state({ '\\taa' }, { 1, 1 })\n  eq(child.cmd_capture('messages'), '')\n\n  move_line('left')\n  validate_line_state({ 'aa' }, { 1, 0 })\n  eq(child.cmd_capture('messages'), '')\n\n  child.ensure_normal_mode()\n\n  -- Reindent when moving vertically linewise should not add \"x lines to\n  -- indent\" messages\n  child.cmd('messages clear')\n  set_lines({ 'aa', '\\tdd' })\n  set_cursor(1, 0)\n  validate_line_state({ 'aa', '\\tdd' }, { 1, 0 })\n\n  move_line('down')\n  validate_line_state({ '\\tdd', '\\taa' }, { 2, 1 })\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['move_line()']['undos all movements at once'] = function()\n  set_lines({ 'aaa', 'bbb', 'ccc', 'ddd' })\n  set_cursor(1, 0)\n  validate_line_state({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 1, 0 })\n\n  move_line('down')\n  move_line('down')\n  move_line('up')\n  move_line('down')\n  validate_line_state({ 'bbb', 'ccc', 'aaa', 'ddd' }, { 3, 0 })\n\n  type_keys('<Esc>', 'u')\n  validate_line_state({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 1, 0 })\nend\n\nT['move_line()']['starts separate undo block on outer cursor move'] = function()\n  set_lines({ 'aaa', 'bbb', 'ccc', 'ddd' })\n  set_cursor(1, 0)\n  validate_line_state({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 1, 0 })\n\n  move_line('down')\n  validate_line_state({ 'bbb', 'aaa', 'ccc', 'ddd' }, { 2, 0 })\n  type_keys('j')\n  validate_line_state({ 'bbb', 'aaa', 'ccc', 'ddd' }, { 3, 0 })\n  move_line('down')\n  validate_line_state({ 'bbb', 'aaa', 'ddd', 'ccc' }, { 4, 0 })\n\n  type_keys('<Esc>', 'u')\n  validate_line_state({ 'bbb', 'aaa', 'ccc', 'ddd' }, { 3, 0 })\n  type_keys('u')\n  validate_line_state({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 1, 0 })\nend\n\nT['move_line()']['does not share undo block with visual moves'] = function()\n  set_lines({ 'aaa', 'bbb', 'ccc', 'ddd' })\n  set_cursor(1, 0)\n  type_keys('V')\n  validate_state({ 'aaa', 'bbb', 'ccc', 'ddd' }, { { 1, 1 }, { 1, 1 } })\n\n  move('down')\n  validate_state({ 'bbb', 'aaa', 'ccc', 'ddd' }, { { 2, 1 }, { 2, 1 } })\n\n  type_keys('<Esc>')\n  move_line('down')\n  validate_line_state({ 'bbb', 'ccc', 'aaa', 'ddd' }, { 3, 0 })\n\n  type_keys('u')\n  validate_line_state({ 'bbb', 'aaa', 'ccc', 'ddd' }, { 2, 0 })\n  type_keys('u')\n  validate_line_state({ 'aaa', 'bbb', 'ccc', 'ddd' }, { 1, 0 })\nend\n\nT['move_line()']['does not create unnecessary jumps'] = function()\n  set_lines({ 'aa', 'bb', 'cc', 'dd' })\n  set_cursor(1, 1)\n  type_keys('m`')\n\n  move_line('down')\n  move_line('down')\n  move_line('down')\n  validate_line_state({ 'bb', 'cc', 'dd', 'aa' }, { 4, 1 })\n\n  -- In jump list there should be only single entry\n  eq(#child.fn.getjumplist()[1], 1)\nend\n\nT['move_line()'][\"silently respects 'nomodifiable'\"] = function()\n  set_lines({ 'aa', '  bb', 'cc' })\n  set_cursor(2, 0)\n\n  local validate = function()\n    validate_line_state({ 'aa', '  bb', 'cc' }, { 2, 0 })\n    eq(child.cmd_capture('messages'), '')\n  end\n  validate()\n\n  child.o.modifiable = false\n\n  move_line('left')\n  validate()\n  move_line('right')\n  validate()\n  move_line('up')\n  validate()\n  move_line('down')\n  validate()\nend\n\nT['move_line()']['respects `vim.{g,b}.minimove_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minimove_disable = true\n\n    set_lines({ 'aaa', 'bbb' })\n    set_cursor(1, 0)\n    validate_line_state({ 'aaa', 'bbb' }, { 1, 0 })\n\n    move_line('down')\n    validate_line_state({ 'aaa', 'bbb' }, { 1, 0 })\n\n    child[var_type].minimove_disable = false\n    move_line('down')\n    validate_line_state({ 'bbb', 'aaa' }, { 2, 0 })\n  end,\n})\n\n-- Integration tests ==========================================================\nT['Mappings'] = new_set()\n\nT['Mappings']['left/right'] = new_set()\n\nT['Mappings']['left/right']['works charwise'] = function()\n  set_lines({ 'XXabcd' })\n  set_cursor(1, 0)\n  type_keys('vl')\n  validate_state1d('XXabcd', { 1, 2 })\n\n  type_keys('<M-l>')\n  validate_state1d('aXXbcd', { 2, 3 })\n  -- Supports `v:count`\n  type_keys('2<M-l>')\n  validate_state1d('abcXXd', { 4, 5 })\n  -- Can allow overshoot without error\n  type_keys('2<M-l>')\n  validate_state1d('abcdXX', { 5, 6 })\n\n  type_keys('<M-h>')\n  validate_state1d('abcXXd', { 4, 5 })\n  -- Supports `v:count`\n  type_keys('2<M-h>')\n  validate_state1d('aXXbcd', { 2, 3 })\n  -- Can allow overshoot without error\n  type_keys('2<M-h>')\n  validate_state1d('XXabcd', { 1, 2 })\nend\n\nT['Mappings']['left/right']['works blockwise'] = function()\n  set_lines({ 'XXabcd', 'XXabcd' })\n  set_cursor(1, 0)\n  type_keys('<C-v>', 'lj')\n  validate_state({ 'XXabcd', 'XXabcd' }, { { 1, 1 }, { 2, 2 } })\n\n  type_keys('<M-l>')\n  validate_state({ 'aXXbcd', 'aXXbcd' }, { { 1, 2 }, { 2, 3 } })\n  -- Supports `v:count`\n  type_keys('2<M-l>')\n  validate_state({ 'abcXXd', 'abcXXd' }, { { 1, 4 }, { 2, 5 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-l>')\n  validate_state({ 'abcdXX', 'abcdXX' }, { { 1, 5 }, { 2, 6 } })\n\n  type_keys('<M-h>')\n  validate_state({ 'abcXXd', 'abcXXd' }, { { 1, 4 }, { 2, 5 } })\n  -- Supports `v:count`\n  type_keys('2<M-h>')\n  validate_state({ 'aXXbcd', 'aXXbcd' }, { { 1, 2 }, { 2, 3 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-h>')\n  validate_state({ 'XXabcd', 'XXabcd' }, { { 1, 1 }, { 2, 2 } })\nend\n\nT['Mappings']['left/right']['works linewise'] = function()\n  set_lines({ '  aa', 'bb' })\n  set_cursor(1, 0)\n  type_keys('Vjl')\n  validate_state({ '  aa', 'bb' }, { { 1, 1 }, { 2, 2 } })\n\n  type_keys('<M-l>')\n  validate_state({ '\\t  aa', '\\tbb' }, { { 1, 1 }, { 2, 3 } })\n  -- Supports `v:count`\n  type_keys('2<M-l>')\n  validate_state({ '\\t\\t\\t  aa', '\\t\\t\\tbb' }, { { 1, 1 }, { 2, 5 } })\n\n  type_keys('<M-h>')\n  validate_state({ '\\t\\t  aa', '\\t\\tbb' }, { { 1, 1 }, { 2, 4 } })\n  -- Supports `v:count`\n  type_keys('2<M-h>')\n  validate_state({ '  aa', 'bb' }, { { 1, 1 }, { 2, 2 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-h>')\n  validate_state({ 'aa', 'bb' }, { { 1, 1 }, { 2, 2 } })\nend\n\nT['Mappings']['down/up'] = new_set()\n\nT['Mappings']['down/up']['works charwise'] = function()\n  set_lines({ '1XXx', '2a', '3b', '4c', '5d' })\n  set_cursor(1, 1)\n  type_keys('vl')\n  validate_state({ '1XXx', '2a', '3b', '4c', '5d' }, { { 1, 2 }, { 1, 3 } })\n\n  type_keys('<M-j>')\n  validate_state({ '1x', '2XXa', '3b', '4c', '5d' }, { { 2, 2 }, { 2, 3 } })\n  -- Supports `v:count`\n  type_keys('2<M-j>')\n  validate_state({ '1x', '2a', '3b', '4XXc', '5d' }, { { 4, 2 }, { 4, 3 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-j>')\n  validate_state({ '1x', '2a', '3b', '4c', '5XXd' }, { { 5, 2 }, { 5, 3 } })\n\n  type_keys('<M-k>')\n  validate_state({ '1x', '2a', '3b', '4XXc', '5d' }, { { 4, 2 }, { 4, 3 } })\n  -- Supports `v:count`\n  type_keys('2<M-k>')\n  validate_state({ '1x', '2XXa', '3b', '4c', '5d' }, { { 2, 2 }, { 2, 3 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-k>')\n  validate_state({ '1XXx', '2a', '3b', '4c', '5d' }, { { 1, 2 }, { 1, 3 } })\nend\n\nT['Mappings']['down/up']['works blockwise'] = function()\n  set_lines({ '1XXa', '2YYb', '3c', '4d', '5e' })\n  set_cursor(1, 1)\n  type_keys('<C-v>', 'lj')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\n\n  type_keys('<M-j>')\n  validate_state({ '1a', '2XXb', '3YYc', '4d', '5e' }, { { 2, 2 }, { 3, 3 } })\n  -- Supports `v:count`\n  type_keys('2<M-j>')\n  validate_state({ '1a', '2b', '3c', '4XXd', '5YYe' }, { { 4, 2 }, { 5, 3 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-j>')\n  validate_state({ '1a', '2b', '3c', '4XXd', '5YYe' }, { { 4, 2 }, { 5, 3 } })\n\n  type_keys('<M-k>')\n  validate_state({ '1a', '2b', '3XXc', '4YYd', '5e' }, { { 3, 2 }, { 4, 3 } })\n  -- Supports `v:count`\n  type_keys('2<M-k>')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-k>')\n  validate_state({ '1XXa', '2YYb', '3c', '4d', '5e' }, { { 1, 2 }, { 2, 3 } })\nend\n\nT['Mappings']['down/up']['works linewise'] = function()\n  set_lines({ 'XX', 'YY', 'aa', 'bb', 'cc' })\n  set_cursor(1, 0)\n  type_keys('Vj')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 1 } })\n\n  type_keys('<M-j>')\n  validate_state({ 'aa', 'XX', 'YY', 'bb', 'cc' }, { { 2, 1 }, { 3, 1 } })\n  -- Supports `v:count`\n  type_keys('2<M-j>')\n  validate_state({ 'aa', 'bb', 'cc', 'XX', 'YY' }, { { 4, 1 }, { 5, 1 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-j>')\n  validate_state({ 'aa', 'bb', 'cc', 'XX', 'YY' }, { { 4, 1 }, { 5, 1 } })\n\n  type_keys('<M-k>')\n  validate_state({ 'aa', 'bb', 'XX', 'YY', 'cc' }, { { 3, 1 }, { 4, 1 } })\n  -- Supports `v:count`\n  type_keys('2<M-k>')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 1 } })\n  -- Should allow overshoot without error\n  type_keys('2<M-k>')\n  validate_state({ 'XX', 'YY', 'aa', 'bb', 'cc' }, { { 1, 1 }, { 2, 1 } })\nend\n\nT['Mappings']['line_left/line_right'] = new_set()\n\nT['Mappings']['line_left/line_right']['works'] = function()\n  -- Should be the same as indent (`>`) and dedent (`<`)\n  set_lines({ '  aa' })\n  set_cursor(1, 1)\n  validate_line_state({ '  aa' }, { 1, 1 })\n\n  type_keys('<M-l>')\n  validate_line_state({ '\\t  aa' }, { 1, 2 })\n  type_keys('2<M-l>')\n  validate_line_state({ '\\t\\t\\t  aa' }, { 1, 4 })\n\n  type_keys('<M-h>')\n  validate_line_state({ '\\t\\t  aa' }, { 1, 3 })\n  type_keys('2<M-h>')\n  validate_line_state({ '  aa' }, { 1, 1 })\n  -- Should allow to try impossible dedent without error\n  type_keys('2<M-h>')\n  validate_line_state({ 'aa' }, { 1, 0 })\nend\n\nT['Mappings']['line_down/line_up'] = new_set()\n\nT['Mappings']['line_down/line_up']['works'] = function()\n  set_lines({ 'XX', 'aa', 'bb', 'cc' })\n  set_cursor(1, 1)\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\n\n  type_keys('<M-j>')\n  validate_line_state({ 'aa', 'XX', 'bb', 'cc' }, { 2, 1 })\n  -- Supports `v:count`\n  type_keys('2<M-j>')\n  validate_line_state({ 'aa', 'bb', 'cc', 'XX' }, { 4, 1 })\n  -- Should allow overshoot without error\n  type_keys('2<M-j>')\n  validate_line_state({ 'aa', 'bb', 'cc', 'XX' }, { 4, 1 })\n\n  type_keys('<M-k>')\n  validate_line_state({ 'aa', 'bb', 'XX', 'cc' }, { 3, 1 })\n  -- Supports `v:count`\n  type_keys('2<M-k>')\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\n  -- Should allow overshoot without error\n  type_keys('2<M-k>')\n  validate_line_state({ 'XX', 'aa', 'bb', 'cc' }, { 1, 1 })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_notify.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('notify', config) end\nlocal unload_module = function() child.mini_unload('notify') end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Common test helpers\nlocal get_notif_win_id = function(tabpage_id)\n  tabpage_id = tabpage_id or child.api.nvim_get_current_tabpage()\n  local all_wins = child.api.nvim_tabpage_list_wins(tabpage_id)\n  for _, win_id in ipairs(all_wins) do\n    local win_buf = child.api.nvim_win_get_buf(win_id)\n    local shows_notifications = child.api.nvim_buf_get_option(win_buf, 'filetype') == 'mininotify'\n    if shows_notifications then return win_id end\n  end\nend\n\nlocal is_notif_window_shown = function(tabpage_id) return get_notif_win_id(tabpage_id) ~= nil end\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal get = forward_lua('MiniNotify.get')\nlocal get_all = forward_lua('MiniNotify.get_all')\n\n-- Common mocks\nlocal ref_seconds, ref_microseconds = 1703680496, 0.123456\nlocal mock_gettimeofday = function()\n  -- Ensure reproducibility of `vim.fn.strftime`\n  child.loop.os_setenv('TZ', 'Etc/UTC')\n  child.loop.os_setenv('_TZ', 'Etc/UTC')\n  child.cmd('language time en_US.UTF-8')\n\n  local lua_cmd = string.format(\n    [[local start, n = %d, -1\n      vim.loop.gettimeofday = function()\n        n = n + 1\n        return start + n, %d\n      end]],\n    ref_seconds,\n    1000000 * ref_microseconds\n  )\n  child.lua(lua_cmd)\nend\n\n-- Time constants\nlocal default_duration_last = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Load module\n      load_module()\n\n      -- Make more comfortable screenshots\n      child.set_size(7, 45)\n      child.o.laststatus = 0\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniNotify)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniNotify'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniNotifyBorder', 'links to FloatBorder')\n  has_highlight('MiniNotifyLspProgress', 'links to MiniNotifyNormal')\n  has_highlight('MiniNotifyNormal', 'links to NormalFloat')\n  has_highlight('MiniNotifyTitle', 'links to FloatTitle')\n\n  -- `vim.notify` implementation\n  child.lua('vim.notify(\"Hello\", vim.log.levels.WARN)')\n  eq(child.lua_get('#MiniNotify.get_all()'), 1)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniNotify.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniNotify.config.' .. field), value) end\n\n  expect_config('content.format', vim.NIL)\n  expect_config('content.sort', vim.NIL)\n\n  expect_config('lsp_progress.enable', true)\n  expect_config('lsp_progress.duration_last', 1000)\n\n  expect_config('window.config', {})\n  expect_config('window.max_width_share', 0.382)\n  expect_config('window.winblend', 25)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ window = { winblend = 0 } })\n  eq(child.lua_get('MiniNotify.config.window.winblend'), 0)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ content = 'a' }, 'content', 'table')\n  expect_config_error({ content = { format = 'a' } }, 'content.format', 'function')\n  expect_config_error({ content = { sort = 'a' } }, 'content.sort', 'function')\n\n  expect_config_error({ lsp_progress = 'a' }, 'lsp_progress', 'table')\n  expect_config_error({ lsp_progress = { enable = 'a' } }, 'lsp_progress.enable', 'boolean')\n  expect_config_error({ lsp_progress = { duration_last = 'a' } }, 'lsp_progress.duration_last', 'number')\n\n  expect_config_error({ window = 'a' }, 'window', 'table')\n  expect_config_error({ window = { config = 'a' } }, 'window.config', 'table or callable')\n  expect_config_error({ window = { max_width_share = 'a' } }, 'window.max_width_share', 'number')\n  expect_config_error({ window = { winblend = 'a' } }, 'window.winblend', 'number')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniNotifyBorder'), 'links to FloatBorder')\nend\n\nT['setup()']['clears the history'] = function()\n  child.lua([[\n    local id_1 = MiniNotify.add(\"Hello\")\n    local id_2 = MiniNotify.add(\"Hello\")\n    MiniNotify.remove(id_1)\n  ]])\n  eq(#child.lua_get('MiniNotify.get_all()'), 2)\n  eq(is_notif_window_shown(), true)\n\n  child.lua('MiniNotify.setup(MiniNotify.config)')\n  -- Should also remove possibly visible notification window\n  eq(#child.lua_get('MiniNotify.get_all()'), 0)\n  eq(is_notif_window_shown(), false)\nend\n\nT['make_notify()'] = new_set()\n\nlocal notify = forward_lua('vim.notify')\n\nT['make_notify()']['works'] = function()\n  child.set_size(10, 45)\n  mock_gettimeofday()\n\n  local test_duration = 5 * small_time\n  child.lua('_G.dur = ' .. test_duration)\n  child.lua([[\n    local level_opts = {\n      ERROR = { duration = 6 * _G.dur },\n      WARN  = { duration = 5 * _G.dur },\n      INFO  = { duration = 4 * _G.dur },\n      DEBUG = { duration = 3 * _G.dur },\n      TRACE = { duration = 2 * _G.dur },\n      OFF   = { duration = 1 * _G.dur },\n    }\n    vim.notify = MiniNotify.make_notify(level_opts)\n  ]])\n\n  local validate_active = function(ref)\n    local active = vim.tbl_filter(function(notif) return notif.ts_remove == nil end, get_all())\n    eq(vim.tbl_map(function(notif) return notif.msg end, active), ref)\n  end\n\n  local levels = child.lua_get('vim.log.levels')\n\n  notify('error', levels.ERROR)\n  notify('warn', levels.WARN)\n  notify('info', levels.INFO)\n  notify('debug', levels.DEBUG)\n  notify('trace', levels.TRACE)\n  notify('off', levels.OFF)\n\n  child.expect_screenshot()\n\n  -- Should add all notifications to history with proper `level` and `hl_group`\n  local history = vim.tbl_map(\n    function(notif) return { msg = notif.msg, level = notif.level, hl_group = notif.hl_group, data = notif.data } end,\n    get_all()\n  )\n  --stylua: ignore\n  eq(history, {\n    { msg = 'error', level = 'ERROR', hl_group = 'DiagnosticError',  data = { source = 'vim.notify' } },\n    { msg = 'warn',  level = 'WARN',  hl_group = 'DiagnosticWarn',   data = { source = 'vim.notify' } },\n    { msg = 'info',  level = 'INFO',  hl_group = 'DiagnosticInfo',   data = { source = 'vim.notify' } },\n    { msg = 'debug', level = 'DEBUG', hl_group = 'DiagnosticHint',   data = { source = 'vim.notify' } },\n    { msg = 'trace', level = 'TRACE', hl_group = 'DiagnosticOk',     data = { source = 'vim.notify' } },\n    { msg = 'off',   level = 'OFF',   hl_group = 'MiniNotifyNormal', data = { source = 'vim.notify' } },\n  })\n\n  -- Should make notifications disappear after configured duration\n  validate_active({ 'error', 'warn', 'info', 'debug', 'trace', 'off' })\n  sleep(test_duration + small_time)\n  validate_active({ 'error', 'warn', 'info', 'debug', 'trace' })\n  sleep(test_duration)\n  validate_active({ 'error', 'warn', 'info', 'debug' })\n  sleep(test_duration)\n  validate_active({ 'error', 'warn', 'info' })\n  sleep(test_duration)\n  validate_active({ 'error', 'warn' })\n  sleep(test_duration)\n  validate_active({ 'error' })\n  sleep(test_duration)\n  validate_active({})\nend\n\nT['make_notify()']['uses INFO level by default'] = function()\n  child.lua([[vim.notify = MiniNotify.make_notify()]])\n  notify('Hello')\n  local notif = get_all()[1]\n  eq(notif.level, 'INFO')\n  eq(notif.hl_group, 'DiagnosticInfo')\nend\n\nT['make_notify()']['does not show some levels by default'] = function()\n  child.lua('vim.notify = MiniNotify.make_notify()')\n  notify('debug', child.lua_get('vim.log.levels.DEBUG'))\n  notify('trace', child.lua_get('vim.log.levels.TRACE'))\n  notify('off', child.lua_get('vim.log.levels.OFF'))\n  eq(get_all(), {})\nend\n\nT['make_notify()']['respects `opts.hl_group`'] = function()\n  child.lua([[vim.notify = MiniNotify.make_notify({ ERROR = { hl_group = 'Comment' } })]])\n  notify('Hello', child.lua_get('vim.log.levels.ERROR'))\n  eq(get_all()[1].hl_group, 'Comment')\nend\n\nT['make_notify()']['validates arguments'] = function()\n  local validate = function(opts, err_pattern)\n    expect.error(function() child.lua('MiniNotify.make_notify(...)', { opts }) end, err_pattern)\n  end\n\n  local validate_level = function(level)\n    validate({ [level] = 1 }, 'Level data.*table')\n    validate({ [level] = { duration = 'a' } }, '`duration`.*number')\n    validate({ [level] = { hl_group = 1 } }, '`hl_group`.*string')\n  end\n\n  validate({ error = {} }, 'Keys.*log level names')\n\n  validate_level('ERROR')\n  validate_level('WARN')\n  validate_level('INFO')\n  validate_level('DEBUG')\n  validate_level('TRACE')\n  validate_level('OFF')\nend\n\nT['make_notify()']['has output working in fast event'] = function()\n  child.lua('_G.dur = ' .. small_time)\n  child.lua([[\n    vim.notify = MiniNotify.make_notify()\n    local timer = vim.loop.new_timer()\n    timer:start(_G.dur, 0, function() vim.notify('Hello', vim.log.levels.INFO) end)\n  ]])\n  sleep(small_time + small_time)\n  eq(child.cmd_capture('messages'), '')\n  eq(get_all()[1].msg, 'Hello')\nend\n\nT['make_notify()']['has output working when completion is active'] = function()\n  child.lua([[\n    vim.notify = MiniNotify.make_notify()\n    _G.completefunc_notify = function() vim.notify(\"Hello\", vim.log.levels.INFO) end\n  ]])\n  child.o.completefunc = 'v:lua.completefunc_notify'\n  child.type_keys('i', '<C-x><C-u>')\n  sleep(small_time + small_time)\n  eq(child.cmd_capture('messages'), '')\n  eq(get_all()[1].msg, 'Hello')\nend\n\nT['make_notify()']['has output validating arguments'] = function()\n  child.lua('vim.notify = MiniNotify.make_notify()')\n  child.lua([[vim.notify('Hello', 'ERROR')]])\n  sleep(small_time)\n  expect.match(child.cmd_capture('messages'), 'valid values.*vim%.log%.levels')\nend\n\nT['make_notify()']['allows non-positive `duration`'] = function()\n  -- Should not show notification at all\n  child.lua([[vim.notify = MiniNotify.make_notify({ ERROR = { duration = -100 }, WARN = { duration = 0 } })]])\n  notify('error', child.lua_get('vim.log.levels.ERROR'))\n  notify('warn', child.lua_get('vim.log.levels.WARN'))\n  eq(get_all(), {})\nend\n\nT['add()'] = new_set()\n\nlocal add = forward_lua('MiniNotify.add')\n\nT['add()']['works'] = function()\n  mock_gettimeofday()\n\n  local id = add('Hello')\n\n  -- Should return notification identifier number\n  eq(type(id), 'number')\n\n  -- Should show notification in a floating window\n  child.expect_screenshot()\n\n  -- Should add proper notification object to history\n  local notif = get(id)\n  local notif_fields = vim.tbl_keys(notif)\n  table.sort(notif_fields)\n  eq(notif_fields, { 'data', 'hl_group', 'level', 'msg', 'ts_add', 'ts_update' })\n\n  eq(notif.msg, 'Hello')\n\n  -- Non-message arguments should have defaults\n  eq(notif.level, 'INFO')\n  eq(notif.hl_group, 'MiniNotifyNormal')\n  eq(notif.data, {})\n\n  -- Timestamp fields should use `vim.loop.gettimeofday()`\n  eq(notif.ts_add, ref_seconds + ref_microseconds)\n  eq(notif.ts_update, notif.ts_add)\nend\n\nT['add()']['allows empty string message'] = function()\n  mock_gettimeofday()\n\n  add('')\n  child.expect_screenshot()\nend\n\nT['add()']['respects arguments'] = function()\n  local validate = function(level)\n    local id = add('Hello', level, 'Comment', { a = 1, b = { bb = 2 } })\n    eq(get(id).level, level)\n    eq(get(id).hl_group, 'Comment')\n    eq(get(id).data, { a = 1, b = { bb = 2 } })\n  end\n\n  validate('ERROR')\n  validate('WARN')\n  validate('INFO')\n  validate('DEBUG')\n  validate('TRACE')\n  validate('OFF')\nend\n\nT['add()']['validates arguments'] = function()\n  expect.error(function() add(1, 'ERROR', 'Comment') end, '`msg`.*string')\n  expect.error(function() add('Hello', 1, 'Comment') end, '`level`.*key of `vim%.log%.levels`')\n  expect.error(function() add('Hello', 'Error', 'Comment') end, '`level`.*key of `vim%.log%.levels`')\n  expect.error(function() add('Hello', 'ERROR', 1) end, '`hl_group`.*string')\nend\n\nT['update()'] = new_set()\n\nlocal update = forward_lua('MiniNotify.update')\n\nT['update()']['works'] = function()\n  mock_gettimeofday()\n  child.lua([[\n    MiniNotify.config.content.format = function(notif)\n      return (notif.data.a > 10 and 'NEW' or 'OLD') .. ' ' .. notif.msg\n    end\n  ]])\n\n  local id = add('Hello', 'ERROR', 'Comment', { a = 1, b = true, c = 'c' })\n  child.expect_screenshot()\n  local init_notif = get(id)\n\n  update(id, { msg = 'World', level = 'WARN', hl_group = 'String', data = { a = 11 } })\n\n  -- Should show updated notification in a floating window\n  child.expect_screenshot()\n\n  -- Should properly update notification object in history\n  local notif = get(id)\n\n  eq(notif.msg, 'World')\n  eq(notif.level, 'WARN')\n  eq(notif.hl_group, 'String')\n\n  -- Should assign non-nil `data` as is, without `vim.tbl_deep_extend`\n  eq(notif.data, { a = 11 })\n\n  -- Add time should be untouched\n  eq(notif.ts_add, init_notif.ts_add)\n\n  -- Update time should be increased\n  eq(init_notif.ts_update < notif.ts_update, true)\nend\n\nT['update()']['allows partial new content'] = function()\n  local id = add('Hello', 'ERROR', 'Comment', { a = 1, b = true })\n  update(id, { msg = 'World', data = { b = false } })\n  local notif = get(id)\n  eq(notif.msg, 'World')\n  eq(notif.level, 'ERROR')\n  eq(notif.hl_group, 'Comment')\n  eq(notif.data, { b = false })\n\n  -- Empty table\n  update(id, {})\n  eq(notif.msg, 'World')\n  eq(notif.level, 'ERROR')\n  eq(notif.hl_group, 'Comment')\n  eq(notif.data, { b = false })\nend\n\nT['update()']['can update only active notification'] = function()\n  local id = child.lua([[\n    local id = MiniNotify.add('Hello')\n    MiniNotify.remove(id)\n    return id\n  ]])\n  expect.error(function() update(id, { msg = 'World' }) end, '`id`.*not.*active')\nend\n\nT['update()']['validates arguments'] = function()\n  local id = add('Hello')\n  expect.error(function() update('a', { msg = 'World' }) end, '`id`.*identifier')\n  expect.error(function() update(id, 1) end, '`new`.*table')\n  expect.error(function() update(id, { msg = 1 }) end, '`msg`.*string')\n  expect.error(function() update(id, { level = 1 }) end, '`level`.*key of `vim%.log%.levels`')\n  expect.error(function() update(id, { level = 'Error' }) end, '`level`.*key of `vim%.log%.levels`')\n  expect.error(function() update(id, { hl_group = 1 }) end, '`hl_group`.*string')\n  expect.error(function() update(id, { data = 1 }) end, '`data`.*table')\nend\n\nT['remove()'] = new_set()\n\nlocal remove = forward_lua('MiniNotify.remove')\n\nT['remove()']['works'] = function()\n  mock_gettimeofday()\n\n  local id = add('Hello', 'ERROR', 'Comment')\n  child.expect_screenshot()\n  local init_notif = get(id)\n  eq(init_notif.ts_remove, nil)\n\n  remove(id)\n\n  -- Should update notification window (and remove it completely in this case)\n  child.expect_screenshot()\n\n  -- Should only update `ts_remove` field\n  local notif = get(id)\n\n  eq(notif.ts_remove, ref_seconds + 1 + ref_microseconds)\n\n  init_notif.ts_remove, notif.ts_remove = nil, nil\n  eq(init_notif, notif)\nend\n\nT['remove()']['works with several active notifications'] = function()\n  mock_gettimeofday()\n\n  local id_1 = add('Hello', 'ERROR', 'Comment')\n  local id_2 = add('World', 'ERROR', 'String')\n  child.expect_screenshot()\n\n  remove(id_2)\n  child.expect_screenshot()\n\n  eq(get(id_1).ts_remove, nil)\n  eq(type(get(id_2).ts_remove), 'number')\nend\n\nT['remove()']['does nothing on not proper input'] = function()\n  local id = add('Hello', 'ERROR', 'Comment')\n  local validate = function(...)\n    local args = { ... }\n    expect.no_error(function() remove(unpack(args)) end)\n  end\n\n  validate(nil)\n  validate(id + 1)\n  validate('a')\nend\n\nT['clear()'] = new_set()\n\nlocal clear = forward_lua('MiniNotify.clear')\n\nT['clear()']['works'] = function()\n  mock_gettimeofday()\n\n  local id_1 = add('Hello', 'ERROR', 'Comment')\n  local id_2 = add('World', 'ERROR', 'String')\n  child.expect_screenshot()\n\n  clear()\n  child.expect_screenshot()\n\n  eq(type(get(id_1).ts_remove), 'number')\n  eq(type(get(id_2).ts_remove), 'number')\nend\n\nT['clear()']['affects only active notifications'] = function()\n  local id_1 = add('Hello', 'ERROR', 'Comment')\n  local id_2 = add('World', 'ERROR', 'String')\n  remove(id_1)\n  local ts_remove_1 = get(id_1).ts_remove\n  eq(type(ts_remove_1), 'number')\n  eq(get(id_2).ts_remove, nil)\n\n  sleep(small_time)\n  clear()\n  eq(get(id_1).ts_remove, ts_remove_1)\n  local ts_remove_2 = get(id_2).ts_remove\n  eq(type(ts_remove_2), 'number')\n  eq(ts_remove_1 < ts_remove_2, true)\nend\n\nT['refresh()'] = new_set()\n\nlocal refresh = forward_lua('MiniNotify.refresh')\n\n-- Most tests are done in 'Window' set and tests for other functions\nT['refresh()']['works'] = function() eq(child.lua_get('type(MiniNotify.refresh)'), 'function') end\n\nT['refresh()']['handles manual buffer/window delete'] = function()\n  add('Hello')\n\n  -- Window\n  child.cmd('wincmd o')\n  eq(is_notif_window_shown(), false)\n  refresh()\n  eq(is_notif_window_shown(), true)\n\n  -- Buffer\n  child.cmd('%bw')\n  eq(is_notif_window_shown(), false)\n  refresh()\n  eq(is_notif_window_shown(), true)\nend\n\nT['refresh()']['can be used inside fast event'] = function()\n  add('Hello')\n  child.lua('_G.dur = ' .. small_time)\n  child.lua([[\n    local timer = vim.loop.new_timer()\n    timer:start(_G.dur, 0, function() MiniNotify.refresh() end)\n  ]])\n  sleep(small_time + small_time)\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['refresh()']['can be used when editor is locked'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`SafeState` is present only on Neovim>=0.10') end\n\n  -- `:h :map-expression` lists things that are not allowed to be done when\n  -- the mapping is still active. Editing another buffer (like the one used by\n  -- 'mini.notify') is not allowed.\n  child.lua([[\n    local notif_id = MiniNotify.add(\"Hello\")\n    local a = function()\n      MiniNotify.refresh()\n      MiniNotify.refresh()\n      return \"2l\"\n    end\n    vim.keymap.set('o', '<C-a>', a, { expr = true })\n\n    local r = function()\n      MiniNotify.remove(notif_id)\n      return \"2h\"\n    end\n    vim.keymap.set('n', '<C-r>', r, { expr = true })\n  ]])\n\n  child.type_keys('y<C-a>')\n  eq(child.cmd_capture('messages'), '')\n  eq(is_notif_window_shown(), true)\n\n  child.type_keys('<C-r>')\n  eq(child.cmd_capture('messages'), '')\n  eq(is_notif_window_shown(), false)\nend\n\nT['refresh()']['respects `vim.{g,b}.mininotify_disable`'] = new_set({ parametrize = { { 'g' }, { 'b' } } }, {\n  test = function(var_type)\n    mock_gettimeofday()\n    add('Hello')\n\n    child[var_type].mininotify_disable = true\n    child.expect_screenshot()\n    refresh()\n    child.expect_screenshot()\n    child[var_type].mininotify_disable = false\n    refresh()\n    child.expect_screenshot()\n  end,\n})\n\nT['get()'] = new_set()\n\nT['get()']['returns copy'] = function()\n  local res = child.lua([[\n    local id = MiniNotify.add('Hello')\n    local notif = MiniNotify.get(id)\n    notif.msg = 'Should not change history'\n    return MiniNotify.get(id).msg == 'Hello'\n  ]])\n  eq(res, true)\nend\n\nT['get_all()'] = new_set()\n\nT['get_all()']['works'] = function()\n  local id_1 = add('Hello')\n  local id_2 = add('World')\n  remove(id_2)\n\n  local history = get_all()\n  eq(vim.tbl_count(history), 2)\n\n  eq(history[id_1].msg, 'Hello')\n  eq(history[id_2].msg, 'World')\nend\n\nT['get_all()']['returns copy'] = function()\n  local res = child.lua([[\n    local id_1 = MiniNotify.add('Hello')\n    local id_2 = MiniNotify.add('World')\n    local history = MiniNotify.get_all()\n    history[id_1].msg = 'Should not change history'\n    history[id_2].msg = 'Nowhere'\n\n    local new_history = MiniNotify.get_all()\n    return new_history[id_1].msg == 'Hello' and new_history[id_2].msg == 'World'\n  ]])\n  eq(res, true)\nend\n\nT['show_history()'] = new_set()\n\nlocal show_history = forward_lua('MiniNotify.show_history')\n\nT['show_history()']['works'] = function()\n  mock_gettimeofday()\n\n  add('Hello')\n  add('World', 'WARN', 'Comment')\n  show_history()\n  child.expect_screenshot()\n\n  -- Should set proper buffer name and filetype\n  eq(child.api.nvim_buf_get_name(0), 'mininotify://' .. child.api.nvim_get_current_buf() .. '/history')\n  eq(child.bo.filetype, 'mininotify-history')\nend\n\nT['show_history()']['shows all notifications'] = function()\n  mock_gettimeofday()\n\n  add('Hello')\n  local id = add('World', 'WARN', 'Comment')\n  add('Brave', 'INFO', 'String')\n  remove(id)\n  show_history()\n  child.expect_screenshot()\nend\n\nT['show_history()']['reuses history buffer'] = function()\n  mock_gettimeofday()\n\n  add('Hello')\n  show_history()\n  local buf_id = child.api.nvim_get_current_buf()\n  local n_bufs = #child.api.nvim_list_bufs()\n\n  add('World')\n  show_history()\n  child.expect_screenshot()\n\n  eq(child.api.nvim_get_current_buf(), buf_id)\n  eq(#child.api.nvim_list_bufs(), n_bufs)\nend\n\nT['show_history()']['respects `content.format`'] = function()\n  mock_gettimeofday()\n\n  add('Hello')\n  child.lua([[MiniNotify.config.content.format = function() return 'New message' end]])\n  show_history()\n  child.expect_screenshot()\nend\n\nT['show_history()']['sorts by update time'] = function()\n  mock_gettimeofday()\n\n  add('Hello', 'ERROR', 'Comment')\n  local id = add('World', 'WARN', 'Comment')\n  add('Brave', 'ERROR', 'Comment')\n\n  update(id, { msg = 'WORLD' })\n\n  show_history()\n  child.expect_screenshot()\nend\n\nT['default_format()'] = new_set()\n\nlocal default_format = forward_lua('MiniNotify.default_format')\n\nT['default_format()']['works'] = function()\n  mock_gettimeofday()\n  eq(default_format({ msg = 'Hello', ts_update = ref_seconds + ref_microseconds }), '12:34:56 │ Hello')\nend\n\nT['default_sort()'] = new_set()\n\nlocal default_sort = forward_lua('MiniNotify.default_sort')\n\nT['default_sort()']['works'] = function()\n  --stylua: ignore\n  -- First should sort by level and then by update time\n  local notif_arr = {\n    { msg = 'Thirteen', level = 'OFF',   ts_add = ref_seconds + 1, ts_update = ref_seconds + 62 },\n    { msg = 'Twelve',   level = 'OFF',   ts_add = ref_seconds,     ts_update = ref_seconds + 63 },\n    { msg = 'Eleven',   level = 'TRACE', ts_add = ref_seconds + 1, ts_update = ref_seconds + 52 },\n    { msg = 'Ten',      level = 'TRACE', ts_add = ref_seconds,     ts_update = ref_seconds + 53 },\n    { msg = 'Nine',     level = 'DEBUG', ts_add = ref_seconds + 1, ts_update = ref_seconds + 42 },\n    { msg = 'Eight',    level = 'DEBUG', ts_add = ref_seconds,     ts_update = ref_seconds + 43 },\n    { msg = 'Seven',    level = 'INFO',  ts_add = ref_seconds + 1, ts_update = ref_seconds + 32 },\n    { msg = 'Six',      level = 'INFO',  ts_add = ref_seconds,     ts_update = ref_seconds + 33 },\n    { msg = 'Five',     level = 'WARN',  ts_add = ref_seconds + 1, ts_update = ref_seconds + 22 },\n    { msg = 'Four',     level = 'WARN',  ts_add = ref_seconds,     ts_update = ref_seconds + 23 },\n    { msg = 'Three',    level = 'ERROR', ts_add = ref_seconds + 1, ts_update = ref_seconds + 1, ts_remove = ref_seconds + 4 },\n    { msg = 'Two',      level = 'ERROR', ts_add = ref_seconds + 1, ts_update = ref_seconds + 12 },\n    { msg = 'One',      level = 'ERROR', ts_add = ref_seconds,     ts_update = ref_seconds + 13 },\n  }\n  local ref = {}\n  for i = #notif_arr, 1, -1 do\n    table.insert(ref, notif_arr[i])\n  end\n  eq(default_sort(notif_arr), ref)\nend\n\nT['default_sort()']['does not affect input'] = function()\n  local lua_cmd = string.format(\n    [[local notif_arr = {\n        { msg = 'Hello', level = 'WARN',  ts_update = %d },\n        { msg = 'World', level = 'ERROR', ts_update = %d },\n      }\n      MiniNotify.default_sort(notif_arr)\n      return notif_arr[1].msg == 'Hello']],\n    ref_seconds,\n    ref_seconds\n  )\n  eq(child.lua(lua_cmd), true)\nend\n\n-- Integration tests ----------------------------------------------------------\nT['Window'] = new_set({ hooks = {\n  pre_case = function()\n    mock_gettimeofday()\n    child.set_size(12, 45)\n  end,\n} })\n\nT['Window']['uses notification `hl_group` to highlight its lines'] = function()\n  add('Hello', 'ERROR', 'Comment')\n  add('World', 'WARN', 'String')\n  local ns_id = child.api.nvim_get_namespaces()['MiniNotifyHighlight']\n  local win_id = get_notif_win_id()\n  local buf_id = child.api.nvim_win_get_buf(win_id)\n  local extmarks = child.api.nvim_buf_get_extmarks(buf_id, ns_id, 0, -1, { details = true })\n  eq(#extmarks, 2)\n  eq(extmarks[1][4].hl_group, 'Comment')\n  eq(extmarks[2][4].hl_group, 'String')\nend\n\nT['Window']['works with multiline messages'] = function()\n  add('Hello\\nBrave\\nWorld')\n  add('Hello\\nAgain')\n  child.expect_screenshot()\nend\n\nT['Window']['computes default dimensions based on buffer content'] = function()\n  add('a')\n  child.expect_screenshot()\n  add('aaa')\n  child.expect_screenshot()\nend\n\nT['Window']['wraps text'] = function()\n  -- Should also correctly compute dimensions\n  add('A very big notification message which should be wrapped')\n  child.expect_screenshot()\n  add('Another wrapped message')\n  child.expect_screenshot()\nend\n\nT['Window']['shows start of buffer if it does not fit whole'] = function()\n  for i = 1, 20 do\n    add('#' .. i)\n  end\n  child.expect_screenshot()\nend\n\nT['Window']['uses proper buffer filetype and name'] = function()\n  child.lua([[\n    local f = function(args) _G.is_correct = vim.api.nvim_buf_get_name(args.buf) == ('mininotify://') .. args.buf .. '/content' end\n    vim.api.nvim_create_autocmd('FileType', { pattern = 'mininotify', callback = f })\n  ]])\n  add('Hello')\n  eq(child.lua_get('_G.is_correct'), true)\nend\n\nT['Window']['respects `content.format`'] = function()\n  child.lua('MiniNotify.config.content.format = function(notif) return notif.msg end')\n  add('Hello')\n  child.expect_screenshot()\nend\n\nT['Window']['respects `content.sort`'] = function()\n  child.lua([[MiniNotify.config.content.sort = function(notif_arr)\n    -- Show from earliest to latest\n    table.sort(notif_arr, function(a, b) return a.ts_update < b.ts_update end)\n    return notif_arr\n  end]])\n  add('Hello')\n  add('World')\n  child.expect_screenshot()\nend\n\nT['Window']['respects `window.config`'] = function()\n  -- As table\n  child.lua([[MiniNotify.config.window.config = { border = 'none', zindex = 100, width = 30, height = 1 }]])\n  add('Hello')\n  add('World')\n  child.expect_screenshot()\n\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Neovim<0.10 has issues with displaying title in some cases') end\n\n  -- As callable\n  child.lua([[MiniNotify.config.window.config = function(buf_id)\n    _G.buffer_filetype = vim.bo[buf_id].filetype\n    return { border = 'double', width = 25, height = 5, title = 'Custom title to check truncation' }\n  end]])\n  refresh()\n  child.expect_screenshot()\n\n  -- Should properly truncate title\n  child.lua([[\n    local title = string.sub('abcdefgijklmnopqrstuvwxyzabcdefgijklmnopqrstuvwxyz', -vim.o.columns)\n    MiniNotify.config.window.config = { width = vim.o.columns, title = title }\n  ]])\n  refresh()\n  child.expect_screenshot()\nend\n\nT['Window'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  local validate = function(winborder)\n    child.o.winborder = winborder\n    add('Hello', 'ERROR', 'Comment')\n    child.expect_screenshot()\n    clear()\n  end\n\n  validate('rounded')\n\n  -- Should prefer explicitly configured value over 'winborder'\n  child.lua('MiniNotify.config.window.config.border = \"double\"')\n  validate('rounded')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  child.lua('MiniNotify.config.window.config.border = nil')\n  validate('+,-,+,|,+,-,+,|')\nend\n\nT['Window']['respects `window.max_width_share`'] = function()\n  child.lua('MiniNotify.config.window.max_width_share = 0.75')\n  add('A very-very-very-very-very long notification')\n  child.expect_screenshot()\n  child.lua('MiniNotify.config.window.max_width_share = 1')\n  refresh()\n  child.expect_screenshot()\n\n  -- Handles out of range values\n  child.lua('MiniNotify.config.window.max_width_share = 10')\n  refresh()\n  child.expect_screenshot()\n\n  child.lua('MiniNotify.config.window.max_width_share = 0')\n  refresh()\n  child.expect_screenshot()\nend\n\nT['Window']['respects `window.winblend`'] = function()\n  local validate_winblend = function(ref)\n    local win_id = get_notif_win_id()\n    eq(child.api.nvim_win_get_option(win_id, 'winblend'), ref)\n  end\n\n  add('Hello')\n  validate_winblend(child.lua_get('MiniNotify.config.window.winblend'))\n  clear()\n\n  child.lua('MiniNotify.config.window.winblend = 50')\n  add('Hello')\n  validate_winblend(50)\nend\n\nT['Window']['respects tabline/statusline/cmdline'] = function()\n  child.set_size(7, 20)\n  child.lua('MiniNotify.config.content.format = function(notif) return notif.msg end')\n  for i = 1, 7 do\n    add('#' .. i)\n  end\n\n  -- Validate tabline/statusline\n  local validate = function(screenshot_opts)\n    refresh()\n    child.expect_screenshot(screenshot_opts)\n  end\n\n  local validate_ui_lines = function()\n    local ignore_tabline = child.fn.has('nvim-0.11') == 0 and 1 or nil\n    local ignore_ruler = child.fn.has('nvim-0.12') == 0 and 7 or nil\n\n    child.o.showtabline, child.o.laststatus = 2, 2\n    validate({ ignore_text = { ignore_tabline, ignore_ruler }, ignore_attr = { ignore_tabline } })\n\n    child.o.showtabline, child.o.laststatus = 2, 0\n    validate({ ignore_text = { ignore_tabline, ignore_ruler }, ignore_attr = { ignore_tabline } })\n\n    child.o.showtabline, child.o.laststatus = 0, 2\n    validate({ ignore_text = { ignore_ruler } })\n\n    child.o.showtabline, child.o.laststatus = 0, 0\n    validate({ ignore_text = { ignore_ruler } })\n  end\n\n  -- Both with and without border\n  validate_ui_lines()\n  child.lua([[MiniNotify.config.window.config = { border = 'none' }]])\n  validate_ui_lines()\n\n  -- Command line\n  child.o.showtabline, child.o.laststatus = 0, 0\n  child.o.cmdheight = 3\n  local ignore_cmdline = child.fn.has('nvim-0.11') == 1 and {} or { ignore_text = { 5 }, ignore_attr = { 5, 6, 7 } }\n  validate(ignore_cmdline)\n\n  child.o.cmdheight = 0\n  validate()\nend\n\nT['Window']['persists across tabpages'] = function()\n  add('Hello')\n  local init_tabpage_id = child.api.nvim_get_current_tabpage()\n  eq(is_notif_window_shown(init_tabpage_id), true)\n\n  -- Window should appear only in current tabpage\n  child.cmd('tabe')\n  local new_tabpage_id = child.api.nvim_get_current_tabpage()\n  eq(is_notif_window_shown(init_tabpage_id), false)\n  eq(is_notif_window_shown(new_tabpage_id), true)\n\n  child.cmd('tabnext')\n  eq(is_notif_window_shown(init_tabpage_id), true)\n  eq(is_notif_window_shown(new_tabpage_id), false)\nend\n\nT['Window']['fully updates on vim resize'] = function()\n  -- With default window config\n  child.set_size(10, 50)\n  add('A very long notification')\n  child.expect_screenshot()\n  child.o.columns = 25\n  child.expect_screenshot()\n  clear()\n\n  -- With callable window config\n  child.set_size(15, 50)\n  child.lua([[MiniNotify.config.window.config = function()\n    return { row = math.floor(0.2 * vim.o.lines), col = math.floor(0.8 * vim.o.columns) }\n  end]])\n  add('A very long notification')\n  child.expect_screenshot()\n  child.o.lines, child.o.columns = 10, 25\n  child.expect_screenshot()\nend\n\nT['Window']['does not affect normal window navigation'] = function()\n  local win_id_1 = child.api.nvim_get_current_win()\n  child.cmd('botright wincmd v')\n  local win_id_2 = child.api.nvim_get_current_win()\n  add('Hello')\n\n  child.cmd('wincmd w')\n  eq(child.api.nvim_get_current_win(), win_id_1)\n  child.cmd('wincmd w')\n  eq(child.api.nvim_get_current_win(), win_id_2)\n  child.cmd('wincmd w')\n  eq(child.api.nvim_get_current_win(), win_id_1)\nend\n\nT['Window']['uses dedicated UI highlight groups'] = function()\n  add('Hello')\n  local win_id = get_notif_win_id()\n  local winhighlight = child.api.nvim_win_get_option(win_id, 'winhighlight')\n  expect.match(winhighlight, 'NormalFloat:MiniNotifyNormal')\n  expect.match(winhighlight, 'FloatBorder:MiniNotifyBorder')\n  expect.match(winhighlight, 'FloatTitle:MiniNotifyTitle')\nend\n\nT['Window']['handles width computation for empty lines inside notification buffer'] = function()\n  child.set_size(7, 20)\n  child.lua('MiniNotify.config.content.format = function(notif) return notif.msg end')\n\n  add('')\n  add('')\n  child.expect_screenshot()\nend\n\nT['LSP progress'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(7, 50)\n      mock_gettimeofday()\n      child.lua('MiniNotify.config.window.config = { width = 45, height = 1 }')\n\n      -- Mock LSP just to have its client id\n      child.cmd('luafile tests/mock-lsp/fruits.lua')\n    end,\n  },\n})\n\nlocal call_handler = function(result, ctx)\n  local result_str = vim.inspect(result, { newline = ' ', indent = '' })\n  local ctx_str = vim.inspect(ctx, { newline = ' ', indent = '' })\n  local lua_cmd = string.format([[vim.lsp.handlers['$/progress'](nil, %s, %s, {})]], result_str, ctx_str)\n  child.lua(lua_cmd)\nend\n\nT['LSP progress']['works'] = function()\n  local ctx = { bufnr = vim.api.nvim_get_current_buf(), client_id = child.lua_get('_G.fruits_lsp_client_id') }\n\n  local result = { token = 'test', value = { kind = 'begin', title = 'Testing', message = '0/1', percentage = 0 } }\n  call_handler(result, ctx)\n  child.expect_screenshot()\n\n  result.value.kind, result.value.message, result.value.percentage = 'report', '1/1', 100\n  call_handler(result, ctx)\n  child.expect_screenshot()\n\n  result.value.kind, result.value.message, result.value.percentage = 'end', 'done', nil\n  call_handler(result, ctx)\n  child.expect_screenshot()\n\n  -- Should wait some time and then hide notifications\n  sleep(default_duration_last - small_time)\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n  child.expect_screenshot()\n\n  -- Should update single notification (and not remove/add new ones)\n  local history = get_all()\n  eq(#history, 1)\n  -- - Should use correct content based on latest LSP response\n  eq(history[1].level, 'INFO')\n  eq(history[1].hl_group, 'MiniNotifyLspProgress')\n  eq(history[1].data, { source = 'lsp_progress', client_name = 'fruits-lsp', response = result, context = ctx })\nend\n\nT['LSP progress']['handles not present data'] = function()\n  -- NOTE: client's name is always present\n  local ctx = { bufnr = vim.api.nvim_get_current_buf(), client_id = child.lua_get('_G.fruits_lsp_client_id') }\n\n  -- All data which is allowed to be absent (as per LSP spec) is absent\n  local result = { token = 'test', value = { kind = 'begin', title = 'Testing' } }\n  call_handler(result, ctx)\n  child.expect_screenshot()\n\n  result.value.kind, result.value.title = 'report', nil\n  call_handler(result, ctx)\n  child.expect_screenshot()\n\n  result.value.kind = 'end'\n  call_handler(result, ctx)\n  child.expect_screenshot()\nend\n\nT['LSP progress']['handles sent error'] = function()\n  child.lua('vim.notify = function(...) _G.notify_args = {...} end')\n  child.lua([[vim.lsp.handlers['$/progress'](\n    { code = 1, message = 'Error' },\n    {},\n    {bufnr = vim.api.nvim_get_current_buf(), client_id = _G.fruits_lsp_client_id},\n    {}\n  )]])\n  eq(\n    child.lua_get('_G.notify_args'),\n    { vim.inspect({ code = 1, message = 'Error' }), child.lua_get('vim.log.levels.ERROR') }\n  )\nend\n\nT['LSP progress']['respects `lsp_progress.enable`'] = function()\n  local ctx = { bufnr = vim.api.nvim_get_current_buf(), client_id = child.lua_get('_G.fruits_lsp_client_id') }\n  local result = { token = 'test', value = { kind = 'begin', title = 'Testing', message = '0/1', percentage = 0 } }\n\n  child.lua('MiniNotify.config.lsp_progress.enable = false')\n  call_handler(result, ctx)\n  eq(is_notif_window_shown(), false)\n\n  child.lua('MiniNotify.config.lsp_progress.enable = true')\n  call_handler(result, ctx)\n  eq(is_notif_window_shown(), true)\nend\n\nT['LSP progress']['respects `lsp_progress.level`'] = function()\n  child.lua('MiniNotify.config.lsp_progress.level = \"ERROR\"')\n  local ctx = { bufnr = vim.api.nvim_get_current_buf(), client_id = child.lua_get('_G.fruits_lsp_client_id') }\n  local result = { token = 'test', value = { kind = 'begin', title = 'Testing', message = '0/1', percentage = 0 } }\n\n  call_handler(result, ctx)\n  eq(get_all()[1].level, 'ERROR')\nend\n\nT['LSP progress']['respects `lsp_progress.duration_last`'] = function()\n  local ctx = { bufnr = vim.api.nvim_get_current_buf(), client_id = child.lua_get('_G.fruits_lsp_client_id') }\n  local result = { token = 'test', value = { kind = 'begin', title = 'Testing', message = '0/1', percentage = 0 } }\n  call_handler(result, ctx)\n\n  result.value.kind, result.value.message, result.value.percentage = 'report', '1/1', 100\n  call_handler(result, ctx)\n\n  local new_duration_last = 6 * small_time\n  child.lua('MiniNotify.config.lsp_progress.duration_last = ' .. new_duration_last)\n  result.value.kind, result.value.message, result.value.percentage = 'end', 'done', nil\n  call_handler(result, ctx)\n  sleep(new_duration_last - 2 * small_time)\n  child.expect_screenshot()\n  sleep(2 * small_time + small_time)\n  child.expect_screenshot()\nend\n\nT['LSP progress']['reuses previous LSP handler'] = function()\n  -- Test only on Neovim>=0.10 as previously it was different event and\n  -- (possibly) different implementation (which makes mocking difficult).\n  -- But relevant event should still be triggered in Neovim<0.10.\n  if child.fn.has('nvim-0.10') == 0 then return end\n  child.cmd('au LspProgress * lua _G.n_been_here = (_G.n_been_here or 0) + 1')\n\n  local ctx = { bufnr = vim.api.nvim_get_current_buf(), client_id = child.lua_get('_G.fruits_lsp_client_id') }\n  local result = { token = 'test', value = { kind = 'begin', title = 'Testing' } }\n  call_handler(result, ctx)\n\n  eq(child.lua_get('_G.n_been_here'), 1)\n\n  -- Should persist even if module was removed\n  package.loaded['mini.notify'] = nil\n  child.lua([[require('mini.notify').setup()]])\n  call_handler(result, ctx)\n  eq(child.lua_get('_G.n_been_here'), 2)\n\n  -- Should be callable multiple times\n  call_handler(result, ctx)\n  eq(child.lua_get('_G.n_been_here'), 3)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_operators.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('operators', config) end\nlocal unload_module = function() child.mini_unload('operators') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\n-- Custom validators\nlocal validate_edit = function(lines_before, cursor_before, keys, lines_after, cursor_after)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n\n  child.ensure_normal_mode()\nend\n\nlocal validate_edit1d = function(line_before, col_before, keys, line_after, col_after)\n  validate_edit({ line_before }, { 1, col_before }, keys, { line_after }, { 1, col_after })\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniOperators)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniOperators'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local validate_hl_group = function(name, ref) expect.match(child.cmd_capture('hi ' .. name), ref) end\n\n  validate_hl_group('MiniOperatorsExchangeFrom', 'links to IncSearch')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniOperators.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniOperators.config.' .. field), value) end\n\n  expect_config('evaluate.prefix', 'g=')\n  expect_config('evaluate.func', vim.NIL)\n\n  expect_config('exchange.prefix', 'gx')\n  expect_config('exchange.reindent_linewise', true)\n\n  expect_config('multiply.prefix', 'gm')\n  expect_config('multiply.func', vim.NIL)\n\n  expect_config('replace.prefix', 'gr')\n  expect_config('replace.reindent_linewise', true)\n\n  expect_config('sort.prefix', 'gs')\n  expect_config('sort.func', vim.NIL)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ exchange = { reindent_linewise = false } })\n  eq(child.lua_get('MiniOperators.config.exchange.reindent_linewise'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n\n  expect_config_error({ evaluate = 'a' }, 'evaluate', 'table')\n  expect_config_error({ evaluate = { prefix = 1 } }, 'evaluate.prefix', 'string')\n  expect_config_error({ evaluate = { func = 'a' } }, 'evaluate.func', 'function')\n\n  expect_config_error({ exchange = 'a' }, 'exchange', 'table')\n  expect_config_error({ exchange = { prefix = 1 } }, 'exchange.prefix', 'string')\n  expect_config_error({ exchange = { reindent_linewise = 'a' } }, 'exchange.reindent_linewise', 'boolean')\n\n  expect_config_error({ multiply = 'a' }, 'multiply', 'table')\n  expect_config_error({ multiply = { prefix = 1 } }, 'multiply.prefix', 'string')\n  expect_config_error({ multiply = { func = 'a' } }, 'multiply.func', 'function')\n\n  expect_config_error({ replace = 'a' }, 'replace', 'table')\n  expect_config_error({ replace = { prefix = 1 } }, 'replace.prefix', 'string')\n  expect_config_error({ replace = { reindent_linewise = 'a' } }, 'replace.reindent_linewise', 'boolean')\n\n  expect_config_error({ sort = 'a' }, 'sort', 'table')\n  expect_config_error({ sort = { prefix = 1 } }, 'sort.prefix', 'string')\n  expect_config_error({ sort = { func = 'a' } }, 'sort.func', 'function')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniOperatorsExchangeFrom'), 'links to IncSearch')\nend\n\nT['setup()']['removes built-in LSP mappings'] = function()\n  eq(child.fn.maparg('gra'), '')\n  eq(child.fn.maparg('gri'), '')\n  eq(child.fn.maparg('grn'), '')\n  eq(child.fn.maparg('grt'), '')\n  eq(child.fn.maparg('grx'), '')\nend\n\nT['setup()']['remaps built-in `gx` mappings'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Neovim<0.10 does not have built-in `gx` mappings') end\n\n  -- Mock functions used to compute and show URI at cursor\n  child.lua('vim.lsp.buf_request_sync = function() return {} end')\n  child.lua('vim.ui.open = function() _G.n = (_G.n or 0) + 1 end')\n\n  set_lines({ 'https://nvim-mini.org' })\n  set_cursor(1, 0)\n\n  local validate = function(keys, ref_n)\n    type_keys(keys)\n    eq(child.lua_get('_G.n'), ref_n)\n  end\n\n  validate('gX', 1)\n  validate('vgX', 2)\n\n  -- Should remap only built-in `gx`\n  child.lua('vim.keymap.del({ \"n\", \"x\" }, \"gX\")')\n  child.lua('vim.keymap.set({ \"n\", \"x\" }, \"gx\", function() _G.n = _G.n + 5 end)')\n  child.lua('MiniOperators.setup()')\n  validate('gX', 2)\n  validate('vgX', 2)\n\n  -- Should not override already present mapping\n  child.lua('vim.keymap.set({ \"n\", \"x\" }, \"gx\", function() _G.n = _G.n + 5 end, { desc = \"URI under cursor\" })')\n  child.lua('vim.keymap.set({ \"n\", \"x\" }, \"gX\", function() _G.n = _G.n + 10 end)')\n  child.lua('MiniOperators.setup()')\n  validate('gX', 12)\n  validate('vgX', 22)\nend\n\nT['evaluate()'] = new_set()\n\nT['evaluate()']['is present'] = function() eq(child.lua_get('type(MiniOperators.evaluate)'), 'function') end\n\nT['exchange()'] = new_set()\n\nT['exchange()']['is present'] = function() eq(child.lua_get('type(MiniOperators.exchange)'), 'function') end\n\nT['replace()'] = new_set()\n\nT['replace()']['is present'] = function() eq(child.lua_get('type(MiniOperators.replace)'), 'function') end\n\nT['sort()'] = new_set()\n\nT['sort()']['is present'] = function() eq(child.lua_get('type(MiniOperators.sort)'), 'function') end\n\nT['make_mappings()'] = new_set()\n\nlocal make_mappings = forward_lua('MiniOperators.make_mappings')\n\n-- Targeted tests for each operator is done in tests for every operator\n\nT['make_mappings()']['respects empty string as lhs'] = function()\n  child.api.nvim_del_keymap('n', 'gr')\n  child.api.nvim_del_keymap('n', 'grr')\n  child.api.nvim_del_keymap('x', 'gr')\n\n  -- Should not create mapping for that particular variant\n  local lhs_tbl_ref = { textobject = 'cs', line = 'css', selection = 'cs' }\n\n  local validate = function(variant)\n    pcall(child.api.nvim_del_keymap, 'n', 'cs')\n    pcall(child.api.nvim_del_keymap, 'n', 'css')\n    pcall(child.api.nvim_del_keymap, 'x', 'cs')\n\n    local lhs_tbl = vim.deepcopy(lhs_tbl_ref)\n    lhs_tbl[variant] = ''\n    -- Creating mapping for line is not allowed without textobject mapping\n    if variant == 'textobject' then lhs_tbl.line = '' end\n    make_mappings('replace', lhs_tbl)\n\n    local mode = variant == 'selection' and 'x' or 'n'\n    eq(child.fn.maparg(lhs_tbl_ref[variant], mode), '')\n  end\n\n  validate('textobject')\n  validate('line')\n  validate('selection')\nend\n\nT['make_mappings()']['validates arguments'] = function()\n  expect.error(function() make_mappings(1, {}) end, '`operator_name`')\n\n  expect.error(function() make_mappings('replace', 1) end, '`lhs_tbl`')\n  expect.error(function() make_mappings('replace', { textobject = 1, line = 'crr', selection = 'cr' }) end, '`lhs_tbl`')\n  expect.error(function() make_mappings('replace', { textobject = 'cr', line = 1, selection = 'cr' }) end, '`lhs_tbl`')\n  expect.error(function() make_mappings('replace', { textobject = 'cr', line = 'crr', selection = 1 }) end, '`lhs_tbl`')\n\n  expect.error(\n    function() make_mappings('replace', { textobject = '', line = 'crr', selection = 'cr' }) end,\n    '`line`.*`textobject`'\n  )\nend\n\nT['default_sort_func()'] = new_set()\n\nlocal default_sort_func = forward_lua('MiniOperators.default_sort_func')\n\nT['default_sort_func()']['works for charwise'] = function()\n  local validate = function(lines_input, ref_output)\n    eq(default_sort_func({ lines = lines_input, submode = 'v' }), ref_output)\n  end\n\n  -- Basic tests\n  validate({ 'b, a' }, { 'a, b' })\n  validate({ 'b; a' }, { 'a; b' })\n  validate({ 'b a' }, { 'a b' })\n  validate({ 'ba' }, { 'ab' })\n\n  -- Already sorted\n  validate({ 'a, b' }, { 'a, b' })\n\n  -- Correctly picks split pattern (',' > ';' > '%s*' > '')\n  validate({ 'c, a; b' }, { 'a; b, c' })\n  validate({ 'c a; b' }, { 'b; c a' })\n  validate({ 'c a b' }, { 'a b c' })\n\n  -- Works with whitespace (preserves and sorts without it)\n  validate({ 'e ,  d,   b    ,a,c' }, { 'a ,  b,   c    ,d,e' })\n  validate({ 'e ;  d;   b    ;a;c' }, { 'a ;  b;   c    ;d;e' })\n  validate({ 'c a  b' }, { 'a b  c' })\n\n  -- Works with multiline region\n  validate({ 'c, a, ', 'b' }, { 'a, b, ', 'c' })\n  -- - Here there are essentially three parts: 'c', 'd\\na', 'b\\ne'.\n  --   They are sorted and then resplit by '\\n'.\n  validate({ 'c, d', 'a, b', 'e' }, { 'b', 'e, c, d', 'a' })\n\n  -- Works with empty parts\n  validate({ 'b,,a,' }, { ',,a,b' })\nend\n\nT['default_sort_func()']['works for linewise'] = function()\n  local validate = function(lines_input, ref_output)\n    eq(default_sort_func({ lines = lines_input, submode = 'V' }), ref_output)\n  end\n\n  validate({ 'c', 'a', 'b' }, { 'a', 'b', 'c' })\n  validate({ 'xc', 'xa', 'xb' }, { 'xa', 'xb', 'xc' })\n\n  -- Already sorted\n  validate({ 'a', 'b' }, { 'a', 'b' })\n\n  -- Doesn't ignore whitespace\n  validate({ 'a', ' b' }, { ' b', 'a' })\nend\n\nT['default_sort_func()']['works for blockwise'] = function()\n  local validate = function(lines_input, ref_output)\n    eq(default_sort_func({ lines = lines_input, submode = '\\22' }), ref_output)\n  end\n\n  validate({ 'c', 'a', 'b' }, { 'a', 'b', 'c' })\n  validate({ 'xc', 'xa', 'xb' }, { 'xa', 'xb', 'xc' })\n\n  -- Already sorted\n  validate({ 'a', 'b' }, { 'a', 'b' })\n\n  -- Doesn't ignore whitespace\n  validate({ 'a', ' b' }, { ' b', 'a' })\nend\n\nT['default_sort_func()']['respects `opts.compare_fun`'] = function()\n  -- Compare by the second character\n  child.lua('_G.compare_fun = function(a, b) return a:sub(2, 2) < b:sub(2, 2) end')\n\n  eq(\n    child.lua_get([[MiniOperators.default_sort_func(\n        { lines = { 'ab', 'ba' }, submode = 'V' },\n        { compare_fun = _G.compare_fun }\n      )]]),\n    { 'ba', 'ab' }\n  )\nend\n\nT['default_sort_func()']['respects `opts.split_patterns`'] = function()\n  local validate = function(lines_input, ref_output, split_patterns)\n    eq(default_sort_func({ lines = lines_input, submode = 'v' }, { split_patterns = split_patterns }), ref_output)\n  end\n\n  validate({ 'b + c+a' }, { ' c+a+b ' }, { '%+' })\n  validate({ 'b + c+a' }, { 'a + b+c' }, { '%s*%+%s*' })\n\n  validate({ 'b++c+++a' }, { '+++a+b+c' }, { '%+' })\n  validate({ 'b++c+++a' }, { 'a++b+++c' }, { '%++' })\n\n  -- Correctly picks in order\n  validate({ 'c+b-a' }, { 'b-a+c' }, { '%+', '%-' })\n  validate({ 'c-b-a' }, { 'a-b-c' }, { '%+', '%-' })\n\n  -- Allows empty string as pattern\n  validate({ 'c a b' }, { '  abc' }, { '' })\n\n  -- Does nothing if no pattern is found\n  validate({ 'c a b' }, { 'c a b' }, { ',' })\nend\n\nT['default_sort_func()']['validates arguments'] = function()\n  expect.error(function() default_sort_func(1) end, '`content`')\n  expect.error(function() default_sort_func({}) end, '`content`')\n  expect.error(function() default_sort_func({ submode = 'v' }) end, '`content`')\n  expect.error(function() default_sort_func({ lines = { 'a' } }) end, '`content`')\n\n  local content = { lines = { 'a', 'b' }, submode = 'V' }\n  expect.error(function() default_sort_func(content, { compare_fun = 1 }) end, '`opts.compare_fun`')\n  expect.error(function() default_sort_func(content, { split_patterns = 1 }) end, '`opts.split_patterns`')\nend\n\nT['default_evaluate_func()'] = new_set()\n\nlocal default_evaluate_func = forward_lua('MiniOperators.default_evaluate_func')\n\nT['default_evaluate_func()']['works for charwise and linewise'] = new_set({ parametrize = { { 'v' }, { 'V' } } }, {\n  test = function(submode)\n    local validate = function(lines_input, ref_output)\n      eq(default_evaluate_func({ lines = lines_input, submode = submode }), ref_output)\n    end\n\n    validate({ '1 + 1' }, { '2' })\n    validate({ 'local x = 1', 'x + 1' }, { '2' })\n    eq(child.lua_get('x'), vim.NIL)\n\n    -- Should allow `return` in last line\n    validate({ 'return 1 + 1' }, { '2' })\n    validate({ 'local x = 1', 'return x + 1' }, { '2' })\n\n    -- Should be possible to use global variables\n    child.lua('_G.y = 1')\n    validate({ '_G.y + 1' }, { '2' })\n\n    -- Should `vim.inspect()` returned object(s)\n    validate({ 'local t = {}', 't.a = 1', 't' }, { '{', '  a = 1', '}' })\n\n    -- Should allow returning tuple\n    validate({ 'local t = { a = 1 }', 't, 1' }, { '{', '  a = 1', '}', '1' })\n\n    -- Should allow `nil` in tuple\n    validate({ 'local x = 1', 'x - 1, nil, x + 1, nil' }, { '0', 'nil', '2', 'nil' })\n\n    -- Should allow comments\n    validate({ '-- A comment', '1 + 1' }, { '2' })\n  end,\n})\n\nT['default_evaluate_func()']['works for blockwise'] = function()\n  local validate = function(lines_input, ref_output)\n    eq(default_evaluate_func({ lines = lines_input, submode = '\\22' }), ref_output)\n  end\n\n  -- Should evaluate each line separately\n  validate({ '1 + 1' }, { '2' })\n  validate({ '1 + 1', '1 + 2' }, { '2', '3' })\n  validate({ '1 + 1', 'return 1 + 2' }, { '2', '3' })\n\n  -- Should be possible to use global variables\n  child.lua('_G.y = 1')\n  validate({ '_G.y + 1' }, { '2' })\nend\n\nT['default_evaluate_func()']['does not modify input'] = function()\n  local validate = function(content)\n    local lua_cmd = string.format(\n      [[_G.content = %s\n        MiniOperators.default_evaluate_func(_G.content)]],\n      vim.inspect(content)\n    )\n    child.lua(lua_cmd)\n    eq(child.lua_get('_G.content'), content)\n  end\n\n  validate({ lines = { '1 + 1' }, submode = 'v' })\n  validate({ lines = { '1 + 1' }, submode = 'V' })\n  validate({ lines = { '1 + 1', '1 + 2' }, submode = '\\22' })\nend\n\nT['default_evaluate_func()']['validates arguments'] = function()\n  expect.error(function() default_evaluate_func(1) end, '`content`')\n  expect.error(function() default_evaluate_func({}) end, '`content`')\n  expect.error(function() default_evaluate_func({ submode = 'v' }) end, '`content`')\n  expect.error(function() default_evaluate_func({ lines = { 'a' } }) end, '`content`')\nend\n\n-- Integration tests ==========================================================\nT['Evaluate'] = new_set()\n\n-- More testing is done in `default_evaluate_func()` tests\n\nT['Evaluate']['works charwise in Normal mode'] = function()\n  validate_edit1d('1 + 1 = 1 + 1', 8, { 'g=$' }, '1 + 1 = 2', 8)\n\n  validate_edit({ 'local x = 1', 'x + 1 ' }, { 1, 0 }, { 'g=/ $<CR>' }, { '2 ' }, { 1, 0 })\n\n  -- With dot-repeat\n  validate_edit({ '1 + 1', '1 + 2' }, { 1, 0 }, { 'g=$', 'j', '.' }, { '2', '3' }, { 2, 0 })\nend\n\nT['Evaluate']['works linewise in Normal mode'] = function()\n  validate_edit(\n    { 'Not evaluated', 'local x = 1', 'return x + 1' },\n    { 2, 0 },\n    { 'g=j' },\n    { 'Not evaluated', '2' },\n    { 2, 0 }\n  )\n\n  -- With dot-repeat\n  validate_edit({ '1 + 1', '1 + 2' }, { 1, 0 }, { 'g=_', 'j', '.' }, { '2', '3' }, { 2, 0 })\nend\n\nT['Evaluate']['works blockwise in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'ia', function() vim.cmd('normal! \\22j$') end)]])\n  child.lua([[vim.keymap.set('o', 'ib', function() vim.cmd('normal! \\22j4l') end)]])\n\n  validate_edit({ '1 + 1', '1 + 2' }, { 1, 0 }, { 'g=ia' }, { '2', '3' }, { 1, 0 })\n  validate_edit({ 'x=10-10=x', 'y=20-20=y' }, { 1, 2 }, { 'g=ib' }, { 'x=0    =x', 'y=0    =y' }, { 1, 2 })\n\n  -- With dot-repeat\n  validate_edit(\n    { '1 + 1', '1 + 2', '1 + 3', '1 + 4' },\n    { 1, 0 },\n    { 'g=ia', '2j', '.' },\n    { '2', '3', '4', '5' },\n    { 3, 0 }\n  )\nend\n\nT['Evaluate']['works in Normal mode for line'] = function()\n  validate_edit({ '1 + 1' }, { 1, 0 }, { 'g==' }, { '2' }, { 1, 0 })\n\n  -- With dot-repeat\n  validate_edit({ '1 + 1', '1 + 2' }, { 1, 0 }, { 'g==', 'j', '.' }, { '2', '3' }, { 2, 0 })\nend\n\nT['Evaluate']['works with empty textobject/motion'] = function()\n  child.api.nvim_set_keymap('o', 'w', '<Cmd><CR>', {})\n  child.lua('_G.x = 1')\n  set_lines({ 'xxx' })\n  set_cursor(1, 1)\n  type_keys('g=', 'w')\n  eq(get_lines(), { 'xxx' })\nend\n\nT['Evaluate']['works in Visual mode'] = function()\n  -- Charwise\n  validate_edit({ '1 + 1 = (1 + 1)' }, { 1, 8 }, { 'va)', 'g=' }, { '1 + 1 = 2' }, { 1, 8 })\n  validate_edit({ 'local x = 1', 'x - 1, x + 1' }, { 1, 0 }, { 'vj$', 'g=' }, { '0', '2' }, { 1, 0 })\n\n  -- Linewise\n  validate_edit({ 'local x = 1', 'x - 1, x + 1' }, { 1, 0 }, { 'Vj', 'g=' }, { '0', '2' }, { 1, 0 })\n\n  -- Blockwise\n  validate_edit({ '1 + 1', '1 + 2' }, { 1, 0 }, { '<C-v>j$', 'g=' }, { '2', '3' }, { 1, 0 })\nend\n\nT['Evaluate']['works with different `virtualedit`'] = function()\n  local validate = function()\n    -- Charwise\n    validate_edit1d('1+1=x', 0, { 'g=', '3l' }, '2=x', 0)\n    validate_edit1d('x=1+1=x', 2, { 'g=', '3l' }, 'x=2=x', 2)\n    validate_edit1d('x=1+1', 2, { 'g=', '3l' }, 'x=2', 2)\n\n    validate_edit1d('1+1=x', 0, { 'v2l', 'g=' }, '2=x', 0)\n    validate_edit1d('x=1+1=x', 2, { 'v2l', 'g=' }, 'x=2=x', 2)\n    validate_edit1d('x=1+1', 2, { 'v2l', 'g=' }, 'x=2', 2)\n\n    -- Linewise\n    validate_edit({ '0+1', '0+2', '0+3' }, { 1, 0 }, { 'g==' }, { '1', '0+2', '0+3' }, { 1, 0 })\n    validate_edit({ '0+1', '0+2', '0+3' }, { 2, 0 }, { 'g==' }, { '0+1', '2', '0+3' }, { 2, 0 })\n    validate_edit({ '0+1', '0+2', '0+3' }, { 3, 0 }, { 'g==' }, { '0+1', '0+2', '3' }, { 3, 0 })\n\n    validate_edit({ '0+1', '0+2', '0+3' }, { 1, 0 }, { 'V', 'g=' }, { '1', '0+2', '0+3' }, { 1, 0 })\n    validate_edit({ '0+1', '0+2', '0+3' }, { 2, 0 }, { 'V', 'g=' }, { '0+1', '2', '0+3' }, { 2, 0 })\n    validate_edit({ '0+1', '0+2', '0+3' }, { 3, 0 }, { 'V', 'g=' }, { '0+1', '0+2', '3' }, { 3, 0 })\n\n    -- Blockwise\n    child.lua([[vim.keymap.set('o', 'iL', function() vim.cmd('normal! \\22jll') end)]])\n    validate_edit({ '1+1=x', '1+2=y' }, { 1, 0 }, { 'g=', 'iL' }, { '2  =x', '3  =y' }, { 1, 0 })\n    validate_edit({ 'x=1+1=x', 'y=1+2=y' }, { 1, 2 }, { 'g=', 'iL' }, { 'x=2  =x', 'y=3  =y' }, { 1, 2 })\n    validate_edit({ 'x=1+1', 'y=1+2' }, { 1, 2 }, { 'g=', 'iL' }, { 'x=2', 'y=3' }, { 1, 2 })\n\n    validate_edit({ '1+1=x', '1+2=y' }, { 1, 0 }, { '<C-v>jll', 'g=' }, { '2  =x', '3  =y' }, { 1, 0 })\n    validate_edit({ 'x=1+1=x', 'y=1+2=y' }, { 1, 2 }, { '<C-v>jll', 'g=' }, { 'x=2  =x', 'y=3  =y' }, { 1, 2 })\n    validate_edit({ 'x=1+1', 'y=1+2' }, { 1, 2 }, { '<C-v>jll', 'g=' }, { 'x=2', 'y=3' }, { 1, 2 })\n  end\n\n  child.o.virtualedit = 'all'\n  validate()\n  child.o.virtualedit = 'onemore'\n  validate()\n  child.o.virtualedit = 'block'\n  validate()\nend\n\nT['Evaluate']['respects `config.evaluate.func`'] = function()\n  child.lua([[MiniOperators.config.evaluate.func = function() return { 'a', 'b' } end]])\n\n  validate_edit({ '1 + 1' }, { 1, 0 }, { 'g=ip' }, { 'a', 'b' }, { 1, 0 })\nend\n\nT['Evaluate'][\"works with 'y' in 'cpoptions'\"] = function()\n  child.cmd('set cpoptions+=y')\n\n  -- Dot-repeat should still work\n  validate_edit1d('(1 + 1) (1 + 2)', 0, { 'g=i)', 'f(', '.' }, '(2) (3)', 5)\nend\n\nT['Evaluate']['does not have side effects'] = function()\n  set_lines({ 'local x = 1', 'x + 1', 'xy' })\n\n  -- All non-operator related marks and registers 'x', '\"'\n  set_cursor(3, 0)\n  type_keys('ma')\n  type_keys('v\"xy')\n\n  set_cursor(3, 1)\n  type_keys('mx')\n  type_keys('vy')\n\n  -- Do evaluate\n  set_cursor(1, 0)\n  type_keys('g=j')\n\n  -- Validate\n  eq(get_lines(), { '2', 'xy' })\n  eq(child.api.nvim_buf_get_mark(0, 'a'), { 2, 0 })\n  eq(child.api.nvim_buf_get_mark(0, 'x'), { 2, 1 })\n  eq(child.fn.getreg('x'), 'x')\n  eq(child.fn.getreg('\"'), 'y')\nend\n\nT['Evaluate']['preserves visual marks'] = function()\n  set_lines({ 'local x = 1', 'x + 1', 'select' })\n\n  -- Create marks\n  set_cursor(3, 0)\n  type_keys('viw', '<Esc>')\n\n  -- Sort\n  set_cursor(1, 0)\n  type_keys('g=j')\n  eq(get_lines(), { '2', 'select' })\n  eq(child.api.nvim_buf_get_mark(0, '<'), { 2, 0 })\n  eq(child.api.nvim_buf_get_mark(0, '>'), { 2, 5 })\nend\n\nT['Evaluate']['respects `config.evaluate.prefix`'] = function()\n  child.api.nvim_del_keymap('n', 'g=')\n  child.api.nvim_del_keymap('n', 'g==')\n  child.api.nvim_del_keymap('x', 'g=')\n\n  load_module({ evaluate = { prefix = 'c=' } })\n\n  validate_edit1d('1 + 1', 0, { 'c=$' }, '2', 0)\n  validate_edit1d('1 + 1', 0, { 'c==' }, '2', 0)\n  validate_edit1d('1 + 1', 0, { 'v$', 'c=' }, '2', 0)\nend\n\nT['Evaluate']['works with `make_mappings()`'] = function()\n  child.api.nvim_del_keymap('n', 'g=')\n  child.api.nvim_del_keymap('n', 'g==')\n  child.api.nvim_del_keymap('x', 'g=')\n\n  load_module({ evaluate = { prefix = '' } })\n  make_mappings('evaluate', { textobject = 'c=', line = 'c==', selection = 'c=' })\n\n  validate_edit1d('1 + 1', 0, { 'c=$' }, '2', 0)\n  validate_edit1d('1 + 1', 0, { 'c==' }, '2', 0)\n  validate_edit1d('1 + 1', 0, { 'v$', 'c=' }, '2', 0)\nend\n\nT['Evaluate'][\"respects 'selection=exclusive'\"] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j3l') end)]])\n  child.o.selection = 'exclusive'\n\n  validate_edit1d('x = (1 + 1) = y', 5, { 'g=i)' }, 'x = (2) = y', 5)\n  validate_edit({ 'local x = 1', 'x + 1' }, { 1, 0 }, { 'g=ip' }, { '2' }, { 1, 0 })\n  validate_edit({ 'x=1-1=x', 'y=1+1=y' }, { 1, 2 }, { 'g=ie' }, { 'x=0  =x', 'y=2  =y' }, { 1, 2 })\n\n  validate_edit1d('x = (1 + 1) = y', 5, { 'vi)', 'g=' }, 'x = (2) = y', 5)\n  validate_edit({ 'local x = 1', 'x + 1' }, { 1, 0 }, { 'Vip', 'g=' }, { '2' }, { 1, 0 })\n  validate_edit({ 'x=1-1=x', 'y=1+1=y' }, { 1, 2 }, { '<C-v>j3l', 'g=' }, { 'x=0  =x', 'y=2  =y' }, { 1, 2 })\nend\n\nT['Evaluate'][\"respects 'nomodifiable'\"] = function()\n  set_lines({ '1 + 1' })\n  set_cursor(1, 0)\n  child.bo.modifiable = false\n  type_keys('g=$')\n  eq(get_lines(), { '1 + 1' })\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['Evaluate']['does not trigger `TextYankPost` event'] = function()\n  child.cmd('au TextYankPost * lua _G.been_here = true')\n  -- Should also not block other events, like ModeChanged\n  child.cmd('au ModeChanged * lua _G.n = (_G.n or 0) + 1')\n\n  validate_edit1d('1 + 1', 0, { 'g=$' }, '2', 0)\n\n  eq(child.lua_get('_G.been_here'), vim.NIL)\n  eq(child.lua_get('_G.n') >= 8, true)\n  eq(child.o.eventignore, '')\nend\n\nT['Evaluate']['respects `vim.{g,b}.minioperators_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minioperators_disable = true\n    validate_edit1d('1 + 1', 0, { 'g=$' }, '1 + 1', 4)\n  end,\n})\n\nT['Evaluate']['respects `vim.b.minioperators_config`'] = function()\n  child.lua([[vim.b.minioperators_config = { evaluate = { func = function() return { 'a', 'b' } end } }]])\n  validate_edit({ '1 + 1' }, { 1, 0 }, { 'g=ip' }, { 'a', 'b' }, { 1, 0 })\nend\n\nT['Exchange'] = new_set()\n\nT['Exchange']['works charwise in Normal mode'] = function()\n  local keys = { 'gxiw', 'w', 'gxiw' }\n  validate_edit1d('a bb', 0, keys, 'bb a', 3)\n  validate_edit1d('a bb ccc', 0, keys, 'bb a ccc', 3)\n  validate_edit1d('a bb ccc', 3, keys, 'a ccc bb', 6)\n  validate_edit1d('a bb ccc dddd', 3, keys, 'a ccc bb dddd', 6)\n\n  -- With dot-repeat allowing multiple exchanges\n  validate_edit1d('a bb', 0, { 'gxiw', 'w', '.' }, 'bb a', 3)\n  validate_edit1d('a bb ccc dddd', 0, { 'gxiw', 'w', '.', 'w.w.' }, 'bb a dddd ccc', 10)\n\n  -- Different order\n  local keys_back = { 'gxiw', 'b', 'gxiw' }\n  validate_edit1d('a bb', 2, keys_back, 'bb a', 0)\n  validate_edit1d('a bb ccc', 2, keys_back, 'bb a ccc', 0)\n  validate_edit1d('a bb ccc', 5, keys_back, 'a ccc bb', 2)\n  validate_edit1d('a bb ccc dddd', 5, keys_back, 'a ccc bb dddd', 2)\n\n  -- Over several lines\n  set_lines({ 'aa bb', 'cc dd', 'ee ff', 'gg hh' })\n\n  -- - Set marks\n  set_cursor(2, 2)\n  type_keys('ma')\n  set_cursor(4, 2)\n  type_keys('mb')\n\n  -- - Validate\n  set_cursor(1, 0)\n  type_keys('gx`a', '2j', 'gx`b')\n  eq(get_lines(), { 'ee ff', 'gg dd', 'aa bb', 'cc hh' })\n  eq(get_cursor(), { 3, 0 })\n\n  -- Single cell\n  validate_edit1d('aa bb', 0, { 'gxl', 'w', 'gxl' }, 'ba ab', 3)\nend\n\nT['Exchange']['works linewise in Normal mode'] = function()\n  local keys = { 'gx_', 'j', 'gx_' }\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, keys, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, keys, { 'bb', 'aa', 'cc' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, keys, { 'aa', 'cc', 'bb' }, { 3, 0 })\n  validate_edit({ 'aa', 'bb', 'cc', 'dd' }, { 2, 0 }, keys, { 'aa', 'cc', 'bb', 'dd' }, { 3, 0 })\n\n  -- With dot-repeat allowing multiple exchanges\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gx_', 'j', '.' }, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc', 'dd' }, { 1, 0 }, { 'gx_', 'j', '.', 'j.j.' }, { 'bb', 'aa', 'dd', 'cc' }, { 4, 0 })\n\n  -- Different order\n  local keys_back = { 'gx_', 'k', 'gx_' }\n  validate_edit({ 'aa', 'bb' }, { 2, 0 }, keys_back, { 'bb', 'aa' }, { 1, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, keys_back, { 'bb', 'aa', 'cc' }, { 1, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, keys_back, { 'aa', 'cc', 'bb' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc', 'dd' }, { 3, 0 }, keys_back, { 'aa', 'cc', 'bb', 'dd' }, { 2, 0 })\n\n  -- Empty line\n  validate_edit({ 'aa', '' }, { 1, 0 }, { 'gx_', 'G', 'gx_' }, { '', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', '', 'bb' }, { 1, 0 }, { 'gx_', 'G', 'gx_' }, { 'bb', '', 'aa' }, { 3, 0 })\n\n  -- Over several lines\n  validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'gxip', 'G', 'gxip' }, { 'cc', '', 'aa', 'bb' }, { 3, 0 })\n\n  -- Blank line(s)\n  child.lua('MiniOperators.config.exchange.reindent_linewise = false')\n  validate_edit({ 'aa', '  ' }, { 1, 0 }, { 'gx_', 'G', 'gx_' }, { '  ', 'aa' }, { 2, 0 })\n  validate_edit({ ' ', '  ' }, { 1, 0 }, { 'gx_', 'G', 'gx_' }, { '  ', ' ' }, { 2, 0 })\nend\n\nT['Exchange']['works blockwise in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'io', function() vim.cmd('normal! \\22') end)]])\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n  child.lua([[vim.keymap.set('o', 'iE', function() vim.cmd('normal! \\22jj') end)]])\n  child.lua([[vim.keymap.set('o', 'il', function() vim.cmd('normal! \\22jl') end)]])\n\n  local keys = { 'gxie', 'w', 'gxil' }\n  validate_edit({ 'a bb', 'c dd' }, { 1, 0 }, keys, { 'bb a', 'dd c' }, { 1, 3 })\n  validate_edit({ 'a bb x', 'c dd y' }, { 1, 0 }, keys, { 'bb a x', 'dd c y' }, { 1, 3 })\n  validate_edit({ 'a b xx', 'c d yy' }, { 1, 2 }, keys, { 'a xx b', 'c yy d' }, { 1, 5 })\n  validate_edit({ 'a b xx u', 'c d yy v' }, { 1, 2 }, keys, { 'a xx b u', 'c yy d v' }, { 1, 5 })\n\n  -- With dot-repeat allowing multiple exchanges\n  validate_edit({ 'a bb', 'c dd' }, { 1, 0 }, { 'gxie', 'w', '.' }, { 'b ab', 'd cd' }, { 1, 2 })\n  validate_edit({ 'a b x y', 'c d u v' }, { 1, 0 }, { 'gxie', 'w', '.', 'w.w.' }, { 'b a y x', 'd c v u' }, { 1, 6 })\n\n  -- Different order\n  local keys_back = { 'gxil', 'b', 'gxie' }\n  validate_edit({ 'a bb', 'c dd' }, { 1, 2 }, keys_back, { 'bb a', 'dd c' }, { 1, 0 })\n  validate_edit({ 'a bb x', 'c dd y' }, { 1, 2 }, keys_back, { 'bb a x', 'dd c y' }, { 1, 0 })\n  validate_edit({ 'a b xx', 'c d yy' }, { 1, 4 }, keys_back, { 'a xx b', 'c yy d' }, { 1, 2 })\n  validate_edit({ 'a b xx u', 'c d yy v' }, { 1, 4 }, keys_back, { 'a xx b u', 'c yy d v' }, { 1, 2 })\n\n  -- Spanning empty/blank line\n  validate_edit({ 'a b', '', 'c d' }, { 1, 0 }, { 'gxiE', 'w', 'gxiE' }, { 'b a', '  ', 'd c' }, { 1, 2 })\n  validate_edit({ 'a b', '   ' }, { 1, 0 }, { 'gxie', 'w', 'gxie' }, { 'b a', '   ' }, { 1, 2 })\n\n  -- Single cell\n  validate_edit1d('aa bb', 0, { 'gxio', 'w', 'gxio' }, 'ba ab', 3)\nend\n\nT['Exchange']['works with mixed submodes in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n\n  -- Charwise from - Linewise to\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'gxiw', 'j', 'gx_' }, { 'bb', 'aa', 'cc' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'gx/b$<CR>', 'G', 'gx_' }, { 'ccb', 'aa', 'b' }, { 2, 0 })\n\n  -- Charwise from - Blockwise to\n  validate_edit({ 'aa', 'bc', 'de' }, { 1, 0 }, { 'gxiw', 'j', 'gxie' }, { 'b', 'd', 'aac', 'e' }, { 3, 0 })\n  validate_edit({ 'aa', 'bc', 'de' }, { 1, 0 }, { 'gx/c<CR>', 'jl', 'gxie' }, { 'c', 'eaa', 'db' }, { 2, 1 })\n\n  -- Linewise from - Charwise to\n  validate_edit({ 'aa', 'bb bb' }, { 1, 0 }, { 'gx_', 'j', 'gxiw' }, { 'bb', 'aa bb' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc cc' }, { 1, 0 }, { 'gxj', '2j', 'gxiw' }, { 'cc', 'aa', 'bb cc' }, { 2, 0 })\n\n  -- Linewise from - Blockwise to\n  validate_edit({ 'aa', 'bc', 'de' }, { 1, 0 }, { 'gx_', 'j', 'gxie' }, { 'b', 'd', 'aac', 'e' }, { 3, 0 })\n  validate_edit({ 'aa', 'bb', 'cd', 'ef' }, { 1, 0 }, { 'gxj', '2j', 'gxie' }, { 'c', 'e', 'aad', 'bbf' }, { 3, 0 })\n\n  -- Blockwise from - Charwise to\n  validate_edit({ 'aa', 'bb bb' }, { 1, 0 }, { '<C-v>gx', 'j', 'gxiw' }, { 'bba', 'a bb' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb bb' }, { 1, 0 }, { '<C-v>jgx', 'jw', 'gxiw' }, { 'bba', 'b a', 'b' }, { 2, 2 })\n\n  -- Blockwise from - Linewise to\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { '<C-v>gx', 'j', 'gx_' }, { 'bba', 'a', 'cc' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { '<C-v>jgx', 'G', 'gx_' }, { 'cca', 'b', 'a', 'b' }, { 3, 0 })\nend\n\nT['Exchange']['works with `[count]` in Normal mode'] = function()\n  validate_edit1d('aa bb cc dd ee ', 0, { '2gxaw', '2w', 'gx3aw' }, 'cc dd ee aa bb ', 9)\n\n  -- With dot-repeat\n  validate_edit1d('aa bb cc dd ', 0, { '2gxaw', '2w', '.', '0.2w.' }, 'aa bb cc dd ', 6)\nend\n\nT['Exchange']['works in Normal mode for line'] = function()\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gxx', 'j', 'gxx' }, { 'bb', 'aa' }, { 2, 0 })\n\n  -- With dot-repeat\n  validate_edit({ 'aa', 'bb', 'cc', 'dd' }, { 1, 0 }, { 'gxx', 'j', '.', 'j.j.' }, { 'bb', 'aa', 'dd', 'cc' }, { 4, 0 })\nend\n\nT['Exchange']['works with `[count]` in Normal mode for line'] = function()\n  validate_edit(\n    { 'aa', 'bb', 'cc', 'dd', 'ee' },\n    { 1, 0 },\n    { '2gxx', '2j', '3gxx' },\n    { 'cc', 'dd', 'ee', 'aa', 'bb' },\n    { 4, 0 }\n  )\n\n  -- With dot-repeat\n  validate_edit(\n    { 'aa', 'bb', 'cc', 'dd' },\n    { 1, 0 },\n    { '2gxx', '2j', '.', 'gg.2j.' },\n    { 'aa', 'bb', 'cc', 'dd' },\n    { 3, 0 }\n  )\nend\n\nT['Exchange']['works with empty textobject/motion'] = function()\n  child.api.nvim_set_keymap('o', 'w', '<Cmd><CR>', {})\n\n  -- On step one\n  set_lines({ 'xxx', 'yyy' })\n  set_cursor(1, 1)\n  type_keys('gx', 'w')\n  eq(child.fn.maparg('<C-c>'), '')\n  -- - Should ignore previous time and treat this as step one\n  type_keys('j', 'gx', '$')\n  eq(get_lines(), { 'xxx', 'yyy' })\n  type_keys('k', 'gx', '$')\n  eq(get_lines(), { 'xyy', 'yxx' })\n\n  -- On step two\n  set_lines({ 'xxx', 'yyy' })\n  set_cursor(1, 1)\n  type_keys('gx', 'iw')\n  -- - Should ignore this one while still allowing proper step two\n  type_keys('jl', 'gx', 'w')\n  eq(get_lines(), { 'xxx', 'yyy' })\n  type_keys('gx', '$')\n  eq(get_lines(), { 'yy', 'yxxx' })\nend\n\nT['Exchange']['works in Visual mode'] = function()\n  -- Charwise from - Charwise to\n  validate_edit1d('aa bb', 0, { 'viwgx', 'w', 'viwgx' }, 'bb aa', 3)\n  validate_edit1d('aa bb', 3, { 'viwgx', '0', 'viwgx' }, 'bb aa', 0)\n\n  -- Charwise from - Linewise to\n  validate_edit({ 'aa x', 'bb' }, { 1, 0 }, { 'viwgx', 'j', 'Vgx' }, { 'bb x', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa x', 'bb' }, { 2, 0 }, { 'Vgx', 'k0', 'viwgx' }, { 'bb x', 'aa' }, { 1, 0 })\n\n  -- Charwise from - Blockwise to\n  validate_edit({ 'aa x', 'bb', 'cc' }, { 1, 0 }, { 'viwgx', 'j0', '<C-v>jgx' }, { 'b', 'c x', 'aab', 'c' }, { 3, 0 })\n  validate_edit({ 'aa x', 'bb', 'cc' }, { 2, 0 }, { '<C-v>jgx', 'gg0', 'viwgx' }, { 'b', 'c x', 'aab', 'c' }, { 1, 0 })\n\n  -- Linewise from - Charwise to\n  validate_edit({ 'aa', 'bb x' }, { 1, 0 }, { 'Vgx', 'j0', 'viwgx' }, { 'bb', 'aa x' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb x' }, { 2, 0 }, { 'viwgx', 'k', 'Vgx' }, { 'bb', 'aa x' }, { 1, 0 })\n\n  -- Linewise from - Linewise to\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'Vgx', 'j', 'Vgx' }, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb' }, { 2, 0 }, { 'Vgx', 'k', 'Vgx' }, { 'bb', 'aa' }, { 1, 0 })\n\n  -- Linewise from - Blockwise to\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'Vgx', 'j0', '<C-v>jgx' }, { 'b', 'c', 'aab', 'c' }, { 3, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { '<C-v>jgx', 'gg0', 'Vgx' }, { 'b', 'c', 'aab', 'c' }, { 1, 0 })\n\n  -- Blockwise from - Charwise to\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { '<C-v>jgx', 'G', 'viwgx' }, { 'cca', 'b', 'a', 'b' }, { 3, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'viwgx', 'gg0', '<C-v>jgx' }, { 'cca', 'b', 'a', 'b' }, { 1, 0 })\n\n  -- Blockwise from - Linewise to\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { '<C-v>jgx', 'G', 'Vgx' }, { 'cca', 'b', 'a', 'b' }, { 3, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'Vgx', 'gg0', '<C-v>jgx' }, { 'cca', 'b', 'a', 'b' }, { 1, 0 })\n\n  -- Blockwise from - Blockwise to\n  validate_edit({ 'ab', 'cd' }, { 1, 0 }, { '<C-v>jgx', 'l', '<C-v>jgx' }, { 'ba', 'dc' }, { 1, 1 })\n  validate_edit({ 'ab', 'cd' }, { 1, 1 }, { '<C-v>jgx', 'h', '<C-v>jgx' }, { 'ba', 'dc' }, { 1, 0 })\nend\n\nT['Exchange']['works with newline in region'] = function()\n  validate_edit(\n    { 'a(', '  b', ')', 'c{', '  d,', '}' },\n    { 2, 2 },\n    { 'vk', 'gx', '4jl', 'vk', 'gx' },\n    { 'a(', '  d', ')', 'c{', '  b,', '}' },\n    { 4, 1 }\n  )\n\n  -- Doesn't 100% work with trailing newline due to Neovim limitations\n  -- See https://github.com/neovim/neovim/issues/37664\nend\n\nT['Exchange']['works with different `virtualedit`'] = function()\n  local validate = function()\n    -- Charwise\n    validate_edit1d('aa bb cc', 3, { 'gx', 'iw', 'b', 'gx', 'iw' }, 'bb aa cc', 0)\n    validate_edit1d('aa bb cc', 0, { 'gx', 'iw', 'w', 'gx', 'iw' }, 'bb aa cc', 3)\n    validate_edit1d('aa bb cc', 0, { 'gx', 'iw', '2w', 'gx', 'iw' }, 'cc bb aa', 6)\n\n    validate_edit1d('aa bb cc', 3, { 'viw', 'gx', '2b', 'viw', 'gx' }, 'bb aa cc', 0)\n    validate_edit1d('aa bb cc', 0, { 'viw', 'gx', 'w', 'viw', 'gx' }, 'bb aa cc', 3)\n    validate_edit1d('aa bb cc', 0, { 'viw', 'gx', '2w', 'viw', 'gx' }, 'cc bb aa', 6)\n\n    -- Linewise\n    validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'gxx', 'j', 'gxx' }, { 'bb', 'aa', 'cc' }, { 2, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { 'gxx', 'j', 'gxx' }, { 'aa', 'cc', 'bb' }, { 3, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'gxx', 'k', 'gxx' }, { 'aa', 'cc', 'bb' }, { 2, 0 })\n\n    validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'V', 'gx', 'j', 'V', 'gx' }, { 'bb', 'aa', 'cc' }, { 2, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { 'V', 'gx', 'j', 'V', 'gx' }, { 'aa', 'cc', 'bb' }, { 3, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'V', 'gx', 'k', 'V', 'gx' }, { 'aa', 'cc', 'bb' }, { 2, 0 })\n\n    -- Blockwise\n    child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n    validate_edit({ 'abc', 'def' }, { 1, 0 }, { 'gx', 'ie', 'l', 'gx', 'ie' }, { 'bac', 'edf' }, { 1, 1 })\n    validate_edit({ 'abc', 'def' }, { 1, 1 }, { 'gx', 'ie', 'l', 'gx', 'ie' }, { 'acb', 'dfe' }, { 1, 2 })\n    validate_edit({ 'abc', 'def' }, { 1, 2 }, { 'gx', 'ie', 'h', 'gx', 'ie' }, { 'acb', 'dfe' }, { 1, 1 })\n\n    validate_edit({ 'abc', 'def' }, { 1, 0 }, { '<C-v>jgx', 'l', '<C-v>jgx' }, { 'bac', 'edf' }, { 1, 1 })\n    validate_edit({ 'abc', 'def' }, { 1, 1 }, { '<C-v>jgx', 'l', '<C-v>jgx' }, { 'acb', 'dfe' }, { 1, 2 })\n    validate_edit({ 'abc', 'def' }, { 1, 2 }, { '<C-v>jgx', 'h', '<C-v>jgx' }, { 'acb', 'dfe' }, { 1, 1 })\n  end\n\n  child.o.virtualedit = 'all'\n  validate()\n  child.o.virtualedit = 'onemore'\n  validate()\n  child.o.virtualedit = 'block'\n  validate()\nend\n\nT['Exchange']['works when regions are made in different modes'] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n\n  -- Normal from - Visual to\n  validate_edit1d('aa bb', 0, { 'gxiw', 'w', 'viwgx' }, 'bb aa', 3)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gx_', 'j', 'Vgx' }, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit({ 'ab', 'cd' }, { 1, 0 }, { 'gxie', 'l', '<C-v>jgx' }, { 'ba', 'dc' }, { 1, 1 })\n\n  -- Normal to - Visual from\n  validate_edit1d('aa bb', 0, { 'viwgx', 'w', 'gxiw' }, 'bb aa', 3)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'Vgx', 'j', 'gx_' }, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit({ 'ab', 'cd' }, { 1, 0 }, { '<C-v>jgx', 'l', 'gxie' }, { 'ba', 'dc' }, { 1, 1 })\nend\n\nT['Exchange']['correctly reindents linewise'] = function()\n  -- Should exchange indents\n  validate_edit({ '\\taa', 'bb' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { '\\tbb', 'aa' }, { 2, 0 })\n  validate_edit({ '\\taa', 'bb' }, { 2, 0 }, { 'gx_', 'k', 'gx_' }, { '\\tbb', 'aa' }, { 1, 0 })\n  validate_edit({ '\\taa', '\\t\\tbb' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { '\\tbb', '\\t\\taa' }, { 2, 0 })\n  validate_edit({ '\\taa', '\\t\\tbb' }, { 2, 0 }, { 'gx_', 'k', 'gx_' }, { '\\tbb', '\\t\\taa' }, { 1, 0 })\n\n  validate_edit({ '  aa', 'bb' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { '  bb', 'aa' }, { 2, 0 })\n  validate_edit({ '  aa', 'bb' }, { 2, 0 }, { 'gx_', 'k', 'gx_' }, { '  bb', 'aa' }, { 1, 0 })\n  validate_edit({ '  aa', '    bb' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { '  bb', '    aa' }, { 2, 0 })\n  validate_edit({ '  aa', '    bb' }, { 2, 0 }, { 'gx_', 'k', 'gx_' }, { '  bb', '    aa' }, { 1, 0 })\n\n  -- Should replace current region indent with new one\n  validate_edit({ '\\taa', '\\t\\tbb', 'cc' }, { 1, 0 }, { 'gxj', 'G', 'gx_' }, { '\\tcc', 'aa', '\\tbb' }, { 2, 0 })\n\n  -- Should preserve tabs vs spaces\n  validate_edit({ '\\taa', '  bb' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { '\\tbb', '  aa' }, { 2, 0 })\n  validate_edit({ '\\taa', '  bb' }, { 2, 0 }, { 'gx_', 'k', 'gx_' }, { '\\tbb', '  aa' }, { 1, 0 })\n\n  -- Should correctly work in presence of blank lines (compute indent and not\n  -- reindent them)\n  validate_edit(\n    { '\\t\\taa', '', '\\t', '\\tcc' },\n    { 1, 0 },\n    { 'gx2j', 'G', 'gx_' },\n    { '\\t\\tcc', '\\taa', '', '\\t' },\n    { 2, 0 }\n  )\n\n  -- Should correctly work exchanging **only** blank lines region\n  validate_edit({ 'aa', '\\t\\t', '\\t' }, { 1, 0 }, { 'gx_', 'j', 'gxj' }, { '\\t\\t', '\\t', '\\taa' }, { 3, 0 })\nend\n\nT['Exchange']['respects `config.exchange.reindent_linewise`'] = function()\n  child.lua('MiniOperators.config.exchange.reindent_linewise = false')\n  validate_edit({ '\\taa', 'bb' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { 'bb', '\\taa' }, { 2, 0 })\nend\n\nT['Exchange']['highlights first step'] = new_set(\n  { parametrize = { { 'charwise' }, { 'linewise' }, { 'blockwise' } } },\n  {\n    test = function(mode)\n      child.set_size(5, 12)\n      local keys = ({ charwise = 'gxiw', linewise = 'gx_', blockwise = '<C-v>jlgx' })[mode]\n\n      set_lines({ 'aa aa', 'bb' })\n      set_cursor(1, 0)\n      type_keys(keys)\n      child.expect_screenshot()\n    end,\n  }\n)\n\nT['Exchange'][\"correctly highlights first step with 'selection=exclusive'\"] = function()\n  child.set_size(5, 12)\n  child.o.selection = 'exclusive'\n\n  set_lines({ 'aaa bbb' })\n  set_cursor(1, 0)\n  type_keys('v2l', 'gx')\n  child.expect_screenshot()\nend\n\nT['Exchange']['can be canceled'] = function()\n  child.set_size(5, 12)\n  set_lines({ 'aa bb' })\n  set_cursor(1, 0)\n\n  type_keys('gxiw')\n  child.expect_screenshot()\n\n  -- Should reset highlighting and \"exchange state\"\n  type_keys('<C-c>')\n  child.expect_screenshot()\n\n  type_keys('gxiw', 'w', 'gxiw')\n  eq(get_lines(), { 'bb aa' })\n\n  -- Should cleanup temporary mapping\n  eq(child.fn.maparg('<C-c>'), '')\nend\n\nT['Exchange']['works for intersecting regions'] = function()\n  -- Charwise\n  validate_edit1d('abcd', 0, { 'gx3l', 'l', 'gx3l' }, 'bcdabc', 3)\n  validate_edit1d('abcd', 0, { 'gx4l', 'l', 'gx2l' }, 'abcd', 2)\n  validate_edit1d('abcd', 1, { 'gx2l', '0', 'gx4l' }, 'bc', 0)\n\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'vjgx', 'vjgx' }, { 'bb', 'caa', 'bc' }, { 2, 1 })\n\n  -- Linewise\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'Vjgx', 'Vjgx' }, { 'bb', 'cc', 'aa', 'bb' }, { 3, 0 })\n  validate_edit({ 'aa', 'bb', 'cc', '' }, { 1, 0 }, { 'Vipgx', 'k', 'Vgx' }, { 'aa', 'bb', 'cc', '' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc', '' }, { 2, 0 }, { 'Vgx', 'Vipgx' }, { 'bb', '' }, { 1, 0 })\n\n  -- Blockwise\n  validate_edit({ 'abc', 'def' }, { 1, 0 }, { '<C-v>jlgx', 'l', '<C-v>jlgx' }, { 'bcab', 'efde' }, { 1, 2 })\n  validate_edit({ 'abc', 'def' }, { 1, 0 }, { '<C-v>jllgx', 'l', '<C-v>jgx' }, { 'abc', 'def' }, { 1, 1 })\n  validate_edit({ 'abc', 'def' }, { 1, 1 }, { '<C-v>jgx', 'h', '<C-v>jllgx' }, { 'b', 'e' }, { 1, 0 })\nend\n\nT['Exchange']['works for regions in different buffers'] = function()\n  local buf_1 = child.api.nvim_create_buf(true, false)\n  local buf_2 = child.api.nvim_create_buf(true, false)\n\n  child.api.nvim_buf_set_lines(buf_1, 0, -1, true, { 'aa', 'aa' })\n  child.api.nvim_buf_set_lines(buf_2, 0, -1, true, { 'bb', 'bb' })\n\n  child.api.nvim_set_current_buf(buf_1)\n  type_keys('gx_')\n  child.api.nvim_set_current_buf(buf_2)\n  type_keys('gx_')\n\n  eq(child.api.nvim_buf_get_lines(buf_1, 0, -1, true), { 'bb', 'aa' })\n  eq(child.api.nvim_buf_get_lines(buf_2, 0, -1, true), { 'aa', 'bb' })\nend\n\nT['Exchange']['accounts for outdated first step buffer'] = function()\n  local buf_1 = child.api.nvim_create_buf(true, false)\n  local buf_2 = child.api.nvim_create_buf(true, false)\n\n  child.api.nvim_buf_set_lines(buf_1, 0, -1, true, { 'aa', 'aa' })\n  child.api.nvim_buf_set_lines(buf_2, 0, -1, true, { 'bb', 'cc' })\n\n  child.api.nvim_set_current_buf(buf_1)\n  type_keys('gx_')\n  child.api.nvim_set_current_buf(buf_2)\n\n  child.api.nvim_buf_delete(buf_1, { force = true })\n  -- Should not error and restart exchange process\n  type_keys('gx_')\n  eq(get_lines(), { 'bb', 'cc' })\n\n  type_keys('j', 'gx_')\n  eq(get_lines(), { 'cc', 'bb' })\nend\n\nT['Exchange']['works for same region'] = function()\n  -- Charwise\n  validate_edit1d('aa bb cc', 4, { 'gxiw', 'gxiw' }, 'aa bb cc', 3)\n\n  -- Linewise\n  validate_edit1d('aa bb cc', 4, { 'gx_', 'gx_' }, 'aa bb cc', 0)\n\n  -- Blockwise\n  validate_edit({ 'ab', 'cd' }, { 1, 0 }, { '<C-v>jgx', '<C-v>jgx' }, { 'ab', 'cd' }, { 2, 0 })\nend\n\nT['Exchange']['works with multibyte characters'] = function()\n  child.set_size(5, 12)\n\n  -- Charwise 2 bytes\n  set_lines({ '  ыыы ффф' })\n  set_cursor(1, 2)\n  type_keys('gx2l')\n  -- - Should properly highlight range\n  child.expect_screenshot()\n\n  type_keys('w', 'gx2l')\n  eq(get_lines(), { '  ффы ыыф' })\n  eq(get_cursor(), { 1, 9 })\n\n  -- Charwise 3 bytes\n  set_lines({ '  ╔═╗ ╚═╝' })\n  set_cursor(1, 2)\n  type_keys('gx2l')\n  child.expect_screenshot()\n\n  type_keys('w', 'gx2l')\n  eq(get_lines(), { '  ╚═╗ ╔═╝' })\n  eq(get_cursor(), { 1, 12 })\n\n  -- Charwise 4 bytes\n  set_lines({ '  🬕🬂🬨  🬲🬭🬷' })\n  set_cursor(1, 2)\n  type_keys('gx2l')\n  child.expect_screenshot()\n\n  type_keys('w', 'gx2l')\n  eq(get_lines(), { '  🬲🬭🬨  🬕🬂🬷' })\n  eq(get_cursor(), { 1, 16 })\n\n  -- Linewise\n  set_lines({ '  ыыы ффф', '  эээ ююю' })\n  set_cursor(1, 2)\n  type_keys('gx_')\n  child.expect_screenshot()\n\n  type_keys('j', 'gx_')\n  eq(get_lines(), { '  эээ ююю', '  ыыы ффф' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Blockwise\n  set_lines({ '  ыыы ффф', '  эээ ююю' })\n  set_cursor(1, 2)\n  type_keys('<C-v>jl', 'gx')\n  child.expect_screenshot()\n\n  type_keys('w', '<C-v>jl', 'gx')\n  eq(get_lines(), { '  ффы ыыф', '  ююэ ээю' })\n  eq(get_cursor(), { 1, 9 })\nend\n\nT['Exchange']['does not have side effects'] = function()\n  set_lines({ 'rst', 'aa', 'bb' })\n\n  -- Marks `x`, `y` and registers `a`, `b`, '\"'\n  set_cursor(1, 0)\n  type_keys('mx')\n  type_keys('v\"ay')\n\n  set_cursor(1, 1)\n  type_keys('my')\n  type_keys('v\"by')\n\n  set_cursor(1, 2)\n  type_keys('vy')\n\n  -- Should properly manage stop mapping\n  child.api.nvim_set_keymap('n', '<C-c>', ':echo 1<CR>', {})\n\n  -- Do exchange\n  set_cursor(2, 0)\n  type_keys('gx_', 'j', 'gx_')\n\n  -- Validate\n  eq(get_lines(), { 'rst', 'bb', 'aa' })\n  eq(child.api.nvim_buf_get_mark(0, 'x'), { 1, 0 })\n  eq(child.api.nvim_buf_get_mark(0, 'y'), { 1, 1 })\n  eq(child.fn.getreg('a'), 'r')\n  eq(child.fn.getreg('b'), 's')\n  eq(child.fn.getreg('\"'), 't')\n  eq(child.fn.maparg('<C-c>'), ':echo 1<CR>')\nend\n\nT['Exchange']['preserves visual marks'] = function()\n  set_lines({ 'aa', 'bb', 'select', 'cc' })\n\n  -- Create marks\n  set_cursor(3, 0)\n  type_keys('viw', '<Esc>')\n\n  -- Exchange\n  set_cursor(1, 0)\n  type_keys('gxj', 'G', 'gx_')\n  eq(get_lines(), { 'cc', 'select', 'aa', 'bb' })\n  eq(child.api.nvim_buf_get_mark(0, '<'), { 2, 0 })\n  eq(child.api.nvim_buf_get_mark(0, '>'), { 2, 5 })\nend\n\nT['Exchange']['respects `config.exchange.prefix`'] = function()\n  child.api.nvim_del_keymap('n', 'gx')\n  child.api.nvim_del_keymap('n', 'gxx')\n  child.api.nvim_del_keymap('x', 'gx')\n\n  load_module({ exchange = { prefix = 'cx' } })\n\n  validate_edit1d('aa bb', 0, { 'cxiw', 'w', 'cxiw' }, 'bb aa', 3)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'cxx', 'j', 'cxx' }, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit1d('aa bb', 0, { 'viwcx', 'w', 'viwcx' }, 'bb aa', 3)\nend\n\nT['Exchange']['works with `make_mappings()`'] = function()\n  child.api.nvim_del_keymap('n', 'gx')\n  child.api.nvim_del_keymap('n', 'gxx')\n  child.api.nvim_del_keymap('x', 'gx')\n\n  load_module({ exchange = { prefix = '' } })\n  make_mappings('exchange', { textobject = 'cx', line = 'cxx', selection = 'cx' })\n\n  validate_edit1d('aa bb', 0, { 'cxiw', 'w', 'cxiw' }, 'bb aa', 3)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'cxx', 'j', 'cxx' }, { 'bb', 'aa' }, { 2, 0 })\n  validate_edit1d('aa bb', 0, { 'viwcx', 'w', 'viwcx' }, 'bb aa', 3)\nend\n\nT['Exchange']['respects `selection=exclusive`'] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n  child.o.selection = 'exclusive'\n\n  validate_edit1d('aaa bbb x', 0, { 'gxiw', 'w', 'gxiw' }, 'bbb aaa x', 4)\n  validate_edit({ 'aa', 'bb', 'x' }, { 1, 0 }, { 'gx_', 'j', 'gx_' }, { 'bb', 'aa', 'x' }, { 2, 0 })\n  validate_edit({ 'a b c', 'a b c' }, { 1, 0 }, { 'gxie', 'w', 'gxie' }, { 'b a c', 'b a c' }, { 1, 2 })\n\n  validate_edit1d('aaa bbb x', 0, { 'v2l', 'gx', 'w', 'v2l', 'gx' }, 'bba aab x', 4)\n  validate_edit({ 'aa', 'bb', 'x' }, { 1, 0 }, { 'V', 'gx', 'j', 'V', 'gx' }, { 'bb', 'aa', 'x' }, { 2, 0 })\n  validate_edit(\n    { 'aaa bbb', 'ccc ddd' },\n    { 1, 0 },\n    { '<C-v>jll', 'gx', 'w', '<C-v>jll', 'gx' },\n    { 'bba aab', 'ddc ccd' },\n    { 1, 4 }\n  )\nend\n\nT['Exchange'][\"respects 'nomodifiable'\"] = function()\n  set_lines({ 'aa bb' })\n  set_cursor(1, 0)\n  child.bo.modifiable = false\n  type_keys('gxe', 'w', 'gx$')\n  eq(get_lines(), { 'aa bb' })\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['Exchange']['does not trigger `TextYankPost` event'] = function()\n  child.cmd('au TextYankPost * lua _G.been_here = true')\n  -- Should also not block other events, like ModeChanged\n  child.cmd('au ModeChanged * lua _G.n = (_G.n or 0) + 1')\n\n  validate_edit1d('aa bb', 0, { 'gxiw', 'w', 'gxiw' }, 'bb aa', 3)\n\n  eq(child.lua_get('_G.been_here'), vim.NIL)\n  eq(child.lua_get('_G.n') >= 16, true)\n  eq(child.o.eventignore, '')\nend\n\nT['Exchange']['respects `vim.{g,b}.minioperators_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minioperators_disable = true\n    validate_edit1d('aa bb', 0, { 'gxiw' }, 'waa bb', 1)\n  end,\n})\n\nT['Exchange']['respects `vim.b.minioperators_config`'] = function()\n  child.b.minioperators_config = { exchange = { reindent_linewise = false } }\n\n  validate_edit(\n    { '\\taa', '\\tbb', 'cc', 'dd' },\n    { 2, 0 },\n    { 'gx_', 'G', 'gx_' },\n    { '\\taa', 'dd', 'cc', '\\tbb' },\n    { 4, 0 }\n  )\nend\n\nT['Multiply'] = new_set()\n\nT['Multiply']['works charwise in Normal mode'] = function()\n  validate_edit1d('aa bb', 0, { 'gmiw' }, 'aaaa bb', 2)\n  validate_edit1d('aa bb', 0, { 'gmaw' }, 'aa aa bb', 3)\n\n  -- With dot-repeat\n  validate_edit1d('aa bb', 0, { 'gmiw', 'w', '.' }, 'aaaa bbbb', 7)\n\n  -- With [count] and dot-repeat\n  validate_edit1d('aa bb', 0, { '2gmiw', 'w', '.' }, 'aaaaaa bbbbbb', 9)\n\n  -- Over several lines\n  validate_edit({ 'aa', 'bb_cc' }, { 1, 0 }, { 'gm/c<CR>' }, { 'aa', 'bb_aa', 'bb_cc' }, { 2, 3 })\nend\n\nT['Multiply']['works linewise in Normal mode'] = function()\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gm_' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit({ 'aa', ' ', 'bb' }, { 1, 0 }, { 'gmap' }, { 'aa', ' ', 'aa', ' ', 'bb' }, { 3, 0 })\n\n  -- With dot-repeat\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gm_', 'j', '.' }, { 'aa', 'aa', 'bb', 'bb' }, { 4, 0 })\n\n  -- Should put cursor on first non-blank of paste\n  validate_edit({ '  aa', 'bb' }, { 1, 0 }, { 'gm_' }, { '  aa', '  aa', 'bb' }, { 2, 2 })\n  validate_edit({ '\\taa', 'bb' }, { 1, 0 }, { 'gm_' }, { '\\taa', '\\taa', 'bb' }, { 2, 1 })\n\n  -- With [count] and dot-repeat. Should put cursor on first new non-blank.\n  validate_edit(\n    { '\\taa', '\\tbb' },\n    { 1, 0 },\n    { '2gm_', '2j', '.' },\n    { '\\taa', '\\taa', '\\taa', '\\tbb', '\\tbb', '\\tbb' },\n    { 5, 1 }\n  )\nend\n\nT['Multiply']['works blockwise in Normal mode'] = function()\n  -- Validate for all four ways to create block\n  child.lua([[vim.keymap.set('o', 'ia', function() vim.cmd('normal! \\22jl') end)]])\n  child.lua([[vim.keymap.set('o', 'ib', function() vim.cmd('normal! \\22jh') end)]])\n  child.lua([[vim.keymap.set('o', 'ic', function() vim.cmd('normal! \\22kl') end)]])\n  child.lua([[vim.keymap.set('o', 'id', function() vim.cmd('normal! \\22kh') end)]])\n\n  local lines = { 'ab rs', 'cd uv' }\n\n  local ref_lines, ref_cursor = { 'abab rs', 'cdcd uv' }, { 1, 2 }\n  validate_edit(lines, { 1, 0 }, { 'gmia' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 1, 1 }, { 'gmib' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 0 }, { 'gmic' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 1 }, { 'gmid' }, ref_lines, ref_cursor)\n\n  -- With dot-repeat\n  local ref_lines_dot, ref_cursor_dot = { 'abab rsrs', 'cdcd uvuv' }, { 1, 7 }\n  validate_edit(lines, { 1, 0 }, { 'gmia', 'w', '.' }, ref_lines_dot, ref_cursor_dot)\n  validate_edit(lines, { 1, 1 }, { 'gmib', 'we', '.' }, ref_lines_dot, ref_cursor_dot)\n  validate_edit(lines, { 2, 0 }, { 'gmic', 'wj', '.' }, ref_lines_dot, ref_cursor_dot)\n  validate_edit(lines, { 2, 1 }, { 'gmid', 'wej', '.' }, ref_lines_dot, ref_cursor_dot)\n\n  -- With [count] and dot-repeat\n  local ref_lines_count, ref_cursor_count = { 'ababab rsrsrs', 'cdcdcd uvuvuv' }, { 1, 9 }\n  validate_edit(lines, { 1, 0 }, { '2gmia', 'w', '.' }, ref_lines_count, ref_cursor_count)\n  validate_edit(lines, { 1, 1 }, { '2gmib', 'we', '.' }, ref_lines_count, ref_cursor_count)\n  validate_edit(lines, { 2, 0 }, { '2gmic', 'wj', '.' }, ref_lines_count, ref_cursor_count)\n  validate_edit(lines, { 2, 1 }, { '2gmid', 'wej', '.' }, ref_lines_count, ref_cursor_count)\nend\n\nT['Multiply']['works with two types of `[count]` in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'ia', function() vim.cmd('normal! \\22j' .. vim.v.count1 .. 'l') end)]])\n\n  -- Second `[count]` for textobject with dot-repeat\n  validate_edit1d('aa bb cc dd x', 0, { 'gm2aw', '2w', '.' }, 'aa bb aa bb cc dd cc dd x', 18)\n  validate_edit(\n    { 'aa', 'bb', 'cc', 'dd', 'x' },\n    { 1, 0 },\n    { 'gm2_', '2j', '.' },\n    { 'aa', 'bb', 'aa', 'bb', 'cc', 'dd', 'cc', 'dd', 'x' },\n    { 7, 0 }\n  )\n  validate_edit(\n    { 'abc rst', 'def uvw' },\n    { 1, 0 },\n    { 'gm2ia', 'w', '.' },\n    { 'abcabc rstrst', 'defdef uvwuvw' },\n    { 1, 10 }\n  )\n\n  -- Both `[count]`s with dot-repeat\n  validate_edit1d('aa bb cc dd x', 0, { '2gm2aw', '4w', '.' }, 'aa bb aa bb aa bb cc dd cc dd cc dd x', 24)\n  validate_edit(\n    { 'aa', 'bb', 'cc', 'dd', 'x' },\n    { 1, 0 },\n    { '2gm2_', '4j', '.' },\n    { 'aa', 'bb', 'aa', 'bb', 'aa', 'bb', 'cc', 'dd', 'cc', 'dd', 'cc', 'dd', 'x' },\n    { 9, 0 }\n  )\n  validate_edit(\n    { 'abc rst', 'def uvw' },\n    { 1, 0 },\n    { '2gm2ia', 'w', '.' },\n    { 'abcabcabc rstrstrst', 'defdefdef uvwuvwuvw' },\n    { 1, 13 }\n  )\nend\n\nT['Multiply']['works in Normal mode for line'] = function()\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gmm' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit({ '  aa', 'bb' }, { 1, 0 }, { 'gmm' }, { '  aa', '  aa', 'bb' }, { 2, 2 })\n\n  -- With dot-repeat\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gmm', 'j', '.' }, { 'aa', 'aa', 'bb', 'bb' }, { 4, 0 })\nend\n\nT['Multiply']['works with `[count]` in Normal mode for line'] = function()\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { '2gmm' }, { 'aa', 'aa', 'aa', 'bb' }, { 2, 0 })\n\n  -- With dot-repeat\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { '2gmm', '2j', '.' }, { 'aa', 'aa', 'aa', 'bb', 'bb', 'bb' }, { 5, 0 })\nend\n\nT['Multiply']['works with `cmdheight=0`'] = function()\n  child.set_size(7, 20)\n  child.o.cmdheight = 0\n  child.o.statusline = 'My statusline'\n  -- Force quick test for regular `gm` operator\n  child.api.nvim_del_keymap('n', 'gmm')\n\n  set_lines({ 'aa bb' })\n  type_keys('gm')\n  child.expect_screenshot({ redraw = false })\n  type_keys('iw')\n  child.expect_screenshot({ redraw = false })\nend\n\nT['Multiply']['works with empty textobject/motion'] = function()\n  child.api.nvim_set_keymap('o', 'w', '<Cmd><CR>', {})\n  set_lines({ 'xxx' })\n  set_cursor(1, 1)\n  type_keys('gm', 'w')\n  eq(get_lines(), { 'xxx' })\nend\n\nT['Multiply']['works in Visual mode'] = function()\n  validate_edit1d('aa bb', 0, { 'viw', 'gm' }, 'aaaa bb', 2)\n\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'V', 'gm' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit({ '  aa', 'bb' }, { 1, 0 }, { 'V', 'gm' }, { '  aa', '  aa', 'bb' }, { 2, 2 })\n\n  local lines = { 'ab rs', 'cd uv' }\n  local ref_lines, ref_cursor = { 'abab rs', 'cdcd uv' }, { 1, 2 }\n  validate_edit(lines, { 1, 0 }, { '<C-v>jl', 'gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 1, 1 }, { '<C-v>jh', 'gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 0 }, { '<C-v>kl', 'gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 1 }, { '<C-v>kh', 'gm' }, ref_lines, ref_cursor)\nend\n\nT['Multiply']['works with `[count]` in Visual mode'] = function()\n  validate_edit1d('aa bb', 0, { 'viw', '2gm' }, 'aaaaaa bb', 2)\n\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'V', '2gm' }, { 'aa', 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit({ '  aa', 'bb' }, { 1, 0 }, { 'V', '2gm' }, { '  aa', '  aa', '  aa', 'bb' }, { 2, 2 })\n\n  local lines = { 'ab rs', 'cd uv' }\n  local ref_lines, ref_cursor = { 'ababab rs', 'cdcdcd uv' }, { 1, 2 }\n  validate_edit(lines, { 1, 0 }, { '<C-v>jl', '2gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 1, 1 }, { '<C-v>jh', '2gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 0 }, { '<C-v>kl', '2gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 1 }, { '<C-v>kh', '2gm' }, ref_lines, ref_cursor)\nend\n\nT['Multiply']['works with newline in region'] = function()\n  validate_edit({ 'a(', '  b', ')' }, { 2, 2 }, { 'vk', 'gm' }, { 'a(', '  b', '  b', ')' }, { 2, 2 })\n\n  -- Doesn't 100% work with trailing newline due to Neovim limitations\n  -- See https://github.com/neovim/neovim/issues/37664\nend\n\nT['Multiply']['works with different `virtualedit`'] = function()\n  local validate = function()\n    -- Charwise\n    validate_edit1d('aa bb cc', 0, { 'gm', 'iw' }, 'aaaa bb cc', 2)\n    validate_edit1d('aa bb cc', 3, { 'gm', 'iw' }, 'aa bbbb cc', 5)\n    validate_edit1d('aa bb cc', 6, { 'gm', 'iw' }, 'aa bb cccc', 8)\n\n    validate_edit1d('aa bb cc', 0, { 'viw', 'gm' }, 'aaaa bb cc', 2)\n    validate_edit1d('aa bb cc', 3, { 'viw', 'gm' }, 'aa bbbb cc', 5)\n    validate_edit1d('aa bb cc', 6, { 'viw', 'gm' }, 'aa bb cccc', 8)\n\n    -- Linewise\n    validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'gmm' }, { 'aa', 'aa', 'bb', 'cc' }, { 2, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { 'gmm' }, { 'aa', 'bb', 'bb', 'cc' }, { 3, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'gmm' }, { 'aa', 'bb', 'cc', 'cc' }, { 4, 0 })\n\n    validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'V', 'gm' }, { 'aa', 'aa', 'bb', 'cc' }, { 2, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { 'V', 'gm' }, { 'aa', 'bb', 'bb', 'cc' }, { 3, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'V', 'gm' }, { 'aa', 'bb', 'cc', 'cc' }, { 4, 0 })\n\n    -- Blockwise\n    child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n    validate_edit({ 'abc', 'def' }, { 1, 0 }, { 'gm', 'ie' }, { 'aabc', 'ddef' }, { 1, 1 })\n    validate_edit({ 'abc', 'def' }, { 1, 1 }, { 'gm', 'ie' }, { 'abbc', 'deef' }, { 1, 2 })\n    validate_edit({ 'abc', 'def' }, { 1, 2 }, { 'gm', 'ie' }, { 'abcc', 'deff' }, { 1, 3 })\n\n    validate_edit({ 'abc', 'def' }, { 1, 0 }, { '<C-v>j', 'gm' }, { 'aabc', 'ddef' }, { 1, 1 })\n    validate_edit({ 'abc', 'def' }, { 1, 1 }, { '<C-v>j', 'gm' }, { 'abbc', 'deef' }, { 1, 2 })\n    validate_edit({ 'abc', 'def' }, { 1, 2 }, { '<C-v>j', 'gm' }, { 'abcc', 'deff' }, { 1, 3 })\n  end\n\n  child.o.virtualedit = 'all'\n  validate()\n  child.o.virtualedit = 'onemore'\n  validate()\n  child.o.virtualedit = 'block'\n  validate()\nend\n\nT['Multiply']['works with multibyte characters'] = function()\n  -- Charwise\n  validate_edit({ 'ыыы', 'aa x' }, { 1, 0 }, { 'gm/x<CR>' }, { 'ыыы', 'aa ыыы', 'aa x' }, { 2, 3 })\n\n  -- Linewise\n  validate_edit({ 'ыыы', 'aaa', 'x' }, { 1, 0 }, { 'gmj' }, { 'ыыы', 'aaa', 'ыыы', 'aaa', 'x' }, { 3, 0 })\n\n  -- All four blockwise selections\n  local validate_blockwise = function(init_cursor, keys)\n    validate_edit({ 'ыыы x', 'aaa x' }, init_cursor, keys, { 'ыыыыыы x', 'aaaaaa x' }, { 1, 6 })\n  end\n\n  validate_blockwise({ 1, 0 }, { '<C-v>je', 'gm' })\n  validate_blockwise({ 1, 4 }, { '<C-v>jb', 'gm' })\n  validate_blockwise({ 2, 0 }, { '<C-v>ke', 'gm' })\n  validate_blockwise({ 2, 2 }, { '<C-v>kb', 'gm' })\nend\n\nT['Multiply']['works in edge cases'] = function()\n  -- End of line\n  validate_edit1d('aa bb', 3, { 'gmiw' }, 'aa bbbb', 5)\n  validate_edit1d('aa bb', 4, { 'gmiw' }, 'aa bbbb', 5)\n\n  -- Last line\n  validate_edit({ 'aa' }, { 1, 0 }, { 'gm_' }, { 'aa', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb' }, { 2, 0 }, { 'gm_' }, { 'aa', 'bb', 'bb' }, { 3, 0 })\nend\n\nT['Multiply']['respects `config.multiply.func`'] = function()\n  -- Indent by two spaces only for linewise content\n  child.lua([[MiniOperators.config.multiply.func = function(content)\n    if content.submode ~= 'V' then return content.lines end\n    return vim.tbl_map(function(l) return '  ' .. l end, content.lines)\n  end]])\n\n  validate_edit1d('aa bb', 0, { 'gmiw' }, 'aaaa bb', 2)\n  validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'gmip' }, { 'aa', 'bb', '  aa', '  bb', '', 'cc' }, { 3, 2 })\n  validate_edit({ 'ab', 'cd' }, { 1, 0 }, { '<C-v>j', 'gm' }, { 'aab', 'ccd' }, { 1, 1 })\nend\n\nT['Multiply'][\"works with 'y' in 'cpoptions'\"] = function()\n  child.cmd('set cpoptions+=y')\n\n  -- Dot-repeat should still work\n  validate_edit1d('aa bb', 0, { 'gmiw', 'w', '.' }, 'aaaa bbbb', 7)\nend\n\nT['Multiply']['does not have side effects'] = function()\n  set_lines({ 'aa', 'bb', 'xy' })\n\n  -- All non-operator related marks and registers 'x', '\"'\n  set_cursor(3, 0)\n  type_keys('ma')\n  type_keys('v\"xy')\n\n  set_cursor(3, 1)\n  type_keys('mx')\n  type_keys('vy')\n\n  -- Do multiply\n  set_cursor(1, 0)\n  type_keys('gmj')\n\n  -- Validate\n  eq(get_lines(), { 'aa', 'bb', 'aa', 'bb', 'xy' })\n  eq(child.api.nvim_buf_get_mark(0, 'a'), { 5, 0 })\n  eq(child.api.nvim_buf_get_mark(0, 'x'), { 5, 1 })\n  eq(child.fn.getreg('x'), 'x')\n  eq(child.fn.getreg('\"'), 'y')\nend\n\nT['Multiply']['preserves visual marks'] = function()\n  set_lines({ 'aa', 'bb', 'select' })\n\n  -- Create marks\n  set_cursor(3, 0)\n  type_keys('viw', '<Esc>')\n\n  -- Multiply\n  set_cursor(1, 0)\n  type_keys('gmj')\n  eq(get_lines(), { 'aa', 'bb', 'aa', 'bb', 'select' })\n  eq(child.api.nvim_buf_get_mark(0, '<'), { 5, 0 })\n  eq(child.api.nvim_buf_get_mark(0, '>'), { 5, 5 })\nend\n\nT['Multiply']['respects `config.multiply.prefix`'] = function()\n  child.api.nvim_del_keymap('n', 'gm')\n  child.api.nvim_del_keymap('n', 'gmm')\n  child.api.nvim_del_keymap('x', 'gm')\n\n  load_module({ multiply = { prefix = 'cm' } })\n\n  validate_edit1d('aa bb', 0, { 'cmiw' }, 'aaaa bb', 2)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'cmm' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit1d('aa bb', 0, { 'viw', 'cm' }, 'aaaa bb', 2)\nend\n\nT['Multiply']['works with `make_mappings()`'] = function()\n  child.api.nvim_del_keymap('n', 'gm')\n  child.api.nvim_del_keymap('n', 'gmm')\n  child.api.nvim_del_keymap('x', 'gm')\n\n  load_module({ multiply = { prefix = '' } })\n  make_mappings('multiply', { textobject = 'cm', line = 'cmm', selection = 'cm' })\n\n  validate_edit1d('aa bb', 0, { 'cmiw' }, 'aaaa bb', 2)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'cmm' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit1d('aa bb', 0, { 'viw', 'cm' }, 'aaaa bb', 2)\nend\n\nT['Multiply']['respects `selection=exclusive`'] = function()\n  child.o.selection = 'exclusive'\n\n  -- Charwise\n  validate_edit1d('aa bb', 0, { 'gmiw' }, 'aaaa bb', 2)\n  validate_edit1d('aa bb', 0, { 'viw', 'gm', '<Esc>' }, 'aaaa bb', 2)\n\n  -- Linewise\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gm_' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'V', 'gm' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n\n  -- Blockwise for all four ways to create block\n  -- - Normal mode\n  child.lua([[_G.block_object = function(keys)\n    return function()\n      vim.o.selection = 'inclusive'\n      vim.cmd('normal! \\22' .. keys)\n      vim.schedule(function() vim.o.selection = 'exclusive' end)\n    end\n  end]])\n  child.lua([[vim.keymap.set('o', 'ia', _G.block_object('jl'))]])\n  child.lua([[vim.keymap.set('o', 'ib', _G.block_object('jh'))]])\n  child.lua([[vim.keymap.set('o', 'ic', _G.block_object('kl'))]])\n  child.lua([[vim.keymap.set('o', 'id', _G.block_object('kh'))]])\n\n  local lines = { 'ab rs', 'cd uv' }\n  local ref_lines, ref_cursor = { 'abab rs', 'cdcd uv' }, { 1, 2 }\n  validate_edit(lines, { 1, 0 }, { 'gmia' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 1, 1 }, { 'gmib' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 0 }, { 'gmic' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 1 }, { 'gmid' }, ref_lines, ref_cursor)\n\n  -- - Visual mode\n  validate_edit(lines, { 1, 0 }, { '<C-v>jll', 'gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 1, 1 }, { '<C-v>jh', 'gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 0 }, { '<C-v>kl', 'gm' }, ref_lines, ref_cursor)\n  validate_edit(lines, { 2, 2 }, { '<C-v>khh', 'gm' }, ref_lines, ref_cursor)\nend\n\nT['Multiply'][\"respects 'nomodifiable'\"] = function()\n  set_lines({ 'aa bb' })\n  set_cursor(1, 0)\n  child.bo.modifiable = false\n  type_keys('gm$')\n  eq(get_lines(), { 'aa bb' })\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['Multiply']['does not trigger `TextYankPost` event'] = function()\n  child.cmd('au TextYankPost * lua _G.been_here = true')\n  -- Should also not block other events, like ModeChanged\n  child.cmd('au ModeChanged * lua _G.n = (_G.n or 0) + 1')\n\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'gmm' }, { 'aa', 'aa', 'bb' }, { 2, 0 })\n\n  eq(child.lua_get('_G.been_here'), vim.NIL)\n  eq(child.lua_get('_G.n') >= 5, true)\n  eq(child.o.eventignore, '')\nend\n\nT['Multiply']['respects `vim.{g,b}.minioperators_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minioperators_disable = true\n    validate_edit1d('aa bb', 0, { 'gmiw' }, 'waa bb', 1)\n  end,\n})\n\nT['Multiply']['respects `vim.b.minioperators_config`'] = function()\n  -- Indent by two spaces\n  child.lua([[_G.multiply_func = function(content)\n    return vim.tbl_map(function(l) return '  ' .. l end, content.lines)\n  end\n  vim.b.minioperators_config = { multiply = { func = _G.multiply_func } }\n  ]])\n\n  validate_edit({ 'aa', 'bb', '', 'cc' }, { 1, 0 }, { 'gmip' }, { 'aa', 'bb', '  aa', '  bb', '', 'cc' }, { 3, 2 })\nend\n\nT['Replace'] = new_set()\n\nT['Replace']['works charwise in Normal mode'] = function()\n  validate_edit1d('aa bb cc', 0, { 'yiw', 'w', 'graW' }, 'aa aacc', 3)\n\n  -- With dot-repeat\n  validate_edit1d('aa bb cc', 0, { 'yiw', 'w', 'graW', '.' }, 'aaaa', 2)\n\n  -- Over several lines\n  set_lines({ 'aa bb', 'cc dd' })\n\n  -- - Set mark\n  set_cursor(2, 2)\n  type_keys('ma')\n\n  -- - Validate\n  set_cursor(1, 0)\n  type_keys('yiw', 'w', 'gr`a')\n  eq(get_lines(), { 'aa aa dd' })\n  eq(get_cursor(), { 1, 3 })\n\n  -- Single cell\n  validate_edit1d('aa bb', 0, { 'yl', 'w', 'grl' }, 'aa ab', 3)\nend\n\nT['Replace']['works linewise in Normal mode'] = function()\n  local lines = { 'aa', '', 'bb', 'cc', '', 'dd', 'ee' }\n  validate_edit(lines, { 1, 0 }, { 'yy', '2j', 'grip' }, { 'aa', '', 'aa', '', 'dd', 'ee' }, { 3, 0 })\n\n  -- - With dot-repeat\n  validate_edit(lines, { 1, 0 }, { 'yy', '2j', 'grip', '2j', '.' }, { 'aa', '', 'aa', '', 'aa' }, { 5, 0 })\nend\n\nT['Replace']['correctly reindents linewise in Normal mode'] = function()\n  -- Should use indent from text being replaced\n  validate_edit({ '\\taa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { '\\taa', 'aa' }, { 2, 0 })\n  validate_edit({ '\\taa', 'bb' }, { 2, 0 }, { 'yy', 'k', 'gr_' }, { '\\tbb', 'bb' }, { 1, 0 })\n  validate_edit({ '\\taa', '\\t\\tbb' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { '\\taa', '\\t\\taa' }, { 2, 0 })\n  validate_edit({ '\\taa', '\\t\\tbb' }, { 2, 0 }, { 'yy', 'k', 'gr_' }, { '\\tbb', '\\t\\tbb' }, { 1, 0 })\n\n  validate_edit({ '  aa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { '  aa', 'aa' }, { 2, 0 })\n  validate_edit({ '  aa', 'bb' }, { 2, 0 }, { 'yy', 'k', 'gr_' }, { '  bb', 'bb' }, { 1, 0 })\n  validate_edit({ '  aa', '    bb' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { '  aa', '    aa' }, { 2, 0 })\n  validate_edit({ '  aa', '    bb' }, { 2, 0 }, { 'yy', 'k', 'gr_' }, { '  bb', '    bb' }, { 1, 0 })\n\n  -- Should replace current region indent with new one\n  validate_edit(\n    { '\\taa', '\\t\\tbb', 'cc' },\n    { 1, 0 },\n    { 'yj', 'G', 'gr_' },\n    { '\\taa', '\\t\\tbb', 'aa', '\\tbb' },\n    { 3, 0 }\n  )\n\n  -- Should preserve tabs vs spaces\n  validate_edit({ '\\taa', '  bb' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { '\\taa', '  aa' }, { 2, 2 })\n  validate_edit({ '\\taa', '  bb' }, { 2, 0 }, { 'yy', 'k', 'gr_' }, { '\\tbb', '  bb' }, { 1, 0 })\n\n  -- Should correctly work in presence of blank lines (compute indent and not\n  -- reindent them)\n  validate_edit(\n    { '\\t\\taa', '', '\\t', '\\tcc' },\n    { 1, 0 },\n    { 'y2j', 'G', 'gr_' },\n    { '\\t\\taa', '', '\\t', '\\taa', '', '\\t' },\n    { 4, 0 }\n  )\n\n  -- Should correctly work replacing **only** blank lines\n  validate_edit({ 'aa', '\\t\\t', '\\t' }, { 1, 0 }, { 'yy', 'j', 'grj' }, { 'aa', '\\taa' }, { 2, 0 })\nend\n\nT['Replace']['works blockwise in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'io', function() vim.cmd('normal! \\22') end)]])\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n\n  validate_edit({ 'a b c', 'a b c' }, { 1, 0 }, { 'y<C-v>j', 'w', 'grie' }, { 'a a c', 'a a c' }, { 1, 2 })\n\n  -- With dot-repeat\n  validate_edit({ 'a b c', 'a b c' }, { 1, 0 }, { 'y<C-v>j', 'w', 'grie', 'w', '.' }, { 'a a a', 'a a a' }, { 1, 4 })\n\n  -- Single cell\n  validate_edit1d('aa bb', 0, { '<C-v>y', 'w', 'grio' }, 'aa ab', 3)\nend\n\nT['Replace']['works with mixed submodes in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n\n  -- Charwise paste - Linewise region\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'yiw', 'j', 'gr_' }, { 'aa', 'aa', 'cc' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'y/b$<CR>', 'j', 'gr_' }, { 'aa', 'aa', 'b', 'cc' }, { 2, 0 })\n\n  -- Charwise paste - Blockwise region\n  validate_edit({ 'aa', 'bc', 'de' }, { 1, 0 }, { 'yiw', 'j', 'grie' }, { 'aa', 'aac', 'e' }, { 2, 0 })\n  validate_edit({ 'aa', 'bc', 'de' }, { 1, 0 }, { 'y/c<CR>', 'j', 'grie' }, { 'aa', 'aac', 'b e' }, { 2, 0 })\n\n  -- Linewise paste - Charwise region\n  validate_edit({ 'aa', 'bb bb' }, { 1, 0 }, { 'yy', 'j', 'griw' }, { 'aa', 'aa bb' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc cc' }, { 1, 0 }, { 'yj', '2j', 'griw' }, { 'aa', 'bb', 'aa', 'bb cc' }, { 3, 0 })\n\n  -- Linewise paste - Blockwise region\n  validate_edit({ 'aa', 'bc', 'de' }, { 1, 0 }, { 'yy', 'j', 'grie' }, { 'aa', 'aac', 'e' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cd', 'ef' }, { 1, 0 }, { 'yj', '2j', 'grie' }, { 'aa', 'bb', 'aad', 'bbf' }, { 3, 0 })\n\n  -- Blockwise paste - Charwise region\n  validate_edit({ 'aa', 'bb bb' }, { 1, 0 }, { '<C-v>y', 'j', 'griw' }, { 'aa', 'a bb' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb bb' }, { 1, 0 }, { 'y<C-v>j', 'j', 'griw' }, { 'aa', 'a', 'b bb' }, { 2, 0 })\n\n  -- Blockwise paste - Linewise region\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { '<C-v>y', 'j', 'gr_' }, { 'aa', 'a', 'cc' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'y<C-v>j', 'j', 'gr_' }, { 'aa', 'a', 'b', 'cc' }, { 2, 0 })\nend\n\nT['Replace']['works with two types of `[count]` in Normal mode'] = function()\n  -- First `[count]` for paste with dot-repeat\n  validate_edit1d('aa bb cc dd', 0, { 'yiw', 'w', '2graW' }, 'aa aaaacc dd', 3)\n  validate_edit1d('aa bb cc dd', 0, { 'yiw', 'w', '2graW', 'w', '.' }, 'aa aaaaccaaaa', 9)\n\n  -- Second `[count]` for textobject with dot-repeat\n  validate_edit1d('aa bb cc dd ee', 0, { 'yiw', 'w', 'gr2aW' }, 'aa aadd ee', 3)\n  validate_edit1d('aa bb cc dd ee', 0, { 'yiw', 'w', 'gr2aW', '.' }, 'aaaa', 2)\n\n  -- Both `[count]`s with dot-repeat\n  validate_edit1d('aa bb cc dd ee', 0, { 'yiw', 'w', '2gr2aW' }, 'aa aaaadd ee', 3)\n  validate_edit1d('aa bb cc dd ee', 0, { 'yiw', 'w', '2gr2aW', '.' }, 'aaaaaa', 2)\nend\n\nT['Replace']['works with `cmdheight=0`'] = function()\n  child.set_size(7, 20)\n  child.o.cmdheight = 0\n  child.o.statusline = 'My statusline'\n  -- Force quick test for regular `gr` operator\n  child.api.nvim_del_keymap('n', 'grr')\n\n  set_lines({ 'aa bb' })\n  type_keys('yiw', 'w')\n  type_keys('gr')\n  child.expect_screenshot({ redraw = false })\n  type_keys('iw')\n  child.expect_screenshot({ redraw = false })\nend\n\nT['Replace']['works in Normal mode for line'] = function()\n  validate_edit({ 'aa', 'bb' }, { 1, 1 }, { 'yy', 'j', 'grr' }, { 'aa', 'aa' }, { 2, 0 })\n\n  -- With dot-repeat\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 1 }, { 'yy', 'j', 'grr', 'j', '.' }, { 'aa', 'aa', 'aa' }, { 3, 0 })\nend\n\nT['Replace']['works with `[count]` in Normal mode for line'] = function()\n  validate_edit({ 'aa', 'bb' }, { 1, 1 }, { 'yy', 'j', '2grr' }, { 'aa', 'aa', 'aa' }, { 2, 0 })\n\n  -- With dot-repeat\n  validate_edit(\n    { 'aa', 'bb', 'cc' },\n    { 1, 1 },\n    { 'yy', 'j', '2grr', '2j', '.' },\n    { 'aa', 'aa', 'aa', 'aa', 'aa' },\n    { 4, 0 }\n  )\nend\n\nT['Replace']['works with empty textobject/motion'] = function()\n  child.api.nvim_set_keymap('o', 'w', '<Cmd><CR>', {})\n  set_lines({ 'xxx', 'yyy' })\n  set_cursor(1, 1)\n  type_keys('yiw', 'jl')\n  type_keys('gr', 'w')\n  eq(get_lines(), { 'xxx', 'yyy' })\nend\n\nT['Replace']['works in Visual mode'] = function()\n  -- Charwise selection\n  validate_edit({ 'aa bb' }, { 1, 0 }, { 'yiw', 'w', 'viw', 'gr' }, { 'aa aa' }, { 1, 3 })\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'viw', 'gr' }, { 'aa', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'y<C-v>j', 'viw', 'gr' }, { 'a', 'b', 'bb' }, { 1, 0 })\n\n  -- Linewise selection\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'yiw', 'j', 'V', 'gr' }, { 'aa', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'V', 'gr' }, { 'aa', 'aa' }, { 2, 0 })\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'y<C-v>j', 'j', 'V', 'gr' }, { 'aa', 'a', 'b' }, { 2, 0 })\n\n  -- Blockwise selection\n  validate_edit({ 'a b', 'a b' }, { 1, 0 }, { 'yiw', 'w', '<C-v>j', 'gr' }, { 'a a', 'a ' }, { 1, 2 })\n  validate_edit({ 'a b', 'a b' }, { 1, 0 }, { 'yy', 'w', '<C-v>j', 'gr' }, { 'a a b', 'a ' }, { 1, 2 })\n  validate_edit({ 'a b', 'a b' }, { 1, 0 }, { 'y<C-v>j', 'w', '<C-v>j', 'gr' }, { 'a a', 'a a' }, { 1, 2 })\nend\n\nT['Replace']['works with newline in region'] = function()\n  validate_edit({ 'a(', '  b', ')' }, { 2, 2 }, { 'vky', 'gvgr' }, { 'a(', '  b', ')' }, { 1, 1 })\n\n  -- Doesn't 100% work with trailing newline due to Neovim limitations\n  -- See https://github.com/neovim/neovim/issues/37664\nend\n\nT['Replace']['works with different `virtualedit`'] = function()\n  local validate = function()\n    -- Charwise\n    validate_edit1d('aa bb cc', 3, { 'yiw', 'b', 'gr', 'iw' }, 'bb bb cc', 0)\n    validate_edit1d('aa bb cc', 0, { 'yiw', 'w', 'gr', 'iw' }, 'aa aa cc', 3)\n    validate_edit1d('aa bb cc', 0, { 'yiw', '2w', 'gr', 'iw' }, 'aa bb aa', 6)\n\n    validate_edit1d('aa bb cc', 3, { 'yiw', 'b', 'viw', 'gr' }, 'bb bb cc', 0)\n    validate_edit1d('aa bb cc', 0, { 'yiw', 'w', 'viw', 'gr' }, 'aa aa cc', 3)\n    validate_edit1d('aa bb cc', 0, { 'yiw', '2w', 'viw', 'gr' }, 'aa bb aa', 6)\n\n    -- Linewise\n    validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'yy', 'j', 'grr' }, { 'aa', 'aa', 'cc' }, { 2, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { 'yy', 'j', 'grr' }, { 'aa', 'bb', 'bb' }, { 3, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'yy', 'k', 'grr' }, { 'aa', 'cc', 'cc' }, { 2, 0 })\n\n    validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'yy', 'j', 'V', 'gr' }, { 'aa', 'aa', 'cc' }, { 2, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 2, 0 }, { 'yy', 'j', 'V', 'gr' }, { 'aa', 'bb', 'bb' }, { 3, 0 })\n    validate_edit({ 'aa', 'bb', 'cc' }, { 3, 0 }, { 'yy', 'k', 'V', 'gr' }, { 'aa', 'cc', 'cc' }, { 2, 0 })\n\n    -- Blockwise\n    child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n    validate_edit({ 'abc', 'def' }, { 1, 0 }, { 'y', 'ie', 'l', 'gr', 'ie' }, { 'aac', 'ddf' }, { 1, 1 })\n    validate_edit({ 'abc', 'def' }, { 1, 1 }, { 'y', 'ie', 'l', 'gr', 'ie' }, { 'abb', 'dee' }, { 1, 2 })\n    validate_edit({ 'abc', 'def' }, { 1, 2 }, { 'y', 'ie', 'h', 'gr', 'ie' }, { 'acc', 'dff' }, { 1, 1 })\n\n    validate_edit({ 'abc', 'def' }, { 1, 0 }, { 'y', 'ie', 'l', '<C-v>j', 'gr' }, { 'aac', 'ddf' }, { 1, 1 })\n    validate_edit({ 'abc', 'def' }, { 1, 1 }, { 'y', 'ie', 'l', '<C-v>j', 'gr' }, { 'abb', 'dee' }, { 1, 2 })\n    validate_edit({ 'abc', 'def' }, { 1, 2 }, { 'y', 'ie', 'h', '<C-v>j', 'gr' }, { 'acc', 'dff' }, { 1, 1 })\n  end\n\n  child.o.virtualedit = 'all'\n  validate()\n  child.o.virtualedit = 'onemore'\n  validate()\n  child.o.virtualedit = 'block'\n  validate()\nend\n\nT['Replace']['correctly reindents linewise in Visual mode'] = function()\n  -- Should use indent from text being replaced\n  validate_edit({ '\\taa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'V', 'gr' }, { '\\taa', 'aa' }, { 2, 0 })\n  validate_edit({ '\\taa', 'bb' }, { 2, 0 }, { 'yy', 'k', 'V', 'gr' }, { '\\tbb', 'bb' }, { 1, 0 })\n  validate_edit({ '  aa', '    bb' }, { 1, 0 }, { 'yy', 'j', 'V', 'gr' }, { '  aa', '    aa' }, { 2, 0 })\n  validate_edit({ '  aa', '    bb' }, { 2, 0 }, { 'yy', 'k', 'V', 'gr' }, { '  bb', '    bb' }, { 1, 0 })\n\n  -- Should replace current region indent with new one\n  validate_edit(\n    { '\\taa', '\\t\\tbb', 'cc' },\n    { 1, 0 },\n    { 'yj', 'G', 'V', 'gr' },\n    { '\\taa', '\\t\\tbb', 'aa', '\\tbb' },\n    { 3, 0 }\n  )\n\n  -- Should preserve tabs vs spaces\n  validate_edit({ '\\taa', '  bb' }, { 1, 0 }, { 'yy', 'j', 'V', 'gr' }, { '\\taa', '  aa' }, { 2, 0 })\n  validate_edit({ '\\taa', '  bb' }, { 2, 0 }, { 'yy', 'k', 'V', 'gr' }, { '\\tbb', '  bb' }, { 1, 0 })\n\n  -- Should correctly work in presence of blank lines (compute indent and not\n  -- reindent them)\n  validate_edit(\n    { '\\t\\taa', '', '\\t', '\\tcc' },\n    { 1, 0 },\n    { 'y2j', 'G', 'V', 'gr' },\n    { '\\t\\taa', '', '\\t', '\\taa', '', '\\t' },\n    { 4, 0 }\n  )\n\n  -- Should correctly work replacing **only** blank lines\n  validate_edit({ 'aa', '\\t\\t', '\\t' }, { 1, 0 }, { 'yy', 'j', 'Vj', 'gr' }, { 'aa', '\\taa' }, { 2, 0 })\nend\n\nT['Replace']['works with `[count]` in Visual mode'] = function()\n  validate_edit1d('aa bb', 0, { 'yiw', 'w', 'viw', '2gr' }, 'aa aaaa', 3)\nend\n\nT['Replace']['respects `config.replace.reindent_linewise`'] = function()\n  child.lua('MiniOperators.config.replace.reindent_linewise = false')\n  validate_edit({ '\\taa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { '\\taa', '\\taa' }, { 2, 0 })\nend\n\nT['Replace']['works with `[register]`'] = function()\n  -- Normal mode\n  validate_edit1d('aa bb cc', 0, { '\"xyiw', 'w', 'yiw', 'w', '\"xgriw' }, 'aa bb aa', 6)\n\n  -- Visual mode\n  validate_edit1d('aa bb cc', 0, { '\"xyiw', 'w', 'yiw', 'w', 'viw', '\"xgr' }, 'aa bb aa', 6)\n\n  -- Readonly registers\n  child.o.cmdheight = 15\n  set_lines({ 'aaa' })\n  type_keys('\"xyy')\n\n  -- - Empty yet valid registers (as they were not written yet)\n  expect.error(function() type_keys('\"%griw') end, 'Register \"%%\" is empty')\n  expect.error(function() type_keys('\".griw') end, 'Register \"%.\" is empty')\n  expect.error(function() type_keys('\":griw') end, 'Register \"%:\" is empty')\n\n  child.api.nvim_buf_set_name(0, 'xxx')\n  type_keys('\"%griw')\n  eq(get_lines(), { 'xxx' })\n\n  type_keys('o', 'bbb', '<Esc>', 'k')\n  type_keys('\".griw')\n  eq(get_lines(), { 'bbb', 'bbb' })\n\n  type_keys(':lua print(1)', '<CR>')\n  type_keys('\":griw')\n  eq(get_lines(), { 'lua print(1)', 'bbb' })\n\n  -- Special registers\n  -- - Temporary register used in the implementation\n  type_keys('\"xgriw')\n  eq(get_lines(), { 'aaa print(1)', 'bbb' })\n\n  -- - Alternate file\n  expect.error(function() type_keys('\"#griw') end, 'Register \"#\" is empty')\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false))\n  set_lines({ 'yyy' })\n  type_keys('\"#griw')\n  eq(get_lines(), { 'xxx' })\n\n  -- - Expression register\n  type_keys('\"=', '1+1<CR>', 'griw')\n  eq(get_lines(), { '2' })\n\n  -- - Black hole\n  type_keys('\"_griw')\n  eq(get_lines(), { '' })\n\n  -- Should all work with linewise operator\n  set_lines({ 'uuu', 'vvv' })\n  set_cursor(1, 0)\n  type_keys('\"#grr')\n  eq(get_lines(), { 'xxx', 'vvv' })\n  type_keys('\"=', '[\"a\"]<CR>', 'grr')\n  eq(get_lines(), { 'a', 'vvv' })\n\n  child.cmd('b#')\n  set_cursor(1, 0)\n  type_keys('\"%grr')\n  eq(get_lines(), { 'xxx', 'bbb' })\n  type_keys('\".grr')\n  eq(get_lines(), { 'bbb', 'bbb' })\n  type_keys('\":grr')\n  eq(get_lines(), { 'lua print(1)', 'bbb' })\nend\n\nT['Replace']['propagates informative error about `[register]` content'] = function()\n  child.o.cmdheight = 15\n  set_lines({ 'aa bb' })\n  type_keys('yiw', 'w')\n\n  expect.error(function() type_keys('\"agriw') end, 'Register \"a\" is empty')\n  expect.error(function() type_keys('\"Agriw') end, 'Register \"A\" is invalid')\nend\n\nT['Replace']['works in edge cases'] = function()\n  -- Start of line\n  validate_edit1d('aa bb', 3, { 'yiw', '0', 'griw' }, 'bb bb', 0)\n\n  -- End of line\n  validate_edit1d('aa bb', 0, { 'yiw', 'w', 'griw' }, 'aa aa', 3)\n\n  -- First line\n  validate_edit({ 'aa', 'bb' }, { 2, 0 }, { 'yy', 'k', 'grr' }, { 'bb', 'bb' }, { 1, 0 })\n\n  -- Last line\n  validate_edit({ 'aa', 'bb', 'cc' }, { 1, 0 }, { 'yy', 'G', 'grr' }, { 'aa', 'bb', 'aa' }, { 3, 0 })\nend\n\nT['Replace']['can replace whole buffer'] = function()\n  set_lines({ 'aa', 'bb' })\n  type_keys('yip')\n\n  set_lines({ 'cc', 'dd' })\n  type_keys('grip')\n  eq(get_lines(), { 'aa', 'bb' })\nend\n\nT['Replace']['does not have side effects'] = function()\n  set_lines({ 'aa', 'bb', 'cc', 'xy' })\n\n  -- All non-operator related marks, target and temporary register\n  set_cursor(4, 0)\n  type_keys('ma')\n  type_keys('v\"xy')\n\n  set_cursor(4, 1)\n  type_keys('mx')\n  type_keys('vy')\n\n  -- Do replace\n  set_cursor(1, 0)\n  type_keys('yiw')\n  local target_register_info = child.fn.getreginfo('\"')\n  local temp_register_info = child.fn.getreginfo('x')\n  set_cursor(2, 0)\n  type_keys('grj')\n\n  -- Validate\n  eq(get_lines(), { 'aa', 'aa', 'xy' })\n  eq(child.api.nvim_buf_get_mark(0, 'a'), { 3, 0 })\n  eq(child.api.nvim_buf_get_mark(0, 'x'), { 3, 1 })\n  eq(child.fn.getreginfo('\"'), target_register_info)\n  eq(child.fn.getreginfo('x'), temp_register_info)\nend\n\nT['Replace']['preserves visual marks'] = function()\n  set_lines({ 'aa', 'bb', 'cc', 'select' })\n\n  -- Create marks\n  set_cursor(4, 0)\n  type_keys('viw', '<Esc>')\n\n  -- Replace\n  set_cursor(1, 0)\n  type_keys('yy', 'j', 'grj')\n  eq(get_lines(), { 'aa', 'aa', 'select' })\n  eq(child.api.nvim_buf_get_mark(0, '<'), { 3, 0 })\n  eq(child.api.nvim_buf_get_mark(0, '>'), { 3, 5 })\nend\n\nT['Replace']['respects `config.replace.prefix`'] = function()\n  child.api.nvim_del_keymap('n', 'gr')\n  child.api.nvim_del_keymap('n', 'grr')\n  child.api.nvim_del_keymap('x', 'gr')\n\n  load_module({ replace = { prefix = 'gR' } })\n\n  validate_edit1d('aa bb', 0, { 'yiw', 'w', 'gRiw' }, 'aa aa', 3)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'gRR' }, { 'aa', 'aa' }, { 2, 0 })\n  validate_edit1d('aa bb', 0, { 'yiw', 'w', 'viw', 'gR' }, 'aa aa', 3)\nend\n\nT['Replace']['works with `make_mappings()`'] = function()\n  child.api.nvim_del_keymap('n', 'gr')\n  child.api.nvim_del_keymap('n', 'grr')\n  child.api.nvim_del_keymap('x', 'gr')\n\n  load_module({ replace = { prefix = '' } })\n  make_mappings('replace', { textobject = 'gR', line = 'gRr', selection = 'gR' })\n\n  validate_edit1d('aa bb', 0, { 'yiw', 'w', 'gRiw' }, 'aa aa', 3)\n  validate_edit({ 'aa', 'bb' }, { 1, 0 }, { 'yy', 'j', 'gRr' }, { 'aa', 'aa' }, { 2, 0 })\n  validate_edit1d('aa bb', 0, { 'yiw', 'w', 'viw', 'gR' }, 'aa aa', 3)\nend\n\nT['Replace']['respects `selection=exclusive`'] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n  child.o.selection = 'exclusive'\n\n  validate_edit1d('aaa bbb x', 0, { 'yiw', 'w', 'griw' }, 'aaa aaa x', 4)\n  validate_edit({ 'aa', 'bb', 'x' }, { 1, 0 }, { 'yy', 'j', 'gr_' }, { 'aa', 'aa', 'x' }, { 2, 0 })\n  validate_edit({ 'a b c', 'a b c' }, { 1, 0 }, { 'y<C-v>j', 'w', 'grie' }, { 'a a c', 'a a c' }, { 1, 2 })\n\n  validate_edit1d('aaa bbb x', 0, { 'yiw', 'w', 'viw', 'gr' }, 'aaa aaa x', 4)\n  validate_edit({ 'aa', 'bb', 'x' }, { 1, 0 }, { 'yy', 'j', 'V', 'gr' }, { 'aa', 'aa', 'x' }, { 2, 0 })\n  validate_edit({ 'a b c', 'a b c' }, { 1, 0 }, { 'y<C-v>j', 'w', '<C-v>j', 'gr' }, { 'a a c', 'a a c' }, { 1, 2 })\nend\n\nT['Replace'][\"respects 'nomodifiable'\"] = function()\n  set_lines({ 'aa bb' })\n  set_cursor(1, 0)\n  child.bo.modifiable = false\n  type_keys('yiw', 'w', 'gr$')\n  eq(get_lines(), { 'aa bb' })\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['Replace']['does not trigger `TextYankPost` event'] = function()\n  set_lines({ 'aa' })\n  type_keys('yiw')\n\n  child.cmd('au TextYankPost * lua _G.been_here = true')\n  -- Should also not block other events, like ModeChanged\n  child.cmd('au ModeChanged * lua _G.n = (_G.n or 0) + 1')\n\n  validate_edit1d('bb', 0, { 'griw' }, 'aa', 0)\n\n  eq(child.lua_get('_G.been_here'), vim.NIL)\n  eq(child.lua_get('_G.n') >= 5, true)\n  eq(child.o.eventignore, '')\nend\n\nT['Replace']['respects `vim.{g,b}.minioperators_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minioperators_disable = true\n    validate_edit1d('aa bb', 0, { 'yiw', 'w', 'griw' }, 'aa wbb', 4)\n  end,\n})\n\nT['Replace']['respects `vim.b.minioperators_config`'] = function()\n  child.b.minioperators_config = { replace = { reindent_linewise = false } }\n\n  validate_edit(\n    { '\\taa', '\\tbb', 'cc', 'dd' },\n    { 2, 0 },\n    { 'yy', 'G', 'gr_' },\n    { '\\taa', '\\tbb', 'cc', '\\tbb' },\n    { 4, 0 }\n  )\nend\n\nT['Sort'] = new_set()\n\n-- More testing is done in `default_sort_func()` tests\n\nT['Sort']['works charwise in Normal mode'] = function()\n  validate_edit1d('c, a, b', 0, { 'gs$' }, 'a, b, c', 0)\n\n  -- With dot-repeat\n  validate_edit1d('(b, a) (d, c)', 0, { 'gsi)', 'f(', '.' }, '(a, b) (c, d)', 8)\n\n  -- Over several lines\n  set_lines({ 'b, a', 'd, cx' })\n\n  -- - Set mark\n  set_cursor(2, 4)\n  type_keys('ma')\n\n  -- - Validate\n  set_cursor(1, 0)\n  type_keys('gs`a')\n  eq(get_lines(), { 'a', 'd, b, cx' })\n  eq(get_cursor(), { 1, 0 })\n\n  -- Already sorted\n  validate_edit1d('a, b, c', 0, { 'gs$' }, 'a, b, c', 0)\n\n  -- Correctly picks split pattern\n  validate_edit1d('b, a; c', 0, { 'gs$' }, 'a; c, b', 0)\n  validate_edit1d('b a c', 0, { 'gs$' }, 'a b c', 0)\n  validate_edit1d('bac', 0, { 'gs$' }, 'abc', 0)\n\n  -- Works with empty parts\n  validate_edit1d('a,,b,', 0, { 'gs$' }, ',,a,b', 0)\n\n  -- Preserves whitespace\n  validate_edit1d('e ,  d,   b    ,a,c', 0, { 'gs$' }, 'a ,  b,   c    ,d,e', 0)\nend\n\nT['Sort']['works linewise in Normal mode'] = function()\n  validate_edit({ 'cc', 'bb', 'aa' }, { 1, 0 }, { 'gsip' }, { 'aa', 'bb', 'cc' }, { 1, 0 })\n  validate_edit({ 'xc', 'xb', 'xa' }, { 1, 0 }, { 'gsip' }, { 'xa', 'xb', 'xc' }, { 1, 0 })\n\n  -- - With dot-repeat\n  validate_edit({ 'd', 'c', '', 'b', 'a' }, { 1, 0 }, { 'gsip', 'G', '.' }, { 'c', 'd', '', 'a', 'b' }, { 4, 0 })\nend\n\nT['Sort']['works blockwise in Normal mode'] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22j') end)]])\n  child.lua([[vim.keymap.set('o', 'il', function() vim.cmd('normal! \\22jl') end)]])\n\n  validate_edit({ 'cb', 'ba', 'ac' }, { 1, 1 }, { 'gsie' }, { 'ca', 'bb', 'ac' }, { 1, 1 })\n  validate_edit({ 'cxb', 'bxa', 'axc' }, { 1, 1 }, { 'gsil' }, { 'cxa', 'bxb', 'axc' }, { 1, 1 })\n\n  -- With dot-repeat\n  validate_edit({ 'cbt', 'bar', 'acs' }, { 1, 1 }, { 'gsie', 'l', '.' }, { 'car', 'bbt', 'acs' }, { 1, 2 })\nend\n\nT['Sort']['works in Normal mode for line'] = function()\n  -- Should apply charwise sort on non-blank part of line\n  validate_edit1d('c, a, b', 0, { 'gss' }, 'a, b, c', 0)\n  validate_edit1d('c; a; b', 0, { 'gss' }, 'a; b; c', 0)\n  validate_edit1d('c a b', 0, { 'gss' }, 'a b c', 0)\n\n  validate_edit({ 't, r, s', 'c, a, b' }, { 1, 0 }, { 'gss' }, { 'r, s, t', 'c, a, b' }, { 1, 0 })\n\n  validate_edit1d('c, a, b', 3, { 'gss' }, 'a, b, c', 0)\n  validate_edit1d('  c, a, b  ', 0, { 'gss' }, '  a, b, c  ', 2)\n\n  validate_edit1d('  c a b  ', 0, { 'gss' }, '  a b c  ', 2)\n\n  -- With dot-repeat\n  validate_edit({ 't, r, s', 'c, a, b' }, { 1, 0 }, { 'gss', 'j', '.' }, { 'r, s, t', 'a, b, c' }, { 2, 0 })\nend\n\nT['Sort']['works with empty textobject/motion'] = function()\n  child.api.nvim_set_keymap('o', 'w', '<Cmd><CR>', {})\n  set_lines({ 'fedcba' })\n  set_cursor(1, 1)\n  type_keys('gs', 'w')\n  eq(get_lines(), { 'fedcba' })\nend\n\nT['Sort']['works in Visual mode'] = function()\n  -- Charwise region\n  validate_edit1d('c, a, b', 0, { 'v$', 'gs' }, 'a, b, c', 0)\n  validate_edit1d('(s, r), a', 0, { 'vi)', 'gs' }, '(r, s), a', 1)\n\n  -- Linewise region\n  validate_edit({ 'cc', 'aa', 'bb' }, { 1, 0 }, { 'vip', 'gs' }, { 'aa', 'bb', 'cc' }, { 1, 0 })\n  validate_edit({ 'ss', 'rr', '', 'aa' }, { 1, 0 }, { 'vip', 'gs' }, { 'rr', 'ss', '', 'aa' }, { 1, 0 })\n\n  -- Blockwise region\n  validate_edit({ 'cbx', 'bax', 'acx' }, { 1, 1 }, { '<C-v>2j', 'gs' }, { 'cax', 'bbx', 'acx' }, { 1, 1 })\n  validate_edit({ 'cxb', 'bxa', 'axc' }, { 1, 1 }, { '<C-v>jl', 'gs' }, { 'cxa', 'bxb', 'axc' }, { 1, 1 })\nend\n\nT['Sort']['works with different `virtualedit`'] = function()\n  local validate = function()\n    -- Charwise\n    validate_edit1d('cc bb aa', 0, { 'gs', '2e' }, 'bb cc aa', 0)\n    validate_edit1d('cc bb aa', 3, { 'gs', '2e' }, 'cc aa bb', 3)\n    validate_edit1d('cc bb aa', 0, { 'gs', '3e' }, 'aa bb cc', 0)\n\n    validate_edit1d('cc bb aa', 0, { 'v2e', 'gs' }, 'bb cc aa', 0)\n    validate_edit1d('cc bb aa', 3, { 'v2e', 'gs' }, 'cc aa bb', 3)\n    validate_edit1d('cc bb aa', 0, { 'v3e', 'gs' }, 'aa bb cc', 0)\n\n    -- Linewise\n    validate_edit({ 'cc', 'bb', 'aa' }, { 1, 0 }, { 'gs', 'j' }, { 'bb', 'cc', 'aa' }, { 1, 0 })\n    validate_edit({ 'cc', 'bb', 'aa' }, { 2, 0 }, { 'gs', 'j' }, { 'cc', 'aa', 'bb' }, { 2, 0 })\n    validate_edit({ 'cc', 'bb', 'aa' }, { 1, 0 }, { 'gs', '2j' }, { 'aa', 'bb', 'cc' }, { 1, 0 })\n\n    validate_edit({ 'cc', 'bb', 'aa' }, { 1, 0 }, { 'Vj', 'gs' }, { 'bb', 'cc', 'aa' }, { 1, 0 })\n    validate_edit({ 'cc', 'bb', 'aa' }, { 2, 0 }, { 'Vj', 'gs' }, { 'cc', 'aa', 'bb' }, { 2, 0 })\n    validate_edit({ 'cc', 'bb', 'aa' }, { 1, 0 }, { 'V2j', 'gs' }, { 'aa', 'bb', 'cc' }, { 1, 0 })\n\n    -- Blockwise\n    child.lua([[vim.keymap.set('o', 'iE', function() vim.cmd('normal! \\22jj') end)]])\n    validate_edit({ 'cba', 'bac', 'acb' }, { 1, 0 }, { 'gs', 'iE' }, { 'aba', 'bac', 'ccb' }, { 1, 0 })\n    validate_edit({ 'cba', 'bac', 'acb' }, { 1, 1 }, { 'gs', 'iE' }, { 'caa', 'bbc', 'acb' }, { 1, 1 })\n    validate_edit({ 'cba', 'bac', 'acb' }, { 1, 2 }, { 'gs', 'iE' }, { 'cba', 'bab', 'acc' }, { 1, 2 })\n\n    validate_edit({ 'cba', 'bac', 'acb' }, { 1, 0 }, { '<C-v>jj', 'gs' }, { 'aba', 'bac', 'ccb' }, { 1, 0 })\n    validate_edit({ 'cba', 'bac', 'acb' }, { 1, 1 }, { '<C-v>jj', 'gs' }, { 'caa', 'bbc', 'acb' }, { 1, 1 })\n    validate_edit({ 'cba', 'bac', 'acb' }, { 1, 2 }, { '<C-v>jj', 'gs' }, { 'cba', 'bab', 'acc' }, { 1, 2 })\n  end\n\n  child.o.virtualedit = 'all'\n  validate()\n  child.o.virtualedit = 'onemore'\n  validate()\n  child.o.virtualedit = 'block'\n  validate()\nend\n\nT['Sort']['respects `config.sort.func`'] = function()\n  -- Compare by the second character\n  child.lua([[MiniOperators.config.sort.func = function(content)\n    local compare_second = function(a, b) return a:sub(2, 2) < b:sub(2, 2) end\n    return MiniOperators.default_sort_func(content, { compare_fun = compare_second })\n  end\n  ]])\n\n  validate_edit({ 'ab', 'ba' }, { 1, 0 }, { 'gsip' }, { 'ba', 'ab' }, { 1, 0 })\nend\n\nT['Sort'][\"works with 'y' in 'cpoptions'\"] = function()\n  child.cmd('set cpoptions+=y')\n\n  -- Dot-repeat should still work\n  validate_edit1d('(b, a) (d, c)', 0, { 'gsi)', 'f(', '.' }, '(a, b) (c, d)', 8)\nend\n\nT['Sort']['does not have side effects'] = function()\n  set_lines({ 'bb', 'aa', 'xy' })\n\n  -- All non-operator related marks and registers 'x', '\"'\n  set_cursor(3, 0)\n  type_keys('ma')\n  type_keys('v\"xy')\n\n  set_cursor(3, 1)\n  type_keys('mx')\n  type_keys('vy')\n\n  -- Do sort\n  set_cursor(1, 0)\n  type_keys('gsj')\n\n  -- Validate\n  eq(child.api.nvim_buf_get_mark(0, 'a'), { 3, 0 })\n  eq(child.api.nvim_buf_get_mark(0, 'x'), { 3, 1 })\n  eq(child.fn.getreg('x'), 'x')\n  eq(child.fn.getreg('\"'), 'y')\nend\n\nT['Sort']['preserves visual marks'] = function()\n  set_lines({ 'cc', 'aa', 'bb', 'select' })\n\n  -- Create marks\n  set_cursor(4, 0)\n  type_keys('viw', '<Esc>')\n\n  -- Sort\n  set_cursor(1, 0)\n  type_keys('gs2j')\n  eq(get_lines(), { 'aa', 'bb', 'cc', 'select' })\n  eq(child.api.nvim_buf_get_mark(0, '<'), { 4, 0 })\n  eq(child.api.nvim_buf_get_mark(0, '>'), { 4, 5 })\nend\n\nT['Sort']['respects `config.sort.prefix`'] = function()\n  child.api.nvim_del_keymap('n', 'gs')\n  child.api.nvim_del_keymap('n', 'gss')\n  child.api.nvim_del_keymap('x', 'gs')\n\n  load_module({ sort = { prefix = 'cs' } })\n\n  validate_edit1d('c, a, b', 0, { 'cs$' }, 'a, b, c', 0)\n  validate_edit1d('  c, a, b  ', 0, { 'css' }, '  a, b, c  ', 2)\n  validate_edit1d('(c, a, b)', 0, { 'vi)', 'cs' }, '(a, b, c)', 1)\nend\n\nT['Sort']['works with `make_mappings()`'] = function()\n  child.api.nvim_del_keymap('n', 'gs')\n  child.api.nvim_del_keymap('n', 'gss')\n  child.api.nvim_del_keymap('x', 'gs')\n\n  load_module({ sort = { prefix = '' } })\n  make_mappings('sort', { textobject = 'cs', line = 'css', selection = 'cs' })\n\n  validate_edit1d('c, a, b', 0, { 'cs$' }, 'a, b, c', 0)\n  validate_edit1d('  c, a, b  ', 0, { 'css' }, '  a, b, c  ', 2)\n  validate_edit1d('(c, a, b)', 0, { 'vi)', 'cs' }, '(a, b, c)', 1)\nend\n\nT['Sort'][\"respects 'selection=exclusive'\"] = function()\n  child.lua([[vim.keymap.set('o', 'ie', function() vim.cmd('normal! \\22jll') end)]])\n  child.o.selection = 'exclusive'\n\n  validate_edit1d('(c, a, b)', 1, { 'gsi)' }, '(a, b, c)', 1)\n  validate_edit({ 'bb', 'aa' }, { 1, 0 }, { 'gsip' }, { 'aa', 'bb' }, { 1, 0 })\n  validate_edit({ 'xbax', 'yaby' }, { 1, 1 }, { 'gsie' }, { 'xabx', 'ybay' }, { 1, 1 })\n\n  validate_edit1d('(c, a, b)', 1, { 'vi)', 'gs' }, '(a, b, c)', 1)\n  validate_edit({ 'bb', 'aa' }, { 1, 0 }, { 'Vip', 'gs' }, { 'aa', 'bb' }, { 1, 0 })\n  validate_edit({ 'xbax', 'yaby' }, { 1, 1 }, { '<C-v>jll', 'gs' }, { 'xabx', 'ybay' }, { 1, 1 })\nend\n\nT['Sort'][\"respects 'nomodifiable'\"] = function()\n  set_lines({ 'b, a' })\n  set_cursor(1, 0)\n  child.bo.modifiable = false\n  type_keys('gs$')\n  eq(get_lines(), { 'b, a' })\n  eq(get_cursor(), { 1, 3 })\nend\n\nT['Sort']['does not trigger `TextYankPost` event'] = function()\n  child.cmd('au TextYankPost * lua _G.been_here = true')\n  -- Should also not block other events, like ModeChanged\n  child.cmd('au ModeChanged * lua _G.n = (_G.n or 0) + 1')\n\n  validate_edit1d('b, a', 0, { 'gs$' }, 'a, b', 0)\n\n  eq(child.lua_get('_G.been_here'), vim.NIL)\n  eq(child.lua_get('_G.n') >= 8, true)\n  eq(child.o.eventignore, '')\nend\n\nT['Sort']['respects `vim.{g,b}.minioperators_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minioperators_disable = true\n    validate_edit1d('b, a', 0, { 'gs$' }, 'b, a', 3)\n  end,\n})\n\nT['Sort']['respects `vim.b.minioperators_config`'] = function()\n  -- Compare by the second character\n  child.lua([[\n    _G.sort_by_second = function(content)\n      local compare_second = function(a, b) return a:sub(2, 2) < b:sub(2, 2) end\n      return MiniOperators.default_sort_func(content, { compare_fun = compare_second })\n    end\n    vim.b.minioperators_config = { sort = { func = _G.sort_by_second } }\n  ]])\n\n  validate_edit({ 'ab', 'ba' }, { 1, 0 }, { 'gsip' }, { 'ba', 'ab' }, { 1, 0 })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_pairs.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('pairs', config) end\nlocal unload_module = function() child.mini_unload('pairs') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Make helpers\nlocal get_term_channel = function()\n  local term_chans = vim.tbl_filter(function(x) return x.mode == 'terminal' end, child.api.nvim_list_chans())[1]['id']\n  return term_chans[1]['id']\nend\n\n-- Time constants\nlocal term_mode_wait = helpers.get_time_const(50)\n\n--- Make simple test on empty entity\n---@private\nlocal validate_action = function(mode, test)\n  mode = mode or 'i'\n\n  -- Expects to start in Normal mode\n  if mode == 'i' then\n    -- Setup\n    local lines, cursor = get_lines(), get_cursor()\n    set_lines({})\n    child.cmd('startinsert')\n\n    -- Test\n    test()\n\n    -- Cleanup\n    type_keys('<Esc>')\n    set_lines(lines)\n    set_cursor(unpack(cursor))\n  elseif mode == 'c' then\n    -- Setup\n    type_keys(':')\n\n    -- Test\n    test()\n\n    -- Cleanup\n    type_keys('<Esc>')\n  elseif mode == 't' then\n    helpers.skip_on_windows('Terminal emulator testing is not robust/easy on Windows')\n    helpers.skip_on_macos('Terminal emulator testing is not robust/easy on MacOS')\n\n    -- Setup\n    child.cmd('terminal! bash --noprofile --norc')\n    -- Wait for terminal to get active\n    sleep(term_mode_wait)\n    child.cmd('startinsert')\n\n    -- Test\n    test()\n\n    -- Cleanup\n    type_keys([[<C-\\>]], '<C-n>')\n    child.cmd('bwipeout!')\n  end\nend\n\n--- Validate that `key` on its own inserts `pair` (whatever it is: for smaller\n--- code, it might be single character to test in 'MiniPairs.close()').\n---@private\nlocal validate_open = function(mode, key, pair)\n  local test = ({\n    i = function()\n      type_keys(key)\n      eq(get_lines(), { pair })\n      eq(get_cursor(), { 1, 1 })\n    end,\n    c = function()\n      type_keys(key)\n      eq(child.fn.getcmdline(), pair)\n      eq(child.fn.getcmdpos(), 2)\n    end,\n    t = function()\n      -- Need to wait after each keystroke to allow shell to process it\n      local wait = 50\n      type_keys(wait, key)\n\n      local pair_pattern = vim.pesc(pair) .. '$'\n      expect.match(get_lines()[1], pair_pattern)\n    end,\n  })[mode]\n\n  validate_action(mode, test)\nend\n\n--- Validate that `key` jumps over right hand side of `pair` if it is next.\n---@private\nlocal validate_close = function(mode, key, pair)\n  local test = ({\n    i = function()\n      set_lines({ pair })\n      set_cursor(1, 1)\n      type_keys(key)\n      eq(get_lines(), { pair })\n      eq(get_cursor(), { 1, 2 })\n    end,\n    c = function()\n      type_keys('<C-v>', pair:sub(1, 1), '<C-v>', pair:sub(2, 2), '<Left>')\n      type_keys(key)\n      eq(child.fn.getcmdline(), pair)\n      eq(child.fn.getcmdpos(), 3)\n    end,\n    t = function()\n      local term_channel = get_term_channel()\n\n      -- Jumps over right hand side of `pair` if it is next\n      child.fn.chansend(term_channel, pair)\n      -- Need to wait after each keystroke to allow shell to process it\n      sleep(term_mode_wait)\n      type_keys(term_mode_wait, '<Left>')\n      type_keys(term_mode_wait, key)\n\n      local pair_pattern = vim.pesc(pair) .. '$'\n      expect.match(get_lines()[1], pair_pattern)\n    end,\n  })[mode]\n\n  validate_action(mode, test)\nend\n\n--- Validate that `<BS>` deletes whole pair if inside of it.\n---@private\nlocal validate_bs = function(mode, pair)\n  local test = ({\n    i = function()\n      set_lines({ pair })\n      set_cursor(1, 1)\n      type_keys('<BS>')\n      eq(get_lines(), { '' })\n    end,\n    c = function()\n      type_keys('<C-v>', pair:sub(1, 1), '<C-v>', pair:sub(2, 2), '<Left>')\n      type_keys('<BS>')\n      eq(child.fn.getcmdline(), '')\n      eq(child.fn.getcmdpos(), 1)\n    end,\n    t = function()\n      local term_channel = get_term_channel()\n\n      child.fn.chansend(term_channel, pair)\n      -- Need to wait after each keystroke to allow shell to process it\n      sleep(term_mode_wait)\n      type_keys(term_mode_wait, '<Left>')\n      type_keys(term_mode_wait, '<BS>')\n\n      local pair_pattern = vim.pesc(pair) .. '$'\n      expect.no_match(get_lines()[1], pair_pattern)\n    end,\n  })[mode]\n\n  validate_action(mode, test)\nend\n\n--- Validate that `<CR>` acts like `<CR><C-o>O` in Insert mode if inside pair.\n---@private\nlocal validate_cr = function(pair)\n  local test = function()\n    -- Reference pass to get baseline data for default behavior\n    set_lines({ pair })\n    set_cursor(1, 0)\n    local keys = child.api.nvim_replace_termcodes('<Esc>a<CR><C-o>O', true, true, true)\n    child.api.nvim_feedkeys(keys, 'nx', false)\n\n    local ref_lines, ref_cursor = get_lines(), get_cursor()\n\n    -- Test pass\n    set_lines({ pair })\n    set_cursor(1, 0)\n    type_keys('<Esc>', 'a', '<CR>')\n\n    eq(get_lines(), ref_lines)\n    eq(get_cursor(), ref_cursor)\n    eq(child.fn.mode(), 'i')\n  end\n\n  validate_action('i', test)\nend\n\nlocal validate_neigh_disable = function(neigh, key)\n  set_lines({ neigh })\n  set_cursor(1, 0)\n  type_keys('a')\n\n  type_keys(key)\n  eq(get_lines(), { neigh:sub(1, 1) .. key .. neigh:sub(2, 2) })\n\n  child.ensure_normal_mode()\nend\n\nlocal validate_slash = function(key) validate_neigh_disable([[\\]], key) end\n\nlocal validate_no = function(action, ...)\n  local val_f = ({\n    open = validate_open,\n    close = validate_close,\n    bs = validate_bs,\n    cr = validate_cr,\n    neigh_disable = validate_neigh_disable,\n  })[action]\n\n  -- Validation function `val_f` should throw error\n  local ok, _ = pcall(val_f, ...)\n  child.ensure_normal_mode()\n  eq(ok, false)\nend\n\nlocal validate_disable = function(var_type, key)\n  child[var_type].minipairs_disable = true\n  set_lines({})\n  child.cmd('startinsert')\n  type_keys(key)\n  eq(get_lines(), { key })\n\n  child[var_type].minipairs_disable = nil\nend\n\nlocal validate_cmdline = function(line, pos)\n  eq(child.fn.mode(), 'c')\n  eq(child.fn.getcmdline(), line)\n  eq(child.fn.getcmdpos(), pos or line:len() + 1)\nend\n\nlocal apply_map = function(fun_name, args_string)\n  -- If testing `MiniPairs.map_buf()`, apply it in current buffer\n  local is_buf_local = fun_name == 'map_buf' or fun_name == 'unmap_buf'\n\n  -- Apply mapping function of same scope\n  local fun_name_actual = ({ map = 'map', unmap = 'map', map_buf = 'map_buf', unmap_buf = 'map_buf' })[fun_name]\n\n  local command = ('MiniPairs.%s(%s%s)'):format(fun_name_actual, is_buf_local and '0, ' or '', args_string)\n  child.lua(command)\nend\n\nlocal apply_unmap = function(fun_name, args_string)\n  -- If testing `MiniPairs.map_buf()`, apply it in current buffer\n  local is_buf_local = fun_name == 'map_buf' or fun_name == 'unmap_buf'\n\n  -- Apply mapping function of same scope\n  local fun_name_actual = ({ map = 'unmap', unmap = 'unmap', map_buf = 'unmap_buf', unmap_buf = 'unmap_buf' })[fun_name]\n\n  local command = ('MiniPairs.%s(%s%s)'):format(fun_name_actual, is_buf_local and '0, ' or '', args_string)\n  child.lua(command)\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniPairs)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniPairs'), 1)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniPairs.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniPairs.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('modes', { insert = true, command = false, terminal = false })\n  expect_config(\"mappings['(']\", { action = 'open', pair = '()', neigh_pattern = '^[^\\\\]' })\n  expect_config(\"mappings['[']\", { action = 'open', pair = '[]', neigh_pattern = '^[^\\\\]' })\n  expect_config(\"mappings['{']\", { action = 'open', pair = '{}', neigh_pattern = '^[^\\\\]' })\n  expect_config(\"mappings[')']\", { action = 'close', pair = '()', neigh_pattern = '^[^\\\\]' })\n  expect_config(\"mappings[']']\", { action = 'close', pair = '[]', neigh_pattern = '^[^\\\\]' })\n  expect_config(\"mappings['}']\", { action = 'close', pair = '{}', neigh_pattern = '^[^\\\\]' })\n  local quote_config = { action = 'closeopen', pair = '\"\"', neigh_pattern = '^[^\\\\]', register = { cr = false } }\n  expect_config(\"mappings['\\\"']\", quote_config)\n  quote_config.pair, quote_config.neigh_pattern = \"''\", '^[^%a\\\\]'\n  expect_config('mappings[\"\\'\"]', quote_config)\n  quote_config.pair, quote_config.neigh_pattern = '``', '^[^\\\\]'\n  expect_config(\"mappings['`']\", quote_config)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ modes = { command = true } })\n  eq(child.lua_get('MiniPairs.config.modes.command'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ modes = 'a' }, 'modes', 'table')\n  expect_config_error({ modes = { insert = 'a' } }, 'modes.insert', 'boolean')\n  expect_config_error({ modes = { command = 'a' } }, 'modes.command', 'boolean')\n  expect_config_error({ modes = { terminal = 'a' } }, 'modes.terminal', 'boolean')\n\n  local expect_mapping_pair_info = function(key)\n    local quote = key == \"'\" and '\"' or \"'\"\n    local prefix = ('mappings[%s%s%s]'):format(quote, key, quote)\n    expect_config_error({ mappings = { [key] = { action = 1 } } }, prefix .. '.action', 'string')\n    expect_config_error({ mappings = { [key] = { action = 1 } } }, prefix .. '.action', 'string')\n    expect_config_error({ mappings = { [key] = { pair = 1 } } }, prefix .. '.pair', 'string')\n    expect_config_error({ mappings = { [key] = { neigh_pattern = 1 } } }, prefix .. '.neigh_pattern', 'string')\n    expect_config_error({ mappings = { [key] = { register = 'a' } } }, prefix .. '.register', 'table')\n    expect_config_error({ mappings = { [key] = { register = { bs = 1 } } } }, prefix .. '.register.bs', 'boolean')\n    expect_config_error({ mappings = { [key] = { register = { cr = 1 } } } }, prefix .. '.register.cr', 'boolean')\n  end\n\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_mapping_pair_info('(')\n  expect_mapping_pair_info('[')\n  expect_mapping_pair_info('{')\n  expect_mapping_pair_info(')')\n  expect_mapping_pair_info(']')\n  expect_mapping_pair_info('}')\n  expect_mapping_pair_info('\"')\n  expect_mapping_pair_info(\"'\")\n  expect_mapping_pair_info('`')\nend\n\nlocal has_map = function(lhs, rhs, mode)\n  mode = mode or 'i'\n  local map_capture = child.cmd_capture(mode .. 'map ' .. lhs)\n  return map_capture:find(vim.pesc(rhs)) ~= nil\nend\n\nT['setup()']['makes default `config.mappings`'] = function()\n  eq(has_map('(', [[v:lua.MiniPairs.open(\"()\", \"^[^\\\\]\")]]), true)\n  eq(has_map('[', [[v:lua.MiniPairs.open(\"[]\", \"^[^\\\\]\")]]), true)\n  eq(has_map('{', [[v:lua.MiniPairs.open(\"{}\", \"^[^\\\\]\")]]), true)\n  eq(has_map(')', [[v:lua.MiniPairs.close(\"()\", \"^[^\\\\]\")]]), true)\n  eq(has_map(']', [[v:lua.MiniPairs.close(\"[]\", \"^[^\\\\]\")]]), true)\n  eq(has_map('}', [[v:lua.MiniPairs.close(\"{}\", \"^[^\\\\]\")]]), true)\n  eq(has_map('\"', [[v:lua.MiniPairs.closeopen('\"\"', \"^[^\\\\]\")]]), true)\n  eq(has_map(\"'\", [[v:lua.MiniPairs.closeopen(\"''\", \"^[^%a\\\\]\")]]), true)\n  eq(has_map('`', [[v:lua.MiniPairs.closeopen(\"``\", \"^[^\\\\]\")]]), true)\n\n  eq(has_map('<CR>', 'v:lua.MiniPairs.cr()'), true)\n  eq(has_map('<BS>', 'v:lua.MiniPairs.bs()'), true)\nend\n\nT['setup()']['makes custom `config.mappings`'] = function()\n  reload_module({ mappings = { ['('] = { pair = '[]', action = 'close' } } })\n  eq(has_map('(', [[v:lua.MiniPairs.close(\"[]\", \"^[^\\\\]\")]]), true)\n\n  reload_module({ mappings = { ['*'] = { pair = '**', action = 'closeopen' } } })\n  eq(has_map('*', 'v:lua.MiniPairs.closeopen(\"**\", \"..\")'), true)\nend\n\nT['setup()']['makes mappings in supplied modes'] = function()\n  child.api.nvim_del_keymap('i', '(')\n  reload_module({ modes = { insert = false, command = true, terminal = false } })\n\n  eq(has_map('(', [[v:lua.MiniPairs.open(\"()\", \"^[^\\\\]\")]]), false)\n  eq(has_map('(', [[v:lua.MiniPairs.open(\"()\", \"^[^\\\\]\")]], 'c'), true)\nend\n\nT['setup()']['allows `false` as `mappings` entry to not create mapping'] = function()\n  eq(has_map('(', [[v:lua.MiniPairs.open(\"()\", \"^[^\\\\]\")]]), true)\n  child.api.nvim_del_keymap('i', '(')\n\n  reload_module({ mappings = { ['('] = false } })\n  eq(has_map('(', [[v:lua.MiniPairs.open(\"()\", \"^[^\\\\]\")]]), false)\nend\n\nT['setup()']['has default neighborhood patterns working with multibyte characters'] = function()\n  local validate = function(line_before, col_before, key, line_after)\n    set_lines({ line_before })\n    set_cursor(1, col_before)\n    type_keys('i', '\\\\', key)\n\n    eq(get_lines(), { line_after })\n\n    child.ensure_normal_mode()\n  end\n\n  validate('є', 0, '(', '\\\\(є')\n  validate('є', 0, '[', '\\\\[є')\n  validate('є', 0, '{', '\\\\{є')\n\n  validate('є)', 2, ')', 'є\\\\))')\n  validate('є]', 2, ']', 'є\\\\]]')\n  validate('є}', 2, '}', 'є\\\\}}')\n\n  validate('є', 0, '\"', '\\\\\"є')\n  validate('є', 0, \"'\", \"\\\\'є\")\n  validate('є', 0, '`', '\\\\`є')\nend\n\nT['map()/map_buf()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Allow switching between buffers with unsaved changes\n      child.o.hidden = true\n    end,\n  },\n  parametrize = { { 'map' }, { 'map_buf' } },\n})\n\nT['map()/map_buf()']['work'] = function(fun_name)\n  validate_no('open', 'i', '<', '<>')\n  validate_no('bs', 'i', '<>')\n  validate_no('cr', '<>')\n\n  apply_map(fun_name, [['i', '<', { action = 'open', pair = '<>' }]])\n\n  validate_open('i', '<', '<>')\n  validate_bs('i', '<>')\n  validate_cr('<>')\nend\n\nT['map()/map_buf()']['create mapping properly'] = function(fun_name)\n  local has_open = function()\n    validate_open('i', '<', '<>')\n    validate_bs('i', '<>')\n    validate_cr('<>')\n  end\n  local no_open = function()\n    validate_no('open', 'i', '<', '<>')\n    validate_no('bs', 'i', '<>')\n    validate_no('cr', '<>')\n  end\n\n  -- Set up two buffers\n  local buffers = { cur = child.api.nvim_get_current_buf(), new = child.api.nvim_create_buf(true, false) }\n\n  child.api.nvim_set_current_buf(buffers.cur)\n  no_open()\n  child.api.nvim_set_current_buf(buffers.new)\n  no_open()\n\n  child.api.nvim_set_current_buf(buffers.cur)\n  apply_map(fun_name, [['i', '<', { action = 'open', pair = '<>' }]])\n  has_open()\n\n  child.api.nvim_set_current_buf(buffers.new)\n  if fun_name == 'map_buf' then\n    no_open()\n  else\n    has_open()\n  end\nend\n\nT['map()/map_buf()']['respect `mode` argument'] = function(fun_name)\n  local validate = function(mode)\n    local command = ([['%s', '<', { action = 'open', pair = '<>' }]]):format(mode)\n    apply_map(fun_name, command)\n    validate_open(mode, '<', '<>')\n  end\n\n  validate('i')\n  -- If making global mapping, also test in other modes\n  if fun_name == 'map' then\n    validate('c')\n    validate('t')\n  end\nend\n\nT['map()/map_buf()']['respect `lhs` argument'] = function(fun_name)\n  apply_map(fun_name, [['i', '<', { action = 'open', pair = '<>' }]])\n  validate_open('i', '<', '<>')\n\n  apply_map(fun_name, [['i', '$', { action = 'open', pair = '$%' }]])\n  validate_open('i', '$', '$%')\nend\n\nT['map()/map_buf()']['respect `action` and `pair` of `pair_info` argument'] = function(fun_name)\n  apply_map(fun_name, [['i', '>', { action = 'close', pair = '<>' }]])\n  validate_close('i', '>', '<>')\nend\n\nT['map()/map_buf()']['respect `neigh_pattern` of `pair_info` argument'] = function(fun_name)\n  -- It should insert pair only when cursor after whitespace and before\n  -- letter 'a'\n  apply_map(fun_name, [['i', '<', { action = 'open', pair = '<>', neigh_pattern = '%sa' }]])\n\n  local test = function()\n    -- Use typing delay to poke eventloop and enable correct neighbor pattern\n    -- checks\n    local wait = 1\n\n    -- Shouldn't work in general\n    type_keys(wait, 'a', '<')\n    eq(get_lines(), { 'a<' })\n\n    -- Should work only within specified pattern\n    set_lines({})\n    type_keys(wait, ' a', '<Left>', '<')\n    eq(get_lines(), { ' <>a' })\n  end\n\n  validate_action('i', test)\nend\n\nT['map()/map_buf()']['respect `register` of `pair_info` argument'] = function(fun_name)\n  apply_map(fun_name, [['i', '<', { action = 'open', pair = '<>', register = { bs = true, cr = false } }]])\n\n  validate_bs('i', '<>')\n  validate_no('cr', '<>')\nend\n\nT['map()/map_buf()']['respect `opts` or `pair_info` argument'] = function(fun_name)\n  -- Throws error because mapping `(` should already exist\n  expect.error(\n    function() apply_map(fun_name, [['i', '(', { action = 'open', pair = '()' }, { unique = true }]]) end,\n    '[Mm]apping.*exists'\n  )\nend\n\nT['map()/map_buf()']['create mappings for `<BS>` in new mode'] = function(fun_name)\n  -- Should not override existing one\n  child.cmd('cnoremap <BS> <Cmd>echo \"Hello\"<CR>')\n  apply_map(fun_name, '\"c\", \"<\", { action = \"open\", pair = \"<>\" }')\n  expect.match(child.cmd_capture('cmap <BS>'), 'echo \"Hello\"')\n  child.cmd('cunmap <BS>')\n\n  apply_map(fun_name, '\"c\", \"<\", { action = \"open\", pair = \"<>\" }')\n  expect.match(child.cmd_capture('cmap <BS>'), 'MiniPairs%.bs')\n  validate_bs('c', '<>')\nend\n\nT['map()/map_buf()']['create mappings for `<CR>` in new mode'] = function(fun_name)\n  -- Should not override existing one\n  child.cmd('inoremap <CR> <Cmd>echo \"Hello\"<CR>')\n  apply_map(fun_name, '\"i\", \"<\", { action = \"open\", pair = \"<>\" }')\n  expect.match(child.cmd_capture('imap <CR>'), 'echo \"Hello\"')\n  child.cmd('iunmap <CR>')\n\n  apply_map(fun_name, '\"i\", \"<\", { action = \"open\", pair = \"<>\" }')\n  expect.match(child.cmd_capture('imap <CR>'), 'MiniPairs%.cr')\n  validate_cr('<>')\nend\n\nlocal make_test_map = function(fun_name) apply_map(fun_name, [['i', '<', { action = 'open', pair = '<>' }]]) end\n\nlocal has_test_map = function()\n  validate_open('i', '<', '<>')\n  validate_bs('i', '<>')\n  validate_cr('<>')\nend\n\nlocal no_test_map = function()\n  validate_no('open', 'i', '<', '<>')\n  validate_no('bs', 'i', '<>')\n  validate_no('cr', '<>')\nend\n\nT['unmap()/unmap_buf()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Allow switching between buffers with unsaved changes\n      child.o.hidden = true\n    end,\n  },\n  parametrize = { { 'unmap' }, { 'unmap_buf' } },\n})\n\nT['unmap()/unmap_buf()']['work'] = function(fun_name)\n  make_test_map(fun_name)\n  has_test_map()\n\n  apply_unmap(fun_name, [['i', '<', '<>']])\n  no_test_map()\nend\n\nT['unmap()/unmap_buf()']['delete mapping properly'] = function(fun_name)\n  -- Set up two buffers\n  local buffers = { cur = child.api.nvim_get_current_buf(), new = child.api.nvim_create_buf(true, false) }\n\n  child.api.nvim_set_current_buf(buffers.cur)\n  make_test_map(fun_name)\n  has_test_map()\n  child.api.nvim_set_current_buf(buffers.new)\n  make_test_map(fun_name)\n  has_test_map()\n\n  child.api.nvim_set_current_buf(buffers.cur)\n  apply_unmap(fun_name, [['i', '<', '<>']])\n  no_test_map()\n\n  child.api.nvim_set_current_buf(buffers.new)\n  if fun_name == 'unmap_buf' then\n    has_test_map()\n  else\n    no_test_map()\n  end\nend\n\nT['unmap()/unmap_buf()']['respect `mode` argument'] = function(fun_name)\n  apply_map(fun_name, [['c', '<', { action = 'open', pair = '<>' }]])\n  validate_open('c', '<', '<>')\n  validate_bs('c', '<>')\n\n  apply_unmap(fun_name, [['c', '<', '<>']])\n  validate_no('open', 'c', '<', '<>')\n  validate_no('bs', 'c', '<>')\nend\n\nT['unmap()/unmap_buf()']['require explicit `pair` argument'] = function(fun_name)\n  expect.error(function() apply_unmap(fun_name, [['i', '(']]) end, 'pair.*string')\nend\n\nT['unmap()/unmap_buf()']['allow empty string for `pair` argument to not unregister pair'] = function(fun_name)\n  make_test_map(fun_name)\n  has_test_map()\n\n  apply_unmap(fun_name, [['i', '<', '']])\n  validate_no('open', 'i', '<', '<>')\n  validate_bs('i', '<>')\n  validate_cr('<>')\nend\n\nT['unmap()/unmap_buf()']['work for already missing mapping'] = function(fun_name)\n  expect.no_error(function() apply_unmap(fun_name, [['c', '%', '%%']]) end)\nend\n\n-- Integration tests ==========================================================\nT['Open action'] = new_set()\n\nT['Open action']['works'] = function()\n  validate_open('i', '(', '()')\n  validate_open('i', '[', '[]')\n  validate_open('i', '{', '{}')\n\n  -- There should be no side effects\n  eq(child.o.lazyredraw, false)\nend\n\nT['Open action']['works with multibyte characters'] = function()\n  -- Insert mode\n  child.lua('MiniPairs.map(\"i\", \"ы\", { action = \"open\", pair = \"ы」\" } )')\n  type_keys('i', 'ы')\n  eq(get_lines(), { 'ы」' })\n  eq(get_cursor(), { 1, 2 })\n  type_keys('ы')\n  eq(get_lines(), { 'ыы」」' })\n  eq(get_cursor(), { 1, 4 })\n\n  -- - Should also work for `<BS>`\n  type_keys('<BS>')\n  eq(get_lines(), { 'ы」' })\n  eq(get_cursor(), { 1, 2 })\n\n  -- - Should also work for `<CR>`\n  type_keys('<CR>')\n  eq(get_lines(), { 'ы', '', '」' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Command-line mode\n  child.ensure_normal_mode()\n  child.lua('MiniPairs.map(\"c\", \"ы\", { action = \"open\", pair = \"ы」\" } )')\n  type_keys(':', 'ы')\n  eq(child.fn.getcmdline(), 'ы」')\n  eq(child.fn.getcmdpos(), 3)\n  type_keys('ы')\n  eq(child.fn.getcmdline(), 'ыы」」')\n  eq(child.fn.getcmdpos(), 5)\n\n  -- - Should also work for `<BS>`\n  type_keys('<BS>')\n  eq(child.fn.getcmdline(), 'ы」')\n  eq(child.fn.getcmdpos(), 3)\n\n  -- Omit testing Terminal mode in the hope that it is the same\nend\n\nT['Open action']['does not break undo sequence in Insert mode'] = function()\n  type_keys('i', '((', '<Esc>')\n  eq(get_lines(), { '(())' })\n  eq(get_cursor(), { 1, 1 })\n\n  type_keys('u')\n  eq(get_lines(), { '' })\nend\n\nT['Open action']['works with visible wildmenu'] = function()\n  apply_map('map', '\"c\", \"<\", { action = \"open\", pair = \"<>\" }')\n  type_keys(':', '<Tab>', '<')\n  validate_cmdline('!<>', 3)\nend\n\nT['Open action']['respects neighbor pattern'] = function()\n  validate_slash('(')\n  validate_slash('[')\n  validate_slash('{')\nend\n\nT['Open action']['is correctly initiated in `config.mappings`'] = function()\n  child.api.nvim_del_keymap('i', '(')\n  reload_module({ mappings = { ['('] = { action = 'open', pair = '()', neigh_pattern = '..' } } })\n  validate_no('neigh_disable', [[\\]], '(')\nend\n\nT['Open action']['works with `nvim_feedkeys()`'] = function()\n  child.cmd('inoremap <C-j> <Cmd>call nvim_feedkeys(\"((\", \"\", v:true)<CR>')\n  type_keys('i', '<C-j>')\n  eq(child.o.lazyredraw, false)\nend\n\nT['Open action']['respects `vim.{g,b}.minipairs_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    validate_disable(var_type, '(')\n    validate_disable(var_type, '[')\n    validate_disable(var_type, '{')\n  end,\n})\n\nT['Close action'] = new_set()\n\nT['Close action']['works'] = function()\n  validate_open('i', ')', ')')\n  validate_open('i', ']', ']')\n  validate_open('i', '}', '}')\n  validate_close('i', ')', '()')\n  validate_close('i', ']', '[]')\n  validate_close('i', '}', '{}')\nend\n\nT['Close action']['works with multibyte characters'] = function()\n  -- Insert mode\n  child.lua('MiniPairs.map(\"i\", \"」\", { action = \"close\", pair = \"ы」\" } )')\n  type_keys('i', 'ы', '」', '<Left>')\n  eq(get_lines(), { 'ы」' })\n  eq(get_cursor(), { 1, 2 })\n  type_keys('」')\n  eq(get_lines(), { 'ы」' })\n  eq(get_cursor(), { 1, 5 })\n  type_keys('」')\n  eq(get_lines(), { 'ы」」' })\n  eq(get_cursor(), { 1, 8 })\n\n  -- - Should also work for `<BS>`\n  type_keys('<Left>', '<Left>', '<BS>')\n  eq(get_lines(), { '」' })\n  eq(get_cursor(), { 1, 0 })\n\n  -- - Should also work for `<CR>`\n  type_keys('<C-v>', 'ы', '<CR>')\n  eq(get_lines(), { 'ы', '', '」' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Command-line mode\n  child.ensure_normal_mode()\n  child.lua('MiniPairs.map(\"c\", \"」\", { action = \"close\", pair = \"ы」\" } )')\n  type_keys(':', 'ы', '」', '<Left>')\n  eq(child.fn.getcmdline(), 'ы」')\n  eq(child.fn.getcmdpos(), 3)\n  type_keys('」')\n  eq(child.fn.getcmdline(), 'ы」')\n  eq(child.fn.getcmdpos(), 6)\n  type_keys('」')\n  eq(child.fn.getcmdline(), 'ы」」')\n  eq(child.fn.getcmdpos(), 9)\n\n  -- - Should also work for `<BS>`\n  type_keys('<Left>', '<Left>', '<BS>')\n  eq(child.fn.getcmdline(), '」')\n  eq(child.fn.getcmdpos(), 1)\n\n  -- Omit testing Terminal mode in the hope that it is the same\nend\n\nT['Close action']['does not break undo sequence in Insert mode'] = function()\n  set_lines({ '(())' })\n  set_cursor(1, 2)\n\n  type_keys('i', ')) ', '<Esc>')\n  type_keys('u')\n  eq(get_lines(), { '(())' })\nend\n\nT['Close action']['works with visible wildmenu'] = function()\n  apply_map('map', '\"c\", \"(\", { action = \"open\", pair = \"()\" }')\n  apply_map('map', '\"c\", \")\", { action = \"close\", pair = \"()\" }')\n  child.lua('_G.AAA = 1')\n  type_keys(':', 'lua print(1 + ', '<Tab>')\n  validate_cmdline('lua print(1 + AAA)', 18)\n\n  type_keys(')')\n  validate_cmdline('lua print(1 + AAA)', 19)\nend\n\nT['Close action']['works with inline virtual text'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Inline virtual text is present in Neovim>=0.10') end\n\n  set_lines({ '()' })\n  local ns_id = child.api.nvim_create_namespace('Test')\n  child.api.nvim_buf_set_extmark(0, ns_id, 0, 1, { virt_text = { { 'Virt', 'String' } }, virt_text_pos = 'inline' })\n\n  local validate = function(virtualedit)\n    child.o.virtualedit = virtualedit\n    set_cursor(1, 0)\n\n    type_keys('a', ')')\n    eq(child.fn.getcurpos(), { 0, 1, 3, 0, 7 })\n    -- Should have no side effects\n    eq(child.o.virtualedit, virtualedit)\n\n    type_keys('<Esc>')\n  end\n\n  validate('all')\n  validate('none')\n  validate('block')\n  validate('onemore')\nend\n\nlocal validate_slash_close = function(key, pair)\n  set_lines({ pair })\n  set_cursor(1, 1)\n  child.cmd('startinsert')\n\n  -- Wait to poke eventloop to enable pattern check\n  type_keys(1, [[\\]], key)\n  eq(get_lines(), { pair:sub(1, 1) .. [[\\]] .. key .. pair:sub(2, 2) })\nend\n\nT['Close action']['respects neighbor pattern'] = function()\n  validate_slash_close(')', '()')\n  validate_slash_close(']', '[]')\n  validate_slash_close('}', '{}')\nend\n\nT['Close action']['is correctly initiated in `config.mappings`'] = function()\n  child.api.nvim_del_keymap('i', ')')\n  reload_module({ mappings = { [')'] = { action = 'close', pair = '()', neigh_pattern = '..' } } })\n  expect.error(function() validate_slash_close(')', '()') end)\nend\n\nT['Close action']['respects `vim.{g,b}.minipairs_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    validate_disable(var_type, ')')\n    validate_disable(var_type, ']')\n    validate_disable(var_type, '}')\n  end,\n})\n\nT['Closeopen action'] = new_set()\n\nT['Closeopen action']['works'] = function()\n  validate_open('i', '\"', '\"\"')\n  validate_open('i', \"'\", \"''\")\n  validate_open('i', '`', '``')\n  validate_close('i', '\"', '\"\"')\n  validate_close('i', \"'\", \"''\")\n  validate_close('i', '`', '``')\nend\n\nT['Closeopen action']['works with multibyte characters'] = function()\n  -- Insert mode\n  child.lua('MiniPairs.map(\"i\", \"」\", { action = \"closeopen\", pair = \"」」\" } )')\n  type_keys('i', '」')\n  eq(get_lines(), { '」」' })\n  eq(get_cursor(), { 1, 3 })\n  type_keys('」')\n  eq(get_lines(), { '」」' })\n  eq(get_cursor(), { 1, 6 })\n  type_keys('」')\n  eq(get_lines(), { '」」」」' })\n  eq(get_cursor(), { 1, 9 })\n\n  -- - Should also work for `<BS>`\n  type_keys('<BS>')\n  eq(get_lines(), { '」」' })\n  eq(get_cursor(), { 1, 6 })\n\n  -- - Should also work for `<CR>`\n  type_keys('<Left>', '<CR>')\n  eq(get_lines(), { '」', '', '」' })\n  eq(get_cursor(), { 2, 0 })\n\n  -- Command-line mode\n  child.ensure_normal_mode()\n  child.lua('MiniPairs.map(\"c\", \"」\", { action = \"closeopen\", pair = \"」」\" } )')\n  type_keys(':', '」')\n  eq(child.fn.getcmdline(), '」」')\n  eq(child.fn.getcmdpos(), 4)\n  type_keys('」')\n  eq(child.fn.getcmdline(), '」」')\n  eq(child.fn.getcmdpos(), 7)\n  type_keys('」')\n  eq(child.fn.getcmdline(), '」」」」')\n  eq(child.fn.getcmdpos(), 10)\n\n  -- - Should also work for `<BS>`\n  type_keys('<BS>')\n  eq(child.fn.getcmdline(), '」」')\n  eq(child.fn.getcmdpos(), 7)\n\n  -- Omit testing Terminal mode in the hope that it is the same\nend\n\nT['Closeopen action']['does not break undo sequence in Insert mode'] = function()\n  -- Open\n  set_lines({})\n\n  type_keys('i', '\"\"', '<Esc>')\n  type_keys('u')\n  eq(get_lines(), { '' })\n\n  -- Close\n  set_lines({ '\"\"\"\"' })\n  set_cursor(1, 2)\n\n  type_keys('i', '\"\" ', '<Esc>')\n  type_keys('u')\n  eq(get_lines(), { '\"\"\"\"' })\nend\n\nT['Closeopen action']['works with visible wildmenu'] = function()\n  apply_map('map', '\"c\", \"`\", { action = \"closeopen\", pair = \"``\" }')\n  child.lua('_G.AAA = 1')\n  type_keys(':', 'lua print`1 + ', '<Tab>')\n  validate_cmdline('lua print`1 + AAA`', 18)\n\n  type_keys('`')\n  validate_cmdline('lua print`1 + AAA`', 19)\nend\n\nT['Closeopen action']['works with inline virtual text'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Inline virtual text is present in Neovim>=0.10') end\n\n  set_lines({ '\"\"' })\n  local ns_id = child.api.nvim_create_namespace('Test')\n  child.api.nvim_buf_set_extmark(0, ns_id, 0, 1, { virt_text = { { 'Virt', 'String' } }, virt_text_pos = 'inline' })\n\n  local validate = function(virtualedit)\n    child.o.virtualedit = virtualedit\n    set_cursor(1, 0)\n\n    type_keys('a', '\"')\n    eq(child.fn.getcurpos(), { 0, 1, 3, 0, 7 })\n    -- Should have no side effects\n    eq(child.o.virtualedit, virtualedit)\n\n    type_keys('<Esc>')\n  end\n\n  validate('all')\n  validate('none')\n  validate('block')\n  validate('onemore')\nend\n\nT['Closeopen action']['respects neighbor pattern'] = function()\n  validate_slash('\"')\n  validate_slash(\"'\")\n  validate_slash('`')\n\n  validate_neigh_disable('a ', \"'\")\n\n  validate_no('neigh_disable', '__', '\"')\n  validate_no('neigh_disable', '__', \"'\")\n  validate_no('neigh_disable', '__', '`')\nend\n\nT['Closeopen action']['is correctly initiated in `config.mappings`'] = function()\n  child.api.nvim_del_keymap('i', '\"')\n  reload_module({ mappings = { ['\"'] = { action = 'closeopen', pair = '\"\"', neigh_pattern = '..' } } })\n  validate_no('neigh_disable', [[\\]], '\"')\nend\n\nT['Closeopen action']['respects `vim.{g,b}.minipairs_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    validate_disable(var_type, '\"')\n    validate_disable(var_type, \"'\")\n    validate_disable(var_type, '`')\n  end,\n})\n\nT['<BS> action'] = new_set()\n\nT['<BS> action']['works'] = function()\n  validate_bs('i', '()')\n  validate_bs('i', '[]')\n  validate_bs('i', '{}')\n  validate_bs('i', '\"\"')\n  validate_bs('i', \"''\")\n  validate_bs('i', '``')\n\n  -- Should work in Command-line with redraw\n  child.set_size(10, 12)\n  reload_module({ modes = { command = true } })\n  type_keys(':aa()bb', '<Left>', '<Left>', '<Left>')\n  type_keys('<BS>')\n  child.expect_screenshot()\nend\n\nT['<BS> action']['respects `key` argument'] = function()\n  child.lua([[\n    local map_bs = function(lhs, rhs)\n      vim.keymap.set('i', lhs, rhs, { expr = true, replace_keycodes = false })\n    end\n\n    map_bs('<C-h>', 'v:lua.MiniPairs.bs()')\n    map_bs('<C-w>', 'v:lua.MiniPairs.bs(\"\\23\")')\n    map_bs('<C-u>', 'v:lua.MiniPairs.bs(\"\\21\")')\n  ]])\n  local validate_key = function(key, line_before, col_before, line_after, col_after)\n    child.ensure_normal_mode()\n    set_lines({ line_before })\n    set_cursor(1, col_before)\n    type_keys('a')\n\n    type_keys(key)\n\n    eq(child.api.nvim_get_mode().mode, 'i')\n    eq(get_lines(), { line_after })\n    eq(get_cursor(), { 1, col_after })\n  end\n\n  -- `<C-h>`\n  validate_key('<C-h>', 'aa(b)', 3, 'aa()', 3)\n  validate_key('<C-h>', 'aa()', 2, 'aa', 2)\n  validate_key('<C-h>', 'aa', 1, 'a', 1)\n\n  -- `<C-w>`\n  validate_key('<C-w>', 'aa(bb)', 4, 'aa()', 3)\n  validate_key('<C-w>', 'aa()', 2, 'aa', 2)\n  validate_key('<C-w>', 'aa', 1, '', 0)\n\n  -- `<C-u>`\n  validate_key('<C-u>', 'aa()cc', 1, '()cc', 0)\n  validate_key('<C-u>', 'aa()cc', 2, 'cc', 0)\n  validate_key('<C-u>', 'aa()cc', 5, '', 0)\nend\n\nT['<BS> action']['does not break undo sequence in Insert mode'] = function()\n  set_lines({ 'a()' })\n  set_cursor(1, 2)\n  child.cmd('startinsert')\n\n  type_keys('<BS><BS>', '<Esc>')\n  eq(get_lines(), { '' })\n  type_keys('u')\n  eq(get_lines(), { 'a()' })\nend\n\nlocal reload_unregister_bs = function()\n  child.api.nvim_del_keymap('i', '<BS>')\n  reload_module({\n    mappings = {\n      ['('] = { register = { bs = false } },\n      ['['] = { register = { bs = false } },\n      ['{'] = { register = { bs = false } },\n      [')'] = { register = { bs = false } },\n      [']'] = { register = { bs = false } },\n      ['}'] = { register = { bs = false } },\n      ['\"'] = { register = { bs = false } },\n      [\"'\"] = { register = { bs = false } },\n      ['`'] = { register = { bs = false } },\n    },\n  })\nend\n\nT['<BS> action']['does not create mapping if nothing is registered in `config.mappings`'] = function()\n  expect.match(child.cmd_capture('imap <BS>'), 'MiniPairs%.bs')\n  reload_unregister_bs()\n  expect.match(child.cmd_capture('imap <BS>'), 'No mapping found')\nend\n\nT['<BS> action']['works as normal if nothing is registered'] = function()\n  reload_unregister_bs()\n\n  set_lines({ '()' })\n  set_cursor(1, 1)\n  child.cmd('startinsert')\n\n  type_keys('<BS>')\n  eq(get_lines(), { ')' })\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['<BS> action']['respects `vim.{g,b}.minipairs_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minipairs_disable = true\n    set_lines({ '()' })\n    set_cursor(1, 1)\n    child.cmd('startinsert')\n    type_keys('<BS>')\n    eq(get_lines(), { ')' })\n  end,\n})\n\nT['<CR> action'] = new_set()\n\nT['<CR> action']['works'] = function()\n  validate_cr('()')\n  validate_cr('[]')\n  validate_cr('{}')\n  validate_no('cr', '\"\"')\n  validate_no('cr', \"''\")\n  validate_no('cr', '``')\n\n  -- There should be no side effects\n  eq(child.o.eventignore, '')\n  eq(child.o.lazyredraw, false)\nend\n\nT['<CR> action']['respects `key` argument'] = function()\n  child.api.nvim_set_keymap('i', '<C-u>', 'v:lua.MiniPairs.cr(\"\\21\")', { noremap = true, expr = true })\n\n  local validate_key = function(key, lines_before, cursor_before, lines_after, cursor_after)\n    child.ensure_normal_mode()\n    set_lines(lines_before)\n    set_cursor(unpack(cursor_before))\n    type_keys('a')\n\n    type_keys(key)\n\n    eq(child.api.nvim_get_mode().mode, 'i')\n    eq(get_lines(), lines_after)\n    eq(get_cursor(), cursor_after)\n  end\n\n  -- `<C-u>`\n  validate_key('<C-u>', { 'aa()cc' }, { 1, 1 }, { '()cc' }, { 1, 0 })\n  validate_key('<C-u>', { 'aa()cc' }, { 1, 2 }, { '', ')cc' }, { 1, 0 })\n  validate_key('<C-u>', { 'aa()cc' }, { 1, 5 }, { '' }, { 1, 0 })\nend\n\nT['<CR> action']['does not break undo sequence in Insert mode'] = function()\n  set_lines({ '()' })\n  set_cursor(1, 1)\n  child.cmd('startinsert')\n\n  type_keys('<CR>', 'a', '<Esc>')\n  type_keys('u')\n  eq(get_lines(), { '()' })\nend\n\nT['<CR> action']['reindents the line'] = function()\n  child.bo.cindent = true\n  set_lines({ '{}' })\n  set_cursor(1, 1)\n  child.cmd('startinsert')\n\n  type_keys('<CR>')\n  eq(get_lines(), { '{', '\\t', '}' })\nend\n\nT['<CR> action']['does not trigger mode change'] = function()\n  child.o.eventignore = 'CursorHold'\n  set_lines({ '{}' })\n  set_cursor(1, 1)\n  child.cmd('startinsert')\n  child.cmd('au InsertLeave,InsertLeavePre,InsertEnter,TextChanged,ModeChanged * lua _G.n = (_G.n or 0) + 1')\n  type_keys('<CR>')\n  eq(child.lua_get('_G.n'), vim.NIL)\n  eq(child.o.eventignore, 'CursorHold')\nend\n\nlocal reload_unregister_cr = function()\n  child.api.nvim_del_keymap('i', '<CR>')\n  reload_module({\n    mappings = {\n      ['('] = { register = { cr = false } },\n      ['['] = { register = { cr = false } },\n      ['{'] = { register = { cr = false } },\n      [')'] = { register = { cr = false } },\n      [']'] = { register = { cr = false } },\n      ['}'] = { register = { cr = false } },\n      ['\"'] = { register = { cr = false } },\n      [\"'\"] = { register = { cr = false } },\n      ['`'] = { register = { cr = false } },\n    },\n  })\nend\n\nT['<CR> action']['does not create mapping if nothing is registered in `config.mappings`'] = function()\n  expect.match(child.cmd_capture('imap <CR>'), 'MiniPairs%.cr')\n  reload_unregister_cr()\n  expect.match(child.cmd_capture('imap <CR>'), 'No mapping found')\nend\n\nT['<CR> action']['works as normal if nothing is registered'] = function()\n  reload_unregister_cr()\n\n  set_lines({ '()' })\n  set_cursor(1, 1)\n  child.cmd('startinsert')\n\n  type_keys('<CR>')\n  eq(get_lines(), { '(', ')' })\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['<CR> action']['works with `feedkeys()`'] = function()\n  child.cmd('inoremap <C-j> <Cmd>call nvim_feedkeys(\"(\\\\r(\\\\r\", \"\", v:true)<CR>')\n  type_keys('i', '<C-j>')\n  eq(child.o.eventignore, '')\n  eq(child.o.lazyredraw, false)\nend\n\nT['<CR> action']['respects `vim.{g,b}.minipairs_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minipairs_disable = true\n    set_lines({ '()' })\n    set_cursor(1, 1)\n    child.cmd('startinsert')\n    type_keys('<CR>')\n    eq(get_lines(), { '(', ')' })\n  end,\n})\n\nreturn T\n"
  },
  {
    "path": "tests/test_pick.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('pick', config) end\nlocal unload_module = function() child.mini_unload('pick') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Tweak `expect_screenshot()` to test only on Neovim>=0.10 (as it has floating\n-- window footer). Use `child.expect_screenshot_orig()` for original testing.\nchild.expect_screenshot_orig = child.expect_screenshot\nchild.expect_screenshot = function(opts)\n  if child.fn.has('nvim-0.10') == 0 then return end\n  child.expect_screenshot_orig(opts)\nend\n\n-- Test paths helpers\nlocal join_path = function(...) return table.concat({ ... }, '/') end\n\nlocal full_path = function(x) return (vim.fn.fnamemodify(x, ':p'):gsub('[\\\\/]$', '')) end\n\nlocal test_dir = 'tests/dir-pick'\nlocal test_dir_absolute = full_path(test_dir)\nlocal real_files_dir = 'tests/dir-pick/real-files'\n\nlocal real_file = function(basename) return join_path(real_files_dir, basename) end\n\nlocal setup_windows_pair = function()\n  child.cmd('botright wincmd v')\n  local win_id_1 = child.api.nvim_get_current_win()\n  child.cmd('wincmd h')\n  local win_id_2 = child.api.nvim_get_current_win()\n  child.api.nvim_set_current_win(win_id_1)\n  return win_id_1, win_id_2\nend\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal forward_lua_notify = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_notify(lua_cmd, { ... }) end\nend\n\nlocal stop = forward_lua('MiniPick.stop')\nlocal get_picker_items = forward_lua('MiniPick.get_picker_items')\nlocal get_picker_stritems = forward_lua('MiniPick.get_picker_stritems')\nlocal get_picker_matches = forward_lua('MiniPick.get_picker_matches')\nlocal get_picker_state = forward_lua('MiniPick.get_picker_state')\nlocal get_picker_query = forward_lua('MiniPick.get_picker_query')\nlocal set_picker_items = forward_lua('MiniPick.set_picker_items')\nlocal set_picker_query = forward_lua('MiniPick.set_picker_query')\nlocal get_querytick = forward_lua('MiniPick.get_querytick')\nlocal is_picker_active = forward_lua('MiniPick.is_picker_active')\n\n-- Use `child.api_notify` to allow user input while child process awaits for\n-- `start()` to return a value\nlocal start = function(...) child.lua_notify('MiniPick.start(...)', { ... }) end\n\nlocal start_with_items = function(items, name) start({ source = { items = items, name = name } }) end\n\n-- Common test helpers\nlocal validate_buf_option = function(buf_id, option_name, option_value)\n  eq(child.api.nvim_buf_get_option(buf_id, option_name), option_value)\nend\n\nlocal validate_win_option = function(win_id, option_name, option_value)\n  eq(child.api.nvim_win_get_option(win_id, option_name), option_value)\nend\n\nlocal validate_buf_name = function(buf_id, ref_name)\n  buf_id = buf_id or child.api.nvim_get_current_buf()\n  local name = child.api.nvim_buf_get_name(buf_id):gsub('\\\\', '/')\n  ref_name = ref_name ~= '' and full_path(ref_name) or ''\n  ref_name = ref_name:gsub('\\\\', '/'):gsub('[\\\\/]+$', '')\n  eq(name, ref_name)\nend\n\nlocal validate_helper_buf_name = function(buf_id, ref_name)\n  buf_id = (buf_id == nil or buf_id == 0) and child.api.nvim_get_current_buf() or buf_id\n  eq(child.api.nvim_buf_get_name(buf_id), 'minipick://' .. buf_id .. '/' .. ref_name)\nend\n\nlocal validate_contains_all = function(base, to_be_present)\n  local is_present_map, is_all_present = {}, true\n  for _, x in pairs(to_be_present) do\n    is_present_map[x] = vim.tbl_contains(base, x)\n    is_all_present = is_all_present and is_present_map[x]\n  end\n  if is_all_present then return end\n  local err_msg = string.format(\n    'Not all elements are present:\\nActual: %s\\nReference map: %s',\n    vim.inspect(base),\n    vim.inspect(is_present_map)\n  )\n  error(err_msg)\nend\n\nlocal validate_picker_option = function(string_index, ref)\n  local value = child.lua_get('MiniPick.get_picker_opts().' .. string_index)\n  eq(value, ref)\nend\n\nlocal validate_picker_view = function(view_name)\n  eq(child.api.nvim_get_current_buf(), get_picker_state().buffers[view_name])\nend\n\nlocal validate_current_ind = function(ref_ind) eq(get_picker_matches().current_ind, ref_ind) end\n\nlocal seq_along = function(x)\n  local res = {}\n  for i = 1, #x do\n    res[i] = i\n  end\n  return res\nend\n\nlocal make_match_with_count = function()\n  child.lua('_G.match_n_calls = 0')\n  local validate_match_calls = function(n_calls_ref, match_inds_ref)\n    eq(child.lua_get('_G.match_n_calls'), n_calls_ref)\n    eq(get_picker_matches().all_inds, match_inds_ref)\n  end\n\n  child.lua_notify([[_G.match_with_count = function(...)\n    _G.match_n_calls = _G.match_n_calls + 1\n    return MiniPick.default_match(...)\n  end]])\n  return validate_match_calls\nend\n\nlocal make_event_log = function()\n  child.lua([[\n  _G.event_log = {}\n  _G.track_event = function()\n    local buf_id = MiniPick.get_picker_state().buffers.main\n    local entry\n    if not vim.api.nvim_buf_is_valid(buf_id) then\n      entry = 'Main buffer is invalid'\n    else\n      entry = #vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)\n    end\n    table.insert(_G.event_log, entry)\n  end]])\nend\n\n-- Common mocks\nlocal mock_fn_executable = function(available_executables)\n  local lua_cmd = string.format(\n    'vim.fn.executable = function(x) return vim.tbl_contains(%s, x) and 1 or 0 end',\n    vim.inspect(available_executables)\n  )\n  child.lua(lua_cmd)\nend\n\nlocal mock_picker_cwd = function(cwd)\n  child.lua('vim.fn.fnamemodify = function(x) return x end')\n  child.lua(string.format('MiniPick.set_picker_opts({ source = { cwd = %s } })', vim.inspect(cwd)))\nend\n\nlocal mock_spawn = function()\n  local mock_file = join_path(test_dir, 'mocks', 'spawn.lua')\n  local lua_cmd = string.format('dofile(%s)', vim.inspect(mock_file))\n  child.lua(lua_cmd)\nend\n\nlocal mock_stdout_feed = function(feed) child.lua('_G.stdout_data_feed = ' .. vim.inspect(feed)) end\n\nlocal mock_cli_return = function(items) mock_stdout_feed({ table.concat(items, '\\n') }) end\n\nlocal get_spawn_log = function() return child.lua_get('_G.spawn_log') end\n\nlocal clear_spawn_log = function() child.lua('_G.spawn_log = {}') end\n\nlocal validate_spawn_log = function(ref, index)\n  local present = get_spawn_log()\n  if type(index) == 'number' then present = present[index] end\n  eq(present, ref)\nend\n\nlocal get_process_log = function() return child.lua_get('_G.process_log') end\n\nlocal clear_process_log = function() child.lua('_G.process_log = {}') end\n\n-- Data =======================================================================\nlocal test_items = { 'a_b_c', 'abc', 'a_b_b', 'c_a_a', 'b_c_c' }\n\n-- Time constants\nlocal default_busy_delay = 50\nlocal track_lost_focus_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Make more comfortable screenshots\n      child.o.laststatus = 0\n      child.o.ruler = false\n      child.set_size(15, 40)\n\n      load_module()\n\n      -- Make some UI elements differentiable in screenshots\n      child.cmd('hi MiniPickBorder guifg=Red ctermfg=1')\n      child.cmd('hi MiniPickPrompt guifg=Green ctermfg=2')\n      child.cmd('hi MiniPickPromptCaret guifg=Yellow ctermfg=3')\n      child.cmd('hi MiniPickPromptPrefix guifg=Azure ctermfg=4')\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniPick)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniPick'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local validate_hl_group = function(name, ref) expect.match(child.cmd_capture('hi ' .. name), ref) end\n\n  -- - Make sure to clear highlight groups defined for better screenshots\n  child.cmd('hi clear MiniPickBorder')\n  load_module()\n\n  validate_hl_group('MiniPickBorder', 'links to FloatBorder')\n  validate_hl_group('MiniPickBorderBusy', 'links to DiagnosticFloatingWarn')\n  validate_hl_group('MiniPickBorderText', 'links to FloatTitle')\n  validate_hl_group('MiniPickCursor', 'nocombine.*blend=100')\n  validate_hl_group('MiniPickIconDirectory', 'links to Directory')\n  validate_hl_group('MiniPickIconFile', 'links to MiniPickNormal')\n  validate_hl_group('MiniPickHeader', 'links to DiagnosticFloatingHint')\n  validate_hl_group('MiniPickMatchCurrent', 'links to CursorLine')\n  validate_hl_group('MiniPickMatchMarked', 'links to Visual')\n  validate_hl_group('MiniPickMatchRanges', 'links to DiagnosticFloatingHint')\n  validate_hl_group('MiniPickNormal', 'links to NormalFloat')\n  validate_hl_group('MiniPickPreviewLine', 'links to CursorLine')\n  validate_hl_group('MiniPickPreviewRegion', 'links to IncSearch')\n  validate_hl_group('MiniPickPrompt', 'links to DiagnosticFloatingInfo')\n  validate_hl_group('MiniPickPromptCaret', 'links to MiniPickPrompt')\n  validate_hl_group('MiniPickPromptPrefix', 'links to MiniPickPrompt')\n\n  -- `vim.ui.select` implementation\n  child.lua_notify('vim.ui.select({ \"a\", \"b\" }, {}, function() end)')\n  eq(child.lua_get('MiniPick.get_picker_items() ~= nil'), true)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniPick.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniPick.config.' .. field), value) end\n\n  expect_config('delay.async', 10)\n  expect_config('delay.busy', 50)\n\n  expect_config('mappings.caret_left', '<Left>')\n  expect_config('mappings.caret_right', '<Right>')\n  expect_config('mappings.choose', '<CR>')\n  expect_config('mappings.choose_in_split', '<C-s>')\n  expect_config('mappings.choose_in_tabpage', '<C-t>')\n  expect_config('mappings.choose_in_vsplit', '<C-v>')\n  expect_config('mappings.choose_marked', '<M-CR>')\n  expect_config('mappings.delete_char', '<BS>')\n  expect_config('mappings.delete_char_right', '<Del>')\n  expect_config('mappings.delete_left', '<C-u>')\n  expect_config('mappings.delete_word', '<C-w>')\n  expect_config('mappings.mark', '<C-x>')\n  expect_config('mappings.mark_all', '<C-a>')\n  expect_config('mappings.move_down', '<C-n>')\n  expect_config('mappings.move_start', '<C-g>')\n  expect_config('mappings.move_up', '<C-p>')\n  expect_config('mappings.paste', '<C-r>')\n  expect_config('mappings.refine', '<C-Space>')\n  expect_config('mappings.refine_marked', '<M-Space>')\n  expect_config('mappings.scroll_down', '<C-f>')\n  expect_config('mappings.scroll_left', '<C-h>')\n  expect_config('mappings.scroll_right', '<C-l>')\n  expect_config('mappings.scroll_up', '<C-b>')\n  expect_config('mappings.stop', '<Esc>')\n  expect_config('mappings.toggle_info', '<S-Tab>')\n  expect_config('mappings.toggle_preview', '<Tab>')\n\n  expect_config('options.content_from_bottom', false)\n  expect_config('options.use_cache', false)\n\n  expect_config('source.items', vim.NIL)\n  expect_config('source.name', vim.NIL)\n  expect_config('source.cwd', vim.NIL)\n  expect_config('source.match', vim.NIL)\n  expect_config('source.show', vim.NIL)\n  expect_config('source.preview', vim.NIL)\n  expect_config('source.choose', vim.NIL)\n  expect_config('source.choose_marked', vim.NIL)\n\n  expect_config('window.config', vim.NIL)\n  expect_config('window.prompt_caret', '▏')\n  expect_config('window.prompt_prefix', '> ')\n\n  -- Should temporarily respect deprecated `window.prompt_cursor`\n  local caret_cursor = child.lua([[\n    _G.log = {}\n    vim.notify = function(...) table.insert(_G.log, { ... }) end\n    require('mini.pick').setup({ window = { prompt_cursor = '$' } })\n    return { MiniPick.config.window.prompt_caret, MiniPick.config.window.prompt_cursor }\n  ]])\n  eq(caret_cursor, { '$' })\n  local ref_msg = '(mini.pick) `prompt_cursor` in `config.window` is renamed to `prompt_caret` for better naming consistency.'\n    .. ' It works for now, but will stop in the next release. Sorry for the inconvenience.'\n  eq(child.lua_get('_G.log'), { { ref_msg, child.lua_get('vim.log.levels.WARN') } })\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ options = { use_cache = true } })\n  eq(child.lua_get('MiniPick.config.options.use_cache'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ delay = 'a' }, 'delay', 'table')\n  expect_config_error({ delay = { async = 'a' } }, 'delay.async', 'number')\n  expect_config_error({ delay = { busy = 'a' } }, 'delay.busy', 'number')\n\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { caret_left = 1 } }, 'mappings.caret_left', 'string')\n  expect_config_error({ mappings = { caret_right = 1 } }, 'mappings.caret_right', 'string')\n  expect_config_error({ mappings = { choose = 1 } }, 'mappings.choose', 'string')\n  expect_config_error({ mappings = { choose_in_split = 1 } }, 'mappings.choose_in_split', 'string')\n  expect_config_error({ mappings = { choose_in_tabpage = 1 } }, 'mappings.choose_in_tabpage', 'string')\n  expect_config_error({ mappings = { choose_in_vsplit = 1 } }, 'mappings.choose_in_vsplit', 'string')\n  expect_config_error({ mappings = { choose_marked = 1 } }, 'mappings.choose_marked', 'string')\n  expect_config_error({ mappings = { delete_char = 1 } }, 'mappings.delete_char', 'string')\n  expect_config_error({ mappings = { delete_char_right = 1 } }, 'mappings.delete_char_right', 'string')\n  expect_config_error({ mappings = { delete_left = 1 } }, 'mappings.delete_left', 'string')\n  expect_config_error({ mappings = { delete_word = 1 } }, 'mappings.delete_word', 'string')\n  expect_config_error({ mappings = { mark = 1 } }, 'mappings.mark', 'string')\n  expect_config_error({ mappings = { mark_all = 1 } }, 'mappings.mark_all', 'string')\n  expect_config_error({ mappings = { move_down = 1 } }, 'mappings.move_down', 'string')\n  expect_config_error({ mappings = { move_start = 1 } }, 'mappings.move_start', 'string')\n  expect_config_error({ mappings = { move_up = 1 } }, 'mappings.move_up', 'string')\n  expect_config_error({ mappings = { paste = 1 } }, 'mappings.paste', 'string')\n  expect_config_error({ mappings = { refine = 1 } }, 'mappings.refine', 'string')\n  expect_config_error({ mappings = { refine_marked = 1 } }, 'mappings.refine_marked', 'string')\n  expect_config_error({ mappings = { scroll_down = 1 } }, 'mappings.scroll_down', 'string')\n  expect_config_error({ mappings = { scroll_left = 1 } }, 'mappings.scroll_left', 'string')\n  expect_config_error({ mappings = { scroll_right = 1 } }, 'mappings.scroll_right', 'string')\n  expect_config_error({ mappings = { scroll_up = 1 } }, 'mappings.scroll_up', 'string')\n  expect_config_error({ mappings = { stop = 1 } }, 'mappings.stop', 'string')\n  expect_config_error({ mappings = { toggle_info = 1 } }, 'mappings.toggle_info', 'string')\n  expect_config_error({ mappings = { toggle_preview = 1 } }, 'mappings.toggle_preview', 'string')\n\n  expect_config_error({ options = 'a' }, 'options', 'table')\n  expect_config_error({ options = { content_from_bottom = 1 } }, 'options.content_from_bottom', 'boolean')\n  expect_config_error({ options = { use_cache = 1 } }, 'options.use_cache', 'boolean')\n\n  expect_config_error({ source = 'a' }, 'source', 'table')\n  expect_config_error({ source = { items = 1 } }, 'source.items', 'table')\n  expect_config_error({ source = { name = 1 } }, 'source.name', 'string')\n  expect_config_error({ source = { cwd = 1 } }, 'source.cwd', 'string')\n  expect_config_error({ source = { match = 1 } }, 'source.match', 'function')\n  expect_config_error({ source = { show = 1 } }, 'source.show', 'function')\n  expect_config_error({ source = { preview = 1 } }, 'source.preview', 'function')\n  expect_config_error({ source = { choose = 1 } }, 'source.choose', 'function')\n  expect_config_error({ source = { choose_marked = 1 } }, 'source.choose_marked', 'function')\n\n  expect_config_error({ window = 'a' }, 'window', 'table')\n  expect_config_error({ window = { config = 1 } }, 'window.config', 'table or callable')\n  expect_config_error({ window = { prompt_caret = 1 } }, 'window.prompt_caret', 'string')\n  expect_config_error({ window = { prompt_prefix = 1 } }, 'window.prompt_prefix', 'string')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniPickBorder'), 'links to FloatBorder')\nend\n\nT['setup()']['should `MiniExtra.pickers` to registry'] = function()\n  unload_module()\n  child.lua([[package.loaded['mini.pick'] = nil]])\n\n  child.lua('_G.MiniExtra = { pickers = { miniextra = function() end } }')\n  load_module()\n  eq(child.lua_get('type(MiniPick.registry.miniextra)'), 'function')\n\n  -- Should not override user pickers\n  child.lua([[\n    MiniPick.registry.miniextra = function() _G.hello = 'world' end\n    require('mini.pick').setup()\n  ]])\n  child.lua_notify('MiniPick.registry.miniextra()')\n  eq(child.lua_get('_G.hello'), 'world')\nend\n\n-- This set mostly contains general function testing which doesn't fit into\n-- more specialized integration tests later\nT['start()'] = new_set()\n\nT['start()']['works'] = function()\n  child.lua_notify('_G.picked_item = MiniPick.start(...)', { { source = { items = test_items } } })\n  child.expect_screenshot()\n\n  -- Should focus on floating window\n  eq(child.api.nvim_get_current_win(), get_picker_state().windows.main)\n\n  -- Should close window after an item and print it (as per `default_choose()`)\n  type_keys('<CR>')\n  child.expect_screenshot()\n\n  -- Should return picked value\n  eq(child.lua_get('_G.picked_item'), test_items[1])\nend\n\nT['start()']['returns `nil` when there is no current match'] = function()\n  child.lua_notify('_G.picked_item = MiniPick.start(...)', { { source = { items = test_items } } })\n  type_keys('x')\n  type_keys('<CR>')\n  eq(child.lua_get('_G.picked_item'), vim.NIL)\nend\n\nT['start()']['works with window footer'] = function()\n  child.lua_notify('_G.picked_item = MiniPick.start(...)', { { source = { items = test_items } } })\n  child.expect_screenshot()\n\n  eq(child.api.nvim_get_current_win(), get_picker_state().windows.main)\n  type_keys('<CR>')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.picked_item'), test_items[1])\nend\n\nT['start()']['can be started without explicit items'] = function()\n  child.lua_notify('_G.picked_item = MiniPick.start()')\n  child.expect_screenshot()\n  type_keys('<CR>')\n  eq(child.lua_get('_G.picked_item'), vim.NIL)\nend\n\nT['start()']['creates proper window'] = function()\n  start_with_items(test_items)\n  local win_id = get_picker_state().windows.main\n  eq(child.api.nvim_win_is_valid(win_id), true)\n\n  local win_config = child.api.nvim_win_get_config(win_id)\n  eq(win_config.relative, 'editor')\n  eq(win_config.focusable, true)\n  eq(win_config.zindex, 251)\n\n  validate_win_option(win_id, 'list', true)\n  validate_win_option(win_id, 'listchars', 'extends:…,precedes:…')\n  validate_win_option(win_id, 'wrap', false)\nend\n\nT['start()']['creates proper main buffer'] = function()\n  start_with_items(test_items)\n  local buf_id = get_picker_state().buffers.main\n  eq(child.api.nvim_buf_is_valid(buf_id), true)\n  validate_buf_option(buf_id, 'filetype', 'minipick')\n  validate_buf_option(buf_id, 'buflisted', false)\n  validate_buf_option(buf_id, 'buftype', 'nofile')\nend\n\nT['start()']['uses properly named buffers'] = function()\n  start_with_items(test_items)\n  validate_helper_buf_name(0, 'main')\n  type_keys('<S-Tab>')\n  validate_helper_buf_name(0, 'info')\n  -- NOTE: Source's `preview()` can override buffer's name for more info\n  type_keys('<Tab>')\n  validate_helper_buf_name(0, 'preview')\nend\n\nT['start()']['tracks lost focus'] = function()\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { 'aa bb' })\n  child.lua_notify([[\n    local win_id = vim.api.nvim_get_current_win()\n    local change_focus = function()\n     vim.api.nvim_set_current_win(win_id)\n     return false\n    end\n    MiniPick.start({\n      source = { items = { 'a', 'b' } },\n      mappings = { change_focus = { char = 'e', func = change_focus } },\n    })\n  ]])\n  child.expect_screenshot()\n  type_keys('e')\n  -- By default it checks inside a timer with 1 second period\n  sleep(track_lost_focus_delay + small_time)\n  child.expect_screenshot()\n  -- - Should not keep key query process going\n  type_keys('w')\n  eq(get_cursor(), { 1, 3 })\n\n  -- Should also work in case of an error in action\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b' } },\n    mappings = { error = { char = 'e', func = function() error() end } },\n  })]])\n  type_keys('e')\n  sleep(track_lost_focus_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['start()']['validates `opts`'] = function()\n  local validate = function(opts, error_pattern)\n    expect.error(function() child.lua('MiniPick.start(...)', { opts }) end, error_pattern)\n  end\n\n  validate(1, 'Picker options.*table')\n\n  validate({ delay = { async = 'a' } }, '`delay.async`.*number')\n  validate({ delay = { async = 0 } }, '`delay.async`.*positive')\n  validate({ delay = { busy = 'a' } }, '`delay.busy`.*number')\n  validate({ delay = { busy = 0 } }, '`delay.busy`.*positive')\n\n  validate({ options = { content_from_bottom = 1 } }, '`options%.content_from_bottom`.*boolean')\n  validate({ options = { use_cache = 1 } }, '`options%.use_cache`.*boolean')\n\n  validate({ mappings = { [1] = '<C-f>' } }, '`mappings`.*only string fields')\n  validate({ mappings = { choose = 1 } }, 'Mapping for built%-in action \"choose\".*string')\n  expect.error(\n    function() child.lua('MiniPick.start({ mappings = { choose = { char = \"a\", func = function() end } } })') end,\n    'built%-in action.*string'\n  )\n  validate(\n    { mappings = { ['Custom action'] = 1 } },\n    'Mapping for custom action \"Custom action\".*table with `char` and `func`'\n  )\n\n  validate({ source = { items = 1 } }, '`source%.items`.*array or callable')\n  validate({ source = { cwd = 1 } }, '`source%.cwd`.*valid directory path')\n  validate({ source = { cwd = 'not-existing-path' } }, '`source%.cwd`.*valid directory path')\n  validate({ source = { match = 1 } }, '`source%.match`.*callable')\n  validate({ source = { show = 1 } }, '`source%.show`.*callable')\n  validate({ source = { preview = 1 } }, '`source%.preview`.*callable')\n  validate({ source = { choose = 1 } }, '`source%.choose`.*callable')\n  validate({ source = { choose_marked = 1 } }, '`source%.choose_marked`.*callable')\n\n  validate({ window = { config = 1 } }, '`window%.config`.*table or callable')\nend\n\nT['start()']['respects `source.items`'] = function()\n  -- Array\n  start_with_items({ 'a', 'b' })\n  child.expect_screenshot()\n  stop()\n\n  -- Callable returning array of items\n  child.lua([[_G.items_callable_return = function() return { 'c', 'd' } end]])\n  child.lua_notify('MiniPick.start({ source = { items = _G.items_callable_return } })')\n  child.expect_screenshot()\n  stop()\n\n  -- Callable setting items manually\n  child.lua([[_G.items_callable_later = function() MiniPick.set_picker_items({ 'e', 'f' }) end]])\n  child.lua_notify('MiniPick.start({ source = { items = _G.items_callable_later } })')\n  child.poke_eventloop()\n  child.expect_screenshot()\n  stop()\n\n  -- Callable setting items manually *later*\n  child.lua([[_G.items_callable_later = function()\n    vim.schedule(function() MiniPick.set_picker_items({ 'g', 'h' }) end)\n  end]])\n  child.lua_notify('MiniPick.start({ source = { items = _G.items_callable_later } })')\n  child.poke_eventloop()\n  child.expect_screenshot()\n  stop()\n\n  -- Should execute callback items with `source.cwd` as current directory\n  eq(child.fn.getcwd() ~= test_dir_absolute, true)\n  child.lua('_G.cwd = ' .. vim.inspect(test_dir_absolute))\n  child.lua([[_G.items_callable_cwd = function()\n    _G.cur_cwd = vim.fn.getcwd()\n    return { 'u', 'v' }\n  end]])\n  child.lua_notify('MiniPick.start({ source = { items = _G.items_callable_cwd, cwd = _G.cwd } })')\n  eq(child.lua_get('_G.cur_cwd'), test_dir_absolute)\n  stop()\n\n  -- Problematic items\n  if child.fn.has('nvim-0.10') == 1 then\n    child.lua_notify('_G.res = MiniPick.start({ source = { items = { vim.uv.new_timer() } } })')\n    eq(child.lua_get('vim.tbl_map(type, MiniPick.get_picker_items())'), { 'userdata' })\n    type_keys('<CR>')\n    eq(child.lua_get('type(_G.res)'), 'userdata')\n  end\nend\n\nT['start()']['correctly computes stritems'] = function()\n  child.set_size(15, 80)\n  child.lua_notify([[MiniPick.start({ source = { items = {\n    'string_item',\n    { text = 'table_item' },\n    { a = 'fallback item', b = 1 },\n    function() return 'string_item_from_callable' end,\n    function() return { text = 'table_item_from_callable' } end,\n    function() return { c = 'fallback item from callable', d = 1 } end,\n  } } })]])\n  child.expect_screenshot()\nend\n\nT['start()']['resolves items after making picker active'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = function()\n      _G.picker_is_active = MiniPick.is_picker_active()\n      _G.picker_name = MiniPick.get_picker_opts().source.name\n      return { 'a', 'b' }\n    end,\n    name = 'This picker'\n  } })]])\n  eq(get_picker_stritems(), { 'a', 'b' })\n  eq(child.lua_get('_G.picker_is_active'), true)\n  eq(child.lua_get('_G.picker_name'), 'This picker')\nend\n\nT['start()']['respects `source.name`'] = function()\n  start({ source = { items = test_items, name = 'Hello' } })\n  validate_picker_option('source.name', 'Hello')\n  child.expect_screenshot()\nend\n\nT['start()']['respects `source.cwd`'] = function()\n  local lua_cmd = string.format(\n    [[MiniPick.start({ source = {\n      items = function() return { MiniPick.get_picker_opts().source.cwd } end,\n      cwd = %s,\n    } })]],\n    vim.inspect(test_dir)\n  )\n  child.lua_notify(lua_cmd)\n  local actual_cwd = get_picker_stritems()[1]\n  eq(actual_cwd, full_path(test_dir))\n  eq(actual_cwd:find('/$'), nil)\nend\n\nT['start()']['respects `source.match`'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = { 'a', 'b', 'c' },\n    match = function(...)\n      _G.match_args = { ... }\n      return { 2 }\n    end,\n  } })]])\n\n  child.expect_screenshot()\n  eq(get_picker_matches().all, { 'b' })\n  eq(child.lua_get('_G.match_args'), { { 'a', 'b', 'c' }, { 1, 2, 3 }, {} })\n\n  type_keys('x')\n  eq(get_picker_matches().all, { 'b' })\n  eq(child.lua_get('_G.match_args'), { { 'a', 'b', 'c' }, { 2 }, { 'x' } })\nend\n\nT['start()']['respects `source.show`'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = { 'a', { text = 'b' }, 'bb' },\n    show = function(buf_id, items_to_show, query, ...)\n      _G.show_args = { buf_id, items_to_show, query, ... }\n      -- Information about shown indexes should be up to date at this point\n      _G.shown_inds = MiniPick.get_picker_matches().shown_inds\n      local lines = vim.tbl_map(\n        function(x) return '__' .. (type(x) == 'table' and x.text or x) end,\n        items_to_show\n      )\n      vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n    end,\n  } })]])\n  local buf_id = get_picker_state().buffers.main\n\n  child.expect_screenshot()\n  eq(child.lua_get('_G.show_args'), { buf_id, { 'a', { text = 'b' }, 'bb' }, {} })\n  eq(child.lua_get('_G.shown_inds'), { 1, 2, 3 })\n\n  type_keys('b')\n  child.expect_screenshot()\n  eq(child.lua_get('_G.show_args'), { buf_id, { { text = 'b' }, 'bb' }, { 'b' } })\n  eq(child.lua_get('_G.shown_inds'), { 2, 3 })\nend\n\nT['start()']['respects `source.preview`'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = { 'a', { text = 'b' }, 'bb' },\n    preview = function(buf_id, item, ...)\n      _G.preview_args = { buf_id, item, ... }\n      local stritem = type(item) == 'table' and item.text or item\n      vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, { 'Preview: ' .. stritem })\n    end,\n  } })]])\n  local validate_preview_args = function(item_ref)\n    local preview_args = child.lua_get('_G.preview_args')\n    eq(child.api.nvim_buf_is_valid(preview_args[1]), true)\n    eq(preview_args[2], item_ref)\n  end\n\n  type_keys('<Tab>')\n\n  child.expect_screenshot()\n  validate_preview_args('a')\n  local preview_buf_id_1 = child.lua_get('_G.preview_args')[1]\n\n  type_keys('<C-n>')\n  child.expect_screenshot()\n  validate_preview_args({ text = 'b' })\n  eq(preview_buf_id_1 ~= child.lua_get('_G.preview_args')[1], true)\nend\n\nT['start()']['respects `source.choose`'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = { 'a', { text = 'b' }, 'bb' },\n    choose = function(...) _G.choose_args = { ... } end,\n  } })]])\n\n  type_keys('<C-n>', '<CR>')\n  eq(child.lua_get('_G.choose_args'), { { text = 'b' } })\n  eq(is_picker_active(), false)\nend\n\nT['start()']['respects `source.choose_marked`'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = { 'a', { text = 'b' }, 'bb' },\n    choose_marked = function(...) _G.choose_marked_args = { ... } end,\n  } })]])\n\n  type_keys('<C-x>', '<C-n>', '<C-x>', '<M-CR>')\n  eq(child.lua_get('_G.choose_marked_args'), { { 'a', { text = 'b' } } })\n  eq(is_picker_active(), false)\nend\n\nT['start()']['respects `delay.busy`'] = function()\n  local validate = function(is_busy)\n    local win_id = get_picker_state().windows.main\n    local ref_winhl = 'FloatBorder:MiniPickBorder' .. (is_busy and 'Busy' or '')\n    expect.match(child.api.nvim_win_get_option(win_id, 'winhighlight'), ref_winhl)\n  end\n\n  child.lua_notify(string.format('MiniPick.start({ delay = { busy = %d } })', 0.5 * default_busy_delay))\n\n  validate(false)\n  sleep(0.5 * default_busy_delay + small_time)\n  validate(true)\nend\n\nT['start()']['respects `mappings`'] = function()\n  start({ source = { items = { 'a', 'b' } }, mappings = { stop = 'c' } })\n  eq(is_picker_active(), true)\n  type_keys('a')\n  eq(is_picker_active(), true)\n  type_keys('c')\n  eq(is_picker_active(), false)\nend\n\nT['start()']['respects `options.content_from_bottom`'] = function()\n  start({ source = { items = { 'a', 'b' } }, options = { content_from_bottom = true } })\n  child.expect_screenshot()\nend\n\nT['start()']['respects `options.use_cache`'] = function()\n  local validate_match_calls = make_match_with_count()\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'bb' }, match = _G.match_with_count },\n    options = { use_cache = true },\n  })]])\n  validate_match_calls(0, { 1, 2, 3 })\n\n  type_keys('b')\n  validate_match_calls(1, { 2, 3 })\n\n  type_keys('b')\n  validate_match_calls(2, { 3 })\n\n  type_keys('<BS>')\n  validate_match_calls(2, { 2, 3 })\n\n  type_keys('<BS>')\n  validate_match_calls(2, { 1, 2, 3 })\n\n  type_keys('b')\n  validate_match_calls(2, { 2, 3 })\n\n  type_keys('x')\n  validate_match_calls(3, {})\nend\n\nT['start()']['allows custom mappings'] = function()\n  -- Should prefer custom action over built-ins (even hard-coded alternatives)\n  child.lua('MiniPick.config.mappings.custom_bs = { char = \"<BS>\", func = function() _G.custom_bs = true end }')\n  child.lua('MiniPick.config.mappings.custom_home = { char = \"<Home>\", func = function() _G.custom_home = true end }')\n\n  -- Should work in global and local config\n  child.lua([[MiniPick.config.mappings.custom_global = {\n    char = '<C-d>',\n    -- Should be executed with source's cwd set as current directory\n    func = function(...) _G.cur_cwd, _G.args_global = vim.fn.getcwd(), { ... } end,\n  }]])\n\n  child.lua('_G.cwd = ' .. vim.inspect(test_dir_absolute))\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'ab', 'b' }, cwd = _G.cwd },\n    mappings = {\n      -- Return value is treated as \"should stop picker after execution\"\n      custom = { char = 'm', func = function(...) _G.args_local = { ... }; return true end },\n    },\n  })]])\n\n  type_keys('<C-d>')\n  eq(child.lua_get('_G.cur_cwd'), test_dir_absolute)\n  eq(child.lua_get('_G.args_global'), {})\n  eq(is_picker_active(), true)\n\n  type_keys('a', '<BS>')\n  eq(child.lua_get('_G.custom_bs'), true)\n  eq(get_picker_query(), { 'a' })\n\n  type_keys('<Down>', '<Home>')\n  eq(child.lua_get('_G.custom_home'), true)\n  eq(get_picker_matches().current_ind, 2)\n\n  type_keys('m')\n  eq(child.lua_get('_G.args_local'), {})\n  eq(is_picker_active(), false)\nend\n\nT['start()']['allows overriding built-in mappings'] = function()\n  -- Both in global/local config **but** only as strings\n  child.lua([[MiniPick.config.mappings.caret_left = '<C-e>']])\n\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b' } },\n    mappings = { caret_right = 'm' },\n  })]])\n\n  type_keys('a')\n  eq(get_picker_state().caret, 2)\n  type_keys('<C-e>')\n  eq(get_picker_state().caret, 1)\n  type_keys('m')\n  eq(get_picker_state().caret, 2)\nend\n\nT['start()']['warns about duplicating mappings'] = function()\n  child.lua_notify([[\n    _G.log = {}\n    vim.notify = function(...) table.insert(_G.log, { ... }) end\n    MiniPick.start({\n      source = { 'a' },\n      -- This is duplicating among themselves (since <C-i> and <Tab> are the\n      -- same for `getcharstr()`) and with `toggle_preview`\n      mappings = { move_down = '<Tab>', toggle_info = '<C-i>' },\n    })\n  ]])\n\n  local validate_notif = function(out)\n    eq(#out, 2)\n\n    expect.match(out[1], '%(mini%.pick%) Duplicating mapping keys: ')\n    local does_match = out[1]:find('move_down') ~= nil\n      or out[1]:find('toggle_info') ~= nil\n      or out[1]:find('toggle_preview') ~= nil\n    eq(does_match, true)\n\n    eq(out[2], child.lua_get('vim.log.levels.WARN'))\n  end\n\n  local log = child.lua_get('_G.log')\n  eq(#log, 2)\n  validate_notif(log[1])\n  validate_notif(log[2])\nend\n\nT['start()']['works with language mappings'] = function()\n  if child.fn.has('nvim-0.10') == 0 then\n    MiniTest.skip('Helper function that gets language mappings is available only on Neovim>=0.10')\n  end\n  child.o.keymap = 'ukrainian-jcuken'\n  eq(child.o.iminsert, 1)\n\n  start_with_items({})\n  type_keys('g', 'h')\n  eq(get_picker_query(), { 'п', 'р' })\n  type_keys('<C-u>')\n\n  -- Should allow changing 'iminsert' while picker is active\n  child.o.iminsert = 0\n  type_keys('g', 'h')\n  eq(get_picker_query(), { 'g', 'h' })\n  type_keys('<C-c>')\n\n  -- Should work with custom \"good\" language mappings\n  child.o.keymap = ''\n  child.o.iminsert = 1\n  child.cmd('lmap a 1')\n  child.cmd('lmap b <char-0x1f171>')\n  child.cmd('lmap cc C')\n\n  start_with_items({})\n  type_keys('a', 'b', 'c', 'c')\n  eq(get_picker_query(), { '1', 'b', 'c', 'c' })\n  type_keys('<C-u>')\n\n  -- Should cache language mappings per picker session\n  child.cmd('lmap d 4')\n  type_keys('d')\n  eq(get_picker_query(), { 'd' })\nend\n\nT['start()']['respects `window.config`'] = function()\n  -- As table\n  start({ source = { items = { 'a', 'b', 'c' } }, window = { config = { border = 'double' } } })\n  child.expect_screenshot()\n  stop()\n\n  -- As callable\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'c' } },\n    window = { config = function() return { anchor = 'NW', row = 2, width = vim.o.columns } end },\n  })]])\n  child.expect_screenshot()\n  stop()\nend\n\nT['start()']['respects `window.prompt_caret`'] = function()\n  start({ source = { items = { 'a', 'b', 'c' } }, window = { prompt_caret = '+' } })\n  child.expect_screenshot()\n  type_keys('a', 'b', '<Left>')\n  child.expect_screenshot()\nend\n\nT['start()']['respects `window.prompt_prefix`'] = function()\n  local validate = function(prefix)\n    start({ source = { items = { 'a', 'b', 'c' } }, window = { prompt_prefix = prefix } })\n    child.expect_screenshot()\n    type_keys('a', 'b', '<Left>')\n    child.expect_screenshot()\n    type_keys('<C-c>')\n  end\n\n  validate('$>  ')\n  validate('')\nend\n\nT['start()']['stops currently active picker'] = function()\n  start_with_items({ 'a', 'b', 'c' })\n  eq(is_picker_active(), true)\n  start_with_items({ 'd', 'e', 'f' })\n  sleep(small_time)\n  child.expect_screenshot()\nend\n\nT['start()']['stops improperly aborted previous picker'] = function()\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'c' } },\n    mappings = { error = { char = 'e', func = function() error() end } },\n  })]])\n  child.expect_screenshot()\n  type_keys('e')\n\n  start({ source = { items = { 'd', 'e', 'f' } }, window = { config = { width = 10 } } })\n  child.expect_screenshot()\nend\n\nT['start()']['triggers `MiniPickStart` User event'] = function()\n  make_event_log()\n  child.cmd('au User MiniPickStart lua _G.track_event()')\n  start_with_items(test_items)\n\n  -- User event should be triggered when all elements are usually set\n  eq(child.lua_get('_G.event_log'), { #test_items })\nend\n\nT['start()']['can be called in non-Normal modes'] = function()\n  child.lua('_G.choose = function() vim.schedule(function() _G.cur_mode = vim.fn.mode(1) end) end')\n  local validate = function()\n    local cur_mode = child.fn.mode(1)\n    eq(cur_mode ~= 'n', true)\n    child.lua_notify([[MiniPick.start({ source = { items = { 'a' }, choose = _G.choose } })]])\n    type_keys('<CR>')\n    eq(child.lua_get('_G.cur_mode'), cur_mode)\n\n    -- Cleanup\n    child.lua('_G.cur_mode = nil')\n  end\n\n  -- Insert mode\n  type_keys('i')\n  validate()\n  child.ensure_normal_mode()\n\n  -- Command mode\n  type_keys(':')\n  validate()\n  child.ensure_normal_mode()\n\n  -- Operator-pending mode\n  type_keys('d')\n  validate()\n  child.ensure_normal_mode()\n\n  -- Doesn't work in Visual mode as opening floating window stops it.\n  -- Use `gv` in picker if want to preserve Visual mode.\nend\n\nT['start()']['respects global config'] = function()\n  child.lua([[MiniPick.config.window.config = { anchor = 'NW', row = 1 }]])\n  start_with_items({ 'a', 'b', 'c' })\n  child.expect_screenshot()\nend\n\nT['start()']['respects `vim.b.minipick_config`'] = function()\n  child.lua([[MiniPick.config.window.config = { anchor = 'NW', row = 1 }]])\n  child.b.minipick_config = { window = { config = { row = 3, width = 10 } } }\n  start_with_items({ 'a', 'b', 'c' })\n  child.expect_screenshot()\nend\n\nT['stop()'] = new_set()\n\nT['stop()']['works'] = function()\n  start_with_items(test_items)\n  child.expect_screenshot()\n  stop()\n  child.expect_screenshot()\n  eq(is_picker_active(), false)\nend\n\nT['stop()']['can be called without active picker'] = function() expect.no_error(stop) end\n\nT['stop()']['triggers `MiniPickStop` User event'] = function()\n  make_event_log()\n  child.cmd('au User MiniPickStop lua _G.track_event()')\n  start_with_items(test_items)\n  stop()\n  -- User event should be triggered while buffer is still valid\n  eq(child.lua_get('_G.event_log'), { #test_items })\nend\n\nT['refresh()'] = new_set()\n\nlocal refresh = forward_lua('MiniPick.refresh')\n\nT['refresh()']['works'] = function()\n  start_with_items(test_items)\n  child.expect_screenshot()\n\n  child.lua('MiniPick.set_picker_opts({ window = { config = { width = 10 } } })')\n  refresh()\n  child.expect_screenshot()\nend\n\nT['refresh()']['is called on `VimResized`'] = function()\n  child.set_size(15, 40)\n  start_with_items(test_items)\n  child.expect_screenshot()\n\n  child.set_size(15, 20)\n  child.expect_screenshot()\nend\n\nT['refresh()']['can be called without active picker'] = function() expect.no_error(refresh) end\n\nT['refresh()']['recomputes window config'] = function()\n  child.lua([[\n    _G.width = 0\n    _G.win_config = function()\n      _G.width = _G.width + 10\n      return { width = _G.width }\n    end\n  ]])\n\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a', 'b', 'c' } }, window = { config = _G.win_config } })]])\n  child.expect_screenshot()\n  refresh()\n  child.expect_screenshot()\nend\n\nT['default_match()'] = new_set()\n\nlocal default_match = forward_lua('MiniPick.default_match')\n\nlocal validate_match = function(stritems, query, output_ref)\n  eq(default_match(stritems, seq_along(stritems), query), output_ref)\nend\n\nT['default_match()']['works with active picker'] = function()\n  start_with_items(test_items)\n  type_keys('a')\n  child.expect_screenshot()\n  type_keys('b')\n  child.expect_screenshot()\nend\n\nT['default_match()']['does not block query update'] = function()\n  child.lua('_G.small_time = ' .. small_time)\n  child.lua([[\n    -- Mock slow matching\n    local find_orig = string.find\n    string.find = function(...)\n      vim.loop.sleep(_G.small_time)\n      return find_orig(...)\n    end\n\n    -- Track usage of `set_picker_match_inds`\n    _G.log = {}\n    local set_picker_match_inds_orig = MiniPick.set_picker_match_inds\n    MiniPick.set_picker_match_inds = function(match_inds)\n      table.insert(_G.log, #match_inds)\n      return set_picker_match_inds(match_inds)\n    end\n\n    -- Should use `async` from the picker, not global\n    MiniPick.config.delay.async = 1000\n  ]])\n  child.lua_notify('MiniPick.start({ delay = { async = 1 } })')\n\n  set_picker_items({ 'ab', 'ac', 'bb' })\n  sleep(4 * small_time)\n\n  -- Type three characters very quickly. If `default_match()` were blocking,\n  -- each press would be done after matches from previous ones are set. The\n  -- goal is for each key press to stop active matching and start a new one.\n  -- This test is not ideal, but is the best attempt at testing this.\n  type_keys('abc')\n  eq(child.lua_get('_G.log'), { 3, 0 })\n\n  -- Should work for both fuzzy and exact matching\n  type_keys('<C-u>')\n  child.lua('_G.log = {}')\n  type_keys(\"'abc\")\n  eq(child.lua_get('_G.log'), { 3, 0 })\nend\n\nT['default_match()']['works without active picker'] = function()\n  local stritems, query = { 'aab', 'ac', 'ab' }, { 'a', 'b' }\n  eq(default_match(stritems, { 1, 2, 3 }, query), { 3, 1 })\n  eq(default_match(stritems, { 2, 3 }, query), { 3 })\nend\n\nT['default_match()']['works with empty inputs'] = function()\n  local match_inds, stritems, query = seq_along(test_items), { 'ab', 'cd' }, { 'a' }\n  eq(default_match(stritems, {}, query), {})\n  eq(default_match({}, {}, query), {})\n  eq(default_match(stritems, match_inds, {}), seq_along(stritems))\nend\n\nT['default_match()']['filters items that match query with gaps'] = function()\n  -- Regular cases\n  validate_match({ 'a__', 'b' }, { 'a' }, { 1 })\n  validate_match({ '_a_', 'b' }, { 'a' }, { 1 })\n  validate_match({ '__a', 'b' }, { 'a' }, { 1 })\n  validate_match({ 'b', 'a__' }, { 'a' }, { 2 })\n  validate_match({ 'b', '_a_' }, { 'a' }, { 2 })\n  validate_match({ 'b', '__a' }, { 'a' }, { 2 })\n\n  validate_match({ 'a', 'ab', 'a_b', 'a_b_b', 'ba' }, { 'a', 'b' }, { 2, 3, 4 })\n  validate_match({ 'a', 'ab', 'a_b', 'a_b_b', 'ba' }, { 'a', 'b', 'b' }, { 4 })\n\n  validate_match({ 'a', 'ab', 'axb', 'a?b', 'a\\tb' }, { 'a', 'b' }, { 2, 3, 4, 5 })\n\n  -- Non-single-char-entries queries (each should match exactly)\n  validate_match({ 'a', 'b', 'ab_', 'a_b', '_ab' }, { 'ab' }, { 3, 5 })\n  validate_match({ 'abcd_', '_abcd', 'a_bcd', 'ab_cd', 'abc_d' }, { 'ab', 'cd' }, { 1, 2, 4 })\n\n  -- Edge casees\n  validate_match({ 'a', 'b', '' }, { 'a' }, { 1 })\n\n  validate_match({ 'a', 'b', '' }, { '' }, { 1, 2, 3 })\n  validate_match({ 'a', 'b', '' }, { '', '' }, { 1, 2, 3 })\nend\n\nT['default_match()']['sorts by match width -> match start -> item index'] = function()\n  local query_ab, query_abc = { 'a', 'b' }, { 'a', 'b', 'c' }\n\n  -- Width differs\n  validate_match({ 'ab', 'a_b', 'a__b' }, query_ab, { 1, 2, 3 })\n  validate_match({ 'ab', 'a__b', 'a_b' }, query_ab, { 1, 3, 2 })\n  validate_match({ 'a__b', 'ab', 'a_b' }, query_ab, { 2, 3, 1 })\n  validate_match({ 'a_b', 'ab', 'a__b' }, query_ab, { 2, 1, 3 })\n  validate_match({ 'a_b', 'a__b', 'ab' }, query_ab, { 3, 1, 2 })\n  validate_match({ 'a__b', 'a_b', 'ab' }, query_ab, { 3, 2, 1 })\n\n  validate_match({ '_a__b', '_a_b', '_ab' }, query_ab, { 3, 2, 1 })\n\n  validate_match({ 'a__b_a___b', 'a_b_a___b', 'ab_a___b' }, query_ab, { 3, 2, 1 })\n\n  validate_match({ 'a_b_c', 'a_bc', 'abc' }, query_abc, { 3, 2, 1 })\n  validate_match({ '_a_b_c', '_a_bc', '_abc' }, query_abc, { 3, 2, 1 })\n  validate_match({ 'a_b_c_a__b__c', 'a_bc_a__b__c', 'abc_a__b__c' }, query_abc, { 3, 2, 1 })\n\n  validate_match({ 'ab__cd', 'ab_cd', 'abcd' }, { 'ab', 'cd' }, { 3, 2, 1 })\n\n  -- Start differs with equal width\n  validate_match({ 'ab', '_ab', '__ab' }, query_ab, { 1, 2, 3 })\n  validate_match({ 'ab', '__ab', '_ab' }, query_ab, { 1, 3, 2 })\n  validate_match({ '_ab', 'ab', '__ab' }, query_ab, { 2, 1, 3 })\n  validate_match({ '__ab', 'ab', '_ab' }, query_ab, { 2, 3, 1 })\n  validate_match({ '_ab', '__ab', 'ab' }, query_ab, { 3, 1, 2 })\n  validate_match({ '__ab', '_ab', 'ab' }, query_ab, { 3, 2, 1 })\n\n  validate_match({ '__abc', '_abc', 'abc' }, query_abc, { 3, 2, 1 })\n\n  validate_match({ '__abc_a_b_c', '_abc_a_b_c', 'abc_a_b_c' }, query_abc, { 3, 2, 1 })\n  validate_match({ 'a_b_c__abc', 'a_b_c_abc', 'a_b_cabc' }, query_abc, { 3, 2, 1 })\n\n  validate_match({ '__a_b_c', '_a__bc', 'ab__c' }, query_abc, { 3, 2, 1 })\n\n  validate_match({ '__ab_cd_e', '_ab__cde', 'abcd__e' }, { 'ab', 'cd', 'e' }, { 3, 2, 1 })\n\n  -- Index differs with equal width and start\n  validate_match({ 'a_b_c', 'a__bc', 'ab__c' }, query_abc, { 1, 2, 3 })\n  validate_match({ 'axbxc', 'a??bc', 'ab\\t\\tc' }, query_abc, { 1, 2, 3 })\n\n  validate_match({ 'ab_cd_e', 'ab__cde', 'abcd__e' }, { 'ab', 'cd', 'e' }, { 1, 2, 3 })\nend\n\nT['default_match()']['filters and sorts'] = function()\n  validate_match({ 'a_b_c', 'abc', 'a_b_b', 'c_a_a', 'b_c_c' }, { 'a', 'b' }, { 2, 1, 3 })\n  validate_match({ 'xabcd', 'axbcd', 'abxcd', 'abcxd', 'abcdx' }, { 'ab', 'cd' }, { 5, 1, 3 })\nend\n\nT['default_match()']['respects special queries'] = function()\n  --stylua: ignore\n  local stritems = {\n    '*abc',    -- 1\n    '_*_a_bc', -- 2\n    \"'abc\",    -- 3\n    \"_'_a_bc\", -- 4\n    '^abc',    -- 5\n    '_^_a_bc', -- 6\n    'abc$',    -- 7\n    'ab_c_$_', -- 8\n    'a b c',   -- 9\n    ' a  bc',  -- 10\n  }\n  local all_inds = seq_along(stritems)\n  local validate = function(query, output_ref) validate_match(stritems, query, output_ref) end\n  local validate_same_as = function(query, query_ref)\n    eq(default_match(stritems, all_inds, query), default_match(stritems, all_inds, query_ref))\n  end\n\n  -- Precedence:\n  -- \"forced fuzzy\" = \"forced exact\" > \"exact start/end\" > \"grouped fuzzy\"\n\n  -- Forced fuzzy\n  validate_same_as({ '*' }, { '' })\n  validate_same_as({ '*', 'a' }, { 'a' })\n  validate_same_as({ '*', 'a', 'b' }, { 'a', 'b' })\n\n  validate({ '*', '*', 'a' }, { 1, 2 })\n  validate({ '*', \"'\", 'a' }, { 3, 4 })\n  validate({ '*', '^', 'a' }, { 5, 6 })\n  validate({ '*', 'a', '$' }, { 7, 8 })\n  validate({ '*', 'a', ' ', 'b' }, { 9, 10 })\n\n  -- Forced exact\n  validate_same_as({ \"'\" }, { '' })\n  validate_same_as({ \"'\", 'a' }, { 'a' })\n  validate_same_as({ \"'\", 'a', 'b' }, { 'ab' })\n\n  validate({ \"'\", '*', 'a' }, { 1 })\n  validate({ \"'\", \"'\", 'a' }, { 3 })\n  validate({ \"'\", '^', 'a' }, { 5 })\n  validate({ \"'\", 'c', '$' }, { 7 })\n  validate({ \"'\", 'a', ' ', 'b' }, { 9 })\n\n  -- Exact start\n  validate_same_as({ '^' }, { '' })\n  validate({ '^', 'a' }, { 7, 8, 9 })\n  validate({ '^', 'a', 'b' }, { 7, 8 })\n\n  validate({ '^', '^', 'a' }, { 5 })\n  validate({ '^', \"'\", 'a' }, { 3 })\n  validate({ '^', '*', 'a' }, { 1 })\n  validate({ '^', ' ', 'a' }, { 10 })\n\n  -- Exact end\n  validate({ '$' }, all_inds)\n  validate({ 'c', '$' }, { 1, 3, 5, 9, 10, 2, 4, 6 })\n  validate({ 'b', 'c', '$' }, { 1, 3, 5, 10, 2, 4, 6 })\n\n  validate({ ' ', 'c', '$' }, { 9 })\n\n  -- Grouped\n  validate_same_as({ 'a', ' ' }, { 'a' })\n  validate_same_as({ 'a', ' ', ' ' }, { 'a' })\n  validate_same_as({ 'a', ' ', 'b' }, { 'a', 'b' })\n  validate_same_as({ 'a', ' ', ' ', 'b' }, { 'a', 'b' })\n  validate_same_as({ 'a', ' ', 'b', ' ' }, { 'a', 'b' })\n  validate_same_as({ 'a', ' ', 'b', ' ', 'c' }, { 'a', 'b', 'c' })\n  validate_same_as({ 'a', ' ', 'b', ' ', ' ', 'c' }, { 'a', 'b', 'c' })\n  validate_same_as({ 'a', ' ', 'b', ' ', 'c', ' ' }, { 'a', 'b', 'c' })\n\n  validate({ 'a', 'b', ' ', 'c' }, { 7, 1, 3, 5, 8 })\n  validate({ 'a', ' ', 'b', 'c' }, { 7, 1, 3, 5, 2, 4, 6, 10 })\n  validate({ 'a', 'b', 'c', ' ' }, { 7, 1, 3, 5 })\n\n  validate({ 'ab', ' ', 'c' }, { 7, 1, 3, 5, 8 })\n\n  -- - Whitespace inside non-whitespace elements shouldn't matter\n  validate({ 'a b', ' ', 'c' }, { 9 })\n\n  -- - Amount and type of whitespace inside \"split\" elements shouldn't matter\n  validate_same_as({ 'ab', '  ', 'c' }, { 'ab', ' ', 'c' })\n  validate_same_as({ 'ab', '\\t', 'c' }, { 'ab', ' ', 'c' })\n\n  -- - Only whitespace is allowed\n  validate_same_as({ ' ' }, { '' })\n  validate_same_as({ ' ', ' ' }, { '' })\n\n  -- Combination\n  validate_same_as({ '^', '$' }, { '' })\n  validate({ '^', 'a', ' ', 'b', ' ', 'c', '$' }, { 9 })\n\n  -- Not special\n  validate({ 'a', '*' }, {})\n  validate({ 'a', \"'\" }, {})\n  validate({ 'a', '^' }, {})\n  validate({ '$', 'a' }, {})\nend\n\nT['default_match()']['only input indexes can be in the output'] = function()\n  eq(default_match({ 'a', '_a', '__a', 'b' }, { 1, 2, 4 }, { 'a' }), { 1, 2 })\n\n  -- Special modes\n  eq(default_match({ 'a', '_a', '__a', 'b' }, { 1, 2, 4 }, { \"'\", 'a' }), { 1, 2 })\n  eq(default_match({ 'a', '_a', '__a', 'b' }, { 1, 2, 4 }, { '*', 'a' }), { 1, 2 })\n  eq(default_match({ 'a', 'a_', 'a__', 'b' }, { 1, 2, 4 }, { '^', 'a' }), { 1, 2 })\n  eq(default_match({ 'a', '_a', '__a', 'b' }, { 1, 2, 4 }, { 'a', '$' }), { 1, 2 })\n\n  eq(default_match({ 'abc', 'ab_c', 'ab__c', 'a_b_c' }, { 1, 2, 4 }, { 'a', 'b', ' ', 'c' }), { 1, 2 })\nend\n\nT['default_match()']['works with multibyte characters'] = function()\n  -- In query\n  validate_match({ 'ы', 'ф', 'd' }, { 'ы' }, { 1 })\n\n  validate_match({ 'ы__ф', 'ы_ф', 'ыф', 'ы', 'фы' }, { 'ы', 'ф' }, { 3, 2, 1 })\n  validate_match({ '__ыф', '_ыф', 'ыф' }, { 'ы', 'ф' }, { 3, 2, 1 })\n  validate_match({ '__ы_ф_я', '__ы__фя', '__ыф__я' }, { 'ы', 'ф', 'я' }, { 1, 2, 3 })\n\n  validate_match({ 'ы_ф', '_ыф', 'ы' }, { '*', 'ы', 'ф' }, { 2, 1 })\n  validate_match({ 'ы_ф', '_ыф', 'ы' }, { \"'\", 'ы', 'ф' }, { 2 })\n  validate_match({ 'ы_ф', '_ыф', 'ы' }, { '^', 'ы' }, { 1, 3 })\n  validate_match({ 'ы_ф', '_ыф', 'ы' }, { 'ф', '$' }, { 1, 2 })\n  validate_match({ 'ыы_ф', 'ы_ыф' }, { 'ы', 'ы', ' ', 'ф' }, { 1 })\n\n  validate_match({ '_│_│', '│_│_', '_│_' }, { '│', '│' }, { 2, 1 })\n\n  validate_match({ 'ыdф', '_ы_d_ф' }, { 'ы', 'd', 'ф' }, { 1, 2 })\n\n  -- In stritems\n  validate_match({ 'aыbыc', 'abыc' }, { 'a', 'b', 'c' }, { 2, 1 })\nend\n\nT['default_match()']['works with special characters'] = function()\n  -- function() validate_match('(.+*%-)', 'a(a.a+a*a%a-a)', { 2, 4, 6, 8, 10, 12, 14 }) end\n  local validate_match_special_char = function(char)\n    local stritems = { 'a' .. char .. 'b', 'a_b' }\n    validate_match(stritems, { char }, { 1 })\n    validate_match(stritems, { 'a', char, 'b' }, { 1 })\n  end\n\n  validate_match_special_char('.')\n  validate_match_special_char('+')\n  validate_match_special_char('%')\n  validate_match_special_char('-')\n  validate_match_special_char('(')\n  validate_match_special_char(')')\n\n  validate_match({ 'a*b', 'a_b' }, { 'a', '*', 'b' }, { 1 })\n  validate_match({ 'a^b', 'a_b' }, { 'a', '^', 'b' }, { 1 })\n  validate_match({ 'a$b', 'a_b' }, { 'a', '$', 'b' }, { 1 })\nend\n\nT['default_match()']['respects case'] = function()\n  -- Ignore and smart case should come from how picker uses `source.match`\n  validate_match({ 'ab', 'aB', 'Ba', 'AB' }, { 'a', 'b' }, { 1 })\n  validate_match({ 'ab', 'aB', 'Ba', 'AB' }, { 'a', 'B' }, { 2 })\nend\n\nT['default_match()']['respects `opts.sync`'] = function()\n  start_with_items({ 'aa', 'ab', 'bb' })\n  -- Should process synchronously and return output even if picker is active\n  eq(child.lua_get([[MiniPick.default_match({'xx', 'xy', 'yy'}, { 1, 2, 3 }, { 'y' }, { sync = true })]]), { 3, 2 })\n  eq(get_picker_matches().all, { 'aa', 'ab', 'bb' })\nend\n\nT['default_match()']['respects `opts.preserve_order`'] = function()\n  child.lua_notify([[\n    local opts = { preserve_order = true }\n    local match_nosort = function(stritems, inds, query)\n      MiniPick.default_match(stritems, inds, query, opts)\n    end\n    MiniPick.start({ source = { items = { 'axay', 'b', 'aaxy', 'ccc', 'xaa' }, match = match_nosort } })\n  ]])\n  type_keys('x')\n  eq(get_picker_matches().all_inds, { 1, 3, 5 })\n  type_keys('y')\n  eq(get_picker_matches().all_inds, { 1, 3 })\nend\n\nT['default_show()'] = new_set({ hooks = { pre_case = function() child.set_size(10, 20) end } })\n\nlocal default_show = forward_lua('MiniPick.default_show')\n\nT['default_show()']['works'] = function()\n  child.set_size(15, 40)\n  start_with_items({ 'abc', 'a_bc', 'a__bc' })\n  type_keys('a', 'b')\n  child.expect_screenshot()\nend\n\nT['default_show()']['works without active picker'] = function()\n  -- Allows 0 buffer id for current buffer\n  default_show(0, { 'abc', 'a_bc', 'a__bc' }, { 'a', 'b' })\n  child.expect_screenshot()\n\n  -- Allows non-current buffer\n  local new_buf_id = child.api.nvim_create_buf(false, true)\n  default_show(new_buf_id, { 'def', 'd_ef', 'd__ef' }, { 'd', 'e' })\n  child.api.nvim_set_current_buf(new_buf_id)\n  child.expect_screenshot()\nend\n\nT['default_show()']['shows best match'] = function()\n  default_show(0, { 'a__b_a__b_ab', 'a__b_ab_a__b', 'ab_a__b_a__b', 'ab__ab' }, { 'a', 'b' })\n  child.expect_screenshot()\n\n  default_show(0, { 'aabbccddee' }, { 'a', 'b', 'c', 'd', 'e' })\n  child.expect_screenshot()\nend\n\nT['default_show()']['respects `opts.show_icons`'] = function()\n  child.set_size(13, 45)\n\n  child.cmd('edit ' .. vim.fn.fnameescape(join_path(test_dir, 'file')))\n  local buf_id = child.api.nvim_get_current_buf()\n  child.cmd('enew')\n\n  local items = vim.tbl_map(real_file, vim.fn.readdir(real_files_dir))\n  table.insert(items, test_dir)\n  table.insert(items, join_path(test_dir, 'file'))\n  table.insert(items, 'non-existing')\n  table.insert(items, { text = 'non-string' })\n  table.insert(items, { path = join_path(test_dir, 'builtin-tests', 'file'), text = 'prefer-path-field' })\n  table.insert(items, { buf_id = buf_id, text = 'buffer-prefer-path-field', path = test_dir })\n  table.insert(items, { buf_id = buf_id, text = 'buffer-use-buf-name' })\n  local query = { 'i', 'i' }\n\n  -- Without 'mini.icons'\n  default_show(0, items, query, { show_icons = true })\n  child.expect_screenshot()\n\n  -- With 'mini.icons'\n  child.lua('require(\"mini.icons\").setup()')\n  default_show(0, items, query, { show_icons = true })\n  child.expect_screenshot()\n\n  -- Should still prefer 'mini.icons' even if 'nvim-web-devicons' is present\n  child.cmd('set rtp+=tests/dir-pick')\n  default_show(0, items, query, { show_icons = true })\n  child.expect_screenshot()\n\n  -- With fallback 'nvim-web-devicons'\n  child.lua('_G.MiniIcons = nil')\n  default_show(0, items, query, { show_icons = true })\n  child.expect_screenshot()\nend\n\nT['default_show()']['respects `opts.icons`'] = function()\n  child.set_size(10, 45)\n  local items = vim.tbl_map(real_file, vim.fn.readdir(real_files_dir))\n  table.insert(items, test_dir)\n  table.insert(items, join_path(test_dir, 'file'))\n  table.insert(items, 'non-existing')\n  table.insert(items, { text = 'non-string' })\n  local query = { 'i', 'i' }\n\n  local icon_opts = { show_icons = true, icons = { directory = 'DD', file = 'FF', none = 'NN' } }\n\n  -- Without 'mini.icons'\n  default_show(0, items, query, icon_opts)\n  child.expect_screenshot()\n\n  -- With 'mini.icons'\n  child.lua('require(\"mini.icons\").setup()')\n  default_show(0, items, query, icon_opts)\n  -- - Should use \"file\" and \"directory\" defaults from 'mini.icons'\n  child.expect_screenshot()\n\n  -- With 'nvim-web-devicons'\n  child.lua('_G.MiniIcons = nil')\n  child.cmd('set rtp+=tests/dir-pick')\n  default_show(0, items, query, icon_opts)\n  child.expect_screenshot()\nend\n\nT['default_show()']['handles stritems with non-trivial whitespace'] = function()\n  child.o.tabstop = 3\n  default_show(0, { 'With\\nnewline', 'With\\rCR', 'EndsWithCR\\r', 'EndsWithNL\\n', 'EndsWithCRLF\\r\\n', 'With\\ttab' }, {})\n  child.expect_screenshot()\nend\n\nT['default_show()'][\"respects 'ignorecase'/'smartcase'\"] = function()\n  child.set_size(7, 12)\n  local items = { 'a_b', 'a_B', 'A_b', 'A_B' }\n\n  local validate = function()\n    default_show(0, items, { 'a', 'b' })\n    child.expect_screenshot()\n    default_show(0, items, { 'a', 'B' })\n    child.expect_screenshot()\n  end\n\n  -- Respect case\n  child.o.ignorecase, child.o.smartcase = false, false\n  validate()\n\n  -- Ignore case\n  child.o.ignorecase, child.o.smartcase = true, false\n  validate()\n\n  -- Smart case\n  child.o.ignorecase, child.o.smartcase = true, true\n  validate()\nend\n\nT['default_show()']['handles query similar to `default_match`'] = function()\n  child.set_size(15, 15)\n  local items = { 'abc', '_abc', 'a_bc', 'ab_c', 'abc_', '*abc', \"'abc\", '^abc', 'abc$', 'a b c' }\n\n  local validate = function(query)\n    default_show(0, items, query)\n    child.expect_screenshot()\n  end\n\n  validate({ '*', 'a', 'b' })\n  validate({ \"'\", 'a', 'b' })\n  validate({ '^', 'a', 'b' })\n  validate({ 'b', 'c', '$' })\n  validate({ 'a', 'b', ' ', 'c' })\nend\n\nT['default_show()']['works with multibyte characters'] = function()\n  local items = { 'ыdф', 'ыы_d_ф', '_ыы_d_ф' }\n\n  -- In query\n  default_show(0, items, { 'ы', 'ф' })\n  child.expect_screenshot()\n\n  -- Not in query\n  default_show(0, items, { 'd' })\n  child.expect_screenshot()\nend\n\nT['default_show()']['works with non-single-char-entries queries'] = function()\n  local items = { '_abc', 'a_bc', 'ab_c', 'abc_' }\n  local validate = function(query)\n    default_show(0, items, query)\n    child.expect_screenshot()\n  end\n\n  validate({ 'ab', 'c' })\n  validate({ 'abc' })\n  validate({ 'a b', ' ', 'c' })\nend\n\nT['default_show()']['handles edge cases'] = function()\n  child.set_size(5, 15)\n\n  -- Should not treat empty string as directory\n  default_show(0, { '\\0001', '\\0001\\0001' }, {}, { show_icons = true })\n  child.expect_screenshot()\nend\n\nT['default_preview()'] = new_set()\n\nlocal default_preview = forward_lua('MiniPick.default_preview')\n\nlocal validate_preview = function(items)\n  start_with_items(items)\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  for _ = 1, (#items - 1) do\n    type_keys('<C-n>')\n    child.expect_screenshot()\n  end\nend\n\nT['default_preview()']['works'] = function() validate_preview({ real_file('b.txt') }) end\n\nT['default_preview()']['works without active picker'] = function()\n  -- Allows 0 buffer id for current buffer\n  default_preview(0, real_file('b.txt'))\n  child.expect_screenshot()\n\n  -- Allows non-current buffer\n  local new_buf_id = child.api.nvim_create_buf(false, true)\n  default_preview(new_buf_id, real_file('LICENSE'))\n  child.api.nvim_set_current_buf(new_buf_id)\n  child.expect_screenshot()\nend\n\nT['default_preview()']['can be used in outside preview window'] = function()\n  -- This is not a module's capabilitiy per se, but something it should allow\n  local item = { path = real_file('b.txt'), lnum = 5, text = 'b.txt' }\n  start_with_items({ item })\n\n  local buf_id = child.api.nvim_create_buf(false, true)\n  local win_config = {\n    relative = 'editor',\n    anchor = 'NE',\n    row = 0,\n    col = child.o.columns,\n    height = 3,\n    width = 15,\n    border = 'single',\n    style = 'minimal',\n  }\n  child.api.nvim_open_win(buf_id, false, win_config)\n  sleep(small_time)\n  default_preview(buf_id, item, { line_position = 'center' })\n  child.cmd('redraw')\n  child.expect_screenshot()\nend\n\nT['default_preview()']['works for file path'] = function()\n  local items = {\n    -- Item as string\n    real_file('b.txt'),\n\n    -- Item as table with `path` field\n    { text = real_file('LICENSE'), path = real_file('LICENSE') },\n\n    -- Non-text file\n    real_file('c.gif'),\n  }\n  validate_preview(items)\n\n  -- Should have proper buffer name\n  validate_helper_buf_name(0, 'preview')\n\n  stop()\n\n  -- Should work for failed to read files\n  child.lua('vim.loop.fs_open = function() return nil end')\n  local makefile_path = real_file('Makefile')\n  validate_preview({ makefile_path })\n  validate_helper_buf_name(0, 'preview')\nend\n\nT['default_preview()']['works for relative file path'] = function()\n  local lua_cmd = string.format(\n    [[MiniPick.start({ source = { items = { 'a.lua' }, cwd = %s } })]],\n    vim.inspect(full_path(real_files_dir))\n  )\n  child.lua_notify(lua_cmd)\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  validate_helper_buf_name(0, 'preview')\n  type_keys('<C-c>')\n\n  -- Should respect source's cwd (thanks to window-local cwd)\n  local target_win_id = child.api.nvim_get_current_win()\n  child.lua('_G.cwd = ' .. vim.inspect(test_dir_absolute .. '/builtin-tests'))\n  child.fn.chdir(test_dir_absolute)\n  child.lua_notify('MiniPick.start({ source = { items = { { path = \"file\" } }, cwd = _G.cwd } })')\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  eq(child.fn.getcwd(target_win_id), test_dir_absolute)\nend\n\nT['default_preview()']['works for file path with tilde'] = function()\n  local path = real_file('LICENSE')\n  local path_tilde = child.fn.fnamemodify(full_path(path), ':~')\n  if path_tilde:sub(1, 1) ~= '~' then return end\n\n  child.set_size(5, 15)\n  validate_preview({ path_tilde })\nend\n\nT['default_preview()']['works for URI path'] = function()\n  local items = { { text = real_file('LICENSE'), path = 'file:/' .. full_path(real_file('LICENSE')) } }\n  validate_preview(items)\nend\n\nT['default_preview()']['shows line in file path'] = function()\n  local path = real_file('b.txt')\n  local items = {\n    path .. '\\0003',\n    { text = path .. '\\0as-table', path = path, lnum = 6 },\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['shows position in file path'] = function()\n  local path = real_file('b.txt')\n  local items = {\n    path .. '\\0003\\0004',\n    { text = path .. '\\0as-table', path = path, lnum = 6, col = 2 },\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['shows region in file path'] = function()\n  local path = real_file('b.txt')\n  local items = {\n    { text = path .. '\\000region-oneline', path = path, lnum = 8, col = 3, end_lnum = 8, end_col = 5 },\n    { text = path .. '\\000region-manylines', path = path, lnum = 9, col = 3, end_lnum = 11, end_col = 4 },\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['has syntax highlighting in file path'] = function()\n  local items = {\n    -- With tree-sitter\n    real_file('a.lua'),\n\n    -- With built-in syntax\n    real_file('Makefile'),\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['loads context in file path'] = function()\n  start_with_items({ real_file('b.txt') })\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\nend\n\nT['default_preview()']['works for directory path'] = function()\n  validate_preview({ test_dir, { text = real_files_dir, path = real_files_dir } })\n  validate_helper_buf_name(0, 'preview')\nend\n\nT['default_preview()']['works for buffer'] = function()\n  local buf_id_1 = child.api.nvim_create_buf(false, false)\n  local buf_id_2 = child.api.nvim_create_buf(true, false)\n  local buf_id_3 = child.api.nvim_create_buf(false, true)\n  local buf_id_4 = child.api.nvim_create_buf(true, true)\n\n  child.api.nvim_buf_set_lines(buf_id_1, 0, -1, false, { 'This is buffer #1' })\n  child.api.nvim_buf_set_lines(buf_id_2, 0, -1, false, { 'This is buffer #2' })\n  child.api.nvim_buf_set_lines(buf_id_3, 0, -1, false, { 'This is buffer #3' })\n  child.api.nvim_buf_set_lines(buf_id_4, 0, -1, false, { 'This is buffer #4' })\n\n  local items = {\n    -- As number\n    buf_id_1,\n\n    -- As string convertible to number\n    tostring(buf_id_1),\n\n    -- As table with `bufnr` field\n    { text = 'Buffer #2', bufnr = buf_id_2 },\n\n    -- As table with `buf_id` field\n    { text = 'Buffer #3', buf_id = buf_id_3 },\n\n    -- As table with `buf` field\n    { text = 'Buffer #4', buf = buf_id_4 },\n  }\n  validate_preview(items)\n\n  -- Should have proper buffer name\n  validate_helper_buf_name(0, 'preview')\nend\n\nlocal mock_buffer_for_preview = function()\n  local buf_id = child.api.nvim_create_buf(true, false)\n  local lines = {}\n  for i = 1, 20 do\n    table.insert(lines, string.format('Line %d in buffer %d', i, buf_id))\n  end\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n  return buf_id\nend\n\nT['default_preview()']['shows line in buffer'] = function()\n  local buf_id = mock_buffer_for_preview()\n  validate_preview({ { text = 'Line in buffer', bufnr = buf_id, lnum = 4 } })\nend\n\nT['default_preview()']['shows position in buffer'] = function()\n  local buf_id = mock_buffer_for_preview()\n  validate_preview({ { text = 'Position in buffer', bufnr = buf_id, lnum = 6, col = 3 } })\nend\n\nT['default_preview()']['shows region in buffer'] = function()\n  local buf_id = mock_buffer_for_preview()\n  local items = {\n    { text = 'Oneline region in buffer', bufnr = buf_id, lnum = 8, col = 3, end_lnum = 8, end_col = 6 },\n    { text = 'Manylines region in buffer', bufnr = buf_id, lnum = 10, col = 3, end_lnum = 12, end_col = 4 },\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['has syntax highlighting in buffer'] = function()\n  child.cmd('edit ' .. real_file('a.lua'))\n  local buf_id_lua = child.api.nvim_get_current_buf()\n  child.cmd('edit ' .. real_file('Makefile'))\n  local buf_id_makefile = child.api.nvim_get_current_buf()\n  child.cmd('enew')\n\n  local items = {\n    { text = 'Tree-sitter highlighting', bufnr = buf_id_lua },\n    { text = 'Built-in syntax', bufnr = buf_id_makefile },\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['loads context in buffer'] = function()\n  child.cmd('edit ' .. real_file('b.txt'))\n  local buf_id = child.api.nvim_get_current_buf()\n  child.cmd('enew')\n\n  start_with_items({ { text = 'Buffer', bufnr = buf_id } })\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\n  type_keys('<C-f>')\n  child.expect_screenshot()\nend\n\nT['default_preview()']['has fallback'] = function()\n  child.set_size(10, 40)\n  validate_preview({ -1, { text = 'Random table' } })\n\n  validate_helper_buf_name(0, 'preview')\nend\n\nT['default_preview()']['does not highlight big files'] = function()\n  local big_file = real_file('big.lua')\n  MiniTest.finally(function() child.fn.delete(big_file, 'rf') end)\n\n  -- Has limit per line\n  child.fn.writefile({ string.format('local a = \"%s\"', string.rep('a', 1000)) }, big_file)\n  child.cmd('edit ' .. big_file)\n  local buf_id = child.api.nvim_get_current_buf()\n  child.cmd('enew')\n  validate_preview({ big_file, { bufnr = buf_id, text = 'Buffer item' } })\n\n  -- It also should have total limit, but it is not tested to not overuse file\n  -- system accesses during test\nend\n\nT['default_preview()']['respects `opts.n_context_lines`'] = function()\n  child.lua([[MiniPick.config.source.preview = function(buf_id, item)\n    return MiniPick.default_preview(buf_id, item, { n_context_lines = 2 })\n  end]])\n  local path = real_file('b.txt')\n  child.cmd('edit ' .. path)\n  local buf_id = child.api.nvim_get_current_buf()\n  child.cmd('enew')\n\n  local items = {\n    -- File line\n    path .. '\\0004',\n\n    -- Buffer line\n    { text = 'Buffer', bufnr = buf_id, lnum = 7 },\n  }\n  validate_preview(items)\nend\n\nT['default_preview()']['respects `opts.line_position`'] = new_set({\n  parametrize = { { 'top' }, { 'center' }, { 'bottom' } },\n}, {\n  function(line_position)\n    child.lua('_G.line_position = ' .. vim.inspect(line_position))\n    child.lua([[MiniPick.config.source.preview = function(buf_id, item)\n        return MiniPick.default_preview(buf_id, item, { line_position = _G.line_position })\n      end]])\n    local path = real_file('b.txt')\n    child.cmd('edit ' .. path)\n    local buf_id = child.api.nvim_get_current_buf()\n    child.cmd('enew')\n\n    local items = {\n      -- File line\n      path .. '\\00010',\n\n      -- Buffer line\n      { text = 'Buffer', bufnr = buf_id, lnum = 12 },\n    }\n    validate_preview(items)\n  end,\n})\n\nT['default_preview()']['respects `source.cwd`'] = function()\n  local lua_cmd =\n    string.format([[MiniPick.start({ source = { items = { 'b.txt' }, cwd = %s } })]], vim.inspect(real_files_dir))\n  child.lua_notify(lua_cmd)\n  type_keys('<Tab>')\n  child.expect_screenshot()\nend\n\nT['default_choose()'] = new_set()\n\nlocal default_choose = forward_lua('MiniPick.default_choose')\n\nlocal choose_item = function(item)\n  start_with_items({ item })\n  type_keys('<CR>')\n  eq(is_picker_active(), false)\nend\n\nT['default_choose()']['works'] = function()\n  local path = real_file('b.txt')\n  choose_item(path)\n  validate_buf_name(0, path)\nend\n\nT['default_choose()']['respects picker target window'] = function()\n  local win_id_1, win_id_2 = setup_windows_pair()\n  local buf_id_1 = child.api.nvim_create_buf(false, true)\n  child.api.nvim_win_set_buf(win_id_1, buf_id_1)\n  local buf_id_2 = child.api.nvim_create_buf(false, true)\n  child.api.nvim_win_set_buf(win_id_2, buf_id_2)\n\n  local path = real_file('b.txt')\n  start_with_items({ path })\n  child.lua(string.format('MiniPick.set_picker_target_window(%d)', win_id_2))\n  type_keys('<CR>')\n\n  eq(child.api.nvim_win_get_buf(win_id_1), buf_id_1)\n  validate_buf_name(buf_id_1, '')\n  validate_buf_name(child.api.nvim_win_get_buf(win_id_2), path)\nend\n\nT['default_choose()']['works without active picker'] = function()\n  local win_id_1, win_id_2 = setup_windows_pair()\n  local path = real_file('b.txt')\n  default_choose(path)\n\n  -- Should use current window as target\n  validate_buf_name(child.api.nvim_win_get_buf(win_id_1), path)\n  validate_buf_name(child.api.nvim_win_get_buf(win_id_2), '')\nend\n\nT['default_choose()']['works for file path'] = function()\n  local validate = function(item, path, pos)\n    local win_id = child.api.nvim_get_current_win()\n    default_choose(item)\n\n    local buf_id = child.api.nvim_win_get_buf(win_id)\n    validate_buf_name(buf_id, path)\n    if pos ~= nil then eq(child.api.nvim_win_get_cursor(win_id), pos) end\n\n    -- Cleanup\n    child.api.nvim_buf_delete(buf_id, { force = true })\n  end\n\n  local path = real_file('b.txt')\n\n  -- Path\n  validate(path, path, { 1, 0 })\n  validate({ text = path, path = path }, path, { 1, 0 })\n\n  -- Path with line\n  validate(path .. '\\0004', path, { 4, 0 })\n  validate({ text = path, path = path, lnum = 6 }, path, { 6, 0 })\n\n  -- Path with position\n  validate(path .. '\\0008\\0002', path, { 8, 1 })\n  validate({ text = path, path = path, lnum = 10, col = 4 }, path, { 10, 3 })\n\n  -- Path with region\n  validate({ text = path, path = path, lnum = 12, col = 5, end_lnum = 14, end_col = 3 }, path, { 12, 4 })\nend\n\nT['default_choose()']['works for relative file path'] = function()\n  local lua_cmd =\n    string.format([[MiniPick.start({ source = { items = { 'a.lua' }, cwd = %s } })]], vim.inspect(real_files_dir))\n  child.lua_notify(lua_cmd)\n  type_keys('<CR>')\n  validate_buf_name(0, real_file('a.lua'))\n\n  -- Should open path in relative form for nicer `:buffers`\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]tests/dir%-pick')\n\n  -- Should respect source's cwd (thanks to window-local cwd)\n  child.lua('_G.cwd = ' .. vim.inspect(test_dir_absolute .. '/builtin-tests'))\n  child.fn.chdir(test_dir_absolute)\n  child.lua_notify('MiniPick.start({ source = { items = { { path = \"file\" } }, cwd = _G.cwd } })')\n  type_keys('<CR>')\n  validate_buf_name(0, full_path(test_dir_absolute .. '/builtin-tests/file'))\n  eq(child.fn.getcwd(), test_dir_absolute)\nend\n\nT['default_choose()']['works for URI path'] = function()\n  local path = full_path(real_file('LICENSE'))\n  local item = { path = 'file:/' .. path }\n  local win_id = child.api.nvim_get_current_win()\n  default_choose(item)\n\n  local buf_id = child.api.nvim_win_get_buf(win_id)\n  validate_buf_name(buf_id, path)\nend\n\nT['default_choose()']['works for file path with tilde'] = function()\n  local path = real_file('LICENSE')\n  local path_tilde = child.fn.fnamemodify(full_path(path), ':~')\n  if path_tilde:sub(1, 1) ~= '~' then return end\n\n  child.set_size(5, 15)\n  start_with_items({ path_tilde })\n  type_keys('<CR>')\n  validate_buf_name(0, path)\nend\n\nT['default_choose()']['reuses opened listed buffer for file path'] = function()\n  local path = real_file('b.txt')\n  child.cmd('edit ' .. path)\n  local buf_id_path = child.api.nvim_get_current_buf()\n  validate_buf_name(buf_id_path, path)\n  set_cursor(5, 3)\n\n  local setup_dummy_cur_buf = function() child.api.nvim_set_current_buf(child.api.nvim_create_buf(true, false)) end\n\n  local validate = function(pos)\n    eq(child.api.nvim_win_get_buf(0), buf_id_path)\n    validate_buf_name(buf_id_path, path)\n    eq(child.api.nvim_win_get_cursor(0), pos)\n  end\n\n  -- Reuses without setting cursor\n  setup_dummy_cur_buf()\n  default_choose(path)\n  validate({ 5, 3 })\n\n  -- Reuses with setting cursor\n  setup_dummy_cur_buf()\n  default_choose(path .. '\\0007\\0002')\n  validate({ 7, 1 })\n\n  -- Doesn't reuse if unlisted\n  setup_dummy_cur_buf()\n  child.cmd('bdelete ' .. buf_id_path)\n  eq(child.api.nvim_buf_get_option(buf_id_path, 'buflisted'), false)\n  default_choose(path)\n  validate({ 1, 0 })\n  eq(child.api.nvim_buf_get_option(buf_id_path, 'buflisted'), true)\nend\n\nT['default_choose()']['mimics empty buffer reuse'] = function()\n  local validate = function(ref_n_bufs)\n    default_choose(real_file('b.txt'))\n    eq(#child.api.nvim_list_bufs(), ref_n_bufs)\n    child.cmd('%bwipeout!')\n  end\n\n  -- Should mimic `:h buffer-reuse` similar to how `:edit` does it\n  eq(child.api.nvim_get_current_buf() == 1, true)\n  validate(1)\n\n  eq(child.api.nvim_get_current_buf() ~= 1, true)\n  validate(1)\n\n  child.cmd('tabnew')\n  validate(2)\n\n  -- Should reuse only for strict set of conditions\n  child.api.nvim_buf_set_name(0, 'named-buf')\n  validate(2)\n\n  child.bo.buftype = 'quickfix'\n  validate(2)\n\n  child.cmd('split')\n  eq(#child.fn.win_findbuf(child.api.nvim_get_current_buf()), 2)\n  validate(2)\n\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { ' ' })\n  validate(2)\n\n  child.bo.modified = true\n  validate(2)\nend\n\nT['default_choose()']['works for directory path'] = function()\n  local validate = function(item, path, filetype)\n    local buf_id_init = child.api.nvim_get_current_buf()\n    default_choose(item)\n\n    local buf_id_cur = child.api.nvim_get_current_buf()\n    eq(child.bo.filetype, filetype)\n    validate_buf_name(buf_id_init, path)\n\n    -- Cleanup\n    child.api.nvim_buf_delete(buf_id_init, { force = true })\n    child.api.nvim_buf_delete(buf_id_cur, { force = true })\n\n    child.lua('if _G.MiniFiles ~= nil then _G.MiniFiles.close() end')\n  end\n\n  validate(test_dir, test_dir, 'netrw')\n  validate({ text = test_dir, path = test_dir }, test_dir, 'netrw')\n\n  -- Should work with 'mini.files' as default explorer\n  child.lua('require(\"mini.files\").setup()')\n  validate(test_dir, test_dir, 'minifiles')\n  validate({ text = test_dir, path = test_dir }, test_dir, 'minifiles')\n\n  -- - Should work when there is an already opened file (matters in which code\n  --   path 'mini.files' takes when acting as a default explorer).\n  --   Earlier resulted in an outdated 'mini.pick' floating window.\n  child.cmd('edit ' .. real_file('a.lua'))\n  start_with_items({ test_dir })\n  type_keys('<CR>')\n  eq(#child.api.nvim_list_wins(), 2)\nend\n\nT['default_choose()']['works for buffer'] = function()\n  local buf_id_tmp = child.api.nvim_create_buf(false, true)\n\n  local setup_buffer = function(pos)\n    local buf_id = child.api.nvim_create_buf(true, false)\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, false, vim.fn['repeat']({ 'aaaaaaaaaaaaaaaaaaaa' }, 20))\n\n    local cur_buf = child.api.nvim_win_get_buf(0)\n    child.api.nvim_set_current_buf(buf_id)\n    child.api.nvim_win_set_cursor(0, pos)\n    child.api.nvim_win_set_buf(0, cur_buf)\n\n    return buf_id\n  end\n\n  local validate = function(item, buf_id, pos)\n    local win_id = child.api.nvim_get_current_win()\n    child.api.nvim_win_set_buf(0, buf_id_tmp)\n\n    default_choose(item)\n\n    eq(child.api.nvim_win_get_buf(win_id), buf_id)\n    if pos ~= nil then eq(child.api.nvim_win_get_cursor(win_id), pos) end\n\n    -- Cleanup\n    child.api.nvim_buf_delete(buf_id, { force = true })\n  end\n\n  local buf_id\n\n  -- Buffer without position should reuse current cursor\n  buf_id = setup_buffer({ 1, 1 })\n  validate(buf_id, buf_id, { 1, 1 })\n\n  buf_id = setup_buffer({ 2, 2 })\n  validate(tostring(buf_id), buf_id, { 2, 2 })\n\n  -- Buffer in table\n  buf_id = setup_buffer({ 3, 3 })\n  validate({ text = 'buffer', bufnr = buf_id }, buf_id, { 3, 3 })\n\n  buf_id = setup_buffer({ 4, 4 })\n  validate({ text = 'buffer', buf_id = buf_id }, buf_id, { 4, 4 })\n\n  buf_id = setup_buffer({ 5, 5 })\n  validate({ text = 'buffer', buf = buf_id }, buf_id, { 5, 5 })\n\n  -- Buffer with line\n  buf_id = setup_buffer({ 6, 6 })\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 7 }, buf_id, { 7, 0 })\n\n  -- Buffer with position\n  buf_id = setup_buffer({ 6, 6 })\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 8, col = 8 }, buf_id, { 8, 7 })\n\n  -- Buffer with region\n  buf_id = setup_buffer({ 6, 6 })\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 9, col = 9, end_lnum = 10, end_col = 8 }, buf_id, { 9, 8 })\n\n  -- Already shown buffer\n  local setup_current_buf = function(pos)\n    child.api.nvim_buf_set_lines(0, 0, -1, false, vim.fn['repeat']({ 'aaaaaaaaaaaaaaaaaaaa' }, 20))\n    child.api.nvim_win_set_cursor(0, pos)\n    return child.api.nvim_get_current_buf()\n  end\n\n  buf_id = setup_current_buf({ 11, 11 })\n  validate(buf_id, buf_id, { 11, 11 })\n\n  buf_id = setup_current_buf({ 12, 12 })\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 13 }, buf_id, { 13, 0 })\n\n  buf_id = setup_current_buf({ 12, 12 })\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 14, col = 14 }, buf_id, { 14, 13 })\n\n  buf_id = setup_current_buf({ 12, 12 })\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 15, col = 15, end_lnum = 16, end_col = 14 }, buf_id, { 15, 14 })\nend\n\nT['default_choose()']['ensures valid target window'] = function()\n  local choose_with_bad_target_window = function(item)\n    child.cmd('botright wincmd v')\n    local win_id = child.api.nvim_get_current_win()\n\n    start_with_items({ item })\n    local lua_cmd = string.format([[vim.api.nvim_win_call(%d, function() vim.cmd('close') end)]], win_id)\n    child.lua(lua_cmd)\n\n    type_keys('<CR>')\n  end\n\n  -- Path\n  local path = real_file('b.txt')\n  choose_with_bad_target_window(path)\n  validate_buf_name(child.api.nvim_get_current_buf(), path)\n\n  -- Buffer\n  local buf_id = child.api.nvim_create_buf(true, false)\n  choose_with_bad_target_window({ text = 'buffer', bufnr = buf_id })\n  eq(child.api.nvim_get_current_buf(), buf_id)\nend\n\nT['default_choose()']['centers cursor'] = function()\n  local validate = function(item, ref_topline)\n    choose_item(item)\n    eq(child.fn.line('w0'), ref_topline)\n  end\n\n  -- Path\n  local path = real_file('b.txt')\n  validate({ text = path, path = path, lnum = 10 }, 4)\n\n  -- Buffer\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, false, vim.fn['repeat']({ 'aaaaaaaaaa' }, 100))\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 12 }, 6)\nend\n\nT['default_choose()']['opens just enough folds'] = function()\n  child.api.nvim_buf_set_lines(0, 0, -1, false, vim.fn['repeat']({ 'aaaaaaaaaa' }, 100))\n  child.cmd('2,3fold')\n  child.cmd('12,13fold')\n\n  eq(child.fn.foldclosed(2), 2)\n  eq(child.fn.foldclosed(3), 2)\n  eq(child.fn.foldclosed(12), 12)\n  eq(child.fn.foldclosed(13), 12)\n\n  default_choose({ text = 'buffer', bufnr = child.api.nvim_get_current_buf(), lnum = 12 })\n\n  eq(child.fn.foldclosed(2), 2)\n  eq(child.fn.foldclosed(3), 2)\n  eq(child.fn.foldclosed(12), -1)\n  eq(child.fn.foldclosed(13), -1)\nend\n\nT['default_choose()']['updates jumplist'] = function()\n  -- Same buffer/path\n  local path = real_file('b.txt')\n  local validate = function(item)\n    child.cmd('edit ' .. vim.fn.fnameescape(path))\n    local init_buf_id = child.api.nvim_get_current_buf()\n    set_cursor(9, 1)\n\n    choose_item(item)\n    if item.bufnr ~= nil then eq(child.api.nvim_get_current_buf(), item.bufnr) end\n    if item.path ~= nil then eq(vim.endswith(child.api.nvim_buf_get_name(0):gsub('\\\\', '/'), item.path), true) end\n    eq(get_cursor(), { item.lnum, 0 })\n\n    type_keys('<C-o>')\n    eq(child.api.nvim_get_current_buf(), init_buf_id)\n    eq(get_cursor(), { 9, 1 })\n\n    -- Cleanup\n    child.cmd('%bwipeout!')\n  end\n\n  -- Same path/buffer\n  validate({ text = path, path = path, lnum = 2 })\n\n  local buf_id = child.api.nvim_get_current_buf()\n  validate({ text = 'buffer', bufnr = buf_id, lnum = 2 })\n\n  -- Different path/buffer\n  local new_path = real_file('Makefile')\n  validate({ text = new_path, path = new_path, lnum = 2 })\n\n  local new_buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_lines(new_buf_id, 0, -1, false, { 'aaa', 'bbb' })\n  validate({ text = 'buffer', bufnr = new_buf_id, lnum = 2 })\nend\n\nT['default_choose()']['has print fallback'] = function()\n  choose_item({ text = 'regular-table' })\n  eq(child.cmd_capture('messages'), '{\\n  text = \"regular-table\"\\n}')\nend\n\nT['default_choose()']['does nothing for `nil` input'] = function()\n  expect.no_error(function() default_choose() end)\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['default_choose_marked()'] = new_set()\n\nlocal default_choose_marked = forward_lua('MiniPick.default_choose_marked')\n\nlocal validate_qfitem = function(input, ref)\n  local eq_if_nonnil = function(x, y)\n    if y ~= nil then eq(x, y) end\n  end\n\n  eq_if_nonnil(input.bufnr, ref.bufnr)\n  if ref.filename ~= nil then validate_buf_name(input.bufnr, ref.filename) end\n  eq_if_nonnil(input.lnum, ref.lnum)\n  eq_if_nonnil(input.col, ref.col)\n  eq_if_nonnil(input.end_lnum, ref.end_lnum)\n  eq_if_nonnil(input.end_col, ref.end_col)\n  eq_if_nonnil(input.text, ref.text)\nend\n\nT['default_choose_marked()']['works'] = function()\n  local path = real_file('b.txt')\n  start_with_items({ path })\n  type_keys('<C-x>', '<M-CR>')\n  eq(is_picker_active(), false)\n\n  -- Should create and open quickfix list\n  eq(#child.api.nvim_list_wins(), 2)\n  eq(child.bo.filetype, 'qf')\n\n  local qflist = child.fn.getqflist()\n  eq(#qflist, 1)\n  validate_qfitem(qflist[1], { filename = path, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = '' })\nend\n\nT['default_choose_marked()']['creates proper title'] = function()\n  local validate = function(keys, title)\n    local path = real_file('b.txt')\n    start_with_items({ path }, 'Picker name')\n    type_keys(keys, '<C-x>', '<M-CR>')\n    eq(is_picker_active(), false)\n    eq(child.fn.getqflist({ title = true }).title, title)\n  end\n\n  validate({}, 'Picker name')\n  validate({ 'b', '.', 't' }, 'Picker name : b.t')\nend\n\nT['default_choose_marked()']['sets as last list'] = function()\n  local path = real_file('b.txt')\n  child.fn.setqflist({}, ' ', { items = { { filename = path, lnum = 2, col = 2 } }, nr = '$' })\n  child.fn.setqflist({}, ' ', { items = { { filename = path, lnum = 3, col = 3 } }, nr = '$' })\n  child.cmd('colder')\n\n  start_with_items({ path })\n  type_keys('<C-x>', '<M-CR>')\n  local list_data = child.fn.getqflist({ all = true })\n  validate_qfitem(list_data.items[1], { filename = path, lnum = 1, col = 1 })\n  eq(list_data.nr, 3)\nend\n\nT['default_choose_marked()']['works without active picker'] = function()\n  local path_1, path_2 = real_file('b.txt'), real_file('LICENSE')\n  default_choose_marked({ path_1, path_2 })\n\n  eq(#child.api.nvim_list_wins(), 2)\n  eq(child.bo.filetype, 'qf')\n\n  local list_data = child.fn.getqflist({ all = true })\n  eq(#list_data.items, 2)\n  validate_qfitem(list_data.items[1], { filename = path_1, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = '' })\n  validate_qfitem(list_data.items[2], { filename = path_2, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = '' })\n\n  eq(list_data.title, '<No picker>')\nend\n\nT['default_choose_marked()']['creates quickfix list from file/buffer positions'] = function()\n  local path = real_file('b.txt')\n  local buf_id = child.api.nvim_create_buf(true, false)\n  local buf_id_scratch = child.api.nvim_create_buf(false, true)\n\n  local items = {\n    -- File path\n    path,\n\n    { text = 'filepath', path = path },\n\n    path .. '\\0003',\n    { text = path, path = path, lnum = 4 },\n\n    path .. '\\0005\\0005',\n    path .. '\\0006\\0006\\000extra text',\n    { text = path, path = path, lnum = 7, col = 7 },\n\n    { text = path, path = path, lnum = 8, col = 8, end_lnum = 9, end_col = 9 },\n    { text = path, path = path, lnum = 8, col = 9, end_lnum = 9 },\n\n    -- Buffer\n    buf_id,\n    tostring(buf_id),\n    { text = 'buffer', bufnr = buf_id },\n\n    buf_id_scratch,\n\n    { text = 'buffer', bufnr = buf_id, lnum = 5 },\n\n    { text = 'buffer', bufnr = buf_id, lnum = 6, col = 6 },\n\n    { text = 'buffer', bufnr = buf_id, lnum = 7, col = 7, end_lnum = 8, end_col = 8 },\n    { text = 'buffer', bufnr = buf_id, lnum = 7, col = 8, end_lnum = 8 },\n\n    -- URI\n    { path = 'file:/' .. full_path(path) },\n\n    -- Edge cases\n    { text = '\\000a\\0b', path = path },\n    { text = '\\000a\\0b', bufnr = buf_id },\n  }\n\n  start_with_items(items)\n  type_keys('<C-a>', '<M-CR>')\n  local qflist = child.fn.getqflist()\n  eq(#qflist, #items)\n\n  validate_qfitem(qflist[1], { filename = path, lnum = 1, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[2], { filename = path, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = 'filepath' })\n  validate_qfitem(qflist[3], { filename = path, lnum = 3, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[4], { filename = path, lnum = 4, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[5], { filename = path, lnum = 5, col = 5, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[6], { filename = path, lnum = 6, col = 6, end_lnum = 0, end_col = 0, text = 'extra text' })\n  validate_qfitem(qflist[7], { filename = path, lnum = 7, col = 7, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[8], { filename = path, lnum = 8, col = 8, end_lnum = 9, end_col = 9 })\n  validate_qfitem(qflist[9], { filename = path, lnum = 8, col = 9, end_lnum = 9, end_col = 0 })\n\n  validate_qfitem(qflist[10], { bufnr = buf_id, lnum = 1, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[11], { bufnr = buf_id, lnum = 1, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[12], { bufnr = buf_id, lnum = 1, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[13], { bufnr = buf_id_scratch, lnum = 1, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[14], { bufnr = buf_id, lnum = 5, col = 1, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[15], { bufnr = buf_id, lnum = 6, col = 6, end_lnum = 0, end_col = 0 })\n  validate_qfitem(qflist[16], { bufnr = buf_id, lnum = 7, col = 7, end_lnum = 8, end_col = 8 })\n  validate_qfitem(qflist[17], { bufnr = buf_id, lnum = 7, col = 8, end_lnum = 8, end_col = 0 })\n\n  validate_qfitem(qflist[18], { filename = full_path(path), lnum = 1, col = 1, end_lnum = 0, end_col = 0 })\n\n  validate_qfitem(qflist[19], { filename = path, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = '│a│b' })\n  validate_qfitem(qflist[20], { bufnr = buf_id, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = '│a│b' })\nend\n\nT['default_choose_marked()']['falls back to choosing first item'] = function()\n  child.lua_notify(\n    [[MiniPick.start({source = { items = { -1, { text = 'some_table' }, -3 }, choose = function(item) _G.chosen_item = item end, }})]]\n  )\n  type_keys('<C-n>', '<C-x>', '<C-n>', '<C-x>', '<M-CR>')\n  eq(is_picker_active(), false)\n\n  eq(child.lua_get('_G.chosen_item'), { text = 'some_table' })\n\n  -- Can also be called without active picker and error\n  expect.no_error(function() default_choose_marked({ -1, { text = 'some_table' } }) end)\nend\n\nT['default_choose_marked()']['works for edge case input'] = function()\n  expect.error(default_choose_marked, '`items`.*array')\n  expect.no_error(function() default_choose_marked({}) end)\nend\n\nT['default_choose_marked()']['respects `opts.list_type`'] = function()\n  local win_id = child.api.nvim_get_current_win()\n  local buf_id = child.api.nvim_create_buf(true, false)\n\n  child.lua([[MiniPick.config.source.choose_marked = function(items)\n    return MiniPick.default_choose_marked(items, { list_type = 'location' })\n  end]])\n  start_with_items({ { bufnr = buf_id } }, 'list_type test')\n  type_keys('<C-x>', '<M-CR>')\n  eq(is_picker_active(), false)\n\n  -- Should create and open location list\n  eq(#child.api.nvim_list_wins(), 2)\n  eq(child.bo.filetype, 'qf')\n\n  local loclist = child.fn.getloclist(win_id, { all = true })\n  eq(#loclist.items, 1)\n  validate_qfitem(loclist.items[1], { bufnr = buf_id, lnum = 1, col = 1, end_lnum = 0, end_col = 0, text = '' })\n\n  eq(loclist.title, 'list_type test')\n\n  -- No quickfix lists should be created\n  eq(child.fn.getqflist({ nr = true }).nr, 0)\nend\n\nT['default_choose_marked()']['ensures valid target window for location list'] = function()\n  local win_id_1, win_id_2 = setup_windows_pair()\n\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.lua([[MiniPick.config.source.choose_marked = function(items)\n    return MiniPick.default_choose_marked(items, { list_type = 'location' })\n  end]])\n\n  start_with_items({ { bufnr = buf_id } }, 'ensure valid window')\n  local lua_cmd = string.format([[vim.api.nvim_win_call(%d, function() vim.cmd('close') end)]], win_id_1)\n  child.lua(lua_cmd)\n  type_keys('<C-x>', '<M-CR>')\n  eq(is_picker_active(), false)\n\n  eq(child.fn.getloclist(win_id_2, { title = true }).title, 'ensure valid window')\nend\n\nT['ui_select()'] = new_set()\n\nlocal ui_select = function(items, opts, on_choice_str)\n  opts = opts or {}\n  on_choice_str = on_choice_str or 'function(...) _G.args = { ... } end'\n  local lua_cmd = string.format('MiniPick.ui_select(%s, %s, %s)', vim.inspect(items), vim.inspect(opts), on_choice_str)\n  child.lua_notify(lua_cmd)\nend\n\nT['ui_select()']['works'] = function()\n  ui_select({ -1, -2 })\n  child.expect_screenshot()\n  type_keys('<C-n>', '<CR>')\n  eq(child.lua_get('_G.args'), { -2, 2 })\nend\n\nT['ui_select()']['calls `on_choice(nil)` in case of abort'] = function()\n  ui_select({ -1, -2 })\n  type_keys('<C-c>')\n  eq(child.lua_get('_G.args'), {})\nend\n\nT['ui_select()']['preserves target window after `on_choice`'] = function()\n  local _, win_id_2 = setup_windows_pair()\n\n  local on_choice_str = string.format('function() vim.api.nvim_set_current_win(%d) end', win_id_2)\n  ui_select({ -1, -2 }, {}, on_choice_str)\n  type_keys('<CR>')\n  eq(child.api.nvim_get_current_win(), win_id_2)\nend\n\nT['ui_select()']['calls `on_choice` with target window being current'] = function()\n  local buf_target = child.api.nvim_get_current_buf()\n  local win_target = child.api.nvim_get_current_win()\n  ui_select(\n    { -1, -2 },\n    {},\n    'function() _G.cur_data = { buf = vim.api.nvim_get_current_buf(), win = vim.api.nvim_get_current_win() } end'\n  )\n  type_keys('<CR>')\n  eq(child.lua_get('_G.cur_data'), { buf = buf_target, win = win_target })\nend\n\nT['ui_select()']['calls `on_choice` with the exact item'] = function()\n  -- Should not create copy as `on_choice()` might depend on item being exact\n  child.lua_notify([[\n    local items = { { 'a table' } }\n    local on_choice = function(item, idx) _G.are_same = items[idx] == item end\n    MiniPick.ui_select(items, {}, on_choice)\n  ]])\n  type_keys('<CR>')\n  eq(child.lua_get('_G.are_same'), true)\nend\n\nT['ui_select()']['respects `opts.prompt` and `opts.kind`'] = function()\n  local validate = function(opts, source_name)\n    ui_select({ -1, -2 }, opts)\n    validate_picker_option('source.name', source_name)\n    stop()\n  end\n\n  -- Should try using use both as source name (preferring `prompt` over `kind`)\n  validate({ prompt = 'Prompt' }, 'Prompt')\n  validate({ prompt = 'Prompt', kind = 'Kind' }, 'Prompt')\nend\n\nT['ui_select()']['respects `opts.format_item`'] = function()\n  child.lua_notify([[MiniPick.ui_select(\n    { { var = 'abc' }, { var = 'def' } },\n    { format_item = function(x) return x.var end },\n    function(...) _G.args = { ... } end\n  )]])\n\n  -- Should use formatted output as regular stritems\n  eq(get_picker_stritems(), { 'abc', 'def' })\n  type_keys('d', '<CR>')\n  eq(child.lua_get('_G.args'), { { var = 'def' }, 2 })\nend\n\nT['ui_select()']['shows only original item in preview'] = function()\n  child.lua_notify([[MiniPick.ui_select({ { var = 'abc' } }, { format_item = function(x) return x.var end })]])\n  type_keys('<Tab>')\n  child.expect_screenshot()\nend\n\nT['ui_select()']['respects `opts.preview_item`'] = function()\n  child.lua_notify([[MiniPick.ui_select(\n    { { var = 'abc' } },\n    {\n      format_item = function(x) return x.var end,\n      preview_item = function(x) return { 'My preview', 'Var = ' .. x.var } end,\n    }\n  )]])\n  type_keys('<Tab>')\n  child.expect_screenshot()\nend\n\nT['ui_select()']['respects `start_opts`'] = function()\n  child.lua_notify([[\n    local start_opts = {\n      -- Should ignore these and prefer parts of `source` that come from `opts`\n      source = { name = 'Should not be used', items = { 'c', 'd' } },\n      window = { config = { width = vim.o.columns } },\n    }\n    MiniPick.ui_select({ 'a', 'b' }, { prompt = 'Select:' }, function() end, start_opts)\n  ]])\n  child.expect_screenshot()\nend\n\nT['builtin.files()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal builtin_files = forward_lua_notify('MiniPick.builtin.files')\n\nT['builtin.files()']['works'] = function()\n  child.set_size(10, 60)\n  mock_fn_executable({ 'rg' })\n  local items = { real_file('b.txt'), real_file('LICENSE'), test_dir }\n  mock_cli_return(items)\n\n  child.lua_notify('_G.file_item = MiniPick.builtin.files()')\n\n  -- Should use icons by default\n  child.expect_screenshot()\n\n  -- Should set correct name\n  validate_picker_option('source.name', 'Files (rg)')\n\n  -- Should return chosen value\n  type_keys('<CR>')\n  eq(child.lua_get('_G.file_item'), items[1])\nend\n\nT['builtin.files()']['works with bad file names'] = function()\n  -- Paths with \":\" may not be allowed on Windows\n  if child.loop.os_uname().sysname == 'Windows_NT' then return end\n\n  local path = join_path(test_dir, 'file:1')\n  child.fn.writefile({ 'File with \":\" in the name' }, path)\n  MiniTest.finally(function() child.fn.delete(path) end)\n\n  mock_fn_executable({ 'rg' })\n  local items = { path }\n  mock_cli_return(items)\n\n  child.lua_notify('_G.file_item = MiniPick.builtin.files()')\n  type_keys('<CR>')\n  eq(child.lua_get('_G.file_item'), path)\n\n  eq(child.api.nvim_buf_get_name(0), full_path(path))\nend\n\nT['builtin.files()']['correctly chooses default tool'] = function()\n  local validate = function(executables, ref_tool)\n    mock_fn_executable(executables)\n    mock_cli_return({ real_file('b.txt') })\n    builtin_files()\n    if ref_tool ~= 'fallback' then eq(child.lua_get('_G.spawn_log[1].executable'), ref_tool) end\n    validate_picker_option('source.name', string.format('Files (%s)', ref_tool))\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate({ 'rg', 'fd', 'git' }, 'rg')\n  validate({ 'fd', 'git' }, 'fd')\n  validate({ 'git' }, 'git')\n  validate({}, 'fallback')\nend\n\nT['builtin.files()']['respects `local_opts.tool`'] = function()\n  local validate = function(tool, ref_args)\n    mock_fn_executable({ tool })\n    mock_cli_return({})\n    builtin_files({ tool = tool })\n    local spawn_data = child.lua_get('_G.spawn_log[1]')\n    eq(spawn_data.executable, tool)\n\n    -- Tool should be called with proper arguments\n    validate_contains_all(spawn_data.options.args, ref_args)\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate('rg', { '--files' })\n  validate('fd', { '--type=f' })\n  validate('git', { '-c', 'core.quotepath=false', 'ls-files', '--cached', '--others', '--exclude-standard' })\nend\n\nT['builtin.files()']['has fallback tool'] = function()\n  local cwd = join_path(test_dir, 'builtin-tests')\n  builtin_files({ tool = 'fallback' }, { source = { cwd = cwd } })\n  validate_picker_option('source.cwd', full_path(cwd))\n\n  -- Sleep because fallback is async\n  sleep(small_time)\n  eq(get_picker_items(), { 'file', 'dir1/file1-1', 'dir1/file1-2', 'dir2/file2-1' })\nend\n\nT['builtin.files()']['respects `source.show` from config'] = function()\n  child.set_size(10, 60)\n\n  -- A recommended way to disable icons\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({ real_file('b.txt'), test_dir })\n  builtin_files()\n  child.expect_screenshot()\nend\n\nT['builtin.files()']['respects `opts`'] = function()\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({ real_file('b.txt') })\n  builtin_files({}, { source = { name = 'My name' } })\n  validate_picker_option('source.name', 'My name')\nend\n\nT['builtin.files()']['respects `opts.source.cwd` for cli spawn'] = function()\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({})\n  builtin_files({}, { source = { cwd = test_dir } })\n\n  validate_picker_option('source.cwd', test_dir_absolute)\n  eq(get_spawn_log()[1].options.cwd, test_dir_absolute)\nend\n\nT['builtin.grep()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal builtin_grep = forward_lua_notify('MiniPick.builtin.grep')\n\nT['builtin.grep()']['works'] = function()\n  child.set_size(10, 70)\n  mock_fn_executable({ 'rg' })\n  local items = { real_file('a.lua') .. '\\0003\\0003\\000a', real_file('b.txt') .. '\\0001\\0001\\000b' }\n  mock_cli_return(items)\n\n  child.lua_notify([[_G.grep_item = MiniPick.builtin.grep()]])\n  -- - By default asks for pattern interactively\n  type_keys('b')\n  child.expect_screenshot()\n\n  -- Should use icons by default\n  type_keys('<CR>')\n  child.expect_screenshot()\n\n  -- Should set correct name\n  validate_picker_option('source.name', 'Grep (rg)')\n\n  -- Should return chosen value\n  type_keys('<CR>')\n  eq(child.lua_get('_G.grep_item'), items[1])\nend\n\nT['builtin.grep()']['correctly chooses default tool'] = function()\n  local validate = function(executables, ref_tool)\n    mock_fn_executable(executables)\n    mock_cli_return({ real_file('b.txt') .. '\\0003\\0003\\000b' })\n    builtin_grep({ pattern = 'b' })\n    if ref_tool ~= 'fallback' then eq(child.lua_get('_G.spawn_log[1].executable'), ref_tool) end\n    validate_picker_option('source.name', string.format('Grep (%s)', ref_tool))\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate({ 'rg', 'git' }, 'rg')\n  validate({ 'git' }, 'git')\n  validate({}, 'fallback')\nend\n\nT['builtin.grep()']['respects `local_opts.tool`'] = new_set({ parametrize = { { 'default' }, { 'supplied' } } }, {\n  test = function(pattern_type)\n    local pattern, keys\n    if pattern_type == 'default' then\n      keys = { 'test', '<CR>' }\n    elseif pattern_type == 'supplied' then\n      pattern = 'test'\n    end\n\n    local validate = function(tool, ref_args)\n      mock_fn_executable({ tool })\n      mock_cli_return({})\n      builtin_grep({ tool = tool, pattern = pattern })\n      type_keys(keys)\n\n      local spawn_data = child.lua_get('_G.spawn_log[1]')\n      eq(spawn_data.executable, tool)\n\n      -- Tool should be called with proper arguments\n      validate_contains_all(spawn_data.options.args, ref_args)\n\n      -- Cleanup\n      type_keys('<C-c>')\n      clear_spawn_log()\n    end\n\n    validate('rg', { '--column', '--line-number', '--no-heading', '--', 'test' })\n    validate('git', { 'grep', '--column', '--line-number', '-e', 'test', '--' })\n  end,\n})\n\nT['builtin.grep()']['respects `local_opts.pattern`'] = function()\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({})\n  builtin_grep({ tool = 'rg', pattern = 'abc' })\n  local spawn_log = get_spawn_log()\n  eq(#spawn_log, 1)\n  local args = spawn_log[1].options.args\n  eq(vim.list_slice(args, #args - 3), { '--color=never', '--case-sensitive', '--', 'abc' })\nend\n\nT['builtin.grep()']['can cancel user input'] = function()\n  mock_fn_executable({ 'rg' })\n\n  local validate = function(keys)\n    mock_cli_return({})\n    builtin_grep({ tool = 'rg' })\n    type_keys(keys)\n    eq(is_picker_active(), false)\n    eq(get_spawn_log(), {})\n  end\n\n  validate('<C-c>')\n  validate('<Esc>')\nend\n\nT['builtin.grep()']['respects `local_opts.globs`'] = function()\n  local validate = function(tool, last_args)\n    mock_fn_executable({ tool })\n    mock_cli_return({})\n    clear_spawn_log()\n    builtin_grep({ tool = tool, pattern = 'abc', globs = { '*.lua', 'lua/**' } })\n\n    -- Should actually use glob patterns\n    local args = get_spawn_log()[1].options.args\n    eq(vim.list_slice(args, #args - #last_args + 1), last_args)\n\n    -- Should show glob patterns in picker's name\n    validate_picker_option('source.name', 'Grep (' .. tool .. ' | *.lua, lua/**)')\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate('rg', { '--glob', '*.lua', '--glob', 'lua/**', '--case-sensitive', '--', 'abc' })\n  validate('git', { '-e', 'abc', '--', '*.lua', 'lua/**' })\n\n  -- Should preserve if called as `builtin.resume()`\n  clear_spawn_log()\n\n  mock_cli_return({})\n  child.lua_notify('MiniPick.builtin.resume()')\n  validate_picker_option('source.name', 'Grep (git | *.lua, lua/**)')\nend\n\nT['builtin.grep()']['has fallback tool'] = new_set({ parametrize = { { 'default' }, { 'supplied' } } }, {\n  test = function(pattern_type)\n    local pattern, keys\n    if pattern_type == 'default' then\n      keys = { 'aaa', '<CR>' }\n    elseif pattern_type == 'supplied' then\n      pattern = 'aaa'\n    end\n\n    local cwd = join_path(test_dir, 'builtin-tests')\n    builtin_grep({ tool = 'fallback', pattern = pattern }, { source = { cwd = cwd } })\n    type_keys(keys)\n    validate_picker_option('source.cwd', full_path(cwd))\n\n    -- Sleep because fallback is async\n    sleep(small_time)\n    local ref_items = {\n      'file\\0003\\0001\\000aaa',\n      'dir1/file1-1\\0003\\0001\\000aaa',\n      'dir1/file1-2\\0003\\0001\\000aaa',\n      'dir2/file2-1\\0003\\0001\\000aaa',\n    }\n    eq(get_picker_items(), ref_items)\n  end,\n})\n\nT['builtin.grep()']['respects `source.show` from config'] = function()\n  child.set_size(10, 70)\n\n  -- A recommended way to disable icons\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({ real_file('b.txt') .. '\\0001\\0001' })\n  builtin_grep({ pattern = 'b' })\n  child.expect_screenshot()\nend\n\nT['builtin.grep()'][\"respects 'ignorecase'/'smartcase'\"] = function()\n  local validate = function(tool, ref_case_arg, ref_cases_noarg)\n    mock_fn_executable({ tool })\n    mock_cli_return({})\n    builtin_grep({ pattern = 'b', tool = tool })\n\n    local args = child.lua_get('_G.spawn_log[1].options.args')\n\n    validate_contains_all(args, { ref_case_arg })\n\n    for _, ref_arg in ipairs(ref_cases_noarg) do\n      for _, arg in ipairs(args) do\n        if arg == ref_arg then error('There is ' .. ref_arg .. ' in arguments') end\n      end\n    end\n\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate('rg', '--case-sensitive', { '--ignore-case', '--smart-case' })\n\n  child.o.ignorecase = true\n  validate('rg', '--ignore-case', { '--case-sensitive', '--smart-case' })\n  validate('git', '--ignore-case', {})\n\n  child.o.smartcase = true\n  validate('rg', '--smart-case', { '--case-sensitive', '--ignore-case' })\n  validate('git', '--ignore-case', {})\n\n  child.o.ignorecase = false\n  validate('rg', '--case-sensitive', { '--ignore-case', '--smart-case' })\n  validate('git', nil, { '--ignore-case' })\nend\n\nT['builtin.grep()']['respects `opts`'] = function()\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({ real_file('b.txt') .. '\\0001\\0001' })\n  builtin_grep({ pattern = 'b' }, { source = { name = 'My name' } })\n  validate_picker_option('source.name', 'My name')\nend\n\nT['builtin.grep()']['respects `opts.source.cwd` for cli spawn'] = function()\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({})\n  builtin_grep({ pattern = 'b' }, { source = { cwd = test_dir } })\n\n  validate_picker_option('source.cwd', test_dir_absolute)\n  eq(get_spawn_log()[1].options.cwd, test_dir_absolute)\nend\n\nT['builtin.grep()']['can have empty string pattern interactively'] = function()\n  mock_fn_executable({ 'rg' })\n  mock_cli_return({})\n  builtin_grep({ tool = 'rg' })\n  type_keys('<CR>')\n\n  local args = child.lua_get('_G.spawn_log[1]').options.args\n  eq({ args[#args - 1], args[#args] }, { '--', '' })\nend\n\nT['builtin.grep_live()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal builtin_grep_live = forward_lua_notify('MiniPick.builtin.grep_live')\n\nlocal validate_last_grep_pattern = function(pattern)\n  local log = get_spawn_log()\n  local spawn_args = log[#log].options.args\n  eq({ spawn_args[#spawn_args - 1], spawn_args[#spawn_args] }, { '--', pattern })\nend\n\nT['builtin.grep_live()']['works'] = function()\n  child.set_size(10, 70)\n  mock_fn_executable({ 'rg' })\n  local items = { real_file('a.lua') .. '\\0003\\0003\\000a', real_file('b.txt') .. '\\0001\\0001\\000b' }\n\n  -- Should show no items for empty query\n  child.lua_notify([[_G.grep_live_item = MiniPick.builtin.grep_live()]])\n  eq(get_picker_items(), {})\n\n  -- Should grep pattern after every query update\n  mock_cli_return(items)\n  type_keys('b')\n  eq(get_picker_items(), items)\n  validate_last_grep_pattern('b')\n\n  mock_cli_return({ items[2] })\n  type_keys('t')\n  eq(get_picker_items(), { items[2] })\n  validate_last_grep_pattern('bt')\n\n  -- Should use icons by default\n  child.expect_screenshot()\n\n  -- Should set correct name\n  validate_picker_option('source.name', 'Grep live (rg)')\n\n  -- Should return chosen value\n  type_keys('<CR>')\n  eq(child.lua_get('_G.grep_live_item'), items[2])\nend\n\nT['builtin.grep_live()']['always shows no items for empty query'] = function()\n  mock_fn_executable({ 'rg' })\n  local items = { real_file('a.lua') .. '\\0003\\0003\\000a', real_file('b.txt') .. '\\0001\\0001\\000b' }\n\n  -- Showing empty query should be done without extra spawn\n  mock_cli_return(items)\n  builtin_grep_live()\n  eq(get_picker_items(), {})\n  eq(#get_spawn_log(), 0)\n\n  mock_cli_return(items)\n  type_keys('b')\n  eq(get_picker_items(), items)\n  eq(#get_spawn_log(), 1)\n\n  mock_cli_return({ items[1] })\n  type_keys('<C-u>')\n  eq(get_picker_items(), {})\n  eq(#get_spawn_log(), 1)\nend\n\nT['builtin.grep_live()']['fully stops grep process on every non-empty query update'] = function()\n  mock_fn_executable({ 'rg' })\n  local items = { real_file('a.lua') .. '\\0003\\0003\\000a', real_file('b.txt') .. '\\0001\\0001\\000b' }\n\n  builtin_grep_live()\n  eq(get_process_log(), {})\n\n  mock_cli_return(items)\n  type_keys('b')\n  -- - No process to kill before making query non-empty\n  --stylua: ignore\n  eq(get_process_log(), { 'Stdout Stdout_1 finished reading.', 'Stdout Stdout_1 was closed.', 'Process Pid_1 was closed.' })\n  clear_process_log()\n\n  mock_cli_return({ items[2] })\n  type_keys('y')\n  --stylua: ignore\n  local ref_log = { 'Process Pid_1 was killed.', 'Stdout Stdout_2 finished reading.', 'Stdout Stdout_2 was closed.', 'Process Pid_2 was closed.' }\n  eq(get_process_log(), ref_log)\n  clear_process_log()\n\n  type_keys('<C-u>')\n  eq(get_process_log(), { 'Process Pid_2 was killed.' })\nend\n\nT['builtin.grep_live()']['works with programmatic query update'] = function()\n  mock_fn_executable({ 'rg' })\n  builtin_grep_live()\n\n  mock_cli_return({ real_file('b.txt') .. '\\0001\\0001\\000b' })\n  set_picker_query({ 'b', 't' })\n  validate_last_grep_pattern('bt')\n\n  set_picker_query({ 'ab', '', 'cd' })\n  validate_last_grep_pattern('abcd')\nend\n\nT['builtin.grep_live()']['correctly chooses default tool'] = function()\n  local validate = function(executables, ref_tool)\n    mock_fn_executable(executables)\n    mock_cli_return({ real_file('b.txt') .. '\\0003\\0003\\000b' })\n    builtin_grep_live()\n    type_keys('b')\n    eq(child.lua_get('_G.spawn_log[1].executable'), ref_tool)\n    validate_picker_option('source.name', string.format('Grep live (%s)', ref_tool))\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  -- Needs executable non-fallback \"grep\" tool\n  validate({ 'rg', 'git' }, 'rg')\n  validate({ 'git' }, 'git')\n\n  mock_fn_executable({})\n  expect.error(function() child.lua('MiniPick.builtin.grep_live()') end, '`grep_live`.*non%-fallback')\nend\n\nT['builtin.grep_live()']['respects `local_opts.tool`'] = function()\n  local validate = function(tool, ref_args)\n    mock_fn_executable({ tool })\n    mock_cli_return({})\n    builtin_grep_live({ tool = tool })\n    type_keys('b')\n\n    local spawn_data = child.lua_get('_G.spawn_log[1]')\n    eq(spawn_data.executable, tool)\n\n    -- Tool should be called with proper arguments\n    validate_contains_all(spawn_data.options.args, ref_args)\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  --stylua: ignore\n  local rg_args = {\n    '--column', '--line-number', '--no-heading',\n    '--field-match-separator', '\\\\x00', '--case-sensitive',\n    '--', 'b',\n  }\n  validate('rg', rg_args)\n  validate('git', { 'grep', '--column', '--line-number', '--null', '--', 'b' })\n\n  -- Should not accept \"fallback\" tool\n  mock_fn_executable({})\n  expect.error(\n    function() child.lua([[MiniPick.builtin.grep_live({ tool = 'fallback' })]]) end,\n    '`grep_live`.*non%-fallback'\n  )\nend\n\nT['builtin.grep_live()']['respects `local_opts.globs`'] = function()\n  local validate = function(tool, last_args)\n    mock_fn_executable({ tool })\n    mock_cli_return({})\n    clear_spawn_log()\n    builtin_grep_live({ tool = tool, globs = { '*.lua', 'lua/**' } })\n    type_keys('a')\n\n    -- Should actually use glob patterns\n    local args = get_spawn_log()[1].options.args\n    eq(vim.list_slice(args, #args - #last_args + 1), last_args)\n\n    -- Should show glob patterns in picker's name\n    validate_picker_option('source.name', 'Grep live (' .. tool .. ' | *.lua, lua/**)')\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate('rg', { '--glob', '*.lua', '--glob', 'lua/**', '--case-sensitive', '--', 'a' })\n  validate('git', { '-e', 'a', '--', '*.lua', 'lua/**' })\n\n  -- Should preserve if called as `builtin.resume()`\n  clear_spawn_log()\n\n  child.lua_notify('MiniPick.builtin.resume()')\n  mock_cli_return({})\n  type_keys('b')\n  local args = get_spawn_log()[1].options.args\n  eq(vim.list_slice(args, #args - 4), { '-e', 'ab', '--', '*.lua', 'lua/**' })\n  validate_picker_option('source.name', 'Grep live (git | *.lua, lua/**)')\nend\n\nT['builtin.grep_live()']['has custom \"add glob\" mapping'] = function()\n  child.set_size(10, 70)\n  mock_fn_executable({ 'rg' })\n  builtin_grep_live({ tool = 'rg' })\n  eq(child.lua_get('MiniPick.get_picker_opts().mappings.add_glob.char'), '<C-o>')\n\n  type_keys('<C-o>')\n  child.expect_screenshot()\n  type_keys('*.lua', '<CR>')\n  validate_picker_option('source.name', 'Grep live (rg | *.lua)')\n\n  mock_cli_return({})\n  type_keys('a')\n  local args = get_spawn_log()[1].options.args\n  eq(vim.list_slice(args, #args - 4), { '--glob', '*.lua', '--case-sensitive', '--', 'a' })\nend\n\nT['builtin.grep_live()']['respects `source.show` from config'] = function()\n  child.set_size(10, 70)\n\n  -- A recommended way to disable icons\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  mock_fn_executable({ 'rg' })\n  builtin_grep_live()\n  mock_cli_return({ real_file('b.txt') .. '\\0001\\0001' })\n  type_keys('b')\n  child.expect_screenshot()\nend\n\nT['builtin.grep_live()'][\"respects 'ignorecase'/'smartcase'\"] = function()\n  local validate = function(tool, ref_case_arg, ref_cases_noarg)\n    mock_fn_executable({ tool })\n    mock_cli_return({})\n    builtin_grep_live({ tool = tool })\n    type_keys('b')\n\n    local args = child.lua_get('_G.spawn_log[1].options.args')\n\n    validate_contains_all(args, { ref_case_arg })\n\n    for _, ref_arg in ipairs(ref_cases_noarg) do\n      for _, arg in ipairs(args) do\n        if arg == ref_arg then error('There is ' .. ref_arg .. ' in arguments') end\n      end\n    end\n\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  validate('rg', '--case-sensitive', { '--ignore-case', '--smart-case' })\n\n  child.o.ignorecase = true\n  validate('rg', '--ignore-case', { '--case-sensitive', '--smart-case' })\n  validate('git', '--ignore-case', {})\n\n  child.o.smartcase = true\n  validate('rg', '--smart-case', { '--case-sensitive', '--ignore-case' })\n  validate('git', '--ignore-case', {})\n\n  child.o.ignorecase = false\n  validate('rg', '--case-sensitive', { '--ignore-case', '--smart-case' })\n  validate('git', nil, { '--ignore-case' })\nend\n\nT['builtin.grep_live()']['respects `opts`'] = function()\n  mock_fn_executable({ 'rg' })\n  builtin_grep_live({}, { source = { name = 'My name' } })\n  validate_picker_option('source.name', 'My name')\nend\n\nT['builtin.grep_live()']['respects `opts.source.cwd` for cli spawn'] = function()\n  mock_fn_executable({ 'rg' })\n  builtin_grep_live({}, { source = { cwd = test_dir } })\n  mock_cli_return({ real_file('b.txt') .. '\\0001\\0001' })\n  type_keys('b')\n\n  validate_picker_option('source.cwd', test_dir_absolute)\n  eq(get_spawn_log()[1].options.cwd, test_dir_absolute)\nend\n\nT['builtin.help()'] = new_set()\n\nlocal builtin_help = forward_lua_notify('MiniPick.builtin.help')\n\nlocal validate_help_with_layout = function(win_layout, n_tabpages)\n  eq(child.fn.winlayout()[1], win_layout)\n  eq(#child.api.nvim_list_tabpages(), n_tabpages)\n  local has_help = false\n  for _, win_id in ipairs(child.api.nvim_tabpage_list_wins(0)) do\n    if child.api.nvim_buf_get_option(child.api.nvim_win_get_buf(win_id), 'buftype') == 'help' then has_help = true end\n  end\n  eq(has_help, true)\nend\n\nT['builtin.help()']['works'] = function()\n  child.lua_notify('_G.help_item = MiniPick.builtin.help()')\n  -- Ignore footer as it contains non-reliable number of help tags\n  child.expect_screenshot({ ignore_text = { 14 } })\n\n  -- Should set correct name\n  validate_picker_option('source.name', 'Help')\n\n  -- Should return chosen value\n  local item = get_picker_matches().current\n  type_keys('<CR>')\n  eq(child.lua_get('_G.help_item'), item)\n\n  -- Should open help page as choosing\n  child.expect_screenshot({ ignore_text = { 13 }, ignore_attr = child.fn.has('nvim-0.12') == 0 })\nend\n\nT['builtin.help()']['has proper preview'] = function()\n  child.set_size(15, 80)\n\n  -- Shouldn't have side effects for search pattern and `v:hlsearch`\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { 'aa', 'bb', 'aa' })\n  type_keys('/', 'aa', '<CR>', ':<Esc>')\n  child.cmd('let v:hlsearch=0')\n\n  builtin_help()\n  type_keys('<Tab>')\n  -- Ignore footer as it contains non-reliable number of help tags\n  child.expect_screenshot({ ignore_text = { 14 } })\n  eq(child.bo.buftype, 'nofile')\n  -- Changes buffer name to show explicitly help file.\n  -- This is neither good nor bad. Can be changed in the future.\n  eq(child.api.nvim_buf_get_name(0):find('^minipick://') == nil, true)\n\n  eq(child.v.hlsearch, 0)\n  eq(child.fn.getreg('/'), 'aa')\nend\n\nT['builtin.help()']['has customized `choose` modifications'] = function()\n  child.lua([[\n    MiniPick.config.mappings.choose_in_split = '<C-w>'\n    MiniPick.config.mappings.choose_in_vsplit = '<C-e>'\n    MiniPick.config.mappings.choose_in_tabpage = '<C-r>'\n  ]])\n  local validate = function(keys, win_layout, n_tabpages)\n    builtin_help()\n    type_keys(keys)\n    validate_help_with_layout(win_layout, n_tabpages)\n    child.cmd('%bw')\n  end\n  validate('<C-w>', 'col', 1)\n  validate('<C-e>', 'row', 1)\n  validate('<C-r>', 'leaf', 2)\nend\n\nT['builtin.help()']['respects `local_opts.default_split`'] = function()\n  local validate = function(value, win_layout, n_tabpages)\n    builtin_help({ default_split = value })\n    type_keys('<CR>')\n    validate_help_with_layout(win_layout, n_tabpages)\n    child.cmd('%bw')\n  end\n  validate(nil, 'col', 1)\n  validate('horizontal', 'col', 1)\n  validate('vertical', 'row', 1)\n  validate('tab', 'leaf', 2)\n\n  -- Can work with overridden `choose` key\n  builtin_help({ default_split = 'vertical' }, { mappings = { choose = '<C-z>' } })\n  type_keys('<C-z>')\n  validate_help_with_layout('row', 1)\n  child.cmd('%bw')\n\n  expect.error(\n    function() child.lua('MiniPick.builtin.help({ default_split = \"\" })') end,\n    '`opts%.default_split`.*one of'\n  )\nend\n\nT['builtin.help()']['works for help tags with special characters'] = function()\n  child.set_size(15, 80)\n  builtin_help()\n  set_picker_query({ 'c_CTRL-K' })\n  type_keys('<Tab>')\n  -- Ignore footer as it contains non-reliable number of help tags\n  child.expect_screenshot({ ignore_text = { 14 } })\nend\n\nT['builtin.help()']['works when help window is already opened'] = function()\n  -- Open non-current help window\n  child.cmd('help')\n  child.cmd('wincmd w')\n\n  builtin_help()\n\n  -- Should open help in already opened help window (just like `:help`)\n  type_keys('<CR>')\n  child.expect_screenshot({ ignore_text = { 13 }, ignore_attr = child.fn.has('nvim-0.12') == 0 })\n  eq(#child.api.nvim_list_wins(), 2)\nend\n\nT['builtin.help()']['keeps correct picker state'] = function()\n  builtin_help()\n  type_keys('<Tab>')\n  local state = get_picker_state()\n  eq(child.api.nvim_win_get_buf(state.windows.main), state.buffers.preview)\nend\n\nT['builtin.help()']['can be properly aborted'] = function()\n  builtin_help()\n  type_keys('<C-c>')\n  eq(#child.api.nvim_list_wins(), 1)\nend\n\nT['builtin.help()']['handles consecutive applications'] = function()\n  builtin_help()\n  set_picker_query({ ':help' })\n  type_keys('<CR>')\n\n  builtin_help()\n  set_picker_query({ ':helpg' })\n  type_keys('<CR>')\n\n  child.expect_screenshot({ ignore_attr = child.fn.has('nvim-0.12') == 0, ignore_text = { 13 } })\nend\n\nT['builtin.help()']['works with `builtin.resume()`'] = function()\n  builtin_help()\n  set_picker_query({ ':help' })\n  type_keys('<CR>')\n  sleep(small_time)\n  local ignore_attr = child.fn.has('nvim-0.12') == 0\n  child.expect_screenshot({ ignore_attr = ignore_attr, ignore_text = { 13 } })\n\n  child.cmd('close')\n  eq(#child.api.nvim_list_wins(), 1)\n\n  child.lua_notify('MiniPick.builtin.resume()')\n  type_keys('<CR>')\n  sleep(small_time)\n  child.expect_screenshot({ ignore_attr = ignore_attr, ignore_text = { 13 } })\nend\n\nT['builtin.help()']['respects `opts`'] = function()\n  builtin_help({}, { source = { name = 'My name' } })\n  validate_picker_option('source.name', 'My name')\nend\n\nlocal mock_opened_buffers = function()\n  child.cmd('edit ' .. real_file('b.txt'))\n  child.api.nvim_create_buf(true, false)\n  child.api.nvim_create_buf(false, true)\n  child.cmd('edit ' .. real_file('LICENSE'))\nend\n\nT['builtin.buffers()'] = new_set({ hooks = { pre_case = mock_opened_buffers } })\n\nlocal builtin_buffers = forward_lua_notify('MiniPick.builtin.buffers')\n\nT['builtin.buffers()']['works'] = function()\n  child.set_size(10, 70)\n\n  -- Should show no items for empty query\n  child.lua_notify([[_G.buffers_item = MiniPick.builtin.buffers()]])\n\n  -- Should use icons by default\n  child.expect_screenshot()\n\n  -- Should set correct name\n  validate_picker_option('source.name', 'Buffers')\n\n  -- Should return chosen value\n  local item = get_picker_matches().current\n  type_keys('<CR>')\n  eq(child.lua_get('_G.buffers_item'), item)\nend\n\nT['builtin.buffers()']['respects `local_opts.include_current`'] = function()\n  child.set_size(10, 70)\n  builtin_buffers({ include_current = false })\n  child.expect_screenshot()\nend\n\nT['builtin.buffers()']['respects `local_opts.include_unlisted`'] = function()\n  builtin_buffers({ include_unlisted = true })\n  child.expect_screenshot()\nend\n\nT['builtin.buffers()']['respects `source.show` from config'] = function()\n  -- A recommended way to disable icons\n  child.lua('MiniPick.config.source.show = MiniPick.default_show')\n  builtin_buffers()\n  child.expect_screenshot()\nend\n\nT['builtin.buffers()']['respects `opts`'] = function()\n  builtin_buffers({}, { source = { name = 'My name' } })\n  validate_picker_option('source.name', 'My name')\nend\n\nT['builtin.cli()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal builtin_cli = forward_lua_notify('MiniPick.builtin.cli')\n\nT['builtin.cli()']['works'] = function()\n  mock_cli_return({ 'aa', 'bb' })\n  child.lua_notify([[_G.cli_item = MiniPick.builtin.cli({ command = { 'echo', 'xx\\nyy' } })]])\n\n  -- - Sleep as items are set inside `schedule_wrap`ed function\n  sleep(small_time)\n  eq(get_picker_items(), { 'aa', 'bb' })\n\n  -- Should set correct name\n  validate_picker_option('source.name', 'CLI (echo)')\n\n  -- Should return chosen value\n  type_keys('<CR>')\n  eq(child.lua_get('_G.cli_item'), 'aa')\nend\n\nT['builtin.cli()']['respects `local_opts.postprocess`'] = function()\n  mock_cli_return({ 'aa', 'bb' })\n  child.lua([[_G.postprocess = function(...) _G.args = { ... }; return { 'x', 'y', 'z' } end]])\n  child.lua_notify([[MiniPick.builtin.cli({ command = { 'echo', 'xx\\nyy' }, postprocess = postprocess })]])\n  sleep(small_time)\n  eq(child.lua_get('_G.args'), { { 'aa', 'bb' } })\n  eq(get_picker_items(), { 'x', 'y', 'z' })\nend\n\nT['builtin.cli()']['respects `local_opts.spawn_opts`'] = function()\n  builtin_cli({ command = { 'echo', 'aa\\nbb' }, spawn_opts = { env = { AAA = 'xxx' } } })\n  eq(get_spawn_log()[1].options, { args = { 'aa\\nbb' }, cwd = child.fn.getcwd(), env = { AAA = 'xxx' } })\nend\n\nT['builtin.cli()']['respects `opts.source.cwd` for cli spawn'] = function()\n  local command = { 'echo', 'aa\\nbb' }\n\n  local validate = function(local_opts, opts, ref_cwd, source_cwd)\n    builtin_cli(local_opts, opts)\n    validate_picker_option('source.cwd', source_cwd or ref_cwd)\n    eq(get_spawn_log()[1].options.cwd, ref_cwd)\n\n    -- Cleanup\n    type_keys('<C-c>')\n    clear_spawn_log()\n  end\n\n  -- Should use it as `spawn_opts.cwd` if it is not present\n  validate({ command = command }, { source = { cwd = test_dir } }, test_dir_absolute)\n  validate(\n    { command = command, spawn_opts = { cwd = real_files_dir } },\n    { source = { cwd = test_dir } },\n    full_path(real_files_dir),\n    test_dir_absolute\n  )\nend\n\nT['builtin.cli()']['respects `opts`'] = function()\n  builtin_cli({}, { source = { name = 'My name' } })\n  validate_picker_option('source.name', 'My name')\nend\n\nT['builtin.resume()'] = new_set()\n\nlocal builtin_resume = forward_lua_notify('MiniPick.builtin.resume')\n\nT['builtin.resume()']['works'] = function()\n  local items = { 'a', 'b', 'bb' }\n  start_with_items(items)\n  type_keys('b')\n  eq(get_picker_matches().all, { 'b', 'bb' })\n  type_keys('<CR>')\n\n  -- Default choose prints item\n  eq(child.cmd_capture('messages'), '\"b\"')\n  type_keys(':<Esc>')\n\n  make_event_log()\n  child.cmd('au User MiniPickStart lua _G.track_event()')\n\n  child.lua_notify('_G.resume_item = MiniPick.builtin.resume()')\n\n  -- User event should be triggered when all elements are usually set\n  eq(child.lua_get('_G.event_log'), { 2 })\n\n  -- Should preserve as much as state as possible from latest picker\n  child.expect_screenshot()\n  eq(get_picker_items(), items)\n  eq(get_picker_matches().all, { 'b', 'bb' })\n  eq(get_picker_query(), { 'b' })\n\n  type_keys('<C-u>')\n  eq(get_picker_matches().all, items)\n  type_keys('a')\n  eq(get_picker_matches().all, { 'a' })\n\n  -- Should return value\n  type_keys('<CR>')\n  eq(child.lua_get('_G.resume_item'), 'a')\nend\n\nT['builtin.resume()']['can be called after previous picker was aborted'] = function()\n  start_with_items({ 'aa', 'bb' })\n  type_keys('a', '<C-c>')\n\n  builtin_resume()\n  eq(get_picker_query(), { 'a' })\n  eq(get_picker_matches().all, { 'aa' })\n  eq(get_picker_items(), { 'aa', 'bb' })\nend\n\nT['builtin.resume()']['always starts in main view'] = function()\n  start_with_items({ 'a' })\n  type_keys('<Tab>')\n  validate_picker_view('preview')\n  type_keys('<C-c>')\n\n  builtin_resume()\n  validate_picker_view('main')\n\n  type_keys('<S-Tab>')\n  validate_picker_view('info')\n  type_keys('<C-c>')\n\n  builtin_resume()\n  validate_picker_view('main')\nend\n\nT['builtin.resume()']['preserves current working directory'] = function()\n  local dir_1, dir_2 = full_path(test_dir), full_path(real_files_dir)\n  child.fn.chdir(dir_1)\n  start_with_items({ 'a' })\n  validate_picker_option('source.cwd', full_path(dir_1))\n  type_keys('<C-c>')\n\n  child.fn.chdir(dir_2)\n  builtin_resume()\n  validate_picker_option('source.cwd', full_path(dir_1))\n  eq(child.fn.getcwd(0), dir_1)\nend\n\nT['builtin.resume()']['preserves query cache'] = function()\n  local validate_match_calls = make_match_with_count()\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'bb' }, match = _G.match_with_count },\n    options = { use_cache = true },\n  })]])\n  validate_match_calls(0, { 1, 2, 3 })\n\n  type_keys('b')\n  validate_match_calls(1, { 2, 3 })\n\n  type_keys('b')\n  validate_match_calls(2, { 3 })\n\n  -- Close and resume\n  type_keys('<C-c>')\n  builtin_resume()\n  validate_match_calls(2, { 3 })\n\n  type_keys('<BS>')\n  validate_match_calls(2, { 2, 3 })\n\n  type_keys('<BS>')\n  validate_match_calls(2, { 1, 2, 3 })\nend\n\nT['builtin.resume()']['preserves marked items'] = function()\n  start_with_items({ 'aa', 'bb' })\n  type_keys('<C-x>', '<C-c>')\n\n  builtin_resume()\n  eq(get_picker_matches().marked_inds, { 1 })\nend\n\nT['builtin.resume()']['recomputes target window'] = function()\n  local win_id_1, win_id_2 = setup_windows_pair()\n\n  start_with_items({ 'a' })\n  eq(get_picker_state().windows.target, win_id_1)\n  type_keys('<C-c>')\n\n  child.api.nvim_set_current_win(win_id_2)\n  builtin_resume()\n  eq(get_picker_state().windows.target, win_id_2)\nend\n\nT['builtin.resume()']['can be called consecutively'] = function()\n  local validate = function(query, matches, items)\n    eq(get_picker_query(), query)\n    eq(get_picker_matches().all, matches)\n    eq(get_picker_items(), items)\n  end\n\n  start_with_items({ 'aa', 'bb' })\n  type_keys('a')\n  validate({ 'a' }, { 'aa' }, { 'aa', 'bb' })\n  type_keys('<C-c>')\n\n  builtin_resume()\n  type_keys('<C-u>', 'b')\n  validate({ 'b' }, { 'bb' }, { 'aa', 'bb' })\n  type_keys('<C-c>')\n\n  builtin_resume()\n  type_keys('b')\n  validate({ 'b', 'b' }, { 'bb' }, { 'aa', 'bb' })\n  type_keys('<C-c>')\nend\n\nT['builtin.resume()'][\"restores 'guicursor'\"] = function()\n  start_with_items({ 'a' }, 'My name')\n  type_keys('<C-c>')\n\n  child.o.guicursor = 'n-v-c:block'\n  builtin_resume()\n  -- Should *temporarily* force custom 'guicursor' to hide cursor\n  eq(child.o.guicursor, 'a:MiniPickCursor')\n  type_keys('<C-c>')\n  eq(child.o.guicursor, 'n-v-c:block')\nend\n\nT['builtin.resume()']['validates if no picker was previously called'] = function()\n  expect.error(function() child.lua('MiniPick.builtin.resume()') end, 'no picker to resume')\nend\n\nT['registry'] = new_set()\n\nT['registry']['works'] = function()\n  eq(child.lua_get('type(MiniPick.registry)'), 'table')\n\n  -- All methods from `builtin` should be present\n  local builtin_methods = child.lua_get('vim.tbl_keys(MiniPick.builtin)')\n  table.sort(builtin_methods)\n  local registry_methods = child.lua_get('vim.tbl_keys(MiniPick.registry)')\n  table.sort(registry_methods)\n  eq(builtin_methods, registry_methods)\n\n  local actual_types = child.lua_get('vim.tbl_map(type, MiniPick.registry)')\n  local ref_types = {}\n  for _, key in ipairs(builtin_methods) do\n    ref_types[key] = 'function'\n  end\n  eq(actual_types, ref_types)\nend\n\nT['registry']['is not reloaded in `setup()`'] = function()\n  child.lua([[MiniPick.registry.custom = function() end]])\n  child.lua([[require('mini.pick').setup()]])\n  eq(child.lua_get('type(MiniPick.registry.custom)'), 'function')\nend\n\nT['get_picker_items()'] = new_set()\n\nT['get_picker_items()']['works'] = function()\n  local items = { 'aa', { text = 'bb' } }\n  start_with_items(items)\n  child.lua('_G.res = MiniPick.get_picker_items()')\n  eq(child.lua_get('_G.res'), items)\n\n  -- Returns copy\n  child.lua([[_G.res[2].text = 'xx']])\n  eq(child.lua_get('MiniPick.get_picker_items()'), items)\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(get_picker_items(), vim.NIL)\nend\n\nT['get_picker_items()']['handles callables'] = function()\n  -- Should return actual `items` after global callable expansion\n  child.lua_notify([[MiniPick.start({ source = { items = function() return { 'aa' } end } })]])\n  eq(get_picker_items(), { 'aa' })\n  type_keys('<C-c>')\n\n  -- Should not expand callable item\n  child.lua_notify([[MiniPick.start({ source = { items = { function() return 'aa' end } } })]])\n  eq(child.lua_get('type(MiniPick.get_picker_items()[1])'), 'function')\nend\n\nT['get_picker_stritems()'] = new_set()\n\nT['get_picker_stritems()']['works'] = function()\n  local items, stritems = { 'aa', { text = 'bb' } }, { 'aa', 'bb' }\n  start_with_items(items)\n  child.lua('_G.res = MiniPick.get_picker_stritems()')\n  eq(child.lua_get('_G.res'), stritems)\n\n  -- Returns copy\n  child.lua([[_G.res[2] = 'xx']])\n  eq(child.lua_get('MiniPick.get_picker_stritems()'), stritems)\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(get_picker_stritems(), vim.NIL)\nend\n\nT['get_picker_stritems()']['handles callables'] = function()\n  -- Should always return array of strings\n  child.lua_notify([[MiniPick.start({ source = { items = function() return { 'aa' } end } })]])\n  eq(get_picker_stritems(), { 'aa' })\n  type_keys('<C-c>')\n\n  child.lua_notify([[MiniPick.start({ source = { items = { function() return 'aa' end } } })]])\n  eq(get_picker_stritems(), { 'aa' })\nend\n\nT['get_picker_stritems()'][\"ignores 'ignorecase'\"] = function()\n  child.o.ignorecase = true\n  start_with_items({ 'ab', 'Ab', 'AB' })\n  eq(get_picker_stritems(), { 'ab', 'Ab', 'AB' })\nend\n\nT['get_picker_matches()'] = new_set()\n\nT['get_picker_matches()']['works'] = function()\n  local items = { { text = 'aa' }, 'bb', 'cc' }\n  start_with_items(items)\n  child.lua('_G.res = MiniPick.get_picker_matches()')\n\n  local ref = {\n    all = items,\n    all_inds = { 1, 2, 3 },\n    current = items[1],\n    current_ind = 1,\n    marked = {},\n    marked_inds = {},\n    shown = items,\n    shown_inds = { 1, 2, 3 },\n  }\n  eq(child.lua_get('_G.res'), ref)\n\n  -- Returns copy\n  child.lua([[_G.res.all[1], _G.res.all_inds[1] = 'xx', 100]])\n  child.lua([[_G.res.current, _G.res.current_ind = 'yy', 200]])\n  child.lua([[_G.res.marked[1], _G.res.marked_inds[1] = 'uu', 300]])\n  child.lua([[_G.res.shown[1], _G.res.shown_inds[1] = 'vv', 400]])\n  eq(get_picker_matches(), ref)\nend\n\nT['get_picker_matches()']['reacts to change in all matches'] = function()\n  local validate = function(ref_all, ref_all_inds)\n    local matches = get_picker_matches()\n    eq(matches.all, ref_all)\n    eq(matches.all_inds, ref_all_inds)\n  end\n\n  local items = { 'a', 'bb', 'b' }\n  start_with_items(items)\n  validate(items, { 1, 2, 3 })\n\n  type_keys('b')\n  validate({ 'bb', 'b' }, { 2, 3 })\n\n  type_keys('b')\n  validate({ 'bb' }, { 2 })\n\n  type_keys('x')\n  validate({}, {})\nend\n\nT['get_picker_matches()']['reacts to change in current match'] = function()\n  local validate = function(ref_current, ref_current_ind)\n    local matches = get_picker_matches()\n    eq(matches.current, ref_current)\n    eq(matches.current_ind, ref_current_ind)\n  end\n\n  local items = { 'a', 'b', 'c' }\n  start_with_items(items)\n  validate(items[1], 1)\n\n  type_keys('<C-n>')\n  validate(items[2], 2)\n\n  type_keys('<C-p>')\n  validate(items[1], 1)\nend\n\nT['get_picker_matches()']['reacts to change in marked matches'] = function()\n  local validate = function(ref_marked, ref_marked_inds)\n    local matches = get_picker_matches()\n    eq(matches.marked, ref_marked)\n    eq(matches.marked_inds, ref_marked_inds)\n  end\n\n  local items = { 'a', 'b', 'c' }\n  start_with_items(items)\n  validate({}, {})\n\n  type_keys('<C-x>')\n  validate({ items[1] }, { 1 })\n\n  type_keys('<C-n>', '<C-n>', '<C-x>')\n  validate({ items[1], items[3] }, { 1, 3 })\nend\n\nT['get_picker_matches()']['reacts to change in shown matches'] = function()\n  local validate = function(ref_shown, ref_shown_inds)\n    local matches = get_picker_matches()\n    eq(matches.shown, ref_shown)\n    eq(matches.shown_inds, ref_shown_inds)\n  end\n\n  child.set_size(10, 20)\n\n  local items = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'hha', 'hhha', 'ha' }\n  start_with_items(items)\n  validate({ 'a', 'b', 'c', 'd', 'e' }, { 1, 2, 3, 4, 5 })\n\n  type_keys('<C-p>')\n  validate({ 'f', 'g', 'hha', 'hhha', 'ha' }, { 6, 7, 8, 9, 10 })\n\n  type_keys('a')\n  validate({ 'a', 'ha', 'hha', 'hhha' }, { 1, 10, 8, 9 })\n\n  type_keys('x')\n  validate({}, {})\n\n  type_keys('<C-c>')\n\n  -- Should always order from top to bottom\n  start({ source = { items = { 'a', 'b', 'c', 'ad', 'd' } }, options = { content_from_bottom = true } })\n  validate({ 'd', 'ad', 'c', 'b', 'a' }, { 5, 4, 3, 2, 1 })\n  type_keys('d')\n  validate({ 'ad', 'd' }, { 4, 5 })\nend\n\nT['get_picker_matches()']['handles no matches'] = function()\n  -- When no active picker\n  eq(get_picker_matches(), vim.NIL)\n\n  -- When no items are set\n  start_with_items()\n  eq(get_picker_items(), vim.NIL)\n  eq(get_picker_matches(), {})\n\n  -- When `items` is empty table\n  set_picker_items({})\n  eq(get_picker_items(), {})\n  eq(get_picker_matches(), {})\nend\n\nT['get_picker_opts()'] = new_set()\n\nT['get_picker_opts()']['works'] = function()\n  child.lua('MiniPick.config.window.config = { col = 2 }')\n  child.lua('_G.choose = function(item) print(item) end')\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a', 'b' }, name = 'My name', choose = _G.choose } })]])\n\n  child.lua([[_G.res = MiniPick.get_picker_opts()]])\n\n  local validate_as_config = function(field)\n    local lua_cmd = string.format('vim.deep_equal(_G.res.%s, MiniPick.config.%s)', field, field)\n    eq(child.lua_get(lua_cmd), true)\n  end\n\n  validate_as_config('delay')\n  validate_as_config('mappings')\n  validate_as_config('options')\n  validate_as_config('config')\n\n  -- - Not supplied `source` callables should be inferred\n  eq(child.lua_get('_G.res.source.items'), { 'a', 'b' })\n  eq(child.lua_get('_G.res.source.name'), 'My name')\n  eq(child.lua_get('_G.res.source.cwd'), full_path(child.fn.getcwd()))\n\n  eq(child.lua_get('_G.res.source.match == MiniPick.default_match'), true)\n  eq(child.lua_get('_G.res.source.show == MiniPick.default_show'), true)\n  eq(child.lua_get('_G.res.source.preview == MiniPick.default_preview'), true)\n  eq(child.lua_get('_G.res.source.choose == _G.choose'), true)\n  eq(child.lua_get('_G.res.source.choose_marked == MiniPick.default_choose_marked'), true)\n\n  -- Returns copy\n  child.lua([[_G.res.delay.busy, _G.res.source.name = -10, 'Hello']])\n  child.lua('_G.opts_2 = MiniPick.get_picker_opts()')\n  eq(child.lua_get('_G.opts_2.delay.busy == MiniPick.config.delay.busy'), true)\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(child.lua_get('MiniPick.get_picker_opts()'), vim.NIL)\nend\n\nT['get_picker_state()'] = new_set()\n\nT['get_picker_state()']['works'] = function()\n  local items = { { text = 'aa' }, 'bb', 'cc' }\n  start_with_items(items)\n  child.lua('_G.res = MiniPick.get_picker_state()')\n  local res = child.lua_get('_G.res')\n\n  eq(child.api.nvim_buf_is_valid(res.buffers.main), true)\n  eq(child.api.nvim_win_is_valid(res.windows.main), true)\n  eq(child.api.nvim_win_is_valid(res.windows.target), true)\n  eq(res.caret, 1)\n  eq(res.is_busy, false)\n\n  -- Returns copy\n  child.lua([[_G.res.buffers.main, _G.res.windows.main = -100, -101]])\n  local state = get_picker_state()\n  eq(child.api.nvim_buf_is_valid(state.buffers.main), true)\n  eq(child.api.nvim_win_is_valid(state.windows.main), true)\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(get_picker_state(), vim.NIL)\nend\n\nT['get_picker_state()']['reacts to creation of preview and info views'] = function()\n  local validate = function(ref)\n    local actual = vim.tbl_map(function(x)\n      if x == nil then return nil end\n      return child.api.nvim_buf_is_valid(x)\n    end, get_picker_state().buffers)\n    eq(actual, ref)\n  end\n\n  start_with_items({ 'a', 'b', 'c' })\n  validate({ main = true, preview = nil, info = nil })\n\n  type_keys('<Tab>')\n  validate({ main = true, preview = true, info = nil })\n\n  type_keys('<S-Tab>')\n  -- - Preview buffers have 'bufhidden' set to 'wipe', so become not valid\n  validate({ main = true, preview = false, info = true })\n\n  type_keys('<Tab>')\n  -- - Info buffers are persistent during picker session\n  validate({ main = true, preview = true, info = true })\nend\n\nT['get_picker_state()']['reacts to change in target window'] = function()\n  local win_id_1, win_id_2 = setup_windows_pair()\n\n  start_with_items()\n  eq(get_picker_state().windows.target, win_id_1)\n\n  child.lua(string.format('MiniPick.set_picker_target_window(%d)', win_id_2))\n  eq(get_picker_state().windows.target, win_id_2)\nend\n\nT['get_picker_state()']['properly detects when picker is busy'] = function()\n  child.lua([[_G.match_defer = function()\n    local f = function()\n      local co = coroutine.running()\n      vim.defer_fn(function() coroutine.resume(co) end, 10)\n      coroutine.yield()\n\n      MiniPick.set_picker_match_inds({ 1 })\n    end\n\n    coroutine.resume(coroutine.create(f))\n  end]])\n  child.lua_notify('MiniPick.start({ source = { match = match_defer } })')\n\n  -- Between starting picker and first setting items\n  eq(get_picker_state().is_busy, true)\n  set_picker_items({ 'a', 'b' }, { do_match = false })\n  eq(get_picker_state().is_busy, false)\n\n  -- Between starting match and displaying its results\n  type_keys('a')\n  eq(get_picker_state().is_busy, true)\n  sleep(small_time)\n  eq(get_picker_state().is_busy, false)\nend\n\nT['get_picker_state()']['reacts to caret update'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n  eq(get_picker_state().caret, 1)\n\n  type_keys('abc')\n  eq(get_picker_state().caret, 4)\n\n  type_keys('<Left>')\n  eq(get_picker_state().caret, 3)\n\n  type_keys('<BS>')\n  eq(get_picker_state().caret, 2)\nend\n\nT['get_picker_query()'] = new_set()\n\nT['get_picker_query()']['works'] = function()\n  start_with_items()\n  child.lua('_G.res = MiniPick.get_picker_query()')\n  eq(child.lua_get('_G.res'), {})\n\n  -- Returns copy\n  child.lua([[_G.res[1] = 'a']])\n  eq(get_picker_query(), {})\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(get_picker_query(), vim.NIL)\nend\n\nT['get_picker_query()']['reacts to query update'] = function()\n  local items = { 'a', 'b', 'bb' }\n  start_with_items(items)\n\n  -- Manual\n  eq(get_picker_query(), {})\n  type_keys('b')\n  eq(get_picker_query(), { 'b' })\n  type_keys('b')\n  eq(get_picker_query(), { 'b', 'b' })\n  type_keys('b')\n  eq(get_picker_query(), { 'b', 'b', 'b' })\n  type_keys('<BS>')\n  eq(get_picker_query(), { 'b', 'b' })\n  type_keys('<C-u>')\n  eq(get_picker_query(), {})\n\n  -- Programmatic\n  set_picker_query({ 'aa', 'bb' })\n  eq(get_picker_query(), { 'aa', 'bb' })\nend\n\nT['set_picker_items()'] = new_set()\n\nlocal set_picker_items = forward_lua('MiniPick.set_picker_items')\n\nT['set_picker_items()']['works'] = function()\n  start_with_items()\n  set_picker_items({ 'a', 'b' })\n  eq(get_picker_items(), { 'a', 'b' })\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(get_picker_query(), vim.NIL)\nend\n\nT['set_picker_items()']['resets match inds prior to matching'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n  type_keys('b')\n  eq(get_picker_matches().all_inds, { 2, 3 })\n\n  set_picker_items({ 'b', 'bb', 'a' })\n  eq(get_picker_matches().all_inds, { 1, 2 })\nend\n\nT['set_picker_items()']['resets marked inds'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n  type_keys('<C-x>', '<C-n>', '<C-x>')\n  eq(get_picker_matches().marked_inds, { 1, 2 })\n\n  set_picker_items({ 'a', 'b', 'bb' })\n  eq(get_picker_matches().marked_inds, {})\nend\n\nT['set_picker_items()']['resets query cache'] = function()\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a', 'b' } }, options = { use_cache = true } })]])\n  type_keys('a')\n  eq(get_picker_matches().all_inds, { 1 })\n  type_keys('<BS>')\n\n  set_picker_items({ 'x', 'a', 'aa' })\n  type_keys('a')\n  eq(get_picker_matches().all_inds, { 2, 3 })\nend\n\nT['set_picker_items()']['recomputes visible range'] = function()\n  start_with_items({ 'a', 'b' })\n  set_picker_items({ 'c', 'd', 'e' })\n  child.expect_screenshot()\nend\n\nT['set_picker_items()']['triggers dedicated event'] = function()\n  child.lua('_G.log = {}')\n  child.cmd('au User MiniPickMatch lua table.insert(_G.log, MiniPick.get_picker_matches().all)')\n\n  start_with_items({})\n  eq(child.lua_get('_G.log'), {})\n\n  type_keys('a')\n  eq(child.lua_get('_G.log'), {})\n\n  set_picker_items({ 'a', 'b' })\n  -- Should trigger first during item setting and then after query matching\n  eq(child.lua_get('_G.log'), { { 'a', 'b' }, { 'a' } })\nend\n\nT['set_picker_items()']['respects `opts.do_match`'] = function()\n  local validate_match_calls = make_match_with_count()\n  child.lua_notify([[MiniPick.start({ source = { match = _G.match_with_count } })]])\n  validate_match_calls(0, nil)\n\n  set_picker_items({ 'a', 'b' }, { do_match = false })\n  validate_match_calls(0, { 1, 2 })\n\n  type_keys('a')\n  validate_match_calls(1, { 1 })\n\n  set_picker_items({ 'aa', 'bb' }, { do_match = false })\n  validate_match_calls(1, { 1, 2 })\nend\n\nT['set_picker_items()']['respects `opts.querytick`'] = function()\n  -- Mock slow `set_picker_items`\n  child.lua('_G.small_time = ' .. small_time)\n  child.lua([[\n    _G.log = {}\n    -- Mock slow item preparation\n    local tolower_orig = vim.fn.tolower\n    vim.fn.tolower = function(...)\n      table.insert(_G.log, { time = vim.loop.hrtime(), args = {...} })\n      vim.loop.sleep(_G.small_time)\n      table.insert(_G.log, { time = vim.loop.hrtime() })\n      return tolower_orig(...)\n    end\n\n    -- Reload module for `vim.fn.tolower` mock to take effect\n    package.loaded['mini.pick'] = nil\n    require('mini.pick').setup()\n  ]])\n\n  -- Should check every `delay.async` milliseconds if global querytick is the\n  -- same as supplied. If not - abort without setting items.\n  child.lua('MiniPick.config.delay.async = 1')\n\n  start_with_items()\n  set_picker_items({ 'ab', 'ac', 'bb' }, { querytick = -1 })\n  eq(get_picker_items(), vim.NIL)\nend\n\nT['set_picker_items()']['does not block picker'] = function()\n  child.lua([[\n    _G.log = {}\n    _G.log_func = function()\n      local entry = { is_busy = MiniPick.get_picker_state().is_busy, items_type = type(MiniPick.get_picker_items()) }\n      table.insert(_G.log, entry)\n    end\n    _G.mappings = { append_log = { char = 'l', func = _G.log_func } }\n  ]])\n  child.lua('MiniPick.config.delay.async = 1')\n  child.lua_notify('MiniPick.start({ mappings = _G.mappings })')\n\n  -- Set many items and immediately press a key, which should be processed\n  -- right away even though there is item preprocessing going.\n  -- Mocking \"slow set_picker_items\" doesn't work for some reason.\n  local items = {}\n  for _ = 1, 100000 do\n    table.insert(items, 'ab')\n    table.insert(items, 'ac')\n    table.insert(items, 'bb')\n  end\n  set_picker_items(items)\n  type_keys('l')\n  eq(child.lua_get('_G.log'), { { is_busy = true, items_type = 'nil' } })\nend\n\nT['set_picker_items()']['validates arguments'] = function()\n  expect.error(function() set_picker_items(1) end, '`items`.*array')\nend\n\nT['set_picker_items_from_cli()'] = new_set({ hooks = { pre_case = mock_spawn } })\n\nlocal set_picker_items_from_cli = function(...)\n  -- Work around callables being not transferrable through RPC\n  return child.lua(\n    [[local res = MiniPick.set_picker_items_from_cli(...)\n      for k, v in pairs(res) do\n        if type(v) == 'function' then res[k] = 'function' end\n      end\n      return res]],\n    { ... }\n  )\nend\n\nlocal test_command = { 'echo', 'a\\nb\\nc' }\n\nT['set_picker_items_from_cli()']['works'] = function()\n  start_with_items()\n  mock_stdout_feed({ 'abc\\ndef\\n', 'ghi' })\n  local out = set_picker_items_from_cli({ 'command', 'arg1', 'arg2' })\n\n  -- Should actually set picker items\n  eq(get_picker_items(), { 'abc', 'def', 'ghi' })\n\n  -- Should properly call `vim.spawn`\n  validate_spawn_log({ { executable = 'command', options = { args = { 'arg1', 'arg2' } } } })\n\n  -- Should properly handle process and stdout\n  --stylua: ignore\n  eq(get_process_log(), { 'Stdout Stdout_1 finished reading.', 'Stdout Stdout_1 was closed.', 'Process Pid_1 was closed.' })\n\n  -- Should return proper data\n  eq(out, { pid = 'Pid_1', kill = 'function' })\nend\n\nT['set_picker_items_from_cli()']['can override items'] = function()\n  start_with_items({ 'a', 'b', 'c' })\n  mock_stdout_feed({ 'd\\ne\\nf' })\n  set_picker_items_from_cli({ 'echo' })\n  eq(get_picker_items(), { 'd', 'e', 'f' })\nend\n\nT['set_picker_items_from_cli()']['can be called without active picker'] = function()\n  expect.no_error(function()\n    local output = child.lua_get([[MiniPick.set_picker_items_from_cli({ 'echo', '1\\n2\\n' }, {})]])\n    eq(output, vim.NIL)\n  end)\nend\n\nT['set_picker_items_from_cli()']['correctly processes stdout feed'] = function()\n  -- Should stich items together without adding '\\n'\n  start_with_items()\n  mock_stdout_feed({ 'aa\\n', 'bb', 'cc\\n', 'dd', '\\nee', 'ff', 'gg', '\\nhh\\n' })\n  set_picker_items_from_cli(test_command)\n  eq(get_picker_items(), { 'aa', 'bbcc', 'dd', 'eeffgg', 'hh' })\n  stop()\n\n  -- Should respect both '\\r\\n' and '\\n' to split items\n  start_with_items()\n  mock_stdout_feed({ 'aa\\nbb\\r\\ncc\\rdd\\nee\\r\\n' })\n  set_picker_items_from_cli(test_command)\n  eq(get_picker_items(), { 'aa', 'bb', 'cc\\rdd', 'ee' })\nend\n\nT['set_picker_items_from_cli()']['correctly detects error in stdout feed'] = function()\n  start_with_items()\n  mock_stdout_feed({ 'aa\\n', 'bb', { err = 'Test stdout error' } })\n  expect.error(function() set_picker_items_from_cli(test_command) end, 'Test stdout error')\nend\n\nT['set_picker_items_from_cli()']['fully stops the process if picker is stopped'] = function()\n  local delay = 5 * small_time\n  child.lua('_G.delay = ' .. delay)\n  child.lua([[\n    local is_active_indicator = true\n    local is_closing_indicator = false\n\n    vim.loop.spawn = function(path, options, on_exit)\n      vim.defer_fn(on_exit, _G.delay)\n\n      local process = {\n        pid = 'Pid_1',\n\n        is_active = function() return is_active_indicator end,\n        kill = function()\n          is_active_indicator = false\n          table.insert(_G.process_log, 'Process Pid_1 was killed.')\n        end,\n\n        is_closing = function() return is_closing_indicator end,\n        close = function(_)\n          is_closing_indicator = true\n          table.insert(_G.process_log, 'Process Pid_1 was closed.')\n        end,\n      }\n      return process, pid\n    end\n  ]])\n\n  start_with_items()\n  set_picker_items_from_cli({ 'sleep', '10' })\n  sleep(small_time)\n  type_keys('<Esc>')\n  sleep(delay)\n  --stylua: ignore\n  local ref_log = { 'Stdout Stdout_1 finished reading.', 'Stdout Stdout_1 was closed.', 'Process Pid_1 was killed.', 'Process Pid_1 was closed.' }\n  eq(get_process_log(), ref_log)\n\n  -- Should clean possible helper autocommands\n  eq(child.cmd_capture('au User'), '--- Autocommands ---')\nend\n\nT['set_picker_items_from_cli()']['has default postprocess'] = function()\n  -- Should remove all trailing empty lines\n  start_with_items()\n  mock_stdout_feed({ 'aa\\nbb \\n  \\n\\t\\n\\n\\n' })\n  set_picker_items_from_cli(test_command)\n  eq(get_picker_items(), { 'aa', 'bb ', '  ', '\\t' })\nend\n\nT['set_picker_items_from_cli()']['respects `opts.postprocess`'] = function()\n  start_with_items()\n  mock_stdout_feed({ 'aa\\nbb\\n' })\n  child.lua([[MiniPick.set_picker_items_from_cli(\n    { 'echo', 'aa\\nbb' },\n    { postprocess = function(lines)\n        _G.postprocess_input = lines\n        -- Should be possible to call `vim.fn` functions inside of it\n        local n_chars = vim.fn.strchars(lines[1])\n        -- Can return any number of items\n        return { 'item 1', 'item 2', 'item 3', 'item 4' }\n      end\n    }\n  )]])\n  eq(get_picker_items(), { 'item 1', 'item 2', 'item 3', 'item 4' })\n  eq(child.lua_get('_G.postprocess_input'), { 'aa', 'bb' })\nend\n\nT['set_picker_items_from_cli()']['respects `opts.set_item_opts`'] = function()\n  child.lua('MiniPick.set_picker_items = function(...) _G.args = { ... } end')\n  start_with_items()\n  mock_stdout_feed({ 'aa\\nbb' })\n  set_picker_items_from_cli(test_command, { set_items_opts = { custom_option = true } })\n  eq(child.lua_get('_G.args'), { { 'aa', 'bb' }, { custom_option = true } })\nend\n\nT['set_picker_items_from_cli()']['respects `opts.spawn_opts`'] = function()\n  start_with_items()\n  set_picker_items_from_cli({ 'echo', 'arg1', 'arg2' }, { spawn_opts = { env = { HELLO = 'WORLD' } } })\n  validate_spawn_log({\n    executable = 'echo',\n    options = { args = { 'arg1', 'arg2' }, env = { HELLO = 'WORLD' } },\n  }, 1)\nend\n\nT['set_picker_items_from_cli()']['forces absolute path of `opts.spawn_opts.cwd`'] = function()\n  start_with_items()\n  set_picker_items_from_cli({ 'echo', 'arg' }, { spawn_opts = { cwd = 'tests' } })\n  validate_spawn_log({\n    executable = 'echo',\n    options = { args = { 'arg' }, cwd = full_path('tests') },\n  }, 1)\nend\n\nT['set_picker_items_from_cli()']['validates arguments'] = function()\n  expect.error(function() set_picker_items_from_cli(1) end, '`command`.*array of strings')\n  expect.error(function() set_picker_items_from_cli({}) end, '`command`.*array of strings')\n  expect.error(function() set_picker_items_from_cli({ 'a', 2, 'c' }) end, '`command`.*array of strings')\nend\n\nT['set_picker_match_inds()'] = new_set()\n\nlocal set_picker_match_inds = forward_lua('MiniPick.set_picker_match_inds')\n\nT['set_picker_match_inds()']['works'] = function()\n  child.lua_notify([[MiniPick.start({\n    source = {\n      items = { 'a', 'b', 'bb' },\n      match = function() MiniPick.set_picker_match_inds({ 2 }) end,\n    },\n  })]])\n  child.expect_screenshot()\n  eq(get_picker_matches().all_inds, { 2 })\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(set_picker_match_inds({ 1 }), vim.NIL)\nend\n\nT['set_picker_match_inds()']['updates cache'] = function()\n  local validate_match_calls = make_match_with_count()\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'bb' }, match = _G.match_with_count },\n    options = { use_cache = true },\n  })]])\n  validate_match_calls(0, { 1, 2, 3 })\n\n  type_keys('a')\n  validate_match_calls(1, { 1 })\n\n  -- - Setting match inds should not trigger `source.match`\n  set_picker_match_inds({ 2, 3 })\n  validate_match_calls(1, { 2, 3 })\n\n  type_keys('<BS>')\n  validate_match_calls(1, { 1, 2, 3 })\n\n  type_keys('a')\n  validate_match_calls(1, { 2, 3 })\nend\n\nT['set_picker_match_inds()']['sets first index as current'] = function()\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a', 'b', 'bb' }, match = function() end } })]])\n\n  type_keys('<C-n>', '<C-n>')\n  validate_current_ind(3)\n\n  set_picker_match_inds({ 2, 3 })\n  validate_current_ind(2)\nend\n\nT['set_picker_match_inds()']['triggers relevant event'] = function()\n  child.lua('_G.log = {}')\n  child.cmd('au User MiniPickMatch lua table.insert(_G.log, MiniPick.get_picker_matches().all)')\n\n  start_with_items({ 'a', 'b', 'c' })\n  -- Should trigger first during item setting and then after query matching\n  eq(child.lua_get('_G.log'), { { 'a', 'b', 'c' }, { 'a', 'b', 'c' } })\n  child.lua('_G.log = {}')\n\n  set_picker_match_inds({ 2, 3 })\n  eq(child.lua_get('_G.log'), { { 'b', 'c' } })\nend\n\nT['set_picker_match_inds()']['can set current match index'] = function()\n  child.set_size(10, 35)\n  start_with_items({ 'a', 'b', 'c', 'da' })\n\n  set_picker_match_inds({ 3 }, 'current')\n  eq(get_picker_matches().current, 'c')\n  eq(get_picker_matches().current_ind, 3)\n  -- - Should update in overall view too\n  child.expect_screenshot()\n\n  -- Only first one should be used\n  set_picker_match_inds({ 2, 3 }, 'current')\n  eq(get_picker_matches().current_ind, 2)\n\n  -- Should treat as absolute indexes (i.e. indexes among all items)\n  type_keys('a')\n  set_picker_match_inds({ 4 }, 'current')\n  eq(get_picker_matches().current_ind, 4)\n\n  -- Should still update automatically later\n  type_keys('<C-u>')\n  eq(get_picker_matches().current_ind, 1)\n\n  -- Should throw error on bad input\n  type_keys('a')\n  expect.error(function() set_picker_match_inds({ 2 }, 'current') end, 'among all current matches')\n  type_keys('<C-u>')\n\n  type_keys('x')\n  expect.error(function() set_picker_match_inds({ 1 }, 'current') end, 'among all current matches')\n  type_keys('<C-u>')\n\n  expect.error(function() set_picker_match_inds(4, 'current') end, 'array')\n  expect.error(function() set_picker_match_inds({ 0 }, 'current') end, 'among all current matches')\n  expect.error(function() set_picker_match_inds({ 100 }, 'current') end, 'among all current matches')\nend\n\nT['set_picker_match_inds()']['can set marked match indexes'] = function()\n  child.set_size(10, 35)\n  start_with_items({ 'a', 'b', 'c', 'da' })\n\n  set_picker_match_inds({ 2, 4 }, 'marked')\n  eq(get_picker_matches().marked, { 'b', 'da' })\n  eq(get_picker_matches().marked_inds, { 2, 4 })\n  -- - Should update in overall view too\n  child.expect_screenshot()\n\n  -- Should set all marked indexes to the input\n  set_picker_match_inds({ 3 }, 'marked')\n  eq(get_picker_matches().marked_inds, { 3 })\n  child.expect_screenshot()\n\n  set_picker_match_inds({}, 'marked')\n  eq(get_picker_matches().marked_inds, {})\n\n  -- Should be able to mark not currently matched to query\n  type_keys('a')\n  set_picker_match_inds({ 2 }, 'marked')\n  eq(get_picker_matches().marked_inds, { 2 })\n\n  -- Should still be able to manually mark afterwards\n  type_keys('<C-x>')\n  eq(get_picker_matches().marked_inds, { 1, 2 })\n\n  -- Should throw error on bad input\n  expect.error(function() set_picker_match_inds({ 0 }, 'marked') end, 'from 1 to number of items')\n  expect.error(function() set_picker_match_inds({ 100 }, 'marked') end, 'from 1 to number of items')\nend\n\nT['set_picker_match_inds()']['validates arguments'] = function()\n  expect.error(function() set_picker_match_inds(1) end, '`match_inds`.*array')\n  expect.error(function() set_picker_match_inds({ 'a' }) end, '`match_inds`.*numbers')\n  expect.error(function() set_picker_match_inds({ 1 }, 1) end, '`match_type`.*one of')\n  expect.error(function() set_picker_match_inds({ 1 }, 'x') end, '`match_type`.*one of')\nend\n\nT['set_picker_opts()'] = new_set()\n\nT['set_picker_opts()']['works'] = function()\n  local target_win_id = child.api.nvim_get_current_win()\n  local init_cwd = child.fn.getcwd()\n  start_with_items({ 'a', 'b', 'bb' })\n  child.expect_screenshot()\n\n  child.lua([[MiniPick.set_picker_opts({ source = { name = 'My name' }, window = { config = { col = 5 } } })]])\n  child.expect_screenshot()\n\n  -- Can be used to update mappings\n  child.lua([[MiniPick.set_picker_opts({\n    mappings = { log = { char = '<C-d>', func = function() _G.log = 'hello' end } },\n  })]])\n  type_keys('<C-d>')\n  eq(child.lua_get('_G.log'), 'hello')\n\n  -- Should update present options, not override them\n  child.lua([[MiniPick.set_picker_opts({\n    mappings = { log2 = { char = '<C-z>', func = function() _G.log = 'world' end } },\n  })]])\n  type_keys('<C-z>')\n  eq(child.lua_get('_G.log'), 'world')\n  type_keys('<C-d>')\n  eq(child.lua_get('_G.log'), 'hello')\n\n  -- Can be used to update cwd\n  child.lua('_G.cwd = ' .. vim.inspect(test_dir))\n  child.lua('MiniPick.set_picker_opts({ source = { items = { { path = \"file\" } }, cwd = _G.cwd } })')\n  eq(child.lua_get('MiniPick.get_picker_opts().source.cwd'), test_dir)\n  eq(child.fn.getcwd(0), full_path(test_dir))\n  eq(child.fn.getcwd(target_win_id), init_cwd)\n\n  -- Should rerun match, but only if necessary\n  type_keys('<C-n>')\n  eq(get_picker_matches().current_ind, 2)\n  child.lua([[MiniPick.set_picker_opts({ source = { name = 'My other name' } })]])\n  eq(get_picker_matches().current_ind, 2)\n\n  child.lua('MiniPick.set_picker_opts({ source = { match = function() return { 2 } end } })')\n  eq(get_picker_matches().all_inds, { 2 })\n  child.expect_screenshot()\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(child.lua([[MiniPick.set_picker_opts({ source = { name = 'New name' } })]]), vim.NIL)\nend\n\nT['set_picker_target_window()'] = new_set()\n\nT['set_picker_target_window()']['works'] = function()\n  local win_id_1, win_id_2 = setup_windows_pair()\n  local path = real_file('b.txt')\n  start_with_items({ path })\n  child.lua(string.format('MiniPick.set_picker_target_window(%d)', win_id_2))\n  type_keys('<CR>')\n\n  validate_buf_name(child.api.nvim_win_get_buf(win_id_1), '')\n  validate_buf_name(child.api.nvim_win_get_buf(win_id_2), path)\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  local lua_cmd = string.format('MiniPick.set_picker_target_window(%d)', win_id_2)\n  eq(child.lua_get(lua_cmd), vim.NIL)\nend\n\nT['set_picker_target_window()']['validates arguments'] = function()\n  expect.error(function() child.lua('MiniPick.set_picker_target_window(-1)') end, '`win_id`.*not a valid window')\nend\n\nT['set_picker_query()'] = new_set()\n\nT['set_picker_query()']['works'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n\n  -- Should update querytick\n  local querytick = get_querytick()\n  set_picker_query({ 'b', 'b' })\n  eq(get_querytick(), querytick + 1)\n\n  -- Should match and update visual feedback\n  child.expect_screenshot()\n\n  -- Can be called without active picker\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\n  eq(set_picker_query({ 'a' }), vim.NIL)\nend\n\nT['set_picker_query()']['does not have side effects'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n\n  child.lua([[\n    _G.query = { 'b' }\n    MiniPick.set_picker_query(_G.query)\n  ]])\n\n  type_keys('b')\n  eq(child.lua_get('_G.query'), { 'b' })\nend\n\nT['set_picker_query()']['resets caret'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n  type_keys('b', 'b', '<Left>')\n  eq(get_picker_state().caret, 2)\n\n  set_picker_query({ 'x', 'x', 'x', 'x' })\n  eq(get_picker_state().caret, 5)\n\n  set_picker_query({ 'x' })\n  eq(get_picker_state().caret, 2)\nend\n\nT['set_picker_query()']['respects cache'] = function()\n  local validate_match_calls = make_match_with_count()\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'bb' }, match = _G.match_with_count },\n    options = { use_cache = true },\n  })]])\n  validate_match_calls(0, { 1, 2, 3 })\n\n  -- Should update it\n  set_picker_query({ 'b' })\n  validate_match_calls(1, { 2, 3 })\n\n  type_keys('<BS>', 'b')\n  validate_match_calls(1, { 2, 3 })\n\n  -- Should use it\n  type_keys('<BS>')\n  set_picker_query({ 'b' })\n  validate_match_calls(1, { 2, 3 })\nend\n\nT['set_picker_query()']['resets match inds prior to matching'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n  type_keys('b')\n  eq(get_picker_matches().all_inds, { 2, 3 })\n\n  set_picker_query({ 'a' })\n  eq(get_picker_matches().all_inds, { 1 })\nend\n\nT['set_picker_query()']['validates arguments'] = function()\n  expect.error(function() set_picker_query(1) end, '`query`.*array')\n  expect.error(function() set_picker_query({ 1 }) end, '`query`.*strings')\nend\n\nT['get_querytick()'] = new_set()\n\nlocal get_querytick = forward_lua('MiniPick.get_querytick')\n\nT['get_querytick()']['works'] = function()\n  local init_querytick = get_querytick()\n  eq(type(init_querytick), 'number')\n\n  local validate = function(increase) eq(get_querytick(), init_querytick + increase) end\n\n  -- Should increase after start, any query update, and stop, but not on move\n  -- - Start\n  start_with_items({ 'a', 'b', 'bb' })\n  validate(1)\n\n  -- - Query update\n  type_keys('a')\n  validate(2)\n\n  type_keys('<C-u>')\n  validate(3)\n\n  set_picker_query({ 'a', 'b' })\n  validate(4)\n\n  type_keys('<BS>')\n  validate(5)\n\n  -- - Move\n  type_keys('<Left>')\n  validate(5)\n\n  type_keys('<C-n>')\n  validate(5)\n\n  type_keys('<C-p>')\n  validate(5)\n\n  type_keys('<C-f>')\n  validate(5)\n\n  -- - Change view\n  type_keys('<Tab>')\n  validate(5)\n\n  type_keys('<S-Tab>')\n  validate(5)\n\n  -- - Stop\n  type_keys('<C-c>')\n  validate(6)\nend\n\nT['get_querytick()']['updates even with enabled cache'] = function()\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a', 'b' } }, options = { use_cache = true } })]])\n  local init_querytick = get_querytick()\n\n  type_keys('a')\n  eq(get_querytick(), init_querytick + 1)\n\n  type_keys('<BS>')\n  eq(get_querytick(), init_querytick + 2)\n\n  type_keys('a')\n  eq(get_querytick(), init_querytick + 3)\nend\n\nT['is_picker_active()'] = new_set()\n\nT['is_picker_active()']['works'] = function()\n  eq(is_picker_active(), false)\n  start_with_items()\n  eq(is_picker_active(), true)\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\nend\n\nT['poke_is_picker_active()'] = new_set()\n\nlocal poke_is_picker_active = forward_lua('MiniPick.poke_is_picker_active')\n\nT['poke_is_picker_active()']['works without running coroutine'] = function()\n  eq(poke_is_picker_active(), false)\n  start_with_items()\n  eq(poke_is_picker_active(), true)\n  type_keys('<C-c>')\n  eq(poke_is_picker_active(), false)\nend\n\nT['poke_is_picker_active()']['works with running coroutine'] = function()\n  start_with_items()\n  eq(poke_is_picker_active(), true)\n\n  child.lua([[\n    -- Poke on next event loop\n    local f = function() _G.is_active_poke = MiniPick.poke_is_picker_active() end\n    coroutine.resume(coroutine.create(f))\n    _G.is_active_direct = MiniPick.is_picker_active()\n\n    -- Detect no poking before\n    _G.has_not_poked_yet = _G.is_active_poke == nil\n  ]])\n  eq(child.lua_get('_G.is_active_direct'), true)\n  eq(child.lua_get('_G.has_not_poked_yet'), true)\n  eq(child.lua_get('_G.is_active_poke'), true)\nend\n\n-- Integration tests ==========================================================\nT[':Pick'] = new_set()\n\nT[':Pick']['works'] = function()\n  mock_opened_buffers()\n\n  local validate = function(args)\n    child.api_notify.nvim_exec('Pick ' .. args, false)\n    eq(is_picker_active(), true)\n    child.expect_screenshot()\n    type_keys('<C-c>')\n  end\n\n  validate('buffers')\n  validate('buffers include_unlisted=true')\nend\n\nT[':Pick']['correctly parses arguments'] = function()\n  child.lua('MiniPick.registry.aaa = function(...) _G.args = { ... } end')\n\n  child.cmd([[Pick aaa b='b' c=3 d={x=1,\\ y=2}]])\n  eq(child.lua_get('_G.args'), { { b = 'b', c = 3, d = { x = 1, y = 2 } } })\n\n  -- Expands arguments\n  child.cmd('edit ' .. real_file('b.txt'))\n  child.cmd([[Pick aaa basename='%:t' extension='%:e']])\n  eq(child.lua_get('_G.args'), { { basename = 'b.txt', extension = 'txt' } })\n\n  -- Throws informative error (here because of not escaped whitespace)\n  expect.error(function() child.cmd([[Pick aaa t={ a = 1}]]) end, 'Could not convert.*to table.*t={,')\nend\n\nT[':Pick']['has proper complete'] = function()\n  child.set_size(10, 30)\n  local validate = function(keys)\n    type_keys(':Pick ', keys, '<Tab>')\n    child.expect_screenshot()\n    type_keys('<C-c>')\n  end\n\n  validate({})\n  validate({ 'f' })\n  validate({ 'f x', '<Left>', '<Left>' })\nend\n\nT[':Pick']['validates arguments'] = function()\n  expect.error(function() child.cmd('Pick aaa') end, 'no picker named \"aaa\"')\nend\n\nT['Overall view'] = new_set()\n\nT['Overall view']['shows prompt'] = function()\n  child.set_size(10, 20)\n  start_with_items()\n\n  -- Initial\n  child.expect_screenshot()\n\n  -- After typical typing\n  type_keys('a')\n  child.expect_screenshot()\n  type_keys(' b')\n  child.expect_screenshot()\n\n  -- After moving caret\n  type_keys('<Left>')\n  child.expect_screenshot()\n  type_keys('<Left>')\n  child.expect_screenshot()\nend\n\nT['Overall view']['uses footer for extra info'] = function()\n  start_with_items({ 'a', 'b', 'bb', 'bbb' }, 'My name')\n  child.expect_screenshot()\n\n  -- Should update after matching\n  type_keys('b')\n  child.expect_screenshot()\n\n  -- Should update after moving\n  type_keys('<C-n>')\n  child.expect_screenshot()\n\n  -- Should update after marking and unmarking\n  type_keys('<C-x>')\n  child.expect_screenshot()\n  type_keys('<C-x>')\n  child.expect_screenshot()\n\n  -- Should correctly show no matches\n  type_keys('x')\n  child.expect_screenshot()\nend\n\nT['Overall view']['correctly infers footer empty space'] = function()\n  local validate = function(win_config)\n    local lua_cmd = string.format('MiniPick.config.window.config = %s', vim.inspect(win_config))\n    child.lua(lua_cmd)\n    start_with_items({ 'a' })\n    child.expect_screenshot()\n    type_keys('<C-c>')\n  end\n\n  -- Check both `border = 'double'` and `border = <custom_array>`\n  validate({ border = 'double' })\n  validate({ border = { '!', '@', '#', '$', '%', '^', '&', '*' } })\n  --stylua: ignore\n  validate({\n    border = {\n      { '!', 'Normal' }, { '@', 'Normal' }, { '#', 'Normal' }, { '$', 'Normal' },\n      { '%', 'Normal' }, { '^', 'Normal' }, { '&', 'Normal' }, { '*', 'Normal' }\n    },\n  })\n\n  -- Should respect `content_from_bottom`\n  child.lua('MiniPick.config.options.content_from_bottom = true')\n  validate({ border = { '!', '@', '#', '$', '%', '^', '&', '*' } })\nend\n\nT['Overall view']['does not show footer if items are not set'] = function()\n  start_with_items()\n  child.expect_screenshot()\nend\n\nT['Overall view']['sanitizes picker name'] = function()\n  local bad_name = 'Bad\\000multi\\nline\\npicker\\tname\\n'\n\n  child.lua('MiniPick.config.window.config = { width = vim.o.columns }')\n  start_with_items({ 'a' }, bad_name)\n  child.expect_screenshot()\n  stop()\n\n  child.lua('MiniPick.config.options.content_from_bottom = true')\n  start_with_items({ 'a' }, bad_name)\n  child.expect_screenshot()\nend\n\nT['Overall view']['respects `options.content_from_bottom` with footer'] = function()\n  start({ source = { items = { 'a', 'b' } }, options = { content_from_bottom = true } })\n  child.expect_screenshot()\nend\n\nT['Overall view']['truncates prompt'] = function()\n  child.set_size(10, 17)\n  -- Should work with non-default lengths and multibyte characters in both\n  -- prefix and caret\n  child.lua('MiniPick.config.window.prompt_prefix = \"<ы>\"')\n  child.lua('MiniPick.config.window.prompt_caret = \"!Ы!\"')\n  start_with_items({ 'a' }, 'Test')\n\n  -- Should work with multibyte characters in query\n  local query = 'abcйцф_'\n  type_keys(query)\n  child.expect_screenshot()\n  for _ = 1, vim.fn.strchars(query) do\n    type_keys('<Left>')\n    child.expect_screenshot()\n  end\n\n  -- Should work with more single character query parts\n  local query_arr = { 'ab', 'cde', 'fgh', 'ij' }\n  set_picker_query(query_arr)\n  child.expect_screenshot()\n  for _ = 1, #query_arr do\n    type_keys('<Left>')\n    child.expect_screenshot()\n  end\nend\n\nT['Overall view']['truncates footer'] = function()\n  local validate = function(...)\n    child.set_size(...)\n    start_with_items({ 'a' }, 'Very long name')\n    child.expect_screenshot()\n    type_keys('<C-c>')\n  end\n\n  validate(10, 20)\n  -- Should not partially show footer indexes, only in full (when space allows)\n  validate(10, 38)\n  validate(10, 39)\nend\n\nT['Overall view']['allows \"none\" as border'] = function()\n  child.lua([[MiniPick.config.window.config = { border = 'none' }]])\n  start_with_items({ 'a' }, 'My name')\n  child.expect_screenshot()\nend\n\nT['Overall view']['adjusts dimensions respecting border'] = function()\n  child.set_size(10, 20)\n  child.o.laststatus, child.o.showtabline, child.o.cmdheight = 0, 0, 0\n  child.lua([[MiniPick.config.window.config = { width = vim.o.columns, height = vim.o.lines }]])\n\n  start_with_items({ 'a' }, 'My name')\n  child.expect_screenshot()\n\n  local validate_border = function(border)\n    local border_str = vim.inspect(border)\n    local lua_cmd = string.format('MiniPick.set_picker_opts({ window = { config = { border = %s } } })', border_str)\n    child.lua(lua_cmd)\n    child.expect_screenshot()\n  end\n\n  -- All sides\n  validate_border({ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' })\n  -- No left side\n  validate_border({ '', 'b', 'c', 'd', 'e', 'f', '', '' })\n  -- No right side\n  validate_border({ 'a', 'b', '', '', '', 'f', 'g', 'h' })\n  -- No left and right side\n  validate_border({ '', 'b', '', '', '', 'f', '', '' })\n  -- No top side\n  validate_border({ '', '', '', 'd', 'e', 'f', 'g', 'h' })\n  -- No bottom side\n  validate_border({ 'a', 'b', 'c', 'd', '', '', '', 'h' })\n  -- No top and bottom side\n  validate_border({ '', '', '', 'd', '', '', '', 'h' })\n\n  -- Different length of border array\n  validate_border({ 'a', 'b', 'c', 'd' })\n  validate_border({ 'a', 'b' })\n  validate_border({ 'a' })\n  -- No left and right side\n  validate_border({ '', 'b', '', '' })\n  -- No top and bottom side\n  validate_border({ '', '', '', 'd' })\n\n  -- Forced no sides\n  validate_border({ 'a', '' })\n  validate_border({ '' })\n\n  -- Special \"no sides\"\n  validate_border('none')\nend\n\nT['Overall view'][\"respects 'winborder' option\"] = function()\n  if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n\n  local validate = function(winborder)\n    child.o.winborder = winborder\n    start_with_items({ 'a', 'b', 'c' })\n    child.expect_screenshot()\n    stop()\n  end\n\n  validate('rounded')\n\n  -- Should prefer explicitly configured value over 'winborder'\n  child.lua('MiniPick.config.window.config = { border = \"double\" }')\n  validate('rounded')\n\n  -- Should infer custom border (for visible title/footer) for `winborder=none`\n  child.lua('MiniPick.config.window.config = nil')\n  validate('none')\n\n  -- Should work with \"string array\" 'winborder'\n  if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n  validate('+,-,+,|,+,-,+,|')\nend\n\nT['Overall view'][\"respects tabline, statusline, 'cmdheight'\"] = function()\n  local validate = function(screenshot_opts)\n    start_with_items({ 'a' }, 'My name')\n    child.expect_screenshot(screenshot_opts)\n    type_keys('<C-c>')\n  end\n\n  child.set_size(10, 20)\n  child.o.tabline, child.o.statusline = 'My tabline', 'My statusline'\n\n  child.o.showtabline, child.o.laststatus = 2, 2\n  validate()\n\n  child.o.showtabline, child.o.laststatus = 2, 0\n  validate()\n\n  child.o.showtabline, child.o.laststatus = 0, 2\n  validate()\n\n  child.o.showtabline, child.o.laststatus = 0, 0\n  validate()\n\n  child.o.cmdheight = 2\n  local ignore_cmdline_hl = child.fn.has('nvim-0.11') == 1 and {} or { ignore_attr = { 9, 10 } }\n  validate(ignore_cmdline_hl)\n\n  child.o.cmdheight = 0\n  validate()\nend\n\nT['Overall view']['works with small available dimensions'] = function()\n  child.set_size(5, 40)\n  child.o.showtabline, child.o.laststatus = 0, 0\n  child.o.cmdheight = 4\n\n  start_with_items({ 'a' }, 'My name')\n  child.expect_screenshot({ ignore_attr = child.fn.has('nvim-0.11') == 0 })\nend\n\nT['Overall view'][\"respects 'guicursor'\"] = function()\n  local validate = function(keys, init_guicursor)\n    init_guicursor = init_guicursor or 'n-v-c:block'\n    child.o.guicursor = init_guicursor\n    type_keys(keys)\n    start_with_items({ 'a' }, 'My name')\n    -- Should *temporarily* force custom 'guicursor' to hide cursor\n    eq(child.o.guicursor, 'a:MiniPickCursor')\n    type_keys('<C-c>')\n    eq(child.o.guicursor, init_guicursor)\n    child.ensure_normal_mode()\n  end\n\n  -- Should work in all modes\n  validate('')\n  validate('i')\n  validate('v')\n  validate(':')\n\n  -- Should work with empty guicursor. Should also work around empty string\n  -- 'guicursor' by first setting to some other \"neutral\" value and redrawing.\n  child.cmd('au OptionSet guicursor lua _G.n = (_G.n or 0) + 1')\n  validate('', '')\n  eq(child.lua_get('_G.n'), 4)\nend\n\nT['Overall view']['allows very large dimensions'] = function()\n  child.lua('MiniPick.config.window.config = { height = 100, width = 200 }')\n  start_with_items({ 'a' }, 'My name')\n  child.expect_screenshot()\nend\n\nT['Overall view']['uses dedicated highlight groups'] = function()\n  start_with_items(nil, 'My name')\n  local win_id = get_picker_state().windows.main\n  sleep(default_busy_delay + small_time)\n\n  -- Busy picker\n  eq(get_picker_state().is_busy, true)\n\n  local winhighlight = child.api.nvim_win_get_option(win_id, 'winhighlight')\n  expect.match(winhighlight, 'NormalFloat:MiniPickNormal')\n  expect.match(winhighlight, 'FloatBorder:MiniPickBorderBusy')\n\n  -- Not busy picker\n  set_picker_items({ 'a' })\n  eq(get_picker_state().is_busy, false)\n\n  winhighlight = child.api.nvim_win_get_option(win_id, 'winhighlight')\n  expect.match(winhighlight, 'FloatBorder:MiniPickBorder')\n\n  type_keys('a')\n  local win_config = child.api.nvim_win_get_config(win_id)\n  local ref_title = { { '> ', 'MiniPickPromptPrefix' }, { 'a', 'MiniPickPrompt' }, { '▏', 'MiniPickPromptCaret' } }\n  eq(win_config.title, ref_title)\n\n  -- Footer support is present only on Neovim>=0.10\n  if child.fn.has('nvim-0.10') == 1 then\n    win_config = child.api.nvim_win_get_config(win_id)\n    local footer = win_config.footer\n    eq(footer[1], { ' My name ', 'MiniPickBorderText' })\n    eq(footer[2][2], 'MiniPickBorder')\n    eq(footer[3], { ' 1|1|1 ', 'MiniPickBorderText' })\n  end\nend\n\nT['Overall view']['is shown over number and sign columns'] = function()\n  child.set_size(10, 20)\n  child.o.number, child.o.signcolumn = true, 'yes'\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { 'a', 'b', 'c', 'd', 'e' })\n  start_with_items({ 'a' })\n  child.expect_screenshot()\nend\n\nT['Main view'] = new_set()\n\nT['Main view']['uses dedicated highlight groups'] = function()\n  local validate_extmark = function(extmark_data, line, hl_group)\n    eq({ extmark_data[2], extmark_data[4].hl_group }, { line - 1, hl_group })\n  end\n\n  child.lua([[MiniPick.config.source.show = function(buf_id, items, query)\n    return MiniPick.default_show(buf_id, items, query, { show_icons = true })\n  end]])\n  start_with_items({ real_file('b.txt'), test_dir, 'marked', 'current' })\n  local buf_id = get_picker_state().buffers.main\n  type_keys('<C-n>', '<C-n>', '<C-x>', '<C-n>')\n\n  local match_ns_id = child.api.nvim_get_namespaces().MiniPickMatches\n  local match_extmarks = child.api.nvim_buf_get_extmarks(buf_id, match_ns_id, 0, -1, { details = true })\n  validate_extmark(match_extmarks[1], 3, 'MiniPickMatchMarked')\n  validate_extmark(match_extmarks[2], 4, 'MiniPickMatchCurrent')\n\n  type_keys('d', 'i', 'r')\n\n  local ranges_ns_id = child.api.nvim_get_namespaces().MiniPickRanges\n  local ranges_extmarks = child.api.nvim_buf_get_extmarks(buf_id, ranges_ns_id, 0, -1, { details = true })\n  validate_extmark(ranges_extmarks[1], 1, 'MiniPickIconFile')\n  validate_extmark(ranges_extmarks[2], 1, 'MiniPickMatchRanges')\n  validate_extmark(ranges_extmarks[3], 1, 'MiniPickMatchRanges')\n  validate_extmark(ranges_extmarks[4], 1, 'MiniPickMatchRanges')\n  validate_extmark(ranges_extmarks[5], 2, 'MiniPickIconDirectory')\n  validate_extmark(ranges_extmarks[6], 2, 'MiniPickMatchRanges')\n  validate_extmark(ranges_extmarks[7], 2, 'MiniPickMatchRanges')\n  validate_extmark(ranges_extmarks[8], 2, 'MiniPickMatchRanges')\nend\n\nT['Main view']['works with `content_from_bottom`=true'] = function()\n  child.set_size(10, 30)\n  child.lua([[MiniPick.config.options.content_from_bottom = true]])\n  local items = { 'a', 'b', 'bb', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7' }\n\n  local validate = function()\n    child.expect_screenshot()\n\n    type_keys('<C-p>')\n    child.expect_screenshot()\n\n    type_keys('b')\n    child.expect_screenshot()\n\n    type_keys('<C-p>')\n    child.expect_screenshot()\n\n    type_keys('<C-p>')\n    child.expect_screenshot()\n\n    type_keys('<C-c>')\n  end\n\n  -- With `default_show`\n  start_with_items(items)\n  validate()\n\n  -- With custom `show`\n  local lua_cmd = string.format(\n    [[_G.custom_show = function(buf_id, items, query)\n        local lines = vim.tbl_map(function(x) return 'Item ' .. x end, items)\n        -- Lines should still be set as if direction is from top\n        vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)\n      end\n\n      MiniPick.start({ source = { items = %s, show = _G.custom_show } })]],\n    vim.inspect(items)\n  )\n  child.lua_notify(lua_cmd)\n  validate()\nend\n\nT['Main view']['shows marked items across queries'] = function()\n  child.set_size(10, 20)\n  start_with_items({ 'a', 'ab', 'b', 'bb' })\n  type_keys('a', 'b', '<C-x>', '<C-u>')\n  child.expect_screenshot()\n  type_keys('b')\n  child.expect_screenshot()\nend\n\nT['Main view']['supports vertical scroll'] = function()\n  child.set_size(10, 15)\n\n  local items = {}\n  for i = 1, 100 do\n    items[i] = 'Very big line ' .. i\n  end\n  start_with_items(items)\n  validate_current_ind(1)\n\n  local height = child.api.nvim_win_get_config(get_picker_state().windows.main).height\n\n  -- Vertical scroll should update current item\n  type_keys('<C-f>')\n  validate_current_ind(height + 1)\n  type_keys('<C-f>')\n  validate_current_ind(2 * height + 1)\n\n  type_keys('<C-b>')\n  validate_current_ind(height + 1)\n  type_keys('<C-b>')\n  validate_current_ind(1)\nend\n\nT['Main view']['supports horizontal scroll'] = function()\n  child.set_size(10, 15)\n\n  start_with_items({ 'Short 1', 'Very long item 2', 'Short 3' })\n\n  -- Horizontal scroll should move window view as if cursor is on current item\n  type_keys('<C-l>')\n  child.expect_screenshot()\n  type_keys('<C-l>')\n  child.expect_screenshot()\n  -- - Can't move further because cursor is already on the last item column\n  type_keys('<C-l>')\n  child.expect_screenshot()\n\n  -- Moving item at non-trivial right scroll should preserve horizontal\n  -- view as much as items width allows\n  type_keys('<C-n>')\n  child.expect_screenshot()\n\n  -- Should be able to scroll further horizontally on longer\n  type_keys('<C-l>')\n  child.expect_screenshot()\n\n  -- Should be able to move item from longer to shorter\n  type_keys('<C-n>')\n  child.expect_screenshot()\nend\n\nT['Main view']['properly computes items range to show'] = function()\n  child.set_size(7, 15)\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 1, 2, 3, 4, 5, 6, 7, 8, 9 } },\n    window = { config = { height = 4 } },\n  })]])\n\n  child.expect_screenshot()\n  for _ = 1, 9 do\n    type_keys('<C-n>')\n    child.expect_screenshot()\n  end\n\n  for _ = 1, 9 do\n    type_keys('<C-p>')\n    child.expect_screenshot()\n  end\n\n  for _ = 1, 3 do\n    type_keys('<C-f>')\n    child.expect_screenshot()\n  end\n\n  for _ = 1, 3 do\n    type_keys('<C-b>')\n    child.expect_screenshot()\n  end\nend\n\nT['Main view']['does not inherit highlighting from `matchparen`'] = function()\n  child.cmd('packadd matchparen')\n  child.set_lines({ '(  )' })\n  child.set_cursor(1, 0)\n\n  start_with_items({ 'aaaaaaaa' })\n  eq(child.fn.getmatches(get_picker_state().windows.main), {})\nend\n\nT['Main view']['has correct local cwd'] = function()\n  local target_win_id = child.api.nvim_get_current_win()\n  child.lua('_G.cwd = ' .. vim.inspect(test_dir_absolute .. '/builtin-tests'))\n  child.fn.chdir(test_dir_absolute)\n  child.lua_notify('MiniPick.start({ source = { cwd = _G.cwd } })')\n\n  -- Should set local cwd per window and not affect other windows\n  eq(child.fn.getcwd(0):gsub('\\\\', '/'), full_path(test_dir_absolute .. '/builtin-tests'):gsub('\\\\', '/'))\n  eq(child.fn.getcwd(target_win_id), test_dir_absolute)\nend\n\nT['Info view'] = new_set()\n\nT['Info view']['works'] = function()\n  child.set_size(40, 60)\n  child.lua('MiniPick.config.window.config = { height = 40 }')\n\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n  mock_picker_cwd(test_dir)\n  type_keys('<S-Tab>')\n  child.expect_screenshot()\nend\n\nT['Info view']['respects custom mappings'] = function()\n  child.set_size(23, 60)\n  child.lua([[MiniPick.config.mappings.custom_action = { char = '<C-d>', func = function() print('Hello') end }]])\n  child.lua([[MiniPick.config.mappings.another_action = { char = '<C-e>', func = function() print('World') end }]])\n  -- Should prefer custom action key over built-in\n  child.lua([[MiniPick.config.mappings.dup_key_action = { char = '<Left>', func = function() print('!!!') end }]])\n  child.lua([[MiniPick.config.mappings.choose = 'a']])\n  -- Should omit the rest of \"Choose\" as they are disabled\n  child.lua([[MiniPick.config.mappings.choose_in_split = '']])\n  child.lua([[MiniPick.config.mappings.choose_in_vsplit = '']])\n  child.lua([[MiniPick.config.mappings.choose_in_tabpage = '']])\n  child.lua([[MiniPick.config.mappings.choose_marked = '']])\n\n  child.lua([[MiniPick.config.window.config = { height = 20 }]])\n\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n  mock_picker_cwd(test_dir)\n  type_keys('<S-Tab>')\n  child.expect_screenshot()\nend\n\nT['Info view']['uses dedicated highlight groups'] = function()\n  local validate_extmark = function(extmark_data, line, hl_group)\n    eq({ extmark_data[2], extmark_data[4].hl_group }, { line - 1, hl_group })\n  end\n\n  child.lua([[MiniPick.config.mappings.custom_action = { char = '<C-d>', func = function() print('Hello') end }]])\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n  type_keys('<S-Tab>')\n  local buf_id = get_picker_state().buffers.info\n\n  local header_ns_id = child.api.nvim_get_namespaces().MiniPickHeaders\n  local header_extmarks = child.api.nvim_buf_get_extmarks(buf_id, header_ns_id, 0, -1, { details = true })\n  validate_extmark(header_extmarks[1], 1, 'MiniPickHeader')\n  validate_extmark(header_extmarks[2], 9, 'MiniPickHeader')\n  validate_extmark(header_extmarks[3], 12, 'MiniPickHeader')\nend\n\nT['Info view']['is updated after moving/marking current item'] = function()\n  child.set_size(15, 40)\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n  mock_picker_cwd(test_dir)\n  type_keys('<S-Tab>')\n  child.expect_screenshot()\n\n  -- Move\n  type_keys('<C-n>')\n  child.expect_screenshot()\n\n  -- Mark\n  type_keys('<C-x>')\n  child.expect_screenshot()\n\n  -- Unmark\n  type_keys('<C-x>')\n  child.expect_screenshot()\nend\n\nT['Info view']['switches to main after query update'] = function()\n  local validate = function(key)\n    type_keys('<S-Tab>')\n    validate_picker_view('info')\n    type_keys(key)\n    validate_picker_view('main')\n  end\n\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n\n  validate('b')\n  validate('<C-u>')\n  -- Even if query did not change\n  validate('<C-u>')\nend\n\nT['Info view']['supports vertical and horizontal scroll'] = function()\n  start_with_items({ 'a' })\n  mock_picker_cwd(test_dir)\n  type_keys('<S-Tab>')\n\n  local validate = function(key)\n    type_keys(key)\n    child.expect_screenshot()\n  end\n\n  validate('<C-l>')\n  validate('<C-h>')\n  validate('<C-f>')\n  validate('<C-b>')\nend\n\nT['Preview'] = new_set()\n\nT['Preview']['works'] = function()\n  start_with_items({ real_file('b.txt') }, 'My name')\n  type_keys('<Tab>')\n  child.expect_screenshot()\nend\n\nT['Preview']['uses dedicated highlight groups'] = function()\n  local preview_ns_id = child.api.nvim_get_namespaces().MiniPickPreview\n  local validate_preview_extmark = function(line, pos)\n    local buf_id = get_picker_state().buffers.preview\n    local preview_extmarks = child.api.nvim_buf_get_extmarks(buf_id, preview_ns_id, 0, -1, { details = true })\n\n    eq({ preview_extmarks[1][2], preview_extmarks[1][4].hl_group }, { line - 1, 'MiniPickPreviewLine' })\n    if pos ~= nil then\n      eq({ preview_extmarks[2][2], preview_extmarks[2][4].hl_group }, { pos - 1, 'MiniPickPreviewRegion' })\n    end\n  end\n\n  local path = real_file('b.txt')\n  local items = {\n    { text = 'Preview line', path = path, lnum = 3 },\n    { text = 'Preview position', path = path, lnum = 4, col = 2 },\n    { text = 'Preview region', path = path, lnum = 5, col = 3, end_lnum = 6, end_col = 2 },\n  }\n  start_with_items(items, 'My name')\n\n  type_keys('<Tab>')\n  validate_preview_extmark(3, nil, nil)\n\n  type_keys('<C-n>')\n  validate_preview_extmark(4, 4)\n\n  type_keys('<C-n>')\n  validate_preview_extmark(5, 5)\nend\n\nT['Preview']['is updated after moving current item'] = function()\n  child.set_size(15, 40)\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  type_keys('<C-n>')\n  child.expect_screenshot()\nend\n\nT['Preview']['remains same during (un)marking'] = function()\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n  type_keys('<Tab>')\n  local buf_id = get_picker_state().buffers.preview\n  eq(child.api.nvim_get_current_buf(), buf_id)\n\n  type_keys('<C-x>')\n  eq(child.api.nvim_get_current_buf(), buf_id)\n\n  type_keys('<C-x>')\n  eq(child.api.nvim_get_current_buf(), buf_id)\nend\n\nT['Preview']['switches to main after query update'] = function()\n  local validate = function(key)\n    type_keys('<Tab>')\n    validate_picker_view('preview')\n    type_keys(key)\n    validate_picker_view('main')\n  end\n\n  start_with_items({ 'a', 'b', 'bb' }, 'My name')\n\n  validate('b')\n  validate('<C-u>')\n  -- Even if query did not change\n  validate('<C-u>')\nend\n\nT['Preview']['supports vertical and horizontal scroll'] = function()\n  start_with_items({ real_file('b.txt') })\n  type_keys('<Tab>')\n\n  local validate = function(key)\n    type_keys(key)\n    child.expect_screenshot()\n  end\n\n  validate('<C-l>')\n  validate('<C-h>')\n  validate('<C-f>')\n  validate('<C-b>')\nend\n\nT['Preview']['handles `source.preview` setting buffer directly'] = function()\n  local buf_id_other = child.lua([[\n    _G.buf_id_other = vim.api.nvim_create_buf(false, true)\n    return _G.buf_id_other\n  ]])\n  child.api.nvim_buf_set_lines(buf_id_other, 0, -1, false, { 'Other preview buffer' })\n  child.lua_notify([[\n    local preview = function()\n      local state = MiniPick.get_picker_state()\n      vim.api.nvim_win_set_buf(state.windows.main, buf_id_other)\n    end\n    MiniPick.start({ source = { items = { 'a' }, name = 'Preview other', preview = preview } })\n  ]])\n  type_keys('<Tab>')\n\n  local state = get_picker_state()\n  eq(state.buffers.preview, buf_id_other)\n  eq(child.api.nvim_win_get_buf(state.windows.main), buf_id_other)\nend\n\nT['Preview']['does explicit redraw several times'] = function()\n  child.lua('_G.small_time = ' .. small_time)\n  child.lua_notify([[\n    local ns_id = vim.api.nvim_create_namespace('preview')\n    local preview = function(buf_id, item)\n      vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, { 'A highlight' })\n      vim.defer_fn(function()\n        vim.api.nvim_buf_set_extmark(buf_id, ns_id, 0, 0, { end_row = 0, end_col = 11, hl_group = 'String' })\n      end, 10 * _G.small_time)\n    end\n    MiniPick.start({\n      source = { items = { 'a' }, name = 'Preview redraw', preview = preview },\n      delay = { async = _G.small_time },\n    })\n  ]])\n\n  type_keys('<Tab>')\n  child.expect_screenshot()\n  sleep(10 * small_time + small_time)\n  child.expect_screenshot({ redraw = false })\nend\n\nT['Preview'][\"respects global value of 'list' and 'listchars' option\"] = function()\n  child.lua([[\n    MiniPick.config.source.preview = function(buf_id, item)\n      vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, { '\\tTabs', '    Spaces' })\n    end\n    MiniPick.config.window.config = { width = 8 }\n  ]])\n  child.o.listchars = 'tab:+ '\n  child.o.tabstop = 4\n  local validate = function(list)\n    child.o.list = list\n    start_with_items({ 'a long item' })\n    type_keys('<Tab>')\n    child.expect_screenshot()\n    -- Should always enable 'list' option in main view\n    type_keys('<Tab>')\n    child.expect_screenshot()\n\n    type_keys('<Esc>')\n  end\n\n  validate(true)\n  validate(false)\nend\n\nT['Matching'] = new_set()\n\nlocal start_with_items_matchlog = function(items)\n  child.lua([[\n    _G.match_log = {}\n    _G.match_with_log = function(...)\n      table.insert(_G.match_log, vim.deepcopy({ ... }))\n      MiniPick.default_match(...)\n    end]])\n  local lua_cmd =\n    string.format('MiniPick.start({ source = { items = %s, match = _G.match_with_log } })', vim.inspect(items))\n  child.lua_notify(lua_cmd)\nend\n\nlocal validate_match_log = function(ref) eq(child.lua_get('_G.match_log'), ref) end\nlocal validate_last_match_log = function(ref) eq(child.lua_get('_G.match_log[#_G.match_log]'), ref) end\nlocal clean_match_log = function() child.lua('_G.match_log = {}') end\n\nT['Matching']['works'] = function()\n  start_with_items_matchlog({ 'a', 'b', 'bb' })\n  -- - `match()` should be called on start for empty query\n  validate_match_log({ { { 'a', 'b', 'bb' }, { 1, 2, 3 }, {} } })\n  clean_match_log()\n\n  -- In regular query increase should use previous match inds (for performance)\n  type_keys('b')\n  validate_match_log({ { { 'a', 'b', 'bb' }, { 1, 2, 3 }, { 'b' } } })\n  clean_match_log()\n\n  type_keys('b')\n  validate_match_log({ { { 'a', 'b', 'bb' }, { 2, 3 }, { 'b', 'b' } } })\n  clean_match_log()\n\n  type_keys('x')\n  validate_match_log({ { { 'a', 'b', 'bb' }, { 3 }, { 'b', 'b', 'x' } } })\nend\n\nT['Matching']['uses stritems'] = function()\n  child.lua_notify([[MiniPick.start({ source = {\n    items = { 'a', { text = 'b' }, function() return 'bb' end },\n    match = function(...) _G.match_args = { ... }; return { 1 } end,\n  }})]])\n  eq(child.lua_get('_G.match_args'), { { 'a', 'b', 'bb' }, { 1, 2, 3 }, {} })\nend\n\nT['Matching']['uses cache'] = function()\n  child.lua('_G.match_n_calls = 0')\n  local validate_match_calls = function(n_calls_ref, match_inds_ref)\n    eq(child.lua_get('_G.match_n_calls'), n_calls_ref)\n    eq(get_picker_matches().all_inds, match_inds_ref)\n  end\n\n  child.lua_notify([[_G.match_shrink = function(stritems, match_inds, query)\n    _G.match_n_calls = _G.match_n_calls + 1\n    if #query == 0 then return { 1, 2, 3, 4 } end\n    return vim.list_slice(match_inds, 2, #match_inds)\n  end]])\n\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'ab', 'b', 'bb' }, match = _G.match_shrink },\n    options = { use_cache = true },\n  })]])\n\n  -- As all indexes are matched against empty query when setting them,\n  -- `match()` should not be called after start\n  validate_match_calls(0, { 1, 2, 3, 4 })\n\n  type_keys('b')\n  validate_match_calls(1, { 2, 3, 4 })\n\n  type_keys('b')\n  validate_match_calls(2, { 3, 4 })\n\n  type_keys('<BS>')\n  validate_match_calls(2, { 2, 3, 4 })\n\n  type_keys('<BS>')\n  validate_match_calls(2, { 1, 2, 3, 4 })\n\n  type_keys('b')\n  validate_match_calls(2, { 2, 3, 4 })\n\n  type_keys('x')\n  validate_match_calls(3, { 3, 4 })\n\n  type_keys('<C-u>')\n  validate_match_calls(3, { 1, 2, 3, 4 })\nend\n\nT['Matching']['resets matched indexes when needed'] = function()\n  local items = { 'a', 'b', 'bb' }\n  local validate_all_match_inds = function() validate_last_match_log({ items, { 1, 2, 3 }, get_picker_query() }) end\n\n  start_with_items_matchlog(items)\n\n  -- Any deleting\n  type_keys('b', 'b')\n\n  type_keys('<BS>')\n  validate_all_match_inds()\n\n  type_keys('<C-u>')\n  validate_all_match_inds()\n\n  type_keys('b', 'b', '<Left>')\n\n  type_keys('<Del>')\n  validate_all_match_inds()\n\n  type_keys('<C-w>')\n  validate_all_match_inds()\n\n  -- Adding character inside query\n  type_keys('b', '<Left>')\n  type_keys('x')\n  validate_all_match_inds()\n\n  type_keys('b', 'b', '<Left>')\n  type_keys('x')\n  validate_all_match_inds()\nend\n\nT['Matching']['triggers dedicated event'] = function()\n  child.lua('_G.log = {}')\n  local validate_log = function(ref_log)\n    eq(child.lua_get('_G.log'), ref_log)\n    child.lua('_G.log = {}')\n  end\n  child.cmd('au User MiniPickMatch lua table.insert(_G.log, MiniPick.get_picker_matches().all)')\n\n  start_with_items({ 'ba', 'ab', 'bb' })\n  -- - Triggered twice on start: during setting items and empty query matching\n  validate_log({ { 'ba', 'ab', 'bb' }, { 'ba', 'ab', 'bb' } })\n\n  type_keys('a')\n  validate_log({ { 'ab', 'ba' } })\n\n  type_keys('x')\n  validate_log({ {} })\n\n  type_keys('y')\n  validate_log({ {} })\n\n  type_keys('<BS>')\n  validate_log({ {} })\n\n  type_keys('<C-u>')\n  validate_log({ { 'ba', 'ab', 'bb' } })\n\n  type_keys('<C-c>')\n\n  -- Should trigger when using cache for match inds\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'ba', 'ab', 'bb' } },\n    options = { use_cache = true },\n  })]])\n  validate_log({ { 'ba', 'ab', 'bb' }, { 'ba', 'ab', 'bb' } })\n\n  type_keys('a')\n  validate_log({ { 'ab', 'ba' } })\n\n  type_keys('x')\n  validate_log({ {} })\n\n  type_keys('<BS>')\n  validate_log({ { 'ab', 'ba' } })\n\n  type_keys('<BS>')\n  validate_log({ { 'ba', 'ab', 'bb' } })\n\n  type_keys('a')\n  validate_log({ { 'ab', 'ba' } })\n\n  type_keys('<C-c>')\n\n  -- Should trigger with custom `source.match`\n  child.lua_notify([[\n    local match = function()\n      table.insert(_G.log, 'match')\n      return { 2 }\n    end\n    MiniPick.start({ source = { items = { 'ba', 'ab', 'bb' }, match = match } })\n  ]])\n\n  validate_log({ { 'ba', 'ab', 'bb' }, 'match', { 'ab' } })\n\n  type_keys('x')\n  validate_log({ 'match', { 'ab' } })\n\n  type_keys('<C-c>')\nend\n\nT['Matching']['dedicated event can update window config'] = function()\n  child.lua([[\n    local adjust_height = function()\n      local n_matches = #(MiniPick.get_picker_matches().all or {})\n      local height = math.min(math.max(n_matches, 1), 5)\n      MiniPick.set_picker_opts({ window = { config = { height = height } } })\n    end\n    vim.api.nvim_create_autocmd('User', { pattern = 'MiniPickMatch', callback = adjust_height })\n  ]])\n\n  child.lua_notify('MiniPick.start({ source = { items = { \"ab\", \"bb\" } }, window = { config = { height = 7 } } })')\n\n  -- Should adjust immediately and ignore picker's window config\n  child.expect_screenshot()\n\n  type_keys('a')\n  child.expect_screenshot()\n\n  type_keys('x')\n  child.expect_screenshot()\n\n  type_keys('<C-u>')\n  child.expect_screenshot()\nend\n\nT['Matching']['allows returning wider than input set of match indexes'] = function()\n  child.lua_notify([[_G.match_increase = function(stritems, match_inds, query)\n    if query[#query] == 'x' then return { 1, 2, 3, 4 } end\n    local prompt_pattern = vim.pesc(table.concat(query))\n    return vim.tbl_filter(function(i) return stritems[i]:find(prompt_pattern) ~= nil end, match_inds)\n  end]])\n\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a', 'ab', 'b', 'bb' }, match = _G.match_increase } })]])\n  type_keys('b', 'b')\n  eq(get_picker_matches().all_inds, { 4 })\n\n  type_keys('x')\n  eq(get_picker_matches().all_inds, { 1, 2, 3, 4 })\nend\n\nT['Matching'][\"respects 'ignorecase' and 'smartcase'\"] = function()\n  -- Should precompute and supply lowered versions of stritems and query if\n  -- case should be ignored. Which to use is computed before every matching.\n  local items = { 'ab', 'Ab', 'AB' }\n  local items_lowered = { 'ab', 'ab', 'ab' }\n  start_with_items_matchlog(items)\n\n  local validate = function(query, ref_state)\n    set_picker_query(query)\n    local ref_stritems = ref_state == 'lowered' and items_lowered or items\n    local ref_query = ref_state == 'lowered' and vim.tbl_map(string.lower, query) or query\n    validate_last_match_log({ ref_stritems, { 1, 2, 3 }, ref_query })\n    clean_match_log()\n    type_keys('<C-u>')\n  end\n\n  child.o.ignorecase, child.o.smartcase = false, false\n  validate({ 'ab' }, 'non-lowered')\n  validate({ 'Ab' }, 'non-lowered')\n  validate({ 'AB' }, 'non-lowered')\n\n  child.o.ignorecase, child.o.smartcase = true, false\n  validate({ 'ab' }, 'lowered')\n  validate({ 'Ab' }, 'lowered')\n  validate({ 'AB' }, 'lowered')\n\n  child.o.ignorecase, child.o.smartcase = false, true\n  validate({ 'ab' }, 'non-lowered')\n  validate({ 'Ab' }, 'non-lowered')\n  validate({ 'AB' }, 'non-lowered')\n\n  child.o.ignorecase, child.o.smartcase = true, true\n  validate({ 'ab' }, 'lowered')\n  validate({ 'Ab' }, 'non-lowered')\n  validate({ 'AB' }, 'non-lowered')\nend\n\nT['Matching']['uses proper `tolower` for ignoring case'] = function()\n  local items, items_lowered = { 'ыф', 'Ыф', 'ЫФ' }, { 'ыф', 'ыф', 'ыф' }\n  start_with_items_matchlog(items)\n\n  child.o.ignorecase, child.o.smartcase = true, false\n  type_keys('ы')\n  validate_last_match_log({ items_lowered, { 1, 2, 3 }, { 'ы' } })\n  type_keys('Ф')\n  validate_last_match_log({ items_lowered, { 1, 2, 3 }, { 'ы', 'ф' } })\n  type_keys('<C-u>')\n\n  child.o.ignorecase, child.o.smartcase = true, true\n  type_keys('ы')\n  validate_last_match_log({ items_lowered, { 1, 2, 3 }, { 'ы' } })\n  type_keys('Ф')\n  validate_last_match_log({ items, { 1, 2, 3 }, { 'ы', 'Ф' } })\nend\n\nT['Matching'][\"works with non-default 'regexpengine'\"] = function()\n  child.o.regexpengine = 1\n\n  -- Determining if query is smartcase should be unaffected\n  child.o.ignorecase, child.o.smartcase = true, true\n  start_with_items_matchlog({ 'ab', 'Ab', 'AB' })\n  type_keys('a')\n  validate_last_match_log({ { 'ab', 'ab', 'ab' }, { 1, 2, 3 }, { 'a' } })\n\n  -- Matching keyword should be unaffected\n  type_keys(' ', 'b', 'b')\n  eq(get_picker_query(), { 'a', ' ', 'b', 'b' })\n  type_keys('<C-w>')\n  eq(get_picker_query(), { 'a', ' ' })\n  type_keys('<C-w>')\n  eq(get_picker_query(), { 'a' })\nend\n\nT['Key query process'] = new_set()\n\nT['Key query process']['respects mouse click'] = function()\n  child.set_size(10, 15)\n\n  -- Should ignore if inside main window\n  local validate_press_inside = function(button, row, col)\n    child.api.nvim_input_mouse(button, 'press', '', 0, row, col)\n    eq(is_picker_active(), true)\n  end\n\n  start_with_items({ 'a' })\n\n  -- - Press on all four courners\n  validate_press_inside('left', 2, 0)\n  validate_press_inside('left', 8, 0)\n  validate_press_inside('left', 8, 10)\n  validate_press_inside('left', 2, 10)\n\n  -- - Actual button should not matter\n  validate_press_inside('right', 2, 0)\n  validate_press_inside('middle', 2, 0)\n\n  type_keys('<C-c>')\n\n  -- Should stop picker if outside of main window\n  local validate_press_outside = function(button, row, col)\n    start_with_items({ 'a' })\n    sleep(small_time)\n    child.api.nvim_input_mouse(button, 'press', '', 0, row, col)\n    sleep(small_time)\n    eq(is_picker_active(), false)\n  end\n\n  validate_press_outside('left', 1, 0)\n  validate_press_outside('left', 9, 0)\n  validate_press_outside('left', 9, 10)\n  validate_press_outside('left', 8, 11)\n  validate_press_outside('left', 1, 10)\n  validate_press_outside('left', 2, 11)\n\n  validate_press_outside('right', 1, 0)\n  validate_press_outside('middle', 1, 0)\nend\n\nT['Key query process']['handles not configured key presses'] = function()\n  start_with_items({ 'a' })\n\n  -- Should not add them to query\n  local validate = function(key)\n    type_keys(key)\n    eq(get_picker_query(), {})\n  end\n\n  validate('<M-a>')\n  validate('<S-right>')\n  validate('<C-d>')\n  validate('\\1')\n  validate('\\31')\nend\n\nT['Key query process']['always stops on `<C-c>`'] = function()\n  child.api.nvim_set_keymap('n', '<C-c>', '<Cmd>echo 1<CR>', {})\n  start_with_items({ 'a' })\n  type_keys('<C-c>')\n  eq(is_picker_active(), false)\nend\n\nT['Caret'] = new_set({ hooks = { pre_case = function() child.set_size(10, 15) end } })\n\nlocal validate_caret = function(n) eq(get_picker_state().caret, n) end\n\nT['Caret']['works'] = function()\n  start_with_items({ 'a' })\n  validate_caret(1)\n\n  -- Should move along right edge\n  type_keys('a')\n  validate_caret(2)\n\n  type_keys('b')\n  validate_caret(3)\n\n  -- Should insert character at its place\n  type_keys('<Left>', 'c')\n  validate_caret(3)\n  child.expect_screenshot()\n\n  -- Should delete character at its place\n  type_keys('<BS>')\n  validate_caret(2)\n  child.expect_screenshot()\n\n  type_keys('<Del>')\n  validate_caret(2)\n  child.expect_screenshot()\nend\n\nT['Caret']['moves by query parts'] = function()\n  start_with_items({ 'a' })\n  set_picker_query({ 'ab', 'cd' })\n  validate_caret(3)\n  child.expect_screenshot()\n\n  type_keys('<Left>')\n  validate_caret(2)\n  child.expect_screenshot()\n\n  type_keys('<Left>')\n  validate_caret(1)\n  child.expect_screenshot()\nend\n\nT['Caret']['can not go past query boundaries'] = function()\n  start_with_items({ 'a' })\n  type_keys('<Left>')\n  validate_caret(1)\n  type_keys('<Right>')\n  validate_caret(1)\n\n  type_keys('a', 'b', '<Right>')\n  validate_caret(3)\n  type_keys('<Left>', '<Left>', '<Left>')\n  validate_caret(1)\nend\n\nT['Caret']['works without items'] = function()\n  start_with_items()\n  type_keys('<Left>')\n  validate_caret(1)\n  type_keys('<Right>')\n  validate_caret(1)\nend\n\nT['Choose'] = new_set()\n\nT['Choose']['works for split/tab variations'] = function()\n  local validate = function(key)\n    local global_cwd = child.fn.getcwd(-1, -1)\n    child.lua('_G.source_cwd = ' .. vim.inspect(test_dir_absolute))\n\n    local win_id_init = child.api.nvim_get_current_win()\n    child.lua_notify([[MiniPick.start({\n      source = {\n        items = { 'a' },\n        cwd = _G.source_cwd,\n        choose = function() _G.target_window = MiniPick.get_picker_state().windows.target end,\n      },\n    })]])\n\n    type_keys(key)\n    -- Should create split/tab\n    child.expect_screenshot()\n    -- Should modify target window\n    eq(child.lua_get('_G.target_window') ~= win_id_init, true)\n\n    -- Should not modify any current directory\n    eq(child.fn.getcwd(-1, -1), global_cwd)\n    eq(child.fn.getcwd(0), global_cwd)\n\n    -- Should not create extra buffers due to splitting\n    eq(#child.api.nvim_list_bufs(), 1)\n\n    -- Cleanup\n    child.lua('_G.target_window = nil')\n  end\n\n  validate('<C-s>')\n  validate('<C-v>')\n  validate('<C-t>')\nend\n\nT['Choose']['works without items'] = function()\n  local validate = function(key)\n    child.lua_notify('MiniPick.start({ source = { choose = function(...) _G.been_here = true end } })')\n    type_keys(key)\n    -- Should not do any split/tab\n    eq(#child.api.nvim_list_wins(), 1)\n    -- Should not call `source.choose()` function\n    eq(child.lua_get('_G.been_here'), vim.NIL)\n  end\n\n  validate('<CR>')\n  validate('<C-s>')\n  validate('<C-v>')\n  validate('<C-t>')\nend\n\nT['Choose']['works with no matching items'] = function()\n  local validate = function(key)\n    child.lua_notify([[MiniPick.start({\n      source = { items = { 'a' }, choose = function(...) _G.been_here = true end },\n    })]])\n    type_keys('b', key)\n    -- Should not do any split/tab\n    eq(#child.api.nvim_list_wins(), 1)\n    -- Should not call `source.choose()` function\n    eq(child.lua_get('_G.been_here'), vim.NIL)\n  end\n\n  validate('<CR>')\n  validate('<C-s>')\n  validate('<C-v>')\n  validate('<C-t>')\nend\n\nT['Choose']['uses output as \"should continue\"'] = function()\n  local validate = function(key)\n    child.lua_notify([[MiniPick.start({\n      source = {\n        items = { 'a', 'b' },\n        choose = function(item) _G.latest_item = item; return item == 'a' end,\n        choose_marked = function(items) _G.latest_item = items[#items]; return #items == 1 end,\n      },\n    })]])\n\n    type_keys(key)\n    eq(child.lua_get('_G.latest_item'), 'a')\n    eq(is_picker_active(), true)\n\n    type_keys('<C-n>', key)\n    eq(child.lua_get('_G.latest_item'), 'b')\n    eq(is_picker_active(), false)\n  end\n\n  validate('<CR>')\n  validate('<C-s>')\n  validate('<C-v>')\n  validate('<C-t>')\n\n  validate({ '<C-x>', '<M-CR>' })\nend\n\nT['Choose']['handles error in choose function'] = function()\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a' }, choose = function() error('Oops!') end } })]])\n  expect.error(function() type_keys('<CR>') end, 'Error during choose:.*Oops!')\n  eq(is_picker_active(), false)\n  eq(#child.api.nvim_list_wins(), 1)\n\n  child.lua_notify([[MiniPick.start({ source = { items = { 'a' }, choose_marked = function() error('Oops!') end } })]])\n  type_keys('<C-x>')\n  expect.error(function() type_keys('<M-CR>') end, 'Error during choose marked:.*Oops!')\n  eq(is_picker_active(), false)\n  eq(#child.api.nvim_list_wins(), 1)\nend\n\nT['Mark'] = new_set()\n\nT['Mark']['works'] = function()\n  local validate = function(keys, marked_items)\n    child.lua_notify([[MiniPick.start({ source = {\n      items = { 'a', 'b', 'bb' },\n      choose_marked = function(items) _G.choose_marked_items = items end,\n    } })]])\n    type_keys(keys)\n    type_keys('<M-CR>')\n    eq(child.lua_get('_G.choose_marked_items'), marked_items)\n    eq(is_picker_active(), false)\n  end\n\n  validate({ '<C-x>' }, { 'a' })\n  validate({ '<C-x>', '<C-n>', '<C-x>' }, { 'a', 'b' })\n\n  -- Should be returned in the original order, not how they were marked\n  validate({ '<C-n>', '<C-x>', '<C-p>', '<C-x>' }, { 'a', 'b' })\n\n  -- Should not return unmarked item\n  validate({ '<C-x>', '<C-x>' }, {})\n\n  -- Marked items should be preserved across queries\n  validate({ 'b', '<C-n>', '<C-x>', '<BS>', 'a', '<C-x>' }, { 'a', 'bb' })\n\n  -- Works with 'mark_all': mark all if not all marked, unmark otherwise\n  validate({ '<C-a>' }, { 'a', 'b', 'bb' })\n  validate({ '<C-x>', '<C-a>' }, { 'a', 'b', 'bb' })\n  validate({ '<C-a>', '<C-a>' }, {})\nend\n\nT['Mark']['works without items set'] = function()\n  child.set_size(5, 15)\n  start_with_items()\n  type_keys('<C-x>')\n  type_keys('<C-a>')\n  child.expect_screenshot()\nend\n\nT['Move'] = new_set()\n\nT['Move']['works'] = function()\n  start_with_items({ 'a', 'b', 'bb', 'bbb' })\n\n  -- Next/prev\n  type_keys('<C-n>')\n  validate_current_ind(2)\n  type_keys('<C-n>')\n  validate_current_ind(3)\n  type_keys('<C-p>')\n  validate_current_ind(2)\n\n  -- First\n  type_keys('<C-n>')\n  validate_current_ind(3)\n  type_keys('<C-g>')\n  validate_current_ind(1)\nend\n\nT['Move']['works with non-overridable keys'] = function()\n  start_with_items({ 'a', 'b', 'bb', 'bbb' })\n\n  type_keys('<Down>')\n  validate_current_ind(2)\n  type_keys('<Down>')\n  validate_current_ind(3)\n  type_keys('<Up>')\n  validate_current_ind(2)\n  type_keys('<Down>')\n  validate_current_ind(3)\n  type_keys('<Home>')\n  validate_current_ind(1)\nend\n\nT['Move']['next/prev wraps around edges'] = function()\n  start_with_items({ 'a', 'b' })\n\n  type_keys('<C-n>')\n  validate_current_ind(2)\n  type_keys('<C-n>')\n  validate_current_ind(1)\n\n  type_keys('<C-p>')\n  validate_current_ind(2)\n  type_keys('<C-p>')\n  validate_current_ind(1)\nend\n\nT['Move']['scrolls to edge without wrap and then wraps'] = function()\n  start_with_items({ 'a', 'b', 'bb' })\n\n  type_keys('<C-f>')\n  validate_current_ind(3)\n  type_keys('<C-f>')\n  validate_current_ind(1)\n\n  type_keys('<C-b>')\n  validate_current_ind(3)\n  type_keys('<C-b>')\n  validate_current_ind(1)\nend\n\nT['Move']['works when no items are set'] = function()\n  child.set_size(5, 15)\n  start_with_items()\n  type_keys('<C-n>')\n  type_keys('<C-p>')\n  type_keys('<C-g>')\n  child.expect_screenshot()\nend\n\nT['Paste'] = new_set()\n\nT['Paste']['works'] = function()\n  child.set_size(5, 15)\n  local validate = function(regcontents, ref_query)\n    child.fn.setreg('a', regcontents)\n    start_with_items({ 'a' })\n    type_keys('<C-r>', 'a')\n    eq(get_picker_query(), ref_query)\n    child.expect_screenshot()\n    type_keys('<C-c>')\n  end\n\n  validate('hello', { 'h', 'e', 'l', 'l', 'o' })\n  validate('ыфя', { 'ы', 'ф', 'я' })\n\n  -- Should sanitize register content\n  validate('a\\nb\\tc', { 'a', ' ', 'b', ' ', 'c' })\nend\n\nT['Paste']['supports special registers'] = function()\n  child.o.iskeyword = child.o.iskeyword .. ',-'\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { 'aa bb!cc-dd ee', test_dir })\n  set_cursor(1, 7)\n\n  start_with_items({ 'a' })\n\n  local validate = function(register, ref_query)\n    type_keys('<C-r>', register)\n    eq(get_picker_query(), ref_query)\n    type_keys('<C-u>')\n  end\n\n  validate('<C-w>', vim.split('cc-dd', ''))\n  validate('<C-a>', vim.split('bb!cc-dd', ''))\n  validate('<C-l>', vim.split('aa bb!cc-dd ee', ''))\n\n  type_keys('<C-c>')\n\n  set_cursor(2, 0)\n  start_with_items({ 'a' })\n  validate('<C-f>', vim.split(test_dir, ''))\nend\n\nT['Paste']['pastes at caret'] = function()\n  child.fn.setreg('a', 'hello ')\n  start_with_items({ 'a' })\n  type_keys('w', 'o', 'r', 'l', 'd')\n  type_keys('<Left>', '<Left>', '<Left>', '<Left>', '<Left>')\n  type_keys('<C-r>', 'a')\n  eq(get_picker_query(), { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' })\nend\n\nT['Paste']['does not error on non-existing register label'] = function()\n  start_with_items({ 'a' })\n  type_keys('<C-r>', '<C-y>')\n  eq(get_picker_query(), {})\n  type_keys('a')\n  eq(get_picker_query(), { 'a' })\nend\n\nT['Paste']['is not affected by language mappings'] = function()\n  child.o.iminsert = 1\n  child.cmd('lmap a 1')\n  child.fn.setreg('a', 'xxx')\n  start_with_items({ 'a' })\n  type_keys('<C-r>', 'a')\n  eq(get_picker_query(), { 'x', 'x', 'x' })\nend\n\nT['Refine'] = new_set()\n\nT['Refine']['works'] = function()\n  child.set_size(10, 15)\n  start_with_items({ 'a', 'ab', 'b', 'ba', 'bb' }, 'My name')\n\n  type_keys('b')\n  child.expect_screenshot()\n\n  type_keys('<C-Space>')\n  -- - Should use matches in the sorted order, not their original one.\n  -- - Also should remove matched ranges highlight.\n  child.expect_screenshot()\n  -- - Should reset data and update name\n  validate_picker_option('source.name', 'My name (Refine)')\n\n  -- Can be used several times\n  type_keys('a')\n  type_keys('<C-Space>')\n  child.expect_screenshot()\n  validate_picker_option('source.name', 'My name (Refine 2)')\nend\n\nT['Refine']['works with marked'] = function()\n  child.set_size(10, 15)\n  start_with_items({ 'a', 'b', 'c' }, 'My name')\n\n  type_keys('<C-n>', '<C-x>', '<C-n>', '<C-x>')\n  type_keys('<M-Space>')\n  eq(get_picker_items(), { 'b', 'c' })\n  validate_picker_option('source.name', 'My name (Refine)')\n\n  -- Can be used several times\n  type_keys('<C-a>')\n  type_keys('<M-Space>')\n  eq(get_picker_items(), { 'b', 'c' })\n  validate_picker_option('source.name', 'My name (Refine 2)')\nend\n\nT['Refine']['uses config match'] = function()\n  child.lua_notify([[MiniPick.start({\n    source = { items = { 'a', 'b', 'bb' }, name = 'My name', match = function() return { 1, 2, 3 } end },\n  })]])\n\n  type_keys('b')\n  eq(get_picker_matches().all_inds, { 1, 2, 3 })\n  type_keys('<C-Space>')\n  type_keys('b')\n  eq(get_picker_matches().all_inds, { 2, 3 })\nend\n\nT['Refine']['works when no items are set'] = function()\n  child.set_size(5, 15)\n  start_with_items()\n  type_keys('<C-Space>')\n  type_keys('<M-Space>')\n  child.expect_screenshot()\nend\n\nT['Stop'] = new_set()\n\nT['Stop']['triggers User event'] = function()\n  child.cmd('au User MiniPickStop lua _G.track_event()')\n  local validate = function(key)\n    make_event_log()\n    start_with_items({ 'a', 'b', 'bb' })\n    type_keys('b', key)\n    eq(child.lua_get('_G.event_log'), { 2 })\n  end\n\n  validate('<Esc>')\n  validate('<C-c>')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_sessions.lua",
    "content": "-- General design of testing sessions is to have each session file define\n-- `_G.session_file` variable with value being path to sourced session. So\n-- these assumptions are assumed:\n-- - If `_G.session_file` is `nil`, no session file was sourced.\n-- - If `_G.session_file` is not `nil`, its value is a relative (to project\n--   root) path to a session file that was sourced.\nlocal helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\nlocal project_root = vim.fs.normalize(vim.fn.getcwd())\nlocal empty_dir_relpath = 'tests/dir-sessions/empty'\nlocal empty_dir_path = project_root .. '/' .. empty_dir_relpath\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('sessions', config) end\nlocal unload_module = function() child.mini_unload('sessions') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal reload_from_strconfig = function(strconfig) unload_module(); child.mini_load_strconfig('sessions', strconfig) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal make_path = function(...) return vim.fs.normalize(table.concat({...}, '/')) end\nlocal cd = function(...) child.cmd('cd ' .. make_path(...)) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Make helpers\nlocal cleanup_directories = function()\n  -- Cleanup files for directories to have invariant properties\n  -- Ensure 'empty' directory doesn't exist\n  child.fn.delete(empty_dir_path, 'rf')\n\n  -- Ensure 'missing-directory' doesn't exist\n  child.fn.delete('tests/dir-sessions/missing-directory', 'rf')\n\n  -- Ensure 'global' does not contain file 'Session.vim'\n  local files = { 'tests/dir-sessions/global/Session.vim' }\n\n  for _, f in ipairs(files) do\n    child.fn.delete(f)\n  end\nend\n\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n\nlocal get_buf_names = function()\n  return child.lua_get('vim.tbl_map(function(x) return vim.fn.bufname(x) end, vim.api.nvim_list_bufs())')\nend\n\nlocal compare_buffer_names = function(x, y)\n  -- Don't test exact equality because different Neovim versions create\n  -- different buffer order when sourcing session (see\n  -- https://github.com/vim/vim/pull/9520)\n  table.sort(x)\n  table.sort(y)\n  eq(x, y)\nend\n\n-- Helpers for validating sessions\nlocal populate_sessions = function(delay)\n  delay = delay or 0\n\n  child.fn.delete(empty_dir_path, 'rf')\n  child.fn.mkdir(empty_dir_path)\n\n  local make_file = function(name)\n    local path = make_path(empty_dir_path, name)\n    local value = make_path(empty_dir_relpath, name)\n    child.fn.writefile({ ([[lua _G.session_file = '%s']]):format(value) }, path)\n  end\n\n  make_file('session_a')\n  -- Modification time is up to seconds, so wait to ensure correct order\n  sleep(delay)\n  make_file('session_b')\n\n  return empty_dir_path\nend\n\nlocal validate_session_loaded = function(relative_path)\n  local path = make_path('tests/dir-sessions', relative_path)\n\n  -- It should actually source file\n  eq(child.lua_get('_G.session_file'), path)\n\n  -- It should set `this_session`\n  eq(child.v.this_session, make_path(project_root, path))\nend\n\nlocal validate_no_session_loaded = function() eq(child.lua_get('type(_G.session_file)'), 'nil') end\n\nlocal reset_session_indicator = function() child.lua('_G.session_file = nil') end\n\n-- Helpers for testing hooks\n--stylua: ignore start\nlocal make_hook_string = function(pre_post, action, hook_type)\n  if hook_type == 'config' then\n    return string.format(\n      [[{ %s = { %s = function(...) _G.hooks_args = { ... }; _G.hooks_%s_%s = 'config' end }}]],\n      pre_post, action, pre_post, action\n    )\n  end\n  if hook_type == 'opts' then\n    return string.format(\n      [[{ %s = function(...) _G.hooks_args = { ... }; _G.hooks_%s_%s = 'opts' end }]],\n      pre_post, pre_post, action\n    )\n  end\nend\n--stylua: ignore end\n\nlocal validate_executed_hook = function(pre_post, action, value)\n  local var_name = ('_G.hooks_%s_%s'):format(pre_post, action)\n  eq(child.lua_get(var_name), value)\n\n  -- Only one argument should be passed\n  local hooks_args = child.lua_get('_G.hooks_args')\n  eq(vim.tbl_keys(hooks_args), { 1 })\n\n  -- It is a session data\n  local data = hooks_args[1]\n  local keys = vim.tbl_keys(data)\n  table.sort(keys)\n  eq(keys, { 'modify_time', 'name', 'path', 'type' })\n  eq(vim.tbl_map(function(x) return type(data[x]) end, keys), { 'number', 'string', 'string', 'string' })\nend\n\n-- Time constants\nlocal one_second_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n\n      -- Ensure `require('mini.sessions')` is always possible (which might not be\n      -- the case with all present `cd` calls)\n      child.cmd('set rtp+=' .. project_root)\n\n      -- Ensure always identical starting current directory\n      cd(project_root)\n\n      -- Ensure directory structure invariants\n      cleanup_directories()\n\n      -- Make all showed messages full width\n      child.o.cmdheight = 10\n\n      -- Load module\n      load_module()\n\n      -- Ensure clear message history\n      child.cmd('messages clear')\n    end,\n    post_once = function()\n      cleanup_directories()\n      child.stop()\n    end,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniSessions)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniSessions'), 1)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniSessions.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniSessions.config.' .. field), value) end\n\n  expect_config('autoread', false)\n  expect_config('autowrite', true)\n  expect_config('directory', child.fn.stdpath('data') .. '/session')\n  expect_config('file', 'Session.vim')\n  expect_config('force', { read = false, write = true, delete = false })\n  expect_config('hooks.pre', { read = nil, write = nil, delete = nil })\n  expect_config('hooks.post', { read = nil, write = nil, delete = nil })\n  expect_config('verbose', { read = false, write = true, delete = true })\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ autoread = true })\n  eq(child.lua_get('MiniSessions.config.autoread'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ autoread = 'a' }, 'autoread', 'boolean')\n  expect_config_error({ autowrite = 'a' }, 'autowrite', 'boolean')\n  expect_config_error({ directory = 1 }, 'directory', 'string')\n  expect_config_error({ file = 1 }, 'file', 'string')\n  expect_config_error({ force = 'a' }, 'force', 'table')\n  expect_config_error({ force = { read = 'a' } }, 'force.read', 'boolean')\n  expect_config_error({ force = { write = 'a' } }, 'force.write', 'boolean')\n  expect_config_error({ force = { delete = 'a' } }, 'force.delete', 'boolean')\n  expect_config_error({ hooks = 'a' }, 'hooks', 'table')\n  expect_config_error({ hooks = { pre = 'a' } }, 'hooks.pre', 'table')\n  expect_config_error({ hooks = { pre = { read = 'a' } } }, 'hooks.pre.read', 'function')\n  expect_config_error({ hooks = { pre = { write = 'a' } } }, 'hooks.pre.write', 'function')\n  expect_config_error({ hooks = { pre = { delete = 'a' } } }, 'hooks.pre.delete', 'function')\n  expect_config_error({ hooks = { post = 'a' } }, 'hooks.post', 'table')\n  expect_config_error({ hooks = { post = { read = 'a' } } }, 'hooks.post.read', 'function')\n  expect_config_error({ hooks = { post = { write = 'a' } } }, 'hooks.post.write', 'function')\n  expect_config_error({ hooks = { post = { delete = 'a' } } }, 'hooks.post.delete', 'function')\n  expect_config_error({ verbose = 'a' }, 'verbose', 'table')\n  expect_config_error({ verbose = { read = 'a' } }, 'verbose.read', 'boolean')\n  expect_config_error({ verbose = { write = 'a' } }, 'verbose.write', 'boolean')\n  expect_config_error({ verbose = { delete = 'a' } }, 'verbose.delete', 'boolean')\nend\n\nT['setup()']['detects sessions and respects `config.directory`'] = function()\n  cd('tests', 'dir-sessions')\n\n  reload_module({ directory = 'global' })\n  local detected = child.lua_get('MiniSessions.detected')\n\n  -- Should be a table with correct keys\n  eq(type(detected), 'table')\n  local keys = vim.tbl_keys(detected)\n  table.sort(keys)\n  --stylua: ignore\n  eq(keys, {\n    '.session', 'Session.vim', 'session1', 'session2.vim', 'session3.lua',\n    'session_cd_global', 'session_cd_local', 'session_cd_local_2'\n  })\n\n  -- Elements should have correct structure\n  local cur_dir = child.fn.getcwd()\n  local session_dir = make_path(cur_dir, 'global')\n  for key, val in pairs(detected) do\n    eq(type(val.modify_time), 'number')\n    eq(val.name, key)\n\n    if val.name == 'Session.vim' then\n      eq(val.type, 'local')\n      eq(val.path, make_path(cur_dir, 'Session.vim'))\n    else\n      eq(val.type, 'global')\n      eq(val.path, make_path(session_dir, val.name))\n    end\n  end\nend\n\nT['setup()']['prefers local session file over global'] = function()\n  -- Make file 'Session.vim' be in both `config.directory` and current one\n  local path_local = 'tests/dir-sessions/global/Session.vim'\n  child.fn.writefile({ ([[lua _G.session_file = '%s']]):format(path_local) }, path_local)\n\n  cd('tests', 'dir-sessions')\n\n  reload_module({ directory = 'global' })\n  local detected = child.lua_get('MiniSessions.detected')\n  local expected_path = project_root .. '/tests/dir-sessions/Session.vim'\n\n  eq(detected['Session.vim'].path, expected_path)\nend\n\nT['setup()']['allows empty string for `config.directory`'] = function()\n  reload_module({ directory = '' })\n  eq(child.lua_get('MiniSessions.detected'), {})\nend\n\nT['setup()']['creates missing `config.directory`'] = function()\n  local directory = 'tests/dir-sessions/missing-directory'\n\n  eq(child.fn.isdirectory(directory), 0)\n  reload_module({ directory = directory })\n  eq(child.fn.isdirectory(directory), 1)\nend\n\nT['setup()']['does not create `config.directory` if it is an existing file'] = function()\n  reload_module({ directory = 'lua/mini/sessions.lua' })\n  expect.match(get_latest_message(), '%(mini%.sessions%).*lua/mini/sessions%.lua.*is not a directory path')\nend\n\nT['setup()']['respects `config.file`'] = function()\n  cd('tests', 'dir-sessions', 'local')\n\n  reload_module({ autowrite = false, file = 'alternative-local-session' })\n  local detected = child.lua_get('MiniSessions.detected')\n\n  eq(detected['Session.vim'], nil)\n  eq(detected['alternative-local-session'].type, 'local')\nend\n\nT['setup()']['allows empty string for `config.file`'] = function()\n  cd('tests/dir-sessions')\n  reload_module({ file = '' })\n  local detected = child.lua_get('MiniSessions.detected')\n  eq(vim.tbl_filter(function(x) return x.type == 'local' end, detected), {})\nend\n\nT['detected'] = new_set()\n\nT['detected']['is present'] = function()\n  cd('tests', 'dir-sessions')\n  reload_module({ directory = 'global' })\n  eq(child.lua_get('type(MiniSessions.detected)'), 'table')\nend\n\nT['detected']['is an empty table if no sessions are detected'] = function()\n  reload_module({ directory = vim.fn.fnamemodify(child.fn.tempname(), ':h') })\n  eq(child.lua_get('MiniSessions.detected'), {})\nend\n\nT['read()'] = new_set()\n\nT['read()']['works'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n  child.lua([[MiniSessions.read('session1')]])\n  validate_session_loaded('global/session1')\nend\n\nT['read()']['works with no detected sessions'] = function()\n  reload_module({ directory = '', file = '' })\n  eq(child.lua_get('MiniSessions.detected'), {})\n  expect.no_error(function() child.lua('MiniSessions.read()') end)\n  expect.match(get_latest_message(), '%(mini%.sessions%) There are no detected sessions')\nend\n\nT['read()']['accepts only name of detected session'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n  expect.error(\n    function() child.lua([[MiniSessions.read('session-absent')]]) end,\n    '%(mini%.sessions%) \"session%-absent\" is not a name for detected session'\n  )\n  validate_no_session_loaded()\nend\n\nT['read()']['removes stale local session from detected'] = function()\n  -- Start in 'local' directory\n  cd('tests', 'dir-sessions', 'local')\n  reload_module({ autowrite = false, directory = project_root .. '/tests/dir-sessions/global' })\n  eq(child.lua_get([[MiniSessions.detected['Session.vim'] ~= nil]]), true)\n\n  -- Test yes local -> no local\n  child.lua([[MiniSessions.read('session_cd_global')]])\n  validate_session_loaded('global/session_cd_global')\n  eq(child.lua_get([[MiniSessions.detected['Session.vim'] ~= nil]]), false)\n\n  -- Test no local -> yes local\n  child.lua([[MiniSessions.read('session_cd_local')]])\n  validate_session_loaded('global/session_cd_local')\n  eq(child.lua_get([[MiniSessions.detected['Session.vim'] ~= nil]]), true)\n\n  -- Test yes local -> yes other local\n  child.lua([[MiniSessions.read('session_cd_local_2')]])\n  validate_session_loaded('global/session_cd_local_2')\n  eq(child.lua_get([[MiniSessions.detected['Session.vim'] ~= nil]]), true)\n  local other_local_path = project_root .. '/tests/dir-sessions/local-2/Session.vim'\n  eq(child.lua_get([[MiniSessions.detected['Session.vim'].path ]]), other_local_path)\nend\n\nT['read()']['makes detected sessions up to date'] = function()\n  local new_session = 'tests/dir-sessions/global/new_session'\n  MiniTest.finally(function() vim.fn.delete(new_session) end)\n\n  -- Detect sessions without new session\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n  eq(child.lua_get('MiniSessions.detected.new_session == nil'), true)\n\n  -- Create new session file manually and try to read it directly without\n  -- reloading whole module.\n  child.fn.writefile({ 'lua _G.session_file = ' .. vim.inspect(new_session) }, new_session)\n\n  child.lua([[MiniSessions.read('new_session')]])\n  validate_session_loaded('global/new_session')\nend\n\nlocal setup_unsaved_buffers = function()\n  child.o.hidden = true\n  local res = {}\n  set_lines({ 'aaa' })\n  table.insert(res, child.api.nvim_get_current_buf())\n\n  child.cmd('e foo')\n  set_lines({ 'bbb' })\n  table.insert(res, child.api.nvim_get_current_buf())\n\n  return res\nend\n\nT['read()']['does not source if there are unsaved listed buffers'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n\n  -- Setup unsaved buffers\n  local unsaved_buffers = setup_unsaved_buffers()\n\n  -- Session should not be sourced\n  local error_pattern =\n    vim.pesc('(mini.sessions) There are unsaved listed buffers: ' .. table.concat(unsaved_buffers, ', ') .. '.')\n  expect.error(function() child.lua([[MiniSessions.read('session1')]]) end, error_pattern)\n  validate_no_session_loaded()\nend\n\nT['read()']['ignores unsaved not listed buffers'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n  local buf_id = child.api.nvim_create_buf(false, false)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, true, { 'aaa' })\n  eq(child.api.nvim_buf_get_option(buf_id, 'modified'), true)\n  eq(child.api.nvim_buf_get_option(buf_id, 'buflisted'), false)\n\n  child.lua([[MiniSessions.read('session1')]])\n  validate_session_loaded('global/session1')\nend\n\nT['read()']['uses by default local session'] = function()\n  cd('tests', 'dir-sessions', 'local')\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n\n  eq(child.lua_get([[MiniSessions.detected['Session.vim'].type]]), 'local')\n  child.lua('MiniSessions.read()')\n  validate_session_loaded('local/Session.vim')\nend\n\nT['read()']['uses by default latest global session'] = function()\n  local session_dir = populate_sessions(one_second_delay + small_time)\n\n  reload_module({ autowrite = false, directory = session_dir })\n  child.lua('MiniSessions.read()')\n  validate_session_loaded('empty/session_b')\nend\n\nT['read()']['respects `force` from `config` and `opts` argument'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global', force = { read = true } })\n\n  -- Should overwrite unsaved buffers and load session if `force` is `true`\n  setup_unsaved_buffers()\n  child.lua([[MiniSessions.read('session1')]])\n  validate_session_loaded('global/session1')\n\n  -- Should prefer `opts` over `config`\n  setup_unsaved_buffers()\n  reset_session_indicator()\n  expect.error(\n    function() child.lua([[MiniSessions.read('session2.vim', { force = false })]]) end,\n    '%(mini%.sessions%) There are unsaved listed buffers'\n  )\n  validate_no_session_loaded()\nend\n\nT['read()']['does not stop on source error'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n\n  local session_file = 'tests/dir-sessions/global/session_with_error'\n  local folded_file = 'tests/dir-sessions/folded_file'\n  local extra_file = 'tests/dir-sessions/extra_file'\n  MiniTest.finally(function()\n    vim.fn.delete(session_file)\n    vim.fn.delete(folded_file)\n    vim.fn.delete(extra_file)\n  end)\n\n  -- Create buffer with non-trivial folds to imitate \"No folds found\" error\n  child.o.foldmethod = 'indent'\n  child.cmd('edit ' .. folded_file)\n  set_lines({ 'a', '\\ta', '\\ta', 'a', '\\ta', '\\ta' })\n  child.cmd('write')\n\n  child.cmd('normal! zM')\n  child.cmd('2 | normal! zo')\n\n  -- Create another buffer to check correct session read\n  child.cmd('edit ' .. extra_file)\n  set_lines({ 'This should be preserved in session' })\n  child.cmd('write')\n\n  -- Write session and make sure it contains call to open folds\n  child.cmd('edit ' .. folded_file)\n  child.cmd('mksession ' .. session_file)\n\n  local session_lines = table.concat(child.fn.readfile(session_file), '\\n')\n  expect.match(session_lines, 'normal! zo')\n\n  -- Modify file so that no folds will be found by session file\n  child.fn.writefile({ 'No folds in this file' }, folded_file)\n\n  -- Cleanly read session which should open foldless file without errors\n  child.restart()\n  load_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n\n  expect.no_error(function() child.lua([[MiniSessions.read('session_with_error')]]) end)\n\n  local buffers = child.api.nvim_list_bufs()\n  eq(#buffers, 2)\n\n  child.api.nvim_set_current_buf(buffers[1])\n  local buf_name_1 = child.fs.normalize(child.api.nvim_buf_get_name(0))\n  eq(vim.endswith(buf_name_1, '/' .. folded_file), true)\n  eq(child.api.nvim_buf_get_lines(0, 0, -1, true), { 'No folds in this file' })\n\n  child.api.nvim_set_current_buf(buffers[2])\n  local buf_name_2 = child.fs.normalize(child.api.nvim_buf_get_name(0))\n  eq(vim.endswith(buf_name_2, '/' .. extra_file), true)\n  eq(child.api.nvim_buf_get_lines(0, 0, -1, true), { 'This should be preserved in session' })\nend\n\nT['read()']['writes current session prior to reading a new one'] = function()\n  local cur_session = project_root .. '/tests/dir-sessions/global/current-session'\n  MiniTest.finally(function() child.fn.delete(cur_session) end)\n\n  local validate = function(ref_autowrite)\n    reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n    child.v.this_session = cur_session\n    child.lua('MiniSessions.config.autowrite = ' .. tostring(ref_autowrite))\n\n    eq(child.fn.filereadable(cur_session), 0)\n    child.lua('MiniSessions.read(\"session1\")')\n    -- Should only write current if `autowrite` is enabled\n    eq(child.fn.filereadable(cur_session), ref_autowrite and 1 or 0)\n    child.fn.delete(cur_session)\n  end\n\n  validate(true)\n  validate(false)\nend\n\nT['read()']['respects hooks from `config` and `opts` argument'] = new_set({\n  parametrize = { { 'pre' }, { 'post' } },\n}, {\n  test = function(pre_post)\n    -- Should use `config`\n    local hook_string_config = make_hook_string(pre_post, 'read', 'config')\n    reload_from_strconfig({\n      autowrite = 'false',\n      directory = [['tests/dir-sessions/global']],\n      hooks = hook_string_config,\n    })\n    child.lua([[MiniSessions.read('session1')]])\n\n    validate_session_loaded('global/session1')\n    validate_executed_hook(pre_post, 'read', 'config')\n    -- - Make sure that current session is not written\n    child.v.this_session = ''\n\n    -- Should prefer `opts` over `config`\n    local hook_string_opts = make_hook_string(pre_post, 'read', 'opts')\n    child.lua(([[MiniSessions.read('session2.vim', { hooks = %s })]]):format(hook_string_opts))\n\n    validate_session_loaded('global/session2.vim')\n    validate_executed_hook(pre_post, 'read', 'opts')\n  end,\n})\n\nT['read()']['respects `verbose` from `config` and `opts` argument'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global', verbose = { read = true } })\n\n  -- Should give message about read session\n  child.lua([[MiniSessions.read('session1')]])\n  validate_session_loaded('global/session1')\n  expect.match(get_latest_message(), '%(mini%.sessions%) Read session.*session1')\n  -- - Make sure that current session is not written\n  child.v.this_session = ''\n\n  -- Should prefer `opts` over `config`\n  reset_session_indicator()\n  child.lua([[MiniSessions.read('session2.vim', { verbose = false })]])\n  validate_session_loaded('global/session2.vim')\nend\n\nT['read()']['respects `vim.{g,b}.minisessions_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n    child[var_type].minisessions_disable = true\n\n    reset_session_indicator()\n    child.lua([[MiniSessions.read('session1')]])\n    validate_no_session_loaded()\n  end,\n})\n\nT['write()'] = new_set()\n\nT['write()']['works'] = function()\n  child.fn.mkdir(empty_dir_path)\n  reload_module({ autowrite = false, directory = empty_dir_path })\n\n  -- Setup buffers\n  child.cmd('e foo | e bar')\n  local buf_names_expected = get_buf_names()\n  child.lua([[MiniSessions.write('new_session')]])\n\n  -- Should update `v:this_session`\n  local path_expected = make_path(empty_dir_path, 'new_session')\n  eq(child.v.this_session, path_expected)\n\n  -- Verify that written session is correct\n  child.cmd('%bwipeout')\n  child.cmd('source ' .. path_expected)\n  compare_buffer_names(get_buf_names(), buf_names_expected)\nend\n\nT['write()']['updates `v:this_session`'] = function()\n  child.fn.mkdir(empty_dir_path)\n  reload_module({ autowrite = false, directory = empty_dir_path })\n\n  eq(child.v.this_session, '')\n  child.lua([[MiniSessions.write('new_session')]])\n  eq(child.v.this_session, make_path(empty_dir_path, 'new_session'))\nend\n\nT['write()']['updates `MiniSessions.detected` with new session'] = function()\n  child.fn.mkdir(empty_dir_path)\n  reload_module({ autowrite = false, directory = empty_dir_path })\n\n  eq(child.lua_get('MiniSessions.detected'), {})\n  child.lua([[MiniSessions.write('new_session')]])\n  eq(child.lua_get('MiniSessions.detected.new_session').path, make_path(empty_dir_path, 'new_session'))\nend\n\nT['write()']['updates `MiniSessions.detected` for present session'] = function()\n  local session_dir = populate_sessions(one_second_delay + small_time)\n  reload_module({ directory = session_dir })\n\n  child.lua([[MiniSessions.read('session_a')]])\n  sleep(one_second_delay + small_time)\n  child.lua([[MiniSessions.write('session_a')]])\n\n  local detected = child.lua_get('MiniSessions.detected')\n  eq(detected.session_a.modify_time > detected.session_b.modify_time, true)\nend\n\nT['write()']['validates `session_name`'] = function()\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n  expect.error(\n    function() child.lua([[MiniSessions.write('')]]) end,\n    '%(mini%.sessions%) Supply non%-empty session name'\n  )\nend\n\nT['write()']['writes by default to `v:this_session`'] = function()\n  local session_dir = populate_sessions()\n  reload_module({ directory = session_dir })\n  child.lua([[MiniSessions.read('session_a')]])\n\n  -- Verify that `v:this_session` points to correct place\n  local session_path = make_path(session_dir, 'session_a')\n  eq(child.v.this_session, session_path)\n\n  -- Write session with `session_name = nil`\n  child.cmd('e foo | e bar')\n  local buf_names_expected = get_buf_names()\n  child.lua('MiniSessions.write()')\n\n  -- Verify that it was actually written to `v:this_session`\n  child.cmd('%bwipeout!')\n  child.cmd('source ' .. session_path)\n  compare_buffer_names(get_buf_names(), buf_names_expected)\nend\n\nT['write()']['writes to current directory if passed name of local session file'] = function()\n  reload_module({ file = 'new-local-session', directory = '' })\n\n  child.fn.mkdir(empty_dir_path)\n  cd(empty_dir_path)\n  child.lua([[MiniSessions.write('new-local-session')]])\n\n  local path = make_path(empty_dir_path, 'new-local-session')\n  eq(child.fn.filereadable(path), 1)\nend\n\nT['write()']['writes to global directory'] = function()\n  child.fn.mkdir(empty_dir_path)\n  reload_module({ file = '', directory = empty_dir_path })\n\n  child.lua([[MiniSessions.write('new-global-session')]])\n\n  local target_path = make_path(empty_dir_path, 'new-global-session')\n  eq(child.fn.filereadable(target_path), 1)\nend\n\nT['write()']['respects `force` from `config` and `opts` argument'] = function()\n  child.fn.mkdir(empty_dir_path)\n  reload_module({ directory = empty_dir_path, force = { write = false } })\n\n  -- Should not allow writing to existing file if `force` is `false`\n  local path = make_path(empty_dir_path, 'existing-file')\n  child.fn.writefile({}, path)\n\n  expect.error(\n    function() child.lua([[MiniSessions.write('existing-file')]]) end,\n    [[%(mini%.sessions%) Can't write to existing]]\n  )\n  eq(child.fn.readfile(path), {})\n\n  -- Should prefer `opts` over `config`\n  child.lua([[MiniSessions.write('existing-file', { force = true })]])\n  eq(#child.fn.readfile(path) > 0, true)\nend\n\nT['write()']['respects hooks from `config` and `opts` argument'] = new_set({\n  parametrize = { { 'pre' }, { 'post' } },\n}, {\n  test = function(pre_post)\n    child.fn.mkdir(empty_dir_path)\n    local path\n\n    -- Should use `config`\n    local hook_string_config = make_hook_string(pre_post, 'write', 'config')\n    reload_from_strconfig({ directory = vim.inspect(empty_dir_path), hooks = hook_string_config })\n    child.lua([[MiniSessions.write('file_01')]])\n\n    path = make_path(empty_dir_path, 'file_01')\n    eq(#child.fn.readfile(path) > 0, true)\n    validate_executed_hook(pre_post, 'write', 'config')\n\n    -- Should prefer `opts` over `config`\n    local hook_string_opts = make_hook_string(pre_post, 'write', 'opts')\n    child.lua(([[MiniSessions.write('file_02', { hooks = %s })]]):format(hook_string_opts))\n\n    path = make_path(empty_dir_path, 'file_02')\n    eq(#child.fn.readfile(path) > 0, true)\n    validate_executed_hook(pre_post, 'write', 'opts')\n  end,\n})\n\nT['write()']['respects `verbose` from `config` and `opts` argument'] = function()\n  child.fn.mkdir(empty_dir_path)\n  reload_module({ directory = empty_dir_path, verbose = { write = false } })\n  local msg_pattern = '%(mini%.sessions%) Written session.*session%-written'\n\n  -- Should not give message about written session\n  child.lua([[MiniSessions.write('session-written')]])\n  local path = make_path(empty_dir_path, 'session-written')\n  eq(#child.fn.readfile(path) > 0, true)\n  expect.no_match(get_latest_message(), msg_pattern)\n\n  -- Should prefer `opts` over `config`\n  child.fn.delete(path)\n  child.lua([[MiniSessions.write('session-written', { verbose = true })]])\n  eq(#child.fn.readfile(path) > 0, true)\n  expect.match(get_latest_message(), msg_pattern)\nend\n\nT['write()']['respects `vim.{g,b}.minisessions_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child.fn.mkdir(empty_dir_path)\n    reload_module({ directory = empty_dir_path })\n    local path = make_path(empty_dir_path, 'session-file')\n\n    child[var_type].minisessions_disable = true\n\n    child.fn.delete(path)\n    child.lua([[MiniSessions.write('session-file')]])\n    eq(child.fn.filereadable('session-file'), 0)\n  end,\n})\n\nT['delete()'] = new_set()\n\nT['delete()']['works'] = function()\n  local session_dir = populate_sessions()\n  reload_module({ directory = session_dir })\n  local path = make_path(session_dir, 'session_a')\n\n  eq(child.lua_get('MiniSessions.detected')['session_a'].path, path)\n  child.lua([[MiniSessions.delete('session_a')]])\n  eq(child.fn.filereadable(path), 0)\nend\n\nT['delete()']['validates presence of detected sessions'] = function()\n  reload_module({ file = '', directory = '' })\n\n  expect.error(\n    function() child.lua([[MiniSessions.delete('aaa')]]) end,\n    '%(mini%.sessions%) There are no detected sessions'\n  )\nend\n\nT['delete()']['validates `session_name`'] = function()\n  reload_module({ directory = 'tests/dir-sessions/global' })\n  expect.error(\n    function() child.lua([[MiniSessions.delete('')]]) end,\n    '%(mini%.sessions%) Supply non%-empty session name'\n  )\nend\n\nT['delete()']['deletes by default `v:this_session`'] = function()\n  local session_dir = populate_sessions()\n  reload_module({ directory = session_dir, force = { delete = true } })\n\n  child.lua([[MiniSessions.read('session_a')]])\n  local path = make_path(session_dir, 'session_a')\n  eq(child.v.this_session, path)\n\n  child.lua('MiniSessions.delete()')\n  eq(child.fn.filereadable(path), 0)\n\n  -- Should also update `v:this_session`\n  eq(child.v.this_session, '')\nend\n\nT['delete()']['deletes from current directory if passed name of local session file'] = function()\n  local session_dir = populate_sessions()\n  cd(session_dir)\n  reload_module({ file = 'session_a', directory = '' })\n  eq(child.lua_get('MiniSessions.detected.session_a.type'), 'local')\n\n  child.lua([[MiniSessions.delete('session_a')]])\n\n  local path = make_path(session_dir, 'session_a')\n  eq(child.fn.filereadable(path), 0)\nend\n\nT['delete()']['deletes from global directory'] = function()\n  local session_dir = populate_sessions()\n  reload_module({ file = '', directory = session_dir })\n  eq(child.lua_get('MiniSessions.detected.session_a.type'), 'global')\n\n  child.lua([[MiniSessions.delete('session_a')]])\n\n  local path = make_path(session_dir, 'session_a')\n  eq(child.fn.filereadable(path), 0)\nend\n\nT['delete()']['makes detected sessions up to date'] = function()\n  local new_session = 'tests/dir-sessions/global/new_session'\n  MiniTest.finally(function() vim.fn.delete(new_session) end)\n\n  -- Detect sessions without new session\n  reload_module({ autowrite = false, directory = 'tests/dir-sessions/global' })\n  eq(child.lua_get('MiniSessions.detected.new_session == nil'), true)\n\n  -- Create new session file manually and try to delete it directly without\n  -- reloading whole module.\n  child.fn.writefile({ 'lua _G.session_file = ' .. vim.inspect(new_session) }, new_session)\n\n  child.lua([[MiniSessions.delete('new_session')]])\n  eq(child.fn.filereadable(new_session), 0)\nend\n\nT['delete()']['respects `force` from `config` and `opts` argument'] = function()\n  local session_dir = populate_sessions()\n  reload_module({ directory = session_dir, force = { delete = true } })\n  local path\n\n  -- Should allow deleting current session if `force` is `false`\n  child.lua([[MiniSessions.read('session_a')]])\n  path = make_path(session_dir, 'session_a')\n  eq(child.v.this_session, path)\n\n  child.lua([[MiniSessions.delete('session_a')]])\n  eq(child.fn.filereadable(path), 0)\n\n  -- Should prefer `opts` over `config`\n  child.lua([[MiniSessions.read('session_b')]])\n  path = make_path(session_dir, 'session_b')\n  eq(child.v.this_session, path)\n\n  expect.error(\n    function() child.lua([[MiniSessions.delete('session_b', { force = false })]]) end,\n    [[%(mini%.sessions%) Can't delete current session]]\n  )\n  eq(child.fn.filereadable(path), 1)\nend\n\nT['delete()']['respects hooks from `config` and `opts` argument'] = new_set({\n  parametrize = { { 'pre' }, { 'post' } },\n}, {\n  test = function(pre_post)\n    local session_dir = populate_sessions()\n    local path\n\n    -- Should use `config`\n    local hook_string_config = make_hook_string(pre_post, 'delete', 'config')\n    reload_from_strconfig({ directory = vim.inspect(session_dir), hooks = hook_string_config })\n    child.lua([[MiniSessions.delete('session_a')]])\n\n    path = make_path(session_dir, 'session_a')\n    eq(child.fn.filereadable(path), 0)\n    validate_executed_hook(pre_post, 'delete', 'config')\n\n    -- Should prefer `opts` over `config`\n    local hook_string_opts = make_hook_string(pre_post, 'delete', 'opts')\n    child.lua(([[MiniSessions.delete('session_b', { hooks = %s })]]):format(hook_string_opts))\n\n    path = make_path(session_dir, 'session_b')\n    eq(child.fn.filereadable(path), 0)\n    validate_executed_hook(pre_post, 'delete', 'opts')\n  end,\n})\n\nT['delete()']['respects `verbose` from `config` and `opts` argument'] = function()\n  local session_dir = populate_sessions()\n  reload_module({ directory = session_dir, verbose = { delete = false } })\n  local msg_pattern = '%(mini%.sessions%) Deleted session.*'\n  local path\n\n  -- Should not give message about deleted session\n  child.lua([[MiniSessions.delete('session_a')]])\n  path = make_path(session_dir, 'session_a')\n  eq(child.fn.filereadable(path), 0)\n  expect.no_match(get_latest_message(), msg_pattern .. 'session_a')\n\n  -- Should prefer `opts` over `config`\n  child.lua([[MiniSessions.delete('session_b', { verbose = true })]])\n  path = make_path(session_dir, 'session_b')\n  eq(child.fn.filereadable(path), 0)\n  expect.match(get_latest_message(), msg_pattern .. 'session_b')\nend\n\nT['delete()']['respects `vim.{g,b}.minisessions_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    local session_dir = populate_sessions()\n    reload_module({ directory = session_dir })\n    local path = make_path(session_dir, 'session_a')\n\n    child[var_type].minisessions_disable = true\n\n    if child.fn.filereadable(path) == 0 then populate_sessions() end\n    child.lua([[MiniSessions.delete('session_a')]])\n    eq(child.fn.filereadable(path), 1)\n  end,\n})\n\nT['select()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Mock `vim.ui.select`\n      child.lua('vim.ui = { select = function(...) _G.ui_select_args = { ... } end }')\n\n      -- Load module with detected sessions\n      local session_dir = populate_sessions()\n\n      -- Add local session\n      cd(session_dir)\n      child.fn.writefile({}, make_path(session_dir, 'Session.vim'), '')\n\n      reload_module({ directory = session_dir })\n    end,\n  },\n})\n\nT['select()']['works'] = function()\n  child.lua('MiniSessions.select()')\n\n  -- Should place local session first and then others alphabetically\n  eq(child.lua_get('_G.ui_select_args[1]'), { 'Session.vim', 'session_a', 'session_b' })\n\n  -- Should give informative prompt\n  eq(child.lua_get('_G.ui_select_args[2].prompt'), 'Select session to read')\n\n  -- Should format items by appending session type\n  eq(child.lua_get([[_G.ui_select_args[2].format_item('Session.vim')]]), 'Session.vim (local)')\n  eq(child.lua_get([[_G.ui_select_args[2].format_item('session_a')]]), 'session_a (global)')\n\n  -- By default should read selected session\n  validate_no_session_loaded()\n  child.lua([[_G.ui_select_args[3]('session_a', 2)]])\n  validate_session_loaded('empty/session_a')\nend\n\nT['select()']['makes detected sessions up to date'] = function()\n  child.lua('MiniSessions.select()')\n  eq(child.lua_get('_G.ui_select_args[1]'), { 'Session.vim', 'session_a', 'session_b' })\n\n  -- Remove 'session_a' manually which should be shown in `select()` output\n  local directory = child.lua_get('MiniSessions.config.directory')\n  child.fn.delete(make_path(directory, 'session_a'), 'rf')\n\n  child.lua('MiniSessions.select()')\n  eq(child.lua_get('_G.ui_select_args[1]'), { 'Session.vim', 'session_b' })\nend\n\nT['select()']['verifies presence of `vim.ui` and `vim.ui.select`'] = function()\n  child.lua('vim.ui = 1')\n  expect.error(function() child.lua('MiniSessions.select()') end, '%(mini%.sessions%).*vim%.ui')\n\n  child.lua('vim.ui = {}')\n  expect.error(function() child.lua('MiniSessions.select()') end, '%(mini%.sessions%).*vim%.ui%.select')\nend\n\nT['select()']['validates `action` argument'] = function()\n  expect.error(\n    function() child.lua([[MiniSessions.select('aaa')]]) end,\n    [[%(mini%.sessions%) `action` should be one of 'read', 'write', or 'delete'.]]\n  )\nend\n\nT['select()']['respects `action` argument'] = function()\n  local session_dir = child.lua_get('MiniSessions.config.directory')\n  local path = make_path(session_dir, 'session_a')\n  eq(child.fn.filereadable(path), 1)\n\n  child.lua([[MiniSessions.select('delete')]])\n  child.lua([[_G.ui_select_args[3]('session_a', 2)]])\n  eq(child.fn.filereadable(path), 0)\nend\n\nT['select()']['respects `opts` argument'] = function()\n  child.lua([[MiniSessions.select('read', { verbose = true })]])\n\n  local msg_pattern = '%(mini%.sessions%) Read session.*session_a'\n  expect.no_match(get_latest_message(), msg_pattern)\n  child.lua([[_G.ui_select_args[3]('session_a', 2)]])\n  validate_session_loaded('empty/session_a')\n  expect.match(get_latest_message(), msg_pattern)\nend\n\nT['get_latest()'] = new_set()\n\nT['get_latest()']['works'] = function()\n  local dir = populate_sessions(one_second_delay + small_time)\n  reload_module({ directory = dir })\n  eq(child.lua_get('MiniSessions.get_latest()'), 'session_b')\nend\n\nT['get_latest()']['works if there are no detected sessions'] = function()\n  reload_module({ directory = '', file = '' })\n  eq(child.lua_get('MiniSessions.get_latest()'), vim.NIL)\nend\n\n-- Integration tests ==========================================================\nT['Autoreading sessions'] = new_set()\n\nT['Autoreading sessions']['works'] = function()\n  child.restart({ '-u', 'tests/dir-sessions/init-files/autoread.lua' })\n  validate_session_loaded('local/Session.vim')\nend\n\nT['Autoreading sessions']['does not autoread if Neovim started to show something'] = function()\n  local init_autoread = 'tests/dir-sessions/init-files/autoread.lua'\n  local validate = function(...)\n    child.restart({ '-u', init_autoread, ... })\n    validate_no_session_loaded()\n  end\n\n  -- There are files in arguments (like `nvim foo.txt` with new file).\n  validate('new-file.txt')\n\n  -- Several buffers are listed (like session with placeholder buffers)\n  validate('-c', 'e foo | set buflisted | e bar | set buflisted')\n\n  -- Unlisted buffers (like from `nvim-tree`) don't affect decision\n  child.restart({ '-u', init_autoread, '-c', 'e foo | set nobuflisted | e bar | set buflisted' })\n  validate_session_loaded('local/Session.vim')\n\n  -- Current buffer is meant to show something else\n  validate('-c', 'set filetype=text')\n\n  -- Current buffer has any lines (something opened explicitly)\n  validate('-c', [[call setline(1, 'a')]])\nend\n\nT['Autowriting sessions'] = new_set()\n\nT['Autowriting sessions']['works'] = function()\n  local init_autowrite = 'tests/dir-sessions/init-files/autowrite.lua'\n  child.restart({ '-u', init_autowrite })\n\n  -- Create session with one buffer, expect to autowrite it with second\n  child.fn.mkdir(empty_dir_path)\n  cd(empty_dir_path)\n  child.cmd('e aaa | w | mksession')\n  local path_local = make_path(empty_dir_path, 'Session.vim')\n  eq(child.fn.filereadable(path_local), 1)\n\n  child.cmd('e bbb | w')\n  child.restart({ '-u', 'NONE' })\n  child.cmd('source ' .. path_local)\n  compare_buffer_names(get_buf_names(), { 'aaa', 'bbb' })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_snippets.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq, no_eq = helpers.expect, helpers.expect.equality, helpers.expect.no_equality\nlocal eq_partial_tbl = helpers.expect.equality_partial_tbl\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('snippets', config) end\nlocal unload_module = function() child.mini_unload('snippets') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\nlocal new_buf = function() return child.api.nvim_create_buf(true, false) end\nlocal get_buf = function() return child.api.nvim_get_current_buf() end\nlocal set_buf = function(buf_id) child.api.nvim_set_current_buf(buf_id) end\n--stylua: ignore end\n\nlocal test_dir = 'tests/dir-snippets'\nlocal test_dir_absolute = vim.fn.fnamemodify(test_dir, ':p'):gsub('\\\\', '/'):gsub('(.)/$', '%1')\n\n-- Time constants\nlocal small_time = helpers.get_time_const(10)\n\n-- Tweak `expect_screenshot()` to test only on Neovim>=0.10 (as it has inline\n-- extmarks support). Use `child.expect_screenshot_orig()` for original testing.\nchild.expect_screenshot_orig = child.expect_screenshot\nchild.expect_screenshot = function(opts)\n  if child.fn.has('nvim-0.10') == 0 then return end\n  child.expect_screenshot_orig(opts)\nend\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal get = forward_lua('MiniSnippets.session.get')\nlocal get_all = function() return get(true) end\nlocal jump = forward_lua('MiniSnippets.session.jump')\nlocal stop = forward_lua('MiniSnippets.session.stop')\n\n-- Common helpers\nlocal get_cur_tabstop = function() return (get() or {}).cur_tabstop end\n\nlocal validate_active_session = function() eq(child.lua_get('MiniSnippets.session.get() ~= nil'), true) end\nlocal validate_no_active_session = function() eq(child.lua_get('MiniSnippets.session.get() ~= nil'), false) end\nlocal validate_n_sessions = function(n) eq(child.lua_get('#MiniSnippets.session.get(true)'), n) end\n\nlocal validate_pumvisible = function() eq(child.fn.pumvisible(), 1) end\nlocal validate_no_pumvisible = function() eq(child.fn.pumvisible(), 0) end\nlocal validate_pumitems = function(ref)\n  if #ref == 0 then validate_no_pumvisible() end\n  if #ref > 0 then validate_pumvisible() end\n  eq(vim.tbl_map(function(t) return t.word end, child.fn.complete_info().items), ref)\nend\n\nlocal validate_state = function(mode, lines, cursor)\n  if mode ~= nil then eq(child.fn.mode(), mode) end\n  if lines ~= nil then eq(get_lines(), lines) end\n  if cursor ~= nil then eq(get_cursor(), cursor) end\nend\n\nlocal mock_select = function(user_chosen_id)\n  child.lua('_G.user_chosen_id = ' .. user_chosen_id)\n  child.lua([[\n    vim.ui.select = function(items, opts, on_choice)\n      local format_item = opts.format_item or function(x) return tostring(x) end\n      _G.select_args = {\n        items = items,\n        items_formatted = vim.tbl_map(format_item, items),\n        prompt = opts.prompt,\n        kind = opts.kind\n      }\n      on_choice(items[_G.user_chosen_id], _G.user_chosen_id)\n    end\n  ]])\nend\n\nlocal setup_event_log = function()\n  child.lua([[\n    local suffixes = { 'Start', 'Stop', 'Suspend', 'Resume', 'JumpPre', 'Jump' }\n    local au_events = vim.tbl_map(function(s) return 'MiniSnippetsSession' .. s end, suffixes)\n    _G.au_log = {}\n    local log_event = function(args)\n      table.insert(au_log, { buf_id = args.buf, event = args.match, data = args.data })\n    end\n    vim.api.nvim_create_autocmd('User', { pattern = au_events, callback = log_event })\n  ]])\nend\n\nlocal get_au_log = function() return child.lua_get('_G.au_log') end\n\nlocal clean_au_log = function() return child.lua('_G.au_log = {}') end\n\nlocal get_snippet_body = function(session) return (session or get()).insert_args.snippet.body end\nlocal make_snippet_body = function(body) return { insert_args = { snippet = body } } end\n\nlocal make_get_extmark = function(session)\n  local buf_id, ns_id = session.buf_id, session.ns_id\n  return function(extmark_id)\n    local data = child.api.nvim_buf_get_extmark_by_id(buf_id, ns_id, extmark_id, { details = true })\n    data[3].row, data[3].col = data[1], data[2]\n    return data[3]\n  end\nend\n\nlocal validate_session_nodes_partial = function(session, ref_nodes)\n  local get_extmark = make_get_extmark(session)\n  local nodes = vim.deepcopy(session.nodes)\n  -- Replace `extmark_id` (should be present in every node) with extmark data\n  local replace_extmarks\n  replace_extmarks = function(n_arr)\n    for _, n in ipairs(n_arr) do\n      n.extmark = get_extmark(n.extmark_id)\n      n.extmark_id = nil\n      if n.placeholder ~= nil then replace_extmarks(n.placeholder) end\n    end\n  end\n  replace_extmarks(nodes)\n\n  eq_partial_tbl(nodes, ref_nodes)\nend\n\nlocal ensure_clean_state = function()\n  child.lua([[while MiniSnippets.session.get() do MiniSnippets.session.stop() end]])\n  -- while get() do stop() end\n  child.ensure_normal_mode()\n  set_lines({})\n  clean_au_log()\nend\n\nlocal edit = function(path)\n  child.cmd('edit ' .. child.fn.fnameescape(path))\n  -- Slow context needs a small delay to get things up to date\n  if helpers.is_slow() then sleep(small_time) end\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      child.set_size(8, 40)\n      set_buf(new_buf())\n\n      -- Mock `vim.notify()`\n      child.lua([[\n        _G.notify_log = {}\n        local inverse_levels = {}\n        for k, v in pairs(vim.log.levels) do\n          inverse_levels[v] = k\n        end\n        vim.notify = function(msg, lvl, opts)\n          table.insert(_G.notify_log, { msg, inverse_levels[lvl], opts })\n        end\n      ]])\n\n      -- Add helper for easier RPC communication\n      child.lua([[\n        _G.sanitize_object = function(x)\n          if type(x) == 'function' then return 'function' end\n          if type(x) == 'table' then\n            local res = {}\n            for k, v in pairs(x) do\n              res[k] = _G.sanitize_object(v)\n            end\n            return res\n          end\n          return x\n        end\n      ]])\n\n      -- Better interaction with built-in completion\n      child.o.completeopt = 'menuone,noselect'\n\n      load_module()\n    end,\n    post_once = child.stop,\n    n_retry = helpers.get_n_retry(2),\n  },\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniSnippets)'), 'table')\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  child.cmd('hi DiagnosticUnderlineError guisp=#ff0000 gui=underline cterm=underline')\n  child.cmd('hi DiagnosticUnderlineWarn guisp=#ffff00 gui=undercurl cterm=undercurl')\n  child.cmd('hi DiagnosticUnderlineInfo guisp=#0000ff gui=underdotted cterm=underline')\n  child.cmd('hi DiagnosticUnderlineHint guisp=#00ffff gui=underdashed cterm=underdashed')\n  child.cmd('hi DiagnosticUnderlineOk guifg=#00ff00 guibg=#000000')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniSnippetsCurrent', 'gui=underdouble guisp=#ffff00')\n  has_highlight('MiniSnippetsCurrentReplace', 'gui=underdouble guisp=#ff0000')\n  has_highlight('MiniSnippetsFinal', 'gui=underdouble')\n  has_highlight('MiniSnippetsUnvisited', 'gui=underdouble guisp=#00ffff')\n  has_highlight('MiniSnippetsVisited', 'gui=underdouble guisp=#0000ff')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniSnippets.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniSnippets.config.' .. field), value) end\n\n  expect_config('snippets', {})\n  expect_config('mappings.expand', '<C-j>')\n  expect_config('mappings.jump_next', '<C-l>')\n  expect_config('mappings.jump_prev', '<C-h>')\n  expect_config('mappings.stop', '<C-c>')\n  expect_config('expand', { prepare = nil, match = nil, select = nil, insert = nil })\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ snippets = { { prefix = 'a', body = 'axa' } } })\n  eq(child.lua_get('MiniSnippets.config.snippets'), { { prefix = 'a', body = 'axa' } })\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ snippets = 1 }, 'snippets', 'table')\n  expect_config_error({ mappings = 1 }, 'mappings', 'table')\n  expect_config_error({ mappings = { expand = 1 } }, 'mappings.expand', 'string')\n  expect_config_error({ mappings = { jump_next = 1 } }, 'mappings.jump_next', 'string')\n  expect_config_error({ mappings = { jump_prev = 1 } }, 'mappings.jump_prev', 'string')\n  expect_config_error({ mappings = { stop = 1 } }, 'mappings.stop', 'string')\n  expect_config_error({ expand = 1 }, 'expand', 'table')\n  expect_config_error({ expand = { prepare = 1 } }, 'expand.prepare', 'function')\n  expect_config_error({ expand = { match = 1 } }, 'expand.match', 'function')\n  expect_config_error({ expand = { select = 1 } }, 'expand.select', 'function')\n  expect_config_error({ expand = { insert = 1 } }, 'expand.insert', 'function')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniSnippetsCurrent'), 'gui=underdouble guisp=#')\nend\n\nT['setup()']['adds \"code-snippets\" filetype detection'] = function()\n  eq(child.lua_get('vim.filetype.match({ filename = \"aaa.code-snippets\" })'), 'json')\nend\n\n-- Test are high-level. Granular testing is done in tests for `default_*()`.\nT['expand()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua([[\n        _G.context_log = {}\n        MiniSnippets.config.snippets = {\n          function(context)\n            table.insert(_G.context_log, context)\n            return { { prefix = 'ba', body = 'BA=$1 T0=$0' } }\n          end,\n          { { prefix = 'aa', body = 'AA=$1 T0=$0' } },\n          { prefix = 'xx', body = 'XX=$1 T0=$0' },\n        }]])\n\n      child.bo.filetype = 'myft'\n    end,\n  },\n})\n\nlocal expand = forward_lua('MiniSnippets.expand')\n\nT['expand()']['works with defaults'] = function()\n  local validate = function()\n    -- Should expand snippet with 'ba' prefix, because `default_prepare` sorts\n    -- resolved snippets in prefix's alphabetical order.\n    mock_select(2)\n    expand()\n    eq(child.lua_get('_G.context_log'), { { buf_id = 2, lang = 'myft' } })\n    eq(child.lua_get('_G.select_args.items_formatted'), { 'aa │ AA=$1 T0=$0', 'ba │ BA=$1 T0=$0' })\n    validate_active_session()\n    validate_state('i', { 'BA= T0=' }, { 1, 3 })\n\n    child.lua('_G.context_log, _G.select_args = {}, nil')\n  end\n\n  -- Insert mode\n  type_keys('i', 'a')\n  validate()\n  ensure_clean_state()\n\n  -- Normal mode\n  type_keys('i', 'a', '<Esc>')\n  validate()\nend\n\nT['expand()']['implements proper order of steps'] = function()\n  type_keys('i', 'a')\n  mock_select(2)\n  child.lua([[\n    _G.steps_log = {}\n    local wrap_with_log = function(step_name, f)\n      return function(...)\n        table.insert(_G.steps_log, { step = step_name, args = { ... } })\n        return f(...)\n      end\n    end\n    local opts = {\n      prepare = wrap_with_log('prepare', MiniSnippets.default_prepare),\n      match = wrap_with_log('match', MiniSnippets.default_match),\n      select = wrap_with_log('select', MiniSnippets.default_select),\n      insert = wrap_with_log('insert', MiniSnippets.default_insert),\n    }\n    MiniSnippets.expand(opts)\n  ]])\n\n  local ref_region = { from = { col = 1, line = 1 }, to = { col = 1, line = 1 } }\n  local ref_steps_log = {\n    {\n      -- Should be called with raw config snippets\n      step = 'prepare',\n      args = {\n        {\n          'function',\n          { { prefix = 'aa', body = 'AA=$1 T0=$0' } },\n          { prefix = 'xx', body = 'XX=$1 T0=$0' },\n        },\n      },\n    },\n    {\n      -- Should be called with normalized snippet array\n      step = 'match',\n      args = {\n        {\n          { prefix = 'aa', body = 'AA=$1 T0=$0', desc = 'AA=$1 T0=$0' },\n          { prefix = 'ba', body = 'BA=$1 T0=$0', desc = 'BA=$1 T0=$0' },\n          { prefix = 'xx', body = 'XX=$1 T0=$0', desc = 'XX=$1 T0=$0' },\n        },\n      },\n    },\n    {\n      -- Should be called with matched snippet array and `insert` function\n      step = 'select',\n      args = {\n        {\n          { prefix = 'aa', body = 'AA=$1 T0=$0', desc = 'AA=$1 T0=$0', region = ref_region },\n          { prefix = 'ba', body = 'BA=$1 T0=$0', desc = 'BA=$1 T0=$0', region = ref_region },\n        },\n        'function',\n      },\n    },\n    {\n      -- Should be called with selected snippet, `region` should be removed\n      step = 'insert',\n      args = { { prefix = 'ba', body = 'BA=$1 T0=$0', desc = 'BA=$1 T0=$0' } },\n    },\n  }\n  eq(child.lua_get('_G.sanitize_object(_G.steps_log)'), ref_steps_log)\nend\n\nT['expand()']['uses config as default for steps'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniSnippets.config.expand = {\n      prepare = function(...)\n        table.insert(_G.log, 'global prepare')\n        return MiniSnippets.default_prepare(...)\n      end,\n      match = function(...)\n        table.insert(_G.log, 'global match')\n        return MiniSnippets.default_match(...)\n      end,\n    }\n\n    vim.b.minisnippets_config = { expand = {\n      match = function(...)\n        table.insert(_G.log, 'buffer-local match')\n        return MiniSnippets.default_match(...)\n      end,\n    }}\n  ]])\n\n  mock_select(2)\n  expand()\n  -- Should prefer buffer-local over global config\n  eq(child.lua_get('_G.log'), { 'global prepare', 'buffer-local match' })\nend\n\nT['expand()']['prepares for `insert` to be executed at cursor in Insert mode'] = function()\n  child.lua([[\n    _G.log = {}\n    MiniSnippets.config.expand.insert = function(...)\n      local state = {\n        mode = vim.fn.mode(),\n        line = vim.api.nvim_get_current_line(),\n        cursor = vim.api.nvim_win_get_cursor(0),\n      }\n      table.insert(_G.log, state)\n    end]])\n\n  local validate = function(keys, ref_line, ref_cursor)\n    type_keys(1, 'i', keys)\n    mock_select(1)\n    expand()\n    -- Should ensure Insert mode, remove matched region, ensure cursor\n    eq(child.lua_get('_G.log'), { { mode = 'i', line = ref_line, cursor = ref_cursor } })\n    child.lua('_G.log = {}')\n    ensure_clean_state()\n  end\n\n  -- Insert mode (in different line positions)\n  -- - Should remove matched region\n  validate({ 'a line start', '<Esc>', '0', 'a' }, ' line start', { 1, 0 })\n  validate({ 'line a middle', '<Esc>', 'b<Left>', 'i' }, 'line  middle', { 1, 5 })\n  validate({ 'line end a' }, 'line end ', { 1, 9 })\n\n  -- - Empty base for matching (no region to remove)\n  validate({ 'line start', '<Esc>', '0', 'i' }, 'line start', { 1, 0 })\n  validate({ 'line middle', '<Esc>', 'b', 'i' }, 'line middle', { 1, 5 })\n  validate({ 'line end ' }, 'line end ', { 1, 9 })\n\n  -- Normal mode\n  validate({ 'a line start', '<Esc>', '0' }, ' line start', { 1, 0 })\n  validate({ 'line a middle', '<Esc>', 'b<Left><Left>' }, 'line  middle', { 1, 5 })\n  validate({ 'line end a', '<Esc>' }, 'line end ', { 1, 9 })\n\n  validate({ ' line start', '<Esc>', '0' }, ' line start', { 1, 0 })\n  validate({ 'line middle', '<Esc>', 'b', '<Left>' }, 'line middle', { 1, 4 })\n  validate({ 'line end ', '<Esc>' }, 'line end ', { 1, 8 })\nend\n\nT['expand()']['works with `vim.ui.select` which does not restore Insert mode'] = function()\n  child.lua([[\n    vim.ui.select = function(items, opts, on_choice)\n      vim.api.nvim_feedkeys('\\27', 'nx', false)\n      vim.schedule(function() on_choice(items[1]) end)\n    end\n    _G.log = {}\n    MiniSnippets.config.expand.insert = function(...)\n      local t = { mode = vim.fn.mode(), line = vim.api.nvim_get_current_line(), cursor = vim.api.nvim_win_get_cursor(0)}\n      table.insert(_G.log, t)\n    end\n  ]])\n\n  local validate = function(keys, ref_line, ref_cursor)\n    type_keys('i', keys)\n    expand()\n    -- Poke eventloop because both ensuring Insert mode from Normal mode and\n    -- jumping do not happen immediately\n    child.poke_eventloop()\n    eq(child.lua_get('_G.log'), { { mode = 'i', line = ref_line, cursor = ref_cursor } })\n    ensure_clean_state()\n    child.lua('_G.log = {}')\n  end\n\n  -- With removing region\n  validate({ 'uu a' }, 'uu ', { 1, 3 })\n  validate({ 'uu a vv', '<Left><Left><Left>' }, 'uu  vv', { 1, 3 })\n  validate({ 'a vv', '<Left><Left><Left>' }, ' vv', { 1, 0 })\n\n  -- Without removing region. Currently doesn't work as ensuring Insert mode\n  -- moves cursor one cell to the left (as after `<Esc>i`). It works for case\n  -- with removing region because there is info about where to put cursor.\n  -- validate({ 'uu ' }, 'uu ', { 1, 3 })\n  -- validate({ 'u  u', '<Left><Left>' }, 'u  u', { 1, 2 })\n  -- validate({ ' u', '<Left>' }, ' u', { 1, 1 })\nend\n\nT['expand()']['accepts `false` for some steps'] = function()\n  -- Use all snippets if `match = false`\n  type_keys('i', 'a')\n  -- - Select snippet that is clearly not matched\n  mock_select(3)\n  expand({ match = false })\n  validate_active_session()\n  -- - No region is removed because there was no match\n  validate_state('i', { 'aXX= T0=' }, { 1, 4 })\n  ensure_clean_state()\n\n  -- Force best (first) match insert with `select = false`\n  type_keys('i', 'a')\n  expand({ select = false })\n  validate_active_session()\n  validate_state('i', { 'AA= T0=' }, { 1, 3 })\n  ensure_clean_state()\n\n  -- Return snippets with `insert = false`\n  type_keys('i', 'a')\n\n  -- - Matched snippets by default\n  local ref_region = { from = { col = 1, line = 1 }, to = { col = 1, line = 1 } }\n  local ref_matched_snippets = {\n    { prefix = 'aa', body = 'AA=$1 T0=$0', desc = 'AA=$1 T0=$0', region = ref_region },\n    { prefix = 'ba', body = 'BA=$1 T0=$0', desc = 'BA=$1 T0=$0', region = ref_region },\n  }\n  eq(expand({ insert = false }), ref_matched_snippets)\n  validate_no_active_session()\n  validate_state('i', { 'a' }, { 1, 1 })\n\n  -- - All snippets if `match = false`\n  local ref_all_snippets = {\n    { prefix = 'aa', body = 'AA=$1 T0=$0', desc = 'AA=$1 T0=$0' },\n    { prefix = 'ba', body = 'BA=$1 T0=$0', desc = 'BA=$1 T0=$0' },\n    { prefix = 'xx', body = 'XX=$1 T0=$0', desc = 'XX=$1 T0=$0' },\n  }\n  eq(expand({ match = false, insert = false }), ref_all_snippets)\n  validate_no_active_session()\n  validate_state('i', { 'a' }, { 1, 1 })\nend\n\nT['expand()']['does not warn about no matches if `insert = false`'] = function()\n  -- No matches\n  type_keys('i', 't')\n  eq(expand({ insert = false }), {})\n\n  -- No snippets at all\n  child.lua('MiniSnippets.config.snippets = {}')\n  eq(expand({ match = false, insert = false }), {})\n\n  -- In both cases output should be done silently\n  eq(child.lua_get('_G.notify_log'), {})\nend\n\nT['expand()']['validates correct step output'] = function()\n  local validate_bad_out = function(step_name, bad_output)\n    child.lua('_G.step_name, _G.bad_output = ' .. vim.inspect(step_name) .. ', ' .. vim.inspect(bad_output))\n    child.lua('_G.bad_step = function() return _G.bad_output end')\n    local err_pattern = '`' .. step_name .. '`.*array of snippets'\n    expect.error(function() child.lua('MiniSnippets.expand({ [_G.step_name] = _G.bad_step })') end, err_pattern)\n  end\n\n  -- Should error about not proper `prepare` output\n  validate_bad_out('prepare', 1)\n  validate_bad_out('prepare', { 1 })\n  validate_bad_out('prepare', { 1 })\n  validate_bad_out('prepare', { { body = 1 } })\n  validate_bad_out('prepare', { { body = 'T1=$1', prefix = 1 } })\n  validate_bad_out('prepare', { { body = 'T1=$1', desc = 1 } })\n  validate_bad_out('prepare', { { body = 'T1=$1', region = 1 } })\n\n  -- Should error about not proper `match` output\n  validate_bad_out('match', 1)\n  validate_bad_out('match', { 1 })\n  validate_bad_out('match', { 1 })\n  validate_bad_out('match', { { body = 1 } })\n  validate_bad_out('match', { { body = 'T1=$1', prefix = 1 } })\n  validate_bad_out('match', { { body = 'T1=$1', desc = 1 } })\n  validate_bad_out('match', { { body = 'T1=$1', region = 1 } })\n\n  -- Should warn about no matches and use `context` returned from `prepare` step\n  child.lua([[\n    MiniSnippets.config.expand.prepare = function(...)\n      return _G.prepare_res or MiniSnippets.default_prepare(...), { data = 'my context' }\n    end\n  ]])\n\n  -- - Should warn about no matches\n  type_keys('i', 't')\n  expand()\n  validate_state('i', { 't' }, { 1, 1 })\n  local ref_log = { { '(mini.snippets) No matches in context:\\n{\\n  data = \"my context\"\\n}', 'WARN' } }\n  eq(child.lua_get('_G.notify_log'), ref_log)\n  child.lua('_G.notify_log = {}')\n  ensure_clean_state()\n\n  -- Should warn about no snippets (as returned by prepare step) at all\n  child.lua('_G.prepare_res = {}')\n  type_keys('i', 'a')\n  expand()\n  validate_state('i', { 'a' }, { 1, 1 })\n  ref_log = { { '(mini.snippets) No snippets in context:\\n{\\n  data = \"my context\"\\n}', 'WARN' } }\n  eq(child.lua_get('_G.notify_log'), ref_log)\n  child.lua('_G.notify_log = {}')\n  ensure_clean_state()\nend\n\nT['expand()']['validates input'] = function()\n  expect.error(function() expand({ prepare = 1 }) end, '`opts%.prepare`.*callable')\n  expect.error(function() expand({ match = 1 }) end, '`opts%.match`.*`false` or callable')\n  expect.error(function() expand({ select = 1 }) end, '`opts%.select`.*`false` or callable')\n  expect.error(function() expand({ insert = 1 }) end, '`opts%.insert`.*`false` or callable')\nend\n\nT['expand()']['respects `vim.b.minisnippets_config`'] = function()\n  -- Should process buffer-local config after global config and in this case\n  -- remove snippets with these prefixes (as body is `nil`)\n  child.b.minisnippets_config = { snippets = { { prefix = 'aa' }, { prefix = 'ba' } } }\n  eq(expand({ insert = false, match = false }), { { prefix = 'xx', body = 'XX=$1 T0=$0', desc = 'XX=$1 T0=$0' } })\nend\n\nT['expand()']['respects `vim.{g,b}.minidiff_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisnippets_disable = true\n    mock_select(2)\n    expand()\n    validate_no_active_session()\n    validate_state('n', { '' }, { 1, 0 })\n\n    child[var_type].minisnippets_disable = false\n    mock_select(2)\n    expand()\n    validate_active_session()\n    validate_state('i', { 'BA= T0=' }, { 1, 3 })\n  end,\n})\n\nT['gen_loader'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Monkey-patch `read_file()` to test caching\n      child.lua([[\n        local read_file_orig = MiniSnippets.read_file\n        _G.read_args_log = {}\n        MiniSnippets.read_file = function(...)\n          table.insert(_G.read_args_log, { ... })\n          return read_file_orig(...)\n        end\n      ]])\n    end,\n  },\n})\n\nT['gen_loader']['from_lang()'] = new_set()\n\nT['gen_loader']['from_lang()']['works'] = function()\n  child.o.runtimepath = test_dir_absolute .. '/subdir,' .. test_dir_absolute\n  child.lua('_G.loader = MiniSnippets.gen_loader.from_lang()')\n  local ref_snippet_data = {\n    -- Should first read runtime files (however nested) from \"lua\" directory\n    {\n      { { prefix = 'f', body = 'F=$1', desc = 'subdir/snippets/lua/deeper/another.json' } },\n      { { prefix = 'e', body = 'E=$1', desc = 'subdir/snippets/lua/file.json' } },\n    },\n    {\n      { { prefix = 'd', body = 'D=$1', desc = 'subdir/snippets/lua/snips.lua' } },\n    },\n    -- And only then from exactly named files (however nested)\n    {\n      -- Should read in order of 'runtimepath'\n      { { prefix = 'c', body = 'C=$1', desc = 'subdir/snippets/lua.json' } },\n      { { prefix = 'a', body = 'A=$1', desc = 'snippets/lua.json' } },\n      { { prefix = 'g', body = 'G=$1', desc = 'snippets/nested/lua.json' } },\n    },\n    {\n      { { prefix = 'b', body = 'B=$1', desc = 'snippets/lua.lua' } },\n      { { prefix = 'h', body = 'H=$1', desc = 'snippets/nested/lua.lua' } },\n    },\n  }\n  eq(child.lua_get('_G.loader({ lang = \"lua\" })'), ref_snippet_data)\n\n  -- Should cache output per lang context and thus not call `read_file` again\n  local read_args_log = child.lua_get('_G.read_args_log')\n  child.lua('_G.loader({ lang = \"lua\" })')\n  eq(child.lua_get('_G.read_args_log'), read_args_log)\nend\n\nT['gen_loader']['from_lang()']['respects `opts.lang_patterns`'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua('_G.loader = MiniSnippets.gen_loader.from_lang({ lang_patterns = { lua = { \"lua.lua\" } } })')\n  local ref_snippet_data = { { { { prefix = 'b', body = 'B=$1', desc = 'snippets/lua.lua' } } } }\n  eq(child.lua_get('_G.loader({ lang = \"lua\" })'), ref_snippet_data)\nend\n\nT['gen_loader']['from_lang()']['works with not typical `lang` context'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_lang() ]])\n\n  -- Not string should be silently ignored\n  eq(child.lua_get('_G.loader({ lang = 1 })'), {})\n  eq(child.lua_get('_G.loader({ lang = nil })'), {})\n  eq(child.lua_get('_G.notify_log'), {})\n\n  -- Empty string\n  eq(child.lua_get('_G.loader({ lang = \"\" })'), {})\n\n  -- - Can be made working by explicitly adding language pattern\n  child.lua([[\n    local lang_patterns = { [''] = { 'lua.json' } }\n    _G.loader_2 = MiniSnippets.gen_loader.from_lang({ lang_patterns = lang_patterns })\n  ]])\n  eq(\n    child.lua_get('_G.loader_2({ lang = \"\" })'),\n    { { { { prefix = 'a', body = 'A=$1', desc = 'snippets/lua.json' } } } }\n  )\nend\n\nT['gen_loader']['from_lang()']['outputs share cache per pattern'] = function()\n  child.o.runtimepath = test_dir_absolute .. '/subdir,' .. test_dir_absolute\n  child.lua([[\n    local opts_1 = { lang_patterns = { lua = { 'lua.json', 'lua.lua' } } }\n    _G.loader_1 = MiniSnippets.gen_loader.from_lang(opts_1)\n    local opts_2 = { lang_patterns = { lua = { 'lua.json', 'lua.code-snippets' } } }\n    _G.loader_2 = MiniSnippets.gen_loader.from_lang(opts_2)\n  ]])\n\n  child.lua_get('_G.loader_1({ lang = \"lua\" })')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  child.lua_get('_G.loader_2({ lang = \"lua\" })')\n  -- It should have read one extra 'subdir/snippets/lua.code-snippets', while\n  -- using cache for all 'lua.json' files\n  eq(#child.lua_get('_G.read_args_log'), #read_args_log + 1)\nend\n\nT['gen_loader']['from_lang()']['respects `opts.cache`'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua('_G.loader = MiniSnippets.gen_loader.from_lang({ cache = false })')\n\n  child.lua('_G.loader({ lang = \"lua\" })')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  eq(#read_args_log > 0, true)\n  child.lua('_G.loader({ lang = \"lua\" })')\n  eq(#child.lua_get('_G.read_args_log') > #read_args_log, true)\nend\n\nT['gen_loader']['from_lang()']['clears cache after `setup()`'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua('_G.loader = MiniSnippets.gen_loader.from_lang()')\n\n  child.lua('_G.loader({ lang = \"lua\" })')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  child.lua('MiniSnippets.setup()')\n  child.lua('_G.loader({ lang = \"lua\" })')\n  eq(#child.lua_get('_G.read_args_log') > #read_args_log, true)\nend\n\nT['gen_loader']['from_lang()']['forwards `opts.cache` and `opts.silent` to `from_runtime()`'] = function()\n  child.lua([[\n    local from_runtime_orig = MiniSnippets.gen_loader.from_runtime\n    _G.from_runtime_args_log = {}\n    MiniSnippets.gen_loader.from_runtime = function(...)\n      table.insert(_G.from_runtime_args_log, { ... })\n      return from_runtime_orig(...)\n    end\n  ]])\n\n  child.o.runtimepath = test_dir_absolute\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_lang({ cache = false, silent = true })]])\n  child.lua('_G.loader({ lang = \"lua\" })')\n  local from_runtime_args_log = child.lua_get('_G.from_runtime_args_log')\n  eq(from_runtime_args_log[1][2], { cache = false, silent = true })\n  eq(from_runtime_args_log[2][2], { cache = false, silent = true })\n\n  -- Should not reuse generate `from_runtime()` loaders\n  child.lua('_G.loader({ lang = \"lua\" })')\n  eq(child.lua_get('_G.from_runtime_args_log'), from_runtime_args_log)\nend\n\nT['gen_loader']['from_lang()']['validates input'] = function()\n  local validate_lang_patterns_error = function(lang_patterns, err_pattern)\n    child.lua('_G.lang_patterns = ' .. vim.inspect(lang_patterns))\n    local lua_cmd = 'MiniSnippets.gen_loader.from_lang({ lang_patterns = _G.lang_patterns })'\n    expect.error(function() child.lua(lua_cmd) end, err_pattern)\n  end\n\n  validate_lang_patterns_error({ 'lua' }, 'Keys of `opts.lang_patterns`.*string')\n  validate_lang_patterns_error({ lua = 'lua.lua' }, 'Values of `opts.lang_patterns`.*arrays')\n  validate_lang_patterns_error({ lua = { 1 } }, 'Values of `opts.lang_patterns`.*string')\nend\n\nT['gen_loader']['from_runtime()'] = new_set()\n\nT['gen_loader']['from_runtime()']['works'] = function()\n  child.o.runtimepath = test_dir_absolute .. '/subdir'\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_runtime('lua/**/*.json')]])\n  local ref_snippets = {\n    { { prefix = 'f', body = 'F=$1', desc = 'subdir/snippets/lua/deeper/another.json' } },\n    { { prefix = 'e', body = 'E=$1', desc = 'subdir/snippets/lua/file.json' } },\n  }\n  eq(child.lua_get('_G.loader()'), ref_snippets)\n  local read_args_log = child.lua_get('_G.read_args_log')\n\n  -- Should cache output per pattern and thus not call `read_file` again\n  eq(child.lua_get('_G.loader()'), ref_snippets)\n  eq(child.lua_get('_G.read_args_log'), read_args_log)\n\n  child.lua([[_G.loader_2 = MiniSnippets.gen_loader.from_runtime('lua/**/snips.lua')]])\n  eq(child.lua_get('_G.loader_2()'), { { { prefix = 'd', body = 'D=$1', desc = 'subdir/snippets/lua/snips.lua' } } })\n  eq(#child.lua_get('_G.read_args_log') > #read_args_log, true)\n\n  -- Should read all matching files (not just first)\n  child.o.runtimepath = (test_dir_absolute .. '/subdir') .. ',' .. test_dir_absolute\n  child.lua([[_G.loader_all = MiniSnippets.gen_loader.from_runtime('lua.json')]])\n  local ref_snippets_all = {\n    { { prefix = 'c', body = 'C=$1', desc = 'subdir/snippets/lua.json' } },\n    { { prefix = 'a', body = 'A=$1', desc = 'snippets/lua.json' } },\n  }\n  eq(child.lua_get('_G.loader_all()'), ref_snippets_all)\nend\n\nT['gen_loader']['from_runtime()']['outputs share cache'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua([[\n    _G.loader_1 = MiniSnippets.gen_loader.from_runtime('lua.json')\n    _G.loader_2 = MiniSnippets.gen_loader.from_runtime('lua.json')\n  ]])\n\n  child.lua_get('_G.loader_1()')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  eq(#read_args_log > 0, true)\n  child.lua_get('_G.loader_2()')\n  eq(child.lua_get('_G.read_args_log'), read_args_log)\nend\n\nT['gen_loader']['from_runtime()']['respects `opts.cache`'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_runtime('lua.json', { cache = false })]])\n\n  child.lua('_G.loader()')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  -- Should use `read_file()` again as no caching is done\n  child.lua('_G.loader()')\n  eq(#child.lua_get('_G.read_args_log') > #read_args_log, true)\nend\n\nT['gen_loader']['from_runtime()']['forwards `opts.cache` and `opts.silent` to `read_file()`'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_runtime('lua.json', { cache = false, silent = true })]])\n  child.lua('_G.loader()')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  eq(read_args_log[1][2], { cache = false, silent = true })\nend\n\nT['gen_loader']['from_runtime()']['respects `opts.all`'] = function()\n  child.o.runtimepath = (test_dir_absolute .. '/subdir') .. ',' .. test_dir_absolute\n  child.lua([[_G.loader_first = MiniSnippets.gen_loader.from_runtime('lua.json', { all = false })]])\n  local ref_snippets_first = { { { prefix = 'c', body = 'C=$1', desc = 'subdir/snippets/lua.json' } } }\n  eq(child.lua_get('_G.loader_first()'), ref_snippets_first)\nend\n\nT['gen_loader']['from_runtime()']['clears cache after `setup()`'] = function()\n  child.o.runtimepath = test_dir_absolute\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_runtime('lua.lua')]])\n\n  child.lua('_G.loader()')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  child.lua('MiniSnippets.setup()')\n  child.lua('_G.loader()')\n  eq(#child.lua_get('_G.read_args_log') > #read_args_log, true)\nend\n\nT['gen_loader']['from_runtime()']['validates input'] = function()\n  expect.error(function() child.lua('MiniSnippets.gen_loader.from_runtime(1)') end, '`pattern`.*string')\nend\n\nT['gen_loader']['from_file()'] = new_set()\n\nT['gen_loader']['from_file()']['works'] = function()\n  -- Should be able to work with relative paths\n  child.lua('_G.loader = MiniSnippets.gen_loader.from_file(\"file-array.lua\")')\n\n  -- Should silently return `{}` if file is absent\n  eq(child.lua_get('_G.loader()'), {})\n  eq(child.lua_get('_G.notify_log'), {})\n\n  -- Should load file if present and show warnings\n  child.fn.chdir(test_dir_absolute)\n  local out = child.lua_get('_G.loader()')\n  eq(#out, 5)\n  eq(out[1], { prefix = 'lua_a', body = 'LUA_A=$1', desc = 'Desc LUA_A' })\n  expect.match(child.lua_get('_G.notify_log')[1][1], 'There were problems')\n\n  -- Should work with paths stargin with \"~\"\n  local path_tilde = child.lua([[\n    local path_tilde = vim.fn.fnamemodify('file-array.lua', ':p:~')\n    _G.loader_tilde = MiniSnippets.gen_loader.from_file(path_tilde)\n    return path_tilde\n  ]])\n  if path_tilde:sub(1, 1) ~= '~' then return end\n  eq(child.lua_get('_G.loader_tilde()'), out)\nend\n\nT['gen_loader']['from_file()']['works with function items'] = function()\n  child.lua('_G.file_dynamic_path = ' .. vim.inspect(test_dir_absolute .. '/file-dynamic-snippets.lua'))\n  local dyn_snippets = child.lua([[\n    MiniSnippets.config.snippets = { MiniSnippets.gen_loader.from_file(_G.file_dynamic_path) }\n    return MiniSnippets.expand({ match = false, insert = false })\n  ]])\n  local buf_id = get_buf()\n  eq(dyn_snippets, {\n    { prefix = 'dyn', body = 'Buf: ' .. buf_id, desc = 'Dynamic' },\n    { prefix = 'dynest', body = 'Buf (from nested): ' .. buf_id, desc = 'Dynamic nested' },\n  })\nend\n\nT['gen_loader']['from_file()']['does not cache if there were reading problems'] = function()\n  local temp_file = child.lua([[\n    local temp_file = vim.fn.tempname() .. '.lua'\n    _G.loader = MiniSnippets.gen_loader.from_file(temp_file)\n    return temp_file\n  ]])\n  MiniTest.finally(function() child.fn.delete(temp_file) end)\n\n  child.fn.writefile({ 'return 1' }, temp_file)\n  eq(child.lua_get('_G.loader()'), {})\n\n  child.fn.writefile({ 'return { { prefix = \"a\", body = \"A=$1\" } }' }, temp_file)\n  eq(child.lua_get('_G.loader()'), { { prefix = 'a', body = 'A=$1' } })\nend\n\nT['gen_loader']['from_file()']['forwards `opts` to `read_file()`'] = function()\n  child.fn.chdir(test_dir_absolute)\n  child.lua([[\n    local loader = MiniSnippets.gen_loader.from_file('file-array.lua', { cache = false, silent = true })\n    loader()\n  ]])\n\n  local full_path = child.fn.fnamemodify('file-array.lua', ':p')\n  eq(child.lua_get('_G.read_args_log'), { { full_path, { cache = false, silent = true } } })\nend\n\nT['gen_loader']['from_file()']['clears cache after `setup()`'] = function()\n  child.fn.chdir(test_dir_absolute)\n  child.lua([[_G.loader = MiniSnippets.gen_loader.from_file('file-array.lua')]])\n\n  child.lua('_G.loader()')\n  local read_args_log = child.lua_get('_G.read_args_log')\n  child.lua('MiniSnippets.setup()')\n  child.lua('_G.loader()')\n  eq(#child.lua_get('_G.read_args_log') > #read_args_log, true)\nend\n\nT['gen_loader']['from_file()']['validates input'] = function()\n  expect.error(function() child.lua('MiniSnippets.gen_loader.from_file(1)') end, '`path`.*string')\nend\n\nT['read_file()'] = new_set()\n\nlocal read_file = forward_lua('MiniSnippets.read_file')\n\nlocal validate_problems = function(path_pattern, problem_pattern, clean)\n  local log = child.lua_get('_G.notify_log')\n  eq(#log, 1)\n  local pattern = '%(mini%.snippets%) There were problems reading file.*'\n    .. path_pattern\n    .. '.*:\\n.*'\n    .. problem_pattern\n  expect.match(log[1][1], pattern)\n  expect.match(log[1][2], 'WARN')\n  if clean == nil or clean then child.lua('_G.notify_log = {}') end\nend\n\nT['read_file()']['works with dict-like content'] = function()\n  local validate = function(filename)\n    local ref = {\n      { prefix = 'lua_a', body = 'LUA_A=$1', desc = 'Desc LUA_A' },\n      { prefix = 'lua_b', body = 'LUA_B=$1', description = 'Desc LUA_B' },\n      -- Should try to use table fields as description\n      { prefix = nil, body = 'LUA_C=$1', desc = 'name_c' },\n      -- Should still return non-unique prefixes\n      { prefix = 'd', body = 'D1=$1', desc = 'dupl1' },\n      { prefix = 'd', body = nil, desc = 'Dupl2' },\n    }\n    local out = read_file(test_dir_absolute .. '/' .. filename)\n    eq(type(out), 'table')\n\n    -- - Order is not guaranteed (but usually it is alphabetical by fields)\n    local compare = function(a, b) return (a.desc or a.description or '') < (b.desc or b.description or '') end\n    table.sort(out, compare)\n    table.sort(ref, compare)\n    eq(out, ref)\n\n    -- - Order of problems is also not guaranteed\n    validate_problems(vim.pesc(filename), 'not a valid snippet data.*prefix = 1', false)\n    validate_problems(vim.pesc(filename), 'not a valid snippet data.*2')\n  end\n\n  validate('file-dict.lua')\n  validate('file-dict.json')\n  validate('file-dict.code-snippets')\nend\n\nT['read_file()']['works with array-like content'] = function()\n  local validate = function(filename)\n    local ref = {\n      { prefix = 'lua_a', body = 'LUA_A=$1', desc = 'Desc LUA_A' },\n      -- Should not infer desc-like fields as there is no dict name to infer from\n      { prefix = 'lua_b', body = 'LUA_B=$1', description = 'Desc LUA_B' },\n      { prefix = nil, body = 'LUA_C=$1' },\n      -- Should still return non-unique prefixes\n      { prefix = 'd', body = 'D1=$1' },\n      { prefix = 'd', body = nil, desc = 'Dupl2' },\n    }\n    -- Order of valid entries should be preserved\n    eq(read_file(test_dir_absolute .. '/' .. filename), ref)\n    validate_problems(vim.pesc(filename), 'not a valid snippet data.*prefix = 1.*not a valid snippet data.*2')\n  end\n\n  validate('file-array.lua')\n  validate('file-array.json')\n  validate('file-array.code-snippets')\nend\n\nT['read_file()']['works with function items'] = function()\n  child.lua('_G.file_dynamic_path = ' .. vim.inspect(test_dir_absolute .. '/file-dynamic-snippets.lua'))\n  local dyn_snippets = child.lua([[\n    MiniSnippets.config.snippets = {\n      function() return MiniSnippets.read_file(_G.file_dynamic_path) end\n    }\n    return MiniSnippets.expand({ match = false, insert = false })\n  ]])\n  local buf_id = get_buf()\n  eq(dyn_snippets, {\n    { prefix = 'dyn', body = 'Buf: ' .. buf_id, desc = 'Dynamic' },\n    { prefix = 'dynest', body = 'Buf (from nested): ' .. buf_id, desc = 'Dynamic nested' },\n  })\nend\n\nT['read_file()']['works with relative paths'] = function()\n  child.fn.chdir(test_dir_absolute)\n  eq(read_file('snippets/lua.json'), { { prefix = 'a', body = 'A=$1', desc = 'snippets/lua.json' } })\n\n  -- Should cache per full path\n  child.fn.chdir('subdir')\n  eq(read_file('snippets/lua.json'), { { prefix = 'c', body = 'C=$1', desc = 'subdir/snippets/lua.json' } })\nend\n\nT['read_file()']['works with paths starting with ~'] = function()\n  local path_tilde = child.fn.fnamemodify(test_dir_absolute .. '/snippets/lua.json', ':p:~')\n  if path_tilde:sub(1, 1) ~= '~' then return end\n  eq(read_file(path_tilde), { { prefix = 'a', body = 'A=$1', desc = 'snippets/lua.json' } })\nend\n\nT['read_file()']['correctly computes extension'] = function()\n  eq(read_file(test_dir_absolute .. '/file.many.dots.lua'), { { body = 'A=$1', prefix = 'a' } })\nend\n\nT['read_file()']['warns about problems during reading'] = function()\n  local validate = function(filename, problem_pattern)\n    -- Should return `nil` if there was a problem with reading\n    eq(read_file(test_dir_absolute .. '/' .. filename), vim.NIL)\n    validate_problems(vim.pesc(filename), problem_pattern)\n  end\n\n  validate('not-present', 'File is absent or not readable')\n  validate('file.notsupported', 'Extension is not supported')\n  validate('bad-file-cant-execute.lua', 'Could not execute Lua file')\n  validate('bad-file-not-table-return.lua', 'Returned object is not a table')\n  validate('bad-file-cant-decode.json', 'valid JSON.*invalid token')\n  validate('bad-file-not-dict-object.json', 'not a dictionary or array')\nend\n\nT['read_file()']['does not cache if there were reading problems'] = function()\n  local temp_file = child.fn.tempname() .. '.lua'\n  MiniTest.finally(function() child.fn.delete(temp_file) end)\n\n  child.fn.writefile({ 'return 1' }, temp_file)\n  eq(read_file(temp_file), vim.NIL)\n\n  child.fn.writefile({ 'return { { prefix = \"a\", body = \"A=$1\" } }' }, temp_file)\n  eq(read_file(temp_file), { { prefix = 'a', body = 'A=$1' } })\nend\n\nT['read_file()']['caches output'] = function()\n  child.lua([[\n    local dofile_orig, vim_json_decode_orig = dofile, vim.json.decode\n    _G.n = 0\n    _G.dofile = function(...) _G.n = _G.n + 1; return dofile_orig(...) end\n    vim.json.decode = function(...) _G.n = _G.n + 1; return vim_json_decode_orig(...) end\n  ]])\n\n  -- Use OS specific data for more robust testing\n  local test_dir_absolute_os = child.fn.fnamemodify(test_dir, ':p'):gsub('(.)[\\\\/]$', '%1')\n  local path_sep = helpers.is_windows() and '\\\\' or '/'\n\n  local results = {}\n  local validate = function(filename, ref_n)\n    local out = read_file(test_dir_absolute_os .. path_sep .. filename)\n    eq(child.lua_get('_G.n'), ref_n)\n    if results[filename] ~= nil then eq(results[filename], out) end\n    results[filename] = out\n  end\n\n  validate('file-dict.lua', 1)\n  validate('file-dict.lua', 1)\n  validate('file-dict.json', 2)\n  validate('file-dict.json', 2)\n  validate('file-dict.code-snippets', 3)\n  validate('file-dict.code-snippets', 3)\n  validate('file-array.lua', 4)\n  validate('file-array.lua', 4)\n  validate('file-array.json', 5)\n  validate('file-array.json', 5)\n  validate('file-array.code-snippets', 6)\n  validate('file-array.code-snippets', 6)\n\n  -- Should use full path as cache id\n  child.fn.chdir(test_dir_absolute_os)\n  eq(read_file('file-array.lua'), results['file-array.lua'])\n  eq(child.lua_get('_G.n'), 6)\n\n  -- Should return copy of cache entry\n  local res = child.lua([[\n    local out = MiniSnippets.read_file(\"file-array.lua\")\n    out[1].prefix = 'something else'\n    return MiniSnippets.read_file(\"file-array.lua\")[1].prefix ~= 'something else'\n  ]])\n  eq(res, true)\nend\n\nT['read_file()']['respects `opts.cache`'] = function()\n  child.lua([[\n    local dofile_orig, vim_json_decode_orig = dofile, vim.json.decode\n    _G.n = 0\n    _G.dofile = function(...) _G.n = _G.n + 1; return dofile_orig(...) end\n    vim.json.decode = function(...) _G.n = _G.n + 1; return vim_json_decode_orig(...) end\n  ]])\n\n  local validate = function(filename, ref_n)\n    read_file(test_dir_absolute .. '/' .. filename, { cache = false })\n    eq(child.lua_get('_G.n'), ref_n)\n  end\n\n  validate('file-dict.lua', 1)\n  validate('file-dict.lua', 2)\n  validate('file-dict.json', 3)\n  validate('file-dict.json', 4)\n  validate('file-dict.code-snippets', 5)\n  validate('file-dict.code-snippets', 6)\n  validate('file-array.lua', 7)\n  validate('file-array.lua', 8)\n  validate('file-array.json', 9)\n  validate('file-array.json', 10)\n  validate('file-array.code-snippets', 11)\n  validate('file-array.code-snippets', 12)\nend\n\nT['read_file()']['respects `opts.silent`'] = function()\n  -- Should not warn about any problems during reading\n  local read = function(filename) read_file(test_dir_absolute .. '/' .. filename, { silent = true }) end\n  read('file-array.lua')\n  read('not-present')\n  read('file.notsupported')\n  read('not-present')\n  read('file.notsupported')\n  read('bad-file-cant-execute.lua')\n  read('bad-file-not-table-return.lua')\n  read('bad-file-cant-decode.json')\n  read('bad-file-not-dict-object.json')\n\n  eq(child.lua_get('_G.notify_log'), {})\nend\n\nT['read_file()']['validates input'] = function()\n  expect.error(function() read_file(1) end, '`path`.*string')\nend\n\nT['default_prepare()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua([[\n        _G.loader_log = {}\n        _G.loader_1 = function(context)\n          table.insert(_G.loader_log, { 'loader_1', vim.deepcopy(context) })\n          return { prefix = 'l1', body = 'L1=$1' }\n        end\n        _G.loader_2 = function(context)\n          table.insert(_G.loader_log, { 'loader_2', vim.deepcopy(context) })\n          return { { prefix = 'l2_1', body = 'L2_1=$1' }, { prefix = 'l2_2', body = 'L2_2=$1' } }\n        end\n      ]])\n      child.bo.filetype = 'myft'\n    end,\n  },\n})\n\nlocal default_prepare = forward_lua('MiniSnippets.default_prepare')\n\nT['default_prepare()']['works'] = function()\n  local out = child.lua([[\n    local raw_snippets = {\n      { prefix = 'a', body = 'A=$1' },\n      { { prefix = 'aa', body = 'AA=$1' } },\n      { { { prefix = 'bbb', body = 'BBB=$1' }, { prefix = 'cCc', body = 'CCC=$1' } } },\n      { _G.loader_1 },\n      _G.loader_2,\n    }\n    return MiniSnippets.default_prepare(raw_snippets)\n  ]])\n\n  -- Should be ordered by prefix\n  --stylua: ignore\n  local ref = {\n    { prefix = 'a',    body = 'A=$1',    desc = 'A=$1' },\n    { prefix = 'aa',   body = 'AA=$1',   desc = 'AA=$1' },\n    { prefix = 'bbb',  body = 'BBB=$1',  desc = 'BBB=$1' },\n    { prefix = 'cCc',  body = 'CCC=$1',  desc = 'CCC=$1' },\n    { prefix = 'l1',   body = 'L1=$1',   desc = 'L1=$1' },\n    { prefix = 'l2_1', desc = 'L2_1=$1', body = 'L2_1=$1' },\n    { prefix = 'l2_2', body = 'L2_2=$1', desc = 'L2_2=$1' },\n  }\n  eq(out, ref)\n\n  -- Should call each loader once\n  local cur_buf = get_buf()\n  local ref_loader_log = {\n    { 'loader_1', { buf_id = cur_buf, lang = 'myft' } },\n    { 'loader_2', { buf_id = cur_buf, lang = 'myft' } },\n  }\n  eq(child.lua_get('_G.loader_log'), ref_loader_log)\nend\n\nT['default_prepare()']['works with tricky loaders'] = function()\n  local out = child.lua([[\n    _G.loader_nested = function(context)\n      table.insert(_G.loader_log, { 'loader_nested', vim.deepcopy(context) })\n      return { { _G.loader_1 }, _G.loader_2 }\n    end\n    return MiniSnippets.default_prepare({ _G.loader_nested })\n  ]])\n  --stylua: ignore\n  local ref = {\n    { prefix = 'l1',   body = 'L1=$1',   desc = 'L1=$1' },\n    { prefix = 'l2_1', desc = 'L2_1=$1', body = 'L2_1=$1' },\n    { prefix = 'l2_2', body = 'L2_2=$1', desc = 'L2_2=$1' },\n  }\n  eq(out, ref)\n\n  local cur_buf = get_buf()\n  local ref_loader_log = {\n    { 'loader_nested', { buf_id = cur_buf, lang = 'myft' } },\n    { 'loader_1', { buf_id = cur_buf, lang = 'myft' } },\n    { 'loader_2', { buf_id = cur_buf, lang = 'myft' } },\n  }\n  eq(child.lua_get('_G.loader_log'), ref_loader_log)\nend\n\nT['default_prepare()']['silently ignores bad entries'] = function()\n  local out = default_prepare({ {}, { prefix = 'a', body = 'a=$1' }, 1, { true } })\n  eq(out, { { prefix = 'a', body = 'a=$1', desc = 'a=$1' } })\nend\n\nT['default_prepare()']['properly normalizes snippets'] = function()\n  -- Only unique non-empty prefixes should be present and resolved in order\n  -- they are traversed (latest wins in full, not by parts)\n  local out = child.lua_get([[\n    MiniSnippets.default_prepare({\n      { prefix = 'a', body = 'a1=$1', desc = 'Desc a1' },\n      { prefix = 'b', body = 'b1=$1', desc = 'Desc b1' },\n      function() return { prefix = 'a', body = 'a2=$1', desc = 'Desc a2' } end,\n      { { prefix = 'b', body = 'b2=$1' } },\n    })\n  ]])\n  eq(out, { { prefix = 'a', body = 'a2=$1', desc = 'Desc a2' }, { prefix = 'b', body = 'b2=$1', desc = 'b2=$1' } })\n\n  -- Ensures prefix/body/desc strings: array prefix adds snippet for every\n  -- prefix, array body and desc get concatenated with \"\\n\"\n  local raw_snippets = {\n    { prefix = { 'd', 'c' }, body = { 'multi', 'line' }, desc = { 'also', 'multi', 'line' } },\n    { prefix = { 'a', 'b' }, body = { 'single line' }, description = { 'also single line' } },\n    { prefix = 'x', body = { 'aaaaa', 'bbbb' } },\n  }\n  eq(default_prepare(raw_snippets), {\n    { prefix = 'a', body = 'single line', desc = 'also single line' },\n    { prefix = 'b', body = 'single line', desc = 'also single line' },\n    { prefix = 'c', body = 'multi\\nline', desc = 'also\\nmulti\\nline' },\n    { prefix = 'd', body = 'multi\\nline', desc = 'also\\nmulti\\nline' },\n    { prefix = 'x', body = 'aaaaa\\nbbbb', desc = 'aaaaa\\nbbbb' },\n  })\n\n  -- Absent prefix/body/desc: prefix should be inferred as empty and all added,\n  -- absent body should remove snippet with its prefix, absent desc should be\n  -- inferred as body.\n  raw_snippets = {\n    -- Absent prefix should be inferred as empty and every added\n    { prefix = nil, body = 'a2=$1', desc = 'Desc a2' },\n    { prefix = nil, body = 'a3=$1', desc = 'Desc a3' },\n    { prefix = nil, body = 'a1=$1', desc = 'Desc a1' },\n    -- Absent body should remove snippet with its prefix\n    { prefix = 'b', body = 'b=$1', desc = 'Desc b' },\n    { prefix = 'b', body = nil, desc = 'Desc no matter' },\n    -- Absent desc should be inferred desc>description>body\n    { prefix = 'c1', body = 'c1=$1', description = 'Description' },\n    { prefix = 'c2', body = 'c2=$1' },\n    -- Absent prefix and body should not matter\n    { prefix = nil, body = nil, desc = 'No matter' },\n  }\n  eq(default_prepare(raw_snippets), {\n    { prefix = '', body = 'a2=$1', desc = 'Desc a2' },\n    { prefix = '', body = 'a3=$1', desc = 'Desc a3' },\n    { prefix = '', body = 'a1=$1', desc = 'Desc a1' },\n    -- No 'b' prefix, as it was removed\n    { prefix = 'c1', body = 'c1=$1', desc = 'Description' },\n    { prefix = 'c2', body = 'c2=$1', desc = 'c2=$1' },\n  })\nend\n\nT['default_prepare()']['uses proper default context'] = function()\n  local validate_context = function(ref_context)\n    local out = child.lua_get('select(2, MiniSnippets.default_prepare({}))')\n    eq(out, ref_context)\n  end\n\n  local cur_buf = get_buf()\n\n  -- By default should use buffer's filetype\n  child.bo.filetype = 'myft'\n  validate_context({ buf_id = cur_buf, lang = 'myft' })\n\n  -- With present tree-sitter should use local parser lanuage\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Testing on Neovim>=0.10 is easier with built-in parsers') end\n\n  child.bo.filetype = 'vim'\n  child.lua('vim.treesitter.start()')\n  set_lines({\n    'set background=dark',\n    'lua << EOF',\n    'print(1)',\n    'vim.api.nvim_exec2([[',\n    '    set background=light',\n    ']])',\n    'EOF',\n  })\n  child.cmd('startinsert')\n  set_cursor(1, 0)\n  validate_context({ buf_id = cur_buf, lang = 'vim' })\n  set_cursor(3, 0)\n  validate_context({ buf_id = cur_buf, lang = 'lua' })\n  set_cursor(5, 0)\n  validate_context({ buf_id = cur_buf, lang = 'vim' })\nend\n\nT['default_prepare()']['respects `opts.context`'] = function()\n  local validate = function(context)\n    child.lua('_G.context = ' .. vim.inspect(context))\n    child.lua([[\n      MiniSnippets.default_prepare({ _G.loader_1, _G.loader_2 }, { context = _G.context })\n    ]])\n    eq(child.lua_get('_G.loader_log'), { { 'loader_1', context }, { 'loader_2', context } })\n    child.lua('_G.loader_log = {}')\n  end\n\n  validate({ buf_id = get_buf() })\n  validate({})\n  validate(1)\n  validate(true)\nend\n\nT['default_prepare()']['validates input'] = function()\n  expect.error(function() default_prepare(1) end, '`raw_snippets`.*array')\nend\n\nT['default_match()'] = new_set()\n\nlocal default_match = forward_lua('MiniSnippets.default_match')\n\n--stylua: ignore\nT['default_match()']['works with exact match'] = function()\n  local snippets = {\n    { prefix = 'a', body = 'a1=$1' },\n    { prefix = 'aa', body = 'A1=$1', desc = 'Ends as other prefix' },\n    { prefix = '_t', body = '_1=$1' },\n    { prefix = ' t', body = ' 1=$1' },\n    { prefix = 't_', body = 'T1=$1' },\n    { prefix = 't ', body = 't1=$1' },\n    -- Should ignore empty and absent prefixes\n    { prefix = '', body = '$1', desc = 'Empty prefix' },\n    { body = '$1$2', desc = 'No prefix' },\n  }\n\n  local validate = function(keys, snip_id, ref_region)\n    type_keys(keys)\n    local ref = vim.deepcopy(snippets[snip_id])\n    if ref ~= nil then ref.region = ref_region end\n    eq(default_match(snippets), { ref })\n    ensure_clean_state()\n  end\n\n  validate({ 'i', 'a' }, 1, { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } })\n\n  -- In different line positions\n  validate({ 'i', 'xx a x', '<Left><Left>' }, 1, { from = { line = 1, col = 4 }, to = { line = 1, col = 4 } })\n  validate({ 'i', 'a x',    '<Left><Left>' }, 1, { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } })\n\n  -- Not in first line\n  validate({ 'i', 'x<CR>a' },          1, { from = { line = 2, col = 1 }, to = { line = 2, col = 1 } })\n  validate({ 'i', 'x<CR>a<CR>x<Up>' }, 1, { from = { line = 2, col = 1 }, to = { line = 2, col = 1 } })\n\n  -- Should match the widest exact match\n  validate({ 'i', 'aa' },  2, { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } })\n  validate({ 'i', ' aa' }, 2, { from = { line = 1, col = 2 }, to = { line = 1, col = 3 } })\n\n  -- Should only use part to the left of cursor\n  validate({ 'i', 'aa', '<Left>' }, 1, { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } })\n\n  -- Should ignore exact match if it is not after whitespace or punctuation\n  validate({ 'i', 'ba' }, nil)\n  validate({ 'i', 'baa' }, nil)\n\n  -- Should match regardless of prefix (even if starts/ends with space/punct)\n  validate({ 'i', '_t' }, 3, { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } })\n  validate({ 'i', ' t' }, 4, { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } })\n  validate({ 'i', 't_' }, 5, { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } })\n  validate({ 'i', 't ' }, 6, { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } })\n\n  validate({ 'i', ' _t' }, 3, { from = { line = 1, col = 2 }, to = { line = 1, col = 3 } })\n  validate({ 'i', '  t' }, 4, { from = { line = 1, col = 2 }, to = { line = 1, col = 3 } })\n\n  -- Should work in Normal mode and include character under cursor\n  validate({'i', 'aa', '<Esc>', '$'}, 2, { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } })\nend\n\nT['default_match()']['works with fuzzy match'] = function()\n  local snippets = {\n    { prefix = 'a_bc', body = 'a_bc=$1', desc = 'Should preserve' },\n    { prefix = 'axbc', body = 'axbc=$1' },\n    { prefix = 'xabc', body = 'xabc=$1' },\n    -- Should ignore empty and absent prefixes\n    { prefix = '', body = '$1', desc = 'Empty prefix' },\n    { body = '$1$2', desc = 'No prefix' },\n  }\n\n  local validate = function(keys, snip_ids, ref_region)\n    type_keys(keys)\n    local ref_arr = vim.tbl_map(function(id)\n      local res = vim.deepcopy(snippets[id])\n      res.region = ref_region\n      return res\n    end, snip_ids)\n    eq(default_match(snippets), ref_arr)\n    ensure_clean_state()\n  end\n\n  -- Should return from best to worst fuzzy matches\n  local ref_region = { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } }\n  validate({ 'i', 'x' }, { 3, 2 }, ref_region)\n\n  ref_region = { from = { line = 1, col = 1 }, to = { line = 1, col = 2 } }\n  validate({ 'i', 'xb' }, { 2, 3 }, ref_region)\n\n  -- Should only use part to the left of cursor\n  ref_region = { from = { line = 1, col = 1 }, to = { line = 1, col = 1 } }\n  validate({ 'i', 'xb', '<Left>' }, { 3, 2 }, ref_region)\n\n  -- Should compute base as widest non-whitespace characters\n  ref_region = { from = { line = 1, col = 2 }, to = { line = 1, col = 3 } }\n  validate({ 'i', ' xb' }, { 2, 3 }, ref_region)\n  validate({ 'i', '\\txb' }, { 2, 3 }, ref_region)\n\n  validate({ 'i', 'xxb' }, {}, nil)\n  validate({ 'i', 'b_' }, {}, nil)\n\n  -- Should not return \"connected\" regions (to not be modifiable in place)\n  type_keys('i', 'ab')\n  local res = child.lua([[\n    local snippets = { { prefix = 'axb', body = 'axb=$1' }, { prefix = 'axxb', body = 'axxb=$1' } }\n    local matches = MiniSnippets.default_match(snippets)\n    matches[1].region.from.line = matches[1].region.from.line + 1\n    return matches[1].region.from.line ~= matches[2].region.from.line\n  ]])\n  eq(res, true)\n  ensure_clean_state()\nend\n\nT['default_match()']['works in special cases'] = function()\n  local snippets = { { prefix = 'ab', body = 'ab=$1' }, { prefix = 'axb', body = 'axb=$1' } }\n\n  -- Should return all input snippets if no exact and empty base\n  type_keys('i')\n  eq(default_match(snippets), snippets)\n  type_keys(' ')\n  eq(default_match(snippets), snippets)\n  type_keys('\\t')\n  eq(default_match(snippets), snippets)\n\n  -- Should work with empty array\n  eq(default_match({}), {})\nend\n\nT['default_match()']['does not return fuzzy matches if there is exact match'] = function()\n  local snippets = { { prefix = 'ab', body = 'ab=$1' }, { prefix = 'axb', body = 'axb=$1' } }\n  type_keys('i', 'ab')\n  eq(\n    default_match(snippets),\n    { { prefix = 'ab', body = 'ab=$1', region = { from = { col = 1, line = 1 }, to = { col = 2, line = 1 } } } }\n  )\nend\n\nT['default_match()']['does not modify input snippets'] = function()\n  type_keys('i', 'ab')\n  local res_exact = child.lua([[\n    local snippets = { { prefix = 'ab', body = 'ab=$1' } }\n    local matches = MiniSnippets.default_match(snippets)\n    return { matches_have_region = matches[1].region ~= nil, orig_no_region = snippets[1].region == nil }\n  ]])\n  eq(res_exact, { matches_have_region = true, orig_no_region = true })\n  ensure_clean_state()\n\n  type_keys('i', 'ab')\n  local res_fuzzy = child.lua([[\n    local snippets = { { prefix = 'axb', body = 'axb=$1' } }\n    local matches = MiniSnippets.default_match(snippets)\n    return { matches_have_region = matches[1].region ~= nil, orig_no_region = snippets[1].region == nil }\n  ]])\n  eq(res_fuzzy, { matches_have_region = true, orig_no_region = true })\nend\n\nT['default_match()']['respects `opts.pattern_exact_boundary`'] = function()\n  local snippets = { { prefix = 'a', body = 'a=$1' }, { prefix = 'ab', body = 'ab=$1' } }\n\n  type_keys('i', '_a')\n  -- - No matches as '_' is not whitespace and '_a' is used as fuzzy match base\n  eq(#default_match(snippets, { pattern_exact_boundary = '%s?' }), 0)\n  ensure_clean_state()\n\n  -- Should match pattern against empty string at line start\n  type_keys('i', 'a')\n  -- - There are two matches because they both are fuzzy, i.e. no exact match\n  eq(#default_match(snippets, { pattern_exact_boundary = '%s' }), 2)\nend\n\nT['default_match()']['respects `opts.pattern_fuzzy`'] = function()\n  local snippets = { { prefix = 'ab', body = 'ab=$1' }, { prefix = 'xx', body = 'xx=$1' } }\n\n  type_keys('i', '_a')\n  eq(#default_match(snippets), 0)\n  eq(#default_match(snippets, { pattern_fuzzy = '%w*' }), 1)\n  ensure_clean_state()\n\n  -- Fuzzy matching empty string should return all snippets\n  type_keys('i', 'a')\n  eq(#default_match(snippets), 1)\n  eq(#default_match(snippets, { pattern_fuzzy = '[^a]*' }), 2)\n  ensure_clean_state()\n\n  -- Empty string can be used to not do fuzzy matching\n  type_keys('i', 'a')\n  eq(#default_match(snippets), 1)\n  eq(#default_match(snippets, { pattern_fuzzy = '' }), 0)\nend\n\nT['default_match()']['validates input'] = function()\n  local validate = function(err_pattern, ...)\n    local args = { ... }\n    expect.error(function() default_match(unpack(args)) end, err_pattern)\n  end\n  validate('`snippets`.*array', 1)\n  validate('`snippets`.*snippets', { 1 })\n  validate('`snippets`.*snippets', { { body = 1 } })\n  validate('`snippets`.*snippets', { { body = 'T1=$1', prefix = 1 } })\n  validate('`snippets`.*snippets', { { body = 'T1=$1', desc = 1 } })\n  validate('`snippets`.*snippets', { { body = 'T1=$1', region = 1 } })\n\n  validate('`opts.pattern_exact_boundary`.*string', { { body = 'T1=$1' } }, { pattern_exact_boundary = 1 })\n  validate('`opts.pattern_fuzzy`.*string', { { body = 'T1=$1' } }, { pattern_fuzzy = 1 })\nend\n\nT['default_select()'] = new_set()\n\nlocal default_select = forward_lua('MiniSnippets.default_select')\n\nT['default_select()']['works'] = function()\n  -- Should stop early for empty array of snippets\n  default_select({})\n  eq(child.lua_get('_G.notify_log'), { { '(mini.snippets) No snippets to select from', 'WARN' } })\n\n  -- By default should insert a single snippet\n  default_select({ { body = 'T1=$1 T0=$0' } })\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n  validate_active_session()\n  ensure_clean_state()\n\n  -- Should call `vim.ui.select` for more than one snippets\n  set_lines({ 'abc' })\n  local region = { from = { line = 1, col = 1 }, to = { line = 1, col = 3 } }\n  mock_select(2)\n  local snippets = {\n    { prefix = 'T', body = 'T1=$1 T0=$0' },\n    { body = 'U1=$1 U0=$0', desc = 'U snippet', region = region },\n    { prefix = 'xxx', body = 'X1=$1 X0=$0', description = 'X snippet' },\n  }\n  default_select(snippets)\n  validate_state('i', { 'U1= U0=' }, { 1, 3 })\n  validate_active_session()\n  eq(child.lua_get('_G.select_args'), {\n    items = snippets,\n    items_formatted = {\n      'T           │ <No description>',\n      '<No prefix> │ U snippet',\n      'xxx         │ X snippet',\n    },\n    prompt = 'Snippets',\n  })\nend\n\nT['default_select()']['respects multibyte characters during formatting'] = function()\n  mock_select(2)\n  default_select({\n    { prefix = 'ыыы', body = 'Ы1=$1 Ы0=$0', desc = 'Ы snippet' },\n    { prefix = 'uuu', body = 'U1=$1 U0=$0', desc = 'U snippet' },\n  })\n  eq(child.lua_get('_G.select_args.items_formatted'), { 'ыыы │ Ы snippet', 'uuu │ U snippet' })\nend\n\nT['default_select()']['respects `insert`'] = function()\n  mock_select(2)\n  child.lua([[\n    _G.my_insert = function(...) _G.args = { ... } end\n    local snippets = { { body = 'T1=$1 T0=$0' }, { body = 'T1=$1 T0=$0' } }\n    MiniSnippets.default_select(snippets, my_insert)\n  ]])\n  eq(child.lua_get('_G.args'), { { body = 'T1=$1 T0=$0' } })\nend\n\nT['default_select()']['respects `opts.insert_single`'] = function()\n  child.lua('vim.ui.select = function(items) _G.items = items end')\n  child.lua([[MiniSnippets.default_select({ { body = 'T1=$1 T0=$0' } }, nil, { insert_single = false })]])\n  -- Should still call `vim.ui.select()` even with single item array input\n  eq(child.lua_get('_G.items'), { { body = 'T1=$1 T0=$0' } })\nend\n\nT['default_select()']['validates input'] = function()\n  expect.error(function() default_select(1) end, '`snippets`.*array')\n  expect.error(function() default_select({ 1 }) end, '`snippets`.*snippets')\n  expect.error(function() default_select({ { body = 1 } }) end, '`snippets`.*snippets')\n  expect.error(function() default_select({ { body = 'T1=$1 T0=$0', prefix = 1 } }) end, '`snippets`.*snippets')\n  expect.error(function() default_select({ { body = 'T1=$1 T0=$0', desc = 1 } }) end, '`snippets`.*snippets')\n  expect.error(function() default_select({ { body = 'T1=$1 T0=$0', region = 1 } }) end, '`snippets`.*snippets')\n  expect.error(function() default_select({ { body = 'T1=$1 T0=$0' } }, 1) end, '`insert`.*callable')\nend\n\nT['default_insert()'] = new_set()\n\nlocal default_insert = forward_lua('MiniSnippets.default_insert')\n\nT['default_insert()']['works'] = function()\n  -- Just text\n  child.cmd('startinsert')\n  default_insert({ body = 'Text' })\n  validate_state('i', { 'Text' }, { 1, 4 })\n  validate_no_active_session()\n  ensure_clean_state()\n\n  -- With tabstops (should start active session)\n  child.cmd('startinsert')\n  default_insert({ body = 'T1=$1 T2=$2' })\n  validate_state('i', { 'T1= T2=' }, { 1, 3 })\n  validate_active_session()\n  jump('next')\n  validate_state('i', { 'T1= T2=' }, { 1, 7 })\n  ensure_clean_state()\n\n  -- Should allow array of strings as body\n  child.cmd('startinsert')\n  default_insert({ body = { 'T1=$1', 'T0=$0' } })\n  validate_state('i', { 'T1=', 'T0=' }, { 1, 3 })\nend\n\nT['default_insert()']['ensures Insert mode in current buffer'] = function()\n  -- Normal mode\n  default_insert({ body = 'Text' })\n  validate_state('i', { 'Text' }, { 1, 4 })\n  ensure_clean_state()\n\n  default_insert({ body = 'T1=$1' })\n  validate_state('i', { 'T1=' }, { 1, 3 })\n  validate_active_session()\n  ensure_clean_state()\n\n  -- Visual mode\n  type_keys('v')\n  eq(child.fn.mode(), 'v')\n  default_insert({ body = 'T1=$1 T2=$2' })\n  validate_state('i', { 'T1= T2=' }, { 1, 3 })\n  ensure_clean_state()\n\n  -- Command-line mode\n  type_keys(':')\n  eq(child.fn.mode(), 'c')\n  default_insert({ body = 'T1=$1' })\n  validate_state('i', { 'T1=' }, { 1, 3 })\nend\n\nT['default_insert()']['deletes snippet region'] = function()\n  local validate = function(mode, col_from, col_to, ref_line, ref_cursor)\n    if mode == 'i' then type_keys('i') end\n    set_lines({ 'abcd' })\n    local region = { from = { line = 1, col = col_from }, to = { line = 1, col = col_to } }\n    default_insert({ body = 'T1=$1', region = region })\n    validate_state('i', { ref_line }, ref_cursor)\n\n    ensure_clean_state()\n  end\n\n  validate('i', 1, 1, 'T1=bcd', { 1, 3 })\n  validate('i', 1, 2, 'T1=cd', { 1, 3 })\n  validate('i', 2, 2, 'aT1=cd', { 1, 4 })\n  validate('i', 2, 3, 'aT1=d', { 1, 4 })\n  validate('i', 3, 3, 'abT1=d', { 1, 5 })\n  validate('i', 3, 4, 'abT1=', { 1, 5 })\n\n  validate('n', 1, 1, 'T1=bcd', { 1, 3 })\n  validate('n', 1, 2, 'T1=cd', { 1, 3 })\n  validate('n', 2, 2, 'aT1=cd', { 1, 4 })\n  validate('n', 2, 3, 'aT1=d', { 1, 4 })\n  validate('n', 3, 3, 'abT1=d', { 1, 5 })\n  validate('n', 3, 4, 'abT1=', { 1, 5 })\nend\n\nT['default_insert()']['can be used to create nested session'] = function()\n  default_insert({ body = 'T1=$1' })\n  validate_n_sessions(1)\n  validate_state('i', { 'T1=' }, { 1, 3 })\n\n  default_insert({ body = 'T2=$2' })\n  validate_n_sessions(2)\n  validate_state('i', { 'T1=T2=' }, { 1, 6 })\nend\n\nT['default_insert()']['indent'] = new_set()\n\nT['default_insert()']['indent']['is added on every new line'] = function()\n  type_keys('i', ' \\t')\n  default_insert({ body = 'multi\\n  line\\n\\ttext\\n' })\n  validate_state('i', { ' \\tmulti', ' \\t  line', ' \\t\\ttext', ' \\t' }, { 4, 2 })\n  ensure_clean_state()\n\n  type_keys('i', ' ')\n  default_insert({ body = 'T1=$1\\nT0=$0' })\n  validate_state('i', { ' T1=', ' T0=' }, { 1, 4 })\n  ensure_clean_state()\n\n  -- Should use line's indent (even if inserted not next to whitespace)\n  type_keys('i', ' \\txxx \\t')\n  default_insert({ body = 'multi\\nline\\n' })\n  validate_state('i', { ' \\txxx \\tmulti', ' \\tline', ' \\t' }, { 3, 2 })\n  ensure_clean_state()\n\n  -- Inserting in Normal mode is the same as pressing `i` beforehand\n  type_keys('i', '   ', '<Esc>')\n  default_insert({ body = 'multi\\nline' })\n  validate_state('i', { '  multi', '  line ' }, { 2, 6 })\nend\n\n--stylua: ignore\nT['default_insert()']['indent']['works inside comments'] = function()\n  local validate = function(cur_line, lines_after)\n    set_lines({ cur_line })\n    type_keys('A')\n    default_insert({ body = 'multi\\nline\\n text\\n' })\n    eq(get_lines(), lines_after)\n    ensure_clean_state()\n  end\n\n  -- Indent with comment under 'commentstring'\n  child.o.commentstring = '# %s'\n\n  validate('#',     { '#multi',     '#line',     '# text',     '#' })\n  validate('# ',    { '# multi',    '# line',    '#  text',    '# ' })\n  validate('#\\t',   { '#\\tmulti',   '#\\tline',   '#\\t text',   '#\\t' })\n  validate(' # ',   { ' # multi',   ' # line',   ' #  text',   ' # ' })\n  validate('\\t# ',  { '\\t# multi',  '\\t# line',  '\\t#  text',  '\\t# ' })\n  validate('\\t#\\t', { '\\t#\\tmulti', '\\t#\\tline', '\\t#\\t text', '\\t#\\t' })\n\n  validate('#xx',      { '#xxmulti',      '#line',     '# text',     '#' })\n  validate(' # xx ',   { ' # xx multi',   ' # line',   ' #  text',   ' # ' })\n  validate('\\t#\\txx ', { '\\t#\\txx multi', '\\t#\\tline', '\\t#\\t text', '\\t#\\t' })\n\n  -- Indent with comment under 'comments' parts\n  child.bo.comments = ':---,:--'\n\n  validate('--',     { '--multi',     '--line',     '-- text',     '--' })\n  validate('-- ',    { '-- multi',    '-- line',    '--  text',    '-- ' })\n  validate('--\\t',   { '--\\tmulti',   '--\\tline',   '--\\t text',   '--\\t' })\n  validate(' -- ',   { ' -- multi',   ' -- line',   ' --  text',   ' -- ' })\n  validate('\\t-- ',  { '\\t-- multi',  '\\t-- line',  '\\t--  text',  '\\t-- ' })\n  validate('\\t--\\t', { '\\t--\\tmulti', '\\t--\\tline', '\\t--\\t text', '\\t--\\t' })\n\n  validate('--xx',     { '--xxmulti',     '--line',     '-- text',     '--' })\n  validate(' -- xx',   { ' -- xxmulti',   ' -- line',   ' --  text',   ' -- ' })\n  validate('\\t--\\txx', { '\\t--\\txxmulti', '\\t--\\tline', '\\t--\\t text', '\\t--\\t' })\n\n  -- Should respect `b` flag (leader should be followed by space/tab/EOL)\n  child.bo.comments = 'b:*'\n  validate('*',   { '*multi',   'line',   ' text',   '' })\n  validate(' *',  { ' *multi',  ' line',  '  text',  ' ' })\n  validate('\\t*', { '\\t*multi', '\\tline', '\\t text', '\\t' })\n\n  validate('* ',    { '* multi',    '* line',    '*  text',    '* ' })\n  validate('*\\t',   { '*\\tmulti',   '*\\tline',   '*\\t text',   '*\\t' })\n  validate(' * ',   { ' * multi',   ' * line',   ' *  text',   ' * ' })\n  validate('\\t*\\t', { '\\t*\\tmulti', '\\t*\\tline', '\\t*\\t text', '\\t*\\t' })\n\n  validate('* xx',  { '* xxmulti',  '* line',  '*  text',  '* ' })\n  validate('*\\txx', { '*\\txxmulti', '*\\tline', '*\\t text', '*\\t' })\n\n  -- Should respect `f` flag (only first line should have it)\n  child.bo.comments = 'f:-'\n  validate('-',   { '-multi',   'line',   ' text',   '' })\n  validate(' -',  { ' -multi',  ' line',  '  text',  ' ' })\n  validate('\\t-', { '\\t-multi', '\\tline', '\\t text', '\\t' })\n\n  validate(' - ',   { ' - multi',   ' line',  '  text',  ' ' })\n  validate('\\t-\\t', { '\\t-\\tmulti', '\\tline', '\\t text', '\\t' })\nend\n\nT['default_insert()']['indent']['computes \"indent at cursor\"'] = function()\n  type_keys('i', '   ', '<Left>')\n  eq(get_cursor(), { 1, 2 })\n  default_insert({ body = 'multi\\nline' })\n  validate_state('i', { '  multi', '  line ' }, { 2, 6 })\n  ensure_clean_state()\n\n  child.o.commentstring = '--%s'\n  type_keys('i', ' --', '<Left>')\n  eq(get_cursor(), { 1, 2 })\n  default_insert({ body = 'multi\\nline' })\n  -- `--` is not treated as part of indent because cursor is inside of it\n  validate_state('i', { ' -multi', ' line-' }, { 2, 5 })\nend\n\nT['default_insert()']['indent']['respects manual lookup entries'] = function()\n  type_keys('i', ' \\t')\n  local lookup = { ['1'] = 'tab\\nstop', AAA = 'aaa\\nbbb' }\n  default_insert({ body = 'T1=$1\\nAAA=$AAA' }, { lookup = lookup })\n  validate_state('i', { ' \\tT1=tab', ' \\tstop', ' \\tAAA=aaa', ' \\tbbb' }, { 2, 6 })\nend\n\nT['default_insert()']['indent']['preserves relative indent in variables'] = function()\n  child.fn.setenv('AA', 'aa\\nbb\\n\\tcc')\n  child.fn.setenv('BB', 'bb\\n')\n\n  local validate = function(body, ref_lines)\n    default_insert({ body = body })\n    validate_state('i', ref_lines, nil)\n    ensure_clean_state()\n  end\n\n  validate('  $AA', { '  aa', '  bb', '  \\tcc' })\n  validate('\\t$AA', { '\\taa', '\\tbb', '\\t\\tcc' })\n  validate('  $BB', { '  bb', '  ' })\n  validate('text\\n  $AA', { 'text', '  aa', '  bb', '  \\tcc' })\n\n  validate('$AA\\n\\t$AA', { 'aa', 'bb', '\\tcc', '\\taa', '\\tbb', '\\t\\tcc' })\n  validate('\\t$AA\\n$AA', { '\\taa', '\\tbb', '\\t\\tcc', 'aa', 'bb', '\\tcc' })\n\n  validate('  ${XX:$AA}', { '  aa', '  bb', '  \\tcc' })\n  validate('${XX:  $AA}', { '  aa', '  bb', '  \\tcc' })\n  validate('${XX:  ${UU:\\t$AA}}', { '  \\taa', '  \\tbb', '  \\t\\tcc' })\n  validate('  ${1:$AA}', { '  aa', '  bb', '  \\tcc' })\n\n  -- Should respect values of previously inserted dynamic text\n  child.fn.setenv('XX', 'xx\\n  ')\n  validate('$XX$AA', { 'xx', '  aa', '  bb', '  \\tcc' })\n  validate('$XX\\t$AA', { 'xx', '  \\taa', '  \\tbb', '  \\t\\tcc' })\n\n  -- Should also work with comments\n  child.bo.commentstring = '# %s'\n  type_keys('i', '#  ')\n  validate('$BB$AA', { '#  bb', '#  aa', '#  bb', '#  \\tcc' })\n\n  validate('$AA\\n# $AA', { 'aa', 'bb', '\\tcc', '# aa', '# bb', '# \\tcc' })\n\n  -- As there is no indent \"inside snippet body\", AA is not reindented\n  -- This might be not a good behavior, but fix seems complicated\n  validate('  $BB$AA', { '  bb', '  aa', 'bb', '\\tcc' })\n\n  -- Should work with decreasing indent in variable lines\n  child.fn.setenv('YY', '  xx\\nyy')\n  validate('\\t$YY', { '\\t  xx', '\\tyy' })\n\n  -- Should work with 'expandtab'\n  child.bo.expandtab, child.bo.shiftwidth = true, 2\n  validate('\\t$AA', { '  aa', '  bb', '    cc' })\nend\n\nT['default_insert()']['indent']['preserves relative indent in looked up tabstop text'] = function()\n  local validate = function(body, tabstop_text, ref_lines)\n    default_insert({ body = body }, { lookup = { ['1'] = tabstop_text } })\n    validate_state('i', ref_lines, nil)\n    ensure_clean_state()\n  end\n\n  validate('  $1', 'aa\\nbb', { '  aa', '  bb' })\n  validate('\\t$1', 'aa\\nbb', { '\\taa', '\\tbb' })\n  validate('text\\n  $1', 'aa\\nbb', { 'text', '  aa', '  bb' })\n\n  validate('  $1', '  aa\\nbb', { '    aa', '  bb' })\n  validate('  $1', 'aa\\n  bb', { '  aa', '    bb' })\n\n  -- Should work with linked tabstops\n  validate('$1\\n\\t$1', 'aa\\nbb', { 'aa', 'bb', '\\taa', '\\tbb' })\n  validate('\\t$1\\n$1', 'aa\\nbb', { '\\taa', '\\tbb', 'aa', 'bb' })\n\n  validate('$1\\n${2:\\t$1}', 'aa\\nbb', { 'aa', 'bb', '\\taa', '\\tbb' })\n  validate('$1\\n\\t${2:$1}', 'aa\\nbb', { 'aa', 'bb', '\\taa', '\\tbb' })\n\n  -- Should work with variables\n  child.fn.setenv('XX', 'xx\\n  ')\n  validate('$XX$1', 'aa\\nbb', { 'xx', '  aa', '  bb' })\n\n  -- Should work in placeholders\n  validate('${2:  $1}', 'aa\\nbb', { '  aa', '  bb' })\n  validate('${AA:  $1}', 'aa\\nbb', { '  aa', '  bb' })\n\n  -- Should also work with comments\n  child.bo.commentstring = '# %s'\n  type_keys('i', '#  ')\n  validate('$1', 'aa\\nbb', { '#  aa', '#  bb' })\n\n  validate('$1\\n# $1', 'aa\\nbb', { 'aa', 'bb', '# aa', '# bb' })\n\n  -- Should work with 'expandtab'\n  child.bo.expandtab, child.bo.shiftwidth = true, 2\n  validate('\\t$1', 'aa\\nbb', { '  aa', '  bb' })\n  validate('\\t$1', 'aa\\n\\tbb', { '  aa', '    bb' })\n  child.bo.expandtab = false\nend\n\nT['default_insert()']['triggers start/stop events'] = function()\n  local make_ref_data = function(snippet_body)\n    return { session = { insert_args = { snippet = { body = snippet_body } } } }\n  end\n  setup_event_log()\n  local body, cur_buf = 'T1=$1 T0=0', get_buf()\n\n  default_insert({ body = body })\n  eq_partial_tbl(get_au_log(), { { event = 'MiniSnippetsSessionStart', data = make_ref_data(body), buf_id = cur_buf } })\n  clean_au_log()\n\n  stop()\n  eq_partial_tbl(get_au_log(), { { event = 'MiniSnippetsSessionStop', data = make_ref_data(body), buf_id = cur_buf } })\nend\n\nT['default_insert()']['respects tab-related options'] = function()\n  child.bo.expandtab = true\n  child.bo.shiftwidth = 3\n  default_insert({ body = '\\tT1=$1\\n\\t\\tT0=$0' })\n  validate_state('i', { '   T1=', '      T0=' }, { 1, 6 })\n  ensure_clean_state()\n\n  child.bo.shiftwidth, child.bo.tabstop = 0, 2\n  default_insert({ body = '\\ttext\\t\\t' })\n  validate_state('i', { '  text    ' }, { 1, 10 })\n  ensure_clean_state()\n\n  child.bo.expandtab = false\n  default_insert({ body = '\\tT1=$1\\n\\t\\tT0=$0' })\n  validate_state('i', { '\\tT1=', '\\t\\tT0=' }, { 1, 4 })\n  ensure_clean_state()\n\n  default_insert({ body = '\\ttext\\t\\t' })\n  validate_state('i', { '\\ttext\\t\\t' }, { 1, 7 })\nend\n\nT['default_insert()']['keeps node text up to date'] = function()\n  child.fn.setenv('AA', 'aa\\nbb')\n  child.bo.expandtab, child.bo.shiftwidth = true, 2\n\n  default_insert({ body = '$1\\n\\t$AA' })\n  local ref_nodes = { { tabstop = '1' }, { text = '\\n  ' }, { text = 'aa\\n  bb' }, { tabstop = '0' } }\n  eq_partial_tbl(get().nodes, ref_nodes)\n\n  type_keys('x')\n  ref_nodes = { { tabstop = '1', text = 'x' }, { text = '\\n  ' }, { text = 'aa\\n  bb' }, { tabstop = '0' } }\n  eq_partial_tbl(get().nodes, ref_nodes)\n\n  ensure_clean_state()\n\n  -- Linked tabstops with relative indents\n  default_insert({ body = '$1\\n\\t$1' })\n  type_keys('xx<CR>yy')\n  ref_nodes = { { tabstop = '1', text = 'xx\\nyy' }, { text = '\\n  ' }, { text = 'xx\\n  yy' }, { tabstop = '0' } }\n  eq_partial_tbl(get().nodes, ref_nodes)\nend\n\nT['default_insert()']['shows tabstop choices after start'] = function()\n  -- Called in Insert mode\n  type_keys('i')\n  default_insert({ body = 'T1=${1|aa,bb|}' })\n  validate_pumitems({ 'aa', 'bb' })\n  ensure_clean_state()\n\n  -- Called in Normal mode\n  default_insert({ body = 'T1=${1|aa,bb|}' })\n  validate_pumitems({ 'aa', 'bb' })\n  -- - Should not have side effects\n  eq(child.cmd_capture('au ModeChanged'):find('Insert') == nil, true)\nend\n\nT['default_insert()']['direct call removes placeholder'] = function()\n  default_insert({ body = 'T1=${1:<xxx>}' })\n  -- This can happen if inserting snippet without typing prefix to match) after\n  -- jumping to tabstop with placeholder\n  default_insert({ body = 'U1=$1' })\n  validate_state('i', { 'T1=U1=' }, { 1, 6 })\nend\n\nT['default_insert()']['treats any digit sequence as unique tabstop'] = function()\n  default_insert({ body = '$1 $2 $01 $11 $02 $00 $9' })\n  validate_active_session()\n  -- Should treat as separate tabstops and order as numbers and then as strings\n  local ref_tabstops_partial = {\n    ['00'] = { next = '01', prev = '0' },\n    ['01'] = { next = '1', prev = '00' },\n    ['1'] = { next = '02', prev = '01' },\n    ['02'] = { next = '2', prev = '1' },\n    ['2'] = { next = '9', prev = '02' },\n    ['9'] = { next = '11', prev = '2' },\n    ['11'] = { next = '0', prev = '9' },\n    -- Exactly '0' is a final tabstop\n    ['0'] = { next = '00', prev = '11' },\n  }\n  eq_partial_tbl(get().tabstops, ref_tabstops_partial)\nend\n\nT['default_insert()']['can work with special variables'] = function()\n  -- Prepare linewise selected text which should not end add extra line\n  set_lines({ 'sel', 'text' })\n  type_keys('dip')\n\n  default_insert({ body = 'Selected=$TM_SELECTED_TEXT\\n$TM_LINE_NUMBER\\n$WORKSPACE_FOLDER\\n$1' })\n  validate_state('i', { 'Selected=sel', 'text', '1', child.fn.getcwd(), '' }, { 5, 0 })\nend\n\nT['default_insert()']['respects `opts.empty_tabstop` and `opts.empty_tabstop_final`'] = function()\n  default_insert({ body = 'T1=$1 T2=$2 T0=$0' }, { empty_tabstop = '!', empty_tabstop_final = '?' })\n  child.expect_screenshot()\nend\n\nT['default_insert()']['respects `opts.lookup`'] = function()\n  local lookup = { AAA = 'aaa', TM_SELECTED_TEXT = 'xxx', ['1'] = 'tabstop' }\n  default_insert({ body = '$AAA $TM_SELECTED_TEXT $1 $1 $2' }, { lookup = lookup })\n  child.expect_screenshot()\n  -- Looked up tabstop text should be treated as if user typed it (i.e. proper\n  -- cursor position and no placeholder)\n  eq(get_cursor(), { 1, 15 })\n  eq(get().nodes[5].text, 'tabstop')\nend\n\nT['default_insert()']['validates input'] = function()\n  expect.error(function() default_insert('Text') end, '`snippet`.*snippet table')\n  expect.error(function() default_insert({ body = 'Text' }, { empty_tabstop = 1 }) end, '`empty_tabstop`.*string')\n  expect.error(\n    function() default_insert({ body = 'Text' }, { empty_tabstop_final = 1 }) end,\n    '`empty_tabstop_final`.*string'\n  )\n  expect.error(function() default_insert({ body = 'Text' }, { lookup = 1 }) end, '`lookup`.*table')\n\n  expect.error(function() default_insert({ body = '${1|}' }) end, 'Tabstop with choices')\nend\n\nT['session.get()'] = new_set()\n\nT['session.get()']['works'] = function()\n  -- Should work without active session\n  eq(get(), vim.NIL)\n\n  default_insert({ body = 'T1=${1:<$2>}' }, { empty_tabstop = '$' })\n  local session = get()\n\n  -- Should return correct data structure\n  local fields = vim.tbl_keys(session)\n  table.sort(fields)\n  eq(fields, { 'buf_id', 'cur_tabstop', 'extmark_id', 'insert_args', 'nodes', 'ns_id', 'tabstops' })\n\n  local cur_buf = get_buf()\n  local ref_partial_session = {\n    buf_id = cur_buf,\n    cur_tabstop = '1',\n    insert_args = {\n      snippet = { body = 'T1=${1:<$2>}' },\n      opts = { empty_tabstop = '$', empty_tabstop_final = '∎', lookup = {} },\n    },\n    tabstops = {\n      ['0'] = { is_visited = false, prev = '2', next = '1' },\n      ['1'] = { is_visited = true, prev = '0', next = '2' },\n      ['2'] = { is_visited = false, prev = '1', next = '0' },\n    },\n  }\n  eq_partial_tbl(session, ref_partial_session)\n\n  -- Should return valid namespace for present extmarks\n  local ns_id, is_valid_ns_id = session.ns_id, false\n  for _, id in pairs(child.api.nvim_get_namespaces()) do\n    is_valid_ns_id = is_valid_ns_id or id == ns_id\n  end\n  eq(is_valid_ns_id, true)\n\n  -- Should have correct session extmark\n  local get_extmark = make_get_extmark(session)\n  local ref_extmark = { row = 0, col = 0, end_row = 0, end_col = 5, right_gravity = false, end_right_gravity = true }\n  eq_partial_tbl(get_extmark(session.extmark_id), ref_extmark)\n\n  -- Should have proper node structure with correct extmarks attached to nodes\n  local has_inline_extmarks = child.fn.has('nvim-0.10') == 1\n  --stylua: ignore\n  local ref_nodes = {\n    { text = 'T1=', extmark = { row = 0, col = 0, end_row = 0, end_col = 3 } },\n    {\n      tabstop = '1',\n      extmark = { row = 0, col = 3, end_row = 0, end_col = 5, right_gravity = false, end_right_gravity = true },\n      placeholder = {\n        { text = '<', extmark = { row = 0, col = 3, end_row = 0, end_col = 4 } },\n        {\n          tabstop = '2',\n          extmark = {\n            row = 0, col = 4, end_row = 0, end_col = 4,\n            virt_text = has_inline_extmarks and { { '$', 'MiniSnippetsCurrentReplace' } } or nil,\n            virt_text_pos = has_inline_extmarks and 'inline' or nil,\n          },\n          placeholder = {\n            { text = '', extmark = { row = 0, col = 4, end_row = 0, end_col = 4 } }\n          },\n        },\n        { text = '>', extmark = { row = 0, col = 4, end_row = 0, end_col = 5 } },\n      }\n    },\n    {\n      tabstop = '0',\n      placeholder = { { text = '', extmark = { row = 0, col = 5, end_row = 0, end_col = 5 } } },\n      extmark = {\n        row = 0, col = 5, end_row = 0, end_col = 5,\n        virt_text = has_inline_extmarks and { { '∎', 'MiniSnippetsFinal' } } or nil,\n        virt_text_pos = has_inline_extmarks and 'inline' or nil,\n      }\n    }\n  }\n  validate_session_nodes_partial(session, ref_nodes)\n\n  -- Should update nodes immediately if they are removed\n  type_keys('x')\n  session = get()\n  ref_nodes = {\n    { text = 'T1=', extmark = { row = 0, col = 0, end_row = 0, end_col = 3 } },\n    { tabstop = '1', text = 'x', extmark = { row = 0, col = 3, end_row = 0, end_col = 4 } },\n    { tabstop = '0', placeholder = { { text = '' } }, extmark = { row = 0, col = 4, end_row = 0, end_col = 4 } },\n  }\n  validate_session_nodes_partial(session, ref_nodes)\n\n  -- Session's tabstop can be used to track session's total region\n  get_extmark = make_get_extmark(session)\n  eq_partial_tbl(get_extmark(session.extmark_id), { row = 0, col = 0, end_row = 0, end_col = 4 })\n\n  -- Should return copy of the session data\n  local is_copy = child.lua([[\n    local session = MiniSnippets.session.get()\n    local ref_cur_tabstop = session.cur_tabstop\n    session.cur_tabstop = -1\n    return MiniSnippets.session.get().cur_tabstop == ref_cur_tabstop\n  ]])\n  eq(is_copy, true)\nend\n\nT['session.get()']['reflects up to date tabstop data after jumps'] = function()\n  local validate_tabstops = function(ref_cur_tabstop, ref_visited)\n    local session = get()\n    eq(session.cur_tabstop, ref_cur_tabstop)\n    local out_visited = {}\n    for id, data in pairs(get().tabstops) do\n      out_visited[id] = data.is_visited\n    end\n    eq(out_visited, ref_visited)\n  end\n\n  default_insert({ body = 'T1=$1 T2=$2 T0=$0' })\n  validate_tabstops('1', { ['1'] = true, ['2'] = false, ['0'] = false })\n  jump('next')\n  validate_tabstops('2', { ['1'] = true, ['2'] = true, ['0'] = false })\n  -- Already visited should keep returning `true`\n  jump('prev')\n  validate_tabstops('1', { ['1'] = true, ['2'] = true, ['0'] = false })\n  jump('prev')\n  validate_tabstops('0', { ['1'] = true, ['2'] = true, ['0'] = true })\nend\n\nT['session.get()']['respects `all` argument'] = function()\n  default_insert({ body = 'T1=$1 T0=$0' })\n  default_insert({ body = 'U1=$1 U0=$0' })\n  local sessions = get(true)\n  eq(#sessions, 2)\n\n  local cur_buf = get_buf()\n  eq_partial_tbl(sessions, {\n    { buf_id = cur_buf, cur_tabstop = '1', insert_args = { snippet = { body = 'T1=$1 T0=$0' } } },\n    { buf_id = cur_buf, cur_tabstop = '1', insert_args = { snippet = { body = 'U1=$1 U0=$0' } } },\n  })\n\n  -- Previous session's extmarks should still be tracking\n  eq_partial_tbl(make_get_extmark(sessions[1])(sessions[1].extmark_id), { row = 0, col = 0, end_row = 0, end_col = 14 })\n  type_keys('x')\n  eq_partial_tbl(make_get_extmark(sessions[1])(sessions[1].extmark_id), { row = 0, col = 0, end_row = 0, end_col = 15 })\nend\n\nT['session.jump()'] = new_set()\n\nlocal validate_jumps = function(jump_data_arr)\n  for _, data in ipairs(jump_data_arr) do\n    jump(data[1])\n    eq(get_cur_tabstop(), data[2])\n    if data[3] ~= nil then eq(get_cursor(), data[3]) end\n  end\nend\n\nT['session.jump()']['works'] = function()\n  default_insert({ body = 'T1=$1 T0=$0' })\n  -- Jumping to tabstop with placeholder should put cursor at placeholder start\n  -- Also should wrap tabstops around the end\n  validate_jumps({ { 'next', '0', { 1, 7 } }, { 'next', '1', { 1, 3 } } })\n  validate_jumps({ { 'prev', '0', { 1, 7 } }, { 'prev', '1', { 1, 3 } } })\n\n  -- Should not error without active session\n  stop()\n  eq(jump('next'), vim.NIL)\n  eq(jump('prev'), vim.NIL)\nend\n\nT['session.jump()']['does not lead to replacing already edited tabstop'] = function()\n  default_insert({ body = 'T1=${1:<xxx>}\\nT0=$0' })\n  type_keys('yyy')\n  validate_state('i', { 'T1=yyy', 'T0=' }, { 1, 6 })\n\n  jump('next')\n  jump('prev')\n  eq(get_cursor(), { 1, 6 })\n  type_keys('!')\n  validate_state('i', { 'T1=yyy!', 'T0=' }, { 1, 7 })\n\n  -- Should not matter where cursor was when target tabstop was current\n  type_keys('<Down>')\n  eq(get_cursor(), { 2, 3 })\n  jump('prev')\n  jump('next')\n  eq(get_cursor(), { 1, 7 })\nend\n\nT['session.jump()']['works with several linked tabstops'] = function()\n  default_insert({ body = 'T1=${1:<$0>} T1=$1 T0=$0' })\n\n  -- Should jump only to the first node of target tabstop\n  validate_jumps({ { 'next', '0', { 1, 4 } }, { 'next', '1', { 1, 3 } } })\n  validate_jumps({ { 'prev', '0', { 1, 4 } }, { 'prev', '1', { 1, 3 } } })\n\n  -- Even if it changes\n  type_keys('x')\n  validate_state('i', { 'T1=x T1=x T0=' }, { 1, 4 })\n  validate_jumps({ { 'next', '0', { 1, 13 } }, { 'next', '1', { 1, 4 } } })\nend\n\nT['session.jump()']['jumps in proper order'] = function()\n  default_insert({ body = 'T2=$2 T0=$0 T1=$1' })\n  validate_state('i', { 'T2= T0= T1=' }, { 1, 11 })\n  validate_jumps({ { 'next', '2', { 1, 3 } }, { 'next', '0', { 1, 7 } }, { 'next', '1', { 1, 11 } } })\n  validate_jumps({ { 'prev', '0', { 1, 7 } }, { 'prev', '2', { 1, 3 } }, { 'prev', '1', { 1, 11 } } })\nend\n\nT['session.jump()']['works with tabstop with transform'] = function()\n  -- Should ignore present transform (for now) and treat as regular tabstop\n  default_insert({ body = '$1 ${2/.*/upcase/} $0' })\n  validate_jumps({ { 'next', '2', { 1, 1 } }, { 'next', '0', { 1, 2 } } })\nend\n\nT['session.jump()']['ignores variable nodes'] = function()\n  default_insert({ body = 'T1=$1 $AAA T2=$2 $BBB' }, { lookup = { AAA = 'aaa' } })\n  validate_state('i', { 'T1= aaa T2= ' }, { 1, 3 })\n  validate_jumps({ { 'next', '2', { 1, 11 } }, { 'next', '0', { 1, 12 } }, { 'next', '1', { 1, 3 } } })\nend\n\nT['session.jump()']['ensures session buffer is current'] = function()\n  default_insert({ body = 'T1=$1 T0=$0' })\n  type_keys('<Esc>')\n\n  -- Prepare separate buffers and windows\n  local buf_id_1, buf_id_2 = get_buf(), new_buf()\n  local win_1 = child.api.nvim_get_current_win()\n  child.cmd('vertical split')\n  local win_2 = child.api.nvim_get_current_win()\n  no_eq(win_1, win_2)\n  child.api.nvim_win_set_buf(win_2, buf_id_2)\n\n  -- Should reuse visible window\n  eq(child.api.nvim_get_current_win(), win_2)\n  eq(child.fn.mode(), 'n')\n  jump('next')\n  -- - Poke eventloop because both ensuring Insert mode from Normal mode and\n  --   jumping do not happen immediately\n  child.poke_eventloop()\n  eq(child.api.nvim_get_current_win(), win_1)\n  eq(child.api.nvim_win_is_valid(win_2), true)\n  -- Should ensure Insert mode\n  validate_state('i', { 'T1= T0=' }, { 1, 7 })\n  eq(get_cur_tabstop(), '0')\n\n  -- Should show target buffer in current window if not visible\n  child.api.nvim_win_set_buf(0, buf_id_2)\n  eq(child.fn.win_findbuf(buf_id_1), {})\n  jump('prev')\n  eq(get_buf(), buf_id_1)\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n  eq(get_cur_tabstop(), '1')\nend\n\nT['session.jump()']['shows completion for tabstop with choices'] = function()\n  default_insert({ body = 'T1=${1|aa,bb|} T2=${2|dd,cc|}' })\n  validate_pumitems({ 'aa', 'bb' })\n  jump('next')\n  validate_pumitems({ 'dd', 'cc' })\n  jump('prev')\n  validate_pumitems({ 'aa', 'bb' })\nend\n\nT['session.jump()']['handles when tabstop becomes absent'] = function()\n  default_insert({ body = '${1:$2} ${3:$0}' })\n  type_keys('x')\n  validate_jumps({ { 'next', '3' }, { 'next', '0' }, { 'next', '1' } })\n  validate_jumps({ { 'prev', '0' }, { 'prev', '3' }, { 'prev', '1' } })\n\n  jump('next')\n  type_keys('y')\n  validate_jumps({ { 'next', '1' }, { 'next', '3' } })\n  validate_jumps({ { 'prev', '1' }, { 'prev', '3' } })\nend\n\nT['session.jump()']['validates input'] = function()\n  expect.error(function() jump(1) end, '`direction`.*one of')\nend\n\n--stylua: ignore\nT['session.jump()']['triggers events'] = function()\n  child.lua([[\n    local events = { 'MiniSnippetsSessionJumpPre', 'MiniSnippetsSessionJump' }\n    _G.au_log = {}\n    local track = function(args)\n      local entry = {\n        event = args.match,\n        buf_id = args.buf,\n        data = args.data,\n        cur_tabstop = MiniSnippets.session.get().cur_tabstop,\n      }\n      table.insert(_G.au_log, entry)\n    end\n    vim.api.nvim_create_autocmd('User', { pattern = events, callback = track })\n  ]])\n\n  local cur_buf = get_buf()\n  default_insert({ body = 'T1=$1 T0=$0' })\n  -- Should not trigger during initial insert\n  eq(get_au_log(), {})\n\n  jump('next')\n  local ref_au_log = {\n    -- `*Pre` should be called *before* changing current tabstop\n    { event = 'MiniSnippetsSessionJumpPre', cur_tabstop = '1', data = { tabstop_from = '1', tabstop_to = '0' }, buf_id = cur_buf },\n    { event = 'MiniSnippetsSessionJump',    cur_tabstop = '0', data = { tabstop_from = '1', tabstop_to = '0' }, buf_id = cur_buf },\n  }\n  eq(get_au_log(), ref_au_log)\n\n  jump('next')\n  vim.list_extend(ref_au_log, {\n    { event = 'MiniSnippetsSessionJumpPre', cur_tabstop = '0', data = { tabstop_from = '0', tabstop_to = '1' }, buf_id = cur_buf },\n    { event = 'MiniSnippetsSessionJump',    cur_tabstop = '1', data = { tabstop_from = '0', tabstop_to = '1' }, buf_id = cur_buf },\n  })\n  eq(get_au_log(), ref_au_log)\n\n  stop()\n  clean_au_log()\n\n  -- Should still trigger events if there is only a single tabstop left\n  default_insert({ body = 'T1=${1:$0}' })\n  type_keys('x')\n  jump('next')\n  ref_au_log = {\n    { event = 'MiniSnippetsSessionJumpPre', cur_tabstop = '1', data = { tabstop_from = '1', tabstop_to = '1' }, buf_id = cur_buf },\n    { event = 'MiniSnippetsSessionJump',    cur_tabstop = '1', data = { tabstop_from = '1', tabstop_to = '1' }, buf_id = cur_buf },\n  }\n  eq(get_au_log(), ref_au_log)\nend\n\nT['session.stop()'] = new_set()\n\nT['session.stop()']['works'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  -- Should work without active session\n  expect.no_error(stop)\n\n  default_insert({ body = 'T1=$1 T0=$0' })\n  default_insert({ body = 'U1=$1 U0=$0' })\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 6 })\n  validate_n_sessions(2)\n  child.expect_screenshot(screen_opts)\n\n  -- Should stop active session (no change mode/cursor) and resume previous\n  stop()\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 6 })\n  validate_n_sessions(1)\n  child.expect_screenshot(screen_opts)\n\n  stop()\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 6 })\n  validate_n_sessions(0)\n  child.expect_screenshot(screen_opts)\n\n  -- Should clean all side effects\n  expect.error(function() child.cmd('au MiniSnippetsTrack') end, 'No such group')\n  expect.match(child.cmd_capture('imap <C-h>'), 'No mapping')\n  expect.match(child.cmd_capture('imap <C-l>'), 'No mapping')\n  expect.match(child.cmd_capture('imap <C-c>'), 'No mapping')\nend\n\nT['session.stop()']['hides completion popup'] = function()\n  default_insert({ body = 'T1=$1 T0=$0' })\n  type_keys('<C-x><C-n>')\n  validate_pumvisible()\n  stop()\n  validate_no_pumvisible()\n  eq(child.fn.mode(), 'i')\nend\n\nT['session.stop()']['ensures next nested session is valid'] = function()\n  -- Invalid next session is last\n  set_lines({ '', '' })\n  set_cursor(2, 0)\n  default_insert({ body = 'T1=$1 T0=$0' })\n  type_keys('<Up>')\n  default_insert({ body = 'U1=$1 U0=$0' })\n\n  type_keys('<Esc>', 'G', 'dd', 'gg')\n  stop()\n  validate_no_active_session()\n\n  ensure_clean_state()\n\n  -- Invalid next session is not last\n  set_lines({ '', '', '' })\n  set_cursor(2, 0)\n  default_insert({ body = 'T1=$1 T0=$0' })\n  type_keys('<Down>')\n  default_insert({ body = 'U1=$1 U0=$0' })\n  type_keys('<Up><Up>')\n  default_insert({ body = 'V1=$1 V0=$0' })\n\n  type_keys('<Esc>', 'G', 'dd', 'gg')\n  stop()\n  child.expect_screenshot()\nend\n\nT['parse()'] = new_set()\n\nlocal parse = forward_lua('MiniSnippets.parse')\n\nT['parse()']['works'] = function()\n  --stylua: ignore\n  eq(\n    parse('hello ${1:xx} $var world$0'),\n    {\n      { text = 'hello ' }, { tabstop = '1', placeholder = { { text = 'xx' } } }, { text = ' ' },\n      { var = 'var' }, { text = ' world' }, { tabstop = '0' },\n    }\n  )\n  -- Should allow array of strings\n  eq(parse({ 'aa', '$1', '$var' }), { { text = 'aa\\n' }, { tabstop = '1' }, { text = '\\n' }, { var = 'var' } })\nend\n\n--stylua: ignore\nT['parse()']['text'] = function()\n  -- Common\n  eq(parse('aa'),      { { text = 'aa' } })\n  eq(parse('ыыы ффф'), { { text = 'ыыы ффф' } })\n\n  -- Simple\n  eq(parse(''),    { { text = '' } })\n  eq(parse('$'),   { { text = '$' } })\n  eq(parse('{'),   { { text = '{' } })\n  eq(parse('}'),   { { text = '}' } })\n  eq(parse([[\\]]), { { text = [[\\]] } })\n\n  -- Escaped (should ignore `\\` before `$}\\`)\n  eq(parse([[aa\\$bb\\}cc\\\\dd]]), { { text = [[aa$bb}cc\\dd]] } })\n  eq(parse([[aa\\$]]),           { { text = 'aa$' } })\n  eq(parse([[aa\\${}]]),         { { text = 'aa${}' } })\n  eq(parse([[\\}]]),             { { text = '}' } })\n  eq(parse([[aa \\\\\\$]]),        { { text = [[aa \\$]] } })\n  eq(parse([[\\${1|aa,bb|}]]),   { { text = '${1|aa,bb|}' } })\n\n  -- Not spec: allow unescaped backslash\n  eq(parse([[aa\\bb]]), { { text = [[aa\\bb]] } })\n\n  -- Not spec: allow unescaped $ when can not be mistaken for tabstop or var\n  eq(parse('aa$ bb'), { { text = 'aa$ bb' } })\n\n  -- Allow '$' at the end of the snippet\n  eq(parse('aa$'), { { text = 'aa' }, { text = '$' } })\n\n  -- Not spec: allow unescaped `}` in top-level text\n  eq(parse('{ aa }'),         { { text = '{ aa }' } })\n  eq(parse('{\\n\\taa\\n}'),     { { text = '{\\n\\taa\\n}' } })\n  eq(parse('aa{1}'),          { { text = 'aa{1}' } })\n  eq(parse('aa{1:bb}'),       { { text = 'aa{1:bb}' } })\n  eq(parse('aa{1:{2:cc}}'),   { { text = 'aa{1:{2:cc}}' } })\n  eq(parse('aa{var:{1:bb}}'), { { text = 'aa{var:{1:bb}}' } })\nend\n\n--stylua: ignore\nT['parse()']['tabstop'] = function()\n  -- Common\n  eq(parse('$1'),          { { tabstop = '1' } })\n  eq(parse('aa $1'),       { { text = 'aa ' },    { tabstop = '1' } })\n  eq(parse('aa $1 bb'),    { { text = 'aa ' },    { tabstop = '1' }, { text = ' bb' } })\n  eq(parse('aa$1bb'),      { { text = 'aa' },     { tabstop = '1' }, { text = 'bb' } })\n  eq(parse('hello_$1_bb'), { { text = 'hello_' }, { tabstop = '1' }, { text = '_bb' } })\n  eq(parse('ыыы $1 ффф'),  { { text = 'ыыы ' },   { tabstop = '1' }, { text = ' ффф' } })\n\n  eq(parse('${1}'),          { { tabstop = '1' } })\n  eq(parse('aa ${1}'),       { { text = 'aa ' },    { tabstop = '1' } })\n  eq(parse('aa ${1} bb'),    { { text = 'aa ' },    { tabstop = '1' }, { text = ' bb' } })\n  eq(parse('aa${1}bb'),      { { text = 'aa' },     { tabstop = '1' }, { text = 'bb' } })\n  eq(parse('hello_${1}_bb'), { { text = 'hello_' }, { tabstop = '1' }, { text = '_bb' } })\n  eq(parse('ыыы ${1} ффф'),  { { text = 'ыыы ' },   { tabstop = '1' }, { text = ' ффф' } })\n\n  eq(parse('$0'),    { { tabstop = '0' } })\n  eq(parse('$1 $0'), { { tabstop = '1' }, { text = ' ' }, { tabstop = '0' } })\n\n  eq(parse([[aa\\\\$1]]), { { text = [[aa\\]] }, { tabstop = '1' } })\n\n  -- Adjacent tabstops\n  eq(parse('aa$1$2'),   { { text = 'aa' },   { tabstop = '1' }, { tabstop = '2' } })\n  eq(parse('aa$1$0'),   { { text = 'aa' },   { tabstop = '1' }, { tabstop = '0' } })\n  eq(parse('$1$2'),     { { tabstop = '1' }, { tabstop = '2' } })\n  eq(parse('${1}${2}'), { { tabstop = '1' }, { tabstop = '2' } })\n  eq(parse('$1${2}'),   { { tabstop = '1' }, { tabstop = '2' } })\n  eq(parse('${1}$2'),   { { tabstop = '1' }, { tabstop = '2' } })\n\n  -- Can be any digit sequence in any order\n  eq(parse('$2'),       { { tabstop = '2' } })\n  eq(parse('$3 $10'),   { { tabstop = '3' }, { text = ' ' }, { tabstop = '10' } })\n  eq(parse('$3 $2 $0'), { { tabstop = '3' }, { text = ' ' }, { tabstop = '2' }, { text = ' ' }, { tabstop = '0' } })\n  eq(parse('$3 $0 $2'), { { tabstop = '3' }, { text = ' ' }, { tabstop = '0' }, { text = ' ' }, { tabstop = '2' } })\n  eq(parse('$1 $01'),   { { tabstop = '1' }, { text = ' ' }, { tabstop = '01' } })\n\n  -- Tricky\n  eq(parse('$1$a'), { { tabstop = '1' }, { var = 'a' } })\n  eq(parse('$1$-'), { { tabstop = '1' }, { text = '$-' } })\n  eq(parse('$a$1'), { { var = 'a' },     { tabstop = '1' } })\n  eq(parse('$-$1'), { { text = '$-' },   { tabstop = '1' } })\n  eq(parse('$$1'),  { { text = '$' },    { tabstop = '1' } })\n  eq(parse('$1$'),  { { tabstop = '1' }, { text = '$' } })\nend\n\n--stylua: ignore\nT['parse()']['choice'] = function()\n  -- Common\n  eq(parse('${1|aa|}'),    { { tabstop = '1', choices = { 'aa' } } })\n  eq(parse('${2|aa|}'),    { { tabstop = '2', choices = { 'aa' } } })\n  eq(parse('${1|aa,bb|}'), { { tabstop = '1', choices = { 'aa', 'bb' } } })\n\n  -- Escape (should ignore `\\` before `,|\\` and treat as text)\n  eq(parse([[${1|},$,\\,,\\|,\\\\|}]]), { { tabstop = '1', choices = { '}', '$', ',', '|', [[\\]] } } })\n  eq(parse([[${1|aa\\,bb|}]]),       { { tabstop = '1', choices = { 'aa,bb' } } })\n\n  -- Empty choices\n  eq(parse('${1|,|}'),       { { tabstop = '1', choices = { '', '' } } })\n  eq(parse('${1|aa,|}'),     { { tabstop = '1', choices = { 'aa', '' } } })\n  eq(parse('${1|,aa|}'),     { { tabstop = '1', choices = { '', 'aa' } } })\n  eq(parse('${1|aa,,bb|}'),  { { tabstop = '1', choices = { 'aa', '', 'bb' } } })\n  eq(parse('${1|aa,,,bb|}'), { { tabstop = '1', choices = { 'aa', '', '', 'bb' } } })\n\n  -- Not spec: allow unescaped backslash\n  eq(parse([[${1|aa\\bb,cc|}]]), { { tabstop = '1', choices = { [[aa\\bb]], 'cc' } } })\n\n  -- Should not be ignored in `$0`\n  eq(parse('${0|aa|}'),    { { tabstop = '0', choices = { 'aa' } } })\n  eq(parse('${0|aa,bb|}'), { { tabstop = '0', choices = { 'aa', 'bb' } } })\nend\n\n--stylua: ignore\nT['parse()']['var'] = function()\n  -- Common\n  eq(parse('$aa'),    { { var = 'aa' } })\n  eq(parse('$a_b'),   { { var = 'a_b' } })\n  eq(parse('$_a'),    { { var = '_a' } })\n  eq(parse('$a1'),    { { var = 'a1' } })\n  eq(parse('${aa}'),  { { var = 'aa' } })\n  eq(parse('${a_b}'), { { var = 'a_b' } })\n  eq(parse('${_a}'),  { { var = '_a' } })\n  eq(parse('${a1}'),  { { var = 'a1' } })\n\n  eq(parse([[aa\\\\$bb]]), { { text = [[aa\\]] }, { var = 'bb' } })\n  eq(parse('$$aa'),      { { text = '$' },     { var = 'aa' } })\n  eq(parse('$aa$'),      { { var = 'aa' },     { text = '$' } })\n\n  -- Should recognize only [_a-zA-Z] [_a-zA-Z0-9]*\n  eq(parse('$aa-bb'),     { { var = 'aa' },  { text = '-bb' } })\n  eq(parse('$aa bb'),     { { var = 'aa' },  { text = ' bb' } })\n  eq(parse('aa$bb cc'),   { { text = 'aa' }, { var = 'bb' }, { text = ' cc' } })\n  eq(parse('aa${bb} cc'), { { text = 'aa' }, { var = 'bb' }, { text = ' cc' } })\nend\n\n--stylua: ignore\nT['parse()']['placeholder'] = function()\n  -- Common\n  eq(parse('aa ${1:b}'), { { text = 'aa ' }, { tabstop = '1', placeholder = { { text = 'b' } } } })\n  eq(parse('${1:b}'),    { { tabstop = '1', placeholder = { { text = 'b' } } } })\n  eq(parse('${1:ыыы}'),  { { tabstop = '1', placeholder = { { text = 'ыыы' } } } })\n  eq(parse('${1:}'),     { { tabstop = '1', placeholder = { { text = '' } } } })\n\n  eq(parse('${1:aa} ${2:bb}'), { { tabstop = '1', placeholder = { { text = 'aa' } } }, { text = ' ' }, { tabstop = '2', placeholder = { { text = 'bb' } } } })\n\n  eq(parse('aa ${0:b}'), { { text = 'aa ' }, { tabstop = '0', placeholder = { { text = 'b' } } } })\n  eq(parse('${0:b}'),    { { tabstop = '0', placeholder = { { text = 'b' } } } })\n  eq(parse('${0:}'),     { { tabstop = '0', placeholder = { { text = '' } } } })\n  eq(parse('${0:ыыы}'),  { { tabstop = '0', placeholder = { { text = 'ыыы' } } } })\n  eq(parse('${0:}'),     { { tabstop = '0', placeholder = { { text = '' } } } })\n\n  -- Escaped (should ignore `\\` before `$}\\` and treat as text)\n  eq(parse([[${1:aa\\$bb\\}cc\\\\dd}]]), { { tabstop = '1', placeholder = { { text = [[aa$bb}cc\\dd]] } } } })\n  eq(parse([[${1:aa\\$}]]),           { { tabstop = '1', placeholder = { { text = 'aa$' } } } })\n  eq(parse([[${1:aa\\\\}]]),           { { tabstop = '1', placeholder = { { text = [[aa\\]] } } } })\n  -- - Should allow unescaped `:`\n  eq(parse('${1:aa:bb}'),            { { tabstop = '1', placeholder = { { text = 'aa:bb' } } } })\n\n  -- Not spec: allow unescaped backslash\n  eq(parse([[${1:aa\\bb}]]), { { tabstop = '1', placeholder = { { text = [[aa\\bb]] } } } })\n\n  -- Not spec: allow unescaped dollar\n  eq(parse('${1:aa$-}'),  { { tabstop = '1', placeholder = { { text = 'aa$-' } } } })\n  eq(parse('${1:aa$}'),   { { tabstop = '1', placeholder = { { text = 'aa$' } } } })\n  eq(parse('${1:$2$}'),   { { tabstop = '1', placeholder = { { tabstop = '2' }, { text = '$' } } } })\n  eq(parse('${1:$2}$'),   { { tabstop = '1', placeholder = { { tabstop = '2' } } }, { text = '$' } })\n  eq(parse('${1:aa$}$2'), { { tabstop = '1', placeholder = { { text = 'aa$' } } }, { tabstop = '2' } })\n\n  -- Should not be ignored in `$0`\n  eq(parse('${0:aa$1bb}'), { { tabstop = '0', placeholder = { { text = 'aa' }, { tabstop = '1' }, { text = 'bb' } } } })\n\n  -- Placeholder for variable (assume implemented the same way as for tabstop)\n  eq(parse('${aa:}'),         { { var = 'aa', placeholder = { { text = '' } } } })\n  eq(parse('${aa:bb}'),       { { var = 'aa', placeholder = { { text = 'bb' } } } })\n  eq(parse('${aa:bb:cc}'),    { { var = 'aa', placeholder = { { text = 'bb:cc' } } } })\n  eq(parse('${aa:$1}'),       { { var = 'aa', placeholder = { { tabstop = '1' } } } })\n  eq(parse('${aa:${1}}'),     { { var = 'aa', placeholder = { { tabstop = '1' } } } })\n  eq(parse('${aa:${1:bb}}'),  { { var = 'aa', placeholder = { { tabstop = '1', placeholder = { { text = 'bb' } } } } } })\n  eq(parse('${aa:${1|bb|}}'), { { var = 'aa', placeholder = { { tabstop = '1', choices = { 'bb' } } } } })\n  eq(parse('${aa:${bb:cc}}'), { { var = 'aa', placeholder = { { var = 'bb',    placeholder = { { text = 'cc' } } } } } })\n\n  -- Nested\n  -- - Tabstop\n  eq(parse('${1:$2}'),    { { tabstop = '1', placeholder = { { tabstop = '2' } } } })\n  eq(parse('${1:$2} yy'), { { tabstop = '1', placeholder = { { tabstop = '2' } } }, { text = ' yy' } })\n  eq(parse('${1:${2}}'),  { { tabstop = '1', placeholder = { { tabstop = '2' } } } })\n  eq(parse('${1:${3}}'),  { { tabstop = '1', placeholder = { { tabstop = '3' } } } })\n\n  -- - Placeholder\n  eq(parse('${1:${2:aa}}'),      { { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } } } } })\n  eq(parse('${1:${2:${3:aa}}}'), { { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { tabstop = '3', placeholder = { { text = 'aa' } } } } } } } })\n  eq(parse('${1:${2:${3}}}'),    { { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { tabstop = '3' } } } } } })\n  eq(parse('${1:${3:aa}}'),      { { tabstop = '1', placeholder = { { tabstop = '3', placeholder = { { text = 'aa' } } } } } })\n\n  eq(parse([[${1:${2:aa\\$bb\\}cc\\\\dd}}]]), { { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { text = [[aa$bb}cc\\dd]] } } } } } })\n\n  eq(parse([[${1:{$2\\}}]]),   { { tabstop = '1', placeholder = { { text = '{' }, { tabstop = '2' }, { text = '}' } } } })\n  eq(parse([[${aa:{$1\\}}]]),  { { var = 'aa',    placeholder = { { text = '{' }, { tabstop = '1' }, { text = '}' } } } })\n  eq(parse([[${1:{$aa\\}}]]),  { { tabstop = '1', placeholder = { { text = '{' }, { var = 'aa' },    { text = '}' } } } })\n  eq(parse([[${aa:{$bb\\}}]]), { { var = 'aa',    placeholder = { { text = '{' }, { var = 'bb' },    { text = '}' } } } })\n\n  -- - Choice\n  eq(parse('${1:${2|aa|}}'),    { { tabstop = '1', placeholder = { { tabstop = '2', choices = { 'aa' } } } } })\n  eq(parse('${1:${3|aa|}}'),    { { tabstop = '1', placeholder = { { tabstop = '3', choices = { 'aa' } } } } })\n  eq(parse('${1:${2|aa,bb|}}'), { { tabstop = '1', placeholder = { { tabstop = '2', choices = { 'aa', 'bb' } } } } })\n\n  eq(parse([[${1:${2|aa\\,bb\\|cc\\\\dd|}}]]), { { tabstop = '1', placeholder = { { tabstop = '2', choices = { [[aa,bb|cc\\dd]] } } } } })\n\n  -- - Variable\n  eq(parse('${1:$aa}'),                     { { tabstop = '1', placeholder = { { var = 'aa' } } } })\n  eq(parse('${1:$aa} xx'),                  { { tabstop = '1', placeholder = { { var = 'aa' } } }, { text = ' xx' } })\n  eq(parse('${1:${aa}}'),                   { { tabstop = '1', placeholder = { { var = 'aa' } } } })\n  eq(parse('${1:${aa:bb}}'),                { { tabstop = '1', placeholder = { { var = 'aa', placeholder = { { text = 'bb' } } } } } })\n  eq(parse('${1:${aa:$2}}'),                { { tabstop = '1', placeholder = { { var = 'aa', placeholder = { { tabstop = '2' } } } } } })\n  eq(parse('${1:${aa:bb$2cc}}'),            { { tabstop = '1', placeholder = { { var = 'aa', placeholder = { { text = 'bb' }, { tabstop = '2' }, { text = 'cc' } } } } } })\n  eq(parse('${1:${aa/.*/val/i}}'),          { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', 'val',          'i' } } } } })\n  eq(parse('${1:${aa/.*/${1}/i}}'),         { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', '${1}',         'i' } } } } })\n  eq(parse('${1:${aa/.*/${1:/upcase}/i}}'), { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', '${1:/upcase}', 'i' } } } } })\n  eq(parse('${1:${aa/.*/${1:/upcase}/i}}'), { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', '${1:/upcase}', 'i' } } } } })\n\n  eq(parse('${1:${aa/.*/xx${1:else}/i}}'),     { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', 'xx${1:else}',     'i' } } } } })\n  eq(parse('${1:${aa/.*/xx${1:-else}/i}}'),    { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', 'xx${1:-else}',    'i' } } } } })\n  eq(parse('${1:${aa/.*/xx${1:+if}/i}}'),      { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', 'xx${1:+if}',      'i' } } } } })\n  eq(parse('${1:${aa/.*/xx${1:?if:else}/i}}'), { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', 'xx${1:?if:else}', 'i' } } } } })\n  eq(parse('${1:${aa/.*/xx${1:/upcase}/i}}'),  { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', 'xx${1:/upcase}',  'i' } } } } })\n\n  eq(parse('${1:${aa/.*/${1:?${}:xx}/i}}'),                 { { tabstop = '1', placeholder = { { var = 'aa', transform = { '.*', '${1:?${}:xx}', 'i' } } } } })\n\n  -- - Known limitation of needing to escape `}` in `if`\n  eq(parse([[${1:${aa/regex/${1:?if\\}:else/i}/options}}]]),                { { tabstop = '1', placeholder = { { var = 'aa', transform = { 'regex', [[${1:?if\\}:else/i}]], 'options' } } } } })\n  expect.no_equality(parse([[${1:${aa/regex/${1:?if}:else/i}/options}}]]), { { tabstop = '1', placeholder = { { var = 'aa', transform = { 'regex', '${1:?if}:else/i}',    'options' } } } } }) -- this is bad\n\n  -- Combined\n  eq(parse('${1:aa${2:bb}cc}'),  { { tabstop = '1', placeholder = { { text = 'aa' },  { tabstop = '2', placeholder = { { text = 'bb' } } }, { text = 'cc' } } } })\n  eq(parse('${1:aa $aa bb}'),    { { tabstop = '1', placeholder = { { text = 'aa ' }, { var = 'aa' }, { text = ' bb' } } } })\n  eq(parse('${1:aa${aa:xx}bb}'), { { tabstop = '1', placeholder = { { text = 'aa' },  { var = 'aa', placeholder = { { text = 'xx' } } }, { text = 'bb' } } } })\n  eq(parse('${1:xx$bb}yy'),      { { tabstop = '1', placeholder = { { text = 'xx' }, { var = 'bb' } } }, { text = 'yy'} })\n  eq(parse('${aa:xx$bb}yy'),     { { var = 'aa', placeholder = { { text = 'xx' }, { var = 'bb' } } }, { text = 'yy'} })\n\n  -- Different placeholders for same id/name\n  eq(\n    parse('${1:xx}_${1:yy}_$1'),\n    { { tabstop = '1', placeholder = { { text = 'xx' } } }, { text = '_' }, { tabstop = '1', placeholder = { { text = 'yy' } } }, { text = '_' }, { tabstop = '1' } }\n  )\n  eq(\n    parse('${1:}_$1_${1:yy}'),\n    { { tabstop = '1', placeholder = { { text = '' } } },   { text = '_' }, { tabstop = '1' }, { text = '_' }, { tabstop = '1', placeholder = { { text = 'yy' } } } }\n  )\n\n  eq(\n    parse('${a:xx}_${a:yy}_$a'),\n    { { var = 'a', placeholder = { { text = 'xx' } } }, { text = '_' }, { var = 'a', placeholder = { { text = 'yy' } } }, { text = '_' }, { var = 'a' } }\n  )\n  eq(\n    parse('${a:}-$a-${a:yy}'),\n    { { var = 'a', placeholder = { { text = '' } } },   { text = '-' }, { var = 'a' }, { text = '-' }, { var = 'a', placeholder = { { text = 'yy' } } } }\n  )\nend\n\n--stylua: ignore\nT['parse()']['transform'] = function()\n  -- All transform string should be parsed as is\n\n  -- Should be allowed in variable nodes\n  eq(parse('${var/xx(yy)/${0:aaa}/i}'),     { { var = 'var', transform = { 'xx(yy)', '${0:aaa}', 'i' } } })\n\n  eq(parse('${var/.*/${1}/i}'),             { { var = 'var', transform = { '.*', '${1}',             'i' } } })\n  eq(parse('${var/.*/$1/i}'),               { { var = 'var', transform = { '.*', '$1',               'i' } } })\n  eq(parse('${var/.*/$1/}'),                { { var = 'var', transform = { '.*', '$1',               ''  } } })\n  eq(parse('${var/.*//}'),                  { { var = 'var', transform = { '.*', '',                 ''  } } })\n  eq(parse('${var/.*/This-$1-encloses/i}'), { { var = 'var', transform = { '.*', 'This-$1-encloses', 'i' } } })\n  eq(parse('${var/.*/aa${1:else}/i}'),      { { var = 'var', transform = { '.*', 'aa${1:else}',      'i' } } })\n  eq(parse('${var/.*/aa${1:-else}/i}'),     { { var = 'var', transform = { '.*', 'aa${1:-else}',     'i' } } })\n  eq(parse('${var/.*/aa${1:+if}/i}'),       { { var = 'var', transform = { '.*', 'aa${1:+if}',       'i' } } })\n  eq(parse('${var/.*/aa${1:?if:else}/i}'),  { { var = 'var', transform = { '.*', 'aa${1:?if:else}',  'i' } } })\n  eq(parse('${var/.*/aa${1:/upcase}/i}'),   { { var = 'var', transform = { '.*', 'aa${1:/upcase}',   'i' } } })\n\n  -- Tricky transform strings\n  eq(parse('${var///}'),                { { var = 'var', transform = { '', '', '' } } })\n\n  eq(parse([[${var/.*/$\\//i}]]),        { { var = 'var', transform = { '.*', [[$\\/]],        'i' } } })\n  eq(parse('${var/.*/$${}/i}'),         { { var = 'var', transform = { '.*', '$${}',         'i' } } }) -- `${}` directly after `$`\n  eq(parse('${var/.*/${a/}/i}'),        { { var = 'var', transform = { '.*', '${a/}',        'i' } } }) -- `/` inside a proper `${...}`\n  eq(parse([[${var/.*/$\\x/i}]]),        { { var = 'var', transform = { '.*', [[$\\x]],        'i' } } }) -- `/` after both dollar and backslash\n  eq(parse([[${var/.*/\\$x/i}]]),        { { var = 'var', transform = { '.*', [[\\$x]],        'i' } } }) -- `/` after both dollar and backslash\n  eq(parse([[${var/.*/\\${x/i}]]),       { { var = 'var', transform = { '.*', [[\\${x]],       'i' } } }) -- `/` after not proper `${`\n  eq(parse([[${var/.*/$\\{x/i}]]),       { { var = 'var', transform = { '.*', [[$\\{x]],       'i' } } }) -- `/` after not proper `${`\n  eq(parse('${var/.*/a$/i}'),           { { var = 'var', transform = { '.*', 'a$',           'i' } } }) -- `/` directly after dollar\n  eq(parse('${var/.*/${1:?${}:aa}/i}'), { { var = 'var', transform = { '.*', '${1:?${}:aa}', 'i' } } }) -- `}` inside `format`\n\n  -- Escaped (should ignore `\\` before `$/\\` and treat as text)\n  eq(parse([[${var/.*/\\/a\\/a\\//g}]]),                { { var = 'var', transform = { '.*', [[\\/a\\/a\\/]], 'g' } } })\n\n  -- - Known limitation of needing to escape `}` in `if` of `${1:?if:else}`\n  eq(parse([[${var/.*/${1:?if\\}:else/i}/options}]]),                { { var = 'var', transform = { '.*', [[${1:?if\\}:else/i}]], 'options' } } })\n  expect.no_equality(parse([[${var/.*/${1:?if}:else/i}/options}]]), { { var = 'var', transform = { '.*', [[${1:?if}:else/i}]],  'options' } } }) -- this is bad\n\n  eq(parse([[${var/.*/\\\\aa/g}]]),  { { var = 'var', transform = { '.*', [[\\\\aa]],  'g' } } })\n  eq(parse([[${var/.*/\\$1aa/g}]]), { { var = 'var', transform = { '.*', [[\\$1aa]], 'g' } } })\n\n  -- - Should handle escaped `/` in regex\n  eq(parse([[${var/\\/re\\/gex\\//aa/}]]), { { var = 'var', transform = { [[\\/re\\/gex\\/]], 'aa', '' } } })\n\n  -- Should be allowed in tabstop nodes\n  eq(parse('${1/.*/${0:aaa}/i} xx'),      { { tabstop = '1', transform = { '.*', '${0:aaa}', 'i' } }, { text = ' xx' } })\n  eq(parse('${1/.*/${1}/i}'),             { { tabstop = '1', transform = { '.*', '${1}', 'i' } } })\n  eq(parse('${1/.*/$1/i}'),               { { tabstop = '1', transform = { '.*', '$1', 'i' } } })\n  eq(parse('${1/.*/$1/}'),                { { tabstop = '1', transform = { '.*', '$1', '' } } })\n  eq(parse('${1/.*//}'),                  { { tabstop = '1', transform = { '.*', '', '' } } })\n  eq(parse('${1/.*/This-$1-encloses/i}'), { { tabstop = '1', transform = { '.*', 'This-$1-encloses', 'i' } } })\n  eq(parse('${1/.*/aa${1:else}/i}'),      { { tabstop = '1', transform = { '.*', 'aa${1:else}', 'i' } } })\n  eq(parse('${1/.*/aa${1:-else}/i}'),     { { tabstop = '1', transform = { '.*', 'aa${1:-else}', 'i' } } })\n  eq(parse('${1/.*/aa${1:+if}/i}'),       { { tabstop = '1', transform = { '.*', 'aa${1:+if}', 'i' } } })\n  eq(parse('${1/.*/aa${1:?if:else}/i}'),  { { tabstop = '1', transform = { '.*', 'aa${1:?if:else}', 'i' } } })\n  eq(parse('${1/.*/aa${1:/upcase}/i}'),   { { tabstop = '1', transform = { '.*', 'aa${1:/upcase}', 'i' } } })\nend\n\n--stylua: ignore\nT['parse()']['tricky'] = function()\n  eq(parse('${1:${aa:${1}}}'),                          { { tabstop = '1', placeholder = { { var = 'aa', placeholder = { { tabstop = '1' } } } } } })\n  eq(parse('${1:${aa:bb$1cc}}'),                        { { tabstop = '1', placeholder = { { var = 'aa', placeholder = { { text = 'bb' }, { tabstop = '1' }, { text = 'cc' } } } } } })\n  eq(parse([[${TM_DIRECTORY/.*src[\\/](.*)/$1/}]]),      { { var = 'TM_DIRECTORY', transform = { [[.*src[\\/](.*)]], '$1', '' } } })\n  eq(parse('${aa/(void$)|(.+)/${1:?-\\treturn nil;}/}'), { { var = 'aa', transform = { '(void$)|(.+)', '${1:?-\\treturn nil;}', '' } } })\n\n  eq(\n    parse('${3:nest1 ${1:nest2 ${2:nest3}}} $3'),\n    {\n      { tabstop = '3', placeholder = { { text = 'nest1 ' }, { tabstop = '1', placeholder = { { text = 'nest2 ' }, { tabstop = '2', placeholder = { { text = 'nest3' } } } } } } },\n      { text = ' ' },\n      { tabstop = '3' },\n    }\n  )\n\n  eq(\n    parse('${1:prog}: ${2:$1.cc} - $2'), -- 'prog: .cc - '\n    {\n      { tabstop = '1', placeholder = { { text = 'prog' } } },\n      { text = ': ' },\n      { tabstop = '2', placeholder = { { tabstop = '1' }, { text = '.cc' } } },\n      { text = ' - ' },\n      { tabstop = '2' },\n    }\n  )\n  eq(\n    parse('${1:prog}: ${3:${2:$1.cc}.33} - $2 $3'), -- 'prog: .cc.33 -  '\n    {\n      { tabstop = '1', placeholder = { { text = 'prog' } } },\n      { text = ': ' },\n      { tabstop = '3', placeholder = { { tabstop = '2', placeholder = { { tabstop = '1' }, { text = '.cc' } } }, { text = '.33' } } },\n      { text = ' - ' },\n      { tabstop = '2' },\n      { text = ' ' },\n      { tabstop = '3' },\n    }\n  )\n  eq(\n    parse('${1:$2.one} <> ${2:$1.two}'), -- '.one <> .two'\n    {\n      { tabstop = '1', placeholder = { { tabstop = '2' }, { text = '.one' } } },\n      { text = ' <> ' },\n      { tabstop = '2', placeholder = { { tabstop = '1' }, { text = '.two' } } },\n    }\n  )\n\n  eq(\n    parse('$1 ${1:aaa} ${1|aa,bb|}'),\n    {\n      { tabstop = \"1\" },\n      { text = \" \" },\n      { tabstop = \"1\", placeholder = { { text = \"aaa\" } } },\n      { text = \" \" },\n      { tabstop = \"1\", choices = { \"aa\", \"bb\" } },\n    }\n  )\nend\n\n--stylua: ignore\nT['parse()']['respects `opts.normalize`'] = function()\n  local validate = function(snippet_body, ref_nodes) eq(parse(snippet_body, { normalize = true }), ref_nodes) end\n  local final_tabstop = { tabstop = '0', placeholder = { { text = '' } } }\n\n  child.fn.setenv('AA', 'my-aa')\n  child.fn.setenv('XX', 'my-xx')\n  -- NOTE: on Windows setting environment variable to empty string is the same\n  -- as deleting it (at least until 2024-07-11 change which enables it)\n  child.fn.setenv('EMPTY', '')\n\n  -- Resolves variables\n  validate('$AA',   { { var = 'AA', text = 'my-aa' }, final_tabstop })\n  validate('${AA}', { { var = 'AA', text = 'my-aa' }, final_tabstop })\n  if not helpers.is_windows() then\n    validate('$EMPTY',            { { var = 'EMPTY', text = '' }, final_tabstop })\n    validate('${EMPTY:fallback}', { { var = 'EMPTY', text = '' }, final_tabstop })\n  end\n\n  -- Ensures text-or-placeholder\n  validate('$1',         { { tabstop = '1', placeholder = { { text = '' } } },                                 final_tabstop })\n  validate('${1}',       { { tabstop = '1', placeholder = { { text = '' } } } ,                                final_tabstop })\n  validate('${1:val}',   { { tabstop = '1', placeholder = { { text = 'val' } } },                              final_tabstop })\n  validate('${1/a/b/c}', { { tabstop = '1', placeholder = { { text = '' } }, transform = { 'a', 'b', 'c' } } , final_tabstop })\n  -- - Should use first choice as placeholder\n  validate('${1|u,v|}',  { { tabstop = '1', placeholder = { { text = 'u' } }, choices = { 'u', 'v' } } ,       final_tabstop })\n\n  validate('$BB',         { { var = 'BB', placeholder = { { text = '' } } },                                final_tabstop })\n  validate('${BB}',       { { var = 'BB', placeholder = { { text = '' } } },                                final_tabstop })\n  validate('${BB:var}',   { { var = 'BB', placeholder = { { text = 'var' } } },                             final_tabstop })\n  validate('${BB/a/b/c}', { { var = 'BB', placeholder = { { text = '' } }, transform = { 'a', 'b', 'c' } }, final_tabstop })\n\n  -- - Should be exclusive OR\n  validate('${AA:var}',       { { var = 'AA', text = 'my-aa' }, final_tabstop })\n  validate('${AA:$1}',        { { var = 'AA', text = 'my-aa' }, final_tabstop })\n  validate('${AA:$XX}',       { { var = 'AA', text = 'my-aa' }, final_tabstop })\n  validate('${AA:${XX:var}}', { { var = 'AA', text = 'my-aa' }, final_tabstop })\n\n  validate('aa', { { text = 'aa' }, final_tabstop })\n\n  -- Should not append final tabstop if there is already one present (however deep)\n  validate('$0',          { { tabstop = '0', placeholder = { { text = '' } } } })\n  validate('${0:text}',   { { tabstop = '0', placeholder = { { text = 'text' } } } })\n  validate('$0$1',        { { tabstop = '0', placeholder = { { text = '' } } },     { tabstop = '1', placeholder = { { text = '' } } } })\n  validate('${0:text}$1', { { tabstop = '0', placeholder = { { text = 'text' } } }, { tabstop = '1', placeholder = { { text = '' } } } })\n  validate('$0text',      { { tabstop = '0', placeholder = { { text = '' } } },     { text = 'text' } })\n\n  -- - But only *exactly* '0' should be treated as final tabstop\n  validate('$00', { { tabstop = '00', placeholder = { { text = '' } } }, final_tabstop })\n\n  -- Should ensure same text in linked tabstops\n  validate('${1:aa}$1',           { { tabstop = '1', placeholder = { { text = 'aa' } } }, { tabstop = '1', placeholder = { { text = 'aa' } } }, final_tabstop })\n  validate('${1:aa}${1:bb}',      { { tabstop = '1', placeholder = { { text = 'aa' } } }, { tabstop = '1', placeholder = { { text = 'aa' } } }, final_tabstop })\n  validate('${1:aa}${1:$2}',      { { tabstop = '1', placeholder = { { text = 'aa' } } }, { tabstop = '1', placeholder = { { text = 'aa' } } }, final_tabstop })\n  validate('${1:aa}${1:${2:bb}}', { { tabstop = '1', placeholder = { { text = 'aa' } } }, { tabstop = '1', placeholder = { { text = 'aa' } } }, final_tabstop })\n  validate('$1${1:aa}',           { { tabstop = '1', placeholder = { { text = '' } } },   { tabstop = '1', placeholder = { { text = '' } } },   final_tabstop })\n  validate('${1}${1:aa}',         { { tabstop = '1', placeholder = { { text = '' } } },   { tabstop = '1', placeholder = { { text = '' } } },   final_tabstop })\n\n  validate('${1:${2:aa}}${2:$1}', {\n    {\n      tabstop = '1',\n      placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } } },\n    },\n    { tabstop = '2', placeholder = { { text = 'aa' } } },\n    final_tabstop,\n  })\n  validate('${2:${1:aa}}${1:$2}', {\n    {\n      tabstop = '2',\n      placeholder = { { tabstop = '1', placeholder = { { text = 'aa' } } } },\n    },\n    { tabstop = '1', placeholder = { { text = 'aa' } } },\n    final_tabstop,\n  })\n\n  validate('${1:aa}${1:$2}', { { tabstop = '1', placeholder = { { text = 'aa' } } }, { tabstop = '1', placeholder = { { text = 'aa' } } }, final_tabstop })\n  validate('${1:${2:aa}}$1', {\n    { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } } } },\n    { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } } } },\n    final_tabstop,\n  })\n  validate('${1:${2:aa}}${2:x$1x}', {\n    { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } } } },\n    { tabstop = '2', placeholder = { { text = 'aa' } } },\n    final_tabstop,\n  })\n\n  validate('${1:$AA}${1:aa}', {\n    { tabstop = '1', placeholder = { { text = 'my-aa', var = 'AA' } } },\n    { tabstop = '1', placeholder = { { text = 'my-aa', var = 'AA' } } },\n    final_tabstop,\n  })\n\n  validate('${1:aa}$2${2:bb}$1', {\n    { tabstop = '1', placeholder = { { text = 'aa' } } },\n    { tabstop = '2', placeholder = { { text = '' } } },\n    { tabstop = '2', placeholder = { { text = '' } } },\n    { tabstop = '1', placeholder = { { text = 'aa' } } },\n    final_tabstop,\n  })\n  validate('${1:${2:aa}bb}$2${2:bb}$1', {\n    {\n      tabstop = '1',\n      placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } }, { text = 'bb' } },\n    },\n    { tabstop = '2', placeholder = { { text = 'aa' } } },\n    { tabstop = '2', placeholder = { { text = 'aa' } } },\n    {\n      tabstop = '1',\n      placeholder = { { tabstop = '2', placeholder = { { text = 'aa' } } }, { text = 'bb' } },\n    },\n    final_tabstop,\n  })\n  validate('${1:$AA}${2:$1}$1$2', {\n    { tabstop = '1', placeholder = { { text = 'my-aa', var = 'AA' } } },\n    {\n      tabstop = '2',\n      placeholder = { { tabstop = '1', placeholder = { { text = 'my-aa', var = 'AA' } } } },\n    },\n    { tabstop = '1', placeholder = { { text = 'my-aa', var = 'AA' } } },\n    {\n      tabstop = '2',\n      placeholder = { { tabstop = '1', placeholder = { { text = 'my-aa', var = 'AA' } } } },\n    },\n    final_tabstop,\n  })\n\n  validate('${1:aa${2:bb}cc$AA}$1', {\n    {\n      tabstop = '1',\n      placeholder = { { text = 'aa' }, { tabstop = '2', placeholder = { { text = 'bb' } } }, { text = 'cc' }, { text = 'my-aa', var = 'AA' } },\n    },\n    {\n      tabstop = '1',\n      placeholder = { { text = 'aa' }, { tabstop = '2', placeholder = { { text = 'bb' } } }, { text = 'cc' }, { text = 'my-aa', var = 'AA' } },\n    },\n    final_tabstop,\n  })\n\n  -- - Nesting same tabstop in placeholder is not allowed\n  expect.error(function() validate('${1:$1}') end, 'Placeholder can not contain its tabstop')\n\n  -- - Should sync `choice` but preserve `transform` (for future)\n  validate('$1${1/.*//}${1|a,b|}', {\n    { tabstop = '1', placeholder = { { text = '' } } },\n    { tabstop = '1', placeholder = { { text = '' } }, transform = { '.*', '', '' } },\n    { tabstop = '1', placeholder = { { text = '' } } },\n    final_tabstop,\n  })\n  validate('${1|a,b|}${1/.*//}$1${1|c,d|}', {\n    { tabstop = '1', placeholder = { { text = 'a' } }, choices = { 'a', 'b' } },\n    { tabstop = '1', placeholder = { { text = 'a' } }, choices = { 'a', 'b' }, transform = { '.*', '', '' } },\n    { tabstop = '1', placeholder = { { text = 'a' } }, choices = { 'a', 'b' } },\n    { tabstop = '1', placeholder = { { text = 'a' } }, choices = { 'a', 'b' } },\n    final_tabstop,\n  })\n\n  -- - Should account for `lookup` resolution\n  eq(\n    parse('${1:aa}$1', { normalize = true, lookup = {['1'] = 'bb'} }),\n    { { tabstop = '1', text = 'bb' }, { tabstop = '1', text = 'bb' }, final_tabstop }\n  )\n\n  -- Should normalize however deep\n  validate('${BB:$1}',       { { var = 'BB',    placeholder = { { tabstop = '1', placeholder = { { text = '' } } } } },                                   final_tabstop })\n  validate('${BB:${1:$CC}}', { { var = 'BB',    placeholder = { { tabstop = '1', placeholder = { { var = 'CC', placeholder = { { text = '' } } } } } } }, final_tabstop })\n  validate('${1:${BB:$CC}}', { { tabstop = '1', placeholder = { { var = 'BB',    placeholder = { { var = 'CC', placeholder = { { text = '' } } } } } } }, final_tabstop })\n\n  validate('${1:${AA:$XX}}', { { tabstop = '1', placeholder = { { var = 'AA',    text = 'my-aa' } } },                                   final_tabstop })\n  validate('${1:${2:$AA}}',  { { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { var = 'AA', text = 'my-aa' } } } } }, final_tabstop })\n\n  validate('${1:$0}',        { { tabstop = '1', placeholder = { { tabstop = '0', placeholder = { { text = '' } } } } }     })\n  validate('${1:${0:text}}', { { tabstop = '1', placeholder = { { tabstop = '0', placeholder = { { text = 'text' } } } } } })\n\n  -- Evaluates variable only once\n  child.lua([[\n    _G.log = {}\n    local os_getenv_orig = vim.loop.os_getenv\n    vim.loop.os_getenv = function(...)\n      table.insert(_G.log, { ... })\n      return os_getenv_orig(...)\n    end\n  ]])\n  validate(\n    '${AA}${AA}${BB}${BB}',\n    {\n      { var = 'AA', text = 'my-aa' }, { var = 'AA', text = 'my-aa' },\n      { var = 'BB', placeholder = { { text = '' } } }, { var = 'BB', placeholder = { { text = '' } } },\n      final_tabstop,\n    }\n  )\n  eq(child.lua_get('_G.log'), { { 'AA' }, { 'BB' } })\n\n  -- - But not persistently\n  child.fn.setenv('AA', '!')\n  child.fn.setenv('BB', '?')\n  validate('${AA}${BB}', { { var = 'AA', text = '!' }, { var = 'BB', text = '?' }, final_tabstop })\nend\n\n--stylua: ignore\nT['parse()']['respects `opts.lookup`'] = function()\n  local validate = function(snippet_body, lookup, ref_nodes)\n    eq(parse(snippet_body, { normalize = true, lookup = lookup }), ref_nodes)\n  end\n  local final_tabstop = { tabstop = '0', placeholder = { { text = '' } } }\n\n  -- Can resolve variables from user lookup\n  validate('$BB', { BB = 'hello' }, { { var = 'BB', text = 'hello' }, final_tabstop })\n  validate('$BB', { BB = 1 },       { { var = 'BB', text = '1' },     final_tabstop })\n\n  -- Should use only string fields\n  eq(\n    child.lua_get('MiniSnippets.parse(\"$true\", { normalize = true, lookup = { [true] = \"x\" } })'),\n    { { var = 'true', placeholder = { { text = '' } } }, final_tabstop }\n  )\n  validate('$1', { [1] = 'x' }, { { tabstop = '1', placeholder = { { text = '' } } }, final_tabstop })\n\n  -- - Should prefer user lookup\n  child.fn.setenv('AA', 'my-aa')\n  child.fn.setenv('XX', 'my-xx')\n  child.fn.setenv('EMPTY', '')\n\n  validate('$AA',    { AA = 'other' },        { { var = 'AA',    text = 'other' },     final_tabstop })\n  validate('$AA',    { AA = '' },             { { var = 'AA',    text = '' },          final_tabstop })\n  validate('$EMPTY', { EMPTY = 'not empty' }, { { var = 'EMPTY', text = 'not empty' }, final_tabstop })\n\n  validate('$AA$XX', { AA = '!', XX = '?' }, { { var = 'AA', text = '!' }, { var = 'XX', text = '?' }, final_tabstop })\n\n  -- Can resolve tabstops from user lookup\n  validate('$1',       { ['1'] = 'hello' }, { { tabstop = '1', text = 'hello' }, final_tabstop })\n  validate('${1}',     { ['1'] = 'hello' }, { { tabstop = '1', text = 'hello' }, final_tabstop })\n  validate('${1:var}', { ['1'] = 'hello' }, { { tabstop = '1', text = 'hello' }, final_tabstop })\n\n  -- - Should resolve all tabstop entries\n  validate(\n    '$1$2$1',\n    { ['1'] = 'hello' },\n    {\n      { tabstop = '1', text = 'hello' },\n      { tabstop = '2', placeholder = { { text = '' } } },\n      { tabstop = '1', text = 'hello' },\n      final_tabstop,\n    }\n  )\n\n  validate('$0', { ['0'] = 'world' }, { { tabstop = '0', text = 'world' } })\n\n  -- - Should use tabstop as is\n  local lookup = { ['1'] = 'hello' }\n  local ref_nodes = { { tabstop = '01', placeholder = { { text = '' } } }, { tabstop = '1', text = 'hello' }, final_tabstop }\n  validate('${01}${1}', lookup, ref_nodes)\n\n  -- - Should resolve on any depth\n  validate('${1:$2}',      { ['2'] = 'xx' }, { { tabstop = '1', placeholder = { { tabstop = '2', text = 'xx' } } }, final_tabstop })\n  validate('${1:${2:$3}}', { ['2'] = 'xx' }, { { tabstop = '1', placeholder = { { tabstop = '2', text = 'xx' } } }, final_tabstop })\n  validate('${1:${2:$3}}', { ['3'] = 'xx' }, { { tabstop = '1', placeholder = { { tabstop = '2', placeholder = { { tabstop = '3', text = 'xx' } } } } }, final_tabstop })\n  validate('${1:${2:$3}}', { ['2'] = 'xx', ['3'] = 'yy' }, { { tabstop = '1', placeholder = { { tabstop = '2', text = 'xx' } } }, final_tabstop })\nend\n\n--stylua: ignore\nT['parse()']['can resolve special variables'] = function()\n  local validate = function(snippet_body, ref_nodes) eq(parse(snippet_body, { normalize = true }), ref_nodes) end\n  local final_tabstop = { tabstop = '0', placeholder = { { text = '' } } }\n\n  local path = test_dir_absolute .. '/snippets/lua.json'\n  child.cmd('edit ' .. child.fn.fnameescape(path))\n  set_lines({ 'abc def', 'ghi' })\n  set_cursor(1, 1)\n  type_keys('yvj', '<Esc>')\n  set_cursor(1, 2)\n\n  -- Mock constant clipboard for better reproducibility of system registers\n  -- (mostly on CI). As `setreg('+', 'clip')` is not guaranteed to be working\n  -- for system clipboard, use `g:clipboard` which copies/pastes directly.\n  child.lua([[\n    local clip = function() return { { 'clip' }, 'v' } end\n    local board = function() return { { 'board' }, 'v' } end\n    vim.g.clipboard = {\n      name  = 'myClipboard',\n      copy  = { ['+'] = clip, ['*'] = board },\n      paste = { ['+'] = clip, ['*'] = board },\n    }\n  ]])\n  child.bo.commentstring = '/* %s */'\n\n  -- LSP\n  validate('$TM_SELECTED_TEXT', { { var = 'TM_SELECTED_TEXT', text = 'bc def\\ng' }, final_tabstop })\n  validate('$TM_CURRENT_LINE',  { { var = 'TM_CURRENT_LINE',  text = 'abc def' },   final_tabstop })\n  validate('$TM_CURRENT_WORD',  { { var = 'TM_CURRENT_WORD',  text = 'abc' },       final_tabstop })\n  validate('$TM_LINE_INDEX',    { { var = 'TM_LINE_INDEX',    text = '0' },         final_tabstop })\n  validate('$TM_LINE_NUMBER',   { { var = 'TM_LINE_NUMBER',   text = '1' },         final_tabstop })\n\n  local validate_path = function(var, ref_text)\n    local nodes = parse(var, { normalize = true })\n    nodes[1].text = nodes[1].text:gsub('\\\\',  '/')\n    eq(nodes, { { var = var:sub(2), text = ref_text }, final_tabstop })\n  end\n  validate_path('$TM_FILENAME',      'lua.json')\n  validate_path('$TM_FILENAME_BASE', 'lua')\n  validate_path('$TM_DIRECTORY',     test_dir_absolute .. '/snippets')\n  validate_path('$TM_FILEPATH',      path)\n\n  -- VS Code\n  validate_path('$RELATIVE_FILEPATH', test_dir .. '/snippets/lua.json')\n  validate_path('$WORKSPACE_FOLDER',  child.fn.getcwd():gsub('\\\\', '/'))\n  validate('$CLIPBOARD',         { { var = 'CLIPBOARD', text = 'clip' },  final_tabstop })\n  validate('$CURSOR_INDEX',      { { var = 'CURSOR_INDEX', text = '2' },  final_tabstop })\n  validate('$CURSOR_NUMBER',     { { var = 'CURSOR_NUMBER', text = '3' }, final_tabstop })\n  validate('$LINE_COMMENT',      { { var = 'LINE_COMMENT', text = '/*' }, final_tabstop })\n\n  -- - Date/time\n  child.lua([[\n    _G.args_log = {}\n    vim.fn.strftime = function(...)\n      table.insert(_G.args_log, { ... })\n      return 'datetime'\n    end\n  ]])\n  local validate_datetime = function(var, ref_strftime_format)\n    child.lua('_G.args_log = {}')\n    validate(var, { { var = var:sub(2), text = 'datetime' }, final_tabstop })\n    eq(child.lua_get('_G.args_log'), { { ref_strftime_format } })\n  end\n\n  validate_datetime('$CURRENT_YEAR',             '%Y')\n  validate_datetime('$CURRENT_YEAR_SHORT',       '%y')\n  validate_datetime('$CURRENT_MONTH',            '%m')\n  validate_datetime('$CURRENT_MONTH_NAME',       '%B')\n  validate_datetime('$CURRENT_MONTH_NAME_SHORT', '%b')\n  validate_datetime('$CURRENT_DATE',             '%d')\n  validate_datetime('$CURRENT_DAY_NAME',         '%A')\n  validate_datetime('$CURRENT_DAY_NAME_SHORT',   '%a')\n  validate_datetime('$CURRENT_HOUR',             '%H')\n  validate_datetime('$CURRENT_MINUTE',           '%M')\n  validate_datetime('$CURRENT_SECOND',           '%S')\n  validate_datetime('$CURRENT_TIMEZONE_OFFSET',  '%z')\n\n  child.lua('os.time = function() return 111 end') -- mock for more robust testing\n  validate('$CURRENT_SECONDS_UNIX', { { var = 'CURRENT_SECONDS_UNIX', text = '111' }, final_tabstop })\n\n  -- Random values\n  child.lua('vim.loop.hrtime = function() return 101 end') -- mock reproducible `math.randomseed`\n  local ref_random = {\n    { var = 'RANDOM', text = '491985' }, { var = 'RANDOM', text = '873024' },\n    { var = 'RANDOM_HEX', text = '10347d' }, { var = 'RANDOM_HEX', text = 'df5ed0' },\n    { var = 'UUID', text = '13d0871f-61d3-464a-b774-28645dca9e3a' }, { var = 'UUID', text = '7bac0382-1057-48d1-9f3b-9b45dbf681e8' },\n    final_tabstop,\n  }\n  validate( '${RANDOM}${RANDOM}${RANDOM_HEX}${RANDOM_HEX}${UUID}${UUID}', ref_random)\n\n  -- - Should prefer user lookup\n  eq(\n    parse('$TM_SELECTED_TEXT', { normalize = true, lookup = { TM_SELECTED_TEXT = 'xxx' } }),\n    { { var = 'TM_SELECTED_TEXT', text = 'xxx' }, final_tabstop }\n  )\n  local random_opts = { normalize = true, lookup = { RANDOM = 'a', RANDOM_HEX = 'b', UUID = 'c' } }\n  local random_nodes = {\n    { var = 'RANDOM',     text = 'a' }, { var = 'RANDOM',     text = 'a' },\n    { var = 'RANDOM_HEX', text = 'b' }, { var = 'RANDOM_HEX', text = 'b' },\n    { var = 'UUID',       text = 'c' }, { var = 'UUID',       text = 'c' },\n    final_tabstop,\n  }\n  eq(parse('${RANDOM}${RANDOM}${RANDOM_HEX}${RANDOM_HEX}${UUID}${UUID}', random_opts), random_nodes)\n\n  -- Should evaluate variable only once\n  child.lua('_G.args_log = {}')\n  eq(\n    parse('${CURRENT_YEAR}${CURRENT_YEAR}${CURRENT_MONTH}${CURRENT_MONTH}', { normalize = true }),\n    {\n      { var = 'CURRENT_YEAR',  text = 'datetime' }, { var = 'CURRENT_YEAR',  text = 'datetime' },\n      { var = 'CURRENT_MONTH', text = 'datetime' }, { var = 'CURRENT_MONTH', text = 'datetime' },\n      final_tabstop,\n    }\n  )\n  eq(child.lua_get('_G.args_log'), { { '%Y' }, { '%m' } })\nend\n\nT['parse()']['throws informative errors'] = function()\n  local validate = function(body, error_pattern)\n    expect.error(function() parse(body) end, error_pattern)\n  end\n\n  -- Parsing\n  validate('${-', '${` should be followed by digit %(in tabstop%) or letter/underscore %(in variable%), not \"%-\"')\n  validate('${ ', '${` should be followed by digit %(in tabstop%) or letter/underscore %(in variable%), not \" \"')\n\n  -- Tabstop\n  -- Should be closed with `}`\n  validate('${1', '\"${\" should be closed with \"}\"')\n  validate('${1a}', 'Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not \"a\"')\n\n  -- Should be followed by either `:` or `}`\n  validate('${1 }', 'Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not \" \"')\n  validate('${1?}', 'Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not \"?\"')\n  validate('${1 |}', 'Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not \" \"')\n\n  -- Choice\n  validate('${1|a', 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1|a|', 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1|a}', 'Tabstop with choices should be closed with \"|}\"')\n  validate([[${1|a\\|}]], 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1|a,b', 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1|a,b}', 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1|a,b|', 'Tabstop with choices should be closed with \"|}\"')\n\n  validate('${1|a,b| $2', 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1|a,b|,c}', 'Tabstop with choices should be closed with \"|}\"')\n\n  -- Variable\n  validate('${a }', 'Variable name should be followed by \"}\", \":\" or \"/\", not \" \"')\n  validate('${a?}', 'Variable name should be followed by \"}\", \":\" or \"/\", not \"?\"')\n  validate('${a :}', 'Variable name should be followed by \"}\", \":\" or \"/\", not \" \"')\n  validate('${a?:}', 'Variable name should be followed by \"}\", \":\" or \"/\", not \"?\"')\n\n  -- Placeholder\n  validate('${1:', 'Placeholder should be closed with \"}\"')\n  validate('${1:a', 'Placeholder should be closed with \"}\"')\n  validate('${1:a bb', 'Placeholder should be closed with \"}\"')\n  validate('${1:${2:a', 'Placeholder should be closed with \"}\"')\n\n  validate([[${1:{$2\\}]], 'Placeholder should be closed with \"}\"')\n  validate([[${1:{$aa\\}]], 'Placeholder should be closed with \"}\"')\n\n  -- - Nested nodes should error according to their rules\n  validate('${1:${2?}}', 'Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not \"?\"')\n  validate('${1:${2?', 'Tabstop id should be followed by \"}\", \":\", \"|\", or \"/\" not \"?\"')\n  validate('${1:${2|a}}', 'Tabstop with choices should be closed with \"|}\"')\n  validate('${1:${a }}', 'Variable name should be followed by \"}\", \":\" or \"/\", not \" \"')\n  validate('${1:${-}}', '${` should be followed by digit %(in tabstop%) or letter/underscore %(in variable%), not \"%-\"')\n\n  -- Transform\n  validate([[${var/regex/format}]], 'Transform should contain 3 \"/\" outside of `${...}` and be closed with \"}\"')\n  validate(\n    [[${var/regex\\/format/options}]],\n    'Transform should contain 3 \"/\" outside of `${...}` and be closed with \"}\"'\n  )\n  validate([[${var/.*/$\\/i}]], 'Transform should contain 3 \"/\" outside of `${...}` and be closed with \"}\"')\n  validate('${var/regex/${/}options}', 'Transform should contain 3 \"/\" outside of `${...}` and be closed with \"}\"')\n\n  validate([[${1/regex/format}]], 'Transform should contain 3 \"/\" outside of `${...}` and be closed with \"}\"')\nend\n\nT['parse()']['validates input'] = function()\n  expect.error(function() parse(1) end, 'Snippet body.*string or array of strings')\nend\n\nT['start_lsp_server()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua([[\n        MiniSnippets.config.snippets = {\n          function(context) return { { prefix = 'ba', body = 'Snippet $1 ba' } } end,\n          { { prefix = 'aa', body = 'Snippet $VAR aa' } },\n          { prefix = 'xx', body = 'Snippet xx', desc = 'XX snippet' },\n        }]])\n    end,\n  },\n})\n\nlocal start_lsp_server = forward_lua('MiniSnippets.start_lsp_server')\n\nlocal make_request = function(client_id)\n  child.lua('_G.client = vim.lsp.get_client_by_id(...)', { client_id })\n  child.lua([[\n    _G.response_log = _G.response_log or {}\n    local params = vim.lsp.util.make_position_params(0, 'utf-16')\n    local handler = function(err, result, context) table.insert(_G.response_log, { err = err, result = result, context = context }) end\n    if vim.fn.has('nvim-0.11') == 1 then\n      _G.client:request('textDocument/completion', params, handler)\n    else\n      _G.client.request('textDocument/completion', params, handler)\n    end\n  ]])\nend\n\nlocal get_client_field = function(client_id, field)\n  return child.lua_get('vim.lsp.get_client_by_id(...).' .. field, { client_id })\nend\n\nlocal validate_lsp_items = function(out, ref)\n  -- LSP server should return array of `CompletionItem`, each properly\n  -- constructed to represent a snippet\n  eq_partial_tbl(out, ref)\n\n  local insert_text_format_snippet = child.lua_get('vim.lsp.protocol.InsertTextFormat.Snippet')\n  local kind_snippet = child.lua_get('vim.lsp.protocol.CompletionItemKind.Snippet')\n  for _, item in ipairs(out) do\n    eq(item.insertTextFormat, insert_text_format_snippet)\n    eq(item.kind, kind_snippet)\n  end\nend\n\nlocal validate_attached_clients = function(buf_id, ref_client_ids)\n  child.lua('_G.buf_id = ' .. buf_id)\n  local attached = child.lua([[\n    local get_active_clients = vim.fn.has('nvim-0.10') == 1 and vim.lsp.get_clients or vim.lsp.get_active_clients\n    return vim.tbl_keys(get_active_clients({ bufnr = _G.buf_id }))\n  ]])\n  eq(attached, ref_client_ids)\nend\n\nT['start_lsp_server()']['works'] = function()\n  local client_id = child.lua([[\n    _G.client_id = MiniSnippets.start_lsp_server()\n    return _G.client_id\n  ]])\n\n  -- Should properly register server\n  eq(get_client_field(client_id, 'name'), 'mini.snippets')\n  local ref_completion_provider = { resolveProvider = false, triggerCharacters = {} }\n  eq(get_client_field(client_id, 'server_capabilities').completionProvider, ref_completion_provider)\n\n  -- Should attach to at least current buffer\n  validate_attached_clients(0, { client_id })\n\n  -- Should properly support 'textDocument/completion' request\n  make_request(client_id)\n  local response_log = child.lua_get('_G.response_log')\n  eq(#response_log, 1)\n  eq(response_log[1].err, nil)\n\n  local ref_items = {\n    { label = 'aa', documentation = 'Snippet $VAR aa', insertText = 'Snippet $VAR aa' },\n    { label = 'ba', documentation = 'Snippet $1 ba', insertText = 'Snippet $1 ba' },\n    { label = 'xx', documentation = 'XX snippet', detail = 'Snippet xx', insertText = 'Snippet xx' },\n  }\n  validate_lsp_items(response_log[1].result, ref_items)\n\n  -- Should provide snippet body as `detail` only if it is different from\n  -- already provided description as `documentation` (which is not rare, as\n  -- `desc` is inferred from `body` if there is no such explicit field)\n  eq(response_log[1].result[1].detail, nil)\n  eq(response_log[1].result[2].detail, nil)\n\n  -- Should match via 'mini.snippets' by default\n  type_keys('i', 'a')\n  make_request(client_id)\n  response_log = child.lua_get('_G.response_log')\n  eq(#response_log, 2)\n  eq(response_log[1].err, nil)\n\n  -- - When matching is done on LSP server side, provide `textEdit` with\n  --   information about which region was used for matching\n  local matched_items = {\n    {\n      label = 'aa',\n      documentation = 'Snippet $VAR aa',\n      textEdit = {\n        newText = 'Snippet $VAR aa',\n        range = { start = { character = 0, line = 0 }, ['end'] = { character = 1, line = 0 } },\n      },\n    },\n    {\n      label = 'ba',\n      documentation = 'Snippet $1 ba',\n      textEdit = {\n        newText = 'Snippet $1 ba',\n        range = { start = { character = 0, line = 0 }, ['end'] = { character = 1, line = 0 } },\n      },\n    },\n  }\n  validate_lsp_items(response_log[2].result, matched_items)\n\n  -- Should not leave dangling \"pending\" requests\n  eq(get_client_field(client_id, 'requests'), {})\nend\n\nT['start_lsp_server()']['sets up auto-attach'] = function()\n  -- Should also attach to already existing loaded normal buffers\n  local buf_id_current = child.api.nvim_create_buf(true, false)\n  set_buf(buf_id_current)\n  local buf_id_normal = child.api.nvim_create_buf(true, false)\n  local buf_id_scratch = child.api.nvim_create_buf(false, true)\n\n  local buf_id_unloaded = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_delete(buf_id_unloaded, { unload = true })\n  eq(child.api.nvim_buf_is_valid(buf_id_unloaded), true)\n  eq(child.api.nvim_buf_is_loaded(buf_id_unloaded), false)\n\n  local client_id = start_lsp_server()\n  validate_attached_clients(buf_id_current, { client_id })\n  validate_attached_clients(buf_id_normal, { client_id })\n  validate_attached_clients(buf_id_scratch, {})\n  validate_attached_clients(buf_id_unloaded, {})\n\n  -- Should auto-attach to buffers on explicit `BufEnter`\n  local buf_id_new = child.api.nvim_create_buf(true, false)\n  validate_attached_clients(buf_id_new, {})\n  child.lua('_G.buf_id_new = ' .. buf_id_new)\n  local buf_id_tmp = child.lua([[\n    local buf_id_tmp = vim.api.nvim_create_buf(true, false)\n    vim.api.nvim_set_current_buf(buf_id_tmp)\n    vim.api.nvim_set_current_buf(buf_id_new)\n    return buf_id_tmp\n  ]])\n  validate_attached_clients(buf_id_new, { client_id })\n  validate_attached_clients(buf_id_tmp, {})\nend\n\nT['start_lsp_server()']['respects `opts.before_attach`'] = function()\n  local client_id = child.lua([[\n    -- Returning explicit `false` should stop attaching to the buffer.\n    -- While returning `nil` should still attach.\n    local before_attach = function(buf_id)\n      if vim.bo[buf_id].filetype == 'python' then return nil end\n      if vim.bo[buf_id].filetype ~= 'lua' then return false end\n    end\n    return MiniSnippets.start_lsp_server({ before_attach = before_attach })\n  ]])\n  validate_attached_clients(0, {})\n\n  child.cmd('edit new.lua')\n  validate_attached_clients(0, { client_id })\n  child.cmd('edit new.py')\n  validate_attached_clients(0, { client_id })\n  child.cmd('edit new.unknown')\n  validate_attached_clients(0, {})\nend\n\nT['start_lsp_server()']['respects `opts.match`'] = function()\n  type_keys('i', 'a')\n\n  local client_id = start_lsp_server({ match = false })\n  make_request(client_id)\n  local response_log = child.lua_get('_G.response_log')\n  eq(#response_log, 1)\n  eq(response_log[1].err, nil)\n\n  -- With `match = false` should return all snippets at context\n  local ref_items = {\n    { label = 'aa', documentation = 'Snippet $VAR aa', insertText = 'Snippet $VAR aa' },\n    { label = 'ba', documentation = 'Snippet $1 ba', insertText = 'Snippet $1 ba' },\n    { label = 'xx', documentation = 'XX snippet', insertText = 'Snippet xx' },\n  }\n  validate_lsp_items(response_log[1].result, ref_items)\nend\n\nT['start_lsp_server()']['respects `opts.server_config`'] = function()\n  local cmd_cwd = child.fn.getcwd() .. '/tests'\n  local client_id = start_lsp_server({ server_config = { cmd_cwd = cmd_cwd } })\n  eq(get_client_field(client_id, 'config.cmd_cwd'), cmd_cwd)\nend\n\nT['start_lsp_server()']['respects `opts.triggers`'] = function()\n  local triggers = { '.', '\\\\' }\n  local client_id = start_lsp_server({ triggers = triggers })\n  eq(get_client_field(client_id, 'server_capabilities').completionProvider.triggerCharacters, triggers)\nend\n\nT['start_lsp_server()']['works with built-in Insert mode completion'] = function()\n  child.bo.omnifunc = 'v:lua.vim.lsp.omnifunc'\n  start_lsp_server()\n\n  type_keys('i', '<C-x>', '<C-o>')\n  local ref_items = child.fn.has('nvim-0.11') == 1 and { 'aa', 'ba', 'xx' }\n    or { 'Snippet  aa', 'Snippet  ba', 'Snippet xx' }\n  validate_pumitems(ref_items)\nend\n\nT['start_lsp_server()']['can be called several times without duplicating servers'] = function()\n  local client_id = start_lsp_server()\n  local client_id_second = start_lsp_server()\n  eq(client_id, client_id_second)\n  validate_attached_clients(0, { client_id })\nend\n\n-- Integration tests ==========================================================\nT['Session'] = new_set()\n\nlocal start_session = function(snippet) default_insert({ body = snippet }) end\n\nT['Session']['cleans extmarks when they are not needed'] = function()\n  local ns_id\n  local validate_n_extmarks = function(ref_n)\n    local session = get()\n    if session ~= vim.NIL then ns_id = session.ns_id end\n    local all_extmarks = child.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, {})\n    eq(#all_extmarks, ref_n)\n  end\n\n  start_session('T1=${1:<$2>}')\n  validate_n_extmarks(9)\n\n  type_keys('x')\n  validate_state('i', { 'T1=x' }, { 1, 4 })\n  validate_n_extmarks(5)\n\n  start_session('U1=$1')\n  validate_n_extmarks(11)\n\n  stop()\n  validate_n_extmarks(5)\n  stop()\n  validate_n_extmarks(0)\nend\n\nT['Session']['persists after `:edit`'] = function()\n  local path = test_dir_absolute .. '/tmp'\n  child.fn.writefile({}, path)\n  MiniTest.finally(function() child.fn.delete(path) end)\n  edit(path)\n\n  start_session('T1=$1 T0=$0')\n  validate_active_session()\n\n  -- NOTE: Write changes as making `:edit!` work is unreasonable\n  child.cmd('write')\n  child.cmd('edit')\n  sleep(small_time)\n\n  -- Ensure expect_screenshot succeeds regardless of actual path\n  child.o.statusline = 'Dummy statusline'\n\n  -- Should preserve both highlighting and data\n  validate_active_session()\n  child.expect_screenshot()\nend\n\nT['Session']['should replace placeholder on added text at its start'] = function()\n  start_session('T1=${1:aaa} T0=$0')\n  type_keys('x')\n  validate_state('i', { 'T1=x T0=' }, { 1, 4 })\n  ensure_clean_state()\n\n  -- No replace on adding text not at start\n  start_session('T1=${1:aaa} T0=$0')\n  type_keys('<Right>', 'x')\n  validate_state('i', { 'T1=axaa T0=' }, { 1, 5 })\n\n  -- - But should still track placeholder range to properly delete later\n  type_keys('<Left>', '<Left>', 'y')\n  validate_state('i', { 'T1=y T0=' }, { 1, 4 })\n  ensure_clean_state()\n\n  -- Should be the same if text is added in Normal mode\n  start_session('T1=${1:aaa} T0=$0')\n  type_keys('<Esc>', 'yl', 'p')\n  validate_state('n', { 'T1== T0=' }, { 1, 3 })\n  ensure_clean_state()\n\n  start_session('T1=${1:aaa} T0=$0')\n  type_keys('<Esc>', '<Right><Right>', 'P')\n  validate_state('n', { 'T1=a=aa T0=' }, { 1, 4 })\n  type_keys('<Left>', 'P')\n  validate_state('n', { 'T1== T0=' }, { 1, 3 })\nend\n\nT['Session']['preserves order of \"squashed\" empty tabstops'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('$1$2$3 $1$3$2 $2$1$3 $2$3$1 $3$1$2 $3$2$1')\n  child.expect_screenshot()\n  jump('next')\n  child.expect_screenshot(screen_opts)\n  jump('next')\n  child.expect_screenshot(screen_opts)\n  ensure_clean_state()\n\n  start_session('$1$2$0')\n  jump('next')\n  child.expect_screenshot(screen_opts)\n  jump('next')\n  child.expect_screenshot(screen_opts)\nend\n\nT['Session']['tracks whole session'] = function()\n  local validate_session_range = function(ref_from, ref_to)\n    local session = get()\n    local data =\n      child.api.nvim_buf_get_extmark_by_id(session.buf_id, session.ns_id, session.extmark_id, { details = true })\n    eq({ data[1], data[2], data[3].end_row, data[3].end_col }, { ref_from[1], ref_from[2], ref_to[1], ref_to[2] })\n  end\n\n  type_keys('i', '----', '<Left><Left>')\n  start_session('T1=${1:aa}_T0=$0')\n  validate_session_range({ 0, 2 }, { 0, 11 })\n\n  -- Typing text inside tabstop should be tracked\n  type_keys('x')\n  validate_session_range({ 0, 2 }, { 0, 10 })\n  type_keys('<CR>')\n  validate_session_range({ 0, 2 }, { 1, 4 })\n\n  -- Modifying text outside of intended snippet session should also be tracked\n  -- with \"expanding\" extmark (right_gravity=false end_right_gravity=true)\n  type_keys('<Esc>')\n  -- - Adding text strictly to the left should move session range\n  type_keys('gg0', 'i', 'new')\n  validate_state('i', { 'new--T1=x', '_T0=--' }, { 1, 3 })\n  validate_session_range({ 0, 5 }, { 1, 4 })\n  -- - Adding text at left edge should count as \"in session range\"\n  type_keys('<Right><Right>', 'wow')\n  validate_state('i', { 'new--wowT1=x', '_T0=--' }, { 1, 8 })\n  validate_session_range({ 0, 5 }, { 1, 4 })\n  -- - Adding text at right edge should count as \"in session range\"\n  --   NOTE: typing text at $0 doesn't stop session as $0 is not current\n  type_keys('<Down><Left><Left>', 'huh')\n  validate_state('i', { 'new--wowT1=x', '_T0=huh--' }, { 2, 7 })\n  validate_session_range({ 0, 5 }, { 1, 7 })\n  -- - Adding text past right edge should not touch session\n  type_keys('<Right>', 'no')\n  validate_state('i', { 'new--wowT1=x', '_T0=huh-no-' }, { 2, 10 })\n  validate_session_range({ 0, 5 }, { 1, 7 })\nend\n\nT['Session']['tracks nodes in case of nested placeholders'] = function()\n  start_session('${1:$2} $1')\n  local ref_nodes = {\n    {\n      tabstop = '1',\n      extmark = { row = 0, col = 0, end_row = 0, end_col = 0 },\n      placeholder = {\n        {\n          tabstop = '2',\n          extmark = { row = 0, col = 0, end_row = 0, end_col = 0 },\n          placeholder = { { text = '', extmark = { row = 0, col = 0, end_row = 0, end_col = 0 } } },\n        },\n      },\n    },\n    { text = ' ' },\n    {\n      tabstop = '1',\n      extmark = { row = 0, col = 1, end_row = 0, end_col = 1 },\n      placeholder = {\n        {\n          tabstop = '2',\n          extmark = { row = 0, col = 1, end_row = 0, end_col = 1 },\n          placeholder = { { text = '', extmark = { row = 0, col = 1, end_row = 0, end_col = 1 } } },\n        },\n      },\n    },\n    { tabstop = '0' },\n  }\n  validate_session_nodes_partial(get(), ref_nodes)\n\n  jump('next')\n  type_keys('xxx')\n  local ref_nodes_after = {\n    {\n      tabstop = '1',\n      -- Should expand parent tabstop's region\n      extmark = { row = 0, col = 0, end_row = 0, end_col = 3 },\n      placeholder = {\n        -- Should correctly track region of reference node\n        { tabstop = '2', extmark = { row = 0, col = 0, end_row = 0, end_col = 3 } },\n      },\n    },\n    { text = ' ' },\n    -- Should expand region in linked tabstops also\n    {\n      tabstop = '1',\n      extmark = { row = 0, col = 4, end_row = 0, end_col = 7 },\n      placeholder = {\n        { tabstop = '2', extmark = { row = 0, col = 4, end_row = 0, end_col = 7 } },\n      },\n    },\n    { tabstop = '0' },\n  }\n  validate_session_nodes_partial(get(), ref_nodes_after)\nend\n\nT['Session']['does not show \"Pattern not found\" message'] = function()\n  child.o.cmdheight = 2\n  child.o.showmode = false\n  child.o.shortmess = child.o.shortmess:gsub('c', '')\n\n  type_keys('i')\n  start_session('T1=$1 T2=${2|aa,bb|} T0=$0')\n  jump('next')\n  stop()\n  child.expect_screenshot()\nend\n\nT['Session']['autostop'] = new_set()\n\nT['Session']['autostop']['works when text is typed with final tabstop being current'] = function()\n  local validate = function(key)\n    start_session('T1=$1 T0=$0')\n    validate_active_session()\n    jump('next')\n    type_keys(key)\n    validate_no_active_session()\n    ensure_clean_state()\n  end\n\n  -- Adding visible character\n  validate('x')\n  validate(' ')\n  validate('\\t')\n\n  -- Adding invisible character\n  validate('<CR>')\n\n  -- Deleting\n  validate('<BS>')\n  validate('<C-u>')\n\n  -- Making text not in pure Insert mode\n  validate('<C-o>o')\n  validate('<C-o>guu')\nend\n\nT['Session']['autostop']['works when exiting to Normal mode in final tabstop'] = function()\n  start_session('T1=$1 T0=$0')\n  validate_active_session()\n  jump('next')\n  type_keys('<Esc>')\n  validate_no_active_session()\n  ensure_clean_state()\n\n  -- Should stop only when exiting in full Normal mode\n  start_session('T1=$1 T0=$0')\n  jump('next')\n  type_keys('<C-o><Esc>')\n  validate_active_session()\nend\n\nT['Session']['autostop']['works when final tabstop has explicit placeholder'] = function()\n  -- Typing should remove placeholder and keep Insert mode\n  start_session('T1=$1 T0=${0:aaa}')\n  jump('next')\n  validate_state('i', { 'T1= T0=aaa' }, { 1, 7 })\n\n  type_keys('x')\n  validate_no_active_session()\n  validate_state('i', { 'T1= T0=x' }, { 1, 8 })\n\n  ensure_clean_state()\n\n  -- Exiting in Normal mode should preserve placeholder\n  start_session('T1=$1 T0=${0:aaa}')\n  jump('next')\n  type_keys('<Esc>')\n  validate_no_active_session()\n  validate_state('n', { 'T1= T0=aaa' }, { 1, 6 })\nend\n\nT['Session']['autostop']['is not triggered if final tabstop is not current'] = function()\n  start_session('T1=$1 T0=$0')\n  validate_active_session()\n\n  -- Exiting into Normal mode should still keep session active\n  type_keys('<Esc>')\n  validate_active_session()\n\n  -- Typing at final tabstop should not autostop because it is not current\n  type_keys('A', 'new')\n  validate_active_session()\n  child.expect_screenshot()\n\n  -- Should still be possible to autostop even though final tabstop is moved\n  jump('next')\n  type_keys('x')\n  validate_no_active_session()\nend\n\nT['Session']['highlighting'] = new_set()\n\nlocal validate_tabstop_hl = function(ref_extmark_data, session)\n  session = session or get()\n  local buf_id, ns_id = session.buf_id, session.ns_id\n  local has_inline_extmarks = child.fn.has('nvim-0.10') == 1\n\n  local out = {}\n  local record_tabstop_extmark\n  record_tabstop_extmark = function(n_arr)\n    for _, n in ipairs(n_arr) do\n      if n.tabstop ~= nil then\n        local data = child.api.nvim_buf_get_extmark_by_id(buf_id, ns_id, n.extmark_id, { details = true })\n        local t = {\n          tabstop = n.tabstop,\n          hl_group = data[3].hl_group,\n          virt_text = data[3].virt_text,\n          virt_text_pos = data[3].virt_text_pos,\n        }\n        table.insert(out, t)\n      end\n      if n.placeholder ~= nil then record_tabstop_extmark(n.placeholder) end\n    end\n  end\n  record_tabstop_extmark(session.nodes)\n\n  if not has_inline_extmarks then\n    ref_extmark_data = vim.tbl_map(function(x)\n      x.virt_text, x.virt_text_pos = nil, nil\n      return x\n    end, vim.deepcopy(ref_extmark_data))\n  end\n\n  eq(out, ref_extmark_data)\nend\n\nT['Session']['highlighting']['updates current/visited/unvisited/final'] = function()\n  start_session('T1=${1:aa} T2=$2 T3=${3:cc} T0=$0')\n  local ref_extmark_data = {\n    -- Initial tabstop should be \"*Current*\", not \"*Visited\"\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrentReplace' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', hl_group = 'MiniSnippetsUnvisited' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  -- Changing focused tabstop should update highlight groups accordingly\n  jump('next')\n  ref_extmark_data = {\n    -- Already visited are marked as \"*Visited\"\n    { tabstop = '1', hl_group = 'MiniSnippetsVisited' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', hl_group = 'MiniSnippetsUnvisited' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  -- Revisiting back should again mark as current but keep \"visited\" for others\n  jump('prev')\n  ref_extmark_data = {\n    -- Revisiting should not make a difference for current tabstop\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrentReplace' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', hl_group = 'MiniSnippetsUnvisited' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  -- Jumping left should properly not mark skipped tabstops as visited\n  jump('prev')\n  ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsVisited' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', hl_group = 'MiniSnippetsUnvisited' },\n    -- Current final is marked as \"*CurrentReplace\" as there is a placeholder\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\nend\n\nT['Session']['highlighting']['updates after replacing placeholder'] = function()\n  start_session('T1=$1 T1=${1:aa}')\n  local ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  -- Should switch to \"*Current\" as there is no replacing\n  type_keys('x')\n  ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrent' },\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrent' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  -- Going back should still use \"*Current\" as there is still no replacing\n  jump('next')\n  jump('prev')\n  ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrent' },\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrent' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\nend\n\n--stylua: ignore\nT['Session']['highlighting']['uses same highlight groups for linked tabstops'] = function()\n  start_session('T1=$1 T1=${1:aa} T1=${1|bb,cc|} T2=$2 T2=${2:dd}')\n  local ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    -- All are empty as they are normalized to the same placeholder/text\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  jump('next')\n  ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\nend\n\nT['Session']['highlighting']['properly highlights final tabstop'] = function()\n  -- Should still be highlighted as \"*CurrentReplace\" if automatically added\n  start_session('T1=$1')\n  jump('next')\n  local ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  ensure_clean_state()\n\n  -- Should highlight with explicit placeholder\n  start_session('T1=$1 T0=${0:aa}')\n  jump('next')\n  ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', hl_group = 'MiniSnippetsCurrentReplace' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  ensure_clean_state()\n\n  -- Should never use \"visited\"/\"unvisited\" groups\n  start_session('T1=$1 T0=$0')\n  jump('next')\n  jump('prev')\n  ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  ensure_clean_state()\n\n  -- Works with linked final tabstops (although this snippet makes small sense)\n  start_session('T1=$1 T0=$0 T0=$0')\n  ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  jump('next')\n  ref_extmark_data = {\n    { tabstop = '1', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  ensure_clean_state()\n\n  -- Should treat strictly only $0 as final\n  start_session('$00 $0')\n  ref_extmark_data = {\n    { tabstop = '00', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\nend\n\nT['Session']['highlighting']['uses same highlighting for whole placeholder for current tabstop'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('T1=${1:<T2=${2:$3}>} $2 $0 $3')\n  local ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrentReplace' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  child.expect_screenshot()\n\n  jump('next')\n  ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsVisited' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsUnvisited' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  child.expect_screenshot(screen_opts)\n\n  jump('next')\n  ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsVisited' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '2', virt_text = { { '•', 'MiniSnippetsVisited' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n    { tabstop = '3', virt_text = { { '•', 'MiniSnippetsCurrentReplace' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n  child.expect_screenshot(screen_opts)\nend\n\nT['Session']['highlighting']['hides when nesting'] = function()\n  start_session('T1=${1:aa} T0=$0')\n  local prev_session = get()\n  local ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrentReplace' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data)\n\n  start_session('U1=${1:aa} U0=$0')\n  local cur_session = get()\n\n  -- No highlighting attributes should be set in previous session\n  validate_tabstop_hl({ { tabstop = '1' }, { tabstop = '0' } }, prev_session)\n  -- - Current session should be highlighted\n  ref_extmark_data = {\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrentReplace' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data, cur_session)\n\n  stop()\n  ref_extmark_data = {\n    -- Highlight group changed '*CurrentReplace' -> '*Current' as there was\n    -- text change (nested session text) at the start of tabstop's placeholder\n    { tabstop = '1', hl_group = 'MiniSnippetsCurrent' },\n    { tabstop = '0', virt_text = { { '∎', 'MiniSnippetsFinal' } }, virt_text_pos = 'inline' },\n  }\n  validate_tabstop_hl(ref_extmark_data, prev_session)\nend\n\nT['Session']['choices'] = new_set()\n\nT['Session']['choices']['works'] = function()\n  start_session('T1=${1|aa,bb|} T2=${2|dd,cc|}')\n  child.expect_screenshot()\n\n  -- Should show first choice as placeholder (not as text)\n  eq_partial_tbl(get().nodes[2], { tabstop = '1', placeholder = { { text = 'aa' } }, choices = { 'aa', 'bb' } })\n  eq_partial_tbl(get().nodes[4], { tabstop = '2', placeholder = { { text = 'dd' } }, choices = { 'dd', 'cc' } })\n\n  -- Should show choices initially\n  validate_pumitems({ 'aa', 'bb' })\n\n  -- Initial select should replace placeholder with first choice\n  validate_state('i', { 'T1=aa T2=dd' }, { 1, 3 })\n  type_keys('<C-n>')\n  eq_partial_tbl(get().nodes[2], { tabstop = '1', text = 'aa', choices = { 'aa', 'bb' } })\n  eq(get().nodes[2].placeholder, nil)\n  validate_state('i', { 'T1=aa T2=dd' }, { 1, 5 })\n\n  -- Removing text back to empty text should reshow all choices\n  type_keys('<BS>', '<C-y>')\n  validate_no_pumvisible()\n  type_keys('<BS>')\n  validate_pumitems({ 'aa', 'bb' })\n  -- - Should still show inline virtual text\n  child.expect_screenshot()\nend\n\nT['Session']['choices']['are shown only when needed'] = function()\n  start_session('T1=${1|aa,bb|} T2=${2|dd,cc|}')\n\n  -- Initially\n  validate_pumitems({ 'aa', 'bb' })\n\n  -- After jumps\n  jump('next')\n  validate_pumitems({ 'dd', 'cc' })\n\n  -- Not when editing non-empty text (to not conflict with autocompletion)\n  type_keys('d', 'x')\n  validate_no_pumvisible()\n  type_keys('<BS>')\n  validate_no_pumvisible()\n\n  -- Not when editing text with current tabstop having no text\n  jump('prev')\n  type_keys(' ', '<BS>')\n  validate_pumitems({ 'aa', 'bb' })\n  type_keys('<Left>', '<Left>')\n  type_keys('x')\n  validate_no_pumvisible()\nend\n\nT['Session']['choices']['are always shown all at once'] = function()\n  default_insert({ body = 'T1=${1|aa,bb|} T2=${2|dd,cc|}' }, { lookup = { ['2'] = 'd' } })\n  validate_state('i', { 'T1=aa T2=d' }, { 1, 3 })\n\n  -- Immediately after start\n  validate_pumitems({ 'aa', 'bb' })\n\n  -- After jump\n  jump('next')\n  jump('prev')\n  validate_pumitems({ 'aa', 'bb' })\n\n  -- Can be narrowed down by typing\n  type_keys('bb')\n  child.expect_screenshot()\n\n  -- Reappear after deleting tabstop text\n  type_keys('<C-w>')\n  child.expect_screenshot()\n\n  -- If text is \"forced\" via lookup\n  jump('next')\n  child.expect_screenshot()\nend\n\nT['Session']['choices'][\"work with default 'completeopt'\"] = function()\n  child.o.completeopt = 'menu,preview'\n  start_session('T1=${1|aa,bb|} T2=${2|dd,cc|}')\n  child.expect_screenshot()\n\n  -- As there is no 'noselect', first choice is selected immediately\n  -- and thus replaces placeholder\n  eq_partial_tbl(get().nodes[2], { tabstop = '1', text = 'aa', choices = { 'aa', 'bb' } })\n\n  -- Showing choices at empty text automatically selects first item\n  type_keys('<BS>')\n  type_keys('<BS>')\n  child.expect_screenshot()\nend\n\nT['Session']['choices']['selecting completion item properly replaces current text'] = function()\n  start_session('T1=${1|axax,yy|}')\n  type_keys('xx')\n  jump('next')\n  jump('prev')\n\n  validate_pumitems({ 'axax', 'yy' })\n  type_keys('<C-n>')\n  validate_state('i', { 'T1=axax' }, { 1, 7 })\nend\n\nT['Session']['choices']['handles linked tabstops with different choices'] = function()\n  -- Should resolve all initial text to be the same while removing choices from\n  -- the repeated nodes (as redundant)\n  start_session('T1=${1|aa,bb|} T1=${1|uu,vv|}')\n  validate_active_session()\n  validate_state('i', { 'T1=aa T1=aa' }, { 1, 3 })\n  -- Should only use choices from reference node\n  validate_pumitems({ 'aa', 'bb' })\n  jump('next')\n  eq(get_cur_tabstop(), '0')\nend\n\nT['Session']['linked tabstops'] = new_set()\n\nT['Session']['linked tabstops']['are updated immediately when typing'] = function()\n  start_session('T1=$1_T1=$1')\n  type_keys('a')\n  validate_state('i', { 'T1=a_T1=a' }, { 1, 4 })\n\n  -- Even after jumping back\n  jump('next')\n  jump('prev')\n  type_keys('b')\n  validate_state('i', { 'T1=ab_T1=ab' }, { 1, 5 })\n  child.expect_screenshot()\n\n  -- Even multiline\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('Multiline text sync has issues with cursor on Neovim<0.10') end\n  type_keys('<CR>')\n  validate_state('i', { 'T1=ab', '_T1=ab', '' }, { 2, 0 })\n  child.expect_screenshot()\n  type_keys('c')\n  validate_state('i', { 'T1=ab', 'c_T1=ab', 'c' }, { 2, 1 })\n  child.expect_screenshot()\nend\n\nT['Session']['linked tabstops']['are updated immediately when deleting text'] = function()\n  start_session('$1\\n$1')\n  type_keys('a bcd')\n  validate_state('i', { 'a bcd', 'a bcd' }, { 1, 5 })\n\n  type_keys('<BS>')\n  validate_state('i', { 'a bc', 'a bc' }, { 1, 4 })\n\n  type_keys('<C-w>')\n  validate_state('i', { 'a ', 'a ' }, { 1, 2 })\n\n  type_keys('<C-u>')\n  validate_state('i', { '', '' }, { 1, 0 })\nend\n\nT['Session']['linked tabstops']['are updated on text change in Normal mode'] = function()\n  start_session('$1\\n$1')\n  type_keys('ab cd')\n  validate_state('i', { 'ab cd', 'ab cd' }, { 1, 5 })\n\n  type_keys('<Esc>', 'daw')\n  validate_state('n', { 'ab', 'ab' }, { 1, 1 })\n\n  type_keys('0', 'P')\n  validate_state('n', { ' cdab', ' cdab' }, { 1, 2 })\nend\n\nT['Session']['linked tabstops']['are updated when completion popup is visible'] = function()\n  start_session('aa bb $1 $1')\n  type_keys('<C-x><C-n>')\n  validate_pumitems({ 'aa', 'bb' })\n  validate_state('i', { 'aa bb  ' }, { 1, 6 })\n\n  type_keys('a')\n  validate_state('i', { 'aa bb a a' }, { 1, 7 })\n\n  type_keys('<C-n>')\n  validate_state('i', { 'aa bb aa aa' }, { 1, 8 })\nend\n\nT['Session']['linked tabstops']['delay updating in nested session until stop'] = function()\n  start_session('T1=$1 T1=$1')\n  validate_state('i', { 'T1= T1=' }, { 1, 3 })\n\n  start_session('U1=$1 U1=$1')\n  -- Update right after start to remove placeholder from current session\n  validate_state('i', { 'T1=U1= U1= T1=U1= U1=' }, { 1, 6 })\n\n  -- No update on second `$1` from previous session\n  validate_state('i', { 'T1=U1= U1= T1=U1= U1=' }, { 1, 6 })\n\n  -- Should work with deeper nesting\n  start_session('$1')\n  type_keys('x')\n  validate_state('i', { 'T1=U1=x U1= T1=U1= U1=' }, { 1, 7 })\n\n  -- Should linked tabstops in previous after stopping current\n  stop()\n  validate_state('i', { 'T1=U1=x U1=x T1=U1= U1=' }, { 1, 7 })\n\n  stop()\n  validate_state('i', { 'T1=U1=x U1=x T1=U1=x U1=x' }, { 1, 7 })\nend\n\nT['Session']['linked tabstops']['works for tabstops with different placeholders'] = function()\n  -- Should be resolved to have same placeholder during `parse()`\n  start_session('T1=${1:aa} T1=${1:bb} T1=$1')\n  validate_state('i', { 'T1=aa T1=aa T1=aa' }, { 1, 3 })\n  type_keys('x')\n  validate_state('i', { 'T1=x T1=x T1=x' }, { 1, 4 })\n  ensure_clean_state()\n\n  -- Even if have different initial types\n  start_session('T1=$1 T1=${1:aa} T1=${1|bb,cc|}')\n  validate_state('i', { 'T1= T1= T1=' }, { 1, 3 })\n  type_keys('x')\n  validate_state('i', { 'T1=x T1=x T1=x' }, { 1, 4 })\nend\n\n--stylua: ignore\nT['Session']['linked tabstops']['have proper extmark tracking'] = function()\n  local validate = function(ref_nodes) validate_session_nodes_partial(get(), ref_nodes) end\n\n  -- As placeholder in another tabstop\n  start_session('${1:aaa}\\n${2:${3:$1}}')\n  local ref_nodes = {\n    {\n      tabstop = '1',\n      extmark = { row = 0, col = 0, end_row = 0, end_col = 3 },\n      placeholder = { {\n        text = 'aaa',\n        extmark = { row = 0, col = 0, end_row = 0, end_col = 3 },\n      } },\n    },\n    { text = '\\n', extmark = { row = 0, col = 3, end_row = 1, end_col = 0 } },\n    {\n      tabstop = '2',\n      extmark = { row = 1, col = 0, end_row = 1, end_col = 3 },\n      placeholder = { {\n        tabstop = '3',\n        extmark = { row = 1, col = 0, end_row = 1, end_col = 3 },\n        placeholder = { {\n            tabstop = '1',\n            extmark = { row = 1, col = 0, end_row = 1, end_col = 3 },\n            placeholder = { {\n              text = 'aaa',\n              extmark = { row = 1, col = 0, end_row = 1, end_col = 3 },\n            } },\n        } },\n      } },\n    },\n    { tabstop = '0' },\n  }\n  validate(ref_nodes)\n\n  type_keys('bbb')\n  local ref_nodes_2 = vim.deepcopy(ref_nodes)\n  ref_nodes_2[1].placeholder, ref_nodes_2[1].text = nil, 'bbb'\n  ref_nodes_2[3].placeholder[1].placeholder[1].placeholder = nil\n  ref_nodes_2[3].placeholder[1].placeholder[1].text = 'bbb'\n  validate(ref_nodes_2)\n\n  ensure_clean_state()\n\n  -- As placeholder in variable\n  start_session('${1:aaa}\\n${AAA:${3:$1}}')\n  ref_nodes[3].tabstop, ref_nodes[3].var = nil, 'AAA'\n  validate(ref_nodes)\n\n  type_keys('bbb')\n  ref_nodes_2[3].tabstop, ref_nodes_2[3].var = nil, 'AAA'\n  validate(ref_nodes_2)\n\n  ensure_clean_state()\nend\n\nT['Session']['linked tabstops']['jumps to the first node'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('T1=${1:<T2=$2>} T2=$2 T1=$1')\n  validate_state('i', { 'T1=<T2=> T2= T1=<T2=>' }, { 1, 3 })\n  child.expect_screenshot()\n\n  jump('next')\n  validate_state('i', { 'T1=<T2=> T2= T1=<T2=>' }, { 1, 7 })\n  child.expect_screenshot(screen_opts)\n\n  -- Even if first node for linked tabstops is changed\n  jump('prev')\n  type_keys('x')\n  validate_state('i', { 'T1=x T2= T1=x' }, { 1, 4 })\n  jump('next')\n  validate_state('i', { 'T1=x T2= T1=x' }, { 1, 8 })\n  child.expect_screenshot()\nend\n\nT['Session']['linked tabstops']['validates that session data is valid'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n  local ref_msg = '(mini.snippets) Session contains corrupted data (deleted or out of range extmarks). It is stopped.'\n\n  -- Forcefully removed extmarks\n  start_session('T1=$1\\nT0=$0')\n  child.api.nvim_buf_clear_namespace(0, get().ns_id, 0, -1)\n  validate_active_session()\n\n  type_keys('x')\n  validate_no_active_session()\n  eq(child.lua_get('_G.notify_log'), { { ref_msg, 'WARN' } })\n  child.lua('_G.notify_log = {}')\n  child.expect_screenshot(screen_opts)\n\n  ensure_clean_state()\n\n  -- Out of range extmarks\n  start_session('T1=$1\\nT0=$0')\n  type_keys('<Esc>', 'j', 'dd')\n  validate_no_active_session()\n  eq(child.lua_get('_G.notify_log'), { { ref_msg, 'WARN' } })\n  child.expect_screenshot()\nend\n\nT['Session']['linked tabstops']['handle text change in not reference node'] = function()\n  start_session('T1=${1:aa} T1=${1:aa} T1=${1:aa}')\n  validate_state('i', { 'T1=aa T1=aa T1=aa' }, { 1, 3 })\n\n  -- Any text change is allowed if tabstops are still in \"replace\" stage\n  set_cursor(1, 10)\n  type_keys('x')\n  validate_state('i', { 'T1=aa T1=axa T1=aa' }, { 1, 11 })\n\n  -- Should still track changes and replace appropriately\n  jump('next')\n  jump('prev')\n  type_keys('yy')\n  validate_state('i', { 'T1=yy T1=yy T1=yy' }, { 1, 5 })\n\n  -- After placeholder is replaced, all linked tabstops should be forced to\n  -- have same text as the first (reference) node\n  set_cursor(1, 10)\n  type_keys('A')\n  validate_state('i', { 'T1=yy T1=yy T1=yy' }, { 1, 11 })\n\n  set_cursor(1, 16)\n  type_keys('B')\n  validate_state('i', { 'T1=yy T1=yy T1=yy' }, { 1, 17 })\nend\n\nT['Session']['relative indent'] = new_set()\n\nT['Session']['relative indent']['is preserved'] = function()\n  start_session('\\tT1=$1\\n\\t\\t$1\\n$1')\n  validate_state('i', { '\\tT1=', '\\t\\t', '' }, { 1, 4 })\n\n  type_keys('xx', '<CR>')\n  validate_state('i', { '\\tT1=xx', '\\t', '\\t\\txx', '\\t\\t', 'xx', '' }, { 2, 1 })\n\n  type_keys('yy')\n  validate_state('i', { '\\tT1=xx', '\\tyy', '\\t\\txx', '\\t\\tyy', 'xx', 'yy' }, { 2, 3 })\n\n  -- Should adjust on every sync (even if typing outside of tabstop range)\n  set_cursor(3, 1)\n  type_keys('<BS>')\n  validate_state('i', { '\\tT1=xx', '\\tyy', '\\txx', '\\tyy', 'xx', 'yy' }, { 3, 0 })\nend\n\nT['Session']['relative indent']['is preserved inside placeholder'] = function()\n  start_session('$1\\n\\t${2:$1}')\n  type_keys('aa<CR>bb')\n  validate_state('i', { 'aa', 'bb', '\\taa', '\\tbb' }, { 2, 2 })\n  ensure_clean_state()\n\n  start_session('$1\\n${2:\\t$1}')\n  type_keys('aa<CR>bb')\n  validate_state('i', { 'aa', 'bb', '\\taa', '\\tbb' }, { 2, 2 })\nend\n\nT['Session']['relative indent']['dedents reference text based on smallest indent'] = function()\n  start_session('\\t$1\\n\\t\\t$1')\n  type_keys('aa', '<CR><BS>', 'bb')\n  validate_state('i', { '\\taa', 'bb', '\\t\\taa', '\\t\\tbb' }, { 2, 2 })\n  type_keys('<Left><Left>', '\\t')\n  validate_state('i', { '\\taa', '\\tbb', '\\t\\taa', '\\t\\tbb' }, { 2, 1 })\n  type_keys('\\t')\n  validate_state('i', { '\\taa', '\\t\\tbb', '\\t\\taa', '\\t\\t\\tbb' }, { 2, 2 })\nend\n\nT['Session']['relative indent']['dedents reference text ignoring \"pure indent\" lines during dedent'] = function()\n  type_keys('i', '  ')\n  start_session('$1\\n\\t$1')\n\n  type_keys('aa<CR><CR>bb')\n  -- \"Pure indent\" lines should still be reindented\n  validate_state('i', { '  aa', '', '  bb', '  \\taa', '  \\t', '  \\tbb' }, { 3, 4 })\nend\n\nT['Session']['relative indent']['respects comments'] = function()\n  child.bo.commentstring = '# %s'\n\n  type_keys('i', '  #  ')\n  start_session('$1\\n\\t$1')\n  validate_state('i', { '  #  ', '  #  \\t' }, { 1, 5 })\n\n  type_keys('aa<CR>bb')\n  validate_state('i', { '  #  aa', '  bb', '  #  \\taa', '  #  \\tbb' }, { 2, 4 })\n\n  type_keys('<Left><Left>#  ')\n  validate_state('i', { '  #  aa', '  #  bb', '  #  \\taa', '  #  \\tbb' }, { 2, 5 })\n\n  type_keys(' ')\n  validate_state('i', { '  #  aa', '  #   bb', '  #  \\taa', '  #  \\t bb' }, { 2, 6 })\nend\n\nT['Session']['relative indent']['does not use tabstop text during dedent'] = function()\n  start_session('  $1\\n\\t$1')\n  type_keys('  aa', '<CR>', 'bb')\n  validate_state('i', { '    aa', '    bb', '\\t  aa', '\\t  bb' }, { 2, 6 })\nend\n\nT['Session']['nesting'] = new_set({ hooks = { pre_case = setup_event_log } })\n\nT['Session']['nesting']['works and triggers events'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n  local body_1, body_2, body_3 = 'T1=$1 T0=$0', 'U1=$1 U0=$0', 'V1=$1 V0=$0'\n\n  start_session(body_1)\n  validate_n_sessions(1)\n  eq(get_snippet_body(get()), body_1)\n  child.expect_screenshot()\n\n  start_session(body_2)\n  eq(get_snippet_body(get()), body_2)\n  validate_n_sessions(2)\n  -- Highlighting of previous session should stop, but should still track\n  child.expect_screenshot(screen_opts)\n\n  start_session(body_3)\n  -- Any user typing in nested session should be tracked in all other sessions\n  type_keys('vvv')\n  eq(get_snippet_body(get()), body_3)\n  validate_n_sessions(3)\n  child.expect_screenshot()\n\n  -- Jumping inside nested session should be done only within its tabstops\n  jump('next')\n  eq(get_cursor(), { 1, 16 })\n  -- - Along with wrapping\n  jump('next')\n  eq(get_cursor(), { 1, 12 })\n\n  stop()\n  eq(get_snippet_body(get()), body_2)\n  validate_n_sessions(2)\n  -- Tabstop range of previous session should track changes in nested ones\n  child.expect_screenshot(screen_opts)\n\n  stop()\n  validate_n_sessions(1)\n  eq(get_snippet_body(get()), body_1)\n  child.expect_screenshot(screen_opts)\n\n  stop()\n\n  -- Should trigger proper events in proper order\n  local make_ref_data = function(snippet_body)\n    return { session = { insert_args = { snippet = { body = snippet_body } } } }\n  end\n  local cur_buf_id = get_buf()\n  --stylua: ignore\n  local ref_au_log_partial = {\n    { event = 'MiniSnippetsSessionStart',   data = make_ref_data(body_1), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionSuspend', data = make_ref_data(body_1), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionStart',   data = make_ref_data(body_2), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionSuspend', data = make_ref_data(body_2), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionStart',   data = make_ref_data(body_3), buf_id = cur_buf_id },\n\n    { event = 'MiniSnippetsSessionJumpPre', data = { tabstop_from = '1', tabstop_to = '0' }, buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionJump',    data = { tabstop_from = '1', tabstop_to = '0' }, buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionJumpPre', data = { tabstop_from = '0', tabstop_to = '1' }, buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionJump',    data = { tabstop_from = '0', tabstop_to = '1' }, buf_id = cur_buf_id },\n\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(body_3), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionResume', data = make_ref_data(body_2), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(body_2), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionResume', data = make_ref_data(body_1), buf_id = cur_buf_id },\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(body_1), buf_id = cur_buf_id },\n  }\n  eq_partial_tbl(get_au_log(), ref_au_log_partial)\nend\n\nT['Session']['nesting']['does not nest if no tabstops in new session'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('T1=$1 T0=$0')\n  start_session('just text')\n  validate_n_sessions(1)\n  child.expect_screenshot(screen_opts)\nend\n\nT['Session']['nesting']['resuming session should not change mode/cursor/buffer'] = function()\n  -- Resuming in current buffer\n  start_session('T1=$1\\nT0=$0\\n')\n  type_keys('<Down><Down>')\n  start_session('U1=$1 U0=$0')\n  jump('next')\n\n  validate_state('i', { 'T1=', 'T0=', 'U1= U0=' }, { 3, 7 })\n  validate_n_sessions(2)\n  type_keys('x')\n  validate_state('i', { 'T1=', 'T0=', 'U1= U0=x' }, { 3, 8 })\n  validate_n_sessions(1)\n  eq(get_snippet_body(), 'T1=$1\\nT0=$0\\n')\n\n  ensure_clean_state()\n\n  -- Resuming in another buffer\n  start_session('T1=$1 T0=$0')\n  child.ensure_normal_mode()\n  local new_buf_id = new_buf()\n  set_buf(new_buf_id)\n  start_session('U1=$1 U0=$0')\n\n  jump('next')\n  eq(child.fn.mode(), 'i')\n  eq(get_cur_tabstop(), '0')\n  type_keys('<Esc>')\n  -- Should not change mode or buffer\n  eq(child.fn.mode(), 'n')\n  eq(get_buf(), new_buf_id)\nend\n\nT['Session']['nesting']['can be done outside of current session region'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('T1=$1 T0=$0')\n  type_keys('<Esc>', 'o', '<CR>')\n  start_session('U1=$1 U0=$0')\n  validate_n_sessions(2)\n  child.expect_screenshot(screen_opts)\nend\n\nT['Session']['nesting']['can be done in different buffer'] = function()\n  start_session('T1=$1 T0=$0')\n  child.ensure_normal_mode()\n  local prev_buf_id, new_buf_id = get_buf(), new_buf()\n  set_buf(new_buf_id)\n  start_session('U1=$1 U0=$0')\n\n  validate_n_sessions(2)\n  eq(get_buf(), new_buf_id)\n  eq_partial_tbl(get(), { buf_id = new_buf_id, insert_args = { snippet = { body = 'U1=$1 U0=$0' } } })\n\n  -- Stopping session should not change buffer or jump\n  stop()\n  eq_partial_tbl(get(), { buf_id = prev_buf_id, insert_args = { snippet = { body = 'T1=$1 T0=$0' } } })\n  eq(get_buf(), new_buf_id)\n  validate_state('i', { 'U1= U0=' }, { 1, 3 })\nend\n\nT['Session']['nesting']['session stack is properly cleaned when buffer is unloaded'] = function()\n  local buf_id_1, buf_id_2, buf_id_3 = new_buf(), new_buf(), new_buf()\n  local body_1, body_2, body_3, body_4 = 'T1=$1 T0=$0', 'U1=$1 U0=$0', 'V1=$1 V0=$0', 'W1=$1 W0=$0'\n  set_buf(buf_id_1)\n  start_session(body_1)\n  set_buf(buf_id_2)\n  start_session(body_2)\n  set_buf(buf_id_3)\n  start_session(body_3)\n  start_session(body_4)\n\n  local ref_sessions = {\n    { buf_id = buf_id_1, insert_args = { snippet = { body = body_1 } } },\n    { buf_id = buf_id_2, insert_args = { snippet = { body = body_2 } } },\n    { buf_id = buf_id_3, insert_args = { snippet = { body = body_3 } } },\n    { buf_id = buf_id_3, insert_args = { snippet = { body = body_4 } } },\n  }\n  eq_partial_tbl(get_all(), ref_sessions)\n\n  clean_au_log()\n\n  -- Deleting session in the middle of stack should work\n  child.api.nvim_buf_delete(buf_id_2, { force = true, unload = true })\n  eq_partial_tbl(get_all(), { ref_sessions[1], ref_sessions[3], ref_sessions[4] })\n\n  -- Deleting current session should make the nearest one active\n  child.api.nvim_buf_delete(buf_id_3, { force = true, unload = true })\n  eq_partial_tbl(get_all(), { ref_sessions[1] })\n\n  -- Deleting the last active session should also work\n  eq(get_buf(), buf_id_1)\n  child.api.nvim_buf_delete(buf_id_1, { force = true, unload = false })\n  validate_n_sessions(0)\n\n  -- Proper events should still be triggered during session clean\n  local make_ref_data = function(buf_id, snippet_body)\n    return { session = { buf_id = buf_id, insert_args = { snippet = { body = snippet_body } } } }\n  end\n  --stylua: ignore\n  local ref_au_log_partial = {\n    -- Event can be triggered with other buffer being current (due to\n    -- `vim.schedule_wrap()` needed to make `:edit` work)\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(buf_id_2, body_2), buf_id = buf_id_3 },\n    -- No 'Resume' of already active session\n    -- Unloading current buffer should also be possible\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(buf_id_3, body_3), buf_id = buf_id_1 },\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(buf_id_3, body_4), buf_id = buf_id_1 },\n    -- Deleting active session resumes the next available\n    { event = 'MiniSnippetsSessionResume', data = make_ref_data(buf_id_1, body_1), buf_id = buf_id_1 },\n    { event = 'MiniSnippetsSessionStop',   data = make_ref_data(buf_id_1, body_1), buf_id = get_buf() },\n  }\n  eq_partial_tbl(get_au_log(), ref_au_log_partial)\nend\n\nT['Session']['nesting']['handles several non-valid session'] = function()\n  start_session('T1=$1 T0=$0')\n  start_session('U1=$1 U0=$0')\n  eq(get_lines(), { 'T1=U1= U0= T0=' })\n  type_keys('<Esc>', 'dd')\n  validate_no_active_session()\n  eq(child.cmd_capture('messages'), '')\nend\n\nT['Interaction with built-in completion'] = new_set()\n\nT['Interaction with built-in completion']['popup removal during insert'] = function()\n  set_lines({ 'abc', '' })\n  set_cursor(2, 0)\n\n  type_keys('i', '<C-n>')\n  validate_pumvisible()\n  default_insert({ body = 'no tabstops' })\n  validate_no_pumvisible()\n  validate_no_active_session()\n\n  type_keys('<CR>', '<C-n>')\n  validate_pumvisible()\n  default_insert({ body = 'yes tabstops: $1' })\n  validate_no_pumvisible()\n  validate_active_session()\nend\n\nT['Interaction with built-in completion']['popup removal during jump'] = function()\n  default_insert({ body = 'abc $1 $2' })\n  type_keys('a', '<C-n>')\n  validate_pumvisible()\n  jump('next')\n  validate_no_pumvisible()\n\n  type_keys('a', '<C-n>')\n  validate_pumvisible()\n  jump('prev')\n  validate_no_pumvisible()\nend\n\nT['Interaction with built-in completion']['preserves popup on autoclose'] = function()\n  default_insert({ body = 'abc $1 $0' })\n  jump('next')\n  type_keys('<C-x><C-n>')\n  validate_pumvisible()\n\n  type_keys('a')\n  sleep(small_time)\n  validate_no_active_session()\n  validate_pumvisible()\nend\n\nT['Interaction with built-in completion']['no affect of \"exausted\" popup during jump'] = function()\n  default_insert({ body = 'abc $1 $2' })\n  type_keys('a', '<C-n>', 'x')\n  validate_no_pumvisible()\n  jump('next')\n\n  type_keys('x')\n  child.expect_screenshot()\nend\n\nT['Interaction with built-in completion']['no wrong automatic session stop during jump'] = function()\n  default_insert({ body = 'ab $1\\n$1\\n$0' })\n  type_keys('a', '<C-n>')\n  validate_pumvisible()\n  jump('next')\n  sleep(small_time)\n  validate_active_session()\nend\n\nT['Interaction with built-in completion']['squashed tabstops'] = function()\n  default_insert({ body = '$1$2$1$2$1' })\n  type_keys('abc', '<C-l>', 'x')\n  type_keys('<C-n>')\n  child.expect_screenshot()\n  type_keys('y')\n  -- NOTE: Requires the fix for extmarks to not be affected\n  -- See https://github.com/neovim/neovim/issues/31384\n  if child.fn.has('nvim-0.10.3') == 1 then child.expect_screenshot() end\nend\n\nT['Interaction with built-in completion']['cycling through candidates'] = function()\n  set_lines({ 'aa bb', '' })\n  set_cursor(2, 0)\n  default_insert({ body = '$1$1' })\n  type_keys('<C-x><C-n>', '<C-n>')\n  validate_state('i', { 'aa bb', 'aaaa' }, { 2, 2 })\n  validate_pumvisible()\n\n  type_keys('<C-p>')\n  -- NOTE: Requires the fix for extmarks to not be affected\n  -- See https://github.com/neovim/neovim/pull/31475\n  if child.fn.has('nvim-0.10.3') == 1 then validate_state('i', { 'aa bb', '' }, { 2, 0 }) end\n  validate_pumvisible()\nend\n\nT['Various snippets'] = new_set()\n\nT['Various snippets']['text'] = function()\n  local validate = function(snippet_body, ref_lines, ref_cursor)\n    start_session(snippet_body)\n    validate_no_active_session()\n    validate_state('i', ref_lines, ref_cursor)\n    ensure_clean_state()\n  end\n\n  -- Basic cases\n  validate('Hello world', { 'Hello world' }, { 1, 11 })\n  validate('Hello\\nmultiline \\nworld', { 'Hello', 'multiline ', 'world' }, { 3, 5 })\n\n  type_keys('i', ' \\t')\n  validate('Hello\\nmultiline \\nworld', { ' \\tHello', ' \\tmultiline ', ' \\tworld' }, { 3, 7 })\n\n  -- Single present `$0` should be treated as \"just text\"\n  validate('Hello world$0', { 'Hello world' }, { 1, 11 })\n  validate('Hello $0 world', { 'Hello  world' }, { 1, 6 })\n  validate('Hello\\n  $0\\nworld', { 'Hello', '  ', 'world' }, { 2, 2 })\nend\n\nT['Various snippets']['var'] = function()\n  local validate = function(snippet_body, ref_lines, ref_cursor)\n    start_session(snippet_body)\n    validate_no_active_session()\n    validate_state('i', ref_lines, ref_cursor)\n    ensure_clean_state()\n  end\n\n  -- Basic cases\n  child.lua('vim.loop.hrtime = function() return 101 end') -- mock reproducible `math.randomseed`\n  validate('$RANDOM ${RANDOM}', { '491985 873024' }, { 1, 13 })\n\n  child.fn.setreg('\"', 'abc\\n')\n  validate('<tag>\\n\\t$TM_SELECTED_TEXT\\n</tag>', { '<tag>', '\\tabc', '</tag>' }, { 3, 6 })\n\n  -- Placeholders\n  validate('var=$AAA', { 'var=' }, { 1, 4 })\n  validate('var=${AAA}', { 'var=' }, { 1, 4 })\n  validate('var=${AAA:placeholder}', { 'var=placeholder' }, { 1, 15 })\n  validate('var=${BBB:${AAA:placeholder}}', { 'var=placeholder' }, { 1, 15 })\n\n  child.fn.setenv('AAA', 'aaa')\n  validate('var=$AAA', { 'var=aaa' }, { 1, 7 })\n  validate('var=${AAA}', { 'var=aaa' }, { 1, 7 })\n  validate('var=${AAA:placeholder}', { 'var=aaa' }, { 1, 7 })\n  validate('var=${BBB:${AAA:placeholder}}', { 'var=aaa' }, { 1, 7 })\nend\n\nT['Various snippets']['tabstop'] = function()\n  local validate = function(snippet_body)\n    start_session(snippet_body)\n    validate_active_session()\n    child.expect_screenshot()\n    ensure_clean_state()\n  end\n\n  -- Only tabstops\n  validate('$1')\n  validate('$1$0')\n\n  -- Other special tabstop cases are scattered across narrower test cases\nend\n\nT['Various snippets']['choice'] = function()\n  -- Basic case. More tests are in 'Session'-'choices'\n  start_session('${1|bb,aa|}')\n  validate_active_session()\n  validate_pumitems({ 'bb', 'aa' })\n  -- Should insert first choice\n  validate_state('i', { 'bb' }, { 1, 0 })\nend\n\nT['Various snippets']['transform'] = function()\n  -- Should ignore present transform (for now) in both variables and tabstops\n  child.fn.setreg('\"', 'abc\\n')\n  start_session('Upcase=${TM_SELECTED_TEXT/.*/upcase/}')\n  validate_state('i', { 'Upcase=abc' }, { 1, 10 })\n  ensure_clean_state()\n\n  start_session('Upcase=${1/.*/upcase/};')\n  validate_active_session()\n  validate_state('i', { 'Upcase=;' }, { 1, 7 })\nend\n\nT['Various snippets']['placeholders'] = function()\n  -- Placeholders should be removed during typing\n  start_session('T1=${1:<aaa>} T0=${0:<bbb>}')\n  child.expect_screenshot()\n  type_keys('x')\n  child.expect_screenshot()\n  jump('next')\n  child.expect_screenshot()\n  type_keys('y')\n  -- - Should also remove final tabstop's placeholder\n  child.expect_screenshot()\n  ensure_clean_state()\n\n  -- Multiline placeholder\n  start_session('T1=${1:aa\\nbb\\n} T0=$0')\n  child.expect_screenshot()\n  type_keys('x')\n  child.expect_screenshot()\n  ensure_clean_state()\n\n  -- Placeholder in single final tabstop should result in active session\n  start_session('Text ${0:placeholder}')\n  validate_active_session()\n  child.expect_screenshot()\n  type_keys('x')\n  validate_no_active_session()\nend\n\nT['Tricky snippets'] = new_set()\n\nT['Tricky snippets']['nested empty tabstops'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('${1:${2:$3}} ${2:$3} $3')\n  -- Should show every tabstop with inline text\n  child.expect_screenshot()\n  jump('next')\n  child.expect_screenshot(screen_opts)\n  jump('next')\n  child.expect_screenshot(screen_opts)\n\n  type_keys('a')\n  child.expect_screenshot()\n\n  -- Should remove text from $3 from placeholder\n  jump('prev')\n  type_keys('b')\n  child.expect_screenshot()\n\n  -- Should remove text from $2 as placeholder\n  jump('prev')\n  type_keys('c')\n  child.expect_screenshot()\nend\n\nT['Tricky snippets']['nested empty tabstops, another'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  start_session('$1 ${2:$1} ${3:${2:$1}}')\n  -- Should show every tabstop with inline text\n  child.expect_screenshot()\n  jump('next')\n  child.expect_screenshot(screen_opts)\n  jump('next')\n  child.expect_screenshot(screen_opts)\n\n  jump('prev')\n  jump('prev')\n  type_keys('a')\n  child.expect_screenshot()\n\n  -- Should remove text from $1 from placeholder\n  jump('next')\n  type_keys('b')\n  child.expect_screenshot()\n\n  -- Should remove text from $2 as placeholder\n  jump('next')\n  type_keys('c')\n  child.expect_screenshot()\nend\n\nT['Tricky snippets']['squashed linked empty interleaving tabstops'] = function()\n  start_session('$1$2$1$2$1')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\n\n  jump('next')\n  type_keys('b')\n  child.expect_screenshot()\n\n  type_keys('<BS>')\n  child.expect_screenshot()\n\n  jump('prev')\n  type_keys('<BS>')\n  child.expect_screenshot()\nend\n\nT['Tricky snippets']['squashed linked empty consecutive tabstops'] = function()\n  start_session('$1$1$1$2$2')\n  child.expect_screenshot()\n  type_keys('a')\n  child.expect_screenshot()\n\n  jump('next')\n  type_keys('b')\n  child.expect_screenshot()\n\n  type_keys('<BS>')\n  child.expect_screenshot()\n\n  jump('prev')\n  type_keys('<BS>')\n  child.expect_screenshot()\nend\n\nT['Tricky snippets']['squashed linked tabstops with placeholders'] = function()\n  start_session('$1${2:aa}$1${2:aa}$1')\n  child.expect_screenshot()\n  type_keys('x')\n  child.expect_screenshot()\n\n  jump('next')\n  type_keys('y')\n  child.expect_screenshot()\nend\n\nT['Tricky snippets']['final tabstop is nested'] = function()\n  -- Only nested\n  start_session('T1=${1:<T2=${2:<T0=$0>}>}')\n  jump('next')\n  eq(get_cur_tabstop(), '2')\n  type_keys('x')\n  validate_state('i', { 'T1=<T2=x>' }, { 1, 8 })\n  jump('next')\n  eq(get_cur_tabstop(), '1')\n  ensure_clean_state()\n\n  -- Nested and outside\n  start_session('T1=${1:$0} T0=$0')\n  type_keys('x')\n  validate_state('i', { 'T1=x T0=' }, { 1, 4 })\n  jump('next')\n  eq(get_cur_tabstop(), '0')\nend\n\nT['Tricky snippets']['tricky choices'] = function()\n  -- Should not show popup if there are no choices\n  start_session('No choice ${1||}')\n  validate_active_session()\n  validate_no_pumvisible()\n  ensure_clean_state()\n\n  -- Same ignore repeated choices\n  start_session('Same choices ${1|b,a,b,a,c|}')\n  validate_active_session()\n  validate_pumitems({ 'b', 'a', 'c' })\n  ensure_clean_state()\n\n  -- Should ignore empty choices\n  start_session('Empty choices ${1|b,,a,,|}')\n  validate_active_session()\n  validate_pumitems({ 'b', 'a' })\n  ensure_clean_state()\nend\n\nT['Tricky snippets']['tabstop nested inside itself'] = function()\n  -- Should not be allowed\n  expect.error(function() start_session('${1:$1}') end, 'Placeholder can not contain its tabstop')\nend\n\nT['Tricky snippets']['intertwined nested tabstops'] = function()\n  local screen_opts = child.fn.has('nvim-0.12') == 0 and { ignore_text = { 8 }, ignore_attr = { 8 } } or {}\n\n  -- Should be normalized into 'T1=${1:<T2=$2>} and T2=$2' during `parse()`\n  start_session('T1=${1:<T2=$2>} and T2=${2:<T1=$1>}')\n  child.expect_screenshot()\n  type_keys('x')\n  child.expect_screenshot()\n  jump('next')\n  type_keys('y')\n  child.expect_screenshot()\n  ensure_clean_state()\n\n  -- Order matters\n  start_session('T1=${1:<T2=$2>} and T2=${2:<T1=$1>}')\n  jump('next')\n  child.expect_screenshot(screen_opts)\n  type_keys('x')\n  child.expect_screenshot()\n  jump('prev')\n  type_keys('y')\n  child.expect_screenshot()\nend\n\nT['Mappings'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua([[MiniSnippets.config.snippets = {\n      { prefix = \"tt\", body = \"T1=$1 T0=$0\" },\n      { prefix = \"uu\", body = \"U1=$1 U0=$0\" },\n    }]])\n    end,\n  },\n})\n\nlocal has_mapping = function(lhs) return child.cmd_capture('imap ' .. lhs):find('No mapping') == nil end\n\nT['Mappings']['works'] = function()\n  -- `default_insert()` mappings should be present only for active session(s)\n  eq(has_mapping('<C-j>'), true)\n  eq(has_mapping('<C-l>'), false)\n  eq(has_mapping('<C-h>'), false)\n  eq(has_mapping('<C-c>'), false)\n\n  type_keys('i', 'tt', '<C-j>')\n  validate_active_session()\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n\n  type_keys('<C-l>')\n  eq(get_cur_tabstop(), '0')\n  validate_state('i', { 'T1= T0=' }, { 1, 7 })\n\n  type_keys('<C-h>')\n  eq(get_cur_tabstop(), '1')\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n\n  validate_active_session()\n  type_keys('<C-c>')\n  validate_no_active_session()\n\n  eq(has_mapping('<C-j>'), true)\n  eq(has_mapping('<C-l>'), false)\n  eq(has_mapping('<C-h>'), false)\n  eq(has_mapping('<C-c>'), false)\n\n  -- Should work even if using `default_insert()` directly\n  default_insert({ body = 'U1=$1' })\n  type_keys('<C-l>')\n  eq(get_cur_tabstop(), '0')\n  type_keys('<C-h>')\n  eq(get_cur_tabstop(), '1')\n  type_keys('<C-c>')\n  validate_no_active_session()\nend\n\nT['Mappings']['works with different keys'] = function()\n  child.restart()\n  load_module({\n    snippets = { { prefix = 'tt', body = 'T1=$1 T0=$0' } },\n    mappings = { expand = '<C-]>', jump_next = '<C-j>', jump_prev = '<C-k>', stop = '<C-z>' },\n  })\n\n  type_keys('i', 'tt', '<C-]>')\n  validate_active_session()\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n\n  type_keys('<C-j>')\n  eq(get_cur_tabstop(), '0')\n  validate_state('i', { 'T1= T0=' }, { 1, 7 })\n\n  type_keys('<C-k>')\n  eq(get_cur_tabstop(), '1')\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n\n  validate_active_session()\n  type_keys('<C-z>')\n  validate_no_active_session()\n\n  -- Should work even if using `default_insert()` directly\n  default_insert({ body = 'U1=$1' })\n  type_keys('<C-j>')\n  eq(get_cur_tabstop(), '0')\n  type_keys('<C-k>')\n  eq(get_cur_tabstop(), '1')\n  type_keys('<C-z>')\n  validate_no_active_session()\nend\n\nT['Mappings']['work across buffers'] = function()\n  local init_buf, other_buf = get_buf(), new_buf()\n  type_keys('i', 'tt', '<C-j>')\n  validate_state('i', { 'T1= T0=' }, { 1, 3 })\n  eq(get_cur_tabstop(), '1')\n\n  set_buf(other_buf)\n  type_keys('<C-l>')\n  eq(get_buf(), init_buf)\n  eq(get_cur_tabstop(), '0')\n\n  set_buf(other_buf)\n  type_keys('<C-h>')\n  eq(get_buf(), init_buf)\n  eq(get_cur_tabstop(), '1')\n\n  set_buf(other_buf)\n  validate_active_session()\n  type_keys('<C-c>')\n  validate_no_active_session()\nend\n\nT['Mappings']['`default_insert` mappings respect buffer-local config'] = function()\n  child.b.minisnippets_config = { mappings = { stop = '<C-z>' } }\n\n  eq(has_mapping('<C-c>'), false)\n  eq(has_mapping('<C-z>'), false)\n  type_keys('i', 'tt', '<C-j>')\n  eq(has_mapping('<C-c>'), false)\n  eq(has_mapping('<C-z>'), true)\nend\n\nT['Mappings']['`default_insert` mappings are present for all nested sessions'] = function()\n  type_keys('i', 'tt', '<C-j>')\n  type_keys('uu', '<C-j>')\n  validate_n_sessions(2)\n\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 6 })\n  type_keys('<C-l>')\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 10 })\n  type_keys('<C-h>')\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 6 })\n  type_keys('<C-c>')\n  validate_state('i', { 'T1=U1= U0= T0=' }, { 1, 6 })\n  validate_n_sessions(1)\nend\n\nT['Mappings']['`default_insert` mappings cache and restore global conflicting mappings'] = function()\n  child.api.nvim_set_keymap('i', '<C-l>', '<Cmd>lua print(1)<CR>', {})\n  child.api.nvim_set_keymap('i', '<C-h>', '<Cmd>lua print(2)<CR>', {})\n  child.api.nvim_set_keymap('i', '<C-c>', '<Cmd>lua print(3)<CR>', {})\n\n  local get_map_rhs = function(lhs) return child.fn.maparg(lhs, 'i', false, true).rhs end\n\n  -- Should cache and restore only after there is no active session\n  type_keys('i', 'tt', '<C-j>')\n  no_eq(get_map_rhs('<C-l>'), '<Cmd>lua print(1)<CR>')\n  no_eq(get_map_rhs('<C-h>'), '<Cmd>lua print(2)<CR>')\n  no_eq(get_map_rhs('<C-c>'), '<Cmd>lua print(3)<CR>')\n\n  type_keys('uu', '<C-j>')\n  no_eq(get_map_rhs('<C-l>'), '<Cmd>lua print(1)<CR>')\n  no_eq(get_map_rhs('<C-h>'), '<Cmd>lua print(2)<CR>')\n  no_eq(get_map_rhs('<C-c>'), '<Cmd>lua print(3)<CR>')\n\n  type_keys('<C-c>')\n  no_eq(get_map_rhs('<C-l>'), '<Cmd>lua print(1)<CR>')\n  no_eq(get_map_rhs('<C-h>'), '<Cmd>lua print(2)<CR>')\n  no_eq(get_map_rhs('<C-c>'), '<Cmd>lua print(3)<CR>')\n\n  type_keys('<C-c>')\n  eq(get_map_rhs('<C-l>'), '<Cmd>lua print(1)<CR>')\n  eq(get_map_rhs('<C-h>'), '<Cmd>lua print(2)<CR>')\n  eq(get_map_rhs('<C-c>'), '<Cmd>lua print(3)<CR>')\n\n  ensure_clean_state()\n\n  -- Should always cache map data just before first active session\n  child.api.nvim_set_keymap('i', '<C-l>', '<Cmd>lua print(111)<CR>', {})\n  type_keys('i', 'tt', '<C-j>')\n  no_eq(get_map_rhs('<C-l>'), '<Cmd>lua print(111)<CR>')\n  type_keys('<C-c>')\n  eq(get_map_rhs('<C-l>'), '<Cmd>lua print(111)<CR>')\nend\n\nT['Examples'] = new_set()\n\nT['Examples']['stop session after jump to final tabstop'] = function()\n  child.lua([[\n    local fin_stop = function(args) if args.data.tabstop_to == '0' then MiniSnippets.session.stop() end end\n    vim.api.nvim_create_autocmd('User', { pattern = 'MiniSnippetsSessionJump', callback = fin_stop })\n  ]])\n  start_session('T1=$1; T0=$0')\n  validate_active_session()\n  jump('next')\n  validate_no_active_session()\nend\n\nT['Examples']['stop session after Normal mode exit'] = function()\n  child.lua([[\n    local make_stop = function()\n      local au_opts = { pattern = '*:n', once = true }\n      au_opts.callback = function()\n        while MiniSnippets.session.get() do\n          MiniSnippets.session.stop()\n        end\n      end\n      vim.api.nvim_create_autocmd('ModeChanged', au_opts)\n    end\n    local opts = { pattern = 'MiniSnippetsSessionStart', callback = make_stop }\n    vim.api.nvim_create_autocmd('User', opts)\n  ]])\n\n  start_session('T1=$1; T0=$0')\n  validate_active_session()\n  type_keys('<Esc>')\n  validate_no_active_session()\n  eq(child.cmd_capture('au ModeChanged'):find('snippet') == nil, true)\n\n  start_session('T1=$1; T0=$0')\n  -- Should not stop for \"temporary\" Normal mode\n  type_keys('<C-o>i')\n  validate_active_session()\n  -- Should stop nested sessions\n  start_session('U1=$1; U0=$0')\n  eq(#get(true), 2)\n  type_keys('<Esc>')\n  validate_no_active_session()\nend\n\nT['Examples']['expand all'] = function()\n  child.lua([[\n    local rhs = function() MiniSnippets.expand({ match = false }) end\n    vim.keymap.set('i', '<C-g><C-j>', rhs, { desc = 'Expand all' })\n\n    MiniSnippets.config.snippets = {\n      { prefix = 'aa', body = 'AA=$1' },\n      { prefix = 'ab', body = 'AB=$1' },\n      { prefix = 'xx', body = 'XX=$1' },\n    }\n  ]])\n\n  mock_select(3)\n  type_keys('i', 'a', '<C-g><C-j>')\n  validate_state('i', { 'aXX=' }, { 1, 4 })\nend\n\nT['Examples']['customize variable evaluation'] = function()\n  child.lua([[\n    vim.loop.os_setenv('USERNAME', 'user')\n    local insert_with_lookup = function(snippet)\n      local lookup = {\n        TM_SELECTED_TEXT = table.concat(vim.fn.getreg('a', true, true), '\\n'),\n      }\n      return MiniSnippets.default_insert(snippet, { lookup = lookup })\n    end\n\n    require('mini.snippets').setup({\n      snippets = { { prefix = 't', body = '$USERNAME $TM_SELECTED_TEXT' } },\n      expand = { insert = insert_with_lookup },\n    })\n  ]])\n\n  type_keys('i', 'aa<CR>bb', '<Esc>', '\"adip')\n  type_keys('i', 'xx', '<Esc>', 'dip')\n\n  type_keys('i', 't', '<C-j>')\n  validate_state('i', { 'user aa', 'bb' }, { 2, 2 })\nend\n\nT['Examples']['<Tab>/<S-Tab> mappings'] = function()\n  child.setup()\n  load_module({\n    snippets = { { prefix = 'l', body = 'T1=$1 T0=0' } },\n    mappings = { expand = '', jump_next = '', jump_prev = '' },\n  })\n  child.lua([[\n    local snippets = require('mini.snippets')\n    local match_strict = function(snips)\n      return snippets.default_match(snips, { pattern_fuzzy='%S+' })\n    end\n    snippets.setup({\n      snippets = { { prefix = 'l', body = 'T1=$1 T0=0' } },\n      mappings = { expand = '', jump_next = '' },\n      expand = { match = match_strict },\n    })\n    local expand_or_jump = function()\n      local can_expand = #MiniSnippets.expand({ insert = false }) > 0\n      if can_expand then vim.schedule(MiniSnippets.expand); return '' end\n      local is_active = MiniSnippets.session.get() ~= nil\n      if is_active then MiniSnippets.session.jump('next'); return '' end\n      return '\\t'\n    end\n    local jump_prev = function() MiniSnippets.session.jump('prev') end\n    vim.keymap.set('i', '<Tab>', expand_or_jump, { expr = true })\n    vim.keymap.set('i', '<S-Tab>', jump_prev)\n  ]])\n\n  type_keys('i', '<Tab>')\n  eq(get_lines(), { '\\t' })\n\n  type_keys('l', '<Tab>')\n  validate_active_session()\n  eq(get_cur_tabstop(), '1')\n\n  type_keys('l', '<Tab>')\n  validate_n_sessions(2)\n  eq(get_cur_tabstop(), '1')\n\n  type_keys('<Tab>')\n  validate_n_sessions(2)\n  eq(get_cur_tabstop(), '0')\n\n  type_keys('<S-Tab>')\n  validate_n_sessions(2)\n  eq(get_cur_tabstop(), '1')\nend\n\nT['Examples']['using `vim.snippet.expand()`'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`vim.snippet` is present only in Neovim>=0.10') end\n  child.lua([[\n    require('mini.snippets').setup({\n      snippets = { { prefix = 't', body = 'T1=$1 T2=${2:<two>}' } },\n      expand = {\n        insert = function(snippet, _) vim.snippet.expand(snippet.body) end\n      }\n    })\n    local jump_next = function()\n      if vim.snippet.active({direction = 1}) then return vim.snippet.jump(1) end\n    end\n    local jump_prev = function()\n      if vim.snippet.active({direction = -1}) then vim.snippet.jump(-1) end\n    end\n    vim.keymap.set({ 'i', 's' }, '<C-l>', jump_next)\n    vim.keymap.set({ 'i', 's' }, '<C-h>', jump_prev)\n  ]])\n\n  type_keys('i', 't', '<C-j>')\n  -- SHould not have active session from `default_insert()`\n  validate_no_active_session()\n  validate_state('i', { 'T1= T2=<two>' }, { 1, 3 })\n  type_keys('t1')\n  validate_state('i', { 'T1=t1 T2=<two>' }, { 1, 5 })\n  type_keys('<C-l>')\n  validate_state('s', { 'T1=t1 T2=<two>' }, { 1, 9 })\n  type_keys('t2')\n  validate_state('i', { 'T1=t1 T2=t2' }, { 1, 11 })\n  type_keys('<C-h>')\n  validate_state('s', { 'T1=t1 T2=t2' }, { 1, 3 })\nend\n\nT['Examples']['`default_prepare` with cache'] = function()\n  child.lua([[\n    _G.log = {}\n    local prepare_orig = MiniSnippets.default_prepare\n    MiniSnippets.default_prepare = function(...)\n      table.insert(_G.log, { ... })\n      return prepare_orig(...)\n    end\n\n    local cache = {}\n    _G.prepare_cached = function(raw_snippets)\n      local _, cont = MiniSnippets.default_prepare({})\n      local id = 'buf=' .. cont.buf_id .. ',lang=' .. cont.lang\n      if cache[id] then return unpack(vim.deepcopy(cache[id])) end\n      local snippets = MiniSnippets.default_prepare(raw_snippets)\n      cache[id] = vim.deepcopy({ snippets, cont })\n      return snippets, cont\n    end\n  ]])\n\n  child.bo.filetype = 'myft'\n  child.lua([[_G.prepare_cached({ { prefix = 'a', body = 'a=$1' } })]])\n  eq(child.lua_get('#_G.log'), 2)\n  local out = child.lua_get([[_G.prepare_cached({ { prefix = 'x', body = 'x=$1' } })]])\n  eq(out, { { prefix = 'a', body = 'a=$1', desc = 'a=$1' } })\n  eq(child.lua_get('#_G.log'), 3)\n\n  child.bo.filetype = 'myft2'\n  child.lua([[_G.prepare_cached({ { prefix = 'a', body = 'a=$1' } })]])\n  eq(child.lua_get('#_G.log'), 5)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_splitjoin.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('splitjoin', config) end\nlocal unload_module = function() child.mini_unload('splitjoin') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Helper wrappers\nlocal simplepos_to_pos = function(x) return { line = x[1], col = x[2] } end\n\nlocal validate_positions = function(out, ref) eq(out, vim.tbl_map(simplepos_to_pos, ref)) end\n\n-- More general validators\nlocal validate_edit = function(lines_before, cursor_before, lines_after, cursor_after, fun, ...)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  fun(...)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n  child.ensure_normal_mode()\nend\n\nlocal validate_keys = function(lines_before, cursor_before, lines_after, cursor_after, keys)\n  child.ensure_normal_mode()\n  set_lines(lines_before)\n  set_cursor(cursor_before[1], cursor_before[2])\n\n  type_keys(keys)\n\n  eq(get_lines(), lines_after)\n  eq(get_cursor(), cursor_after)\n  child.ensure_normal_mode()\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniSplitjoin)'), 'table')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniSplitjoin.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniSplitjoin.config.' .. field), value) end\n\n  expect_config('mappings.toggle', 'gS')\n  expect_config('mappings.split', '')\n  expect_config('mappings.join', '')\n\n  expect_config('detect.brackets', vim.NIL)\n  expect_config('detect.separator', ',')\n  expect_config('detect.exclude_regions', vim.NIL)\n\n  expect_config('split.hooks_pre', {})\n  expect_config('split.hooks_post', {})\n\n  expect_config('join.hooks_pre', {})\n  expect_config('join.hooks_post', {})\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ detect = { separator = '[,;]' } })\n  eq(child.lua_get('MiniSplitjoin.config.detect.separator'), '[,;]')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { toggle = 1 } }, 'mappings.toggle', 'string')\n  expect_config_error({ mappings = { split = 1 } }, 'mappings.split', 'string')\n  expect_config_error({ mappings = { join = 1 } }, 'mappings.join', 'string')\n\n  expect_config_error({ detect = 'a' }, 'detect', 'table')\n  expect_config_error({ detect = { brackets = 1 } }, 'detect.brackets', 'table')\n  expect_config_error({ detect = { separator = 1 } }, 'detect.separator', 'string')\n  expect_config_error({ detect = { exclude_regions = 1 } }, 'detect.exclude_regions', 'table')\n\n  expect_config_error({ split = 'a' }, 'split', 'table')\n  expect_config_error({ split = { hooks_pre = 1 } }, 'split.hooks_pre', 'table')\n  expect_config_error({ split = { hooks_post = 1 } }, 'split.hooks_post', 'table')\n\n  expect_config_error({ join = 'a' }, 'join', 'table')\n  expect_config_error({ join = { hooks_pre = 1 } }, 'join.hooks_pre', 'table')\n  expect_config_error({ join = { hooks_post = 1 } }, 'join.hooks_post', 'table')\nend\n\nT['setup()']['properly creates mappings'] = function()\n  local has_map = function(mode, lhs, pattern) return child.cmd_capture(mode .. 'map ' .. lhs):find(pattern) ~= nil end\n  eq(has_map('n', 'gS', 'Toggle'), true)\n  eq(has_map('x', 'gS', 'Toggle'), true)\n  eq(has_map('n', 'gj', 'Join'), false)\n  eq(has_map('x', 'gj', 'Join'), false)\n\n  unload_module()\n  child.api.nvim_del_keymap('n', 'gS')\n  child.api.nvim_del_keymap('x', 'gS')\n\n  -- Supplying empty string should mean \"don't create keymaps\"\n  load_module({ mappings = { toggle = '', join = 'gj' } })\n  eq(has_map('n', 'gS', 'Toggle'), false)\n  eq(has_map('x', 'gS', 'Toggle'), false)\n  eq(has_map('n', 'gj', 'Join'), true)\n  eq(has_map('x', 'gj', 'Join'), true)\nend\n\n-- Most of action specific tests are done in their functions\nT['toggle()'] = new_set()\n\nlocal toggle = function(...) return child.lua_get('MiniSplitjoin.toggle(...)', { ... }) end\n\nT['toggle()']['works'] = function()\n  validate_edit({ '(aaa, bb, c)' }, { 1, 0 }, { '(', '\\taaa,', '\\tbb,', '\\tc', ')' }, { 1, 0 }, toggle)\n  validate_edit({ '[aaa, bb, c]' }, { 1, 0 }, { '[', '\\taaa,', '\\tbb,', '\\tc', ']' }, { 1, 0 }, toggle)\n  validate_edit({ '{aaa, bb, c}' }, { 1, 0 }, { '{', '\\taaa,', '\\tbb,', '\\tc', '}' }, { 1, 0 }, toggle)\n\n  validate_edit({ '(', '\\taaa,', '\\tbb,', '\\tc', ')' }, { 1, 0 }, { '(aaa, bb, c)' }, { 1, 0 }, toggle)\n  validate_edit({ '[', '\\taaa,', '\\tbb,', '\\tc', ']' }, { 1, 0 }, { '[aaa, bb, c]' }, { 1, 0 }, toggle)\n  validate_edit({ '{', '\\taaa,', '\\tbb,', '\\tc', '}' }, { 1, 0 }, { '{aaa, bb, c}' }, { 1, 0 }, toggle)\nend\n\nT['toggle()']['explicitly calls `split()` or `join()`'] = function()\n  local default_opts = {\n    detect = {\n      brackets = { '%b()', '%b[]', '%b{}' },\n      exclude_regions = { '%b()', '%b[]', '%b{}', '%b\"\"', \"%b''\" },\n      separator = ',',\n    },\n    join = {\n      hooks_post = {},\n      hooks_pre = {},\n    },\n    split = {\n      hooks_post = {},\n      hooks_pre = {},\n    },\n  }\n\n  -- Split\n  child.lua('MiniSplitjoin.split = function(...) _G.split_args = {...} end')\n\n  set_lines({ '(aa, b)' })\n  set_cursor(1, 1)\n  toggle()\n\n  local ref_split_args = vim.deepcopy(default_opts)\n  ref_split_args.position = { line = 1, col = 2 }\n  ref_split_args.region = { from = { line = 1, col = 1 }, to = { line = 1, col = 7 } }\n\n  eq(child.lua_get('_G.split_args'), { ref_split_args })\n\n  -- Join\n  child.lua('MiniSplitjoin.join = function(...) _G.join_args = {...} end')\n\n  set_lines({ '(', 'aa', 'b)' })\n  set_cursor(2, 1)\n  toggle()\n\n  local ref_join_args = vim.deepcopy(default_opts)\n  ref_join_args.position = { line = 2, col = 2 }\n  ref_join_args.region = { from = { line = 1, col = 1 }, to = { line = 3, col = 2 } }\n\n  eq(child.lua_get('_G.join_args'), { ref_join_args })\nend\n\nT['toggle()']['respects `opts.position`'] = function()\n  validate_edit({ ' (aa)' }, { 1, 0 }, { ' (', ' \\taa', ' )' }, { 1, 0 }, toggle, { position = { line = 1, col = 2 } })\n  validate_edit({ ' (aa)' }, { 1, 1 }, { ' (aa)' }, { 1, 1 }, toggle, { position = { line = 1, col = 1 } })\nend\n\nT['toggle()']['respects `opts.region`'] = function()\n  -- Force join instead of split\n  set_lines({ '(a, \")\"', ')' })\n  set_cursor(1, 0)\n  toggle({ region = { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } } })\n  eq(get_lines(), { '(a, \")\")' })\n\n  -- Force split instead of join\n  set_lines({ '(a)', ']' })\n  set_cursor(1, 0)\n  toggle({ region = { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } } })\n  eq(get_lines(), { '(a)]' })\nend\n\nT['toggle()']['respects `opts.detect.brackets`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.brackets = { '%b{}' }\")\n  validate_edit({ '[aaa]' }, { 1, 0 }, { '[aaa]' }, { 1, 0 }, toggle)\n  validate_edit({ '{aaa}' }, { 1, 0 }, { '{', '\\taaa', '}' }, { 1, 0 }, toggle)\n\n  -- Local\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, toggle, { detect = { brackets = {} } })\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, toggle, { detect = { brackets = { '%b[]' } } })\nend\n\nT['toggle()']['returns `nil` if no positions are found'] = function()\n  set_lines({ 'aaa' })\n  eq(toggle(), vim.NIL)\n  eq(get_lines(), { 'aaa' })\nend\n\nT['toggle()']['respects `vim.{g,b}.minisplitjoin_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisplitjoin_disable = true\n    validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, toggle)\n  end,\n})\n\nT['toggle()']['respects `vim.b.minisplitjoin_config`'] = function()\n  child.lua([[vim.b.minisplitjoin_config = { detect = { brackets = { '%b[]' } } }]])\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, toggle)\nend\n\nT['split()'] = new_set()\n\nlocal split = function(...) return child.lua_get('MiniSplitjoin.split(...)', { ... }) end\n\nT['split()']['works'] = function()\n  validate_edit({ '(aaa, bb, c)' }, { 1, 0 }, { '(', '\\taaa,', '\\tbb,', '\\tc', ')' }, { 1, 0 }, split)\n  validate_edit({ '[aaa, bb, c]' }, { 1, 0 }, { '[', '\\taaa,', '\\tbb,', '\\tc', ']' }, { 1, 0 }, split)\n  validate_edit({ '{aaa, bb, c}' }, { 1, 0 }, { '{', '\\taaa,', '\\tbb,', '\\tc', '}' }, { 1, 0 }, split)\nend\n\n--stylua: ignore\nT['split()']['works for arguments on multiple lines'] = function()\n  validate_edit({ '(a', 'b',   'c)' },     { 1, 0 }, { '(', '\\ta', '\\tb', '\\tc', ')' }, { 1, 0 }, split)\n  validate_edit({ '(a', '\\tb', '\\t\\tc)' }, { 1, 0 }, { '(', '\\ta', '\\t\\tb', '\\t\\t\\tc', '\\t\\t)' }, { 1, 0 }, split)\n\n  validate_edit({ '(a', 'b, c', 'd)' }, { 1, 0 }, { '(', '\\ta', '\\tb,', '\\tc', '\\td', ')' }, { 1, 0 }, split)\n\n  -- This can be better, but currently is outside of cost/benefit ratio\n  validate_edit({ '(', '\\ta,', '\\tb', ')' }, { 1, 0 }, { \"(\", \"\", \"\\t\\ta,\", \"\\t\", \"\\t\\tb\", \"\\t)\" }, { 1, 0 }, split)\nend\n\nT['split()']['works on any part inside or on brackets'] = function()\n  validate_edit({ 'b( a )b' }, { 1, 0 }, { 'b( a )b' }, { 1, 0 }, split)\n  validate_edit({ 'b( a )b' }, { 1, 1 }, { 'b(', '\\ta', ')b' }, { 1, 1 }, split)\n  validate_edit({ 'b( a )b' }, { 1, 2 }, { 'b(', '\\ta', ')b' }, { 2, 1 }, split)\n  validate_edit({ 'b( a )b' }, { 1, 3 }, { 'b(', '\\ta', ')b' }, { 2, 1 }, split)\n  validate_edit({ 'b( a )b' }, { 1, 4 }, { 'b(', '\\ta', ')b' }, { 2, 1 }, split)\n  validate_edit({ 'b( a )b' }, { 1, 5 }, { 'b(', '\\ta', ')b' }, { 3, 0 }, split)\n  validate_edit({ 'b( a )b' }, { 1, 6 }, { 'b( a )b' }, { 1, 6 }, split)\nend\n\nT['split()']['works on indented line'] = function()\n  validate_edit({ '\\t (aaa, bb, c)' }, { 1, 2 }, { '\\t (', '\\t \\taaa,', '\\t \\tbb,', '\\t \\tc', '\\t )' }, { 1, 2 }, split)\nend\n\nT['split()']['works inside comments'] = function()\n  -- After 'commentstring'\n  child.bo.commentstring = '# %s'\n  validate_edit({ '# (aaa)' }, { 1, 2 }, { '# (', '# \\taaa', '# )' }, { 1, 2 }, split)\n\n  -- After any entry in 'comments'\n  child.bo.comments = ':---,:--'\n  validate_edit({ '-- (aaa)' }, { 1, 3 }, { '-- (', '-- \\taaa', '-- )' }, { 1, 3 }, split)\n  validate_edit({ '--- (aaa)' }, { 1, 4 }, { '--- (', '--- \\taaa', '--- )' }, { 1, 4 }, split)\n\n  -- Respects `b` flag\n  child.bo.comments = 'b:*'\n  validate_edit({ '*(aaa)' }, { 1, 1 }, { '*(', '\\taaa', ')' }, { 1, 1 }, split)\n  validate_edit({ '* (aaa)' }, { 1, 2 }, { '* (', '* \\taaa', '* )' }, { 1, 2 }, split)\n  validate_edit({ '*\\t(aaa)' }, { 1, 2 }, { '*\\t(', '*\\t\\taaa', '*\\t)' }, { 1, 2 }, split)\n\n  -- Respects `f` flag (ignores as comment leader)\n  child.bo.comments = 'f:-'\n  validate_edit({ '-(aaa)' }, { 1, 1 }, { '-(', '\\taaa', ')' }, { 1, 1 }, split)\n  validate_edit({ '- (aaa)' }, { 1, 2 }, { '- (', '\\taaa', ')' }, { 1, 2 }, split)\n  validate_edit({ '-\\t(aaa)' }, { 1, 2 }, { '-\\t(', '\\taaa', ')' }, { 1, 2 }, split)\nend\n\nT['split()']['works with trailing separator'] = function()\n  validate_edit({ '(aa, b,)' }, { 1, 0 }, { '(', '\\taa,', '\\tb,', ')' }, { 1, 0 }, split)\nend\n\nT['split()']['correctly increases indent of commented line in non-commented block'] = function()\n  child.bo.commentstring = '# %s'\n  validate_edit({ '(aa', '# b', 'c)' }, { 1, 0 }, { '(', '\\taa', '\\t# b', '\\tc', ')' }, { 1, 0 }, split)\nend\n\nT['split()']['ignores separators inside nested arguments'] = function()\n  validate_edit(\n    { '(a, (b, c), [d, e], {f, e})' },\n    { 1, 0 },\n    { '(', '\\ta,', '\\t(b, c),', '\\t[d, e],', '\\t{f, e}', ')' },\n    { 1, 0 },\n    split\n  )\nend\n\nT['split()']['ignores separators inside quotes'] = function()\n  validate_edit({ [[(a, 'b, c', \"d, e\")]] }, { 1, 0 }, { '(', '\\ta,', \"\\t'b, c',\", '\\t\"d, e\"', ')' }, { 1, 0 }, split)\nend\n\nT['split()']['works in empty brackets'] = function()\n  validate_edit({ '()' }, { 1, 0 }, { '(', ')' }, { 1, 0 }, split)\n  validate_edit({ '()' }, { 1, 1 }, { '(', ')' }, { 2, 0 }, split)\nend\n\nT['split()'][\"respects 'expandtab' and 'shiftwidth' for indenting\"] = function()\n  child.o.expandtab = true\n  child.o.shiftwidth = 3\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(', '   aaa', ')' }, { 1, 0 }, split)\nend\n\nT['split()']['returns `nil` if no positions are found'] = function()\n  set_lines({ 'aaa' })\n  eq(split(), vim.NIL)\n  eq(get_lines(), { 'aaa' })\nend\n\nT['split()']['respects `opts.position`'] = function()\n  validate_edit({ ' (aaa)' }, { 1, 0 }, { ' (', ' \\taaa', ' )' }, { 1, 0 }, split, { position = { line = 1, col = 2 } })\n  validate_edit({ ' (aaa)' }, { 1, 1 }, { ' (aaa)' }, { 1, 1 }, split, { position = { line = 1, col = 1 } })\nend\n\nT['split()']['respects `opts.region`'] = function()\n  local lines = { '(a, \")\", b)' }\n  local region = { from = { line = 1, col = 1 }, to = { line = 1, col = 11 } }\n  validate_edit(lines, { 1, 0 }, { '(', '\\ta,', '\\t\")\",', '\\tb', ')' }, { 1, 0 }, split, { region = region })\nend\n\nT['split()']['respects `opts.detect.brackets`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.brackets = { '%b{}' }\")\n  validate_edit({ '[aaa]' }, { 1, 0 }, { '[aaa]' }, { 1, 0 }, split)\n  validate_edit({ '{aaa}' }, { 1, 0 }, { '{', '\\taaa', '}' }, { 1, 0 }, split)\n\n  -- Local\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, split, { detect = { brackets = {} } })\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, split, { detect = { brackets = { '%b[]' } } })\nend\n\nT['split()']['respects `opts.detect.separator`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.separator = '|'\")\n  validate_edit({ '(a|b)' }, { 1, 0 }, { '(', '\\ta|', '\\tb', ')' }, { 1, 0 }, split)\n\n  -- Local\n  local opts = { detect = { separator = '[,;]' } }\n  validate_edit({ '(a, b; c)' }, { 1, 0 }, { '(', '\\ta,', '\\tb;', '\\tc', ')' }, { 1, 0 }, split, opts)\n\n  -- Empty separator should mean no internal separator\n  opts = { detect = { separator = '' } }\n  validate_edit({ '(a, b; c)' }, { 1, 0 }, { '(', '\\ta, b; c', ')' }, { 1, 0 }, split, opts)\nend\n\nT['split()']['respects `opts.detect.exclude_regions`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.exclude_regions = { '%b[]' }\")\n  validate_edit(\n    { '(a, (b, c), [d, e])' },\n    { 1, 0 },\n    { '(', '\\ta,', '\\t(b,', '\\tc),', '\\t[d, e]', ')' },\n    { 1, 0 },\n    split\n  )\n\n  -- Local\n  local opts = { detect = { exclude_regions = { '%b()' } } }\n  validate_edit(\n    { '(a, (b, c), [d, e])' },\n    { 1, 0 },\n    { '(', '\\ta,', '\\t(b, c),', '\\t[d,', '\\te]', ')' },\n    { 1, 0 },\n    split,\n    opts\n  )\nend\n\nT['split()']['respects `opts.split.hooks_pre`'] = function()\n  child.lua('_G.hook_pre_1 = function(...) _G.hook_pre_1_args = { ... }; return ... end')\n  child.lua([[_G.hook_pre_2 = function(positions)\n    _G.hook_pre_2_positions = positions\n    return { positions[1] } end\n  ]])\n\n  local positions_ref = { { line = 1, col = 1 }, { line = 1, col = 4 } }\n\n  -- Global\n  child.lua('MiniSplitjoin.config.split.hooks_pre = { _G.hook_pre_2 }')\n  set_lines({ '(aaa)' })\n  split()\n  eq(get_lines(), { '(', 'aaa)' })\n  eq(child.lua_get('_G.hook_pre_1_args'), vim.NIL)\n  eq(child.lua_get('_G.hook_pre_2_positions'), positions_ref)\n\n  -- Local\n  set_lines({ '(aaa)' })\n  child.lua('MiniSplitjoin.split({ split = { hooks_pre = { _G.hook_pre_1, _G.hook_pre_2 } } })')\n  eq(get_lines(), { '(', 'aaa)' })\n  eq(child.lua_get('_G.hook_pre_1_args'), { positions_ref })\n  eq(child.lua_get('_G.hook_pre_2_positions'), positions_ref)\nend\n\nT['split()']['respects `opts.split.hooks_post`'] = function()\n  child.lua('_G.hook_post_1 = function(...) _G.hook_post_1_args = { ... }; return ... end')\n  child.lua([[_G.hook_post_2 = function(positions)\n    _G.hook_post_2_positions = positions\n    return { positions[1] } end\n  ]])\n\n  local positions_ref = { { line = 1, col = 1 }, { line = 2, col = 4 }, { line = 3, col = 1 } }\n\n  -- Global\n  child.lua('MiniSplitjoin.config.split.hooks_post = { _G.hook_post_2 }')\n  set_lines({ '(aaa)' })\n  local out = split()\n  eq(out, { { line = 1, col = 1 } })\n\n  eq(get_lines(), { '(', '\\taaa', ')' })\n  eq(child.lua_get('_G.hook_post_1_args'), vim.NIL)\n  eq(child.lua_get('_G.hook_post_2_positions'), positions_ref)\n\n  -- Local\n  set_lines({ '(aaa)' })\n  out = child.lua_get('MiniSplitjoin.split({ split = { hooks_post = { _G.hook_post_1, _G.hook_post_2 } } })')\n  eq(out, { { line = 1, col = 1 } })\n\n  eq(get_lines(), { '(', '\\taaa', ')' })\n  eq(child.lua_get('_G.hook_post_1_args'), { positions_ref })\n  eq(child.lua_get('_G.hook_post_2_positions'), positions_ref)\nend\n\nT['split()']['respects `vim.{g,b}.minisplitjoin_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisplitjoin_disable = true\n    validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, split)\n  end,\n})\n\nT['split()']['respects `vim.b.minisplitjoin_config`'] = function()\n  child.lua([[vim.b.minisplitjoin_config = { detect = { brackets = { '%b[]' } } }]])\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, split)\nend\n\nT['join()'] = new_set()\n\nlocal join = function(...) return child.lua_get('MiniSplitjoin.join(...)', { ... }) end\n\nT['join()']['works'] = function()\n  validate_edit({ '(', '\\taaa,', '\\tbb,', '\\tc', ')' }, { 1, 0 }, { '(aaa, bb, c)' }, { 1, 0 }, join)\n  validate_edit({ '[', '\\taaa,', '\\tbb,', '\\tc', ']' }, { 1, 0 }, { '[aaa, bb, c]' }, { 1, 0 }, join)\n  validate_edit({ '{', '\\taaa,', '\\tbb,', '\\tc', '}' }, { 1, 0 }, { '{aaa, bb, c}' }, { 1, 0 }, join)\n\n  validate_edit({ '(', 'aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, join)\n  validate_edit({ ' \\t(', 'aaa)' }, { 1, 2 }, { ' \\t(aaa)' }, { 1, 2 }, join)\nend\n\nT['join()']['does nothing if arguments are on single line'] = function()\n  validate_edit({ '(aa, b)' }, { 1, 0 }, { '(aa, b)' }, { 1, 0 }, join)\nend\n\nT['join()']['works inside comments'] = function()\n  -- After 'commentstring'\n  child.bo.commentstring = '# %s'\n  validate_edit({ '# (', '# \\taaa', '# )' }, { 1, 2 }, { '# (aaa)' }, { 1, 2 }, join)\n\n  -- After any entry in 'comments'\n  child.bo.comments = ':---,:--'\n  validate_edit({ '-- (', '-- \\taaa', '-- )' }, { 1, 3 }, { '-- (aaa)' }, { 1, 3 }, join)\n  validate_edit({ '--- (', '--- \\taaa', '--- )' }, { 1, 4 }, { '--- (aaa)' }, { 1, 4 }, join)\n\n  -- Respects `b` flag\n  child.bo.comments = 'b:*'\n  validate_edit({ '*(', '\\t*aaa', '*)' }, { 1, 1 }, { '*(*aaa*)' }, { 1, 1 }, join)\n  validate_edit({ '* (', '\\t* aaa', '* )' }, { 1, 2 }, { '* (aaa)' }, { 1, 2 }, join)\n  validate_edit({ '*\\t(', '\\t*\\taaa', '*\\t)' }, { 1, 2 }, { '*\\t(aaa)' }, { 1, 2 }, join)\n\n  -- Respects `f` flag (ignores as comment leader)\n  child.bo.comments = 'f:-'\n  validate_edit({ '(', '-aaa', ')' }, { 1, 0 }, { '(-aaa)' }, { 1, 0 }, join)\n  validate_edit({ '(', '- aaa', ')' }, { 1, 0 }, { '(- aaa)' }, { 1, 0 }, join)\n  validate_edit({ '(', '-\\taaa', ')' }, { 1, 0 }, { '(-\\taaa)' }, { 1, 0 }, join)\n  validate_edit({ '- (', '- aaa', '- )' }, { 1, 2 }, { '- (- aaa- )' }, { 1, 2 }, join)\nend\n\nT['join()']['works in empty brackets'] = function() validate_edit({ '()' }, { 1, 0 }, { '()' }, { 1, 0 }, join) end\n\nT['join()']['joins nested multiline argument into single line'] = function()\n  validate_edit(\n    { '(', '\\ta,', '\\t(', '\\t\\tb,', '\\t\\tc', '\\t),', '\\td', ')' },\n    { 1, 0 },\n    -- To not have padded brackets in nested arguments, join them separately\n    { '(a, ( b, c ), d)' },\n    { 1, 0 },\n    join\n  )\nend\n\nT['join()']['returns `nil` if no positions are found'] = function()\n  set_lines({ 'aaa' })\n  eq(join(), vim.NIL)\n  eq(get_lines(), { 'aaa' })\nend\n\nT['join()']['respects `opts.position`'] = function()\n  validate_edit({ ' (', ' \\taaa', ' )' }, { 1, 0 }, { ' (aaa)' }, { 1, 0 }, join, { position = { line = 1, col = 2 } })\n  validate_edit({ ' (aaa)' }, { 1, 1 }, { ' (aaa)' }, { 1, 1 }, join, { position = { line = 1, col = 1 } })\nend\n\nT['join()']['respects `opts.region`'] = function()\n  local lines = { '(', '\\ta,', '\\t\")\",', '\\tb', ')' }\n  local region = { from = { line = 1, col = 1 }, to = { line = 5, col = 0 } }\n  validate_edit(lines, { 1, 0 }, { '(a, \")\", b)' }, { 1, 0 }, join, { region = region })\nend\n\nT['join()']['respects `opts.detect.brackets`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.brackets = { '%b{}' }\")\n  validate_edit({ '[aaa]' }, { 1, 0 }, { '[aaa]' }, { 1, 0 }, join)\n  validate_edit({ '{', '\\taaa', '}' }, { 1, 0 }, { '{aaa}' }, { 1, 0 }, join)\n\n  -- Local\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, join, { detect = { brackets = {} } })\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, join, { detect = { brackets = { '%b[]' } } })\nend\n\nT['join()']['respects `opts.detect.separator`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.separator = '|'\")\n  validate_edit({ '(', '\\ta|', '\\tb', ')' }, { 1, 0 }, { '(a| b)' }, { 1, 0 }, join)\n\n  -- Local\n  local opts = { detect = { separator = '[,;]' } }\n  validate_edit({ '(', '\\ta,', '\\tb;', '\\tc', ')' }, { 1, 0 }, { '(a, b; c)' }, { 1, 0 }, join, opts)\n\n  -- Empty separator should mean no internal separator\n  opts = { detect = { separator = '' } }\n  validate_edit({ '(', '\\ta, b; c', ')' }, { 1, 0 }, { '(a, b; c)' }, { 1, 0 }, join, opts)\nend\n\nT['join()']['respects `opts.detect.exclude_regions`'] = function()\n  -- Global\n  child.lua(\"MiniSplitjoin.config.detect.exclude_regions = { '%b[]' }\")\n  validate_edit({ '(', '\\ta,', '\\t(b,', '\\tc),', '\\t[d, e]', ')' }, { 1, 0 }, { '(a, (b, c), [d, e])' }, { 1, 0 }, join)\n\n  -- Local\n  local opts = { detect = { exclude_regions = { '%b()' } } }\n  validate_edit(\n    { '(', '\\ta,', '\\t(b, c),', '\\t[d,', '\\te]', ')' },\n    { 1, 0 },\n    { '(a, (b, c), [d, e])' },\n    { 1, 0 },\n    join,\n    opts\n  )\nend\n\nT['join()']['respects `opts.join.hooks_pre`'] = function()\n  child.lua('_G.hook_pre_1 = function(...) _G.hook_pre_1_args = { ... }; return ... end')\n  child.lua([[_G.hook_pre_2 = function(positions)\n    _G.hook_pre_2_positions = positions\n    return { positions[1] } end\n  ]])\n\n  local positions_ref = { { line = 1, col = 1 }, { line = 2, col = 3 } }\n\n  -- Global\n  child.lua('MiniSplitjoin.config.join.hooks_pre = { _G.hook_pre_2 }')\n  set_lines({ '(', 'aaa', ')' })\n  join()\n  eq(get_lines(), { '(aaa', ')' })\n  eq(child.lua_get('_G.hook_pre_1_args'), vim.NIL)\n  eq(child.lua_get('_G.hook_pre_2_positions'), positions_ref)\n\n  -- Local\n  set_lines({ '(', 'aaa', ')' })\n  child.lua('MiniSplitjoin.join({ join = { hooks_pre = { _G.hook_pre_1, _G.hook_pre_2 } } })')\n  eq(get_lines(), { '(aaa', ')' })\n  eq(child.lua_get('_G.hook_pre_1_args'), { positions_ref })\n  eq(child.lua_get('_G.hook_pre_2_positions'), positions_ref)\nend\n\nT['join()']['respects `opts.join.hooks_post`'] = function()\n  child.lua('_G.hook_post_1 = function(...) _G.hook_post_1_args = { ... }; return ... end')\n  child.lua([[_G.hook_post_2 = function(positions)\n    _G.hook_post_2_positions = positions\n    return { positions[1] } end\n  ]])\n\n  local positions_ref = { { line = 1, col = 1 }, { line = 1, col = 4 }, { line = 1, col = 5 } }\n\n  -- Global\n  child.lua('MiniSplitjoin.config.join.hooks_post = { _G.hook_post_2 }')\n  set_lines({ '(', 'aaa', ')' })\n  local out = join()\n  eq(out, { { line = 1, col = 1 } })\n\n  eq(get_lines(), { '(aaa)' })\n  eq(child.lua_get('_G.hook_post_1_args'), vim.NIL)\n  eq(child.lua_get('_G.hook_post_2_positions'), positions_ref)\n\n  -- Local\n  set_lines({ '(', 'aaa', ')' })\n  out = child.lua_get('MiniSplitjoin.join({ join = { hooks_post = { _G.hook_post_1, _G.hook_post_2 } } })')\n  eq(out, { { line = 1, col = 1 } })\n\n  eq(get_lines(), { '(aaa)' })\n  eq(child.lua_get('_G.hook_post_1_args'), { positions_ref })\n  eq(child.lua_get('_G.hook_post_2_positions'), positions_ref)\nend\n\nT['join()']['respects `vim.{g,b}.minisplitjoin_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisplitjoin_disable = true\n    validate_edit({ '(', 'aaa', ')' }, { 1, 0 }, { '(', 'aaa', ')' }, { 1, 0 }, join)\n  end,\n})\n\nT['join()']['respects `vim.b.minisplitjoin_config`'] = function()\n  child.lua([[vim.b.minisplitjoin_config = { detect = { brackets = { '%b[]' } } }]])\n  validate_edit({ '(', 'aaa', ')' }, { 1, 0 }, { '(', 'aaa', ')' }, { 1, 0 }, join)\nend\n\nT['gen_hook'] = new_set()\n\nT['gen_hook']['pad_brackets()'] = new_set()\n\nT['gen_hook']['pad_brackets()']['works'] = function()\n  child.lua('MiniSplitjoin.config.join.hooks_post = { MiniSplitjoin.gen_hook.pad_brackets() }')\n  validate_edit({ '(', '\\taaa,', '\\tbb,', '\\tc', ')' }, { 1, 0 }, { '( aaa, bb, c )' }, { 1, 0 }, join)\n  validate_edit({ '[', '\\taaa,', '\\tbb,', '\\tc', ']' }, { 1, 0 }, { '[ aaa, bb, c ]' }, { 1, 0 }, join)\n  validate_edit({ '{', '\\taaa,', '\\tbb,', '\\tc', '}' }, { 1, 0 }, { '{ aaa, bb, c }' }, { 1, 0 }, join)\n\n  -- Should return correctly updated input\n  set_lines({ '(', 'a,', 'b', ')' })\n  local out = join()\n  eq(get_lines(), { '( a, b )' })\n  eq(out, { { line = 1, col = 1 }, { line = 1, col = 4 }, { line = 1, col = 6 }, { line = 1, col = 8 } })\nend\n\nT['gen_hook']['pad_brackets()']['does not act in case of no arguments'] = function()\n  child.lua('MiniSplitjoin.config.join.hooks_post = { MiniSplitjoin.gen_hook.pad_brackets() }')\n  validate_edit({ '(', ')' }, { 1, 0 }, { '()' }, { 1, 0 }, join)\nend\n\nT['gen_hook']['pad_brackets()']['respects `opts.pad`'] = function()\n  child.lua(\"MiniSplitjoin.config.join.hooks_post = { MiniSplitjoin.gen_hook.pad_brackets({ pad = '  ' }) }\")\n  validate_edit({ '(', 'aa,', 'b', ')' }, { 1, 0 }, { '(  aa, b  )' }, { 1, 0 }, join)\nend\n\nT['gen_hook']['pad_brackets()']['respects `opts.brackets`'] = function()\n  child.lua([[MiniSplitjoin.config.join.hooks_post = {\n    MiniSplitjoin.gen_hook.pad_brackets({ brackets = { '%b{}' } }),\n  }]])\n  validate_edit({ '(', 'aa,', 'b', ')' }, { 1, 0 }, { '(aa, b)' }, { 1, 0 }, join)\n  validate_edit({ '[', 'aa,', 'b', ']' }, { 1, 0 }, { '[aa, b]' }, { 1, 0 }, join)\n  validate_edit({ '{', 'aa,', 'b', '}' }, { 1, 0 }, { '{ aa, b }' }, { 1, 0 }, join)\nend\n\nT['gen_hook']['add_trailing_separator()'] = new_set()\n\nT['gen_hook']['add_trailing_separator()']['works'] = function()\n  child.lua('MiniSplitjoin.config.split.hooks_post = { MiniSplitjoin.gen_hook.add_trailing_separator() }')\n  validate_edit({ '(aa)' }, { 1, 0 }, { '(', '\\taa,', ')' }, { 1, 0 }, split)\n  validate_edit({ '[aa]' }, { 1, 0 }, { '[', '\\taa,', ']' }, { 1, 0 }, split)\n  validate_edit({ '{aa}' }, { 1, 0 }, { '{', '\\taa,', '}' }, { 1, 0 }, split)\n\n  validate_edit({ '(aa, b)' }, { 1, 0 }, { '(', '\\taa,', '\\tb,', ')' }, { 1, 0 }, split)\n\n  -- Should return correctly updated input\n  set_lines({ '(aa)' })\n  local out = split()\n  eq(get_lines(), { '(', '\\taa,', ')' })\n  eq(out, { { line = 1, col = 1 }, { line = 2, col = 3 }, { line = 3, col = 1 } })\nend\n\nT['gen_hook']['add_trailing_separator()']['does nothing if there is already trailing separator'] = function()\n  child.lua('MiniSplitjoin.config.split.hooks_post = { MiniSplitjoin.gen_hook.add_trailing_separator() }')\n  validate_edit({ '(aa,)' }, { 1, 0 }, { '(', '\\taa,', ')' }, { 1, 0 }, split)\n  validate_edit({ '(aa, b,)' }, { 1, 0 }, { '(', '\\taa,', '\\tb,', ')' }, { 1, 0 }, split)\nend\n\nT['gen_hook']['add_trailing_separator()']['does not act in case of no arguments'] = function()\n  child.lua('MiniSplitjoin.config.split.hooks_post = { MiniSplitjoin.gen_hook.add_trailing_separator() }')\n  validate_edit({ '()' }, { 1, 0 }, { '(', ')' }, { 1, 0 }, split)\nend\n\nT['gen_hook']['add_trailing_separator()']['respects `opts.sep`'] = function()\n  child.lua([[MiniSplitjoin.config.split.hooks_post = {\n    MiniSplitjoin.gen_hook.add_trailing_separator({ sep = '!'}),\n  }]])\n  validate_edit({ '(aa)' }, { 1, 0 }, { '(', '\\taa!', ')' }, { 1, 0 }, split)\nend\n\nT['gen_hook']['add_trailing_separator()']['respects `opts.brackets`'] = function()\n  child.lua([[MiniSplitjoin.config.split.hooks_post = {\n    MiniSplitjoin.gen_hook.add_trailing_separator({ brackets = { '%b{}' }}),\n  }]])\n  validate_edit({ '(aa)' }, { 1, 0 }, { '(', '\\taa', ')' }, { 1, 0 }, split)\n  validate_edit({ '[aa]' }, { 1, 0 }, { '[', '\\taa', ']' }, { 1, 0 }, split)\n  validate_edit({ '{aa}' }, { 1, 0 }, { '{', '\\taa,', '}' }, { 1, 0 }, split)\nend\n\nT['gen_hook']['del_trailing_separator()'] = new_set()\n\nT['gen_hook']['del_trailing_separator()']['works'] = function()\n  child.lua('MiniSplitjoin.config.join.hooks_post = { MiniSplitjoin.gen_hook.del_trailing_separator() }')\n  validate_edit({ '(', '\\taa,', ')' }, { 1, 0 }, { '(aa)' }, { 1, 0 }, join)\n  validate_edit({ '[', '\\taa,', ']' }, { 1, 0 }, { '[aa]' }, { 1, 0 }, join)\n  validate_edit({ '{', '\\taa,', '}' }, { 1, 0 }, { '{aa}' }, { 1, 0 }, join)\n\n  validate_edit({ '(', '\\taa,', '\\tb,', ')' }, { 1, 0 }, { '(aa, b)' }, { 1, 0 }, join)\n\n  -- Should return correctly updated input\n  set_lines({ '(', '\\taa,', ')' })\n  local out = join()\n  eq(get_lines(), { '(aa)' })\n  eq(out, { { line = 1, col = 1 }, { line = 1, col = 4 }, { line = 1, col = 4 } })\nend\n\nT['gen_hook']['del_trailing_separator()']['does nothing if there is already no trailing separator'] = function()\n  child.lua('MiniSplitjoin.config.join.hooks_post = { MiniSplitjoin.gen_hook.del_trailing_separator() }')\n  validate_edit({ '(', '\\taa', ')' }, { 1, 0 }, { '(aa)' }, { 1, 0 }, join)\n  validate_edit({ '(', '\\taa,', '\\tb', ')' }, { 1, 0 }, { '(aa, b)' }, { 1, 0 }, join)\nend\n\nT['gen_hook']['del_trailing_separator()']['respects `opts.sep`'] = function()\n  child.lua([[MiniSplitjoin.config.join.hooks_post = {\n    MiniSplitjoin.gen_hook.del_trailing_separator({ sep = '!'}),\n  }]])\n  validate_edit({ '(', '\\taa!', ')' }, { 1, 0 }, { '(aa)' }, { 1, 0 }, join)\nend\n\nT['gen_hook']['del_trailing_separator()']['respects `opts.brackets`'] = function()\n  child.lua([[MiniSplitjoin.config.join.hooks_post = {\n    MiniSplitjoin.gen_hook.del_trailing_separator({ brackets = { '%b{}' }}),\n  }]])\n  validate_edit({ '(', '\\taa,', ')' }, { 1, 0 }, { '(aa,)' }, { 1, 0 }, join)\n  validate_edit({ '[', '\\taa,', ']' }, { 1, 0 }, { '[aa,]' }, { 1, 0 }, join)\n  validate_edit({ '{', '\\taa,', '}' }, { 1, 0 }, { '{aa}' }, { 1, 0 }, join)\nend\n\nT['split_at()'] = new_set()\n\nlocal split_at = function(positions)\n  return child.lua_get('MiniSplitjoin.split_at(...)', { vim.tbl_map(simplepos_to_pos, positions) })\nend\n\nT['split_at()']['works'] = function()\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '(', '\\taaa', ')' }, { 2, 2 }, split_at, { { 1, 1 }, { 1, 4 } })\n\n  validate_edit({ '()' }, { 1, 1 }, { '(', '', ')' }, { 3, 0 }, split_at, { { 1, 1 }, { 1, 1 } })\n\n  validate_edit(\n    { '(aaa, bb, c)' },\n    { 1, 7 },\n    { '(', '\\taaa,', '\\tbb,', '\\tc', ')' },\n    { 3, 2 },\n    split_at,\n    { { 1, 1 }, { 1, 5 }, { 1, 9 }, { 1, 11 } }\n  )\nend\n\nT['split_at()']['works not on single line'] = function()\n  validate_edit(\n    { 'aabb', 'ccdd' },\n    { 1, 3 },\n    { 'aa', '\\tbb', '\\tcc', 'dd' },\n    { 2, 2 },\n    split_at,\n    { { 1, 2 }, { 2, 2 } }\n  )\nend\n\nT['split_at()']['properly tracks cursor'] = function()\n  validate_edit({ '()' }, { 1, 0 }, { '(', ')' }, { 1, 0 }, split_at, { { 1, 1 } })\n  validate_edit({ '()' }, { 1, 1 }, { '(', ')' }, { 2, 0 }, split_at, { { 1, 1 } })\n\n  local cursors = {\n    { before = { 1, 0 }, after = { 1, 0 } },\n    { before = { 1, 1 }, after = { 1, 1 } },\n    { before = { 1, 2 }, after = { 2, 1 } },\n    { before = { 1, 3 }, after = { 2, 1 } },\n    { before = { 1, 4 }, after = { 2, 2 } },\n    { before = { 1, 5 }, after = { 2, 3 } },\n    { before = { 1, 6 }, after = { 2, 3 } },\n    { before = { 1, 7 }, after = { 3, 0 } },\n    { before = { 1, 8 }, after = { 3, 1 } },\n  }\n  for _, cursor in ipairs(cursors) do\n    validate_edit(\n      { 'b( aaa )b' },\n      cursor.before,\n      { 'b(', '\\taaa', ')b' },\n      cursor.after,\n      split_at,\n      { { 1, 2 }, { 1, 7 } }\n    )\n  end\nend\n\nT['split_at()']['copies indent of current line'] = function()\n  validate_edit(\n    { ' \\t (aaa)' },\n    { 1, 5 },\n    { ' \\t (', ' \\t \\taaa', ' \\t )' },\n    { 2, 5 },\n    split_at,\n    { { 1, 4 }, { 1, 7 } }\n  )\nend\n\nT['split_at()']['does not increase indent of blank lines'] = function()\n  validate_edit(\n    { '(', 'a,b)' },\n    { 2, 3 },\n    { '(', '', '\\ta,', '\\tb', ')' },\n    { 5, 0 },\n    split_at,\n    { { 1, 1 }, { 2, 2 }, { 2, 3 } }\n  )\n\n  validate_edit({ '  (', ')' }, { 2, 0 }, { '  (', '  ', ')' }, { 3, 0 }, split_at, { { 1, 3 } })\nend\n\nT['split_at()']['handles extra whitespace'] = function()\n  validate_edit({ '(   aaa   )' }, { 1, 5 }, { '(', '\\taaa', ')' }, { 2, 2 }, split_at, { { 1, 1 }, { 1, 7 } })\n  validate_edit({ '(   aaa   )' }, { 1, 5 }, { '(', '\\taaa', ')' }, { 2, 2 }, split_at, { { 1, 3 }, { 1, 9 } })\nend\n\nT['split_at()']['correctly tracks input positions'] = function()\n  set_lines({ '(aaa, bb, c)' })\n  local out = split_at({ { 1, 1 }, { 1, 5 }, { 1, 9 }, { 1, 11 } })\n  validate_positions(out, { { 1, 1 }, { 2, 5 }, { 3, 4 }, { 4, 2 } })\n  eq(get_lines(), { '(', '\\taaa,', '\\tbb,', '\\tc', ')' })\nend\n\n--stylua: ignore\nT['split_at()']['works inside comments'] = function()\n  -- After 'commentstring'\n  child.bo.commentstring = '# %s'\n  validate_edit({ '# (aaa)' }, { 1, 2 }, { '# (', '# \\taaa', '# )' }, { 1, 2 }, split_at, { { 1, 3 }, { 1, 6 } })\n\n  -- After any entry in 'comments'\n  child.bo.comments = ':---,:--'\n  validate_edit({ '-- (aaa)' },  { 1, 3 }, { '-- (',  '-- \\taaa',  '-- )' },  { 1, 3 }, split_at, { { 1, 4 }, { 1, 7 } })\n  validate_edit({ '--- (aaa)' }, { 1, 4 }, { '--- (', '--- \\taaa', '--- )' }, { 1, 4 }, split_at, { { 1, 5 }, { 1, 8 } })\n\n  -- Respects `b` flag\n  child.bo.comments = 'b:*'\n  validate_edit({ '*(aaa)' }, { 1, 1 }, { '*(', '\\taaa', ')' }, { 1, 1 }, split_at, { { 1, 2 }, { 1, 5 } })\n  validate_edit({ '* (aaa)' }, { 1, 2 }, { '* (', '* \\taaa', '* )' }, { 1, 2 }, split_at, { { 1, 3 }, { 1, 6 } })\n  validate_edit({ '*\\t(aaa)' }, { 1, 2 }, { '*\\t(', '*\\t\\taaa', '*\\t)' }, { 1, 2 }, split_at, { { 1, 3 }, { 1, 6 } })\n\n  -- Respects `f` flag (ignores as comment leader)\n  child.bo.comments = 'f:-'\n  validate_edit({ '-(aaa)' }, { 1, 1 }, { '-(', '\\taaa', ')' }, { 1, 1 }, split_at, { { 1, 2 }, { 1, 5 } })\n  validate_edit({ '- (aaa)' }, { 1, 2 }, { '- (', '\\taaa', ')' }, { 1, 2 }, split_at, { { 1, 3 }, { 1, 6 } })\n  validate_edit({ '-\\t(aaa)' }, { 1, 2 }, { '-\\t(', '\\taaa', ')' }, { 1, 2 }, split_at, { { 1, 3 }, { 1, 6 } })\nend\n\nT['split_at()']['correctly increases indent of commented line in non-commented block'] = function()\n  child.bo.commentstring = '# %s'\n\n  validate_edit(\n    { '(aa', '# b', 'c)' },\n    { 1, 0 },\n    { '(', '\\taa', '\\t# b', '\\tc', ')' },\n    { 1, 0 },\n    split_at,\n    { { 1, 1 }, { 3, 1 } }\n  )\nend\n\nT['split_at()']['uses first and last positions to determine indent range'] = function()\n  validate_edit(\n    { '(a, b, c)' },\n    { 1, 0 },\n    { '(', 'a,', 'b,', '\\tc', ')' },\n    { 1, 0 },\n    split_at,\n    { { 1, 6 }, { 1, 3 }, { 1, 1 }, { 1, 8 } }\n  )\nend\n\nT['split_at()'][\"respects 'expandtab' and 'shiftwidth' for indent increase\"] = function()\n  child.o.expandtab = true\n  child.o.shiftwidth = 3\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '(', '   aaa', ')' }, { 1, 0 }, split_at, { { 1, 1 }, { 1, 4 } })\nend\n\nT['join_at()'] = new_set()\n\nlocal join_at = function(positions)\n  return child.lua_get('MiniSplitjoin.join_at(...)', { vim.tbl_map(simplepos_to_pos, positions) })\nend\n\nT['join_at()']['works'] = function()\n  validate_edit(\n    { '(', '\\taaa,', '   bb,', 'c', ')' },\n    { 2, 2 },\n    { '(aaa, bb, c)' },\n    { 1, 2 },\n    join_at,\n    { { 1, 1 }, { 2, 4 }, { 3, 3 }, { 4, 1 } }\n  )\nend\n\nT['join_at()']['works on single line'] = function()\n  validate_edit({ '(', '\\ta', '\\tb', ')' }, { 1, 0 }, { '(a b)' }, { 1, 0 }, join_at, { { 1, 1 }, { 1, 1 }, { 1, 1 } })\nend\n\nT['join_at()']['joins line at any its column'] = function()\n  for i = 1, 4 do\n    validate_edit({ '   (', '\\taaa', ')' }, { 2, 2 }, { '   (aaa)' }, { 1, 5 }, join_at, { { 1, i }, { 2, i } })\n  end\nend\n\nT['join_at()']['properly tracks cursor'] = function()\n  validate_edit({ '(', ')' }, { 1, 0 }, { '()' }, { 1, 0 }, join_at, { { 1, 1 } })\n  validate_edit({ '(', ')' }, { 2, 0 }, { '()' }, { 1, 1 }, join_at, { { 1, 1 } })\n\n  local cursors = {\n    { before = { 1, 0 }, after = { 1, 0 } },\n    { before = { 1, 1 }, after = { 1, 1 } },\n    { before = { 2, 0 }, after = { 1, 2 } },\n    { before = { 2, 1 }, after = { 1, 2 } },\n    { before = { 2, 2 }, after = { 1, 3 } },\n    { before = { 2, 3 }, after = { 1, 4 } },\n    { before = { 2, 4 }, after = { 1, 5 } },\n    { before = { 3, 0 }, after = { 1, 5 } },\n    { before = { 3, 1 }, after = { 1, 6 } },\n  }\n  for _, cursor in ipairs(cursors) do\n    validate_edit({ 'b(', '\\taaa ', ')b' }, cursor.before, { 'b(aaa)b' }, cursor.after, join_at, { { 1, 2 }, { 2, 4 } })\n  end\nend\n\nT['join_at()']['handles extra whitespace'] = function()\n  validate_edit(\n    { '( \\t', '\\t\\ta  ', '  b\\t\\t', ' \\t  )' },\n    { 1, 0 },\n    { '(a b)' },\n    { 1, 0 },\n    join_at,\n    { { 1, 1 }, { 2, 1 }, { 3, 1 } }\n  )\nend\n\nT['join_at()']['correctly works with positions on last line'] = function()\n  validate_edit(\n    { '(', 'a', ')b' },\n    { 1, 0 },\n    { '(a )b' },\n    { 1, 0 },\n    join_at,\n    { { 1, 1 }, { 2, 1 }, { 3, 1 }, { 3, 2 } }\n  )\nend\n\nT['join_at()']['correctly tracks input positions'] = function()\n  set_lines({ '(', '\\taaa,', '\\tbb,', '\\tc', ')' })\n  local out = join_at({ { 1, 1 }, { 2, 5 }, { 3, 4 }, { 4, 2 } })\n  validate_positions(out, { { 1, 1 }, { 1, 5 }, { 1, 9 }, { 1, 11 } })\n  eq(get_lines(), { '(aaa, bb, c)' })\nend\n\n--stylua: ignore\nT['join_at()']['works inside comments'] = function()\n  local two_lines_pos = { { 1, 1 }, { 2, 1 } }\n\n  -- After 'commentstring'\n  child.bo.commentstring = '# %s'\n  validate_edit({ '# (', '# \\taaa', '# )' }, { 1, 2 }, { '# (aaa)' }, { 1, 2 }, join_at, two_lines_pos)\n  validate_edit({ '# (', 'aaa',     '# )' }, { 1, 2 }, { '# (aaa)' }, { 1, 2 }, join_at, two_lines_pos)\n\n  -- After any entry in 'comments'\n  child.bo.comments = ':---,:--'\n  validate_edit({ '-- (',  '-- \\taaa',  '-- )' },  { 1, 3 }, { '-- (aaa)' },  { 1, 3 }, join_at, two_lines_pos)\n  validate_edit({ '--- (', '--- \\taaa', '--- )' }, { 1, 4 }, { '--- (aaa)' }, { 1, 4 }, join_at, two_lines_pos)\n\n  -- Respects `b` flag\n  child.bo.comments = 'b:*'\n  validate_edit({ '*(', '\\t*aaa', '*)' }, { 1, 1 }, { '*(*aaa*)' }, { 1, 1 }, join_at, two_lines_pos)\n  validate_edit({ '* (', '\\t* aaa', '* )' }, { 1, 2 }, { '* (aaa)' }, { 1, 2 }, join_at, two_lines_pos)\n  validate_edit({ '*\\t(', '\\t*\\taaa', '*\\t)' }, { 1, 2 }, { '*\\t(aaa)' }, { 1, 2 }, join_at, two_lines_pos)\n\n  -- Respects `f` flag (ignores as comment leader)\n  child.bo.comments = 'f:-'\n  validate_edit({ '(', '-aaa', ')' }, { 1, 0 }, { '(-aaa)' }, { 1, 0 }, join_at, two_lines_pos)\n  validate_edit({ '(', '- aaa', ')' }, { 1, 0 }, { '(- aaa)' }, { 1, 0 }, join_at, two_lines_pos)\n  validate_edit({ '(', '-\\taaa', ')' }, { 1, 0 }, { '(-\\taaa)' }, { 1, 0 }, join_at, two_lines_pos)\n  validate_edit({ '- (', '- aaa', '- )' }, { 1, 2 }, { '- (- aaa- )' }, { 1, 2 }, join_at, two_lines_pos)\nend\n\nT['get_visual_region()'] = new_set()\n\nT['get_visual_region()']['works for charwise selection'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_cursor(1, 1)\n  type_keys('v')\n  set_cursor(2, 1)\n  type_keys('<Esc>')\n\n  eq(child.lua_get('MiniSplitjoin.get_visual_region()'), { from = { line = 1, col = 2 }, to = { line = 2, col = 2 } })\nend\n\nT['get_visual_region()']['works for linewise selection'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_cursor(1, 1)\n  type_keys('V')\n  set_cursor(2, 1)\n  type_keys('<Esc>')\n\n  -- It should tweak marks to be start/end of lines\n  eq(child.lua_get('MiniSplitjoin.get_visual_region()'), { from = { line = 1, col = 1 }, to = { line = 2, col = 3 } })\nend\n\nT['get_visual_region()']['works for blockwise selection'] = function()\n  set_lines({ 'aaa', 'bbb' })\n  set_cursor(1, 1)\n  type_keys('<C-v>')\n  set_cursor(2, 2)\n  type_keys('<Esc>')\n\n  eq(child.lua_get('MiniSplitjoin.get_visual_region()'), { from = { line = 1, col = 2 }, to = { line = 2, col = 3 } })\nend\n\nT['get_indent_part()'] = new_set()\n\nlocal get_indent_part = function(...) return child.lua_get('MiniSplitjoin.get_indent_part(...)', { ... }) end\n\nT['get_indent_part()']['works'] = function()\n  local validate = function(input, out_ref) eq(get_indent_part(input), out_ref) end\n\n  -- No indent\n  validate('aa', '')\n\n  -- Whitespace indent\n  validate(' aa', ' ')\n  validate('\\taa', '\\t')\n  validate('\\t \\taa', '\\t \\t')\n\n  -- Indent with comment under 'commentstring'\n  child.o.commentstring = '# %s'\n\n  validate('#aa', '#')\n  validate('# aa', '# ')\n  validate(' # aa', ' # ')\n  validate('\\t# aa', '\\t# ')\n  validate('\\t \\t# aa', '\\t \\t# ')\n  validate('#\\taa', '#\\t')\n\n  -- Indent with comment under 'comments' parts\n  child.bo.comments = ':---,:--'\n\n  validate('--aa', '--')\n  validate('-- aa', '-- ')\n  validate(' -- aa', ' -- ')\n  validate('\\t-- aa', '\\t-- ')\n  validate('\\t \\t-- aa', '\\t \\t-- ')\n  validate('--\\taa', '--\\t')\n\n  validate('---aa', '---')\n  validate('--- aa', '--- ')\n  validate(' --- aa', ' --- ')\n  validate('\\t--- aa', '\\t--- ')\n  validate('\\t \\t--- aa', '\\t \\t--- ')\n  validate('---\\taa', '---\\t')\n\n  -- Should respect `b` flag\n  child.bo.comments = 'b:*'\n  validate('*aa', '')\n  validate(' *aa', ' ')\n  validate('\\t*aa', '\\t')\n\n  validate(' * aa', ' * ')\n  validate(' *\\taa', ' *\\t')\n  validate('\\t* aa', '\\t* ')\n  validate('\\t*\\taa', '\\t*\\t')\n\n  -- Should respect `f` flag (ignore comment leader)\n  child.bo.comments = 'f:-'\n  validate('-aa', '')\n  validate(' -aa', ' ')\n  validate(' - aa', ' ')\n  validate('\\t-aa', '\\t')\n  validate('\\t-\\taa', '\\t')\nend\n\nT['get_indent_part()']['respects `respect_comments` argument'] = function()\n  local validate = function(input, out_ref) eq(get_indent_part(input, false), out_ref) end\n\n  validate('aa', '')\n\n  validate(' aa', ' ')\n  validate('\\taa', '\\t')\n  validate('\\t \\taa', '\\t \\t')\n\n  child.o.commentstring = '# %s'\n  validate('# aa', '')\n  validate(' # aa', ' ')\n  validate('\\t# aa', '\\t')\n  validate('\\t \\t# aa', '\\t \\t')\n\n  child.o.comments = ':---,:--'\n  validate('-- aa', '')\n  validate(' -- aa', ' ')\n  validate('\\t-- aa', '\\t')\n  validate('\\t \\t-- aa', '\\t \\t')\n\n  validate('--- aa', '')\n  validate(' --- aa', ' ')\n  validate('\\t--- aa', '\\t')\n  validate('\\t \\t--- aa', '\\t \\t')\nend\n\n-- Integration tests ==========================================================\nT['Mappings'] = new_set()\n\nT['Mappings']['Toggle'] = new_set()\n\nT['Mappings']['Toggle']['works in Normal mode'] = function()\n  validate_keys({ '(aa, b)' }, { 1, 0 }, { '(', '\\taa,', '\\tb', ')' }, { 1, 0 }, 'gS')\n  validate_keys({ '(', '\\taa,', '\\tb', ')' }, { 1, 0 }, { '(aa, b)' }, { 1, 0 }, 'gS')\n\n  -- Should also work with dot-repeat\n  set_lines({ '(', '(', 'a', ')', ')' })\n  set_cursor(3, 0)\n  type_keys('gS')\n  eq(get_lines(), { '(', '(a)', ')' })\n\n  set_cursor(1, 0)\n  type_keys('.')\n  eq(get_lines(), { '((a))' })\nend\n\nT['Mappings']['Toggle']['works in Visual mode'] = function()\n  validate_keys({ '(aa, \")\", b)' }, { 1, 0 }, { '(', '\\taa,', '\\t\")\",', '\\tb', ')' }, { 1, 0 }, 'VgS')\n  validate_keys({ '(aa)', 'bb' }, { 1, 0 }, { '(aa)bb' }, { 1, 0 }, 'VjgS')\nend\n\nT['Mappings']['Toggle']['works with different mapping'] = function()\n  child.api.nvim_del_keymap('n', 'gS')\n  child.api.nvim_del_keymap('x', 'gS')\n\n  reload_module({ mappings = { toggle = 'gs' } })\n  validate_keys({ '(aa, b)' }, { 1, 0 }, { '(', '\\taa,', '\\tb', ')' }, { 1, 0 }, 'gs')\n  validate_keys({ '(aa, \")\", b)' }, { 1, 0 }, { '(', '\\taa,', '\\t\")\",', '\\tb', ')' }, { 1, 0 }, 'Vgs')\nend\n\nT['Mappings']['Toggle']['respects `vim.{g,b}.minisplitjoin_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisplitjoin_disable = true\n    validate_keys({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, 'gS')\n  end,\n})\n\nT['Mappings']['Split'] = new_set()\n\nT['Mappings']['Split']['works in Normal mode'] = function()\n  reload_module({ mappings = { split = 'S' } })\n\n  validate_keys({ '(aa, b)' }, { 1, 0 }, { '(', '\\taa,', '\\tb', ')' }, { 1, 0 }, 'S')\n\n  -- Should also work with dot-repeat\n  set_lines({ '((a))' })\n  set_cursor(1, 0)\n  type_keys('S')\n  eq(get_lines(), { '(', '\\t(a)', ')' })\n\n  set_cursor(2, 1)\n  type_keys('.')\n  eq(get_lines(), { '(', '\\t(', '\\t\\ta', '\\t)', ')' })\nend\n\nT['Mappings']['Split']['works in Visual mode'] = function()\n  reload_module({ mappings = { split = 'S' } })\n  validate_keys({ '(aa, \")\", b)' }, { 1, 0 }, { '(', '\\taa,', '\\t\")\",', '\\tb', ')' }, { 1, 0 }, 'VS')\nend\n\nT['Mappings']['Split']['respects `vim.{g,b}.minisplitjoin_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    reload_module({ mappings = { split = 'S' } })\n    child[var_type].minisplitjoin_disable = true\n    validate_keys({ '(aaa)' }, { 1, 0 }, { '(aaa)' }, { 1, 0 }, 'S')\n  end,\n})\n\nT['Mappings']['Join'] = new_set()\n\nT['Mappings']['Join']['works in Normal mode'] = function()\n  reload_module({ mappings = { join = 'J' } })\n\n  validate_keys({ '(', '\\taa,', '\\tb', ')' }, { 1, 0 }, { '(aa, b)' }, { 1, 0 }, 'J')\n\n  -- Should also work with dot-repeat\n  set_lines({ '(', '(', 'a', ')', ')' })\n  set_cursor(3, 0)\n  type_keys('J')\n  eq(get_lines(), { '(', '(a)', ')' })\n\n  set_cursor(1, 0)\n  type_keys('.')\n  eq(get_lines(), { '((a))' })\nend\n\nT['Mappings']['Join']['works in Visual mode'] = function()\n  reload_module({ mappings = { join = 'J' } })\n  validate_keys({ '(aa)', 'bb' }, { 1, 0 }, { '(aa)bb' }, { 1, 0 }, 'VjJ')\nend\n\nT['Mappings']['Join']['respects `vim.{g,b}.minisplitjoin_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    reload_module({ mappings = { join = 'J' } })\n    child[var_type].minisplitjoin_disable = true\n    validate_keys({ '(', 'aaa', ')' }, { 1, 0 }, { '(', 'aaa', ')' }, { 1, 0 }, 'J')\n  end,\n})\n\nreturn T\n"
  },
  {
    "path": "tests/test_starter.lua",
    "content": "-- NOTE: These are basic tests which cover basic functionality. A lot of\n-- nuances are not tested to meet \"complexity-necessity\" trade-off. Feel free\n-- to add tests for new behavior and found edge cases.\nlocal helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('starter', config) end\nlocal unload_module = function() child.mini_unload('starter') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal reload_from_strconfig = function(strconfig) unload_module(); child.mini_load_strconfig('starter', strconfig) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Make helpers\nlocal is_starter_shown = function() return child.bo.filetype == 'ministarter' end\n\nlocal validate_starter_shown = function() eq(is_starter_shown(), true) end\n\nlocal validate_starter_not_shown = function() eq(is_starter_shown(), false) end\n\nlocal validate_equal_starter = function(strconfig_1, strconfig_2)\n  -- Reload with first config\n  reload_from_strconfig(strconfig_1)\n  child.lua('MiniStarter.open()')\n  local lines_1 = get_lines()\n\n  -- Reload with first config\n  reload_from_strconfig(strconfig_2)\n  child.lua('MiniStarter.open()')\n  local lines_2 = get_lines()\n\n  eq(lines_1, lines_2)\n\n  reload_module()\nend\n\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n\nlocal get_active_items_names = function(buf_id)\n  buf_id = buf_id or child.api.nvim_get_current_buf()\n  local items = child.lua_get('MiniStarter.content_to_items(MiniStarter.get_content(...))', { buf_id })\n  local active_items = vim.tbl_filter(function(x) return x._active == true end, items)\n  return vim.tbl_map(function(x) return x.name end, active_items)\nend\n\nlocal mock_user_and_time = function()\n  child.lua([[vim.loop.os_get_passwd = function() return { username = 'MINI' } end]])\n  child.lua([[vim.fn.strftime = function(x) return x == '%H' and '12' or '' end]])\nend\n\nlocal mock_item = function(name, section)\n  return { name = name, action = ('lua _G.item_name = %s'):format(vim.inspect(name)), section = section }\nend\n\nlocal mock_itemstring = function(name, section)\n  return ([[{ name = '%s', action = 'lua _G.item_name = \"%s\"', section = '%s' }]]):format(name, name, section)\nend\n\n-- Data =======================================================================\nlocal example_items = { mock_item('aaab', 'A'), mock_item('aaba', 'A'), mock_item('abaa', 'B'), mock_item('baaa', 'B') }\n\nlocal example_itemstring = '{ '\n  .. table.concat({\n    mock_itemstring('aaab', 'A'),\n    mock_itemstring('aaba', 'A'),\n    mock_itemstring('abaa', 'B'),\n    mock_itemstring('baaa', 'B'),\n  }, ', ')\n  .. ' }'\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n      mock_user_and_time()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniStarter)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniStarter'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniStarterCurrent', 'links to MiniStarterItem')\n  has_highlight('MiniStarterFooter', 'links to Title')\n  has_highlight('MiniStarterHeader', 'links to Title')\n  has_highlight('MiniStarterInactive', 'links to Comment')\n  has_highlight('MiniStarterItem', 'links to Normal')\n  has_highlight('MiniStarterItemBullet', 'links to Delimiter')\n  has_highlight('MiniStarterItemPrefix', 'links to WarningMsg')\n  has_highlight('MiniStarterSection', 'links to Delimiter')\n  has_highlight('MiniStarterQuery', 'links to MoreMsg')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniStarter.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniStarter.config.' .. field), value) end\n\n  expect_config('autoopen', true)\n  expect_config('evaluate_single', false)\n  expect_config('items', vim.NIL)\n  expect_config('header', vim.NIL)\n  expect_config('footer', vim.NIL)\n  expect_config('content_hooks', vim.NIL)\n  expect_config('query_updaters', 'abcdefghijklmnopqrstuvwxyz0123456789_-.')\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ autoopen = false })\n  eq(child.lua_get('MiniStarter.config.autoopen'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ autoopen = 'a' }, 'autoopen', 'boolean')\n  expect_config_error({ evaluate_single = 'a' }, 'evaluate_single', 'boolean')\n  expect_config_error({ items = 'a' }, 'items', 'table')\n  -- `header` and `footer` can have any type\n  expect_config_error({ content_hooks = 'a' }, 'content_hooks', 'table')\n  expect_config_error({ query_updaters = 1 }, 'query_updaters', 'string')\n  expect_config_error({ silent = 1 }, 'silent', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniStarterCurrent'), 'links to MiniStarterItem')\nend\n\n-- Work with Starter buffer ---------------------------------------------------\nT['open()'] = new_set()\n\nT['open()']['works'] = function()\n  local init_buf_id = child.api.nvim_get_current_buf()\n\n  child.lua('MiniStarter.open()')\n\n  local buf_cur = child.api.nvim_get_current_buf()\n  expect.no_equality(buf_cur, init_buf_id)\n  eq(child.api.nvim_buf_get_name(0), 'ministarter://' .. buf_cur .. '/welcome')\n  validate_starter_shown()\n\n  expect.match(table.concat(get_lines(), '\\n'), 'Builtin actions')\nend\n\nT['open()']['sets local options'] = function()\n  -- Cache initial data for future verification\n  child.o.showtabline = 2\n  local init_laststatus = child.o.laststatus\n\n  -- Open Starter buffer\n  child.lua('MiniStarter.open()')\n\n  -- Should set essential local options (not all actually set are tested)\n  eq(child.bo.bufhidden, 'wipe')\n  eq(child.bo.buflisted, false)\n  eq(child.bo.buftype, 'nofile')\n  eq(child.wo.colorcolumn, '')\n  eq(child.wo.foldlevel, 999)\n  eq(child.bo.modifiable, false)\n  eq(child.wo.signcolumn, 'no')\n  eq(child.wo.statuscolumn, '')\n  eq(child.wo.wrap, false)\n\n  -- Should hide tabline but not touch statusline\n  eq(child.o.showtabline, 1)\n  eq(child.o.laststatus, init_laststatus)\n\n  -- Verify that tabline resets to its initial value\n  child.cmd('bwipeout')\n  eq(child.o.showtabline, 2)\nend\n\nT['open()']['ends up in Normal mode'] = new_set(\n  { parametrize = { { 'Insert' }, { 'Visual' }, { 'Replace' }, { 'Command' }, { 'Terminal' } } },\n  {\n    test = function(test_mode)\n      local keys = ({ Insert = 'i', Visual = 'v', Replace = 'R', Command = ':', Terminal = ':terminal<CR>i' })[test_mode]\n      type_keys(keys)\n      local cur_mode_id = ({ Insert = 'i', Visual = 'v', Replace = 'R', Command = 'c', Terminal = 't' })[test_mode]\n      eq(child.fn.mode(), cur_mode_id)\n\n      -- Ensure no `InsertEnter` event is triggered (see #183)\n      child.cmd('au InsertEnter * lua _G.been_inside_insertenter = true')\n\n      -- Ensure `<C-\\>` mapping is respected (see #189)\n      child.cmd([[nnoremap <C-\\> <Cmd>lua _G.been_inside_ctrlslash = true<CR>]])\n      if test_mode ~= 'Replace' then\n        child.cmd(cur_mode_id .. [[noremap <C-\\> <Cmd>lua _G.been_inside_ctrlslash = true<CR>]])\n      end\n\n      child.lua('MiniStarter.open()')\n      validate_starter_shown()\n      eq(child.fn.mode(), 'n')\n\n      eq(child.lua_get('_G.been_inside_insertenter'), vim.NIL)\n      eq(child.lua_get('_G.been_inside_ctrlslash'), vim.NIL)\n    end,\n  }\n)\n\nlocal has_map = function(key, value)\n  value = value or ''\n  local cmd = 'nmap <buffer> ' .. key\n  local pattern = vim.pesc('MiniStarter.' .. value)\n  return child.cmd_capture(cmd):find(pattern) ~= nil\nend\n\nT['open()']['makes buffer mappings'] = function()\n  child.lua('MiniStarter.open()')\n\n  eq(has_map('<CR>', 'eval_current_item()'), true)\n  eq(has_map('<Up>', [[update_current_item('prev')]]), true)\n  eq(has_map('<C-p>', [[update_current_item('prev')]]), true)\n  eq(has_map('<M-k>', [[update_current_item('prev')]]), true)\n  eq(has_map('<Down>', [[update_current_item('next')]]), true)\n  eq(has_map('<C-n>', [[update_current_item('next')]]), true)\n  eq(has_map('<M-j>', [[update_current_item('next')]]), true)\n  eq(has_map('<Esc>', [[set_query('')]]), true)\n  eq(has_map('<BS>', 'add_to_query()'), true)\n  eq(has_map('<C-c>', 'close()'), true)\n\n  -- Defines query updaters\n  eq(has_map('a', 'add_to_query(\"a\")'), true)\nend\n\nT['open()']['handles special query updaters'] = function()\n  reload_module({ query_updaters = [[\"'\\]] })\n  child.lua('MiniStarter.open()')\n\n  eq(has_map('\"', [[add_to_query('\"')]]), true)\n  eq(has_map(\"'\", [[add_to_query(\"'\")]]), true)\n  eq(has_map([[\\]], [[add_to_query(\"\\\\\")]]), true)\nend\n\nT['open()']['makes buffer autocommands'] = function()\n  child.lua('MiniStarter.open()')\n  expect.match(child.cmd_capture('au MiniStarterBuffer'), '<buffer=%d')\nend\n\nT['open()']['respects `buf_id` argument'] = function()\n  local cur_buf_id = child.api.nvim_get_current_buf()\n  child.lua(('MiniStarter.open(%s)'):format(cur_buf_id))\n  eq(child.api.nvim_get_current_buf(), cur_buf_id)\n  eq(child.api.nvim_buf_get_name(0), 'ministarter://' .. cur_buf_id .. '/welcome')\nend\n\nT['open()']['issues an autocommand after finished opening'] = function()\n  -- Finished opening\n  child.lua('_G.n = 0')\n  child.cmd('au User MiniStarterOpened lua _G.n = _G.n + 1')\n  child.lua('MiniStarter.open()')\n\n  eq(child.lua_get('_G.n'), 1)\n\n  -- Not finished opening\n  child.lua('_G.n = 0')\n  child.lua('pcall(MiniStarter.open, \"a\")')\n  eq(child.lua_get('_G.n'), 0)\nend\n\nT['open()']['creates unique buffer names'] = function()\n  child.lua('MiniStarter.open()')\n  eq(child.api.nvim_buf_get_name(0), 'ministarter://' .. child.api.nvim_get_current_buf() .. '/welcome')\n\n  child.lua('MiniStarter.close()')\n  child.lua('MiniStarter.open()')\n  eq(child.api.nvim_buf_get_name(0), 'ministarter://' .. child.api.nvim_get_current_buf() .. '/welcome')\nend\n\nT['open()']['works with `:edit`'] = function()\n  child.lua('MiniStarter.open()')\n  child.cmd('edit')\n  eq(child.cmd_capture('messages'), '')\n  eq(#get_lines() > 1, true)\nend\n\nT['open()']['respects `vim.{g,b}.ministarter_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].ministarter_disable = true\n\n    child.lua('MiniStarter.open()')\n    validate_starter_not_shown()\n  end,\n})\n\nT['open()']['respects `vim.b.ministarter_config`'] = function()\n  -- Although this is defined inside current buffer, it should affect Starter buffer\n  child.b.ministarter_config = { header = 'Hello', footer = 'World', content_hooks = {} }\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['refresh()'] = new_set()\n\nT['refresh()']['does `header` normalization'] = function()\n  validate_equal_starter({ header = '100' }, { header = [['100']] })\n  validate_equal_starter({ header = [[function() return 'aaa' end]] }, { header = [['aaa']] })\n  validate_equal_starter({ header = [[function() return 'aaa\\nbbb' end]] }, { header = [['aaa\\nbbb']] })\n  validate_equal_starter({ header = 'function() return 100 end' }, { header = [['100']] })\n  validate_equal_starter({ header = 'function() return end' }, { header = [['nil']] })\nend\n\nT['refresh()']['does `header` normalization for empty string'] = function()\n  reload_module({ content_hooks = {}, header = '' })\n  child.lua('MiniStarter.open()')\n  -- Empty header should result into no header and no empty line after it\n  expect.no_equality(get_lines()[1], '')\nend\n\nT['refresh()']['does `footer` normalization'] = function()\n  validate_equal_starter({ footer = '100' }, { footer = [['100']] })\n  validate_equal_starter({ footer = [[function() return 'aaa' end]] }, { footer = [['aaa']] })\n  validate_equal_starter({ footer = [[function() return 'aaa\\nbbb' end]] }, { footer = [['aaa\\nbbb']] })\n  validate_equal_starter({ footer = 'function() return 100 end' }, { footer = [['100']] })\n  validate_equal_starter({ footer = 'function() return end' }, { footer = [['nil']] })\nend\n\nT['refresh()']['does `footer` normalization for empty string'] = function()\n  reload_module({ content_hooks = {}, footer = '' })\n  child.lua('MiniStarter.open()')\n  -- Empty footer should result into no footer and no empty line before it\n  local lines = get_lines()\n  expect.no_equality(lines[#lines], '')\nend\n\nT['refresh()']['does `items` normalization'] = function()\n  local item = mock_itemstring('a', 'Section a')\n  local item_2 = mock_itemstring('ba', 'Section b')\n  local item_3 = mock_itemstring('bb', 'Section b')\n  local item_empty = mock_itemstring('empty', '')\n  local item_empty_2 = mock_itemstring('empty2', '')\n\n  -- Evaluates functions\n  validate_equal_starter({ items = ('{ function() return %s end }'):format(item) }, {\n    items = ('{ %s }'):format(item),\n  })\n\n  -- Flattens nested tables\n  validate_equal_starter({ items = ('{{%s}}'):format(item) }, { items = ('{%s}'):format(item) })\n\n  -- Sorts items\n  validate_equal_starter(\n    { items = ('{%s, %s, %s}'):format(item_2, item, item_3) },\n    { items = ('{%s, %s, %s}'):format(item_2, item_3, item) }\n  )\n\n  -- Sorts after flattening\n  validate_equal_starter(\n    { items = ('{{%s, %s}, {%s}}'):format(item_2, item, item_3) },\n    { items = ('{%s, %s, %s}'):format(item_2, item_3, item) }\n  )\n\n  -- Sorts empty section name as any other section name\n  validate_equal_starter(\n    { items = ('{%s, %s, %s, %s}'):format(item_2, item_empty, item_3, item_empty_2) },\n    { items = ('{%s, %s, %s, %s}'):format(item_2, item_3, item_empty, item_empty_2) }\n  )\nend\n\nT['refresh()']['allows empty `items`'] = function()\n  validate_equal_starter(\n    { items = '{}' },\n    { items = [[{ { name = '`config.items` is empty', action = '', section = '' } }]] }\n  )\n  -- It shouldn't give any messages\n  eq(get_latest_message(), '')\nend\n\nT['refresh()']['prevents infinite recursion in `items` normalization'] = function()\n  local item = mock_itemstring('a', 'A')\n  reload_from_strconfig({ items = ('{ %s }'):format(item) })\n  child.lua('MiniStarter.open()')\n  local lines_1 = get_lines()\n\n  child.lua('_G.f = function() return _G.f end')\n  reload_from_strconfig({ items = ('{ _G.f, %s }'):format(item) })\n  child.lua('MiniStarter.open()')\n  local lines_2 = get_lines()\n\n  eq(get_latest_message(), '(mini.starter) Too many nested functions in `config.items`.')\n\n  eq(lines_1, lines_2)\nend\n\nT['refresh()']['does normalization on every call'] = function()\n  child.lua('_G.n = 0')\n\n  local strconfig_1 = {\n    header = 'function() _G.n = _G.n + 1; return _G.n end',\n    items = [[{ function() return { action = 'echo \"a\"', name = tostring(_G.n), section = 'Section a' } end }]],\n    footer = 'function() return _G.n end',\n  }\n  local strconfig_2 = {\n    header = [['2']],\n    items = [[{ action = 'echo \"a\"', name = '2', section = 'Section a' }]],\n    footer = [['2']],\n  }\n\n  reload_from_strconfig(strconfig_1)\n  child.lua('MiniStarter.open()')\n  child.lua('MiniStarter.refresh()')\n  local lines_1 = get_lines()\n\n  reload_from_strconfig(strconfig_2)\n  child.lua('MiniStarter.open()')\n  local lines_2 = get_lines()\n\n  eq(lines_1, lines_2)\nend\n\nT['refresh()']['uses current `MiniStarter.config`'] = function()\n  child.lua('MiniStarter.open()')\n  child.lua('MiniStarter.config.header = \"New header\"')\n  child.lua('MiniStarter.refresh()')\n  local lines_1 = get_lines()\n\n  reload_from_strconfig({ header = [['New header']] })\n  child.lua('MiniStarter.open()')\n  local lines_2 = get_lines()\n\n  eq(lines_1, lines_2)\nend\n\nlocal reload_with_hooks = function()\n  unload_module()\n  child.lua('_G.hooks_history = {}')\n  child.lua([[\n    require('mini.starter').setup({ content_hooks = {\n      function(x) table.insert(_G.hooks_history, 'a'); return x end,\n      function(x) table.insert(_G.hooks_history, 'b'); return x end,\n    } })]])\nend\n\nT['refresh()']['applies `content_hooks` sequentially'] = function()\n  reload_with_hooks()\n  child.lua('MiniStarter.open()')\n  eq(child.lua_get('_G.hooks_history'), { 'a', 'b' })\nend\n\nT['refresh()']['calls `content_hooks` on every call'] = function()\n  reload_with_hooks()\n  child.lua('MiniStarter.open()')\n  child.lua('MiniStarter.refresh()')\n  eq(child.lua_get('_G.hooks_history'), { 'a', 'b', 'a', 'b' })\nend\n\nT['refresh()']['calls `content_hooks` with proper signature'] = function()\n  child.lua([[MiniStarter.config.content_hooks = {\n    function(...) local dots = {...}; _G.args = dots; return dots[1] end\n  }]])\n  child.lua('MiniStarter.open()')\n  local buf_id = child.api.nvim_get_current_buf()\n\n  -- Hooks should be called with `(content, buf_id)` signature\n  child.lua('MiniStarter.refresh()')\n  local args = child.lua_get('_G.args')\n\n  eq(#args, 2)\n  eq(child.lua_get('MiniStarter.get_content()'), args[1])\n  eq(buf_id, args[2])\nend\n\nT['refresh()']['respects `vim.b.ministarter_config`'] = function()\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  child.b.ministarter_config = {\n    header = 'Hello',\n    footer = 'World',\n    content_hooks = {},\n    items = { { name = 'aaa', action = 'echo \"aaa\"', section = 'AAA' } },\n  }\n  child.lua('MiniStarter.refresh()')\n  child.expect_screenshot()\nend\n\nT['refresh()']['respects `vim.b.ministarter_config`'] = function()\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  child.b.ministarter_config = {\n    header = 'Hello',\n    footer = 'World',\n    content_hooks = {},\n    items = { { name = 'aaa', action = 'echo \"aaa\"', section = 'AAA' } },\n  }\n  child.lua('MiniStarter.refresh()')\n  child.expect_screenshot()\nend\n\nT['refresh()']['respects `config.silent`'] = function()\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  -- Clear command line\n  child.cmd([[echo '']])\n  child.lua('MiniStarter.config.silent = true')\n\n  type_keys('a')\n  child.expect_screenshot()\nend\n\nT['close()'] = new_set()\n\nT['close()']['works'] = function()\n  child.lua('MiniStarter.open()')\n  local buf_id = child.api.nvim_get_current_buf()\n  validate_starter_shown()\n\n  child.lua('MiniStarter.close()')\n  eq(child.api.nvim_buf_is_valid(buf_id), false)\n  validate_starter_not_shown()\nend\n\nT['close()']['can be used when no Starter buffer is shown'] = function()\n  validate_starter_not_shown()\n  expect.no_error(function() child.lua('MiniStarter.close()') end)\nend\n\nT['eval_current_item()'] = new_set()\n\nT['eval_current_item()']['works'] = function()\n  reload_module({ items = example_items })\n  child.lua('MiniStarter.open()')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n  child.lua('_G.item_name = nil')\n\n  type_keys('b')\n  eq(get_active_items_names(), { 'baaa' })\n  child.lua('_G.item_name = nil')\n\n  -- It should reset query along with evaluating item\n  child.lua('MiniStarter.eval_current_item()')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n  eq(child.lua_get('_G.item_name'), 'baaa')\nend\n\n-- Work with content ----------------------------------------------------------\nT['Default content'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(24, 80)\n      -- Mock functions used to compute header\n      mock_user_and_time()\n    end,\n  },\n})\n\nT['Default content']['works'] = function()\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['Default content']['computes `header` depending on time of day'] = new_set({\n  parametrize = { { '00' }, { '04' }, { '08' }, { '12' }, { '16' }, { '20' } },\n}, {\n  test = function(hour)\n    local cmd = ([[vim.fn.strftime = function(x) return x == '%%H' and '%s' or '' end]]):format(hour)\n    child.lua(cmd)\n    child.lua('MiniStarter.open()')\n    child.expect_screenshot()\n  end,\n})\n\nT['Default content'][\"'Sessions' section\"] = new_set()\n\nT['Default content'][\"'Sessions' section\"]['works'] = function()\n  -- Should show local (first and with `(local)` note) and global sessions\n  child.cmd('cd tests/dir-starter/sessions')\n  child.lua([[require('mini.sessions').setup({ directory = '.' })]])\n\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['Default content'][\"'Sessions' section\"]['present even if no sessions detected'] = function()\n  child.lua([[require('mini.sessions').setup({ file = '', directory = '' })]])\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['Default content'][\"'Recent files' section\"] = new_set()\n\nT['Default content'][\"'Recent files' section\"]['displays only readable files'] = function()\n  child.v.oldfiles = { 'README.md', 'non-existent.lua' }\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['Default content'][\"'Recent files' section\"]['present even if no recent files'] = function()\n  child.v.oldfiles = {}\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['get_content()'] = new_set({ hooks = { pre_case = function() child.set_size(10, 40) end } })\n\nT['get_content()']['works'] = function()\n  local item = mock_item('a', 'Section a')\n  load_module({ content_hooks = {}, header = 'Hello', footer = 'World', items = { item } })\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  -- Every element of array should contain content for a particular line\n  local content = child.lua_get('MiniStarter.get_content()')\n  eq(content[1], { { hl = 'MiniStarterHeader', string = 'Hello', type = 'header' } })\n  eq(content[2], { { string = '', type = 'empty' } })\n  eq(content[3], { { hl = 'MiniStarterSection', string = 'Section a', type = 'section' } })\n  eq(content[4], { { hl = 'MiniStarterItem', item = content[4][1].item, string = 'a', type = 'item' } })\n  eq(content[5], { { string = '', type = 'empty' } })\n  eq(content[6], { { hl = 'MiniStarterFooter', string = 'World', type = 'footer' } })\n\n  local content_item = content[4][1].item\n  eq({ name = content_item.name, action = content_item.action, section = content_item.section }, item)\nend\n\nT['content_coords()'] = new_set({\n  hooks = {\n    pre_case = function()\n      local item = mock_item('a', 'Section A')\n      reload_module({ content_hooks = {}, header = 'Hello', footer = 'World', items = { item } })\n      child.lua('MiniStarter.open()')\n    end,\n  },\n})\n\nT['content_coords()']['works with function argument'] = function()\n  local coords = child.lua_get([[\n    MiniStarter.content_coords(MiniStarter.get_content(), function(x)\n      return vim.tbl_contains({'Hello', 'World'}, x.string)\n    end)]])\n  eq(coords, { { line = 1, unit = 1 }, { line = 6, unit = 1 } })\nend\n\nT['content_coords()']['works with string argument'] = function()\n  local coords = child.lua_get([[MiniStarter.content_coords(MiniStarter.get_content(), 'empty')]])\n  eq(coords, { { line = 2, unit = 1 }, { line = 5, unit = 1 } })\nend\n\nT['content_coords()']['works with no argument'] = function()\n  local coords = child.lua_get('MiniStarter.content_coords(MiniStarter.get_content(), nil)')\n  for i = 1, 6 do\n    eq(coords[i], { line = i, unit = 1 })\n  end\nend\n\nT['content_to_lines()'] = new_set({\n  hooks = {\n    pre_case = function() child.lua('MiniStarter.open()') end,\n  },\n})\n\nT['content_to_lines()']['works'] = function()\n  eq(child.lua_get('MiniStarter.content_to_lines(MiniStarter.get_content())'), get_lines())\nend\n\nT['content_to_items()'] = new_set()\n\nT['content_to_items()']['works'] = function()\n  reload_module({ content_hooks = {}, items = example_items })\n  child.lua('MiniStarter.open()')\n\n  local output = child.lua_get('MiniStarter.content_to_items(MiniStarter.get_content())')\n\n  -- Should contain all information from input items\n  for i, item in ipairs(output) do\n    eq({ name = item.name, action = item.action, section = item.section }, example_items[i])\n  end\n\n  -- Should correctly compute length of minimum unique prefix\n  eq(vim.tbl_map(function(x) return x._nprefix end, output), { 3, 3, 2, 1 })\nend\n\nT['content_to_items()'][\"modifies `item`'s name to equal content unit's `string`\"] = function()\n  local content = {\n    { { type = 'item', string = 'aaa', item = mock_item('bbb', '') } },\n    { { type = 'item', string = 'c\\nc\\nc', item = mock_item('ddd', '') } },\n    { { type = 'empty', string = 'eee', item = mock_item('fff', '') } },\n  }\n  local output = child.lua_get('MiniStarter.content_to_items(...)', { content })\n  eq(#output, 2)\n  eq({ output[1].name, output[1].action }, { 'aaa', content[1][1].item.action })\n  eq({ output[2].name, output[2].action }, { 'c c c', content[2][1].item.action })\nend\n\nT['gen_hook'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(20, 60)\n      mock_user_and_time()\n    end,\n  },\n})\n\nT['gen_hook']['adding_bullet()'] = new_set()\n\nT['gen_hook']['adding_bullet()']['works'] = function()\n  reload_from_strconfig({ content_hooks = '{ require(\"mini.starter\").gen_hook.adding_bullet() }' })\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['gen_hook']['adding_bullet()']['respects `bullet` argument'] = function()\n  reload_from_strconfig({ content_hooks = '{ require(\"mini.starter\").gen_hook.adding_bullet(\"> \") }' })\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['gen_hook']['adding_bullet() respects `place_cursor` argument'] = function()\n  local reload = function(place_cursor)\n    reload_from_strconfig({\n      header = [['']],\n      footer = [['']],\n      items = ('{ %s }'):format(mock_itemstring('bbb', '')),\n      content_hooks = ('{ require(\"mini.starter\").gen_hook.adding_bullet(\"aaa\", %s) }'):format(place_cursor),\n    })\n  end\n\n  reload(false)\n  child.lua('MiniStarter.open()')\n  eq(get_cursor(), { 2, 3 })\n\n  reload(true)\n  child.lua('MiniStarter.open()')\n  eq(get_cursor(), { 2, 0 })\nend\n\nT['gen_hook']['aligning()'] = new_set()\n\nT['gen_hook']['aligning()']['works'] = function()\n  reload_from_strconfig({ content_hooks = '{ require(\"mini.starter\").gen_hook.aligning() }' })\n  child.lua('MiniStarter.open()')\n  -- By default shouldn't do any aligning\n  child.expect_screenshot()\nend\n\nT['gen_hook']['aligning()']['respects arguments'] = new_set({\n  parametrize = {\n    { [['left', 'top']] },\n    { [['left', 'center']] },\n    { [['left', 'bottom']] },\n    { [['center', 'top']] },\n    { [['center', 'center']] },\n    { [['center', 'bottom']] },\n    { [['right', 'top']] },\n    { [['right', 'center']] },\n    { [['right', 'bottom']] },\n  },\n  hooks = {\n    pre_case = function() child.set_size(10, 40) end,\n  },\n}, {\n  test = function(args)\n    reload_from_strconfig({\n      content_hooks = ('{ require(\"mini.starter\").gen_hook.aligning(%s) }'):format(args),\n      header = [['']],\n      footer = [['']],\n      items = ('{ %s, %s }'):format(mock_itemstring('aaa', 'AAA'), mock_itemstring('bbb', 'AAA')),\n    })\n    child.lua('MiniStarter.open()')\n    child.expect_screenshot()\n  end,\n})\n\nT['gen_hook']['aligning()']['handles small windows'] = function()\n  child.set_size(15, 40)\n  child.cmd('vsplit | split')\n  child.api.nvim_win_set_width(0, 2)\n  child.api.nvim_win_set_height(0, 2)\n  reload_from_strconfig({\n    content_hooks = '{ require(\"mini.starter\").gen_hook.aligning(\"right\", \"bottom\") }',\n    header = [['']],\n    footer = [['']],\n    items = ('{ %s, %s }'):format(mock_itemstring('aaa', 'AAA'), mock_itemstring('bbb', 'AAA')),\n  })\n\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['gen_hook']['aligning()']['has output respecting `buf_id` argument'] = function()\n  child.set_size(15, 40)\n  reload_from_strconfig({\n    content_hooks = '{ require(\"mini.starter\").gen_hook.aligning(\"center\", \"center\") }',\n    header = [['']],\n    footer = [['']],\n    items = ('{ %s, %s }'):format(mock_itemstring('aaa', 'AAA'), mock_itemstring('bbb', 'AAA')),\n  })\n\n  child.cmd('vsplit | split | wincmd l')\n  child.lua('MiniStarter.open()')\n  local starter_buf_id = child.api.nvim_get_current_buf()\n  child.expect_screenshot()\n\n  child.cmd('wincmd h')\n  child.api.nvim_win_set_width(0, 5)\n  child.lua('MiniStarter.refresh(...)', { starter_buf_id })\n  child.expect_screenshot()\nend\n\nlocal reload_indexing = function(args)\n  local itemstrings = {\n    mock_itemstring('a', 'AAA'),\n    mock_itemstring('aa', 'AAA'),\n    mock_itemstring('b', 'BBB'),\n    mock_itemstring('bb', 'BBB'),\n  }\n  reload_from_strconfig({\n    header = [['']],\n    footer = [['']],\n    items = '{ ' .. table.concat(itemstrings, ', ') .. '}',\n    content_hooks = ('{ require(\"mini.starter\").gen_hook.indexing(%s) }'):format(args),\n  })\nend\n\nT['gen_hook']['indexing()'] = new_set({ hooks = {\n  pre_case = function() child.set_size(15, 40) end,\n} })\n\nT['gen_hook']['indexing()']['works'] = function()\n  reload_indexing('')\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['gen_hook']['indexing()']['respects arguments'] = new_set({\n  parametrize = { { [['all', nil]] }, { [['section', nil]] }, { 'nil, {}' }, { [[nil, { 'AAA' }]] } },\n}, {\n  test = function(args)\n    reload_indexing(args)\n    child.lua('MiniStarter.open()')\n    child.expect_screenshot()\n  end,\n})\n\nT['gen_hook']['padding()'] = new_set()\n\nT['gen_hook']['padding()']['works'] = function()\n  reload_from_strconfig({ content_hooks = '{ require(\"mini.starter\").gen_hook.padding() }' })\n  child.lua('MiniStarter.open()')\n  -- By default shouldn't do any aligning\n  child.expect_screenshot()\nend\n\nT['gen_hook']['padding()']['respects arguments'] = new_set({\n  parametrize = { { '2, 0' }, { '0, 2' }, { '2, 2' } },\n}, {\n  test = function(args)\n    local command = string.format('{ require(\"mini.starter\").gen_hook.padding(%s) }', args)\n    reload_from_strconfig({ content_hooks = command })\n    child.lua('MiniStarter.open()')\n    child.expect_screenshot()\n  end,\n})\n\nT['sections'] = new_set()\n\nT['sections']['works'] = function()\n  child.set_size(30, 60)\n  child.lua([[MiniStarter.config.items = {\n    MiniStarter.sections.builtin_actions,\n    MiniStarter.sections.recent_files,\n    MiniStarter.sections.sessions,\n    MiniStarter.sections.pick,\n    MiniStarter.sections.telescope,\n  }]])\n  child.lua([[MiniStarter.config.header = '']])\n  child.lua([[MiniStarter.config.footer = '']])\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\nend\n\nT['sections']['has correct items'] = function()\n  local types = child.lua_get('vim.tbl_map(type, MiniStarter.sections)')\n  --stylua: ignore\n  eq(\n    types,\n    { builtin_actions = 'function', recent_files = 'function', sessions = 'function', pick = 'function', telescope = 'function' }\n  )\nend\n\nT['sections']['recent_files()'] = new_set()\n\nT['sections']['recent_files()']['correctly identifies files from current directory'] = function()\n  local dir, dir_similar = 'tests/dir-starter/dir', 'tests/dir-starter/directory'\n  local file = dir_similar .. '/file'\n\n  -- Make recent file with absolute path having current directory as substring\n  -- but not inside current directory\n  child.v.oldfiles = { child.fn.fnamemodify(file, ':p') }\n  child.cmd('cd ' .. dir)\n\n  -- Set up to show files only in current directory\n  child.lua('MiniStarter.config.items = { MiniStarter.sections.recent_files(5, true, true) }')\n  child.lua('MiniStarter.open()')\n  -- \"Recent files\" section should be empty\n  child.expect_screenshot()\nend\n\nT['sections']['recent_files()']['opens path in relative form'] = function()\n  local file = 'tests/dir-starter/dir/file1'\n  child.v.oldfiles = { child.fn.fnamemodify(file, ':p') }\n  child.lua('MiniStarter.open()')\n  local n_bufs = #child.api.nvim_list_bufs()\n  type_keys('<CR>')\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]tests/dir%-starter/dir/file1')\n  -- Should properly hide Starter buffer\n  eq(#child.api.nvim_list_bufs(), n_bufs)\nend\n\nT['sections']['recent_files()']['respects files in subdirectories'] = function()\n  local dir = 'tests/dir-starter/dir'\n  local dir_nested = dir .. '/subdir'\n  local file, file_nested = dir .. '/file1', dir_nested .. '/file2'\n\n  child.v.oldfiles = { child.fn.fnamemodify(file, ':p'), child.fn.fnamemodify(file_nested, ':p') }\n  child.cmd('cd ' .. dir)\n\n  -- Mock forward slash for more robust screenshot testing\n  child.lua([[\n    local fnamemodify_orig = vim.fn.fnamemodify\n    vim.fn.fnamemodify = function(...) return (fnamemodify_orig(...):gsub('\\\\', '/')) end\n  ]])\n\n  -- Set up to show files only in current directory\n  child.lua('MiniStarter.config.items = { MiniStarter.sections.recent_files(5, true, true) }')\n  child.lua('MiniStarter.open()')\n  -- \"Recent files\" section should show both files\n  child.expect_screenshot()\nend\n\nT['sections']['recent_files()']['respects `n`'] = function()\n  local dir = 'tests/dir-starter/dir'\n  local test_file1, test_file3 = dir .. '/file1', dir .. '/file3'\n\n  child.v.oldfiles = { child.fn.fnamemodify(test_file1, ':p'), child.fn.fnamemodify(test_file3, ':p') }\n  eq(child.lua_get('#MiniStarter.sections.recent_files(1, false)()'), 1)\nend\n\nT['sections']['recent_files()']['respects `show_path`'] = function()\n  local test_file = 'tests/dir-starter/dir/file1'\n\n  child.v.oldfiles = { child.fn.fnamemodify(test_file, ':p') }\n\n  child.lua([[MiniStarter.config.items = {\n    MiniStarter.sections.recent_files(5, false, function() return '__hello__' end ),\n  }]])\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  -- Should validate it\n  expect.error(\n    function() child.lua('MiniStarter.sections.recent_files(5, false, 1)') end,\n    '`show_path`.*boolean or callable'\n  )\nend\n\n-- Work with query ------------------------------------------------------------\nT['set_query()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua('MiniStarter.config.items = ' .. example_itemstring)\n      child.lua('MiniStarter.open()')\n    end,\n  },\n})\n\nT['set_query()']['works'] = function()\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n\n  child.lua([[MiniStarter.set_query('aaa')]])\n  eq(get_active_items_names(), { 'aaab' })\n\n  child.lua([[MiniStarter.set_query('a')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n  child.lua([[MiniStarter.set_query('aa')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba' })\nend\n\nT['set_query()']['uses `buf_id` argument'] = function()\n  child.lua('MiniStarter.open()')\n  local buf_id = child.api.nvim_get_current_buf()\n\n  child.lua('MiniStarter.set_query(...)', { 'aaa', buf_id })\n  eq(get_active_items_names(buf_id), { 'aaab' })\nend\n\nT['set_query()']['validates argument'] = function()\n  expect.error(function() child.lua('MiniStarter.set_query(1)') end, '`query`.*`nil` or string')\nend\n\nT['set_query()']['does not allow query resulting in no active items'] = function()\n  -- Make all showed messages full width\n  child.o.cmdheight = 2\n\n  child.lua([[MiniStarter.set_query('a')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n  child.lua([[MiniStarter.set_query('c')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n  expect.match(get_latest_message(), '%(mini%.starter%) Query \"c\" results into no active items%. Current query: a')\nend\n\nT['set_query()']['resets query with empty string'] = function()\n  child.lua([[MiniStarter.set_query('a')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n  child.lua([[MiniStarter.set_query('')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\nend\n\nT['add_to_query()'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.lua('MiniStarter.config.items = ' .. vim.inspect(example_items))\n      child.lua('MiniStarter.open()')\n    end,\n  },\n})\n\nT['add_to_query()']['works'] = function()\n  -- Make all showed messages full width\n  child.o.cmdheight = 2\n\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n\n  child.lua([[MiniStarter.add_to_query('a')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n  child.lua([[MiniStarter.add_to_query('a')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba' })\n\n  child.lua([[MiniStarter.add_to_query('a')]])\n  eq(get_active_items_names(), { 'aaab' })\n\n  child.lua([[MiniStarter.add_to_query('b')]])\n  eq(get_active_items_names(), { 'aaab' })\n\n  -- Allows empty string with no effect\n  child.lua([[MiniStarter.add_to_query('')]])\n  eq(get_active_items_names(), { 'aaab' })\n\n  -- Doesn't allow adding to query resulting into no active items\n  child.lua([[MiniStarter.add_to_query('c')]])\n  eq(get_active_items_names(), { 'aaab' })\n  expect.match(get_latest_message(), 'Query \"aaabc\".*no active items.*Current query: aaab')\nend\n\nT['add_to_query()']['uses `buf_id` argument'] = function()\n  child.lua('MiniStarter.open()')\n  local buf_id = child.api.nvim_get_current_buf()\n\n  child.lua('MiniStarter.add_to_query(...)', { 'a', buf_id })\n  eq(get_active_items_names(buf_id), { 'aaab', 'aaba', 'abaa' })\nend\n\nT['add_to_query()']['removes from query with no argument'] = function()\n  child.lua([[MiniStarter.add_to_query('a')]])\n  child.lua([[MiniStarter.add_to_query('a')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba' })\n\n  child.lua('MiniStarter.add_to_query()')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n  child.lua('MiniStarter.add_to_query()')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n\n  -- Works even when current query is already empty\n  child.lua('MiniStarter.add_to_query()')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\nend\n\n-- Integration tests ==========================================================\nT['Autoopening'] = new_set()\n\nT['Autoopening']['works'] = function()\n  child.restart({ '-u', 'tests/dir-starter/init-files/test-init.lua' })\n  validate_starter_shown()\n\n  -- It should result into total single buffer\n  eq(#child.api.nvim_list_bufs(), 1)\n\n  -- It should trigger `MiniStarterOpened` `User` event\n  eq(child.lua_get('_G.n_event'), 1)\nend\n\nT['Autoopening']['does not autoopen if Neovim started to show something'] = function()\n  local init_autoopen = 'tests/dir-starter/init-files/test-init.lua'\n  local validate = function(...)\n    child.restart({ '-u', init_autoopen, ... })\n    validate_starter_not_shown()\n    eq(child.lua_get('_G.n_event'), 0)\n  end\n\n  -- There are files in arguments (like `nvim foo.txt` with new file).\n  validate('new-file.txt')\n\n  -- Several buffers are listed (like session with placeholder buffers)\n  validate('-c', 'e foo | set buflisted | e bar | set buflisted')\n\n  -- Unlisted buffers (like from `nvim-tree`) don't affect decision\n  child.restart({ '-u', init_autoopen, '-c', 'e foo | set nobuflisted | e bar | set buflisted' })\n  validate_starter_shown()\n  eq(child.lua_get('_G.n_event'), 1)\n\n  -- Current buffer is meant to show something else\n  validate('-c', 'set filetype=text')\n\n  -- Current buffer has any lines (something opened explicitly)\n  validate('-c', [[call setline(1, 'a')]])\nend\n\nT['Querying'] = new_set()\n\nT['Querying']['works'] = function()\n  -- Make all showed messages full width\n  child.o.cmdheight = 2\n\n  reload_module({ items = example_items })\n  child.lua('MiniStarter.open()')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n\n  type_keys('a')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n  type_keys('b')\n  eq(get_active_items_names(), { 'abaa' })\n\n  -- Doesn't allow adding to query resulting into no active items\n  type_keys('c')\n  eq(get_active_items_names(), { 'abaa' })\n  expect.match(get_latest_message(), 'Query \"abc\".*no active items.*Current query: ab')\nend\n\nT['Querying']['respects `config.query_updaters`'] = function()\n  local validate = function()\n    child.lua('MiniStarter.open()')\n    eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n\n    type_keys('a')\n    eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n\n    type_keys('b')\n    eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\n    eq(get_latest_message(), '')\n  end\n\n  reload_module({ items = example_items, query_updaters = 'a' })\n  validate()\n\n  -- Should also use buffer local config\n  child.lua('MiniStarter.close()')\n  reload_module()\n  child.b.ministarter_config = { items = example_items, query_updaters = 'a' }\n  validate()\nend\n\nT['Querying']['respects `config.evaluate_single`'] = function()\n  local validate = function()\n    child.lua('MiniStarter.open()')\n    eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n    child.lua('_G.item_name = nil')\n\n    type_keys('b')\n    -- It should reset query along with evaluating item\n    eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n    eq(child.lua_get('_G.item_name'), 'baaa')\n  end\n\n  reload_module({ evaluate_single = true, items = example_items })\n  validate()\n\n  -- Should also use buffer local config\n  child.lua('MiniStarter.close()')\n  reload_module()\n  child.b.ministarter_config = { evaluate_single = true, items = example_items }\n  validate()\nend\n\nT['Querying']['works with `cmdheight=0`'] = function()\n  child.set_size(20, 50)\n  child.o.cmdheight = 0\n  reload_module({ items = example_items })\n\n  child.lua('MiniStarter.open()')\n\n  -- It should work without giving hit-enter-prompt\n  type_keys('a')\n  type_keys('a')\n  eq(child.api.nvim_get_mode().blocking, false)\n\n  -- There should be no query showed\n  child.expect_screenshot()\n\n  -- There shouldn't be hit-enter-prompt after leaving buffer\n  type_keys(':bw<CR>')\n  eq(child.api.nvim_get_mode().blocking, false)\nend\n\nT['Keybindings'] = new_set({\n  hooks = {\n    pre_case = function()\n      reload_module({ items = example_items, content_hooks = {}, header = '', footer = '' })\n      child.lua('MiniStarter.open()')\n    end,\n  },\n})\n\nT['Keybindings']['have working <BS>'] = function()\n  child.lua([[MiniStarter.set_query('aa')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba' })\n\n  type_keys('<BS>')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa' })\nend\n\nT['Keybindings']['have working <Esc>'] = function()\n  child.lua([[MiniStarter.set_query('aa')]])\n  eq(get_active_items_names(), { 'aaab', 'aaba' })\n\n  type_keys('<Esc>')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\nend\n\nT['Keybindings']['arrows'] = new_set({\n  parametrize = {\n    { { down = '<Down>', up = '<Up>' } },\n    { { down = '<C-n>', up = '<C-p>' } },\n    { { down = '<M-j>', up = '<M-k>' } },\n  },\n}, {\n  function(keys)\n    eq(get_lines(), { 'A', 'aaab', 'aaba', '', 'B', 'abaa', 'baaa' })\n    eq(get_cursor(), { 2, 0 })\n\n    -- Basics work\n    type_keys(keys.down)\n    eq(get_cursor(), { 3, 0 })\n    type_keys(keys.up)\n    eq(get_cursor(), { 2, 0 })\n\n    -- Movement ignores not active items\n    child.lua([[MiniStarter.set_query('aa')]])\n    eq(get_cursor(), { 2, 0 })\n\n    type_keys(keys.down)\n    type_keys(keys.down)\n    eq(get_cursor(), { 2, 0 })\n\n    type_keys(keys.up)\n    type_keys(keys.up)\n    eq(get_cursor(), { 2, 0 })\n\n    -- Works with single active item\n    child.lua([[MiniStarter.set_query('aaab')]])\n    eq(get_cursor(), { 2, 0 })\n\n    type_keys(keys.down)\n    eq(get_cursor(), { 2, 0 })\n\n    type_keys(keys.up)\n    eq(get_cursor(), { 2, 0 })\n  end,\n})\n\nT['Keybindings']['have working <CR>'] = function()\n  child.lua([[MiniStarter.set_query('aaab')]])\n  eq(get_active_items_names(), { 'aaab' })\n  child.lua('_G.item_name = nil')\n\n  type_keys('<CR>')\n  eq(child.lua_get('_G.item_name'), 'aaab')\nend\n\nT['Keybindings']['have working <C-c>'] = function()\n  validate_starter_shown()\n  type_keys('<C-c>')\n  validate_starter_not_shown()\nend\n\nT['Highlighting'] = new_set({\n  hooks = {\n    pre_case = function()\n      reload_module({ items = example_items, content_hooks = {}, header = 'Hello', footer = 'World' })\n      child.set_size(15, 40)\n    end,\n  },\n})\n\nT['Highlighting']['works for querying'] = function()\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  type_keys('a')\n  child.expect_screenshot()\n\n  type_keys('b')\n  child.expect_screenshot()\nend\n\nT['Highlighting']['works for current item'] = function()\n  child.cmd('hi MiniStarterCurrent ctermbg=1')\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  type_keys('<Down>')\n  child.expect_screenshot()\nend\n\nT['Highlighting']['uses `MiniStarterItemBullet`'] = function()\n  reload_from_strconfig({\n    items = example_itemstring,\n    content_hooks = '{ require(\"mini.starter\").gen_hook.adding_bullet() }',\n    header = [['']],\n    footer = [['']],\n  })\n  child.lua('MiniStarter.open()')\n  child.expect_screenshot()\n\n  -- Should now show bullets same as prefix\n  child.cmd('hi! link MiniStarterItemBullet MiniStarterItemPrefix')\n  child.cmd('redraw')\n  child.expect_screenshot()\nend\n\nT['Cursor positioning'] = new_set({\n  hooks = {\n    pre_case = function() reload_module({ items = example_items, content_hooks = {}, header = '', footer = '' }) end,\n  },\n})\n\nT['Cursor positioning']['reacts to keys'] = function()\n  child.lua('MiniStarter.open()')\n  eq(get_lines(), { 'A', 'aaab', 'aaba', '', 'B', 'abaa', 'baaa' })\n  eq(get_cursor(), { 2, 0 })\n\n  type_keys('<Down>')\n  eq(get_cursor(), { 3, 0 })\n\n  type_keys('<Down>')\n  eq(get_cursor(), { 6, 0 })\n\n  type_keys('<Down><Down>')\n  eq(get_cursor(), { 2, 0 })\n\n  type_keys('<Up>')\n  eq(get_cursor(), { 7, 0 })\nend\n\nT['Cursor positioning']['updates when current item becomes inactive'] = function()\n  child.lua('MiniStarter.open()')\n  eq(get_cursor(), { 2, 0 })\n\n  child.lua([[MiniStarter.set_query('baaa')]])\n  eq(get_cursor(), { 7, 0 })\n\n  -- It should stay the same even if previous item again becomes active\n  child.lua([[MiniStarter.set_query('')]])\n  eq(get_cursor(), { 7, 0 })\nend\n\nT['Cursor positioning']['works with bullets'] = new_set({\n  parametrize = { { true, { 2, 0 }, { 3, 0 } }, { false, { 2, 4 }, { 3, 4 } } },\n}, {\n  test = function(place_cursor, cursor_start, cursor_finish)\n    reload_from_strconfig({\n      items = example_itemstring,\n      content_hooks = ('{ require(\"mini.starter\").gen_hook.adding_bullet(nil, %s) }'):format(place_cursor),\n      header = [['']],\n      footer = [['']],\n    })\n\n    child.lua('MiniStarter.open()')\n    eq(get_lines(), { 'A', '░ aaab', '░ aaba', '', 'B', '░ abaa', '░ baaa' })\n    eq(get_cursor(), cursor_start)\n\n    type_keys('<Down>')\n    eq(get_cursor(), cursor_finish)\n  end,\n})\n\nT['Resize'] = new_set()\n\nT['Resize']['updates Starter buffer'] = function()\n  child.lua('MiniStarter.config.items = ' .. example_itemstring)\n  child.lua('MiniStarter.config.header = \"Header\"')\n  child.lua('MiniStarter.config.footer = \"Footer\"')\n\n  child.set_size(12, 20)\n  child.lua('MiniStarter.open()')\n\n  child.set_size(20, 40)\n  child.expect_screenshot()\nend\n\nT['Multiple buffers'] = new_set()\n\nT['Multiple buffers']['are allowed'] = function()\n  child.lua('MiniStarter.config.items = ' .. example_itemstring)\n  child.cmd('autocmd TabNewEntered * lua MiniStarter.open(vim.api.nvim_get_current_buf())')\n\n  child.lua('MiniStarter.open()')\n  local buf_id_1 = child.api.nvim_get_current_buf()\n  child.lua([[MiniStarter.set_query('aa')]])\n  eq(get_active_items_names(buf_id_1), { 'aaab', 'aaba' })\n\n  -- It should open new Starter buffer while keeping previous one\n  child.cmd('tabe')\n  validate_starter_shown()\n  eq(child.api.nvim_buf_get_name(0), 'ministarter://' .. child.api.nvim_get_current_buf() .. '/welcome')\n\n  eq(child.api.nvim_buf_is_valid(buf_id_1), true)\n  eq(child.api.nvim_buf_get_option(buf_id_1, 'filetype'), 'ministarter')\n  eq(get_active_items_names(), { 'aaab', 'aaba', 'abaa', 'baaa' })\n\n  -- State of first Starter buffer should not be affected by second one\n  child.cmd('tabc')\n  eq(get_active_items_names(), { 'aaab', 'aaba' })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_statusline.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('statusline', config) end\nlocal unload_module = function() child.mini_unload('statusline') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal set_width = function(width, win_id) child.api.nvim_win_set_width(win_id or 0, width) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Make helpers\nlocal setup_windows = function()\n  child.cmd('%bwipeout!')\n\n  -- Ensure only two windows\n  if #child.api.nvim_list_wins() > 1 then child.cmd('only') end\n  child.cmd('vsplit')\n\n  local win_list = child.api.nvim_list_wins()\n  if win_list[1] == child.api.nvim_get_current_win() then return { active = win_list[1], inactive = win_list[2] } end\n  return { active = win_list[2], inactive = win_list[1] }\nend\n\nlocal get_two_windows = function()\n  local wins_tabpage = child.api.nvim_tabpage_list_wins(0)\n  local cur_win = child.api.nvim_get_current_win()\n  return { active = cur_win, inactive = cur_win == wins_tabpage[1] and wins_tabpage[2] or wins_tabpage[1] }\nend\n\nlocal eval_statusline = function(stl, win_id) return child.api.nvim_eval_statusline(stl, { winid = win_id }).str end\n\nlocal validate_statusline = function(win_id, ref_content_source)\n  win_id = win_id == 0 and child.api.nvim_get_current_win() or win_id\n  local active = eval_statusline('%{%v:lua.MiniStatusline.active()%}', win_id)\n  local inactive = eval_statusline('%{%v:lua.MiniStatusline.inactive()%}', win_id)\n  local out = eval_statusline(child.api.nvim_get_option_value('statusline', { win = win_id }), win_id)\n  local out_content_source = out == active and 'active' or (out == inactive and 'inactive' or 'unknown')\n  eq(out_content_source, ref_content_source)\nend\n\n-- Mocks\nlocal mock_miniicons = function() child.lua('require(\"mini.icons\").setup()') end\n\nlocal mock_gitsigns = function()\n  child.b.gitsigns_head, child.b.gitsigns_status = 'main', '+1 ~2 -3'\nend\n\nlocal mock_minigit = function() child.b.minigit_summary_string = 'main|bisect (MM)' end\n\nlocal mock_minidiff = function() child.b.minidiff_summary_string = '#4 +3 ~2 -1' end\n\nlocal mock_diagnostics = function()\n  child.cmd('luafile tests/dir-statusline/mock-diagnostics.lua')\n  child.cmd('doautocmd DiagnosticChanged')\nend\n\nlocal mock_lsp = function() child.cmd('luafile tests/mock-lsp/months.lua') end\n\nlocal mock_buffer_size = function(bytes)\n  -- Reduce bytes for end-of-line: '\\n' on Unix and '\\r\\n' on Windows\n  local eol_bytes = helpers.is_windows() and 2 or 1\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { string.rep('a', bytes - eol_bytes) })\n  child.bo.modified = false\nend\n\n-- Time constants\nlocal term_mode_wait = helpers.get_time_const(50)\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n\n      -- Ensure wide enough window\n      child.o.columns = 300\n      setup_windows()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniStatusline)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniStatusline'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniStatuslineModeNormal', 'links to Cursor')\n  has_highlight('MiniStatuslineModeInsert', 'links to DiffChange')\n  has_highlight('MiniStatuslineModeVisual', 'links to DiffAdd')\n  has_highlight('MiniStatuslineModeReplace', 'links to DiffDelete')\n  has_highlight('MiniStatuslineModeCommand', 'links to DiffText')\n  has_highlight('MiniStatuslineModeOther', 'links to IncSearch')\n  has_highlight('MiniStatuslineDevinfo', 'links to StatusLine')\n  has_highlight('MiniStatuslineFilename', 'links to StatusLineNC')\n  has_highlight('MiniStatuslineFileinfo', 'links to StatusLine')\n  has_highlight('MiniStatuslineInactive', 'links to StatusLineNC')\n\n  -- Sets global value of 'statusline'\n  eq(\n    child.go.statusline,\n    '%{%(nvim_get_current_win()==#g:actual_curwin || &laststatus==3) ? v:lua.MiniStatusline.active() : v:lua.MiniStatusline.inactive()%}'\n  )\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniStatusline.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniStatusline.config.' .. field), value) end\n\n  expect_config('content.active', vim.NIL)\n  expect_config('content.inactive', vim.NIL)\n  expect_config('use_icons', true)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ use_icons = false })\n  eq(child.lua_get('MiniStatusline.config.use_icons'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ content = 'a' }, 'content', 'table')\n  expect_config_error({ content = { active = 'a' } }, 'content.active', 'function')\n  expect_config_error({ content = { inactive = 'a' } }, 'content.inactive', 'function')\n  expect_config_error({ use_icons = 'a' }, 'use_icons', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniStatuslineModeNormal'), 'links to Cursor')\nend\n\nT['setup()'][\"sets proper dynamic 'statusline' value\"] = function()\n  local wins = get_two_windows()\n\n  validate_statusline(wins.active, 'active')\n  validate_statusline(wins.inactive, 'inactive')\n\n  child.api.nvim_set_current_win(wins.inactive)\n  validate_statusline(wins.active, 'inactive')\n  validate_statusline(wins.inactive, 'active')\nend\n\nT['setup()']['disables built-in statusline in quickfix window'] = function()\n  child.cmd('copen')\n  validate_statusline(0, 'active')\nend\n\nT['setup()']['ensures content when working with built-in terminal'] = function()\n  helpers.skip_on_windows('Terminal emulator testing is not robust/easy on Windows')\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n\n  child.cmd('terminal! bash --noprofile --norc')\n  -- Wait for terminal to get active\n  vim.loop.sleep(term_mode_wait)\n  validate_statusline(0, 'active')\n  eq(child.api.nvim_get_current_buf() == init_buf_id, false)\n\n  type_keys('i', 'exit', '<CR>')\n  vim.loop.sleep(term_mode_wait)\n  type_keys('<CR>')\n  validate_statusline(0, 'active')\n  eq(child.api.nvim_get_current_buf() == init_buf_id, true)\nend\n\nT['setup()']['ensures content when buffer is displayed in non-current window'] = function()\n  local init_win_id = child.api.nvim_get_current_win()\n  local buf_id = child.api.nvim_create_buf(false, true)\n\n  -- Normal window\n  child.cmd('leftabove vertical split')\n  local new_win_id = child.api.nvim_get_current_win()\n  child.api.nvim_set_current_win(init_win_id)\n  child.api.nvim_win_set_buf(new_win_id, buf_id)\n  validate_statusline(init_win_id, 'active')\n\n  -- Floating window\n  child.api.nvim_open_win(buf_id, false, { relative = 'editor', row = 1, col = 1, height = 4, width = 10 })\n  validate_statusline(init_win_id, 'active')\nend\n\nT['setup()']['handles `laststatus=3`'] = function()\n  -- Should set same active content for all windows\n  child.o.laststatus = 3\n  local init_win_id = child.api.nvim_get_current_win()\n  child.cmd('leftabove vertical split')\n  local new_win_id = child.api.nvim_get_current_win()\n  validate_statusline(init_win_id, 'active')\n  validate_statusline(new_win_id, 'active')\n\n  child.cmd('wincmd w')\n  validate_statusline(init_win_id, 'active')\n  validate_statusline(new_win_id, 'active')\nend\n\nT['combine_groups()'] = new_set()\n\nlocal combine_groups = function(...) return child.lua_get('MiniStatusline.combine_groups(...)', { ... }) end\n\nlocal example_groups = {\n  { hl = 'AA', strings = { 'a1', 'a2' } },\n  { hl = 'BB', strings = { 'b1', '', 'b2' } },\n  '%=',\n  { hl = 'CC', strings = { 'c1' } },\n}\n\nT['combine_groups()']['works'] = function() eq(combine_groups(example_groups), '%#AA# a1 a2 %#BB# b1 b2 %=%#CC# c1 ') end\n\nT['combine_groups()']['handles non-table elements'] = function()\n  -- Strings should be used as is, other non-table elements - filtered out\n  eq(combine_groups({ 1, 'xxx', example_groups[1] }), 'xxx%#AA# a1 a2 ')\n  eq(combine_groups({ example_groups[1], 'xxx' }), '%#AA# a1 a2 xxx')\n  eq(combine_groups({ 'xxx', 'yyy' }), 'xxxyyy')\nend\n\nT['combine_groups()']['uses only non-empty strings from `strings` field'] = function()\n  eq(combine_groups({ { hl = 'AA', strings = { 'a', 1, {}, true, '', 'b' } } }), '%#AA# a b ')\nend\n\nT['combine_groups()']['allows empty `hl` to use previous highlight group'] = function()\n  eq(combine_groups({ { strings = { 'a' } }, { hl = 'BB', strings = { 'b' } } }), ' a %#BB# b ')\n  eq(combine_groups({ { hl = 'BB', strings = { 'b' } }, { strings = { 'a' } } }), '%#BB# b  a ')\nend\n\nT['combine_groups()']['allows empty `strings` to start new highlight'] = function()\n  eq(combine_groups({ { hl = 'AA' }, { strings = { 'b1', 'b2' } } }), '%#AA# b1 b2 ')\n  eq(combine_groups({ { hl = 'AA' }, { hl = 'BB', strings = { 'b1', 'b2' } } }), '%#AA#%#BB# b1 b2 ')\n  eq(combine_groups({ { strings = { 'a1', 'a2' } }, { hl = 'BB' }, { strings = { 'c1' } } }), ' a1 a2 %#BB# c1 ')\nend\n\nlocal is_truncated = function(...) return child.lua_get('MiniStatusline.is_truncated(...)', { ... }) end\n\nT['is_truncated()'] = new_set()\n\nT['is_truncated()']['works'] = function()\n  child.cmd('wincmd v')\n  set_width(50)\n\n  -- Should return `false` (\"not trauncated\") by default\n  eq(is_truncated(), false)\n\n  eq(is_truncated(49), false)\n  eq(is_truncated(50), false)\n  eq(is_truncated(51), true)\nend\n\nT['is_truncated()']['respects global statusline'] = function()\n  child.o.laststatus = 3\n  child.o.columns = 60\n  child.cmd('wincmd v')\n  set_width(50)\n\n  eq(is_truncated(51), false)\n  eq(is_truncated(59), false)\n  eq(is_truncated(60), false)\n  eq(is_truncated(61), true)\nend\n\nlocal eval_content = function(field) return child.lua_get(('MiniStatusline.%s()'):format(field)) end\n\nT['active()/inactive()'] = new_set({\n  parametrize = { { 'active' }, { 'inactive' } },\n})\n\nT['active()/inactive()']['respects `config.content`'] = function(field)\n  unload_module()\n  local command =\n    string.format([[require('mini.statusline').setup({ content = { %s = function() return 'aaa' end } })]], field)\n  child.lua(command)\n  eq(eval_content(field), 'aaa')\n\n  command = string.format([[vim.b.ministatusline_config = { content = { %s = function() return 'bbb' end } }]], field)\n  child.lua(command)\n  eq(eval_content(field), 'bbb')\nend\n\nT['active()/inactive()']['respects `vim.{g,b}.ministatusline_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(field, var_type)\n    child[var_type].ministatusline_disable = true\n    eq(eval_content(field), '')\n  end,\n})\n\n-- Sections -------------------------------------------------------------------\nT['section_diagnostics()'] = new_set({ hooks = { pre_case = mock_diagnostics } })\n\nT['section_diagnostics()']['works'] = function()\n  local get_n_attached_clients = function()\n    return child.lua([[\n      return vim.fn.has('nvim-0.10') == 1 and #vim.lsp.get_clients({ bufnr = 0 }) or\n      #vim.lsp.get_active_clients({ bufnr = 0 })\n    ]])\n  end\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), ' E4 W3 I2 H1')\n\n  -- Should not depend on LSP server attached\n  mock_lsp()\n  eq(get_n_attached_clients(), 1)\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), ' E4 W3 I2 H1')\n\n  child.lua('vim.lsp.buf_detach_client(0, _G.months_lsp_client_id)')\n  eq(get_n_attached_clients(), 0)\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), ' E4 W3 I2 H1')\n\n  -- Should use cache on `DiagnosticChanged`\n  child.cmd('enew')\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), '')\n  child.cmd('doautocmd DiagnosticChanged')\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), ' E4 W3 I2 H1')\n\n  -- Should return empty string if no diagnostic entries is set\n  child.cmd('buffer #')\n  child.lua('vim.diagnostic.get = function(...) return {} end')\n  child.lua('vim.diagnostic.count = function(...) return {} end')\n  child.cmd('doautocmd DiagnosticChanged')\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), '')\nend\n\nT['section_diagnostics()']['respects `args.trunc_width`'] = function()\n  set_width(100)\n  eq(child.lua_get('MiniStatusline.section_diagnostics({ trunc_width = 100 })'), ' E4 W3 I2 H1')\n  set_width(99)\n  eq(child.lua_get('MiniStatusline.section_diagnostics({ trunc_width = 100 })'), '')\nend\n\nT['section_diagnostics()']['respects `args.icon`'] = function()\n  eq(child.lua_get([[MiniStatusline.section_diagnostics({icon = 'A'})]]), 'A E4 W3 I2 H1')\n  eq(child.lua_get([[MiniStatusline.section_diagnostics({icon = 'AAA'})]]), 'AAA E4 W3 I2 H1')\nend\n\nT['section_diagnostics()']['respects `args.signs`'] = function()\n  local out = child.lua_get(\n    [[MiniStatusline.section_diagnostics({ signs = { ERROR = '!', WARN = '?', INFO = '@', HINT = '*' } })]]\n  )\n  eq(out, ' !4 ?3 @2 *1')\nend\n\nT['section_diagnostics()']['respects `config.use_icons`'] = function()\n  child.lua('MiniStatusline.config.use_icons = false')\n  eq(child.lua_get([[MiniStatusline.section_diagnostics({})]]), 'Diag E4 W3 I2 H1')\n\n  -- Should also use buffer local config\n  child.b.ministatusline_config = { use_icons = true }\n  eq(child.lua_get([[MiniStatusline.section_diagnostics({})]]), ' E4 W3 I2 H1')\nend\n\nT['section_diagnostics()']['works in not normal buffers'] = function()\n  -- Should return empty string if there is no diagnostic defined\n  child.cmd('help')\n  child.cmd('doautocmd DiagnosticChanged')\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), ' E4 W3 I2 H1')\n\n  child.lua('vim.diagnostic.get = function(...) return {} end')\n  child.lua('vim.diagnostic.count = function(...) return {} end')\n  child.cmd('doautocmd DiagnosticChanged')\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), '')\nend\n\nT['section_diagnostics()']['is not shown if diagnostics is disabled'] = function()\n  local buf_id = child.api.nvim_get_current_buf()\n  if child.fn.has('nvim-0.10') == 1 then\n    child.diagnostic.enable(false, { bufnr = buf_id })\n  else\n    child.diagnostic.disable(buf_id)\n  end\n  eq(child.lua_get('MiniStatusline.section_diagnostics({})'), '')\nend\n\nT['section_lsp()'] = new_set({ hooks = { pre_case = mock_lsp } })\n\nT['section_lsp()']['works'] = function()\n  eq(child.lua_get('MiniStatusline.section_lsp({})'), '󰰎 +')\n\n  -- Should show number of attached LSP servers\n  child.cmd('luafile tests/mock-lsp/fruits.lua')\n  eq(child.lua_get('MiniStatusline.section_lsp({})'), '󰰎 ++')\n\n  -- Should work if attached buffer clients is returned not as array\n  child.lua('vim.lsp.buf_detach_client(0, _G.months_lsp_client_id)')\n  eq(child.lua_get('MiniStatusline.section_lsp({})'), '󰰎 +')\n\n  -- Should show empty string if no attached LSP servers\n  child.lua('vim.lsp.buf_detach_client(0, _G.fruits_lsp_client_id)')\n  eq(child.lua_get('MiniStatusline.section_lsp({})'), '')\nend\n\nT['section_lsp()']['respects `args.trunc_width`'] = function()\n  set_width(100)\n  eq(child.lua_get('MiniStatusline.section_lsp({ trunc_width = 100 })'), '󰰎 +')\n  set_width(99)\n  eq(child.lua_get('MiniStatusline.section_lsp({ trunc_width = 100 })'), '')\nend\n\nT['section_lsp()']['respects `args.icon`'] = function()\n  eq(child.lua_get('MiniStatusline.section_lsp({icon = \"A\"})'), 'A +')\n  eq(child.lua_get('MiniStatusline.section_lsp({icon = \"AAA\"})'), 'AAA +')\nend\n\nT['section_lsp()']['respects `config.use_icons`'] = function()\n  child.lua('MiniStatusline.config.use_icons = false')\n  eq(child.lua_get('MiniStatusline.section_lsp({})'), 'LSP +')\n\n  -- Should also use buffer local config\n  child.b.ministatusline_config = { use_icons = true }\n  eq(child.lua_get('MiniStatusline.section_lsp({})'), '󰰎 +')\nend\n\nT['section_fileinfo()'] = new_set({ hooks = { pre_case = mock_miniicons } })\n\nlocal validate_fileinfo = function(args, pattern)\n  local command = ('MiniStatusline.section_fileinfo({ %s })'):format(args)\n  expect.match(child.lua_get(command), pattern)\nend\n\nT['section_fileinfo()']['works'] = function()\n  mock_buffer_size(10)\n  child.bo.filetype = 'text'\n  local encoding = child.bo.fileencoding or child.bo.encoding\n  local format = child.bo.fileformat\n  local pattern = '^󰦪 text ' .. vim.pesc(encoding) .. '%[' .. vim.pesc(format) .. '%] 10B$'\n  validate_fileinfo('', pattern)\nend\n\nT['section_fileinfo()']['respects `args.trunc_width`'] = function()\n  mock_buffer_size(10)\n  child.bo.filetype = 'text'\n\n  set_width(100)\n  validate_fileinfo('trunc_width = 100', '^󰦪 text...')\n  set_width(99)\n  validate_fileinfo('trunc_width = 100', '^󰦪 text$')\nend\n\nT['section_fileinfo()']['respects `config.use_icons`'] = function()\n  mock_buffer_size(10)\n  child.bo.filetype = 'text'\n\n  child.lua('MiniStatusline.config.use_icons = false')\n  validate_fileinfo('', '^text...')\n\n  -- Should also use buffer local config\n  child.b.ministatusline_config = { use_icons = true }\n  validate_fileinfo('', '󰦪 text...')\nend\n\nT['section_fileinfo()'][\"can fall back to 'nvim-web-devicons'\"] = function()\n  child.lua('_G.MiniIcons = nil')\n  reload_module()\n\n  -- Mock 'nvim-web-devicons'\n  child.cmd('set rtp+=tests/dir-statusline')\n\n  child.cmd('e tmp.txt')\n  validate_fileinfo('', ' text...')\nend\n\nT['section_fileinfo()']['uses correct filetype'] = function()\n  child.bo.filetype = 'aaa'\n  validate_fileinfo('', ' aaa ')\nend\n\nT['section_fileinfo()']['shows correct size'] = function()\n  -- Should show '0 bytes' on empty buffer\n  validate_fileinfo('', '0B')\n\n  -- Should update based on current text (not saved version)\n  mock_buffer_size(10)\n  validate_fileinfo('', '10B')\n\n  type_keys('i', 'xxx')\n  validate_fileinfo('', '13B')\n\n  -- Should show human friendly size version\n  mock_buffer_size(1024)\n  validate_fileinfo('', '1%.00KiB$')\n\n  mock_buffer_size(1024 * 1024)\n  validate_fileinfo('', '1%.00MiB$')\nend\n\nT['section_fileinfo()']['works in special buffers'] = function()\n  local fileformat = helpers.is_windows() and 'dos' or 'unix'\n\n  -- Should treat normal buffer with empty filetype as failed filetype match\n  validate_fileinfo('', '^%[' .. fileformat .. '%] 0B$')\n\n  child.bo.filetype = 'aaa'\n  validate_fileinfo('', '^󰈔 aaa %[' .. fileformat .. '%] 0B$')\n\n  -- Should show only filetype for not normal buffers\n  child.cmd('help')\n  validate_fileinfo('', '^󰋖 help$')\nend\n\nT['section_filename()'] = new_set()\n\nT['section_filename()']['works'] = function()\n  local name = vim.fn.tempname()\n  child.cmd('edit ' .. name)\n  eq(child.lua_get('MiniStatusline.section_filename({})'), '%F%m%r')\n\n  -- Should work in terminal\n  child.cmd('terminal')\n  eq(child.lua_get('MiniStatusline.section_filename({})'), '%t')\nend\n\nT['section_filename()']['respects `args.trunc_width`'] = function()\n  local name = vim.fn.tempname()\n  child.cmd('edit ' .. name)\n\n  set_width(100)\n  eq(child.lua_get('MiniStatusline.section_filename({ trunc_width = 100 })'), '%F%m%r')\n  set_width(99)\n  eq(child.lua_get('MiniStatusline.section_filename({ trunc_width = 100 })'), '%f%m%r')\nend\n\nT['section_git()'] = new_set({ hooks = { pre_case = mock_minigit } })\n\nT['section_git()']['works'] = function()\n  eq(child.lua_get('MiniStatusline.section_git({})'), ' main|bisect (MM)')\n\n  -- Should return non-empty string even if there is no branch\n  child.b.minigit_summary_string = ''\n  eq(child.lua_get('MiniStatusline.section_git({})'), ' -')\n\n  -- Should return empty string if no Git data is found\n  child.b.minigit_summary_string = nil\n  eq(child.lua_get('MiniStatusline.section_git({})'), '')\nend\n\nT['section_git()'][\"falls back to 'gitsigns.nvim'\"] = function()\n  child.b.minigit_summary_string = nil\n  mock_gitsigns()\n\n  eq(child.lua_get('MiniStatusline.section_git({})'), ' main')\n\n  -- Should return non-empty string even if there is no branch\n  child.b.gitsigns_head = ''\n  eq(child.lua_get('MiniStatusline.section_git({})'), ' -')\n\n  -- Should return empty string if no Git data is found\n  child.b.gitsigns_head = nil\n  eq(child.lua_get('MiniStatusline.section_git({})'), '')\nend\n\nT['section_git()']['respects `args.trunc_width`'] = function()\n  set_width(100)\n  eq(child.lua_get('MiniStatusline.section_git({ trunc_width = 100 })'), ' main|bisect (MM)')\n  set_width(99)\n  eq(child.lua_get('MiniStatusline.section_git({ trunc_width = 100 })'), '')\nend\n\nT['section_git()']['respects `args.icon`'] = function()\n  eq(child.lua_get([[MiniStatusline.section_git({ icon = 'A' })]]), 'A main|bisect (MM)')\n  eq(child.lua_get([[MiniStatusline.section_git({ icon = 'AAA' })]]), 'AAA main|bisect (MM)')\nend\n\nT['section_git()']['respects `config.use_icons`'] = function()\n  child.lua('MiniStatusline.config.use_icons = false')\n  eq(child.lua_get([[MiniStatusline.section_git({})]]), 'Git main|bisect (MM)')\n\n  -- Should also use buffer local config\n  child.b.ministatusline_config = { use_icons = true }\n  eq(child.lua_get([[MiniStatusline.section_git({})]]), ' main|bisect (MM)')\nend\n\nT['section_diff()'] = new_set({ hooks = { pre_case = mock_minidiff } })\n\nT['section_diff()']['works'] = function()\n  eq(child.lua_get('MiniStatusline.section_diff({})'), ' #4 +3 ~2 -1')\n\n  -- Should return non-empty string even if there is no branch\n  child.b.minidiff_summary_string = ''\n  eq(child.lua_get('MiniStatusline.section_diff({})'), ' -')\n\n  -- Should return empty string if no Git data is found\n  child.b.minidiff_summary_string = nil\n  eq(child.lua_get('MiniStatusline.section_diff({})'), '')\nend\n\nT['section_diff()'][\"falls back to 'gitsigns.nvim'\"] = function()\n  child.b.minidiff_summary_string = nil\n  mock_gitsigns()\n\n  eq(child.lua_get('MiniStatusline.section_diff({})'), ' +1 ~2 -3')\n\n  -- Should return non-empty string even if there is no branch\n  child.b.gitsigns_status = ''\n  eq(child.lua_get('MiniStatusline.section_diff({})'), ' -')\n\n  -- Should return empty string if no Git data is found\n  child.b.gitsigns_status = nil\n  eq(child.lua_get('MiniStatusline.section_diff({})'), '')\nend\n\nT['section_diff()']['respects `args.trunc_width`'] = function()\n  set_width(100)\n  eq(child.lua_get('MiniStatusline.section_diff({ trunc_width = 100 })'), ' #4 +3 ~2 -1')\n  set_width(99)\n  eq(child.lua_get('MiniStatusline.section_diff({ trunc_width = 100 })'), '')\nend\n\nT['section_diff()']['respects `args.icon`'] = function()\n  eq(child.lua_get([[MiniStatusline.section_diff({ icon = 'A' })]]), 'A #4 +3 ~2 -1')\n  eq(child.lua_get([[MiniStatusline.section_diff({ icon = 'AAA' })]]), 'AAA #4 +3 ~2 -1')\nend\n\nT['section_diff()']['respects `config.use_icons`'] = function()\n  child.lua('MiniStatusline.config.use_icons = false')\n  eq(child.lua_get([[MiniStatusline.section_diff({})]]), 'Diff #4 +3 ~2 -1')\n\n  -- Should also use buffer local config\n  child.b.ministatusline_config = { use_icons = true }\n  eq(child.lua_get([[MiniStatusline.section_diff({})]]), ' #4 +3 ~2 -1')\nend\n\nT['section_location()'] = new_set()\n\nT['section_location()']['works'] = function()\n  eq(child.lua_get('MiniStatusline.section_location({})'), '%l|%L│%2v|%-2{virtcol(\"$\") - 1}')\nend\n\nT['section_location()']['respects `args.trunc_width`'] = function()\n  set_width(100)\n  eq(child.lua_get('MiniStatusline.section_location({ trunc_width = 100 })'), '%l|%L│%2v|%-2{virtcol(\"$\") - 1}')\n  set_width(99)\n  eq(child.lua_get('MiniStatusline.section_location({ trunc_width = 100 })'), '%l│%2v')\nend\n\nT['section_mode()'] = new_set()\n\nlocal section_mode = function(args) return child.lua_get('{ MiniStatusline.section_mode(...) }', { args or {} }) end\n\nT['section_mode()']['works'] = function() eq(section_mode(), { 'Normal', 'MiniStatuslineModeNormal' }) end\n\nT['section_mode()']['shows correct mode'] = function()\n  local validate = function(output)\n    eq(section_mode(), output)\n    child.ensure_normal_mode()\n  end\n\n  child.cmd('startinsert')\n  validate({ 'Insert', 'MiniStatuslineModeInsert' })\n\n  type_keys('v')\n  validate({ 'Visual', 'MiniStatuslineModeVisual' })\n\n  type_keys('V')\n  validate({ 'V-Line', 'MiniStatuslineModeVisual' })\n\n  type_keys('<C-V>')\n  validate({ 'V-Block', 'MiniStatuslineModeVisual' })\n\n  type_keys(':')\n  validate({ 'Command', 'MiniStatuslineModeCommand' })\n\n  type_keys('R')\n  validate({ 'Replace', 'MiniStatuslineModeReplace' })\n\n  child.cmd('terminal')\n  child.cmd('startinsert')\n  validate({ 'Terminal', 'MiniStatuslineModeOther' })\nend\n\nT['section_mode()']['respects `args.trunc_width`'] = function()\n  set_width(100)\n  eq(section_mode({ trunc_width = 100 }), { 'Normal', 'MiniStatuslineModeNormal' })\n  set_width(99)\n  eq(section_mode({ trunc_width = 100 }), { 'N', 'MiniStatuslineModeNormal' })\nend\n\nT['section_searchcount()'] = new_set({ hooks = { pre_case = function() mock_buffer_size(10) end } })\n\nlocal section_searchcount = function(args)\n  return child.lua_get('MiniStatusline.section_searchcount(...)', { args or {} })\nend\n\nT['section_searchcount()']['works'] = function()\n  set_lines({ '', 'a a a ' })\n\n  -- Shows nothing if search is not initiated\n  eq(section_searchcount(), '')\n\n  type_keys('/', 'a', '<CR>')\n  set_cursor(1, 0)\n  eq(section_searchcount(), '0/3')\n\n  set_cursor(2, 0)\n  eq(section_searchcount(), '1/3')\n\n  set_cursor(2, 1)\n  eq(section_searchcount(), '1/3')\n\n  set_cursor(2, 5)\n  eq(section_searchcount(), '3/3')\nend\n\nT['section_searchcount()']['works with many search matches'] = function()\n  local maxcount = child.fn.has('nvim-0.12') == 1 and 999 or 99\n  local args = { options = { timeout = 15 * small_time } }\n\n  set_lines({ string.rep('a ', maxcount + 2) })\n  type_keys('/', 'a', '<CR>')\n  set_cursor(1, 0)\n\n  eq(section_searchcount(args), '1/>' .. maxcount)\n\n  set_cursor(1, maxcount * 2 - 1)\n  eq(section_searchcount(args), maxcount .. '/>' .. maxcount)\n\n  set_cursor(1, maxcount * 2)\n  eq(section_searchcount(args), '>' .. maxcount .. '/>' .. maxcount)\nend\n\nT['section_searchcount()']['respects `args.trunc_width`'] = function()\n  set_lines({ '', 'a a a ' })\n  type_keys('/', 'a', '<CR>')\n  set_cursor(1, 0)\n\n  set_width(100)\n  eq(section_searchcount({ trunc_width = 100 }), '0/3')\n  set_width(99)\n  eq(section_searchcount({ trunc_width = 100 }), '')\nend\n\nT['section_searchcount()']['respects `args.options`'] = function()\n  -- Disable recomputation from section in default content\n  child.lua([[MiniStatusline.config.content.active = function() return '%f' end]])\n  set_lines({ '', 'a a a ' })\n  type_keys('/', 'a', '<CR>')\n\n  eq(section_searchcount({ options = { recompute = false } }), '1/3')\n  set_cursor(2, 5)\n  eq(section_searchcount({ options = { recompute = false } }), '1/3')\nend\n\nT['section_searchcount()']['does not fail on `searchcount()` error'] = function()\n  -- This matters because it is assumed that `section_searchcount` will be\n  -- called on every statusline update, which will happen during typing `/\\(`\n  -- to search for something like `\\(\\)`.\n  child.fn.setreg('/', [[\\(]])\n  expect.no_error(section_searchcount)\nend\n\n-- Integration tests ==========================================================\nT['Default content'] = new_set()\n\nT['Default content']['active'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.set_size(5, 160)\n\n      child.lua('require(\"mini.icons\").setup()')\n      child.cmd('edit tests/dir-statusline/mocked.lua')\n      child.bo.fileencoding = 'utf-8'\n      mock_buffer_size(10)\n\n      -- Mock filename section to use relative path for consistent screenshots\n      child.lua([[MiniStatusline.section_filename = function() return '%f%m%r' end]])\n      mock_diagnostics()\n      mock_lsp()\n      mock_minigit()\n      mock_minidiff()\n      type_keys('/a', '<CR>')\n    end,\n  },\n  -- There should also be test for 140, but it is for truncating in\n  -- `section_filename` from full to relative paths\n  parametrize = { { 120 }, { 75 }, { 40 }, { 39 } },\n}, {\n  test = function(window_width)\n    helpers.skip_on_windows('Windows has different default path separator')\n\n    validate_statusline(0, 'active')\n    set_width(window_width)\n    child.expect_screenshot()\n  end,\n})\n\nT['Default content']['inactive'] = function()\n  eq(child.lua_get('MiniStatusline.inactive()'), '%#MiniStatuslineInactive#%F%=')\nend\n\nT['Default content']['inactive is evaluated in the context of its window'] = function()\n  child.set_size(10, 30)\n  child.lua([[\n    local f = function() return vim.api.nvim_get_current_win() end\n    MiniStatusline.config.content = { active = f, inactive = f }\n  ]])\n  child.cmd('wincmd =')\n  child.cmd('redraw!')\n  child.expect_screenshot()\n  eq(child.api.nvim_get_current_win(), 1001)\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_surround.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('surround', config) end\nlocal unload_module = function() child.mini_unload('surround') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child) end\n--stylua: ignore end\n\n-- Make helpers\nlocal clear_messages = function() child.cmd('messages clear') end\n\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n\nlocal has_message_about_not_found = function(char, n_lines, search_method, n_times)\n  n_lines = n_lines or 20\n  search_method = search_method or 'cover'\n  n_times = n_times or 1\n  local msg = string.format(\n    [[(mini.surround) No surrounding %s found within %s lines and `config.search_method = '%s'`.]],\n    vim.inspect((n_times > 1 and n_times or '') .. char),\n    n_lines,\n    search_method\n  )\n  eq(get_latest_message(), msg)\nend\n\n-- Custom validators\nlocal validate_edit = function(before_lines, before_cursor, after_lines, after_cursor, test_action, ...)\n  child.ensure_normal_mode()\n\n  set_lines(before_lines)\n  set_cursor(unpack(before_cursor))\n\n  test_action(...)\n\n  eq(get_lines(), after_lines)\n  eq(get_cursor(), after_cursor)\nend\n\nlocal validate_edit1d = function(before_line, before_column, after_line, after_column, test_action, ...)\n  validate_edit({ before_line }, { 1, before_column }, { after_line }, { 1, after_column }, test_action, ...)\nend\n\nlocal validate_find = function(lines, start_pos, positions, f, ...)\n  set_lines(lines)\n  set_cursor(unpack(start_pos))\n\n  for _, pos in ipairs(positions) do\n    f(...)\n    eq(get_lines(), lines)\n    eq(get_cursor(), pos)\n  end\nend\n\nlocal validate_no_find = function(lines, start_pos, f, ...)\n  set_lines(lines)\n  set_cursor(unpack(start_pos))\n  f(...)\n  eq(get_cursor(), start_pos)\nend\n\n-- Time constants\nlocal default_highlight_duraion = 500\nlocal reminder_delay = 1000\nlocal small_time = helpers.get_time_const(10)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n\n      -- Make all showed messages full width\n      child.o.cmdheight = 10\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniSurround)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniSurround'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniSurround'), 'links to IncSearch')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniSurround.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniSurround.config.' .. field), value) end\n\n  -- Check default values\n  expect_config('custom_surroundings', vim.NIL)\n  expect_config('n_lines', 20)\n  expect_config('highlight_duration', 500)\n  expect_config('mappings.add', 'sa')\n  expect_config('mappings.delete', 'sd')\n  expect_config('mappings.find', 'sf')\n  expect_config('mappings.find_left', 'sF')\n  expect_config('mappings.highlight', 'sh')\n  expect_config('mappings.replace', 'sr')\n  expect_config('mappings.suffix_last', 'l')\n  expect_config('mappings.suffix_next', 'n')\n  expect_config('respect_selection_type', false)\n  expect_config('search_method', 'cover')\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ n_lines = 10 })\n  eq(child.lua_get('MiniSurround.config.n_lines'), 10)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ custom_surroundings = 'a' }, 'custom_surroundings', 'table')\n  expect_config_error({ highlight_duration = 'a' }, 'highlight_duration', 'number')\n  expect_config_error({ mappings = 'a' }, 'mappings', 'table')\n  expect_config_error({ mappings = { add = 1 } }, 'mappings.add', 'string')\n  expect_config_error({ mappings = { delete = 1 } }, 'mappings.delete', 'string')\n  expect_config_error({ mappings = { find = 1 } }, 'mappings.find', 'string')\n  expect_config_error({ mappings = { find_left = 1 } }, 'mappings.find_left', 'string')\n  expect_config_error({ mappings = { highlight = 1 } }, 'mappings.highlight', 'string')\n  expect_config_error({ mappings = { replace = 1 } }, 'mappings.replace', 'string')\n  expect_config_error({ mappings = { suffix_last = 1 } }, 'mappings.suffix_last', 'string')\n  expect_config_error({ mappings = { suffix_next = 1 } }, 'mappings.suffix_next', 'string')\n  expect_config_error({ n_lines = 'a' }, 'n_lines', 'number')\n  expect_config_error({ respect_selection_type = 1 }, 'respect_selection_type', 'boolean')\n  expect_config_error({ search_method = 1 }, 'search_method', 'one of')\n  expect_config_error({ silent = 1 }, 'silent', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniSurround'), 'links to IncSearch')\nend\n\nT['setup()']['properly handles `config.mappings`'] = function()\n  local has_surround_map = function(lhs, mode) return child.fn.maparg(lhs, mode):find('[Ss]urround') ~= nil end\n\n  local make_clean_state = function()\n    unload_module()\n    for _, map in ipairs(child.api.nvim_get_keymap('n')) do\n      child.api.nvim_del_keymap('n', map.lhs)\n    end\n    for _, map in ipairs(child.api.nvim_get_keymap('x')) do\n      child.api.nvim_del_keymap('x', map.lhs)\n    end\n  end\n\n  -- Regular mappings\n  eq(has_surround_map('sa', 'n'), true)\n\n  -- Should map \"s\" to <Nop>, but only if needed\n  eq(child.fn.maparg('s', 'n'), '<Nop>')\n  eq(child.fn.maparg('s', 'x'), '<Nop>')\n\n  -- Supplying empty string should mean \"don't create keymap\"\n  make_clean_state()\n  load_module({ mappings = { add = '' } })\n  eq(has_surround_map('sa', 'n'), false)\n\n  -- Extended mappings\n  eq(has_surround_map('sdl', 'n'), true)\n  eq(has_surround_map('sdn', 'n'), true)\n\n  make_clean_state()\n  load_module({ mappings = { delete = '', suffix_last = '' } })\n  eq(has_surround_map('sdl', 'n'), false)\n  eq(has_surround_map('sdn', 'n'), false)\n  eq(has_surround_map('srl', 'n'), false)\n  eq(has_surround_map('srn', 'n'), true)\n\n  -- Should precisely set 's' keymap\n  make_clean_state()\n  load_module({ mappings = { add = 'cs', delete = 'sd', find = '', find_left = '' } })\n  eq(child.fn.maparg('s', 'n'), '<Nop>')\n  eq(child.fn.maparg('s', 'x'), '')\n\n  -- - Should ignore presence of buffer-local mappings\n  local vim_surround_mappings = {\n    add = 'ys',\n    delete = 'ds',\n    find = '',\n    find_left = '',\n    highlight = '',\n    replace = 'cs',\n    suffix_last = '',\n    suffix_next = '',\n  }\n  -- - Should also not override already present user mapping for `s`\n  make_clean_state()\n  child.cmd('nmap s <Cmd>echo 1<CR>')\n  load_module({ mappings = vim_surround_mappings })\n  eq(child.fn.maparg('s', 'n'), '<Cmd>echo 1<CR>')\n  eq(child.fn.maparg('s', 'x'), '')\n\n  -- - Should allow creating a plain `s` as a mapping\n  vim_surround_mappings.add = 's'\n  make_clean_state()\n  load_module({ mappings = vim_surround_mappings })\n  eq(has_surround_map('s', 'n'), true)\n  eq(has_surround_map('s', 'x'), true)\n\n  -- - Should ignore buffer-local `s` mappings and still create global `<Nop>`\n  make_clean_state()\n  child.cmd('nmap <buffer> s <Cmd>echo 1<CR>')\n  child.cmd('xmap <buffer> s <Cmd>echo 2<CR>')\n  load_module()\n  eq(child.fn.maparg('s', 'n'), '<Cmd>echo 1<CR>')\n  eq(child.fn.maparg('s', 'x'), '<Cmd>echo 2<CR>')\n\n  local get_global_mapping = function(mode, lhs)\n    for _, map in ipairs(child.api.nvim_get_keymap(mode)) do\n      if map.lhs == lhs then return map end\n    end\n    return {}\n  end\n  -- - NOTE: `nvim_get_keymap()` return `rhs=''` if it is mapped to `<Nop>`\n  --   For absent mapping it would have been `nil`\n  eq(get_global_mapping('n', 's').rhs, '')\n  eq(get_global_mapping('x', 's').rhs, '')\n\n  -- - Should work when there are both buffer-local and global mappings\n  make_clean_state()\n  child.cmd('nmap          s <Cmd>echo 1<CR>')\n  child.cmd('nmap <buffer> s <Cmd>echo 10<CR>')\n  child.cmd('xmap          s <Cmd>echo 2<CR>')\n  child.cmd('xmap <buffer> s <Cmd>echo 20<CR>')\n\n  load_module()\n\n  eq(child.fn.maparg('s', 'n'), '<Cmd>echo 10<CR>')\n  eq(child.fn.maparg('s', 'x'), '<Cmd>echo 20<CR>')\n  eq(get_global_mapping('n', 's').rhs, '<Cmd>echo 1<CR>')\n  eq(get_global_mapping('x', 's').rhs, '<Cmd>echo 2<CR>')\nend\n\nT['update_n_lines()'] = new_set({\n  hooks = {\n    pre_case = function() child.lua('vim.keymap.set(\"n\", \"sn\", \"<Cmd>lua MiniSurround.update_n_lines()<CR>\")') end,\n  },\n})\n\nT['update_n_lines()']['works'] = function()\n  local cur_n_lines = child.lua_get('MiniSurround.config.n_lines')\n\n  -- Should ask for input, display prompt text and current value of `n_lines`\n  type_keys('sn')\n  eq(child.fn.mode(), 'c')\n  eq(child.fn.getcmdline(), tostring(cur_n_lines))\n\n  type_keys('0', '<CR>')\n  eq(child.lua_get('MiniSurround.config.n_lines'), 10 * cur_n_lines)\nend\n\nT['update_n_lines()']['allows cancelling with `<Esc> and <C-c>`'] = function()\n  local validate_cancel = function(key)\n    child.ensure_normal_mode()\n    local cur_n_lines = child.lua_get('MiniSurround.config.n_lines')\n\n    type_keys('sn')\n    eq(child.fn.mode(), 'c')\n\n    type_keys(key)\n    eq(child.fn.mode(), 'n')\n    eq(child.lua_get('MiniSurround.config.n_lines'), cur_n_lines)\n  end\n\n  validate_cancel('<Esc>')\n  validate_cancel('<C-c>')\nend\n\nT['gen_spec'] = new_set()\n\nT['gen_spec']['input'] = new_set()\n\nT['gen_spec']['input']['treesitter()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Mock tree-sitter queries\n      child.cmd('noautocmd set rtp+=tests/mock-treesitter')\n\n      -- Start editing reference file\n      child.cmd('edit tests/mock-treesitter/lua-file.lua')\n      child.lua('vim.treesitter.start()')\n\n      -- Define \"function definition\" surrounding\n      child.lua([[MiniSurround.config.custom_surroundings = {\n        F = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@function.outer', inner = '@function.inner' }) }\n      }]])\n    end,\n  },\n})\n\nT['gen_spec']['input']['treesitter()']['works'] = function()\n  local lines = get_lines()\n\n  -- Should prefer range from metadata instead of node itself. This is useful,\n  -- for example, with `#offset!` directive to create more precise captures.\n  validate_find(lines, { 9, 0 }, { { 10, 12 }, { 11, 2 }, { 7, 6 }, { 8, 1 } }, type_keys, 'sf', 'F')\n  validate_no_find(lines, { 13, 0 }, type_keys, 'sf', 'F')\n\n  -- Should prefer match on current line over multiline covering\n  child.lua('MiniSurround.config.search_method = \"cover_or_next\"')\n  validate_find(lines, { 4, 0 }, { { 4, 9 }, { 4, 19 }, { 4, 34 }, { 4, 37 } }, type_keys, 'sf', 'F')\nend\n\nT['gen_spec']['input']['treesitter()']['works with empty region'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    o = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@return.outer', inner = '@return.inner' }) },\n  }]])\n  local lines = get_lines()\n\n  -- Delete\n  set_lines(lines)\n  set_cursor(10, 2)\n  type_keys('sd', 'o')\n  eq(get_lines()[10], '  true')\n\n  -- Replace\n  set_lines(lines)\n  set_cursor(10, 2)\n  type_keys('sr', 'o', '>')\n  eq(get_lines()[10], '  <true>')\n\n  -- Find\n  validate_find(lines, { 10, 2 }, { { 10, 8 }, { 10, 2 } }, type_keys, 'sf', 'o')\n\n  -- Highlight\n  child.set_size(15, 40)\n  child.o.cmdheight = 1\n  set_lines(lines)\n  set_cursor(10, 2)\n  type_keys('sh', 'o')\n  -- It highlights `return` differently from other places\n  if child.fn.has('nvim-0.11') == 1 then child.expect_screenshot() end\n\n  -- Edge case for empty region on end of last line\n  set_lines(lines)\n  set_cursor(13, 0)\n  type_keys('sd', 'o')\n  eq(get_lines()[13], 'M')\nend\n\nT['gen_spec']['input']['treesitter()']['works with no inner captures'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    o = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@return.outer', inner = '@string' }) },\n  }]])\n  local lines = get_lines()\n\n  -- Delete\n  set_lines(lines)\n  set_cursor(10, 2)\n  type_keys('sd', 'o')\n  -- - Should treat the whole \"outer\" match as left surrounding with\n  --   right surrounding being a single position right match edge.\n  eq(get_lines()[10], '  ')\n\n  -- Replace\n  set_lines(lines)\n  set_cursor(10, 2)\n  type_keys('sr', 'o', '>')\n  eq(get_lines()[10], '  <>')\n\n  -- Find\n  validate_find(lines, { 10, 2 }, { { 10, 12 }, { 10, 2 } }, type_keys, 'sf', 'o')\nend\n\nT['gen_spec']['input']['treesitter()']['works with parent of injected language'] = function()\n  if child.fn.has('nvim-0.10') == 0 then MiniTest.skip('`LanguageTree:parent()` requires Neovim>=0.10') end\n\n  local lines = {\n    'local foo = function()',\n    '  vim.cmd([[',\n    'set cursorline',\n    ']])',\n    'end',\n  }\n\n  validate_find(lines, { 3, 0 }, { { 4, 2 }, { 5, 2 }, { 1, 12 }, { 2, 1 } }, type_keys, 'sf', 'F')\n  validate_no_find(lines, { 1, 0 }, type_keys, 'sf', 'F')\nend\n\nT['gen_spec']['input']['treesitter()']['respects `opts.use_nvim_treesitter`'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    F = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@function.outer', inner = '@function.inner' }) },\n    o = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@plugin_other.outer', inner = '@plugin_other.inner' }) },\n    O = {\n      input = MiniSurround.gen_spec.input.treesitter(\n        { outer = '@plugin_other.outer', inner = '@plugin_other.inner' },\n        { use_nvim_treesitter = true }\n      )\n    },\n  }]])\n  local lines = get_lines()\n\n  -- By default it should be `false`\n  validate_find(lines, { 9, 0 }, { { 10, 12 }, { 11, 2 }, { 7, 6 }, { 8, 1 } }, type_keys, 'sf', 'F')\n  validate_no_find(lines, { 1, 0 }, type_keys, 'sf', 'o')\n  validate_no_find(lines, { 1, 0 }, type_keys, 'sf', 'O')\n\n  child.cmd('noautocmd set rtp+=tests/dir-surround/mock-nvim-treesitter')\n  -- Should prefer range from metadata instead of node itself. This is useful,\n  -- for example, with `#offset!` directive to create more precise captures.\n  validate_find(lines, { 9, 0 }, { { 10, 12 }, { 11, 2 }, { 7, 6 }, { 8, 1 } }, type_keys, 'sf', 'F')\n  validate_no_find(lines, { 1, 0 }, type_keys, 'sf', 'o')\n  validate_find(lines, { 1, 0 }, { { 1, 5 }, { 1, 0 } }, type_keys, 'sf', 'O')\nend\n\nT['gen_spec']['input']['treesitter()']['works with directives'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    S = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@string', inner = '@string_offset' }) }\n  }]])\n  local lines = get_lines()\n  validate_find(lines, { 9, 9 }, { { 9, 16 }, { 9, 17 }, { 9, 8 }, { 9, 16 } }, type_keys, 'sf', 'S')\nend\n\nT['gen_spec']['input']['treesitter()']['works with quantified captures'] = function()\n  if child.fn.has('nvim-0.10') == 0 then\n    MiniTest.skip('`Query:iter_matches()` returning several nodes requires Neovim>=0.10')\n  end\n\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    P = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@parameter.outer', inner = '@parameter.inner' }) }\n  }]])\n\n  local lines = get_lines()\n  local validate = function(col, ref_line)\n    set_lines(lines)\n    set_cursor(3, col)\n    type_keys('sr', 'P', '>')\n    eq(get_lines()[3], ref_line)\n  end\n  validate(13, 'function M.a(<u> vv, www)')\n  validate(16, 'function M.a(u<vv>, www)')\n  validate(21, 'function M.a(u, vv<www>)')\nend\n\nT['gen_spec']['input']['treesitter()']['works with row-exclusive, col-0 end range'] = function()\n  if child.fn.has('nvim-0.10') == 0 then\n    MiniTest.skip('`Query:iter_matches()` returning several nodes requires Neovim>=0.10')\n  end\n\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    c = { input = MiniSurround.gen_spec.input.treesitter({ outer = '@chunk.outer', inner = '@chunk.inner' }) }\n  }]])\n\n  local lines = get_lines()\n  validate_find(lines, { 4, 0 }, { { 13, 0 }, { 13, 7 }, { 1, 0 }, { 1, 11 } }, type_keys, 'sf', 'c')\nend\n\nT['gen_spec']['input']['treesitter()']['respects plugin options'] = function()\n  local lines = get_lines()\n\n  -- `opts.n_lines`\n  child.lua('MiniSurround.config.n_lines = 0')\n  validate_no_find(lines, { 1, 0 }, type_keys, 'sf', 'F')\n\n  -- `opts.search_method`\n  child.lua('MiniSurround.config.n_lines = 50')\n  child.lua('MiniSurround.config.search_method = \"next\"')\n  validate_no_find(lines, { 9, 0 }, type_keys, 'sf', 'F')\nend\n\nT['gen_spec']['input']['treesitter()']['validates `captures` argument'] = function()\n  local validate = function(args)\n    expect.error(function() child.lua([[MiniSurround.gen_spec.input.treesitter(...)]], { args }) end, 'captures')\n  end\n\n  validate('a')\n  validate({})\n  -- Each `outer` and `inner` should be a string starting with '@'\n  validate({ outer = 1 })\n  validate({ outer = 'function.outer' })\n  validate({ inner = 1 })\n  validate({ inner = 'function.inner' })\nend\n\nT['gen_spec']['input']['treesitter()']['validates builtin treesitter presence'] = function()\n  child.cmdheight = 40\n\n  -- Query\n  child.bo.filetype = 'vim'\n  expect.error(\n    function() type_keys('sd', 'F', '<CR>') end,\n    '%(mini%.surround%) Can not get query for buffer 1 and language \"vim\"%.'\n  )\n\n  -- Parser\n  child.bo.filetype = 'aaa'\n  expect.error(\n    function() type_keys('sd', 'F', '<CR>') end,\n    '%(mini%.surround%) Can not get parser for buffer 1 and language \"aaa\"%.'\n  )\n\n  -- - Should respect registered language for a filetype\n  child.lua('vim.treesitter.language.register(\"my_aaa\", \"aaa\")')\n  expect.error(\n    function() type_keys('sd', 'F', '<CR>') end,\n    '%(mini%.surround%) Can not get parser for buffer 1 and language \"my_aaa\"%.'\n  )\nend\n\n-- Integration tests ==========================================================\n-- Operators ------------------------------------------------------------------\nT['Add surrounding'] = new_set()\n\nT['Add surrounding']['works in Normal mode with dot-repeat'] = function()\n  validate_edit({ 'aaa' }, { 1, 0 }, { '(aaa)' }, { 1, 1 }, type_keys, 'sa', 'iw', ')')\n  validate_edit({ ' aaa ' }, { 1, 1 }, { ' (aaa) ' }, { 1, 2 }, type_keys, 'sa', 'iw', ')')\n\n  -- Allows immediate dot-repeat\n  type_keys('.')\n  eq(get_lines(), { ' ((aaa)) ' })\n  eq(get_cursor(), { 1, 3 })\n\n  -- Allows not immediate dot-repeat\n  set_lines({ 'aaa bbb' })\n  set_cursor(1, 5)\n  type_keys('.')\n  eq(get_lines(), { 'aaa (bbb)' })\nend\n\nT['Add surrounding']['works in Visual mode without dot-repeat'] = function()\n  -- Reset dot-repeat\n  set_lines({ ' aaa ' })\n  type_keys('dd')\n\n  validate_edit({ ' aaa ' }, { 1, 1 }, { ' (aaa) ' }, { 1, 2 }, type_keys, 'viw', 'sa', ')')\n  eq(child.fn.mode(), 'n')\n\n  -- Does not allow dot-repeat. Should do `dd`.\n  type_keys('.')\n  eq(get_lines(), { '' })\nend\n\nT['Add surrounding']['works in line and block Visual mode'] = function()\n  validate_edit({ 'aaa' }, { 1, 0 }, { '(aaa)' }, { 1, 1 }, type_keys, 'V', 'sa', ')')\n\n  validate_edit({ 'aaa', 'bbb' }, { 1, 0 }, { '(aaa', 'bbb)' }, { 1, 1 }, type_keys, '<C-v>j$', 'sa', ')')\nend\n\n--stylua: ignore\nT['Add surrounding']['respects `config.respect_selection_type` in linewise mode'] = function()\n  child.lua('MiniSurround.config.respect_selection_type = true')\n\n  local validate = function(before_lines, before_cursor, after_lines, after_cursor, selection_keys)\n    validate_edit(before_lines, before_cursor, after_lines, after_cursor, type_keys, selection_keys, 'sa', ')')\n  end\n\n  -- General test in Visual mode\n  validate({ 'aaa' }, { 1, 0 }, { '(', '\\taaa', ')' }, { 2, 1 }, 'V')\n\n  -- Correctly computes indentation\n  validate({ 'aaa',   ' bbb', '  ccc' }, { 2, 0 }, { 'aaa', ' (',      '\\t bbb', '\\t  ccc', ' )' },  { 3, 2 }, 'Vj')\n  validate({ ' aaa',  '',     ' bbb' },  { 1, 0 }, { ' (',  '\\t aaa',  '',       '\\t bbb',  ' )' },  { 2, 2 }, 'V2j')\n  validate({ '  aaa', ' ',    '  bbb' }, { 1, 0 }, { '  (', '\\t  aaa', '\\t ',    '\\t  bbb', '  )' }, { 2, 3 }, 'V2j')\n\n  -- Handles empty/blank lines\n  validate({ '  aaa', '', ' ', '  bbb' }, { 1, 0 }, { '  (', '\\t  aaa', '', '\\t ', '\\t  bbb', '  )' }, { 2, 3 }, 'V3j')\n\n  validate({ '',  '  aaa', '' },  { 1, 0 }, { '  (', '',    '\\t  aaa', '',    '  )' }, { 2, 0 }, 'V2j')\n  validate({ ' ', '  aaa', ' ' }, { 1, 0 }, { '  (', '\\t ', '\\t  aaa', '\\t ', '  )' }, { 2, 1 }, 'V2j')\n\n  -- Doesn't produce messages\n  validate({ 'aa', 'bb', 'cc' }, { 1, 0 }, { '(', '\\taa', '\\tbb', '\\tcc', ')' }, { 2, 1 }, 'Vip')\n  eq(child.cmd_capture('1messages'), '')\n\n  -- Works with different surroundings\n  validate_edit({ 'aaa' }, { 1, 0 }, { 'ff(', '\\taaa', ')' }, { 2, 1 }, type_keys, 'V', 'sa', 'f', 'ff<CR>')\n\n  -- General test in Operator-pending mode\n  validate_edit({ 'aaa' }, { 1, 0 }, { '(', '\\taaa', ')' }, { 2, 1 }, type_keys, 'sa', 'ip', ')')\n\n  -- Respects `expandtab`\n  child.o.expandtab = true\n  child.o.shiftwidth = 3\n  validate({ 'aaa' }, { 1, 0 }, { '(', '   aaa', ')' }, { 2, 3 }, 'V')\nend\n\n--stylua: ignore\nT['Add surrounding']['respects `config.respect_selection_type` in blockwise mode'] = function()\n  -- NOTE: this doesn't work with mix of multibyte and normal characters,\n  -- as well as outside of text lines.\n  child.lua('MiniSurround.config.respect_selection_type = true')\n\n  local validate = function(before_lines, before_cursor, after_lines, after_cursor, selection_keys)\n    validate_edit(before_lines, before_cursor, after_lines, after_cursor, type_keys, selection_keys, 'sa', ')')\n  end\n\n  -- General test in Visual mode\n  validate({ 'aaa', 'bbb' }, { 1, 1 }, { 'a(a)a', 'b(b)b' }, { 1, 2 }, '<C-v>j')\n  validate({ 'aaaa', 'bbbb' }, { 1, 1 }, { 'a(aa)a', 'b(bb)b' }, { 1, 2 }, '<C-v>jl')\n\n  -- Works on single line\n  validate({ 'aaaa' }, { 1, 1 }, { 'a(aa)a' }, { 1, 2 }, '<C-v>l')\n\n  -- Works when selection is created in different directions\n  validate({ 'aaaa', 'bbbb' }, { 1, 2 }, { 'a(aa)a', 'b(bb)b' }, { 1, 2 }, '<C-v>jh')\n  validate({ 'aaaa', 'bbbb' }, { 2, 1 }, { 'a(aa)a', 'b(bb)b' }, { 1, 2 }, '<C-v>kl')\n  validate({ 'aaaa', 'bbbb' }, { 2, 2 }, { 'a(aa)a', 'b(bb)b' }, { 1, 2 }, '<C-v>kh')\n\n  -- Works with different surroundings\n  validate_edit({ 'aaa', 'bbb' }, { 1, 1 }, { 'aff(a)a', 'bff(b)b' }, { 1, 4 }, type_keys, '<C-v>j', 'sa', 'f', 'ff<CR>')\n\n  -- General test in Operator-pending mode\n  set_lines({ 'aaaaa', 'bbbbb' })\n\n  -- - Create mark to be able to perform non-trivial movement\n  set_cursor(2, 3)\n  type_keys('ma')\n\n  set_cursor(1, 1)\n  type_keys('sa', '<C-v>', '`a', ')')\n  -- - As motion is end-exclusive, it registers end mark one column short.\n  eq(get_lines(), { 'a(aa)aa', 'b(bb)bb' })\n  eq(get_cursor(), { 1, 2 })\nend\n\nT['Add surrounding']['places cursor to the right of left surrounding'] = function()\n  local f = function(surrounding, visual_key)\n    if visual_key == nil then\n      type_keys('sa', surrounding)\n    else\n      type_keys(visual_key, surrounding, 'sa')\n    end\n    type_keys('f', 'myfunc', '<CR>')\n  end\n\n  -- Same line\n  validate_edit({ 'aaa' }, { 1, 0 }, { 'myfunc(aaa)' }, { 1, 7 }, f, 'iw')\n  validate_edit({ 'aaa' }, { 1, 0 }, { 'myfunc(aaa)' }, { 1, 7 }, f, 'iw', 'v')\n  validate_edit({ 'aaa' }, { 1, 0 }, { 'myfunc(aaa)' }, { 1, 7 }, f, '', 'V')\n\n  -- Not the same line\n  validate_edit({ 'aaa', 'bbb', 'ccc' }, { 2, 0 }, { 'myfunc(aaa', 'bbb', 'ccc)' }, { 1, 7 }, f, 'ip')\n  validate_edit({ 'aaa', 'bbb', 'ccc' }, { 2, 0 }, { 'myfunc(aaa', 'bbb', 'ccc)' }, { 1, 7 }, f, 'ip', 'v')\n  validate_edit({ 'aaa', 'bbb', 'ccc' }, { 2, 0 }, { 'myfunc(aaa', 'bbb', 'ccc)' }, { 1, 7 }, f, 'ip', 'V')\nend\n\nT['Add surrounding']['shows reminder after one idle second'] = function()\n  child.set_size(5, 70)\n  child.o.cmdheight = 1\n\n  set_lines({ ' aaa ' })\n  set_cursor(1, 1)\n\n  -- Execute one time to test if 'needs help message' flag is set per call\n  type_keys('sa', 'iw', ')')\n  sleep(0.1 * reminder_delay)\n\n  type_keys('sa', 'iw')\n  sleep(reminder_delay + small_time)\n\n  -- Should show helper message without adding it to `:messages` and causing\n  -- hit-enter-prompt\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\n\n  -- Should clear afterwards\n  type_keys(')')\n  child.expect_screenshot()\nend\n\nT['Add surrounding']['works with multibyte characters'] = function()\n  local f = function() type_keys('sa', 'iw', ')') end\n\n  validate_edit({ '  ыыы  ' }, { 1, 2 }, { '  (ыыы)  ' }, { 1, 3 }, f)\n  validate_edit({ 'ыыы ttt' }, { 1, 2 }, { '(ыыы) ttt' }, { 1, 1 }, f)\n  validate_edit({ 'ttt ыыы' }, { 1, 4 }, { 'ttt (ыыы)' }, { 1, 5 }, f)\n\n  -- Test 4-byte characters (might be a cause of incorrect marks retrieval)\n  validate_edit({ '🬗 🬗 🬗 🬗 🬗' }, { 1, 20 }, { '🬗 🬗 🬗 🬗 (🬗)' }, { 1, 21 }, f)\nend\n\nT['Add surrounding']['works on whole line'] = function()\n  -- Should ignore both indent (leading whitespace) at start line and trailing\n  -- whitespace and end line. Should work with both tabs and spaces.\n  validate_edit({ ' \\t aaa\\t ', '' }, { 1, 0 }, { ' \\t (aaa)\\t ', '' }, { 1, 4 }, type_keys, 'sa', '_', ')')\n  validate_edit({ ' \\t aaa\\t ', '' }, { 1, 0 }, { ' \\t (aaa)\\t ', '' }, { 1, 4 }, type_keys, 'V', 'sa', ')')\nend\n\nT['Add surrounding']['works on multiple lines'] = function()\n  local f = function() type_keys('sa', 'ap', ')') end\n  local f_vis = function() type_keys('Vap', 'sa', ')') end\n\n  -- Should ignore both indent (leading whitespace) at start line and trailing\n  -- whitespace and end line. Should work with both tabs and spaces.\n  validate_edit({ ' \\t aaa ', 'bbb', ' ccc\\t ' }, { 1, 0 }, { ' \\t (aaa ', 'bbb', ' ccc)\\t ' }, { 1, 4 }, f)\n  validate_edit({ ' \\t aaa ', 'bbb', ' ccc\\t ' }, { 1, 0 }, { ' \\t (aaa ', 'bbb', ' ccc)\\t ' }, { 1, 4 }, f_vis)\n  validate_edit({ ' \\t aaa ', '\\t ' }, { 1, 0 }, { ' \\t (aaa ', ')\\t ' }, { 1, 4 }, f)\n  validate_edit({ ' \\t aaa ', '\\t ' }, { 1, 0 }, { ' \\t (aaa ', ')\\t ' }, { 1, 4 }, f_vis)\nend\n\nT['Add surrounding']['works with multiline output surroundings'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    a = { output = { left = '\\n(\\n', right = '\\n)\\n' } }\n  }]])\n  local lines = { '  xxx' }\n  validate_edit(lines, { 1, 3 }, { '  ', '(', 'xxx', ')', '' }, { 1, 1 }, type_keys, 'sa', 'iw', 'a')\nend\n\nT['Add surrounding']['works when using $ motion'] = function()\n  -- It might not work because cursor column is outside of line width\n  validate_edit({ 'aaa' }, { 1, 0 }, { '(aaa)' }, { 1, 1 }, type_keys, 'sa', '$', ')')\n  validate_edit({ 'aaa' }, { 1, 0 }, { '(aaa)' }, { 1, 1 }, type_keys, 'v$', 'sa', ')')\nend\n\nT['Add surrounding']['allows cancelling with `<Esc> and <C-c>`'] = function()\n  local validate_cancel = function(key)\n    child.ensure_normal_mode()\n    set_lines({ ' aaa ' })\n    set_cursor(1, 1)\n\n    -- Cancel before surrounding\n    type_keys(1, 'sa', key)\n    eq(get_lines(), { ' aaa ' })\n    eq(get_cursor(), { 1, 1 })\n\n    -- Cancel before output surrounding\n    type_keys(1, 'sa', 'iw', key)\n    eq(get_lines(), { ' aaa ' })\n    eq(get_cursor(), { 1, 1 })\n  end\n\n  validate_cancel('<Esc>')\n  validate_cancel('<C-c>')\nend\n\nT['Add surrounding']['works with different mapping'] = function()\n  reload_module({ mappings = { add = 'SA' } })\n\n  validate_edit({ 'aaa' }, { 1, 0 }, { '(aaa)' }, { 1, 1 }, type_keys, 'SA', 'iw', ')')\n  child.api.nvim_del_keymap('n', 'SA')\nend\n\nT['Add surrounding']['respects two types of `[count]` in Normal mode'] = function()\n  validate_edit1d('aa bb cc dd', 0, '((aa ))bb cc dd', 2, type_keys, '2sa', 'aw', ')')\n  validate_edit1d('aa bb cc dd', 0, '(aa bb cc )dd', 1, type_keys, 'sa', '3aw', ')')\n  validate_edit1d('aa bb cc dd', 0, '((aa bb cc ))dd', 2, type_keys, '2sa', '3aw', ')')\n\n  -- Should work with dot-repeat\n  validate_edit1d('aa bb cc dd ee', 0, '((aa bb ))((cc dd ))ee', 12, type_keys, '2sa2aw)', 'fc', '.')\nend\n\nT['Add surrounding']['respects `[count]` in Visual mode'] = function()\n  validate_edit1d('aa bb cc dd', 0, '((aa ))bb cc dd', 2, type_keys, 'vaw', '2sa', ')')\n  validate_edit1d('aa bb cc dd', 0, '((aa bb cc ))dd', 2, type_keys, 'v3aw', '2sa', ')')\nend\n\nT['Add surrounding']['handles `[count]` cache'] = function()\n  set_lines({ 'aa bb' })\n  set_cursor(1, 0)\n\n  type_keys('2saiw)')\n  eq(get_lines(), { '((aa)) bb' })\n\n  set_cursor(1, 7)\n  type_keys('viw', 'sa)')\n  eq(get_lines(), { '((aa)) (bb)' })\nend\n\nT['Add surrounding']['works with `cmdheight=0`'] = function()\n  child.set_size(7, 20)\n  child.o.cmdheight = 0\n  child.o.statusline = 'My statusline'\n  set_lines({ 'aa bb' })\n  type_keys('sa')\n  child.expect_screenshot({ redraw = false })\n  type_keys('iw')\n  child.expect_screenshot({ redraw = false })\n  type_keys(')')\n  child.expect_screenshot({ redraw = false })\nend\n\nT['Add surrounding']['respects `selection=exclusive` option'] = function()\n  child.o.selection = 'exclusive'\n  local f = function() type_keys('v2l', 'sa', ')') end\n\n  -- Regular case\n  validate_edit({ ' aaa ' }, { 1, 1 }, { ' (aa)a ' }, { 1, 2 }, f)\n\n  -- Multibyte characters\n  validate_edit({ ' ыыы ' }, { 1, 1 }, { ' (ыы)ы ' }, { 1, 2 }, f)\nend\n\nT['Add surrounding']['respects `vim.{g,b}.minisurround_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisurround_disable = true\n\n    set_lines({ ' aaa ' })\n    set_cursor(1, 1)\n\n    -- It should ignore `sa` and start typing in Insert mode after `i`\n    type_keys('sa', 'iw', ')')\n    eq(get_lines(), { ' w)aaa ' })\n    eq(get_cursor(), { 1, 3 })\n  end,\n})\n\nT['Add surrounding']['respects `config.silent`'] = function()\n  child.lua('MiniSurround.config.silent = true')\n  child.set_size(10, 20)\n\n  set_lines({ ' aaa ' })\n  set_cursor(1, 1)\n\n  -- It should not show helper message after one idle second\n  type_keys('sa', 'iw')\n  sleep(reminder_delay + small_time)\n  child.expect_screenshot()\nend\n\nT['Add surrounding']['respects `vim.b.minisurround_config`'] = function()\n  child.b.minisurround_config = { custom_surroundings = { ['<'] = { output = { left = '>', right = '<' } } } }\n  validate_edit({ 'aaa' }, { 1, 1 }, { '>aaa<' }, { 1, 1 }, type_keys, 'sa', 'iw', '<')\nend\n\nT['Delete surrounding'] = new_set()\n\nT['Delete surrounding']['works with dot-repeat'] = function()\n  validate_edit({ '(aaa)' }, { 1, 0 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', ')')\n  validate_edit({ '(aaa)' }, { 1, 4 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', ')')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', ')')\n\n  -- Allows immediate dot-repeat\n  set_lines({ '((aaa))' })\n  set_cursor(1, 2)\n  type_keys('sd', ')')\n  type_keys('.')\n  eq(get_lines(), { 'aaa' })\n  eq(get_cursor(), { 1, 0 })\n\n  -- Allows not immediate dot-repeat\n  set_lines({ 'aaa (bbb)' })\n  set_cursor(1, 5)\n  type_keys('.')\n  eq(get_lines(), { 'aaa bbb' })\nend\n\n--stylua: ignore\nT['Delete surrounding']['respects `config.respect_selection_type` in linewise mode'] = function()\n  child.lua('MiniSurround.config.respect_selection_type = true')\n\n  local validate = function(before_lines, before_cursor, after_lines, after_cursor)\n    validate_edit(before_lines, before_cursor, after_lines, after_cursor, type_keys, 'sd', ')')\n  end\n\n  -- General test\n  validate({ '(', '\\taaa', ')' }, { 2, 0 }, { 'aaa' }, { 1, 0 })\n\n  -- Works when cursor is on any part of region\n  validate({ '(', '\\taaa', ')' }, { 1, 0 }, { 'aaa' }, { 1, 0 })\n  validate({ '(', '\\taaa', ')' }, { 3, 0 }, { 'aaa' }, { 1, 0 })\n\n  -- Correctly applies when it should\n  validate({ '(',   '\\t\\taaa', '\\tbbb', ')' },   { 2, 2 }, { '\\taaa', 'bbb' }, { 1, 1 })\n  validate({ '  (', '\\t\\taaa', '\\tbbb', ')  ' }, { 2, 2 }, { '\\taaa', 'bbb' }, { 1, 1 })\n\n  -- Correctly doesn't apply when it shouldn't\n  validate({ 'aaa',  '  ()  ', 'bbb' },  { 2, 2 }, { 'aaa', '    ',  'bbb' }, { 2, 2 })\n  validate({ 'aaa(', '\\tbbb',  ')' },    { 2, 2 }, { 'aaa', '\\tbbb', '' },    { 1, 2 })\n  validate({ '(',    '\\tbbb',  ')ccc' }, { 2, 2 }, { '',    '\\tbbb', 'ccc' }, { 1, 0 })\n\n  -- Correctly dedents\n  validate({ '(', 'aaa', ')' }, { 2, 0 }, { 'aaa' }, { 1, 0 })\n\n  -- Doesn't produce messages\n  validate({ '(', '\\taa', '\\tbb', '\\tcc', ')' }, { 2, 1 }, { 'aa', 'bb', 'cc' }, { 1, 0 })\n  eq(child.cmd_capture('1messages'), '')\n\n  child.o.shiftwidth = 3\n  validate({ '(', '    aaa', ')' }, { 2, 0 }, { ' aaa' }, { 1, 1 })\n\n  child.o.expandtab = true\n  validate({ '(', '    aaa', ')' }, { 2, 0 }, { ' aaa' }, { 1, 1 })\nend\n\nT['Delete surrounding']['works in extended mappings'] = function()\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) bb (cc)', 5, type_keys, 'sdn', ')')\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) (bb) cc', 10, type_keys, '2sdn', ')')\n\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) bb (cc)', 5, type_keys, 'sdl', ')')\n  validate_edit1d('(aa) (bb) (cc)', 11, 'aa (bb) (cc)', 0, type_keys, '2sdl', ')')\n\n  -- Dot-repeat\n  set_lines({ '(aa) (bb) (cc)' })\n  set_cursor(1, 0)\n  type_keys('sdn', ')')\n  type_keys('.')\n  eq(get_lines(), { '(aa) bb cc' })\n  eq(get_cursor(), { 1, 8 })\nend\n\nT['Delete surrounding']['respects `config.n_lines`'] = function()\n  reload_module({ n_lines = 2 })\n  local lines = { '(', '', '', 'a', '', '', ')' }\n  validate_edit(lines, { 4, 0 }, lines, { 4, 0 }, type_keys, 'sd', ')')\n  has_message_about_not_found(')', 2)\n\n  -- Should also use buffer local config\n  child.b.minisurround_config = { n_lines = 10 }\n  validate_edit(lines, { 4, 0 }, { '', '', '', 'a', '', '', '' }, { 1, 0 }, type_keys, 'sd', ')')\nend\n\nT['Delete surrounding']['respects `config.search_method`'] = function()\n  local lines = { 'aaa (bbb)' }\n\n  -- By default uses 'cover'\n  validate_edit(lines, { 1, 0 }, lines, { 1, 0 }, type_keys, 'sd', ')')\n  has_message_about_not_found(')')\n\n  -- Should change behavior according to `config.search_method`\n  reload_module({ search_method = 'cover_or_next' })\n  validate_edit(lines, { 1, 0 }, { 'aaa bbb' }, { 1, 4 }, type_keys, 'sd', ')')\n\n  -- Should also use buffer local config\n  child.b.minisurround_config = { search_method = 'cover' }\n  validate_edit(lines, { 1, 0 }, lines, { 1, 0 }, type_keys, 'sd', ')')\nend\n\nT['Delete surrounding']['places cursor to the right of left surrounding'] = function()\n  local f = function() type_keys('sd', 'f') end\n\n  -- Same line\n  validate_edit({ 'myfunc(aaa)' }, { 1, 7 }, { 'aaa' }, { 1, 0 }, f)\n\n  -- Not the same line\n  validate_edit({ 'myfunc(aaa', 'bbb', 'ccc)' }, { 1, 8 }, { 'aaa', 'bbb', 'ccc' }, { 1, 0 }, f)\n  validate_edit({ 'myfunc(aaa', 'bbb', 'ccc)' }, { 2, 0 }, { 'aaa', 'bbb', 'ccc' }, { 1, 0 }, f)\n  validate_edit({ 'myfunc(aaa', 'bbb', 'ccc)' }, { 3, 2 }, { 'aaa', 'bbb', 'ccc' }, { 1, 0 }, f)\nend\n\nT['Delete surrounding']['shows reminder after one idle second'] = function()\n  child.set_size(5, 70)\n  child.o.cmdheight = 1\n\n  -- Mapping is applied only after `timeoutlen` milliseconds, because\n  -- there are `sdn`/`sdl` mappings. Wait 1000 seconds after that.\n  child.o.timeoutlen = 5 * small_time\n  local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n  set_lines({ '((aaa))' })\n  set_cursor(1, 1)\n\n  -- Execute one time to test if 'needs help message' flag is set per call\n  type_keys('sd', ')')\n  sleep(0.1 * reminder_delay)\n\n  type_keys('sd')\n  sleep(total_wait_time)\n\n  -- Should show helper message without adding it to `:messages` and causing\n  -- hit-enter-prompt\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\n\n  -- Should clear afterwards\n  type_keys(')')\n  child.expect_screenshot()\nend\n\nT['Delete surrounding']['handles special characters in \"not found\" message'] = function()\n  type_keys('sd', '\\t')\n  has_message_about_not_found('\\t')\n  type_keys('sd', '<C-j>')\n  has_message_about_not_found('\\n')\nend\n\nT['Delete surrounding']['works with multibyte characters'] = function()\n  local f = function() type_keys('sd', ')') end\n\n  validate_edit({ '  (ыыы)  ' }, { 1, 3 }, { '  ыыы  ' }, { 1, 2 }, f)\n  validate_edit({ '(ыыы) ttt' }, { 1, 1 }, { 'ыыы ttt' }, { 1, 0 }, f)\n  validate_edit({ 'ttt (ыыы)' }, { 1, 5 }, { 'ttt ыыы' }, { 1, 4 }, f)\nend\n\nT['Delete surrounding']['works on multiple lines'] = function()\n  local f = function() type_keys('sd', ')') end\n\n  validate_edit({ '(aaa', 'bbb', 'ccc)' }, { 1, 3 }, { 'aaa', 'bbb', 'ccc' }, { 1, 0 }, f)\n  validate_edit({ '(aaa', 'bbb', 'ccc)' }, { 2, 0 }, { 'aaa', 'bbb', 'ccc' }, { 1, 0 }, f)\nend\n\nT['Delete surrounding']['works with multiline input surroundings'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    a = { input = { '%(\\na().-()a\\n%)' } },\n    b = { input = { '%(\\n().-()\\n%)' } },\n    c = { input = { '\\na().-()a\\n' } },\n    d = { input = { '\\n().-()\\n' } },\n  }]])\n  local lines = { 'xxx(', 'aaa', ')xxx' }\n  local f\n\n  f = function() type_keys('sd', 'a') end\n  validate_edit(lines, { 1, 3 }, { 'xxxaxxx' }, { 1, 3 }, f)\n  validate_edit(lines, { 2, 1 }, { 'xxxaxxx' }, { 1, 3 }, f)\n  validate_edit(lines, { 3, 0 }, { 'xxxaxxx' }, { 1, 3 }, f)\n\n  f = function() type_keys('sd', 'b') end\n  validate_edit(lines, { 1, 3 }, { 'xxxaaaxxx' }, { 1, 3 }, f)\n  validate_edit(lines, { 2, 1 }, { 'xxxaaaxxx' }, { 1, 3 }, f)\n  validate_edit(lines, { 3, 0 }, { 'xxxaaaxxx' }, { 1, 3 }, f)\n\n  f = function() type_keys('sd', 'c') end\n  -- No case for first line because there is no covering match\n  validate_edit(lines, { 2, 1 }, { 'xxx(a)xxx' }, { 1, 4 }, f)\n  -- No case for third line because there is no covering match\n\n  f = function() type_keys('sd', 'd') end\n  -- No case for first line because there is no covering match\n  validate_edit(lines, { 2, 1 }, { 'xxx(aaa)xxx' }, { 1, 4 }, f)\n  -- There is a `\\n` at the end of last line, so it is matched\n  validate_edit(lines, { 3, 0 }, { 'xxx(', 'aaa)xxx' }, { 2, 3 }, f)\nend\n\nT['Delete surrounding']['allows cancelling with `<Esc> and <C-c>`'] = function()\n  local validate_cancel = function(key)\n    child.ensure_normal_mode()\n    set_lines({ '<aaa>' })\n    set_cursor(1, 1)\n\n    type_keys(1, 'sd', key)\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n  end\n\n  validate_cancel('<Esc>')\n  validate_cancel('<C-c>')\nend\n\nT['Delete surrounding']['works with different mapping'] = function()\n  reload_module({ mappings = { delete = 'SD' } })\n\n  validate_edit({ '(aaa)' }, { 1, 1 }, { 'aaa' }, { 1, 0 }, type_keys, 'SD', ')')\n  child.api.nvim_del_keymap('n', 'SD')\nend\n\nT['Delete surrounding']['respects `v:count` for input surrounding'] = function()\n  validate_edit({ '(a(b(c)b)a)' }, { 1, 5 }, { '(ab(c)ba)' }, { 1, 2 }, type_keys, '2sd', ')')\n\n  -- Should give informative message on failure\n  validate_edit({ '(a)' }, { 1, 0 }, { '(a)' }, { 1, 0 }, type_keys, '2sd', ')')\n  has_message_about_not_found(')', nil, nil, 2)\n\n  -- Should respect search method\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  validate_edit({ '(aa) (bb) (cc)' }, { 1, 1 }, { '(aa) bb (cc)' }, { 1, 5 }, type_keys, '2sd', ')')\nend\n\nT['Delete surrounding']['respects `vim.{g,b}.minisurround_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisurround_disable = true\n\n    set_lines({ '<aaa>' })\n    set_cursor(1, 1)\n\n    -- It should ignore `sd`\n    type_keys('sd', '>')\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n  end,\n})\n\nT['Delete surrounding']['respects `config.silent`'] = function()\n  child.lua('MiniSurround.config.silent = true')\n  child.set_size(10, 20)\n\n  child.o.timeoutlen = 5 * small_time\n  local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n  set_lines({ '<aaa>' })\n  set_cursor(1, 1)\n\n  -- It should not show helper message after one idle second\n  type_keys('sd')\n  sleep(total_wait_time)\n  child.expect_screenshot()\n\n  -- It should not show message about \"No surrounding found\"\n  type_keys(')')\n  child.expect_screenshot()\nend\n\nT['Delete surrounding']['respects `vim.b.minisurround_config`'] = function()\n  child.b.minisurround_config = { custom_surroundings = { ['<'] = { input = { '>().-()<' } } } }\n  validate_edit({ '>aaa<' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', '<')\nend\n\nT['Replace surrounding'] = new_set()\n\n-- NOTE: use `>` for replacement because it itself is not a blocking key.\n-- Like if you type `}` or `]`, Neovim will have to wait for the next key,\n-- which blocks `child`.\nT['Replace surrounding']['works with dot-repeat'] = function()\n  validate_edit({ '(aaa)' }, { 1, 0 }, { '<aaa>' }, { 1, 1 }, type_keys, 'sr', ')', '>')\n  validate_edit({ '(aaa)' }, { 1, 4 }, { '<aaa>' }, { 1, 1 }, type_keys, 'sr', ')', '>')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '<aaa>' }, { 1, 1 }, type_keys, 'sr', ')', '>')\n\n  -- Allows immediate dot-repeat\n  set_lines({ '((aaa))' })\n  set_cursor(1, 2)\n  type_keys('sr', ')', '>')\n  type_keys('.')\n  eq(get_lines(), { '<<aaa>>' })\n  eq(get_cursor(), { 1, 1 })\n\n  -- Allows not immediate dot-repeat\n  set_lines({ 'aaa (bbb)' })\n  set_cursor(1, 5)\n  type_keys('.')\n  eq(get_lines(), { 'aaa <bbb>' })\nend\n\nT['Replace surrounding']['works in extended mappings'] = function()\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) <bb> (cc)', 6, type_keys, 'srn', ')', '>')\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) (bb) <cc>', 11, type_keys, '2srn', ')', '>')\n\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) <bb> (cc)', 6, type_keys, 'srl', ')', '>')\n  validate_edit1d('(aa) (bb) (cc)', 11, '<aa> (bb) (cc)', 1, type_keys, '2srl', ')', '>')\n\n  -- Dot-repeat\n  set_lines({ '(aa) (bb) (cc)' })\n  set_cursor(1, 0)\n  type_keys('srn', ')', '>')\n  type_keys('.')\n  eq(get_lines(), { '(aa) <bb> <cc>' })\n  eq(get_cursor(), { 1, 11 })\nend\n\nT['Replace surrounding']['respects `config.n_lines`'] = function()\n  reload_module({ n_lines = 2 })\n  local lines = { '(', '', '', 'a', '', '', ')' }\n  validate_edit(lines, { 4, 0 }, lines, { 4, 0 }, type_keys, 'sr', ')', '>')\n  has_message_about_not_found(')', 2)\n\n  -- Should also use buffer local config\n  child.b.minisurround_config = { n_lines = 10 }\n  validate_edit(lines, { 4, 0 }, { '<', '', '', 'a', '', '', '>' }, { 1, 0 }, type_keys, 'sr', ')', '>')\nend\n\nT['Replace surrounding']['respects `config.search_method`'] = function()\n  local lines = { 'aaa (bbb)' }\n\n  -- By default uses 'cover'\n  validate_edit(lines, { 1, 0 }, lines, { 1, 0 }, type_keys, 'sr', ')', '>')\n  has_message_about_not_found(')')\n\n  -- Should change behavior according to `config.search_method`\n  reload_module({ search_method = 'cover_or_next' })\n  validate_edit(lines, { 1, 0 }, { 'aaa <bbb>' }, { 1, 5 }, type_keys, 'sr', ')', '>')\n\n  -- Should also use buffer local config\n  child.b.minisurround_config = { search_method = 'cover' }\n  validate_edit(lines, { 1, 0 }, lines, { 1, 0 }, type_keys, 'sr', ')', '>')\nend\n\nT['Replace surrounding']['places cursor to the right of left surrounding'] = function()\n  local f = function() type_keys('sr', 'f', '>') end\n\n  -- Same line\n  validate_edit({ 'myfunc(aaa)' }, { 1, 7 }, { '<aaa>' }, { 1, 1 }, f)\n\n  -- Not the same line\n  validate_edit({ 'myfunc(aaa', 'bbb', 'ccc)' }, { 1, 8 }, { '<aaa', 'bbb', 'ccc>' }, { 1, 1 }, f)\n  validate_edit({ 'myfunc(aaa', 'bbb', 'ccc)' }, { 2, 0 }, { '<aaa', 'bbb', 'ccc>' }, { 1, 1 }, f)\n  validate_edit({ 'myfunc(aaa', 'bbb', 'ccc)' }, { 3, 2 }, { '<aaa', 'bbb', 'ccc>' }, { 1, 1 }, f)\nend\n\nT['Replace surrounding']['shows reminder after one idle second'] = function()\n  child.set_size(5, 70)\n  child.o.cmdheight = 1\n\n  -- Mapping is applied only after `timeoutlen` milliseconds, because\n  -- there are `srn`/`srl` mappings. Wait 1000 seconds after that.\n  child.o.timeoutlen = 5 * small_time\n  local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n  set_lines({ '((aaa))' })\n  set_cursor(1, 1)\n\n  -- Execute one time to test if 'needs help message' flag is set per call\n  type_keys('sr', ')', '>')\n  sleep(0.1 * reminder_delay)\n\n  type_keys('sr')\n  sleep(total_wait_time)\n\n  -- Should show helper message without adding it to `:messages` and causing\n  -- hit-enter-prompt\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\n\n  clear_messages()\n  type_keys(')')\n\n  -- Here mapping collision doesn't matter any more\n  sleep(reminder_delay + small_time)\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\n\n  -- Should clear afterwards\n  type_keys('>')\n  child.expect_screenshot()\nend\n\nT['Replace surrounding']['handles special characters in \"not found\" message'] = function()\n  type_keys('sr', '\\t', ')')\n  has_message_about_not_found('\\t')\n  type_keys('sr', '<C-j>', ')')\n  has_message_about_not_found('\\n')\nend\n\nT['Replace surrounding']['works with multibyte characters'] = function()\n  local f = function() type_keys('sr', ')', '>') end\n\n  validate_edit({ '  (ыыы)  ' }, { 1, 3 }, { '  <ыыы>  ' }, { 1, 3 }, f)\n  validate_edit({ '(ыыы) ttt' }, { 1, 1 }, { '<ыыы> ttt' }, { 1, 1 }, f)\n  validate_edit({ 'ttt (ыыы)' }, { 1, 5 }, { 'ttt <ыыы>' }, { 1, 5 }, f)\nend\n\nT['Replace surrounding']['works on multiple lines'] = function()\n  local f = function() type_keys('sr', ')', '>') end\n\n  validate_edit({ '(aaa', 'bbb', 'ccc)' }, { 1, 3 }, { '<aaa', 'bbb', 'ccc>' }, { 1, 1 }, f)\n  validate_edit({ '(aaa', 'bbb', 'ccc)' }, { 2, 0 }, { '<aaa', 'bbb', 'ccc>' }, { 1, 1 }, f)\nend\n\nT['Replace surrounding']['works with multiline input surroundings'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    a = { input = { '%(\\na().-()a\\n%)' } },\n    b = { input = { '%(\\n().-()\\n%)' } },\n    c = { input = { '\\na().-()a\\n' } },\n    d = { input = { '\\n().-()\\n' } },\n  }]])\n  local lines = { 'xxx(', 'aaa', ')xxx' }\n  local f\n\n  f = function() type_keys('sr', 'a', '>') end\n  validate_edit(lines, { 1, 3 }, { 'xxx<a>xxx' }, { 1, 4 }, f)\n  validate_edit(lines, { 2, 1 }, { 'xxx<a>xxx' }, { 1, 4 }, f)\n  validate_edit(lines, { 3, 0 }, { 'xxx<a>xxx' }, { 1, 4 }, f)\n\n  f = function() type_keys('sr', 'b', '>') end\n  validate_edit(lines, { 1, 3 }, { 'xxx<aaa>xxx' }, { 1, 4 }, f)\n  validate_edit(lines, { 2, 1 }, { 'xxx<aaa>xxx' }, { 1, 4 }, f)\n  validate_edit(lines, { 3, 0 }, { 'xxx<aaa>xxx' }, { 1, 4 }, f)\n\n  f = function() type_keys('sr', 'c', '>') end\n  -- No case for first line because there is no covering match\n  validate_edit(lines, { 2, 1 }, { 'xxx(<a>)xxx' }, { 1, 5 }, f)\n  -- No case for third line because there is no covering match\n\n  f = function() type_keys('sr', 'd', '>') end\n  -- No case for first line because there is no covering match\n  validate_edit(lines, { 2, 1 }, { 'xxx(<aaa>)xxx' }, { 1, 5 }, f)\n  -- There is a `\\n` at the end of last line. It is matched but can't be replaced.\n  validate_edit(lines, { 3, 0 }, { 'xxx(', 'aaa<)xxx' }, { 2, 4 }, f)\nend\n\nT['Replace surrounding']['works with multiline output surroundings'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    a = { output = { left = '\\n(\\n', right = '\\n)\\n' } }\n  }]])\n  local lines = { '  [xxx]' }\n  validate_edit(lines, { 1, 3 }, { '  ', '(', 'xxx', ')', '' }, { 1, 1 }, type_keys, 'sr', ']', 'a')\nend\n\nT['Replace surrounding']['allows cancelling with `<Esc> and <C-c>`'] = function()\n  local validate_cancel = function(key)\n    child.ensure_normal_mode()\n    set_lines({ '<aaa>' })\n    set_cursor(1, 1)\n\n    -- Cancel before input surrounding\n    type_keys(1, 'sr', key)\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n\n    -- Cancel before output surrounding\n    type_keys(1, 'sr', '>', key)\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n  end\n\n  validate_cancel('<Esc>')\n  validate_cancel('<C-c>')\nend\n\nT['Replace surrounding']['works with different mapping'] = function()\n  reload_module({ mappings = { replace = 'SR' } })\n\n  validate_edit({ '(aaa)' }, { 1, 1 }, { '<aaa>' }, { 1, 1 }, type_keys, 'SR', ')', '>')\n  child.api.nvim_del_keymap('n', 'SR')\nend\n\nT['Replace surrounding']['respects `v:count` for input surrounding'] = function()\n  validate_edit({ '(a(b(c)b)a)' }, { 1, 5 }, { '(a<b(c)b>a)' }, { 1, 3 }, type_keys, '2sr', ')', '>')\n\n  -- Should give informative message on failure\n  validate_edit({ '(a)' }, { 1, 0 }, { '(a)' }, { 1, 0 }, type_keys, '2sr', ')', '>')\n  has_message_about_not_found(')', nil, nil, 2)\n\n  -- Should respect search method\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  validate_edit({ '(aa) (bb) (cc)' }, { 1, 1 }, { '(aa) <bb> (cc)' }, { 1, 6 }, type_keys, '2sr', ')', '>')\nend\n\nT['Replace surrounding']['respects `vim.{g,b}.minisurround_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisurround_disable = true\n\n    set_lines({ '<aaa>' })\n    set_cursor(1, 1)\n\n    -- It should ignore `sr`\n    type_keys('sr', '>', '\"')\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n  end,\n})\n\nT['Replace surrounding']['respects `config.silent`'] = function()\n  child.lua('MiniSurround.config.silent = true')\n  child.set_size(10, 20)\n\n  child.o.timeoutlen = 5 * small_time\n  local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n  set_lines({ '<aaa>' })\n  set_cursor(1, 1)\n\n  -- It should not show helper message after one idle second\n  type_keys('sr')\n  sleep(total_wait_time)\n  child.expect_screenshot()\n\n  -- It should not show message about \"No surrounding found\"\n  type_keys(')')\n  child.expect_screenshot()\nend\n\nT['Replace surrounding']['respects `vim.b.minisurround_config`'] = function()\n  child.b.minisurround_config = { custom_surroundings = { ['<'] = { output = { left = '>', right = '<' } } } }\n  validate_edit({ '<aaa>' }, { 1, 2 }, { '>aaa<' }, { 1, 1 }, type_keys, 'sr', '>', '<')\nend\n\nT['Find surrounding'] = new_set()\n\n-- NOTE: most tests are done for `sf` ('find right') in hope that `sF` ('find\n-- left') is implemented similarly\nT['Find surrounding']['works without dot-repeat'] = function()\n  validate_find({ '(aaa)' }, { 1, 0 }, { { 1, 4 }, { 1, 0 }, { 1, 4 } }, type_keys, 'sf', ')')\n  validate_find({ '(aaa)' }, { 1, 2 }, { { 1, 4 }, { 1, 0 }, { 1, 4 } }, type_keys, 'sf', ')')\n  validate_find({ '(aaa)' }, { 1, 4 }, { { 1, 0 }, { 1, 4 }, { 1, 0 } }, type_keys, 'sf', ')')\n\n  -- Does not override dot-repeat\n  set_lines({ '(aaa)' })\n  set_cursor(1, 0)\n  type_keys('r]', 'u') -- dot-repeatable action\n  set_cursor(1, 2)\n  type_keys('sf', ')')\n  type_keys('.')\n  eq(get_lines(), { '(aaa]' })\n  eq(get_cursor(), { 1, 4 })\nend\n\nT['Find surrounding']['works in left direction without dot-repeat'] = function()\n  validate_find({ '(aaa)' }, { 1, 0 }, { { 1, 4 }, { 1, 0 }, { 1, 4 } }, type_keys, 'sF', ')')\n  validate_find({ '(aaa)' }, { 1, 4 }, { { 1, 0 }, { 1, 4 }, { 1, 0 } }, type_keys, 'sF', ')')\n  validate_find({ '(aaa)' }, { 1, 2 }, { { 1, 0 }, { 1, 4 }, { 1, 0 } }, type_keys, 'sF', ')')\n\n  -- Does not override dot-repeat\n  set_lines({ '(aaa)' })\n  set_cursor(1, 0)\n  type_keys('r[', 'u') -- dot-repeatable action\n  set_cursor(1, 2)\n  type_keys('sF', ')')\n  type_keys('.')\n  eq(get_lines(), { '[aaa)' })\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Find surrounding']['works with \"non single character\" surroundings'] = function()\n  --stylua: ignore start\n  -- Cursor is strictly inside surroundings\n  validate_find({ 'myfunc(aaa)' }, { 1, 9 }, { {1,10}, {1,0}, {1,6}, {1,10} }, type_keys, 'sf', 'f')\n  validate_find({ '<t>aaa</t>' }, { 1, 4 }, { {1,6}, {1,9}, {1,0}, {1,2}, {1,6} }, type_keys, 'sf', 't')\n  validate_find({ '_aaa*^' }, { 1, 2 }, { {1,4}, {1,5}, {1,0}, {1,4} }, type_keys, 'sf', '?', '_<CR>', '*^<CR>')\n\n  -- Cursor is inside one of the surrounding parts\n  validate_find({ 'myfunc(aaa)' }, { 1, 2 }, { {1,6}, {1,10}, {1,0}, {1,6} }, type_keys, 'sf', 'f')\n  validate_find({ '<t>aaa</t>' }, { 1, 1 }, { {1,2}, {1,6}, {1,9}, {1,0}, {1,2} }, type_keys, 'sf', 't')\n  validate_find({ '_aaa*^' }, { 1, 4 }, { {1,5}, {1,0}, {1,4}, {1,5} }, type_keys, 'sf', '?', '_<CR>', '*^<CR>')\n\n  -- Moving in left direction\n  validate_find({ 'myfunc(aaa)' }, { 1, 8 }, { {1,6}, {1,0}, {1,10}, {1,6} }, type_keys, 'sF', 'f')\n  validate_find({ '<t>aaa</t>' }, { 1, 4 }, { {1,2}, {1,0}, {1,9}, {1,6}, {1,2} }, type_keys, 'sF', 't')\n  validate_find({ '_aaa*^' }, { 1, 2 }, { {1,0}, {1,5}, {1,4}, {1,0} }, type_keys, 'sF', '?', '_<CR>', '*^<CR>')\n  --stylua: ignore end\nend\n\nT['Find surrounding']['works in extended mappings'] = function()\n  -- \"Find right\" when outside of outer surroundings puts cursor on left-most\n  -- position. If cursor is on the left, that is obvious. When on the right -\n  -- it behaves as on the right-most surrounding position.\n  -- \"Find left\" puts on right-most position for the same reasons.\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) (bb) (cc)', 5, type_keys, 'sfn', ')')\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) (bb) (cc)', 10, type_keys, '2sfn', ')')\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) (bb) (cc)', 8, type_keys, 'sFn', ')')\n  validate_edit1d('(aa) (bb) (cc)', 1, '(aa) (bb) (cc)', 13, type_keys, '2sFn', ')')\n\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) (bb) (cc)', 5, type_keys, 'sfl', ')')\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) (bb) (cc)', 0, type_keys, '2sfl', ')')\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) (bb) (cc)', 8, type_keys, 'sFl', ')')\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) (bb) (cc)', 3, type_keys, '2sFl', ')')\n\n  -- Does not override dot-repeat\n  set_lines({ '(aa) (bb) (cc)' })\n  set_cursor(1, 0)\n  type_keys('r[', 'u') -- dot-repeatable action\n  type_keys('sfn', ')')\n  type_keys('.')\n  eq(get_lines(), { '(aa) [bb) (cc)' })\n  eq(get_cursor(), { 1, 5 })\nend\n\nT['Find surrounding']['works in Visual mode'] = function()\n  local validate = function(line, before_column, after_column, keys)\n    set_lines({ line })\n    set_cursor(1, before_column)\n\n    type_keys('v', keys)\n    eq(get_cursor(), { 1, after_column })\n    eq(child.fn.col('v'), before_column + 1)\n    eq(child.fn.mode(), 'v')\n\n    child.ensure_normal_mode()\n  end\n\n  validate('(aa) (bb) (cc)', 1, 3, 'sf(')\n  validate('(aa) (bb) (cc)', 1, 5, 'sfn(')\n  validate('(aa) (bb) (cc)', 1, 10, '2sfn(')\n  validate('(aa) (bb) (cc)', 11, 5, 'sfl(')\n  validate('(aa) (bb) (cc)', 11, 0, '2sfl(')\n\n  validate('(aa) (bb) (cc)', 2, 0, 'sF)')\n  validate('(aa) (bb) (cc)', 2, 8, 'sFn)')\n  validate('(aa) (bb) (cc)', 2, 13, '2sFn)')\n  validate('(aa) (bb) (cc)', 11, 8, 'sFl)')\n  validate('(aa) (bb) (cc)', 11, 3, '2sFl)')\nend\n\nT['Find surrounding']['works in Operator-pending mode'] = function()\n  validate_edit1d('(aa) (bb) (cc)', 1, '() (bb) (cc)', 1, type_keys, 'dsf(')\n  validate_edit1d('(aa) (bb) (cc)', 1, '((bb) (cc)', 1, type_keys, 'dsfn(')\n  validate_edit1d('(aa) (bb) (cc)', 1, '((cc)', 1, type_keys, 'd2sfn(')\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) cc)', 5, type_keys, 'dsfl(')\n  validate_edit1d('(aa) (bb) (cc)', 11, 'cc)', 0, type_keys, 'd2sfl(')\n\n  validate_edit1d('(aa) (bb) (cc)', 2, 'a) (bb) (cc)', 0, type_keys, 'dsF)')\n  validate_edit1d('(aa) (bb) (cc)', 2, '(a) (cc)', 2, type_keys, 'dsFn)')\n  validate_edit1d('(aa) (bb) (cc)', 2, '(a)', 2, type_keys, 'd2sFn)')\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aa) (bbcc)', 8, type_keys, 'dsFl(')\n  validate_edit1d('(aa) (bb) (cc)', 11, '(aacc)', 3, type_keys, 'd2sFl(')\n\n  -- Works with dot-repeat\n  local validate_dot = function(before_line, column_1, keys, column_2, after_line)\n    set_lines({ before_line })\n    set_cursor(1, column_1)\n    type_keys('d', keys)\n    set_cursor(1, column_2)\n    type_keys('.')\n    eq(get_lines(), { after_line })\n  end\n\n  validate_dot('(aa) (bb) (cc)', 1, 'sf(', 4, '() () (cc)')\n  validate_dot('(aa) (bb) (cc)', 1, 'sfn(', 2, '(((cc)')\n  validate_dot('(aa) (bb) (cc)', 11, 'sfl(', 5, 'cc)')\n\n  validate_dot('(aa) (bb) (cc)', 2, 'sF(', 5, 'a) b) (cc)')\n  validate_dot('(aa) (bb) (cc)', 2, 'sFn(', 2, '(a)')\n  validate_dot('(aa) (bb) (cc)', 11, 'sFl(', 8, '(aacc)')\nend\n\nT['Find surrounding']['respects `config.n_lines`'] = function()\n  reload_module({ n_lines = 2 })\n  local lines = { '(', '', '', 'a', '', '', ')' }\n  validate_find(lines, { 4, 0 }, { { 4, 0 } }, type_keys, 'sf', ')')\n  has_message_about_not_found(')', 2)\n\n  -- Should also use buffer local config\n  child.b.minisurround_config = { n_lines = 10 }\n  validate_find(lines, { 4, 0 }, { { 7, 0 } }, type_keys, 'sf', ')')\nend\n\nT['Find surrounding']['respects `config.search_method`'] = function()\n  local lines = { 'aaa (bbb)' }\n\n  -- By default uses 'cover'\n  validate_find(lines, { 1, 0 }, { { 1, 0 } }, type_keys, 'sf', ')')\n  has_message_about_not_found(')')\n\n  clear_messages()\n  validate_find(lines, { 1, 0 }, { { 1, 0 } }, type_keys, 'sF', ')')\n  has_message_about_not_found(')')\n\n  -- Should change behavior according to `config.search_method`\n  reload_module({ search_method = 'cover_or_next' })\n  validate_find(lines, { 1, 0 }, { { 1, 4 } }, type_keys, 'sf', ')')\n  validate_find(lines, { 1, 0 }, { { 1, 8 } }, type_keys, 'sF', ')')\n\n  -- Should also use buffer local config\n  child.b.minisurround_config = { search_method = 'cover' }\n  validate_find(lines, { 1, 0 }, { { 1, 0 } }, type_keys, 'sf', ')')\nend\n\nT['Find surrounding']['shows reminder after one idle second'] = function()\n  child.set_size(5, 70)\n  child.o.cmdheight = 1\n\n  -- Mapping is applied only after `timeoutlen` milliseconds, because\n  -- there are `sfn`/`sfl` mappings. Wait 1000 seconds after that.\n  child.o.timeoutlen = 5 * small_time\n  local total_wait_time = reminder_delay + child.o.timeoutlen + small_time\n\n  set_lines({ '(aaa)' })\n  set_cursor(1, 2)\n\n  -- Execute one time to test if 'needs help message' flag is set per call\n  type_keys('sf', ')')\n  sleep(0.1 * reminder_delay)\n\n  type_keys('sf')\n  sleep(total_wait_time)\n\n  -- Should show helper message without adding it to `:messages` and causing\n  -- hit-enter-prompt\n  eq(get_latest_message(), '')\n  child.expect_screenshot()\n\n  -- Should clear afterwards\n  type_keys(')')\n  child.expect_screenshot()\nend\n\nT['Find surrounding']['handles special characters in \"not found\" message'] = function()\n  type_keys('sf', '\\t')\n  has_message_about_not_found('\\t')\n  type_keys('sf', '<C-j>')\n  has_message_about_not_found('\\n')\nend\n\nT['Find surrounding']['works with multibyte characters'] = function()\n  local f = function() type_keys('sf', ')') end\n\n  validate_find({ '  (ыыы)  ' }, { 1, 5 }, { { 1, 9 }, { 1, 2 } }, f)\n  validate_find({ '(ыыы) ttt' }, { 1, 3 }, { { 1, 7 }, { 1, 0 } }, f)\n  validate_find({ 'ttt (ыыы)' }, { 1, 7 }, { { 1, 11 }, { 1, 4 } }, f)\nend\n\nT['Find surrounding']['works on multiple lines'] = function()\n  validate_find({ '(aaa', 'bbb', 'ccc)' }, { 1, 3 }, { { 3, 3 }, { 1, 0 } }, type_keys, 'sf', ')')\n  validate_find({ '(aaa', 'bbb', 'ccc)' }, { 1, 3 }, { { 1, 0 }, { 3, 3 } }, type_keys, 'sF', ')')\nend\n\nT['Find surrounding']['works with multiline input surroundings'] = function()\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    a = { input = { '%(\\na().-()a\\n%)' } },\n    b = { input = { '%(\\n().-()\\n%)' } },\n    c = { input = { '\\na().-()a\\n' } },\n    d = { input = { '\\n().-()\\n' } },\n  }]])\n  local lines = { 'xxx(', 'aaa', ')xxx' }\n\n  validate_find(lines, { 2, 1 }, { { 2, 2 }, { 3, 0 }, { 1, 3 }, { 2, 0 } }, type_keys, 'sf', 'a')\n  validate_find(lines, { 2, 1 }, { { 2, 0 }, { 1, 3 }, { 3, 0 }, { 2, 2 } }, type_keys, 'sF', 'a')\n\n  -- Same as `a` because new line characters are normalized \"inside\" surrounding\n  validate_find(lines, { 2, 1 }, { { 2, 2 }, { 3, 0 }, { 1, 3 }, { 2, 0 } }, type_keys, 'sf', 'b')\n  validate_find(lines, { 2, 1 }, { { 2, 0 }, { 1, 3 }, { 3, 0 }, { 2, 2 } }, type_keys, 'sF', 'b')\n\n  validate_find(lines, { 2, 1 }, { { 2, 2 }, { 2, 0 } }, type_keys, 'sf', 'c')\n  validate_find(lines, { 2, 1 }, { { 2, 0 }, { 2, 2 } }, type_keys, 'sF', 'c')\n\n  -- Same as `c` because new line characters are normalized \"inside\" surrounding\n  validate_find(lines, { 2, 1 }, { { 2, 2 }, { 2, 0 } }, type_keys, 'sf', 'd')\n  validate_find(lines, { 2, 1 }, { { 2, 0 }, { 2, 2 } }, type_keys, 'sF', 'd')\nend\n\nT['Find surrounding']['allows cancelling with `<Esc> and <C-c>`'] = function()\n  local validate_cancel = function(key)\n    child.ensure_normal_mode()\n    set_lines({ '<aaa>' })\n    set_cursor(1, 1)\n\n    -- It should work with `sf`\n    type_keys(1, 'sf', key)\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n\n    -- It should work with `sF`\n    type_keys(1, 'sF', key)\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n  end\n\n  validate_cancel('<Esc>')\n  validate_cancel('<C-c>')\nend\n\nT['Find surrounding']['works with different mapping'] = function()\n  reload_module({ mappings = { find = 'SF', find_left = 'Sf' } })\n\n  validate_find({ '(aaa)' }, { 1, 2 }, { { 1, 4 }, { 1, 0 } }, type_keys, 'SF', ')')\n  validate_find({ '(aaa)' }, { 1, 2 }, { { 1, 0 }, { 1, 4 } }, type_keys, 'Sf', ')')\n  child.api.nvim_del_keymap('n', 'SF')\n  child.api.nvim_del_keymap('n', 'Sf')\nend\n\nT['Find surrounding']['respects `v:count` for input surrounding'] = function()\n  validate_edit({ '(a(b(c)b)a)' }, { 1, 5 }, { '(a(b(c)b)a)' }, { 1, 8 }, type_keys, '2sf', ')')\n  validate_edit({ '(a(b(c)b)a)' }, { 1, 5 }, { '(a(b(c)b)a)' }, { 1, 2 }, type_keys, '2sF', ')')\n\n  -- Should give informative message on failure\n  validate_edit({ '(a)' }, { 1, 0 }, { '(a)' }, { 1, 0 }, type_keys, '2sf', ')')\n  has_message_about_not_found(')', nil, nil, 2)\n\n  -- Should respect search method\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  validate_edit({ '(aa) (bb) (cc)' }, { 1, 1 }, { '(aa) (bb) (cc)' }, { 1, 5 }, type_keys, '2sf', ')')\n\n  child.lua([[MiniSurround.config.search_method = 'cover_or_prev']])\n  validate_edit({ '(aa) (bb) (cc)' }, { 1, 13 }, { '(aa) (bb) (cc)' }, { 1, 8 }, type_keys, '2sF', ')')\nend\n\nT['Find surrounding']['respects `vim.{g,b}.minisurround_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minisurround_disable = true\n\n    set_lines({ '<aaa>' })\n    set_cursor(1, 1)\n\n    -- It should ignore `sf`\n    type_keys('sf', '>')\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n\n    -- It should ignore `sF`\n    type_keys('sF', '>')\n    eq(get_lines(), { '<aaa>' })\n    eq(get_cursor(), { 1, 1 })\n  end,\n})\n\nT['Find surrounding']['respects `vim.b.minisurround_config`'] = function()\n  child.b.minisurround_config = { custom_surroundings = { ['<'] = { input = { '>().-()<' } } } }\n  validate_edit({ '>aaa<' }, { 1, 2 }, { '>aaa<' }, { 1, 4 }, type_keys, 'sf', '<')\nend\n\n-- NOTE: most tests are done specifically for highlighting in hope that\n-- finding of surrounding is done properly\nT['Highlight surrounding'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Reduce default highlight duration to speed up tests execution\n      child.lua('MiniSurround.config.highlight_duration = ' .. (5 * small_time))\n      child.set_size(5, 12)\n      child.o.cmdheight = 1\n    end,\n  },\n})\n\nlocal activate_highlighting = function()\n  type_keys('sh)')\n  child.poke_eventloop()\nend\n\nT['Highlight surrounding']['works without dot-repeat'] = function()\n  -- Check this only on Neovim>=0.11, as there is a slight change in\n  -- highlighting command line area\n  if child.fn.has('nvim-0.11') == 0 then return end\n\n  local test_duration = child.lua_get('MiniSurround.config.highlight_duration')\n  set_lines({ ' ' })\n  set_cursor(1, 0)\n  type_keys('rx') -- dot-repeatable action\n\n  set_lines({ '(aaa) (bbb)' })\n  set_cursor(1, 2)\n\n  -- Should show highlighting immediately\n  activate_highlighting()\n  child.expect_screenshot()\n\n  -- Should still highlight\n  sleep(test_duration - 2 * small_time)\n  child.expect_screenshot()\n\n  -- Should stop highlighting\n  sleep(2 * small_time + small_time)\n  child.expect_screenshot()\n\n  -- Does not override dot-repeat\n  type_keys('.')\n\n  -- - No highlighting should be present\n  child.expect_screenshot()\nend\n\nT['Highlight surrounding']['works in extended mappings'] = function()\n  child.set_size(5, 15)\n  local test_duration = child.lua_get('MiniSurround.config.highlight_duration')\n  set_lines({ ' ' })\n  set_cursor(1, 0)\n  type_keys('rx') -- dot-repeatable action\n  set_lines({ '(aa) (bb) (cc)' })\n  set_cursor(1, 0)\n\n  set_cursor(1, 1)\n  type_keys('shn', ')')\n  child.poke_eventloop()\n  child.expect_screenshot()\n  sleep(test_duration + small_time)\n\n  set_cursor(1, 12)\n  type_keys('shl', ')')\n  child.poke_eventloop()\n  child.expect_screenshot()\n  sleep(test_duration + small_time)\n\n  -- Does not override dot-repeat\n  type_keys('.')\n\n  -- - No highlighting should be present\n  child.expect_screenshot()\nend\n\nT['Highlight surrounding']['respects `config.highlight_duration`'] = function()\n  -- Currently tested in every `pre_case()`\nend\n\nT['Highlight surrounding']['respects `config.n_lines`'] = function()\n  child.set_size(15, 40)\n  child.o.cmdheight = 3\n\n  child.lua('MiniSurround.config.n_lines = 2')\n  set_lines({ '(', '', '', 'a', '', '', ')' })\n  set_cursor(4, 0)\n  activate_highlighting()\n\n  -- Shouldn't highlight anything\n  child.expect_screenshot()\n  has_message_about_not_found(')', 2)\nend\n\nT['Highlight surrounding']['works with multiline input surroundings'] = function()\n  -- Check this only on Neovim>=0.11, as there is a slight change in\n  -- highlighting command line area\n  if child.fn.has('nvim-0.11') == 0 then return end\n\n  child.lua('MiniSurround.config.highlight_duration = ' .. small_time)\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    a = { input = { '%(\\na().-()a\\n%)' } },\n    b = { input = { '%(\\n().-()\\n%)' } },\n    c = { input = { '\\na().-()a\\n' } },\n    d = { input = { '\\n().-()\\n' } },\n  }]])\n  set_lines({ 'xxx(', 'aaa', ')xxx' })\n  set_cursor(2, 1)\n\n  type_keys('sh', 'a')\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n\n  type_keys('sh', 'b')\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n\n  type_keys('sh', 'c')\n  child.expect_screenshot()\n  sleep(small_time + small_time)\n\n  type_keys('sh', 'd')\n  child.expect_screenshot()\nend\n\nT['Highlight surrounding']['removes highlighting in correct buffer'] = function()\n  child.set_size(5, 60)\n  local test_duration = child.lua_get('MiniSurround.config.highlight_duration')\n\n  set_lines({ '(aaa)' })\n  set_cursor(1, 2)\n  activate_highlighting()\n\n  child.cmd('vsplit current')\n  set_lines({ '(bbb)' })\n  set_cursor(1, 2)\n  sleep(0.5 * test_duration + small_time)\n  activate_highlighting()\n\n  -- Highlighting should be removed only in previous buffer\n  child.expect_screenshot()\n  sleep(0.5 * test_duration + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlight surrounding']['removes highlighting per line'] = function()\n  -- Check this only on Neovim>=0.11, as there is a slight change in\n  -- highlighting command line area\n  if child.fn.has('nvim-0.11') == 0 then return end\n\n  local test_duration = child.lua_get('MiniSurround.config.highlight_duration')\n  local half_duration = 0.5 * test_duration\n  set_lines({ '(aaa)', '(bbb)' })\n\n  -- Create situation when there are two highlights simultaneously but on\n  -- different lines. Check that they are properly and independently removed.\n  set_cursor(1, 2)\n  activate_highlighting()\n  sleep(half_duration)\n  set_cursor(2, 2)\n  activate_highlighting()\n\n  -- Should highlight in both lines\n  child.expect_screenshot()\n\n  -- Should highlight only in second line\n  sleep(half_duration + small_time)\n  child.expect_screenshot()\n\n  -- Should stop highlighting at all\n  sleep(half_duration + small_time)\n  child.expect_screenshot()\nend\n\nT['Highlight surrounding']['respects `v:count` for input surrounding'] = function()\n  set_lines({ '(a(b(c)b)a)' })\n  set_cursor(1, 5)\n  type_keys('2sh', ')')\n  -- Check this only on Neovim>=0.11, as there is a slight change in\n  -- highlighting command line area\n  if child.fn.has('nvim-0.11') == 1 then child.expect_screenshot() end\n\n  -- Should give informative message on failure\n  child.set_size(10, 80)\n  child.o.cmdheight = 10\n  set_lines({ '(a)' })\n  set_cursor(1, 0)\n  type_keys('2sh', ')')\n\n  has_message_about_not_found(')', nil, nil, 2)\nend\n\nT['Highlight surrounding']['respects `vim.{g,b}.minisurround_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    -- Check this only on Neovim>=0.11, as there is a slight change in\n    -- highlighting command line area\n    if child.fn.has('nvim-0.11') == 0 then return end\n\n    child[var_type].minisurround_disable = true\n\n    set_lines({ '(aaa)', 'bbb' })\n    set_cursor(1, 2)\n    type_keys('sh', ')')\n    child.poke_eventloop()\n\n    -- Shouldn't highlight anything (instead moves cursor with `)` motion)\n    child.expect_screenshot()\n  end,\n})\n\nT['Highlight surrounding']['respects `vim.b.minisurround_config`'] = function()\n  child.b.minisurround_config = {\n    custom_surroundings = { ['<'] = { input = { '>().-()<' } } },\n    highlight_duration = 5 * small_time,\n  }\n  validate_edit({ '>aaa<' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', '<')\n\n  set_lines({ '>aaa<', 'bbb' })\n  set_cursor(1, 2)\n  type_keys('sh', '<')\n  child.poke_eventloop()\n  child.expect_screenshot({ ignore_attr = { 5 } })\n\n  -- Should stop highlighting after duration from local config\n  sleep(5 * small_time + small_time)\n  child.expect_screenshot({ ignore_attr = { 5 } })\nend\n\nT['Search method'] = new_set()\n\nT['Search method']['works with \"cover_or_prev\"'] = function()\n  reload_module({ search_method = 'cover_or_prev' })\n  local f = function() type_keys('sr', ')', '>') end\n\n  -- Works (on same line and on multiple lines)\n  validate_edit({ '(aaa) bbb' }, { 1, 7 }, { '<aaa> bbb' }, { 1, 1 }, f)\n  validate_edit({ '(aaa)', 'bbb' }, { 2, 0 }, { '<aaa>', 'bbb' }, { 1, 1 }, f)\n\n  -- Should prefer covering surrounding if both are on the same line\n  validate_edit({ '(aaa) (bbb)' }, { 1, 8 }, { '(aaa) <bbb>' }, { 1, 7 }, f)\n  validate_edit({ '((aaa) bbb)' }, { 1, 8 }, { '<(aaa) bbb>' }, { 1, 1 }, f)\n\n  -- Should prefer covering surrounding if both are not on the same line\n  validate_edit({ '(aaa) (', 'bbb)' }, { 2, 0 }, { '(aaa) <', 'bbb>' }, { 1, 6 }, f)\n\n  -- Should prefer \"previous\" if it is on the same line, but covering is not\n  validate_edit({ '(aaa) (bbb', ')' }, { 1, 8 }, { '<aaa> (bbb', ')' }, { 1, 1 }, f)\n\n  -- Should ignore presence of \"next\" surrounding (even on same line)\n  validate_edit({ '(aaa) bbb (ccc)' }, { 1, 7 }, { '<aaa> bbb (ccc)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa)', 'bbb (ccc)' }, { 2, 1 }, { '<aaa>', 'bbb (ccc)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa) (', 'bbb (ccc))' }, { 2, 0 }, { '(aaa) <', 'bbb (ccc)>' }, { 1, 6 }, f)\nend\n\nT['Search method']['works with \"cover_or_next\"'] = function()\n  reload_module({ search_method = 'cover_or_next' })\n  local f = function() type_keys('sr', ')', '>') end\n\n  -- Works (on same line and on multiple lines)\n  validate_edit({ 'aaa (bbb)' }, { 1, 0 }, { 'aaa <bbb>' }, { 1, 5 }, f)\n  validate_edit({ 'aaa', '(bbb)' }, { 1, 0 }, { 'aaa', '<bbb>' }, { 2, 1 }, f)\n\n  -- Should prefer covering surrounding if both are on the same line\n  validate_edit({ '(aaa) (bbb)' }, { 1, 2 }, { '<aaa> (bbb)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa (bbb))' }, { 1, 2 }, { '<aaa (bbb)>' }, { 1, 1 }, f)\n\n  -- Should prefer covering surrounding if both are not on the same line\n  validate_edit({ '(aaa', ') (bbb)' }, { 1, 2 }, { '<aaa', '> (bbb)' }, { 1, 1 }, f)\n\n  -- Should prefer \"next\" if it is on the same line, but covering is not\n  validate_edit({ '(', 'aaa) (bbb)' }, { 2, 1 }, { '(', 'aaa) <bbb>' }, { 2, 6 }, f)\n\n  -- Should ignore presence of \"previous\" surrounding (even on same line)\n  validate_edit({ '(aaa) bbb (ccc)' }, { 1, 7 }, { '(aaa) bbb <ccc>' }, { 1, 11 }, f)\n  validate_edit({ '(aaa) bbb', '(ccc)' }, { 1, 7 }, { '(aaa) bbb', '<ccc>' }, { 2, 1 }, f)\n  validate_edit({ '(aaa) (', '(bbb) ccc)' }, { 2, 7 }, { '(aaa) <', '(bbb) ccc>' }, { 1, 6 }, f)\nend\n\nT['Search method']['works with \"cover_or_nearest\"'] = function()\n  reload_module({ search_method = 'cover_or_nearest' })\n  local f = function() type_keys('sr', ')', '>') end\n\n  -- Works (on same line and on multiple lines)\n  validate_edit({ '(aaa) bbb (ccc)' }, { 1, 6 }, { '<aaa> bbb (ccc)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa) bbb (ccc)' }, { 1, 7 }, { '<aaa> bbb (ccc)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa) bbb (ccc)' }, { 1, 8 }, { '(aaa) bbb <ccc>' }, { 1, 11 }, f)\n\n  validate_edit({ '(aaa)', 'bbb', '(ccc)' }, { 2, 0 }, { '<aaa>', 'bbb', '(ccc)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa)', 'bbb', '(ccc)' }, { 2, 1 }, { '<aaa>', 'bbb', '(ccc)' }, { 1, 1 }, f)\n  validate_edit({ '(aaa)', 'bbb', '(ccc)' }, { 2, 2 }, { '(aaa)', 'bbb', '<ccc>' }, { 3, 1 }, f)\n\n  -- Should prefer covering surrounding if both are on the same line\n  validate_edit({ '(aaa) (bbb) (ccc)' }, { 1, 7 }, { '(aaa) <bbb> (ccc)' }, { 1, 7 }, f)\n  validate_edit({ '((aaa) bbb (ccc))' }, { 1, 7 }, { '<(aaa) bbb (ccc)>' }, { 1, 1 }, f)\n\n  -- Should prefer covering surrounding if both are not on the same line\n  validate_edit({ '(aaa) (', 'bbb', ') (ccc)' }, { 2, 0 }, { '(aaa) <', 'bbb', '> (ccc)' }, { 1, 6 }, f)\n\n  -- Should prefer \"nearest\" if it is on the same line, but covering is not\n  validate_edit({ '(aaa) (', 'bbb) (ccc)' }, { 2, 1 }, { '(aaa) (', 'bbb) <ccc>' }, { 2, 6 }, f)\n\n  -- Computes \"nearest\" based on closest part of candidate surroundings (based\n  -- on distance between *left* part of current cell and span edges)\n  validate_edit({ '(aaaaaaa) b  (c)' }, { 1, 7 }, { '<aaaaaaa> b  (c)' }, { 1, 1 }, f)\n  validate_edit({ '(a)   b (ccccccc)' }, { 1, 6 }, { '(a)   b <ccccccc>' }, { 1, 9 }, f)\n\n  -- If either \"previous\" or \"next\" is missing, should return the present one\n  validate_edit({ '(aaa) bbb' }, { 1, 7 }, { '<aaa> bbb' }, { 1, 1 }, f)\n  validate_edit({ '(aaa)', 'bbb' }, { 2, 0 }, { '<aaa>', 'bbb' }, { 1, 1 }, f)\n  validate_edit({ 'aaa (bbb)' }, { 1, 0 }, { 'aaa <bbb>' }, { 1, 5 }, f)\n  validate_edit({ 'aaa', '(bbb)' }, { 1, 0 }, { 'aaa', '<bbb>' }, { 2, 1 }, f)\nend\n\nT['Search method']['throws error on incorrect `config.search_method`'] = function()\n  child.lua([[MiniSurround.config.search_method = 'aaa']])\n  local lines = { 'aaa (bbb)' }\n  -- Avoid hit-enter-prompt from three big error message\n  child.o.cmdheight = 40\n\n  set_lines(lines)\n  set_cursor(1, 0)\n  expect.error(function() type_keys('sd', ')') end, 'one of')\n  eq(get_lines(), lines)\n  eq(get_cursor(), { 1, 0 })\nend\n\nT['Search method']['respects `vim.b.minisurround_config`'] = function()\n  child.b.minisurround_config = { search_method = 'cover_or_next' }\n  validate_edit({ 'aaa (bbb)' }, { 1, 0 }, { 'aaa <bbb>' }, { 1, 5 }, type_keys, 'sr', ')', '>')\nend\n\n-- Surroundings ---------------------------------------------------------------\nT['Builtin'] = new_set()\n\nT['Builtin']['Bracket'] = new_set()\n\nT['Builtin']['Bracket']['works with open character'] = function()\n  local validate = function(key, pair)\n    -- Should work as input surrounding (by removing )\n    local input = pair:sub(1, 1) .. '  aaa  ' .. pair:sub(2, 2)\n    validate_edit({ input }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', key)\n\n    -- Should work as output surrounding\n    local output = string.format('%s aaa %s', pair:sub(1, 1), pair:sub(2, 2))\n    validate_edit({ '_aaa_' }, { 1, 2 }, { output }, { 1, 2 }, type_keys, 'sr', '_', key)\n  end\n\n  validate('(', '()')\n  validate('[', '[]')\n  validate('{', '{}')\n  validate('<', '<>')\nend\n\nT['Builtin']['Bracket']['works with close character'] = function()\n  local validate = function(key, pair)\n    -- Should work as input surrounding (by removing )\n    local input = pair:sub(1, 1) .. '  aaa  ' .. pair:sub(2, 2)\n    validate_edit({ input }, { 1, 2 }, { '  aaa  ' }, { 1, 0 }, type_keys, 'sd', key)\n\n    -- Should work as output surrounding\n    local output = pair:sub(1, 1) .. 'aaa' .. pair:sub(2, 2)\n    validate_edit({ '_aaa_' }, { 1, 2 }, { output }, { 1, 1 }, type_keys, 'sr', '_', key)\n  end\n\n  validate(')', '()')\n  validate(']', '[]')\n  validate('}', '{}')\n  validate('>', '<>')\nend\n\n-- All remaining tests are done with ')' and '>' in hope that others work\n-- similarly\nT['Builtin']['Bracket']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n  local f = function() type_keys('sr', ')', '>') end\n\n  -- It does not take into account that part is inside string\n  validate_edit({ [[(a, ')', b)]] }, { 1, 1 }, { \"<a, '>', b)\" }, { 1, 1 }, f)\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_edit({ '(a', '# )', 'b)' }, { 1, 1 }, { '<a', '# >', 'b)' }, { 1, 1 }, f)\nend\n\nT['Builtin']['Bracket']['is indeed balanced'] = function()\n  local f = function() type_keys('sr', ')', '>') end\n\n  validate_edit({ '(a())' }, { 1, 1 }, { '<a()>' }, { 1, 1 }, f)\n  validate_edit({ '(()a)' }, { 1, 3 }, { '<()a>' }, { 1, 1 }, f)\n\n  validate_edit({ '((()))' }, { 1, 0 }, { '<(())>' }, { 1, 1 }, f)\n  validate_edit({ '((()))' }, { 1, 1 }, { '(<()>)' }, { 1, 2 }, f)\n  validate_edit({ '((()))' }, { 1, 2 }, { '((<>))' }, { 1, 3 }, f)\n  validate_edit({ '((()))' }, { 1, 3 }, { '((<>))' }, { 1, 3 }, f)\n  validate_edit({ '((()))' }, { 1, 4 }, { '(<()>)' }, { 1, 2 }, f)\n  validate_edit({ '((()))' }, { 1, 5 }, { '<(())>' }, { 1, 1 }, f)\nend\n\nT['Builtin']['Brackets alias'] = new_set()\n\nT['Builtin']['Brackets alias']['works'] = function()\n  local f\n\n  -- Input\n  f = function() type_keys('sd', 'b') end\n  validate_edit({ '(aa)' }, { 1, 0 }, { 'aa' }, { 1, 0 }, f)\n  validate_edit({ '[aa]' }, { 1, 0 }, { 'aa' }, { 1, 0 }, f)\n  validate_edit({ '{aa}' }, { 1, 0 }, { 'aa' }, { 1, 0 }, f)\n\n  -- Output\n  f = function() type_keys('sr', '_', 'b') end\n  validate_edit({ '_aa_' }, { 1, 0 }, { '(aa)' }, { 1, 1 }, f)\n\n  -- Balanced\n  f = function() type_keys('sd', 'b') end\n  validate_edit({ '(aa())' }, { 1, 0 }, { 'aa()' }, { 1, 0 }, f)\n  validate_edit({ '[aa[]]' }, { 1, 0 }, { 'aa[]' }, { 1, 0 }, f)\n  validate_edit({ '{aa{}}' }, { 1, 0 }, { 'aa{}' }, { 1, 0 }, f)\nend\n\nT['Builtin']['Quotes alias'] = new_set()\n\nT['Builtin']['Quotes alias']['works'] = function()\n  local f\n\n  -- Input\n  f = function() type_keys('sd', 'q') end\n  validate_edit({ \"'aa'\" }, { 1, 0 }, { 'aa' }, { 1, 0 }, f)\n  validate_edit({ '\"aa\"' }, { 1, 0 }, { 'aa' }, { 1, 0 }, f)\n  validate_edit({ '`aa`' }, { 1, 0 }, { 'aa' }, { 1, 0 }, f)\n\n  -- Output\n  f = function() type_keys('sr', '_', 'q') end\n  validate_edit({ '_aa_' }, { 1, 0 }, { '\"aa\"' }, { 1, 1 }, f)\n\n  -- Not balanced\n  f = function() type_keys('sd', 'q') end\n  validate_edit({ \"'aa'bb'cc'\" }, { 1, 4 }, { \"'aabbcc'\" }, { 1, 3 }, f)\n  validate_edit({ '\"aa\"bb\"cc\"' }, { 1, 4 }, { '\"aabbcc\"' }, { 1, 3 }, f)\n  validate_edit({ '`aa`bb`cc`' }, { 1, 4 }, { '`aabbcc`' }, { 1, 3 }, f)\nend\n\nT['Builtin']['Default'] = new_set()\n\nT['Builtin']['Default']['works'] = function()\n  local validate = function(key)\n    local s = key .. 'aaa' .. key\n\n    -- Should work as input surrounding\n    validate_edit({ s }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', key)\n\n    -- Should work as output surrounding\n    validate_edit({ '(aaa)' }, { 1, 2 }, { s }, { 1, 1 }, type_keys, 'sr', ')', key)\n  end\n\n  validate(' ')\n  validate('_')\n  validate('*')\n  validate('\"')\n  validate(\"'\")\nend\n\nT['Builtin']['Default']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n  local f = function() type_keys('sr', '_', '>') end\n\n  -- It does not take into account that part is inside string\n  validate_edit({ [[_a, '_', b_]] }, { 1, 1 }, { \"<a, '>', b_\" }, { 1, 1 }, f)\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_edit({ '_a', '# _', 'b_' }, { 1, 1 }, { '<a', '# >', 'b_' }, { 1, 1 }, f)\nend\n\nT['Builtin']['Default']['detects covering with smallest width'] = function()\n  local f = function() type_keys('sr', '\"', ')') end\n\n  validate_edit({ '\"a\"aa\"' }, { 1, 2 }, { '(a)aa\"' }, { 1, 1 }, f)\n  validate_edit({ '\"aa\"a\"' }, { 1, 3 }, { '\"aa(a)' }, { 1, 4 }, f)\n\n  validate_edit({ '\"\"\"a\"\"\"' }, { 1, 3 }, { '\"\"(a)\"\"' }, { 1, 3 }, f)\nend\n\nT['Builtin']['Default']['works in edge cases'] = function()\n  local f = function() type_keys('sr', '*', ')') end\n\n  -- Consecutive identical matching characters\n  validate_edit({ '****' }, { 1, 0 }, { '()**' }, { 1, 1 }, f)\n  validate_edit({ '****' }, { 1, 1 }, { '()**' }, { 1, 1 }, f)\n  validate_edit({ '****' }, { 1, 2 }, { '*()*' }, { 1, 2 }, f)\n  validate_edit({ '****' }, { 1, 3 }, { '**()' }, { 1, 3 }, f)\nend\n\nT['Builtin']['Default']['supports any identifier which can be `getcharstr()` output'] = function()\n  validate_edit({ 'aaa' }, { 1, 0 }, { 'ыaaaы' }, { 1, 2 }, type_keys, 'sa', 'iw', 'ы')\n  validate_edit({ 'ыaaaы' }, { 1, 3 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'ы')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'ыaaaы' }, { 1, 2 }, type_keys, 'sr', ')', 'ы')\n\n  validate_edit({ 'aaa' }, { 1, 0 }, { '「aaa「' }, { 1, 3 }, type_keys, 'sa', 'iw', '「')\n  validate_edit({ '「aaa「' }, { 1, 3 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', '「')\n  validate_edit({ '(aaa)' }, { 1, 1 }, { '「aaa「' }, { 1, 3 }, type_keys, 'sr', ')', '「')\n\n  -- <C-j> is `\\n`\n  validate_edit({ 'aaa' }, { 1, 0 }, { '', 'aaa', '' }, { 1, 0 }, type_keys, 'sa', 'iw', '<C-j>')\n  validate_edit({ 'aaa', 'bbb', 'ccc' }, { 2, 0 }, { 'aaabbbccc' }, { 1, 3 }, type_keys, 'sd', '<C-j>')\n  validate_edit({ 'aaa', 'bbb', 'ccc' }, { 2, 0 }, { 'aaa(bbb)ccc' }, { 1, 4 }, type_keys, 'sr', '<C-j>', ')')\nend\n\nT['Builtin']['Function call'] = new_set()\n\nT['Builtin']['Function call']['works'] = function()\n  -- Should work as input surrounding\n  validate_edit({ 'myfunc(aaa)' }, { 1, 8 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'f')\n\n  -- Should work as output surrounding\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'myfunc(aaa)' }, { 1, 7 }, type_keys, 'sr', ')', 'f', 'myfunc<CR>')\n\n  -- Should work with empty arguments\n  validate_edit({ 'myfunc()' }, { 1, 0 }, { '' }, { 1, 0 }, type_keys, 'sd', 'f')\nend\n\nT['Builtin']['Function call']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n  local f = function() type_keys('sr', 'f', '>') end\n\n  -- It does not take into account that part is inside string\n  validate_edit({ [[myfunc(a, ')', b)]] }, { 1, 7 }, { \"<a, '>', b)\" }, { 1, 1 }, f)\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_edit({ 'myfunc(a', '# )', 'b)' }, { 1, 7 }, { '<a', '# >', 'b)' }, { 1, 1 }, f)\nend\n\nT['Builtin']['Function call']['is detected with \"_\" and \".\" in name'] = function()\n  validate_edit({ 'my_func(aaa)' }, { 1, 9 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'f')\n  validate_edit({ 'my.func(aaa)' }, { 1, 9 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'f')\n  validate_edit({ 'big-new_my.func(aaa)' }, { 1, 17 }, { 'big-aaa' }, { 1, 4 }, type_keys, 'sd', 'f')\n  validate_edit({ 'big new_my.func(aaa)' }, { 1, 17 }, { 'big aaa' }, { 1, 4 }, type_keys, 'sd', 'f')\n\n  validate_edit({ '[(myfun(aaa))]' }, { 1, 9 }, { '[(aaa)]' }, { 1, 2 }, type_keys, 'sd', 'f')\nend\n\nT['Builtin']['Function call']['works in different parts of line and neighborhood'] = function()\n  -- This check is viable because of complex nature of Lua patterns\n  validate_edit({ 'myfunc(aaa)' }, { 1, 8 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'f')\n  validate_edit({ 'Hello myfunc(aaa)' }, { 1, 14 }, { 'Hello aaa' }, { 1, 6 }, type_keys, 'sd', 'f')\n  validate_edit({ 'myfunc(aaa) world' }, { 1, 8 }, { 'aaa world' }, { 1, 0 }, type_keys, 'sd', 'f')\n  validate_edit({ 'Hello myfunc(aaa) world' }, { 1, 14 }, { 'Hello aaa world' }, { 1, 6 }, type_keys, 'sd', 'f')\n\n  --stylua: ignore start\n  validate_edit({ 'myfunc(aaa)', 'Hello', 'world' }, { 1, 8 }, { 'aaa', 'Hello', 'world' }, { 1, 0 }, type_keys, 'sd', 'f')\n  validate_edit({ 'Hello', 'myfunc(aaa)', 'world' }, { 2, 8 }, { 'Hello', 'aaa', 'world' }, { 2, 0 }, type_keys, 'sd', 'f')\n  validate_edit({ 'Hello', 'world', 'myfunc(aaa)' }, { 3, 8 }, { 'Hello', 'world', 'aaa' }, { 3, 0 }, type_keys, 'sd', 'f')\n  --stylua: ignore end\nend\n\nT['Builtin']['Function call']['has limited support of multibyte characters'] = function()\n  -- Due to limitations of Lua patterns used for detecting surrounding, it\n  -- currently doesn't support detecting function calls with multibyte\n  -- character in name. It would be great to fix this.\n  expect.error(function() validate_edit({ 'ыыы(aaa)' }, { 1, 8 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'f') end)\n\n  -- Should work in output surrounding\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'ыыы(aaa)' }, { 1, 7 }, type_keys, 'sr', ')', 'f', 'ыыы<CR>')\nend\n\nT['Builtin']['Function call']['handles <C-c>, <Esc>, <CR> in user input'] = function()\n  -- Should do nothing on `<C-c>` and `<Esc>`\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '(aaa)' }, { 1, 2 }, type_keys, 1, 'sr', ')', 'f', '<Esc>')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '(aaa)' }, { 1, 2 }, type_keys, 1, 'sr', ')', 'f', '<C-c>')\n\n  -- Should treat `<CR>` as empty string input\n  validate_edit({ '[aaa]' }, { 1, 2 }, { '(aaa)' }, { 1, 1 }, type_keys, 'sr', ']', 'f', '<CR>')\nend\n\nT['Builtin']['Function call']['colors its prompts'] = function()\n  child.set_size(5, 40)\n\n  set_lines({ '(aaa)' })\n  set_cursor(1, 2)\n  type_keys('sr', ')', 'f', 'hello')\n  child.expect_screenshot()\n  type_keys('<CR>')\n\n  -- Should clean command line afterwards\n  child.expect_screenshot()\nend\n\nT['Builtin']['Tag'] = new_set()\n\nT['Builtin']['Tag']['works'] = function()\n  -- Should work as input surrounding\n  validate_edit({ '<x>aaa</x>' }, { 1, 4 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 't')\n\n  -- Should work as output surrounding\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '<x>aaa</x>' }, { 1, 3 }, type_keys, 'sr', ')', 't', 'x<CR>')\n\n  -- Should work with empty tag name\n  validate_edit({ '<>aaa</>' }, { 1, 3 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 't')\n\n  -- Should work with empty inside content\n  validate_edit({ '<x></x>' }, { 1, 2 }, { '' }, { 1, 0 }, type_keys, 'sd', 't')\nend\n\nT['Builtin']['Tag']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n  local f = function() type_keys('sr', 't', '>') end\n\n  -- It does not take into account that part is inside string\n  validate_edit({ [[<x>a, '</x>', b</x>]] }, { 1, 3 }, { \"<a, '>', b</x>\" }, { 1, 1 }, f)\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_edit({ '<x>a', '# </x>', 'b</x>' }, { 1, 3 }, { '<a', '# >', 'b</x>' }, { 1, 1 }, f)\n\n  -- Tags result into smallest width\n  validate_edit({ '<x><x></x></x>' }, { 1, 1 }, { '<x><x></x></x>' }, { 1, 1 }, type_keys, 'sr', 't', '.')\n\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  validate_edit({ '<x><x></x></x>' }, { 1, 1 }, { '<x>..</x>' }, { 1, 4 }, type_keys, 'sr', 't', '.')\n  child.lua([[MiniSurround.config.search_method = 'cover']])\n\n  -- Don't work at end of self-nesting tags\n  validate_edit({ '<x><x></x></x>' }, { 1, 12 }, { '<x><x></x></x>' }, { 1, 12 }, type_keys, 'sr', 't')\n  has_message_about_not_found('t')\nend\n\nT['Builtin']['Tag']['detects tag with the same name'] = function()\n  validate_edit({ '<x><y>a</x></y>' }, { 1, 1 }, { '_<y>a_</y>' }, { 1, 1 }, type_keys, 'sr', 't', '_')\nend\n\nT['Builtin']['Tag']['allows extra symbols in opening tag on input'] = function()\n  validate_edit({ '<x bbb cc_dd!>aaa</x>' }, { 1, 15 }, { '_aaa_' }, { 1, 1 }, type_keys, 'sr', 't', '_')\n\n  -- Symbol `<` is not allowed\n  validate_edit({ '<x <>aaa</x>' }, { 1, 6 }, { '<x <>aaa</x>' }, { 1, 6 }, type_keys, 'sr', 't')\n  has_message_about_not_found('t')\nend\n\nT['Builtin']['Tag']['allows extra symbols in opening tag on output'] = function()\n  validate_edit({ 'aaa' }, { 1, 0 }, { '<a b>aaa</a>' }, { 1, 5 }, type_keys, 'sa', 'iw', 't', 'a b', '<CR>')\n  validate_edit({ '<a b>aaa</a>' }, { 1, 5 }, { '<a c>aaa</a>' }, { 1, 5 }, type_keys, 'sr', 't', 't', 'a c', '<CR>')\nend\n\nT['Builtin']['Tag']['detects covering with smallest width'] = function()\n  local f = function() type_keys('sr', 't', '_') end\n\n  -- In all cases width of `<y>...</y>` is smaller than of `<x>...</x>`\n  validate_edit({ '<x>  <y>a</x></y>' }, { 1, 8 }, { '<x>  _a</x>_' }, { 1, 6 }, f)\n  validate_edit({ '<y><x>a</y>  </x>' }, { 1, 6 }, { '_<x>a_  </x>' }, { 1, 1 }, f)\n\n  -- Width should be from the left-most point to right-most\n  validate_edit({ '<y><x bbb>a</y></x>' }, { 1, 10 }, { '_<x bbb>a_</x>' }, { 1, 1 }, f)\n\n  -- Works with identical nested tags\n  validate_edit({ '<x><x>aaa</x></x>' }, { 1, 7 }, { '<x>_aaa_</x>' }, { 1, 4 }, f)\nend\n\nT['Builtin']['Tag']['works in edge cases'] = function()\n  local f = function() type_keys('sr', 't', '_') end\n\n  -- Nesting different tags\n  validate_edit({ '<x><y></y></x>' }, { 1, 1 }, { '_<y></y>_' }, { 1, 1 }, f)\n  validate_edit({ '<x><y></y></x>' }, { 1, 4 }, { '<x>__</x>' }, { 1, 4 }, f)\n\n  -- End of overlapping tags\n  validate_edit({ '<y><x></y></x>' }, { 1, 12 }, { '<y>_</y>_' }, { 1, 4 }, f)\n\n  -- `>` between tags\n  validate_edit({ '<x>>aaa</x>' }, { 1, 5 }, { '_>aaa_' }, { 1, 1 }, f)\n\n  -- Similar but different names shouldn't match\n  validate_edit({ '<xy>aaa</x>' }, { 1, 5 }, { '<xy>aaa</x>' }, { 1, 5 }, type_keys, 'sd', 't')\nend\n\nT['Builtin']['Tag']['has limited support of multibyte characters'] = function()\n  -- Due to limitations of Lua patterns used for detecting surrounding, it\n  -- currently doesn't support detecting tag with multibyte character in\n  -- name. It would be great to fix this.\n  expect.error(function() validate_edit({ '<ы>aaa</ы>' }, { 1, 5 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 't') end)\n\n  -- Should work in output surrounding\n  validate_edit({ '(aaa)' }, { 1, 8 }, { '<ы>aaa</ы>' }, { 1, 4 }, type_keys, 'sr', ')', 't', 'ы<CR>')\nend\n\nT['Builtin']['Tag']['handles <C-c>, <Esc>, <CR> in user input'] = function()\n  -- Should do nothing on `<C-c>` and `<Esc>`\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '(aaa)' }, { 1, 2 }, type_keys, 1, 'sr', ')', 't', '<Esc>')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '(aaa)' }, { 1, 2 }, type_keys, 1, 'sr', ')', 't', '<C-c>')\n\n  -- Should treat `<CR>` as empty string input\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '<>aaa</>' }, { 1, 2 }, type_keys, 'sr', ')', 't', '<CR>')\nend\n\nT['Builtin']['Tag']['colors its prompts'] = function()\n  child.set_size(5, 40)\n\n  set_lines({ '(aaa)' })\n  set_cursor(1, 2)\n  type_keys('sr', ')', 't', 'hello')\n  child.expect_screenshot()\n  type_keys('<CR>')\n\n  -- Should clean command line afterwards\n  child.expect_screenshot()\nend\n\nT['Builtin']['User prompt'] = new_set()\n\nT['Builtin']['User prompt']['works'] = function()\n  -- Should work as input surrounding\n  validate_edit({ '%*aaa*%' }, { 1, 3 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', '?', '%*<CR>', '*%<CR>')\n\n  -- Should work as output surrounding\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '%*aaa*%' }, { 1, 2 }, type_keys, 'sr', ')', '?', '%*<CR>', '*%<CR>')\nend\n\nT['Builtin']['User prompt']['does not work in some cases'] = function()\n  -- Although, it would be great if it did\n  local f = function() type_keys('sr', '?', '**<CR>', '**<CR>', '>') end\n\n  -- It does not take into account that part is inside string\n  validate_edit({ [[**a, '**', b**]] }, { 1, 2 }, { \"<a, '>', b**\" }, { 1, 1 }, f)\n\n  -- It does not take into account that part is inside comment\n  child.bo.commentstring = '# %s'\n  validate_edit({ '**a', '# **', 'b**' }, { 1, 2 }, { '<a', '# >', 'b**' }, { 1, 1 }, f)\n\n  -- It does not work sometimes in presence of many identical valid parts\n  -- (basically because it is a `%(.-%)` and not `%(.*%)`).\n  f = function() type_keys('sr', '?', '(<CR>', ')<CR>', '>') end\n  validate_edit({ '((()))' }, { 1, 3 }, { '((<>))' }, { 1, 3 }, f)\n  validate_edit({ '((()))' }, { 1, 4 }, { '((()))' }, { 1, 4 }, f)\n  validate_edit({ '((()))' }, { 1, 5 }, { '((()))' }, { 1, 5 }, f)\nend\n\nT['Builtin']['User prompt']['detects covering with smallest width'] = function()\n  local f = function() type_keys('sr', '?', '**<CR>', '**<CR>', ')') end\n\n  validate_edit({ '**a**aa**' }, { 1, 4 }, { '(a)aa**' }, { 1, 1 }, f)\n  validate_edit({ '**aa**a**' }, { 1, 4 }, { '**aa(a)' }, { 1, 5 }, f)\nend\n\nT['Builtin']['User prompt']['works in edge cases'] = function()\n  local f = function() type_keys('sr', '?', '(<CR>', ')<CR>', '>') end\n\n  -- Having `.-` in pattern means the smallest matching span\n  validate_edit({ '(())' }, { 1, 0 }, { '(())' }, { 1, 0 }, f)\n  validate_edit({ '(())' }, { 1, 1 }, { '(<>)' }, { 1, 2 }, f)\nend\n\nT['Builtin']['User prompt']['works with multibyte characters in parts'] = function()\n  -- Should work as input surrounding\n  validate_edit({ 'ыtttю' }, { 1, 3 }, { 'ttt' }, { 1, 0 }, type_keys, 'sd', '?', 'ы<CR>', 'ю<CR>')\n\n  -- Should work as output surrounding\n  validate_edit({ 'ыtttю' }, { 1, 3 }, { '(ttt)' }, { 1, 1 }, type_keys, 'sr', '?', 'ы<CR>', 'ю<CR>', ')')\nend\n\nT['Builtin']['User prompt']['handles <C-c>, <Esc>, <CR> in user input'] = function()\n  local validate_single = function(...)\n    child.ensure_normal_mode()\n    -- Wait before every keygroup because otherwise it seems to randomly\n    -- break for `<C-c>`\n    validate_edit({ '(aaa)' }, { 1, 2 }, { '(aaa)' }, { 1, 2 }, type_keys, 10, ...)\n  end\n\n  local validate_nothing = function(key)\n    -- Should do nothing on any `<C-c>` and `<Esc>` (in both input and output)\n    validate_single('sr', '?', key)\n    validate_single('sr', '?', '(<CR>', key)\n    validate_single('sr', ')', '?', key)\n    validate_single('sr', ')', '?', '*<CR>', key)\n  end\n\n  validate_nothing('<Esc>')\n  validate_nothing('<C-c>')\n\n  -- Should treat `<CR>` as empty string in output surrounding\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '_aaa' }, { 1, 1 }, type_keys, 'sr', ')', '?', '_<CR>', '<CR>')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'aaa_' }, { 1, 0 }, type_keys, 'sr', ')', '?', '<CR>', '_<CR>')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sr', ')', '?', '<CR>', '<CR>')\n\n  -- Should stop on `<CR>` in input surrounding because can't use empty\n  -- string in pattern search\n  validate_edit({ '**aaa**' }, { 1, 3 }, { '**aaa**' }, { 1, 3 }, type_keys, 'sr', '?', '<CR>')\n  validate_edit({ '**aaa**' }, { 1, 3 }, { '**aaa**' }, { 1, 3 }, type_keys, 'sr', '?', '**<CR>', '<CR>')\nend\n\nT['Builtin']['User prompt']['colors its prompts'] = function()\n  child.set_size(5, 40)\n\n  set_lines({ '(aaa)' })\n  set_cursor(1, 2)\n  type_keys('sr', ')', '?', 'xxx')\n  child.expect_screenshot()\n  type_keys('<CR>', 'yyy')\n  child.expect_screenshot()\n  type_keys('<CR>')\n\n  -- Should clean command line afterwards\n  child.expect_screenshot()\nend\n\nlocal set_custom_surr = function(tbl) child.lua('MiniSurround.config.custom_surroundings = ' .. vim.inspect(tbl)) end\n\nT['Custom surrounding'] = new_set()\n\nT['Custom surrounding']['works'] = function()\n  set_custom_surr({ q = { input = { '@().-()#' }, output = { left = '@', right = '#' } } })\n\n  validate_edit({ '@aaa#' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'q')\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '@aaa#' }, { 1, 1 }, type_keys, 'sr', ')', 'q')\nend\n\nT['Custom surrounding']['supports any identifier which can be `getcharstr()` output'] = function()\n  set_custom_surr({\n    ['\\22'] = { input = { '@().-()#' }, output = { left = '@', right = '#' } },\n    ['ы'] = { input = { 'Ы().-()Ы' }, output = { left = 'Ы', right = 'Ы' } },\n    ['「'] = { input = { '「().-()」' }, output = { left = '「', right = '」' } },\n  })\n\n  validate_edit({ ' aaa ' }, { 1, 1 }, { ' 「aaa」 ' }, { 1, 4 }, type_keys, 'sa', 'iw', '「')\n  validate_edit({ 'ЫaaaЫ' }, { 1, 3 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', 'ы')\n  validate_edit({ '@aaa#' }, { 1, 2 }, { '「aaa」' }, { 1, 3 }, type_keys, 'sr', '<C-v>', '「')\n  validate_edit({ '「aaa」' }, { 1, 3 }, { '@aaa#' }, { 1, 1 }, type_keys, 'sr', '「', '<C-v>')\nend\n\nT['Custom surrounding']['overrides builtins'] = function()\n  set_custom_surr({ ['('] = { input = { '%(%(().-()%)%)' }, output = { left = '((', right = '))' } } })\n\n  validate_edit({ '((aaa))' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', '(')\n  validate_edit({ 'aaa' }, { 1, 0 }, { '((aaa))' }, { 1, 2 }, type_keys, 'sa', 'iw', '(')\nend\n\nT['Custom surrounding']['allows setting partial information'] = function()\n  -- Modifying present single character identifier (takes from present)\n  set_custom_surr({ [')'] = { output = { left = '( ', right = ' )' } } })\n\n  validate_edit({ '(aaa)' }, { 1, 2 }, { 'aaa' }, { 1, 0 }, type_keys, 'sd', ')')\n  validate_edit({ '<aaa>' }, { 1, 2 }, { '( aaa )' }, { 1, 2 }, type_keys, 'sr', '>', ')')\n\n  -- New single character identifier (takes from default)\n  set_custom_surr({ ['#'] = { input = { '#_().-()_#' } } })\n\n  -- Should find '#_' and '_#' and extract first and last two characters\n  validate_edit({ '_#_aaa_#_' }, { 1, 4 }, { '_aaa_' }, { 1, 1 }, type_keys, 'sd', '#')\n  -- `output` should be taken from default\n  validate_edit({ '(aaa)' }, { 1, 2 }, { '#aaa#' }, { 1, 1 }, type_keys, 'sr', ')', '#')\nend\n\nT['Custom surrounding']['validates captures in extract pattern'] = function()\n  -- Avoid hit-enter-prompt from three big error message\n  child.o.cmdheight = 40\n\n  local validate = function(line, col, key)\n    set_lines({ line })\n    set_cursor(1, col)\n    expect.error(function() type_keys('sd', key) end, 'two or four empty captures')\n\n    -- Clear command line to error accumulation and hit-enter-prompt\n    type_keys(':<Esc>')\n  end\n\n  set_custom_surr({ ['#'] = { input = { '#.-#' } } })\n  validate('#a#', 1, '#')\n\n  set_custom_surr({ ['_'] = { input = { '_.-()_' } } })\n  validate('_a_', 1, '_')\n\n  set_custom_surr({ ['@'] = { input = { '(@).-(@)' } } })\n  validate('@a@', 1, '@')\nend\n\nT['Custom surrounding']['works with `.-`'] = function()\n  local f = function() type_keys('sr', '#', '>') end\n\n  set_custom_surr({ ['#'] = { input = { '#().-()@' } } })\n\n  -- Using `.-` results into match with smallest width\n  validate_edit({ '##@@' }, { 1, 0 }, { '##@@' }, { 1, 0 }, f)\n  validate_edit({ '##@@' }, { 1, 1 }, { '#<>@' }, { 1, 2 }, f)\n\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  validate_edit({ '##@@' }, { 1, 0 }, { '#<>@' }, { 1, 2 }, f)\nend\n\nT['Custom surrounding']['works with empty parts in input surrounding'] = function()\n  set_custom_surr({ x = { input = { 'x()().-()x()' } } })\n  validate_edit1d('axbbbxc', 3, 'axbbbc', 2, type_keys, 'sd', 'x')\n  validate_edit1d('axbbbxc', 3, 'ax<bbb>c', 3, type_keys, 'sr', 'x', '>')\n\n  set_custom_surr({ y = { input = { '()y().-y()()' } } })\n  validate_edit1d('aybbbyc', 3, 'abbbyc', 1, type_keys, 'sd', 'y')\n  validate_edit1d('aybbbyc', 3, 'a<bbby>c', 2, type_keys, 'sr', 'y', '>')\n\n  set_custom_surr({ t = { input = { '()()t.-t()()' } } })\n  validate_edit1d('atbbbtc', 3, 'atbbbtc', 1, type_keys, 'sd', 't')\n  validate_edit1d('atbbbtc', 3, 'a<tbbbt>c', 2, type_keys, 'sr', 't', '>')\nend\n\nT['Custom surrounding']['handles function as surrounding spec'] = function()\n  -- Function which returns composed pattern\n  child.lua([[MiniSurround.config.custom_surroundings = {\n    x = { input = function(...) _G.args = {...}; return {'x()x()x'} end }\n  }]])\n\n  validate_edit1d('aaxxxbb', 2, 'aa<x>bb', 3, type_keys, 'sr', 'x', '>')\n  -- Should be called without arguments\n  eq(child.lua_get('_G.args'), {})\n\n  -- Function which returns region pair\n  child.lua([[_G.edge_lines = function()\n    local n_lines = vim.fn.line('$')\n    return {\n      left = {\n        from = { line = 1, col = 1 },\n        to = { line = 1, col = vim.fn.getline(1):len() },\n      },\n      right = {\n        from = { line = n_lines, col = 1 },\n        to = { line = n_lines, col = vim.fn.getline(n_lines):len() },\n      },\n    }\n  end]])\n  child.lua('MiniSurround.config.custom_surroundings = { e = { input = _G.edge_lines} }')\n\n  set_lines({ 'aaa', '', 'bbb', '' })\n  set_cursor(3, 0)\n  validate_edit({ 'aa', 'bb', '' }, { 2, 0 }, { '(', 'bb', ')' }, { 1, 0 }, type_keys, 'sr', 'e', ')')\n\n  -- Function which returns array of region pairs\nend\n\nT['Custom surrounding']['handles function as specification item'] = function()\n  child.lua([[_G.c_spec = {\n    '%b()',\n    function(s, init) if init > 1 then return end; return 2, s:len() end,\n    '^().*().$'\n  }]])\n  child.lua([[MiniSurround.config.custom_surroundings = { c = { input = _G.c_spec } }]])\n  validate_edit1d('aa(bb)', 3, 'aa(<bb>', 4, type_keys, 'sr', 'c', '>')\nend\n\nT['Custom surrounding']['works with special patterns'] = new_set()\n\nT['Custom surrounding']['works with special patterns']['%bxx'] = function()\n  -- Avoid hit-enter-prompt from three big error message\n  child.o.cmdheight = 40\n\n  -- `%bxx` should represent balanced character\n  set_custom_surr({ e = { input = { '%bee', '^e().*()e$' } } })\n\n  local line = 'e e e e e'\n  local f = function() type_keys('sr', 'e', '>') end\n\n  for i = 0, 2 do\n    validate_edit1d(line, i, '< > e e e', 1, f)\n  end\n  for i = 4, 6 do\n    validate_edit1d(line, i, 'e e < > e', 5, f)\n  end\n\n  for _, i in ipairs({ 3, 7, 8 }) do\n    validate_edit1d(line, i, 'e e e e e', i, f)\n  end\nend\n\nT['Custom surrounding']['works with special patterns']['x.-y'] = function()\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n\n  -- `x.-y` should match the smallest possible width\n  set_custom_surr({ x = { input = { 'e.-o', '^.().*().$' } } })\n  validate_edit1d('e e o o e o', 0, 'e < > o e o', 3, type_keys, 'sr', 'x', '>')\n  validate_edit1d('e e o o e o', 0, 'e e o o < >', 9, type_keys, '2sr', 'x', '>')\n\n  -- `x.-y` should work with `a%.-a` and `a.%-a`\n  set_custom_surr({ y = { input = { 'y()%.-()y' } } })\n  validate_edit1d('y.y yay y..y', 0, '<.> yay y..y', 1, type_keys, 'sr', 'y', '>')\n  validate_edit1d('y.y yay y..y', 0, 'y.y yay <..>', 9, type_keys, '2sr', 'y', '>')\n\n  set_custom_surr({ c = { input = { 'c().%-()c' } } })\n  validate_edit1d('c_-c c__c c+-c', 0, '<_-> c__c c+-c', 1, type_keys, 'sr', 'c', '>')\n  validate_edit1d('c_-c c__c c+-c', 0, 'c_-c c__c <+->', 11, type_keys, '2sr', 'c', '>')\n\n  -- `x.-y` should allow patterns with `+` quantifiers\n  -- To improve, force other character in between (`%f[x]x+[^x]-x+%f[^x]`)\n  set_custom_surr({ r = { input = { 'r+().-()r+' } } })\n  validate_edit1d('rraarr', 0, 'rraa<>', 5, type_keys, 'sr', 'r', '>')\n  validate_edit1d('rrrr', 0, 'rr<>', 3, type_keys, 'sr', 'r', '>')\nend\n\nT['Custom surrounding']['works with quantifiers in patterns'] = function()\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n\n  set_custom_surr({ x = { input = { '%f[x]x+%f[^x]', '^x().*()x$' } } })\n  validate_edit1d('axxaxxx', 0, 'a<>axxx', 2, type_keys, 'sr', 'x', '>')\n  validate_edit1d('axxaxxx', 0, 'axxa<x>', 5, type_keys, '2sr', 'x', '>')\nend\n\nT['Custom surrounding']['works with multibyte characters'] = function()\n  set_custom_surr({ x = { input = { 'ыы фф', '^.-() ().-$' } } })\n  validate_edit1d('ыы ыы фф фф', 9, 'ыы < > фф', 6, type_keys, 'sr', 'x', '>')\nend\n\nT['Custom surrounding']['documented examples'] = new_set()\n\nT['Custom surrounding']['documented examples']['function call with name from user input'] = function()\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  child.lua([[_G.fun_prompt = function()\n    local left_edge = vim.pesc(vim.fn.input('Function name: '))\n    return { string.format('%s+%%b()', left_edge), '^.-%(().*()%)$' }\n  end]])\n  child.lua('MiniSurround.config.custom_surroundings = { F = { input = _G.fun_prompt} }')\n\n  validate_edit1d('aa(xx) bb(xx)', 0, 'aa(xx) <xx>', 8, type_keys, 'sr', 'F', 'bb<CR>', '>')\nend\n\nT['Custom surrounding']['documented examples']['first and last buffer lines'] = function()\n  child.lua([[_G.edge_lines = function()\n    local n_lines = vim.fn.line('$')\n    return {\n      left = {\n        from = { line = 1, col = 1 },\n        to = { line = 1, col = vim.fn.getline(1):len() },\n      },\n      right = {\n        from = { line = n_lines, col = 1 },\n        to = { line = n_lines, col = vim.fn.getline(n_lines):len() },\n      },\n    }\n  end]])\n  child.lua('MiniSurround.config.custom_surroundings = { e = { input = _G.edge_lines} }')\n\n  set_lines({ 'aaa', '', 'bbb', '' })\n  set_cursor(3, 0)\n  validate_edit({ 'aa', 'bb', '' }, { 2, 0 }, { '(', 'bb', ')' }, { 1, 0 }, type_keys, 'sr', 'e', ')')\nend\n\nT['Custom surrounding']['documented examples']['edges of wide lines'] = function()\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n  child.lua([[_G.wide_line_edges = function()\n    local make_line_region_pair = function(n)\n      local left = { line = n, col = 1 }\n      local right = { line = n, col = vim.fn.getline(n):len() }\n      return { left = { from = left, to = left }, right = { from = right, to = right } }\n    end\n\n    local res = {}\n    for i = 1, vim.fn.line('$') do\n      if vim.fn.getline(i):len() > 80 then table.insert(res, make_line_region_pair(i)) end\n    end\n    return res\n  end]])\n  child.lua([[MiniSurround.config.custom_surroundings = { L = { input = _G.wide_line_edges } }]])\n\n  local lines = { string.rep('a', 80), string.rep('b', 81), string.rep('c', 80), string.rep('d', 81) }\n\n  local validate = function(start_line, target_line)\n    set_lines(lines)\n    set_cursor(start_line, 1)\n    type_keys('sr', 'L', '>')\n    local target = get_lines()[target_line]\n    eq(target:sub(1, 1), '<')\n    eq(target:sub(-1, -1), '>')\n  end\n\n  validate(1, 2)\n  validate(2, 2)\n\n  child.lua([[MiniSurround.config.search_method = 'next']])\n  validate(2, 4)\n\n  child.lua([[MiniSurround.config.n_lines = 0]])\n  set_lines(lines)\n  set_cursor(1, 1)\n  type_keys('sr', 'L', '>')\n  eq(get_lines(), lines)\nend\n\nT['Custom surrounding']['documented examples']['Lua block string'] = function()\n  child.lua([=[MiniSurround.config.custom_surroundings = {\n    s = { input = { '%[%[().-()%]%]' }, output = { left = '[[', right = ']]' } }\n  }]=])\n  validate_edit1d('aa[[bb]]cc', 2, 'aa<bb>cc', 3, type_keys, 'sr', 's', '>')\n  validate_edit1d('aa(bb)cc', 2, 'aa[[bb]]cc', 4, type_keys, 'sr', ')', 's')\nend\n\nT['Custom surrounding']['documented examples']['balanced parenthesis with big enough width'] = function()\n  child.lua([[_G.wide_parens_spec = {\n    '%b()',\n    function(s, init)\n      if init > 1 or s:len() < 5 then return end\n      return 1, s:len()\n    end,\n    '^.().*().$'\n  }]])\n  child.lua('MiniSurround.config.custom_surroundings = { p = { input = _G.wide_parens_spec } }')\n  child.lua([[MiniSurround.config.search_method = 'cover_or_next']])\n\n  validate_edit1d('() (a) (aa) (aaa)', 0, '() (a) (aa) <aaa>', 13, type_keys, 'sr', 'p', '>')\nend\n\nT['Custom surrounding']['documented examples']['handles function as specification item'] = function()\n  child.lua([[_G.c_spec = {\n    '%b()',\n    function(s, init) if init > 1 then return end; return 2, s:len() end,\n    '^().*().$'\n  }]])\n  child.lua([[MiniSurround.config.custom_surroundings = { c = { input = _G.c_spec } }]])\n  validate_edit1d('aa(bb)', 3, 'aa(<bb>', 4, type_keys, 'sr', 'c', '>')\nend\n\nT['Custom surrounding']['documented examples']['brackets with newlines'] = function()\n  child.lua([=[MiniSurround.config.custom_surroundings = {\n    x = { output = { left = '(\\n', right = '\\n)' } }\n  }]=])\n  validate_edit({ '  aaa' }, { 1, 2 }, { '  (', 'aaa', ')' }, { 1, 2 }, type_keys, 'sa', 'iw', 'x')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_tabline.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('tabline', config) end\nlocal unload_module = function() child.mini_unload('tabline') end\nlocal reload_module = function(config) unload_module(); load_module(config) end\nlocal set_lines = function(...) return child.set_lines(...) end\n--stylua: ignore end\n\n-- Make helpers\nlocal mock_miniicons = function() child.lua('require(\"mini.icons\").setup()') end\n\nlocal edit = function(name) child.cmd('edit ' .. name) end\n\nlocal edit_path = function(rel_path) child.cmd('edit tests/dir-tabline/' .. rel_path) end\n\nlocal path_sep = package.config:sub(1, 1)\n\nlocal eval_tabline = function(show_hl, show_action)\n  local res = child.lua_get('MiniTabline.make_tabline_string()')\n\n  -- Unify path separator for more robust testing\n  res = res:gsub(path_sep, '/')\n\n  if not show_hl then res = res:gsub('%%#%w+#', '') end\n\n  if not show_action then res = res:gsub('%%%d+@%w+@', ''):gsub('%%X', '') end\n\n  return res\nend\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniTabline)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniTabline'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  local has_highlight = function(group, value) expect.match(child.cmd_capture('hi ' .. group), value) end\n\n  has_highlight('MiniTablineCurrent', 'links to TabLineSel')\n  has_highlight('MiniTablineVisible', 'links to TabLineSel')\n  has_highlight('MiniTablineHidden', 'links to TabLine')\n  has_highlight('MiniTablineModifiedCurrent', 'links to StatusLine')\n  has_highlight('MiniTablineModifiedVisible', 'links to StatusLine')\n  has_highlight('MiniTablineModifiedHidden', 'links to StatusLineNC')\n  has_highlight('MiniTablineFill', 'links to Normal')\n  has_highlight('MiniTablineTabpagesection', 'links to Search')\n  has_highlight('MiniTablineTrunc', 'links to MiniTablineHidden')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniTabline.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniTabline.config.' .. field), value) end\n\n  expect_config('show_icons', true)\n  expect_config('format', vim.NIL)\n  expect_config('tabpage_section', 'left')\nend\n\nT['setup()']['respects `config` argument'] = function()\n  reload_module({ show_icons = false })\n  eq(child.lua_get('MiniTabline.config.show_icons'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ show_icons = 'a' }, 'show_icons', 'boolean')\n  expect_config_error({ format = 'a' }, 'format', 'function')\n  expect_config_error({ tabpage_section = 1 }, 'tabpage_section', 'string')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniTablineCurrent'), 'links to TabLineSel')\nend\n\nT['setup()'][\"sets proper 'tabline' option\"] = function()\n  eq(child.api.nvim_get_option('tabline'), '%!v:lua.MiniTabline.make_tabline_string()')\n  child.cmd('tabedit')\n  eq(child.api.nvim_get_option('tabline'), '%!v:lua.MiniTabline.make_tabline_string()')\nend\n\nT['setup()']['sets recommended option values'] = function()\n  eq(child.o.showtabline, 2)\n\n  -- Should set even if was previously set (it is essential for custom tabline)\n  child.o.showtabline = 1\n  reload_module()\n  eq(child.o.showtabline, 2)\nend\n\nT['make_tabline_string()'] = new_set()\n\nT['make_tabline_string()']['works'] = function()\n  child.cmd('edit aaa')\n  local buf_aaa = child.api.nvim_get_current_buf()\n  child.cmd('edit bbb')\n  local buf_bbb = child.api.nvim_get_current_buf()\n  --stylua: ignore\n  eq(\n    eval_tabline(true, true),\n    table.concat({\n      '%#MiniTablineHidden#',\n      '%', buf_aaa, '@MiniTablineSwitchBuffer@',\n      ' aaa ',\n      '%#MiniTablineCurrent#',\n      '%', buf_bbb, '@MiniTablineSwitchBuffer@',\n      ' bbb ',\n      '%X%#MiniTablineFill#',\n    })\n  )\nend\n\nT['make_tabline_string()']['works with unnamed buffers'] = function()\n  -- Labels: `*` for regular unnamed and `!` for scratch buffer\n  child.api.nvim_create_buf(true, true)\n  eq(eval_tabline(true), '%#MiniTablineCurrent# * %#MiniTablineHidden# !(2) %#MiniTablineFill#')\nend\n\nT['make_tabline_string()']['works with quickfix and location lists'] = function()\n  child.cmd('edit aaa')\n  set_lines({ 'AAA' })\n\n  -- Quickfix list\n  child.cmd('cbuffer | copen')\n  eq(eval_tabline(), ' aaa  *quickfix*(2) ')\n\n  child.cmd('q')\n\n  -- Location list\n  child.cmd('lbuffer | lopen')\n  eq(eval_tabline(), ' aaa  *location*(3) ')\nend\n\nT['make_tabline_string()']['respects `config.tabpage_section`'] = function()\n  child.o.columns = 20\n  edit('aaa')\n  child.cmd('tabedit bbb')\n\n  child.lua([[MiniTabline.config.tabpage_section = 'left']])\n  child.cmd('1tabnext')\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineTabpagesection# Tab 1/2 %#MiniTablineCurrent# aaa %#MiniTablineHidden# bbb %#MiniTablineFill#'\n  )\n  child.cmd('2tabnext')\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineTabpagesection# Tab 2/2 %#MiniTablineHidden# aaa %#MiniTablineCurrent# bbb %#MiniTablineFill#'\n  )\n\n  child.lua([[MiniTabline.config.tabpage_section = 'right']])\n  child.cmd('1tabnext')\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineCurrent# aaa %#MiniTablineHidden# bbb %#MiniTablineFill#%=%#MiniTablineTabpagesection# Tab 1/2 '\n  )\n  child.cmd('2tabnext')\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineHidden# aaa %#MiniTablineCurrent# bbb %#MiniTablineFill#%=%#MiniTablineTabpagesection# Tab 2/2 '\n  )\n\n  child.lua([[MiniTabline.config.tabpage_section = 'none']])\n  child.cmd('1tabnext')\n  eq(eval_tabline(true), '%#MiniTablineCurrent# aaa %#MiniTablineHidden# bbb %#MiniTablineFill#')\n  child.cmd('2tabnext')\n  eq(eval_tabline(true), '%#MiniTablineHidden# aaa %#MiniTablineCurrent# bbb %#MiniTablineFill#')\n\n  -- Should also use buffer local config\n  child.b.minitabline_config = { tabpage_section = 'right' }\n  child.poke_eventloop()\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineHidden# aaa %#MiniTablineCurrent# bbb %#MiniTablineFill#%=%#MiniTablineTabpagesection# Tab 2/2 '\n  )\nend\n\nT['make_tabline_string()']['shows only listed buffers'] = function()\n  child.cmd('edit aaa | edit bbb | setlocal nobuflisted | help')\n  eq(eval_tabline(), ' aaa ')\n\n  -- Can work when there is no listed buffers\n  child.cmd('%bwipeout')\n  edit('aaa')\n  child.bo.buflisted = false\n  eq(eval_tabline(), '')\n\n  child.cmd('tabe')\n  child.bo.buflisted = false\n  eq(eval_tabline(), ' Tab 2/2 ')\nend\n\nT['make_tabline_string()']['works with \"problematic\" labels'] = function()\n  -- Problematic characters: '.', '%'\n  child.cmd([[edit tests/dir-tabline/dir1/bad\\%new.file.lua]])\n\n  -- Should have double `%` to escape it and show properly\n  eq(eval_tabline(), ' bad%%new.file.lua ')\nend\n\nT['make_tabline_string()']['attaches correct highlight group'] = function()\n  child.cmd('edit aaa')\n  local buf_aaa = child.api.nvim_get_current_buf()\n  child.cmd('edit bbb')\n  local buf_bbb = child.api.nvim_get_current_buf()\n  child.cmd('vsplit | edit ccc')\n  local buf_ccc = child.api.nvim_get_current_buf()\n\n  -- Highlight groups for non-modified buffers\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineHidden# aaa %#MiniTablineVisible# bbb %#MiniTablineCurrent# ccc %#MiniTablineFill#'\n  )\n\n  child.api.nvim_buf_set_lines(buf_aaa, 0, -1, true, { 'AAA' })\n  child.api.nvim_buf_set_lines(buf_bbb, 0, -1, true, { 'BBB' })\n  child.api.nvim_buf_set_lines(buf_ccc, 0, -1, true, { 'CCC' })\n\n  -- Highlight groups for modified buffers\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineModifiedHidden# aaa %#MiniTablineModifiedVisible# bbb %#MiniTablineModifiedCurrent# ccc %#MiniTablineFill#'\n  )\nend\n\nT['make_tabline_string()']['attaches correct highlight group to unnamed buffers'] = function()\n  local buf_scratch = child.api.nvim_create_buf(true, true)\n  child.api.nvim_buf_set_lines(0, 0, -1, true, { 'NONAME' })\n  child.api.nvim_buf_set_lines(buf_scratch, 0, -1, true, { 'SCRATCH' })\n  -- Scratch buffers can't be 'modified', so don't use `*Modified*` group\n  eq(eval_tabline(true), '%#MiniTablineModifiedCurrent# * %#MiniTablineHidden# !(2) %#MiniTablineFill#')\nend\n\nT['make_tabline_string()']['respects `config.show_icons`'] = function()\n  child.cmd('edit LICENSE | edit init.lua')\n  eq(eval_tabline(true), '%#MiniTablineHidden# LICENSE %#MiniTablineCurrent# init.lua %#MiniTablineFill#')\n\n  -- If `true`, should add icons via 'mini.icons' first\n  mock_miniicons()\n  eq(eval_tabline(true), '%#MiniTablineHidden#  LICENSE %#MiniTablineCurrent#  init.lua %#MiniTablineFill#')\n\n  -- If `false`, should not add icons\n  child.lua('MiniTabline.config.show_icons = false')\n  child.cmd('bnext')\n  eq(eval_tabline(true), '%#MiniTablineCurrent# LICENSE %#MiniTablineHidden# init.lua %#MiniTablineFill#')\n\n  -- Should also use buffer local config\n  child.b.minitabline_config = { show_icons = true }\n  child.poke_eventloop()\n  eq(eval_tabline(true), '%#MiniTablineCurrent#  LICENSE %#MiniTablineHidden#  init.lua %#MiniTablineFill#')\n\n  -- Should prefer 'mini.icons' even if 'nvim-web-devicons' is present\n  child.cmd('set rtp+=tests/dir-tabline')\n  eq(eval_tabline(true), '%#MiniTablineCurrent#  LICENSE %#MiniTablineHidden#  init.lua %#MiniTablineFill#')\n\n  -- If no 'mini.icons' is set up, should fall back to 'nvim-web-devicons'\n  child.lua('_G.MiniIcons = nil')\n  reload_module()\n  eq(eval_tabline(true), '%#MiniTablineCurrent#  LICENSE %#MiniTablineHidden#  init.lua %#MiniTablineFill#')\nend\n\nT['make_tabline_string()']['respects `config.format`'] = function()\n  edit_path('dir1/aaa')\n  edit_path('dir2/aaa')\n  child.api.nvim_create_buf(true, true)\n\n  -- Should be called for all buffers and already non-unique labels\n  child.lua([[\n    _G.log = {}\n    MiniTabline.config.format = function(buf_id, label)\n      table.insert(_G.log, label)\n      return string.format('[%d] |%s| ', buf_id, label)\n    end]])\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineHidden#[1] |dir1/aaa| %#MiniTablineCurrent#[2] |dir2/aaa| %#MiniTablineHidden#[3] |!(2)| %#MiniTablineFill#'\n  )\n  local log = child.lua_get('_G.log')\n  eq({ log[1], log[2], log[3] }, { 'dir1' .. path_sep .. 'aaa', 'dir2' .. path_sep .. 'aaa', '!(2)' })\n\n  -- Should also use buffer local config\n  child.lua([[vim.b.minitabline_config = {\n    format = function(buf_id, label) return string.format('{%s} (%d)', label, buf_id) end\n  }]])\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineHidden#{dir1/aaa} (1)%#MiniTablineCurrent#{dir2/aaa} (2)%#MiniTablineHidden#{!(2)} (3)%#MiniTablineFill#'\n  )\n  child.b.minitabline_config = nil\n\n  -- Should be possible to use buffer options\n  child.lua([[MiniTabline.config.format = function(buf_id, label)\n    return ' ' .. label .. (vim.bo[buf_id].modified and ' +' or '')\n  end]])\n\n  edit_path('dir1/aaa')\n  set_lines({ 'Hello' })\n\n  eq(\n    eval_tabline(true),\n    '%#MiniTablineModifiedCurrent# dir1/aaa +%#MiniTablineHidden# dir2/aaa%#MiniTablineHidden# !(2)%#MiniTablineFill#'\n  )\n\n  -- Should treat strictly as text (no 'statusline' like constructs)\n  child.lua([[MiniTabline.config.format = function(buf_id, label) return '%#HLname#' .. label end]])\n  child.cmd('%bwipeout!')\n  edit_path('file')\n  eq(eval_tabline(true), '%#MiniTablineCurrent#%%#HLname#file%#MiniTablineFill#')\nend\n\nT['make_tabline_string()']['deduplicates named labels'] = function()\n  edit_path('dir1/aaa')\n  eq(eval_tabline(), ' aaa ')\n\n  edit_path('dir2/aaa')\n  eq(eval_tabline(), ' dir1/aaa  dir2/aaa ')\n\n  edit_path('dir1/dir_nested/aaa')\n  eq(eval_tabline(), ' dir1/aaa  dir2/aaa  dir_nested/aaa ')\n\n  -- Should deduplicate only to level where it makes a difference\n  edit_path('dir2/dir_nested/aaa')\n  eq(eval_tabline(), ' dir1/aaa  dir2/aaa  dir1/dir_nested/aaa  dir2/dir_nested/aaa ')\n\n  -- Should work for buffers without initial path\n  local expected = ' dir1/aaa  dir2/aaa  dir1/dir_nested/aaa  dir2/dir_nested/aaa '\n  local buf_id = child.api.nvim_create_buf(true, false)\n  child.api.nvim_buf_set_name(buf_id, 'aaa')\n  -- Avoid truncation by ensuring that width is large enough to also hold part of cwd\n  expected = expected .. (' %s/aaa '):format(child.fn.fnamemodify(child.fn.getcwd(), ':t'))\n  child.o.columns = #expected\n  eq(eval_tabline(), expected)\nend\n\nT['make_tabline_string()']['deduplicates independent of current working directory'] = function()\n  edit_path('dir1/aaa')\n  edit_path('dir1/dir_nested/aaa')\n\n  child.fn.chdir('tests/dir-tabline/dir1')\n  eq(eval_tabline(), ' dir1/aaa  dir_nested/aaa ')\nend\n\nT['make_tabline_string()']['deduplicates unnamed labels'] = function()\n  -- First unnamed buffer should not have id beside it\n  eq(eval_tabline(), ' * ')\n\n  -- Identifier should sequentially track all buffers\n  local buf_id = child.api.nvim_create_buf(true, false)\n  eq(eval_tabline(), ' *  *(2) ')\n\n  -- Identifiers should continue even if previous one is deleted\n  child.api.nvim_buf_delete(buf_id, { force = true })\n  eq(eval_tabline(), ' * ')\n  child.api.nvim_create_buf(true, false)\n  eq(eval_tabline(), ' *  *(3) ')\n\n  -- Should use single identifier stream for all types of unnamed labels\n  child.api.nvim_create_buf(true, true)\n  eq(eval_tabline(), ' *  *(3)  !(4) ')\n  set_lines({ 'AAA' })\n  child.cmd('cbuffer | copen')\n  eq(eval_tabline(), ' *  *(3)  !(4)  *quickfix*(5) ')\nend\n\nT['make_tabline_string()']['dedpulicates with \"problematic\" paths'] = function()\n  -- Problematic characters: '.', '%'\n  edit_path('dir1/aaa')\n  edit_path([[bad\\%new.dir/aaa]])\n  -- Should have double `%` to escape it and show properly\n  eq(eval_tabline(), ' dir1/aaa  bad%%new.dir/aaa ')\nend\n\nT['make_tabline_string()']['fits to display width'] = function()\n  child.o.columns = 15\n\n  -- Display width is bigger than needed\n  edit('aaa')\n  edit('bbb')\n  eq(eval_tabline(), ' aaa  bbb ')\n\n  -- Display width is exactly as needed\n  edit('ccc')\n  eq(eval_tabline(), ' aaa  bbb  ccc ')\n\n  -- Display width is smaller than needed\n  edit('ddd')\n  eq(eval_tabline(), ' bbb  ccc  ddd ')\nend\n\nT['make_tabline_string()']['fits to display width in case of multiple tabpages'] = function()\n  child.o.columns = 20\n  edit('aaaaaaaa')\n  child.cmd('tabedit')\n  edit('bbbbbbbb')\n\n  reload_module({ tabpage_section = 'left' })\n  child.cmd('1tabnext')\n  eq(eval_tabline(), ' Tab 1/2 aaaaa  bbbb')\n  child.cmd('2tabnext')\n  eq(eval_tabline(), ' Tab 2/2   bbbbbbbb ')\n\n  reload_module({ tabpage_section = 'right' })\n  child.cmd('1tabnext')\n  eq(eval_tabline(), 'aaaaa  bbbb%= Tab 1/2 ')\n  child.cmd('2tabnext')\n  eq(eval_tabline(), '  bbbbbbbb %= Tab 2/2 ')\n\n  reload_module({ tabpage_section = 'none' })\n  child.cmd('1tabnext')\n  eq(eval_tabline(), ' aaaaaaaa  bbbbbbbb ')\n  child.cmd('2tabnext')\n  eq(eval_tabline(), ' aaaaaaaa  bbbbbbbb ')\nend\n\nT['make_tabline_string()']['properly centers current buffer'] = function()\n  local get_buf_name = function(buf_id)\n    buf_id = buf_id or 0\n    buf_id = buf_id == 0 and child.api.nvim_get_current_buf() or buf_id\n    return child.fn.bufname(buf_id)\n  end\n\n  child.o.columns = 25\n  vim.tbl_map(edit, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg' })\n\n  -- Should not move \"left\" buffers to center\n  edit('aaa')\n  eq(get_buf_name(), 'aaa')\n  eq(eval_tabline(), ' aaa  bbb  ccc  ddd  eee ')\n\n  edit('bbb')\n  eq(get_buf_name(), 'bbb')\n  eq(eval_tabline(), ' aaa  bbb  ccc  ddd  eee ')\n\n  -- Should center right end (which is ' ') of \"middle\" buffers\n  edit('ccc')\n  eq(eval_tabline(), 'aa  bbb  ccc  ddd  eee  f')\n  edit('ddd')\n  eq(eval_tabline(), 'bb  ccc  ddd  eee  fff  g')\n\n  -- Should not move \"right\" buffers to center\n  edit('eee')\n  eq(eval_tabline(), ' ccc  ddd  eee  fff  ggg ')\n  edit('fff')\n  eq(eval_tabline(), ' ccc  ddd  eee  fff  ggg ')\n  edit('ggg')\n  eq(eval_tabline(), ' ccc  ddd  eee  fff  ggg ')\n\n  -- Should pick center buffer only from those shown in tabline\n  child.cmd('help')\n  eq(eval_tabline(), ' ccc  ddd  eee  fff  ggg ')\nend\n\nT['make_tabline_string()']['properly truncates left and right tabs'] = function()\n  local validate = function(columns, strings)\n    local cache_columns = child.o.columns\n    child.o.columns = columns\n    eq(eval_tabline(true), table.concat(strings))\n    child.o.columns = cache_columns\n  end\n\n  for _, name in ipairs({ 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' }) do\n    edit(name)\n  end\n  edit('ccc')\n\n  -- Should preserve highlight group from truncated tabs (even whitespace)\n  validate(22, {\n    '%#MiniTablineHidden# ',\n    '%#MiniTablineHidden# bbb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# eee ',\n    '%#MiniTablineHidden# ',\n    '%#MiniTablineFill#',\n  })\n  -- For odd display width \"actual center\" is between second to last and last\n  -- characters of center label\n  validate(21, {\n    '%#MiniTablineHidden# ',\n    '%#MiniTablineHidden# bbb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# eee ',\n    '%#MiniTablineFill#',\n  })\n  validate(20, {\n    '%#MiniTablineHidden# bbb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# eee ',\n    '%#MiniTablineFill#',\n  })\n  validate(19, {\n    '%#MiniTablineHidden# bbb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# eee',\n    '%#MiniTablineFill#',\n  })\n  validate(18, {\n    '%#MiniTablineHidden#bbb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# eee',\n    '%#MiniTablineFill#',\n  })\n  validate(17, {\n    '%#MiniTablineHidden#bbb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# ee',\n    '%#MiniTablineFill#',\n  })\n  validate(16, {\n    '%#MiniTablineHidden#bb %#MiniTablineCurrent# ccc ',\n    '%#MiniTablineHidden# ddd %#MiniTablineHidden# ee',\n    '%#MiniTablineFill#',\n  })\nend\n\nT['make_tabline_string()']['properly truncates in edge cases'] = function()\n  -- Too wide center label\n  edit('aaaaaaaaaa')\n  edit('bbbbbbbbbb')\n  child.o.columns = 15\n\n  edit('aaaaaaaaaa')\n  eq(eval_tabline(), 'aaaaaaa  bbbbbb')\nend\n\nT['make_tabline_string()']['can show truncation characters'] = function()\n  child.o.columns = 15\n  for _, name in ipairs({ 'aaa', 'bbb', 'ccc', 'ddd', 'eee' }) do\n    edit(name)\n  end\n  edit('aaa')\n\n  -- Should show nothing extra if 'list' is not enabled (as by default)\n  eq(eval_tabline(), ' aaa  bbb  ccc ')\n\n  child.o.list = true\n  child.o.listchars = 'precedes:<,extends:>'\n  eq(eval_tabline(), ' aaa  bbb  ccc>')\n  edit('bbb')\n  -- - Should show if edge tab is shown but not in full\n  eq(eval_tabline(), '<a  bbb  ccc  >')\n  edit('ccc')\n  eq(eval_tabline(), '<b  ccc  ddd  >')\n  edit('ddd')\n  eq(eval_tabline(), '<ccc  ddd  eee ')\n  edit('eee')\n  eq(eval_tabline(), '<ccc  ddd  eee ')\n\n  -- Should use special highlight group\n  edit('ccc')\n  local ref_tabline_with_hl = '%#MiniTablineTrunc#<'\n    .. '%#MiniTablineHidden#b %#MiniTablineCurrent# ccc %#MiniTablineHidden# ddd %#MiniTablineHidden# '\n    .. '%#MiniTablineTrunc#>'\n    .. '%#MiniTablineFill#'\n  eq(eval_tabline(true), ref_tabline_with_hl)\n\n  -- Should be properly shown if there is tabpage section\n  child.o.columns = 24\n  child.cmd('tabedit ccc')\n  eq(eval_tabline(true), '%#MiniTablineTabpagesection# Tab 2/2 ' .. ref_tabline_with_hl)\n  child.cmd('close')\n\n  -- Should react to 'list' and/or 'listchars' changes\n  child.o.columns = 15\n  child.o.listchars = 'precedes:^,extends:$'\n  edit('ccc')\n  eq(eval_tabline(), '^b  ccc  ddd  $')\n\n  child.o.list = false\n  eq(eval_tabline(), 'bb  ccc  ddd  e')\n\n  -- Uses global value of 'list' and 'listchars'\n  child.go.list, child.wo.list = true, false\n  child.go.listchars, child.wo.listchars = 'precedes:<,extends:>', 'precedes:^,extends:$'\n  eq(eval_tabline(), '<b  ccc  ddd  >')\n\n  -- Works with multibyte characters\n  child.cmd('%bwipeout')\n  for _, name in ipairs({ 'ыыы', 'ффф', 'ййй', 'ццц', 'яяя' }) do\n    edit(name)\n  end\n  edit('ййй')\n  eq(eval_tabline(), '<ф  ййй  ццц  >')\n\n  -- Works when there is no listed buffers\n  child.cmd('%bwipeout')\n  child.bo.buflisted = false\n  eq(eval_tabline(), '')\n\n  child.cmd('tabe')\n  child.bo.buflisted = false\n  eq(eval_tabline(), ' Tab 2/2 ')\nend\n\nT['make_tabline_string()'][\"properly uses 'listchars' option to get truncation characters\"] = function()\n  child.o.columns = 15\n  child.o.list = true\n  for _, name in ipairs({ 'aaa', 'bbb', 'ccc', 'ddd', 'eee' }) do\n    edit(name)\n  end\n  edit('ccc')\n\n  local validate = function(listchars, ref_tabline)\n    child.o.listchars = listchars\n    eq(eval_tabline(), ref_tabline)\n  end\n\n  -- None of relevant fields\n  validate('', 'bb  ccc  ddd  e')\n  validate('tab:> ', 'bb  ccc  ddd  e')\n\n  -- Only single\n  validate('precedes:<', '<b  ccc  ddd  e')\n  validate('extends:>', 'bb  ccc  ddd  >')\n\n  -- Multibyte\n  validate('extends:…,precedes:•', '•b  ccc  ddd  …')\n  validate('extends:…,nbsp:␣,precedes:•', '•b  ccc  ddd  …')\n\n  -- Problematic characters\n  validate('extends:,,precedes:,', ',b  ccc  ddd  ,')\n  child.o.listchars = 'extends:%,precedes:%'\n  local ref_tabline = '%#MiniTablineTrunc#%%'\n    .. '%#MiniTablineHidden#b %#MiniTablineCurrent# ccc %#MiniTablineHidden# ddd %#MiniTablineHidden# '\n    .. '%#MiniTablineTrunc#%%'\n    .. '%#MiniTablineFill#'\n  eq(eval_tabline(true), ref_tabline)\nend\n\nlocal validate_columns = function(columns, string)\n  local cache_columns = child.o.columns\n  child.o.columns = columns\n  eq(eval_tabline(), string)\n  child.o.columns = cache_columns\nend\n\nT['make_tabline_string()']['handles multibyte characters in labels'] = function()\n  for _, name in ipairs({ 'ббб', 'ввв', 'ггг', 'ддд', 'жжж', 'ззз' }) do\n    edit(name)\n  end\n  edit('ггг')\n\n  validate_columns(20, ' ввв  ггг  ддд  жжж ')\n  validate_columns(19, ' ввв  ггг  ддд  жжж')\n  validate_columns(18, 'ввв  ггг  ддд  жжж')\n  validate_columns(17, 'ввв  ггг  ддд  жж')\n  validate_columns(16, 'вв  ггг  ддд  жж')\n  validate_columns(15, 'вв  ггг  ддд  ж')\nend\n\nT['make_tabline_string()']['handles multibyte icons'] = function()\n  mock_miniicons()\n\n  edit('LICENSE')\n  edit('aaaa.lua')\n  edit('bbbb.txt')\n\n  child.o.columns = 15\n  eq(eval_tabline(), 'ua  󰦪 bbbb.txt ')\n\n  edit('aaaa.lua')\n  eq(eval_tabline(), 'aaa.lua  󰦪 bbbb')\n\n  validate_columns(16, 'aaa.lua  󰦪 bbbb.')\n  validate_columns(17, 'aaaa.lua  󰦪 bbbb.')\n  validate_columns(18, 'aaaa.lua  󰦪 bbbb.t')\n  validate_columns(19, ' aaaa.lua  󰦪 bbbb.t')\n  validate_columns(20, ' aaaa.lua  󰦪 bbbb.tx')\n  validate_columns(21, '󰢱 aaaa.lua  󰦪 bbbb.tx')\nend\n\nT['make_tabline_string()']['respects `vim.{g,b}.minitabline_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minitabline_disable = true\n    eq(eval_tabline(), '')\n  end,\n})\n\nT['default_format()'] = new_set()\n\nT['default_format()']['works'] = function()\n  child.lua([[MiniTabline.config.format = function(buf_id, label)\n    return '_' .. MiniTabline.default_format(buf_id, label) .. '_'\n  end]])\n  edit('LICENSE')\n  edit('init.lua')\n\n  eq(eval_tabline(true), '%#MiniTablineHidden#_ LICENSE _%#MiniTablineCurrent#_ init.lua _%#MiniTablineFill#')\n\n  mock_miniicons()\n  eq(eval_tabline(true), '%#MiniTablineHidden#_  LICENSE _%#MiniTablineCurrent#_  init.lua _%#MiniTablineFill#')\n\n  -- Should respect `config.use_icons`\n  child.lua('MiniTabline.config.show_icons = false')\n  eq(eval_tabline(true), '%#MiniTablineHidden#_ LICENSE _%#MiniTablineCurrent#_ init.lua _%#MiniTablineFill#')\nend\n\nT['default_format()']['uses full buffer name to compute icon with \"mini.icons\"'] = function()\n  child.lua([[\n    require(\"mini.icons\").setup()\n    _G.icons_log = {}\n    local orig_get = MiniIcons.get\n    MiniIcons.get = function(...)\n      table.insert(_G.icons_log, { ... })\n      return orig_get(...)\n    end\n  ]])\n\n  edit('LICENSE')\n  eq(child.lua_get('_G.icons_log'), { { 'file', child.api.nvim_buf_get_name(0) } })\nend\n\nT['default_format()']['uses buffer basename to compute icon with \"nvim-web-devicons\"'] = function()\n  child.cmd('set rtp+=tests/dir-tabline')\n  edit('LICENSE')\n  eq(child.lua_get('_G.devicons_args'), { filename = 'LICENSE', options = { default = true } })\nend\n\n-- Integration tests ==========================================================\nT['Screen'] = new_set()\n\nT['Screen']['works'] = function()\n  child.set_size(5, 40)\n  child.cmd('edit aaa | edit bbb | edit ccc')\n\n  -- Initial screenshot\n  child.cmd('edit aaa')\n  child.expect_screenshot()\n\n  -- Change of current buffer\n  child.cmd('edit bbb')\n  child.expect_screenshot()\n\n  -- Modified other buffer\n  set_lines({ 'aaa' })\n  child.cmd('edit ccc')\n  child.expect_screenshot()\n\n  -- Multiple tabpages\n  child.cmd('tabedit ddd')\n  child.expect_screenshot()\n\n  -- Other visible buffer\n  child.cmd('hi MiniTablineVisible ctermbg=1')\n  child.cmd('vsplit eee')\n  child.expect_screenshot()\nend\n\nT['Mouse click'] = new_set()\n\nlocal click = function(column) child.api.nvim_input_mouse('left', 'press', '', 0, 0, column) end\n\nT['Mouse click']['works'] = function()\n  edit('aaa')\n  edit('bbb')\n  eq(child.fn.bufname(), 'bbb')\n  eq(eval_tabline(true), '%#MiniTablineHidden# aaa %#MiniTablineCurrent# bbb %#MiniTablineFill#')\n\n  -- Clicking within tab should result in buffer becoming current while\n  -- updating highlight\n  click(0)\n  eq(child.fn.bufname(), 'aaa')\n  eq(eval_tabline(true), '%#MiniTablineCurrent# aaa %#MiniTablineHidden# bbb %#MiniTablineFill#')\n\n  -- More granular checks for tabline ' aaa  bbb '\n  click(5)\n  eq(child.fn.bufname(), 'bbb')\n  click(4)\n  eq(child.fn.bufname(), 'aaa')\n\n  click(6)\n  eq(child.fn.bufname(), 'bbb')\n  click(3)\n  eq(child.fn.bufname(), 'aaa')\n\n  -- Clicking to the right of actual label shouldn't do anything\n  click(9)\n  eq(child.fn.bufname(), 'bbb')\n  edit('aaa')\n\n  eq(child.fn.bufname(), 'aaa')\n  click(10)\n  eq(child.fn.bufname(), 'aaa')\nend\n\nT['Mouse click']['works in case of multiple tabpages'] = function()\n  edit('aaa')\n  child.cmd('tabedit bbb')\n\n  reload_module({ tabpage_section = 'left' })\n  eq(child.fn.bufname(), 'bbb')\n  eq(eval_tabline(), ' Tab 2/2  aaa  bbb ')\n\n  -- Clicking on tabpage section shouldn't do anything\n  click(0)\n  eq(child.fn.bufname(), 'bbb')\n  eq(eval_tabline(), ' Tab 2/2  aaa  bbb ')\n\n  -- Clicking between right label and tabpage section shouldn't do anything\n  child.o.columns = 40\n  reload_module({ tabpage_section = 'right' })\n  edit('aaa')\n  eq(child.fn.bufname(), 'aaa')\n  eq(eval_tabline(), ' aaa  bbb %= Tab 2/2 ')\n\n  click(20)\n  eq(child.fn.bufname(), 'aaa')\n  eq(eval_tabline(), ' aaa  bbb %= Tab 2/2 ')\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_test.lua",
    "content": "-- This is intended to mostly cover general API. In a sense, all tests in this\n-- plugin also test 'mini.test'.\nlocal helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set, finally = MiniTest.new_set, MiniTest.finally\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('test', config) end\nlocal unload_module = function() child.mini_unload('test') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\n--stylua: ignore end\n\n-- TODO: Remove after compatibility with Neovim=0.9 is dropped\nlocal islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist\n\nlocal get_latest_message = function() return child.cmd_capture('1messages') end\n\nlocal get_ref_path = function(name) return string.format('tests/dir-test/%s', name) end\n\nlocal get_current_all_cases = function()\n  -- Encode functions inside child. Works only for \"simple\" functions.\n  local command = [[vim.tbl_map(function(case)\n    case.hooks.pre = vim.tbl_map(string.dump, case.hooks.pre)\n    case.hooks.post = vim.tbl_map(string.dump, case.hooks.post)\n    case.test = string.dump(case.test)\n    return case\n  end, MiniTest.current.all_cases)]]\n  local res = child.lua_get(command)\n\n  -- Decode functions in current process\n  res = vim.tbl_map(function(case)\n    case.hooks.pre = vim.tbl_map(loadstring, case.hooks.pre)\n    case.hooks.post = vim.tbl_map(loadstring, case.hooks.post)\n    case.test = loadstring(case.test)\n    return case\n  end, res)\n\n  -- Update array to enable getting element by last entry of `desc` field\n  return setmetatable(res, {\n    __index = function(t, key)\n      return vim.tbl_filter(function(case_output)\n        local last_desc = case_output.desc[#case_output.desc]\n        return last_desc == key\n      end, t)[1]\n    end,\n  })\nend\n\nlocal testrun_ref_file = function(name)\n  local find_files_command = string.format([[_G.find_files = function() return { '%s' } end]], get_ref_path(name))\n  child.lua(find_files_command)\n  child.lua([[\n    _G.reporter_log = {}\n    _G.report_in_log = {\n      start = function(...) table.insert(_G.reporter_log, { 'start', ... }) end,\n      update = function(...)\n        table.insert(_G.reporter_log, { 'update', vim.deepcopy(MiniTest.current.case.exec.state), ... })\n      end,\n      finish = function(...) table.insert(_G.reporter_log, { 'finish', ... }) end,\n    }\n  ]])\n  child.lua([[MiniTest.run({ collect = { find_files = _G.find_files }, execute = { reporter = _G.report_in_log } })]])\n  return get_current_all_cases()\nend\n\nlocal filter_by_desc = function(cases, id, value)\n  return vim.tbl_filter(function(c) return c.desc[id] == value end, cases)\nend\n\nlocal expect_all_state = function(cases, state)\n  local res = true\n  for _, c in ipairs(cases) do\n    if type(c.exec) ~= 'table' or c.exec.state ~= state then res = false end\n  end\n\n  eq(res, true)\nend\n\n-- Time constants\nlocal terminal_wait = helpers.get_time_const(500)\n\n-- Output test set\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      -- Mock UI so that default reporter is as if used interactively\n      child.lua('vim.api.nvim_list_uis = function() return { 1 } end')\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniTest)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniTest'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniTestFail'), 'gui=bold')\n  expect.match(child.cmd_capture('hi MiniTestPass'), 'gui=bold')\n  expect.match(child.cmd_capture('hi MiniTestEmphasis'), 'gui=bold')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniTest.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniTest.config.' .. field), value) end\n\n  expect_config('collect.emulate_busted', true)\n  eq(child.lua_get('type(_G.MiniTest.config.collect.find_files)'), 'function')\n  eq(child.lua_get('type(_G.MiniTest.config.collect.filter_cases)'), 'function')\n  expect_config('execute.reporter', vim.NIL)\n  expect_config('execute.stop_on_error', false)\n  expect_config('script_path', 'scripts/minitest.lua')\n  expect_config('silent', false)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ script_path = 'a' })\n  eq(child.lua_get('MiniTest.config.script_path'), 'a')\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ collect = 'a' }, 'collect', 'table')\n  expect_config_error({ collect = { emulate_busted = 'a' } }, 'collect.emulate_busted', 'boolean')\n  expect_config_error({ collect = { find_files = 'a' } }, 'collect.find_files', 'function')\n  expect_config_error({ collect = { filter_cases = 'a' } }, 'collect.filter_cases', 'function')\n  expect_config_error({ execute = 'a' }, 'execute', 'table')\n  expect_config_error({ execute = { reporter = 'a' } }, 'execute.reporter', 'function')\n  expect_config_error({ execute = { stop_on_error = 'a' } }, 'execute.stop_on_error', 'boolean')\n  expect_config_error({ script_path = 1 }, 'script_path', 'string')\n  expect_config_error({ silent = 1 }, 'silent', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniTestFail'), 'gui=bold')\n  expect.match(child.cmd_capture('hi MiniTestPass'), 'gui=bold')\n  expect.match(child.cmd_capture('hi MiniTestEmphasis'), 'gui=bold')\nend\n\nT['new_set()'] = new_set()\n\nT['new_set()']['tracks field order'] = function()\n  local res = testrun_ref_file('testref_new-set.lua')\n\n  -- Check order\n  local order_cases = vim.tbl_map(\n    function(c) return c.desc[#c.desc] end,\n    vim.tbl_filter(function(c) return c.desc[2] == 'order' end, res)\n  )\n  eq(order_cases, { 'From initial call', 'zzz First added', 'aaa Second added', 1 })\nend\n\nT['new_set()']['stores `opts`'] = function()\n  local opts = { parametrize = { { 'a' } }, n_retry = 10 }\n  child.lua([[_G.set = MiniTest.new_set(...)]], { opts })\n  eq(child.lua_get([[getmetatable(_G.set).opts]]), opts)\nend\n\nT['case helpers'] = new_set()\n\nT['case helpers']['work'] = function()\n  local res = testrun_ref_file('testref_case-helpers.lua')\n\n  -- `finally()`\n  eq(res['finally() with error; check'].exec.state, 'Pass')\n  eq(res['finally() no error; check'].exec.state, 'Pass')\n  eq(child.lua_get('_G.finally_log'), { 'one', 'two' })\n\n  -- `skip()`\n  eq(res['skip(); no message'].exec.state, 'Pass with notes')\n  eq(res['skip(); no message'].exec.notes, { 'Skip test' })\n\n  eq(res['skip(); with message'].exec.state, 'Pass with notes')\n  eq(res['skip(); with message'].exec.notes, { 'This is a custom skip message' })\n\n  eq(res['skip() can be called from helper'].exec.notes, { 'Skip from helper' })\n\n  eq(res['skip one'].exec.state, 'Pass with notes')\n  eq(res['skip one'].exec.notes, { 'Should skip case' })\n  eq(res['skip two'].exec.state, 'Pass with notes')\n  eq(res['skip two'].exec.notes, { 'Should skip case' })\n\n  eq(res['skip() in other hooks'].exec.state, 'Fail')\n  eq(res['skip() in other hooks'].exec.notes, {})\n\n  -- `add_note()`\n  eq(res['add_note() case'].exec.state, 'Pass with notes')\n  eq(res['add_note() case'].exec.notes, { 'pre_once', 'pre_case', 'test case', 'post_case', 'post_once' })\nend\n\nT['run()'] = new_set()\n\nT['run()']['respects `opts` argument'] = function()\n  child.lua('MiniTest.run({ collect = { find_files = function() return {} end } })')\n  eq(#get_current_all_cases(), 0)\n\n  -- Should also use buffer local config\n  local general_file = get_ref_path('testref_general.lua')\n  local command = string.format(\n    [[vim.b.minitest_config = { collect = { find_files = function() return { '%s' } end } }]],\n    general_file\n  )\n  child.lua(command)\n  child.lua('MiniTest.run()')\n  eq(#get_current_all_cases() > 0, true)\nend\n\nT['run()']['tries to execute script if no arguments are supplied'] = function()\n  local validate = function()\n    local cache_local_config = child.b.minitest_config\n\n    eq(child.lua_get('_G.custom_script_result'), vim.NIL)\n    child.lua('MiniTest.run()')\n    eq(child.lua_get('_G.custom_script_result'), 'This actually ran')\n\n    -- Global and buffer local config should be restored\n    eq(child.lua_get('type(MiniTest.config.aaa)'), 'nil')\n    eq(child.b.minitest_config, cache_local_config)\n  end\n\n  local script_path = get_ref_path('testref_custom-script.lua')\n  child.lua('MiniTest.config.script_path = ' .. vim.inspect(script_path))\n  validate()\n\n  -- Should also use buffer local config\n  child.lua([[MiniTest.config.script_path = '']])\n  child.lua('_G.custom_script_result = nil')\n  child.b.minitest_config = { script_path = script_path }\n  validate()\nend\n\nT['run()']['handles `parametrize`'] = function()\n  local res = testrun_ref_file('testref_run-parametrize.lua')\n  eq(#res, 10)\n\n  local short_res = vim.tbl_map(function(c)\n    local desc = vim.list_slice(c.desc, 2)\n    return { args = c.args, desc = desc, passed_args = c.exec.fails[1]:match('Passed arguments: (.-)\\n  Traceback.*$') }\n  end, res)\n\n  eq(short_res[1], { args = { 'a' }, desc = { 'parametrize', 'first level' }, passed_args = '\"a\"' })\n  eq(short_res[2], { args = { 'b' }, desc = { 'parametrize', 'first level' }, passed_args = '\"b\"' })\n\n  eq(short_res[3], { args = { 'a', 1 }, desc = { 'parametrize', 'nested', 'test' }, passed_args = '\"a\", 1' })\n  eq(short_res[4], { args = { 'a', 2 }, desc = { 'parametrize', 'nested', 'test' }, passed_args = '\"a\", 2' })\n  eq(short_res[5], { args = { 'b', 1 }, desc = { 'parametrize', 'nested', 'test' }, passed_args = '\"b\", 1' })\n  eq(short_res[6], { args = { 'b', 2 }, desc = { 'parametrize', 'nested', 'test' }, passed_args = '\"b\", 2' })\n\n  --stylua: ignore start\n  eq(short_res[7],  { args = { 'a', 'a', 1, 1 }, desc = { 'multiple args', 'nested', 'test' }, passed_args = '\"a\", \"a\", 1, 1' })\n  eq(short_res[8],  { args = { 'a', 'a', 2, 2 }, desc = { 'multiple args', 'nested', 'test' }, passed_args = '\"a\", \"a\", 2, 2' })\n  eq(short_res[9],  { args = { 'b', 'b', 1, 1 }, desc = { 'multiple args', 'nested', 'test' }, passed_args = '\"b\", \"b\", 1, 1' })\n  eq(short_res[10], { args = { 'b', 'b', 2, 2 }, desc = { 'multiple args', 'nested', 'test' }, passed_args = '\"b\", \"b\", 2, 2' })\n  --stylua: ignore end\nend\n\nT['run()']['validates `parametrize`'] = function()\n  expect.error(\n    function() testrun_ref_file('testref_run-parametrize-error.lua') end,\n    [[`parametrize` should have only tables. Got \"a\"]]\n  )\nend\n\nT['run()']['handles `data`'] = function()\n  local res = testrun_ref_file('testref_run-data.lua')\n  local short_res = vim.tbl_map(function(c) return { data = c.data, desc = vim.list_slice(c.desc, 2) } end, res)\n\n  eq(#short_res, 2)\n  eq(short_res[1], {\n    data = { a = 1, b = 2 },\n    desc = { 'data', 'first level' },\n  })\n  eq(short_res[2], {\n    data = { a = 10, b = 2, c = 30 },\n    desc = { 'data', 'nested', 'should override' },\n  })\nend\n\nT['run()']['handles `hooks`'] = function()\n  local res = testrun_ref_file('testref_run-hooks.lua')\n  --stylua: ignore\n  eq(child.lua_get('_G.log'), {\n    -- Test order\n    \"pre_once_1\",\n    \"pre_case_1\", \"First level test\", \"post_case_1\",\n    \"pre_once_2\",\n    \"pre_case_1\", \"pre_case_2\", \"Nested #1\", \"post_case_2\", \"post_case_1\",\n    \"pre_case_1\", \"pre_case_2\", \"Nested #2\", \"post_case_2\", \"post_case_1\",\n    \"post_once_2\",\n    \"post_once_1\",\n\n    -- Test skip case on hook error. All hooks should still be called.\n    \"pre_case_3\", \"post_case_3\", \"post_once_3\",\n    \"pre_once_4\", \"post_case_4\", \"post_once_4\",\n\n    -- Using same function in `*_once` hooks should still lead to its multiple\n    -- execution.\n    \"Same function\",\n    \"Same function\",\n    \"Same hook test\",\n    \"Same function\",\n    \"Same function\",\n  })\n\n  -- Skipping test case due to hook errors should add a note\n  expect.match(filter_by_desc(res, 2, 'skip_case_on_hook_error #1')[1].exec.notes[1], '^Skip.*error.*hooks')\nend\n\nT['run()']['handles `n_retry`'] = function()\n  local res = testrun_ref_file('testref_run-n_retry.lua')\n  --stylua: ignore\n  local ref_log = {\n    'default',\n    'should override', 'should override',\n    'more override', 'more override', 'more override',\n    'first success #1', 'first success #2', 'first success #3',\n    'latest error #1', 'latest error #2', 'latest error #3',\n\n    -- Retries should NOT be applied separately to hooks\n    'no retry pre_once', 'no retry pre_case', 'no retry post_case', 'no retry post_once',\n\n    -- Should retry failed case with all its `pre_case` and `post_case`.\n    -- The `pre_once` and `post_once` should still be executed only once.\n    'outer pre_once', 'inner pre_once',\n    'outer pre_case', 'inner pre_case', 'hook exec case', 'inner post_case', 'outer post_case',\n    'outer pre_case', 'inner pre_case', 'hook exec case', 'inner post_case', 'outer post_case',\n    'inner post_once', 'outer post_once',\n\n    'screenshot', 'screenshot',\n    'skip',\n    'parameter 1', 'parameter 1', 'parameter 2', 'parameter 2'\n  }\n  eq(child.lua_get('_G.log'), ref_log)\n\n  -- Should track relevant `n_retry` value\n  eq(vim.tbl_map(function(x) return x.n_retry end, res), { 1, 2, 3, 10, 3, 2, 2, 2, 2, 2, 2, 2 })\n\n  -- Should report latest (and only latest) error among all retries\n  local latest_error_case_fails = filter_by_desc(res, 2, 'reports latest error')[1].exec.fails\n  eq(#latest_error_case_fails, 1)\n  expect.match(latest_error_case_fails[1], 'Error #3')\n\n  -- Should report hook fails even if `n_retry > 1`\n  eq(#filter_by_desc(res, 2, 'does not retry hooks')[1].exec.fails, 4)\n\n  -- Should not generate new screenshots after first try\n  eq(filter_by_desc(res, 2, 'screenshot number')[1].exec.notes, {})\n\n  -- Should update state on every retry\n  local update_case_num\n  for i, case in ipairs(res) do\n    if case.desc[2] == 'updates state on every retry' then update_case_num = i end\n  end\n  child.lua('_G.target_case_num = ' .. (update_case_num or #res))\n  local updates_of_target_case = child.lua([[\n    local res = {}\n    for _, t in ipairs(_G.reporter_log) do\n      if t[1] == 'update' and t[3] == target_case_num then table.insert(res, t) end\n    end\n    return res\n  ]])\n  local ref_updates = {\n    { 'update', \"Executing 'pre' hook #1\", 12 },\n    { 'update', \"Executing 'pre' hook #2\", 12 },\n    { 'update', 'Executing test', 12 },\n    { 'update', \"Executing 'post' hook #1\", 12 },\n    -- Method `update()` of reporter should be called on every retry\n    { 'update', \"Executing 'pre' hook #2\", 12 },\n    { 'update', 'Executing test', 12 },\n    { 'update', \"Executing 'post' hook #1\", 12 },\n    { 'update', \"Executing 'post' hook #2\", 12 },\n    { 'update', 'Fail', 12 },\n  }\n  eq(updates_of_target_case, ref_updates)\nend\n\nT['run()']['respects `stop_on_error` after all retries'] = function()\n  local path = get_ref_path('testref_run-n_retry-stop_on_error.lua')\n  local command = string.format([[_G.cases = MiniTest.collect({ find_files = function() return { '%s' } end })]], path)\n  child.lua(command)\n\n  -- Should indeed stop on first \"final\" error (i.e. ignore errors from tries)\n  child.lua('MiniTest.execute(_G.cases, { stop_on_error = true })')\n  eq(child.lua_get('_G.log'), { 'try #1', 'try #2', 'try #3', 'continue' })\n  eq(child.lua_get('_G.cases[3].exec'), vim.NIL)\nend\n\nT['run()']['appends traceback to fails'] = function()\n  local res = testrun_ref_file('testref_general.lua')\n  local ref_path = get_ref_path('testref_general.lua')\n  local n = 0\n  for _, case in ipairs(res) do\n    if #case.exec.fails > 0 then\n      expect.match(case.exec.fails[1], 'Traceback:%s+' .. vim.pesc(ref_path))\n      n = n + 1\n    end\n  end\n\n  if n == 0 then error('No actual fails was tested', 0) end\nend\n\nT['run_file()'] = new_set()\n\nT['run_file()']['works'] = function()\n  child.lua([[MiniTest.run_file(...)]], { get_ref_path('testref_run.lua') })\n  local last_desc =\n    child.lua_get([[vim.tbl_map(function(case) return case.desc[#case.desc] end, MiniTest.current.all_cases)]])\n  eq(last_desc, { 'run_at_location()', 'extra case' })\nend\n\nT['run_file()']['normalizes input path'] = function()\n  child.lua('MiniTest.run_file(...)', { './' .. get_ref_path('testref_run.lua') })\n  eq(child.lua_get('MiniTest.current.all_cases[1].desc[1]'):gsub('\\\\', '/'), 'tests/dir-test/testref_run.lua')\nend\n\nT['run_at_location()'] = new_set()\n\nT['run_at_location()']['works with non-default input'] = new_set({ parametrize = { { 3 }, { 4 }, { 5 } } }, {\n  function(line)\n    local path = get_ref_path('testref_run.lua')\n    local command = string.format([[MiniTest.run_at_location({ file = '%s', line = %s })]], path, line)\n    child.lua(command)\n\n    local all_cases = get_current_all_cases()\n    eq(#all_cases, 1)\n    eq(all_cases[1].desc, { path, 'run_at_location()' })\n  end,\n})\n\nT['run_at_location()']['uses cursor position by default'] = function()\n  local path = get_ref_path('testref_run.lua')\n  child.cmd('edit ' .. path)\n  set_cursor(4, 0)\n  child.lua('MiniTest.run_at_location()')\n\n  local all_cases = get_current_all_cases()\n  eq(#all_cases, 1)\n  local desc = all_cases[1].desc\n  eq(desc[1]:gsub('\\\\', '/'), path)\n  eq(desc[2], 'run_at_location()')\nend\n\nlocal collect_general = function()\n  local path = get_ref_path('testref_general.lua')\n  local command = string.format([[_G.cases = MiniTest.collect({ find_files = function() return { '%s' } end })]], path)\n  child.lua(command)\nend\n\nT['collect()'] = new_set()\n\nT['collect()']['works'] = function()\n  child.lua('_G.cases = MiniTest.collect()')\n\n  -- TODO: Remove after compatibility with Neovim=0.9 is dropped\n  child.lua([[_G.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist]])\n\n  -- Should return array of cases\n  eq(child.lua_get('_G.islist(_G.cases)'), true)\n\n  local keys = child.lua_get('vim.tbl_keys(_G.cases[1])')\n  table.sort(keys)\n  eq(keys, { 'args', 'data', 'desc', 'hooks', 'n_retry', 'test' })\n\n  local hook_keys = child.lua_get('vim.tbl_keys(_G.cases[1].hooks)')\n  table.sort(hook_keys)\n  eq(hook_keys, { 'post', 'post_source', 'pre', 'pre_source' })\nend\n\nT['collect()']['respects `emulate_busted` option'] = function()\n  local res = testrun_ref_file('testref_collect-busted.lua')\n\n  -- All descriptions should be prepended with file name\n  eq(#filter_by_desc(res, 1, get_ref_path('testref_collect-busted.lua')), #res)\n\n  -- `describe()/it()`\n  eq(#filter_by_desc(res, 2, 'describe()/it()'), 3)\n\n  -- `setup()/teardown()`\n  expect_all_state(filter_by_desc(res, 2, 'setup()/teardown()'), 'Pass')\n\n  -- `before_each()/after_each()`\n  expect_all_state(filter_by_desc(res, 2, 'before_each()/after_each()'), 'Pass')\n\n  -- `MiniTest.skip()`\n  expect_all_state(filter_by_desc(res, 2, 'MiniTest.skip()'), 'Pass with notes')\n\n  -- `MiniTest.finally()`\n  local cases_finally = filter_by_desc(res, 2, 'MiniTest.finally()')\n  -- all_have_state(filter_by_desc(cases_finally, 3, 'works with no error'))\n  expect_all_state(filter_by_desc(cases_finally, 3, 'works with no error'), 'Pass')\n  expect_all_state(filter_by_desc(cases_finally, 3, 'works with error'), 'Pass')\n\n  -- Should also use buffer local config\n  child.lua([[vim.b.minitest_config = { collect = { emulate_busted = false } }]])\n  local busted_file = get_ref_path('testref_collect-busted.lua')\n  local command = string.format([[MiniTest.collect({ find_files = function() return { '%s' } end })]], busted_file)\n  expect.error(function() child.lua(command) end, 'attempt to call global')\nend\n\nT['collect()']['respects `find_files` option'] = function()\n  local command = string.format(\n    [[_G.cases = MiniTest.collect({ find_files = function() return { '%s' } end })]],\n    get_ref_path('testref_general.lua')\n  )\n  child.lua(command)\n  eq(child.lua_get('#_G.cases'), 2)\n  eq(child.lua_get('_G.cases[1].desc[1]'), 'tests/dir-test/testref_general.lua')\n\n  child.lua([[vim.b.minitest_config = { collect = { find_files = function() return {} end } }]])\n  child.lua('_G.cases = MiniTest.collect()')\n  eq(child.lua_get('#_G.cases'), 0)\nend\n\nT['collect()']['respects `filter_cases` option'] = function()\n  local command = string.format(\n    [[_G.cases = MiniTest.collect({\n      find_files = function() return { '%s' } end,\n      filter_cases = function(case) return case.desc[2] == 'case 2' end,\n    })]],\n    get_ref_path('testref_general.lua')\n  )\n  child.lua(command)\n\n  eq(child.lua_get('#_G.cases'), 1)\n  eq(child.lua_get('_G.cases[1].desc[2]'), 'case 2')\n\n  child.lua([[vim.b.minitest_config = { collect = { filter_cases = function() return false end } }]])\n  child.lua('_G.cases = MiniTest.collect()')\n  eq(child.lua_get('#_G.cases'), 0)\nend\n\nT['execute()'] = new_set()\n\nT['execute()']['respects `reporter` option'] = new_set()\n\nT['execute()']['respects `reporter` option']['empty'] = function()\n  collect_general()\n  child.lua('MiniTest.execute(_G.cases, { reporter = {} })')\nend\n\nT['execute()']['respects `reporter` option']['partial'] = function()\n  collect_general()\n  child.lua([[MiniTest.execute(\n    _G.cases,\n    { reporter = {\n      start = function() _G.was_in_start = true end,\n      finish = function() _G.was_in_finish = true end,\n    } }\n  )]])\n\n  eq(child.lua_get('_G.was_in_start'), true)\n  eq(child.lua_get('_G.was_in_finish'), true)\n\n  child.lua('vim.b.minitest_config = { execute = { reporter = { update = function() _G.was_in_update = true end } } }')\n  child.lua('MiniTest.execute(_G.cases)')\n  eq(child.lua_get('_G.was_in_update'), true)\nend\n\nT['execute()']['respects `stop_on_error` option'] = function()\n  collect_general()\n\n  child.lua('MiniTest.execute(_G.cases, { stop_on_error = true })')\n\n  eq(child.lua_get('type(_G.cases[1].exec)'), 'table')\n  eq(child.lua_get('_G.cases[1].exec.state'), 'Fail')\n\n  eq(child.lua_get('type(_G.cases[2].exec)'), 'nil')\n\n  -- Should also use buffer local config\n  child.lua('vim.b.minitest_config = { execute = { stop_on_error = false } }')\n  child.lua('MiniTest.execute(_G.cases)')\n  eq(child.lua_get('type(_G.cases[2].exec)'), 'table')\nend\n\nT['execute()']['properly calls `reporter` methods'] = function()\n  collect_general()\n\n  child.lua([[\n  _G.update_history = {}\n  _G.reporter = {\n    start = function(all_cases) _G.all_cases = all_cases end,\n    update = function(case_num)\n      table.insert(_G.update_history, { case_num = case_num, state = _G.all_cases[case_num].exec.state })\n    end,\n    finish = function() _G.was_in_finish = true end,\n  }]])\n\n  child.lua([[MiniTest.execute(_G.cases, { reporter = _G.reporter })]])\n  eq(child.lua_get('#_G.all_cases'), 2)\n  eq(child.lua_get('_G.update_history'), {\n    { case_num = 1, state = \"Executing 'pre' hook #1\" },\n    { case_num = 1, state = \"Executing 'pre' hook #2\" },\n    { case_num = 1, state = 'Executing test' },\n    { case_num = 1, state = \"Executing 'post' hook #1\" },\n    { case_num = 1, state = 'Fail' },\n    { case_num = 2, state = \"Executing 'pre' hook #1\" },\n    { case_num = 2, state = 'Executing test' },\n    { case_num = 2, state = \"Executing 'post' hook #1\" },\n    { case_num = 2, state = \"Executing 'post' hook #2\" },\n    { case_num = 2, state = 'Pass' },\n  })\n  eq(child.lua_get('_G.was_in_finish'), true)\nend\n\nT['execute()']['handles no cases'] = function()\n  child.lua('MiniTest.execute({})')\n  eq(child.lua_get('MiniTest.current.all_cases'), {})\n\n  -- Should throw message\n  eq(get_latest_message(), '(mini.test) No cases to execute.')\nend\n\nT['execute()']['respects `config.silent`'] = function()\n  child.lua('MiniTest.config.silent = true')\n  child.lua('MiniTest.execute({})')\n  eq(child.lua_get('MiniTest.current.all_cases'), {})\n\n  -- Should not throw message\n  eq(get_latest_message(), '')\nend\n\nT['stop()'] = new_set()\n\nT['stop()']['works'] = function()\n  collect_general()\n\n  child.lua('_G.grandchild = MiniTest.new_child_neovim(); _G.grandchild.start()')\n  child.lua('MiniTest.execute(_G.cases, { reporter = { start = function() MiniTest.stop() end } })')\n\n  eq(child.lua_get('type(_G.cases[1].exec)'), 'nil')\n  eq(child.lua_get('type(_G.cases[2].exec)'), 'nil')\n\n  -- Should close all opened child processed by default\n  eq(child.lua_get('_G.grandchild.is_running()'), false)\nend\n\nT['stop()']['respects `close_all_child_neovim` option'] = function()\n  collect_general()\n\n  child.lua('_G.grandchild = MiniTest.new_child_neovim(); _G.grandchild.start()')\n  -- Register cleanup\n  finally(function() child.lua('_G.grandchild.stop()') end)\n  child.lua([[MiniTest.execute(\n    _G.cases,\n    { reporter = { start = function() MiniTest.stop({ close_all_child_neovim = false }) end } }\n  )]])\n\n  -- Shouldn't close as per option\n  eq(child.lua_get('_G.grandchild.is_running()'), true)\nend\n\nT['is_executing()'] = new_set()\n\nT['is_executing()']['works'] = function()\n  collect_general()\n\n  -- Tests are executing all the time while reporter is active, but not before\n  -- or after\n  eq(child.lua_get('MiniTest.is_executing()'), false)\n\n  child.lua([[\n  _G.executing_states = {}\n  local track_is_executing = function() table.insert(_G.executing_states, MiniTest.is_executing()) end\n  MiniTest.execute(\n    _G.cases,\n    { reporter = { start = track_is_executing, update = track_is_executing, finish = track_is_executing } }\n  )]])\n\n  local all_true = true\n  for _, s in ipairs(child.lua_get('_G.executing_states')) do\n    if s ~= true then all_true = false end\n  end\n  eq(all_true, true)\n\n  eq(child.lua_get('MiniTest.is_executing()'), false)\nend\n\nT['expect'] = new_set()\n\nlocal validate_fail_reason = function(expectation, reason, args)\n  table.insert(args, { fail_reason = reason })\n  local ok, err = pcall(expectation, unpack(args))\n\n  -- Should error with specific pattern\n  eq(ok, false)\n  if vim.is_callable(reason) then reason = reason() end\n  expect.match(err, vim.pesc(reason))\n\n  -- Should not show default \"Failed expectation ...\" text\n  expect.no_match(err, 'Failed expectation')\nend\n\nT['expect']['equality()'] = new_set()\n\nT['expect']['equality()']['works'] = function()\n  local f, empty_tbl = function() end, {}\n\n  -- Pass\n  local validate_pass = function(x, y) eq(MiniTest.expect.equality(x, y), true) end\n\n  validate_pass(1, 1)\n  validate_pass('a', 'a')\n  validate_pass(f, f)\n  validate_pass(empty_tbl, empty_tbl)\n\n  -- - Tables should be compared \"deeply per elements\"\n  validate_pass(empty_tbl, {})\n  validate_pass({ 1 }, { 1 })\n  validate_pass({ a = 1 }, { a = 1 })\n  validate_pass({ { b = 2 } }, { { b = 2 } })\n\n  -- Fail\n  local validate_fail = function(x, y)\n    expect.error(function() MiniTest.expect.equality(x, y) end, 'equality.*Left:  .*Right: ')\n  end\n\n  validate_fail(1, 2)\n  validate_fail(1, '1')\n  validate_fail('a', 'b')\n  validate_fail(f, function() end)\n\n  -- - Tables should be compared \"deeply per elements\"\n  validate_fail({ 1 }, { 2 })\n  validate_fail({ a = 1 }, { a = 2 })\n  validate_fail({ a = 1 }, { b = 1 })\n  validate_fail({ a = 1 }, { { a = 1 } })\n  validate_fail({ { b = 2 } }, { { b = 3 } })\n  validate_fail({ { b = 2 } }, { { c = 2 } })\nend\n\nT['expect']['equality()']['provides proper cause'] = function()\n  local validate = function(a, b, cause)\n    expect.error(function() MiniTest.expect.equality(a, b) end, 'Cause: ' .. vim.pesc(cause) .. '\\n')\n  end\n\n  -- Different types\n  validate({ 1 }, 1, 'different types')\n  validate({ 1 }, 'a', 'different types')\n  validate(1, nil, 'different types')\n  validate(nil, 1, 'different types')\n\n  -- Strings\n  validate('a', 'bc', 'different string length')\n  validate('a', 'ab', 'different string length')\n  validate('ab', 'abc', 'different string length')\n  validate('', 'a', 'different string length')\n\n  validate('a', 'b', 'different character at position 1, left = \"a\", right = \"b\"')\n  validate('aa', 'ab', 'different character at position 2, left = \"a\", right = \"b\"')\n  validate('aac', 'abc', 'different character at position 2, left = \"a\", right = \"b\"')\n  validate('aa', 'bb', 'different character at position 1, left = \"a\", right = \"b\"')\n  validate('aaaa', 'abba', 'different character at position 2, left = \"a\", right = \"b\"')\n\n  -- Tables\n  validate({ 1 }, {}, 'different values at key 1, left = 1, right = nil')\n  validate({}, { 1 }, 'different values at key 1, left = nil, right = 1')\n  validate({ a = 1 }, {}, 'different values at key \"a\", left = 1, right = nil')\n  validate({}, { a = 1 }, 'different values at key \"a\", left = nil, right = 1')\n  validate({ 1, 2 }, { 1 }, 'different values at key 2, left = 2, right = nil')\n  validate({ 1 }, { 1, 2 }, 'different values at key 2, left = nil, right = 2')\n  validate({ a = 1, b = 2 }, { a = 1 }, 'different values at key \"b\", left = 2, right = nil')\n  validate({ a = 1 }, { a = 1, b = 2 }, 'different values at key \"b\", left = nil, right = 2')\n\n  validate({ 1 }, { 2 }, 'different values at key 1, left = 1, right = 2')\n  validate({ a = 1 }, { a = 2 }, 'different values at key \"a\", left = 1, right = 2')\n  validate({ 1, 2 }, { 1, 3 }, 'different values at key 2, left = 2, right = 3')\n  validate({ a = 1, b = 2 }, { a = 1, b = 3 }, 'different values at key \"b\", left = 2, right = 3')\n\n  validate({ 1, a = 3 }, { 2, a = 3 }, 'different values at key 1, left = 1, right = 2')\n  validate({ 1, a = 3 }, { 1, a = 4 }, 'different values at key \"a\", left = 3, right = 4')\n\n  validate({ { 1 } }, { {} }, 'different values at key branch 1->1, left = 1, right = nil')\n  validate({ {} }, { { 1 } }, 'different values at key branch 1->1, left = nil, right = 1')\n  validate({ { a = 1 } }, { {} }, 'different values at key branch 1->\"a\", left = 1, right = nil')\n  validate({ {} }, { { a = 1 } }, 'different values at key branch 1->\"a\", left = nil, right = 1')\n  validate({ a = { 1 } }, { a = {} }, 'different values at key branch \"a\"->1, left = 1, right = nil')\n  validate({ a = {} }, { a = { 1 } }, 'different values at key branch \"a\"->1, left = nil, right = 1')\n  validate({ a = { b = 1 } }, { a = {} }, 'different values at key branch \"a\"->\"b\", left = 1, right = nil')\n  validate({ a = {} }, { a = { b = 1 } }, 'different values at key branch \"a\"->\"b\", left = nil, right = 1')\n\n  validate({ 1, { 2 } }, { 1, 2 }, 'different values at key 2, left = { 2 }, right = 2')\n  validate({ 1, 2 }, { 1, { 2 } }, 'different values at key 2, left = 2, right = { 2 }')\n  validate({ 1, { a = 1 } }, { 1, 2 }, 'different values at key 2, left = { a = 1 }, right = 2')\n  validate({ 1, 2 }, { 1, { a = 1 } }, 'different values at key 2, left = 2, right = { a = 1 }')\n\n  validate({ { { { 1 } } } }, { { { { 2 } } } }, 'different values at key branch 1->1->1->1, left = 1, right = 2')\n\n  validate({ { 1, 2 } }, { { 1, 3 } }, 'different values at key branch 1->2, left = 2, right = 3')\n  validate({ 1, { 2 } }, { 1, { 3 } }, 'different values at key branch 2->1, left = 2, right = 3')\n\n  --->Should prefer consistent/deterministic different key\n  validate({ 1, 2, 3 }, { 1, 3, 4 }, 'different values at key 2, left = 2, right = 3')\n  validate({ 1, { 2 }, 3 }, { 1, { 3 }, 4 }, 'different values at key branch 2->1, left = 2, right = 3')\n  validate({ a = 1, b = 2, c = 3 }, { a = 1, b = 3, c = 4 }, 'different values at key \"b\", left = 2, right = 3')\n  validate(\n    { a = 1, b = { 2 }, c = 3 },\n    { a = 1, b = { 3 }, c = 4 },\n    'different values at key branch \"b\"->1, left = 2, right = 3'\n  )\n  validate({ 1, a = 3 }, { 2, a = 4 }, 'different values at key 1, left = 1, right = 2')\n\n  -- Fallback response for other types\n  validate(false, true, 'different values')\n  validate(1, 2, 'different values')\n  -- - Can not compare functions other than by their id (always different)\n  validate(function() end, function() end, 'different values')\nend\n\nT['expect']['equality()']['respects `opts.fail_reason`'] = function()\n  validate_fail_reason(MiniTest.expect.equality, 'This is test 1', { 1, 2 })\n  validate_fail_reason(MiniTest.expect.equality, function() return 'This is test 2' end, { 2, 3 })\nend\n\nT['expect']['no_equality()'] = new_set()\n\nT['expect']['no_equality()']['works'] = function()\n  local f, empty_tbl = function() end, {}\n\n  -- Pass\n  local validate_pass = function(x, y) eq(MiniTest.expect.no_equality(x, y), true) end\n\n  validate_pass(1, 2)\n  validate_pass(1, '1')\n  validate_pass('a', 'b')\n  validate_pass(f, function() end)\n\n  -- - Tables should be compared \"deeply per elements\"\n  validate_pass({ 1 }, { 2 })\n  validate_pass({ a = 1 }, { a = 2 })\n  validate_pass({ a = 1 }, { b = 1 })\n  validate_pass({ a = 1 }, { { a = 1 } })\n  validate_pass({ { b = 2 } }, { { b = 3 } })\n  validate_pass({ { b = 2 } }, { { c = 2 } })\n\n  -- Fail\n  local validate_fail = function(x, y)\n    expect.error(function() MiniTest.expect.no_equality(x, y) end, '%*no%* equality.*Object:')\n  end\n\n  validate_fail(1, 1)\n  validate_fail('a', 'a')\n  validate_fail(f, f)\n  validate_fail(empty_tbl, empty_tbl)\n\n  -- - Tables should be compared \"deeply per elements\"\n  validate_fail(empty_tbl, {})\n  validate_fail({ 1 }, { 1 })\n  validate_fail({ a = 1 }, { a = 1 })\n  validate_fail({ { b = 2 } }, { { b = 2 } })\nend\n\nT['expect']['no_equality()']['respects `opts.fail_reason`'] = function()\n  validate_fail_reason(MiniTest.expect.no_equality, 'This is test 3', { 1, 1 })\n  validate_fail_reason(MiniTest.expect.no_equality, function() return 'This is test 4' end, { 2, 2 })\nend\n\nT['expect']['error()'] = new_set()\n\nT['expect']['error()']['works'] = function()\n  expect.error(function()\n    MiniTest.expect.error(function() end)\n  end, 'error.*Observed no error')\n\n  expect.error(function()\n    MiniTest.expect.error(function() end, 'aa')\n  end, 'error matching pattern \"aa\".*Observed no error')\n\n  expect.error(function() MiniTest.expect.error(error, 'bb') end, 'error matching pattern \"bb\".*Observed error:')\nend\n\nT['expect']['error()']['respects `pattern` argument'] = function()\n  ---@diagnostic disable-next-line:param-type-mismatch\n  expect.error(function() MiniTest.expect.error(error, 1) end, 'pattern.*string')\n\n  -- `nil` and `''` are placeholders for 'any error'\n  expect.no_error(function() MiniTest.expect.error(error, '') end)\n  expect.no_error(function() MiniTest.expect.error(error, nil) end)\nend\n\n-- TODO: Remove after releasing 'mini.nvim' 0.18.0\nT['expect']['error()']['provides backward compatibility for vararg function arguments'] = function()\n  local notify_log = {}\n  local notify_orig = vim.notify\n  vim.notify = function(msg, level)\n    local level_name\n    for k, v in pairs(vim.log.levels) do\n      if v == level then level_name = k end\n    end\n    table.insert(notify_log, { msg, level_name })\n  end\n  MiniTest.finally(function() vim.notify = notify_orig end)\n\n  local f = function(x, y)\n    if x ~= y then error('`x` and `y` are not equal') end\n  end\n\n  expect.no_error(function() MiniTest.expect.error(f, 'not equal', 1, 2) end)\n  expect.error(function() MiniTest.expect.error(f, 'not equal', 1, 1) end)\n\n  eq(#notify_log, 2)\nend\n\nT['expect']['error()']['returns `true` on success'] = function() eq(MiniTest.expect.error(error), true) end\n\nT['expect']['error()']['respects `opts.fail_reason`'] = function()\n  local f = function() return 1 end\n  validate_fail_reason(MiniTest.expect.error, 'This is test 1', { f, '' })\n  validate_fail_reason(MiniTest.expect.error, function() return 'This is test 2' end, { f, '' })\n\n  local g = function() error('xxx') end\n  validate_fail_reason(MiniTest.expect.error, 'This is test 3', { g, 'yyy' })\n  validate_fail_reason(MiniTest.expect.error, function() return 'This is test 4' end, { g, 'yyy' })\nend\n\nT['expect']['no_error()'] = new_set()\n\nT['expect']['no_error()']['works'] = function()\n  expect.error(function() MiniTest.expect.no_error(error) end, '%*no%* error.*Observed error:')\n\n  expect.no_error(function()\n    MiniTest.expect.no_error(function() end)\n  end)\nend\n\n-- TODO: Remove after releasing 'mini.nvim' 0.18.0\nT['expect']['no_error()']['provides backward compatibility for vararg function arguments'] = function()\n  local notify_log = {}\n  local notify_orig = vim.notify\n  vim.notify = function(msg, level)\n    local level_name\n    for k, v in pairs(vim.log.levels) do\n      if v == level then level_name = k end\n    end\n    table.insert(notify_log, { msg, level_name })\n  end\n  MiniTest.finally(function() vim.notify = notify_orig end)\n\n  local f = function(x, y)\n    if x ~= y then error('`x` and `y` are not equal') end\n  end\n\n  expect.error(function() MiniTest.expect.no_error(f, 1, 2) end)\n  expect.no_error(function() MiniTest.expect.no_error(f, 1, 1) end)\n\n  eq(#notify_log, 2)\nend\n\nT['expect']['no_error()']['returns `true` on success'] = function()\n  eq(MiniTest.expect.no_error(function() end), true)\nend\n\nT['expect']['no_error()']['respects `opts.fail_reason`'] = function()\n  local f = function() error('Error msg') end\n  validate_fail_reason(MiniTest.expect.no_error, 'This is test 1', { f })\n  validate_fail_reason(MiniTest.expect.no_error, function() return 'This is test 2' end, { f })\nend\n\nT['expect']['reference_screenshot()'] = new_set()\n\nT['expect']['reference_screenshot()']['works'] = function()\n  local path = get_ref_path('reference-screenshot')\n  child.set_size(5, 12)\n\n  set_lines({ 'aaa' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), path), true)\n\n  set_lines({ 'bbb' })\n  expect.error(\n    function() MiniTest.expect.reference_screenshot(child.get_screenshot(), path) end,\n    'screenshot equality to reference at ' .. vim.pesc(vim.inspect(path)) .. '.*Reference:.*Observed:'\n  )\n\n  -- Should pass if supplied `nil` (like in case of no reasonable screenshot)\n  eq(MiniTest.expect.reference_screenshot(nil), true)\nend\n\nT['expect']['reference_screenshot()']['locates problem'] = function()\n  local path = get_ref_path('reference-screenshot')\n  local validate = function(screen, pattern)\n    expect.error(function() MiniTest.expect.reference_screenshot(screen, path) end, pattern)\n  end\n\n  child.set_size(5, 12)\n  set_lines({ 'aaa' })\n  local screen = child.get_screenshot()\n\n  -- Number of lines\n  local screen_text_lines = vim.deepcopy(screen)\n  table.remove(screen_text_lines.text, 1)\n  validate(screen_text_lines, 'different number of `text` lines%, reference = 5, observed = 4')\n\n  local screen_attr_lines = vim.deepcopy(screen)\n  table.remove(screen_attr_lines.attr, 1)\n  validate(screen_attr_lines, 'different number of `attr` lines, reference = 5, observed = 4')\n\n  -- Number of columns\n  local screen_text_columns = vim.deepcopy(screen)\n  table.remove(screen_text_columns.text[1], 1)\n  validate(screen_text_columns, 'different number of columns in `text` line 1%, reference = 12, observed = 11')\n\n  local screen_attr_columns = vim.deepcopy(screen)\n  table.remove(screen_attr_columns.attr[1], 1)\n  validate(screen_attr_columns, 'different number of columns in `attr` line 1%, reference = 12, observed = 11')\n\n  -- Cells\n  local screen_text_cell = vim.deepcopy(screen)\n  screen_text_cell.text[1][2] = 'X'\n  validate(screen_text_cell, 'different `text` cell at line 1 column 2, reference = \"a\", observed = \"X\"')\n\n  local screen_attr_cell = vim.deepcopy(screen)\n  screen_attr_cell.attr[1][2] = 'X'\n  validate(screen_attr_cell, 'different `attr` cell at line 1 column 2, reference = \"0\", observed = \"X\"')\nend\n\nT['expect']['reference_screenshot()']['correctly infers reference path'] = function()\n  child.set_size(5, 20)\n\n  set_lines({ 'This path should be correctly inferred without suffix' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot()), true)\n\n  set_lines({ 'This path should have suffix 002' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot()), true)\n\n  set_lines({ 'This is a call to `reference_screenshot()` with manual path' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), 'tests/dir-test/intermediate-screenshot'), true)\n\n  set_lines({ 'This path should have suffix 004' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot()), true)\nend\n\nlocal validate_path_sanitize = function()\n  child.set_size(5, 12)\n  set_lines({ 'Path should be correctly sanitized' })\n\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot()), true)\nend\n\nlocal useful_punctuation = [=[_-+{}()[]'\"]=]\nlocal linux_forbidden = [[/]]\nlocal windows_forbidden = [[<>:\"/\\|?*]]\nlocal whitespace = '\\t '\nlocal special_characters = string.char(0) .. string.char(1) .. string.char(31)\nlocal suffix = useful_punctuation .. linux_forbidden .. windows_forbidden .. whitespace .. special_characters\n\n-- Don't permanently create reference file because its name is very long. This\n-- might hurt Windows users which are not interested in testing this plugin.\nT['expect']['reference_screenshot()']['correctly sanitizes path ' .. suffix] = new_set(\n  { parametrize = { { suffix } } },\n  {\n    test = function()\n      local expected_filename = table.concat({\n        'tests/screenshots/',\n        'tests-test_test.lua---',\n        'expect---',\n        'reference_screenshot()---',\n        'correctly-sanitizes-path-',\n        [[_-+{}()[]''----'-------------]],\n        'test-+-args-',\n        [[{-'_-+{}()[]'-'-----'-------t--0-1-31'-}]],\n      }, '')\n      finally(function()\n        MiniTest.current.case.exec.notes = {}\n        vim.fn.delete(expected_filename)\n      end)\n      eq(vim.fn.filereadable(expected_filename), 0)\n      validate_path_sanitize()\n      eq(vim.fn.filereadable(expected_filename), 1)\n    end,\n  }\n)\n\n-- Paths should not end with whitespace or dot\nT['expect']['reference_screenshot()']['correctly sanitizes path for Windows '] = validate_path_sanitize\nT['expect']['reference_screenshot()']['correctly sanitizes path for Windows #2.'] = validate_path_sanitize\n\nT['expect']['reference_screenshot()']['creates reference if it does not exist'] = function()\n  local path = get_ref_path('nonexistent-reference-screenshot')\n  child.fn.delete(path)\n  finally(function()\n    child.fn.delete(path)\n    MiniTest.current.case.exec.notes = {}\n  end)\n\n  set_lines({ 'nonexistent' })\n  local screenshot = child.get_screenshot()\n\n  eq(MiniTest.expect.reference_screenshot(screenshot, path), true)\n  eq(MiniTest.current.case.exec.notes, { 'Created reference screenshot at path ' .. vim.inspect(path) })\n\n  MiniTest.current.case.exec.notes = {}\n  eq(MiniTest.expect.reference_screenshot(screenshot, path), true)\n  eq(MiniTest.current.case.exec.notes, {})\nend\n\nT['expect']['reference_screenshot()']['respects `opts.force` argument'] = function()\n  local path = get_ref_path('force-reference-screenshot')\n  local notes = { 'Created reference screenshot at path ' .. vim.inspect(path) }\n\n  child.fn.delete(path)\n  finally(function()\n    child.fn.delete(path)\n    MiniTest.current.case.exec.notes = {}\n  end)\n\n  set_lines({ 'First run' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), path), true)\n  eq(MiniTest.current.case.exec.notes, notes)\n\n  MiniTest.current.case.exec.notes = {}\n  set_lines({ 'This should be forced' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), path, { force = true }), true)\n  eq(MiniTest.current.case.exec.notes, notes)\nend\n\nT['expect']['reference_screenshot()']['respects `opts.ignore_text`'] = function()\n  local path = get_ref_path('reference-screenshot')\n  child.set_size(5, 12)\n  local validate = function(ignore_text, ref)\n    eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), path, { ignore_text = ignore_text }), ref)\n  end\n\n  set_lines({ 'aaa' })\n  validate(nil, true)\n  validate(false, true)\n\n  -- Make different text but same highlighting\n  set_lines({ 'aaa', 'bbb' })\n  local ns_id = child.api.nvim_create_namespace('test-hl')\n  child.api.nvim_buf_set_extmark(0, ns_id, 1, 0, { end_row = 2, end_col = 0, hl_group = 'EndOfBuffer', hl_eol = true })\n\n  validate({ 2 }, true)\n  validate({ 1, 2, 3 }, true)\n\n  set_lines({ 'ccc', 'bbb' })\n  expect.error(\n    function() MiniTest.expect.reference_screenshot(child.get_screenshot(), path, { ignore_text = { 2 } }) end,\n    'screenshot equality to reference at '\n      .. vim.pesc(vim.inspect(path))\n      .. '.*different `text` cell at line 1 column 1, reference = \"a\", observed = \"c\"'\n  )\nend\n\nT['expect']['reference_screenshot()']['respects `opts.ignore_attr`'] = function()\n  local path = get_ref_path('reference-screenshot')\n  child.set_size(5, 12)\n  local validate = function(ignore_attr, ref)\n    eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), path, { ignore_attr = ignore_attr }), ref)\n  end\n\n  set_lines({ 'aaa' })\n  validate(nil, true)\n  validate(false, true)\n\n  -- Make different attr but same text\n  local ns_id = child.api.nvim_create_namespace('test-hl')\n  child.api.nvim_buf_set_extmark(0, ns_id, 0, 1, { end_row = 0, end_col = 3, hl_group = 'EndOfBuffer' })\n\n  validate({ 1 }, true)\n  validate({ 1, 2 }, true)\n\n  expect.error(\n    function() MiniTest.expect.reference_screenshot(child.get_screenshot(), path, { ignore_text = { 2 } }) end,\n    'screenshot equality to reference at '\n      .. vim.pesc(vim.inspect(path))\n      .. '.*different `attr` cell at line 1 column 2, reference = \"0\", observed = \"1\"'\n  )\nend\n\nT['expect']['reference_screenshot()']['respects `opts.directory`'] = function()\n  child.set_size(5, 12)\n  set_lines({ 'opts.directory' })\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), nil, { directory = 'tests/dir-test' }), true)\n  eq(MiniTest.expect.reference_screenshot(child.get_screenshot(), nil, { directory = 'tests/dir-test/' }), true)\nend\n\nT['expect']['reference_screenshot()']['respects `opts.fail_reason`'] = function()\n  local path = get_ref_path('reference-screenshot')\n  child.set_size(5, 12)\n  set_lines({ 'bbb' })\n  local screen = child.get_screenshot()\n  validate_fail_reason(MiniTest.expect.reference_screenshot, 'This is test 1', { screen, path })\n  validate_fail_reason(MiniTest.expect.reference_screenshot, function() return 'This is test 2' end, { screen, path })\nend\n\nT['expect']['reference_screenshot()']['works with multibyte characters'] = function()\n  child.set_size(5, 12)\n  set_lines({ '  1  2' })\n  expect.no_error(function() MiniTest.expect.reference_screenshot(child.get_screenshot()) end)\nend\n\nT['new_expectation()'] = new_set()\n\nT['new_expectation()']['works'] = function()\n  local expect_truthy = MiniTest.new_expectation(\n    'truthy',\n    function(x) return x end,\n    function(x) return 'Object: ' .. vim.inspect(x) end\n  )\n\n  expect.error(function() expect_truthy(false) end, 'truthy.*Object:')\n  expect.no_error(function() expect_truthy(1) end)\nend\n\nT['new_expectation()']['allows string or function arguments'] = function()\n  local expect_truthy = MiniTest.new_expectation(\n    function() return 'func_truthy' end,\n    function(x) return x end,\n    'Not truthy'\n  )\n\n  expect.error(function() expect_truthy(false) end, 'func_truthy.*Not truthy')\n  expect.no_error(function() expect_truthy(1) end)\nend\n\nT['new_child_neovim()'] = new_set()\n\nT['new_child_neovim()']['works'] = function()\n  finally(function() child.lua('_G.grandchild.stop()') end)\n  child.lua('_G.grandchild = MiniTest.new_child_neovim(); _G.grandchild.start()')\n  eq(child.lua_get('_G.grandchild.is_running()'), true)\nend\n\nT['child'] = new_set()\n\nT['child']['job'] = function()\n  eq(type(child.job), 'table')\n\n  child.stop()\n  eq(child.job, nil)\nend\n\nT['child']['start()'] = new_set()\n\nT['child']['start()']['respects `args` argument'] = function()\n  child.stop()\n\n  child.start({ '-c', 'lua _G.inside_args = true' })\n  eq(child.lua_get('_G.inside_args'), true)\nend\n\nT['child']['start()']['does nothing if already running'] = function()\n  finally(function() child.lua('_G.grandchild.stop()') end)\n  child.lua('_G.grandchild = MiniTest.new_child_neovim(); _G.grandchild.start()')\n\n  child.lua('_G.should_be_present = true')\n  child.lua('_G.grandchild.start()')\n  eq(child.lua_get('_G.should_be_present'), true)\n\n  eq(get_latest_message(), '(mini.test) Child process is already running. Use `child.restart()`.')\nend\n\nT['child']['stop()'] = function()\n  eq(child.is_running(), true)\n  child.stop()\n  eq(child.is_running(), false)\nend\n\nT['child']['restart()'] = new_set()\n\nT['child']['restart()']['respects `args` argument'] = function()\n  eq(child.lua_get('_G.inside_args'), vim.NIL)\n  child.restart({ '-c', 'lua _G.inside_args = true' })\n  eq(child.lua_get('_G.inside_args'), true)\nend\n\nT['child']['restart()']['uses `args` from `start()` by default'] = function()\n  child.stop()\n\n  child.start({ '-c', 'lua _G.inside_args = true' })\n  eq(child.lua_get('_G.inside_args'), true)\n\n  child.restart()\n  eq(child.lua_get('_G.inside_args'), true)\nend\n\nlocal validate_child_method = function(method, opts)\n  opts = vim.tbl_deep_extend('force', { prevent_hanging = true }, opts or {})\n\n  -- Validate presence of method\n  expect.no_error(method)\n\n  -- Validate hanging prevention\n  if opts.prevent_hanging then\n    child.type_keys('di')\n    expect.error(method, opts.name .. '.*child process is blocked')\n    -- Unblock for faster test execution\n    child.type_keys('<Esc>')\n  end\n\n  -- Validate ensuring running\n  child.stop()\n  expect.error(method, 'Child process is not running')\nend\n\nlocal validate_child_field = function(tbl_name, field_name, value)\n  local var = string.format('vim[%s][%s]', vim.inspect(tbl_name), vim.inspect(field_name))\n\n  -- Setting\n  child[tbl_name][field_name] = value\n  eq(child.lua_get(var), value)\n\n  -- Getting\n  eq(child[tbl_name][field_name], child.lua_get(var))\nend\n\nT['child']['api'] = function()\n  local method = function() return child.api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa' }) end\n  validate_child_method(method, { prevent_hanging = false })\nend\n\nT['child']['api_notify'] = function()\n  local method = function() return child.api_notify.nvim_buf_set_lines(0, 0, -1, true, { 'aaa' }) end\n  validate_child_method(method, { prevent_hanging = false })\nend\n\nT['child']['redirected method tables'] = new_set({\n  parametrize = {\n    { 'diagnostic', 'get', { 0 } },\n    { 'fn', 'fnamemodify', { '.', ':p' } },\n    { 'highlight', 'range', { 0, 1, 'Comment', { 0, 1 }, { 0, 2 } } },\n    { 'hl', 'range', { 0, 1, 'Comment', { 0, 1 }, { 0, 2 } } },\n    { 'json', 'encode', { { a = 1 } } },\n    { 'loop', 'hrtime', {} },\n    { 'lsp', 'get_active_clients', {} },\n    { 'mpack', 'encode', { { a = 1 } } },\n    { 'spell', 'check', { 'thouht' } },\n    { 'treesitter', 'get_parser', {} },\n    { 'ui', 'select', {} },\n    { 'fs', 'normalize', { '/tmp/' } },\n  },\n  hooks = {\n    pre_case = function()\n      -- Mock problematic methods\n      child.lua('vim.treesitter.get_parser = function() end')\n      child.lua('vim.ui.select = function() end')\n    end,\n  },\n})\n\nT['child']['redirected method tables']['method'] = function(tbl_name, field_name, args)\n  if tbl_name == 'hl' and child.fn.has('nvim-0.11') == 0 then return end\n  local method = function() return child[tbl_name][field_name](unpack(args)) end\n  validate_child_method(method, { name = tbl_name .. '.' .. field_name })\nend\n\nT['child']['redirected method tables']['field'] = function(tbl_name, field_name, _)\n  if tbl_name == 'hl' and child.fn.has('nvim-0.11') == 0 then return end\n  -- Although being tables, they should be overridable to allow test doubles\n  validate_child_field(tbl_name, field_name, true)\nend\n\nT['child']['ui'] = function()\n  -- Nothing to actually test due to mandatory function argument\n  eq(type(child.ui), 'table')\nend\n\nT['child']['scoped variables'] = new_set({ parametrize = { { 'g' }, { 'b' }, { 'w' }, { 't' }, { 'v' }, { 'env' } } })\n\nT['child']['scoped variables']['method'] = function(scope)\n  local method = function() return child[scope].char end\n  validate_child_method(method, { name = scope })\nend\n\nT['child']['scoped variables']['field'] = function(scope) validate_child_field(scope, 'char', 'a') end\n\nT['child']['scoped options'] = new_set({\n  parametrize = { { 'o', 'lines', 10 }, { 'go', 'lines', 10 }, { 'bo', 'filetype', 'lua' }, { 'wo', 'number', true } },\n})\n\nT['child']['scoped options']['method'] = function(tbl_name, field_name, _)\n  local method = function() return child[tbl_name][field_name] end\n  validate_child_method(method, { name = tbl_name })\nend\n\nT['child']['scoped options']['field'] = function(tbl_name, field_name, value)\n  validate_child_field(tbl_name, field_name, value)\nend\n\nT['child']['type_keys()'] = new_set()\n\nT['child']['type_keys()']['works'] = function()\n  local method = function() child.type_keys('i', 'abc') end\n  validate_child_method(method, { prevent_hanging = false })\nend\n\nT['child']['type_keys()']['allows strings and arrays of strings'] = function()\n  child.type_keys('i', { 'H', 'e', 'l', 'l', 'o' }, ' ', { 'World' }, '<Esc>')\n  eq(get_lines(), { 'Hello World' })\nend\n\nT['child']['type_keys()']['validates input'] = function()\n  local pattern = 'type_keys.*string'\n\n  expect.error(function() child.type_keys('a', 1) end, pattern)\n  expect.error(function() child.type_keys('a', { 'a', 1 }) end, pattern)\nend\n\nT['child']['type_keys()']['throws error explicitly'] = function()\n  expect.error(function() child.type_keys(':aaa<CR>') end, 'E492: Not an editor command: aaa')\nend\n\nT['child']['type_keys()']['respects `wait` argument'] = function()\n  local delay = helpers.get_time_const(100)\n  local start_time = vim.loop.hrtime()\n  child.type_keys(delay, 'i', 'Hello', { 'w', 'o' }, 'rld')\n  local end_time = vim.loop.hrtime()\n  local duration = (end_time - start_time) * 0.000001\n  eq(0.9 * 5 * delay <= duration and duration <= 1.1 * 5 * delay, true)\nend\n\nT['child']['cmd()'] = function()\n  local method = function() child.cmd([[echomsg 'Hello world']]) end\n\n  method()\n  eq(child.cmd_capture('1messages'), 'Hello world')\n\n  validate_child_method(method, { name = 'cmd' })\nend\n\nT['child']['cmd_capture()'] = function()\n  local method = function() return child.cmd_capture([[echomsg 'Hello world']]) end\n\n  eq(method(), 'Hello world')\n\n  validate_child_method(method, { name = 'cmd_capture' })\nend\n\nT['child']['lua()'] = function()\n  local method = function() return child.lua('_G.n = 0') end\n\n  eq(child.lua_get('_G.n'), vim.NIL)\n  method()\n  eq(child.lua_get('_G.n'), 0)\n\n  validate_child_method(method, { name = 'lua' })\nend\n\nT['child']['lua_notify()'] = function()\n  local method = function() return child.lua_notify('_G.n = 0') end\n\n  eq(child.lua_get('_G.n'), vim.NIL)\n  method()\n  eq(child.lua_get('_G.n'), 0)\n\n  validate_child_method(method, { prevent_hanging = false })\nend\n\nT['child']['lua_get()'] = function()\n  local method = function() return child.lua_get('1 + 1') end\n\n  eq(method(), 2)\n\n  validate_child_method(method, { name = 'lua_get' })\nend\n\nT['child']['lua_func()'] = function()\n  -- Works\n  local method = function()\n    return child.lua_func(function() return 1 + 1 end)\n  end\n  eq(method(), 2)\n\n  -- Actually executes function in child neovim\n  child.lua('_G.var = 1')\n  child.lua_func(function() _G.var = 10 end)\n  eq(child.lua_get('_G.var'), 10)\n\n  -- Can take arguments\n  eq(child.lua_func(function(a, b) return a + b end, 1, 2), 3)\n\n  -- Has no side effects\n  child.lua_func(function() end)\n  eq(child.lua_get('f'), vim.NIL)\n\n  -- Can error\n  expect.error(function()\n    return child.lua_func(function() error('test error') end)\n  end, 'test error')\n\n  validate_child_method(method, { name = 'lua_func' })\nend\n\nT['child']['is_blocked()'] = function()\n  eq(child.is_blocked(), false)\n\n  child.type_keys('di')\n  eq(child.is_blocked(), true)\n\n  child.ensure_normal_mode()\n  validate_child_method(child.is_blocked, { prevent_hanging = false })\nend\n\nT['child']['is_running()'] = function()\n  eq(child.is_running(), true)\n  child.stop()\n  eq(child.is_running(), false)\nend\n\nT['child']['ensure_normal_mode()'] = new_set()\n\nT['child']['ensure_normal_mode()']['works'] = new_set({ parametrize = { { 'i' }, { 'v' }, { ':' }, { 'R' } } }, {\n  function(keys)\n    child.type_keys(keys)\n    expect.no_equality(child.api.nvim_get_mode().mode, 'n')\n    child.ensure_normal_mode()\n    eq(child.api.nvim_get_mode().mode, 'n')\n  end,\n})\n\nT['child']['ensure_normal_mode()']['ensures running'] = function()\n  validate_child_method(child.ensure_normal_mode, { prevent_hanging = false })\nend\n\nT['child']['get_screenshot()'] = new_set()\n\nT['child']['get_screenshot()']['ensures running'] = function()\n  validate_child_method(child.get_screenshot, { name = 'get_screenshot' })\nend\n\nT['child']['get_screenshot()']['works'] = function()\n  set_lines({ 'aaa' })\n  local screenshot = child.get_screenshot()\n\n  -- Structure\n  eq(type(screenshot), 'table')\n  eq(islist(screenshot.text), true)\n  eq(islist(screenshot.attr), true)\n\n  local n_lines, n_cols = child.o.lines, child.o.columns\n\n  eq(#screenshot.text, n_lines)\n  eq(#screenshot.attr, n_lines)\n\n  for i = 1, n_lines do\n    eq(islist(screenshot.text[i]), true)\n    eq(islist(screenshot.attr[i]), true)\n\n    eq(#screenshot.text[i], n_cols)\n    eq(#screenshot.attr[i], n_cols)\n\n    for j = 1, n_cols do\n      eq(type(screenshot.text[i][j]), 'string')\n      eq(type(screenshot.attr[i][j]), 'string')\n    end\n  end\n\n  -- Content\n  expect.match(table.concat(screenshot.text[1], ''), '^aaa')\n  expect.no_equality(screenshot.attr[1][1], screenshot.attr[2][1])\nend\n\nT['child']['get_screenshot()']['respects `opts.redraw`'] = function()\n  -- This blocks redraw until explicitly called\n  child.lua_notify('vim.fn.getchar()')\n  set_lines({ 'Should be visible only after redraw' })\n\n  local screenshot = child.get_screenshot({ redraw = false })\n  expect.match(table.concat(screenshot.text[1]), '^   ')\n  -- - Should be `redraw = true` by default\n  screenshot = child.get_screenshot()\n  expect.match(table.concat(screenshot.text[1]), '^Should be visible')\nend\n\nT['child']['get_screenshot()']['`tostring()`'] = new_set()\n\nT['child']['get_screenshot()']['`tostring()`']['works'] = function()\n  set_lines({ 'aaa' })\n  local screenshot = child.get_screenshot()\n  local lines = vim.split(tostring(screenshot), '\\n')\n  local n_lines, n_cols = child.o.lines, child.o.columns\n\n  -- \"Ruler\" + \"Lines\" + \"Empty line\" + \"Ruler\" + \"Lines\"\n  eq(#lines, 2 * n_lines + 3)\n  eq(lines[n_lines + 2], '')\n\n  -- Content\n  eq(vim.fn.strchars(lines[2]), 3 + n_cols)\n  expect.match(lines[2], '^01|aaa')\n\n  eq(vim.fn.strchars(lines[n_lines + 4]), 3 + n_cols)\n  expect.no_equality(lines[n_lines + 4]:sub(4, 4), lines[n_lines + 5]:sub(4, 4))\nend\n\nT['child']['get_screenshot()']['`tostring()`']['makes proper rulers'] = function()\n  local validate = function(ref_ruler)\n    local lines = vim.split(tostring(child.get_screenshot()), '\\n')\n    eq(lines[1], ref_ruler)\n    local n = 0.5 * (#lines - 3)\n    eq(lines[n + 3], ref_ruler)\n  end\n\n  child.set_size(5, 12)\n  validate('-|---------|--')\n\n  child.set_size(10, 12)\n  validate('--|---------|--')\n\n  child.set_size(100, 20)\n  validate('---|---------|---------|')\nend\n\nT['child']['get_screenshot()']['`tostring()`']['makes proper line numbers'] = function()\n  local validate = function(...)\n    local lines = vim.split(tostring(child.get_screenshot()), '\\n')\n    local n = 0.5 * (#lines - 3)\n\n    for _, ref in ipairs({ ... }) do\n      local pattern = '^' .. ref[2] .. '|'\n      expect.match(lines[1 + ref[1]], pattern)\n      expect.match(lines[n + 3 + ref[1]], pattern)\n    end\n  end\n\n  child.set_size(5, 12)\n  validate({ 1, '1' }, { 5, '5' })\n\n  child.set_size(10, 12)\n  validate({ 1, '01' }, { 10, '10' })\n\n  child.set_size(100, 12)\n  validate({ 1, '001' }, { 10, '010' }, { 100, '100' })\nend\n\nT['child']['get_screenshot()']['works with floating windows'] = function()\n  -- This setup should result into displayed text 'bb a': 'bb ' from floating\n  -- window, 'aa' - from underneath text\n  set_lines({ 'aaaa' })\n\n  local buf_id = child.api.nvim_create_buf(true, true)\n  child.api.nvim_buf_set_lines(buf_id, 0, -1, true, { 'bb ' })\n  child.api.nvim_open_win(buf_id, false, { relative = 'editor', width = 3, height = 1, row = 0, col = 0 })\n\n  local screenshot = child.get_screenshot()\n  eq(screenshot.text[1][1], 'b')\n  eq(screenshot.text[1][2], 'b')\n  eq(screenshot.text[1][3], ' ')\n  eq(screenshot.text[1][4], 'a')\nend\n\n-- Integration tests ==========================================================\nT['gen_reporter'] = new_set()\n\nT['gen_reporter']['buffer'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.o.termguicolors = true\n      child.set_size(70, 120)\n    end,\n  },\n  parametrize = {\n    { '' },\n    { 'group_depth=2' },\n    { 'window={width=0.9*vim.o.columns,col=0.05*vim.o.columns}' },\n    { 'window={border=\"double\",title=(\"a\"):rep(200)}' },\n  },\n}, {\n  test = function(opts_element)\n    -- Should respect non-empty 'winborder' while preferring explicitly\n    -- configured value over it\n    if vim.startswith(opts_element, 'window') then\n      if child.fn.has('nvim-0.11') == 0 then MiniTest.skip(\"'winborder' option is present on Neovim>=0.11\") end\n      child.o.winborder = 'rounded'\n    end\n\n    -- Testing \"in dynamic\" is left for manual approach\n    local path = get_ref_path('testref_reporters.lua')\n    local reporter_command = string.format('_G.reporter = MiniTest.gen_reporter.buffer({ %s })', opts_element)\n    child.lua(reporter_command)\n\n    local execute_command = string.format([[MiniTest.run_file('%s', { execute = { reporter = _G.reporter } })]], path)\n    child.lua(execute_command)\n\n    -- Unify path separator for more robust testing. Rely on search and replace\n    -- to preserve extmark highlighting.\n    if package.config:sub(1, 1) == '\\\\' then\n      local cur_pos = child.api.nvim_win_get_cursor(0)\n      child.cmd([[silent! %s^\\S\\zs\\\\^/^g]])\n      child.cmd('silent! nohlsearch')\n      set_cursor(unpack(cur_pos))\n    end\n\n    child.expect_screenshot()\n\n    -- Should be able to run several times\n    expect.no_error(function() child.lua(execute_command) end)\n    expect.no_error(function() child.lua(execute_command) end)\n\n    -- Should use properly named buffer\n    eq(child.api.nvim_buf_get_name(0), 'minitest://' .. child.api.nvim_get_current_buf() .. '/buffer-reporter')\n\n    child.cmd('quit')\n\n    -- Should work with \"string array\" 'winborder'\n    if child.fn.has('nvim-0.12') == 0 then MiniTest.skip(\"String array 'winborder' is present on Neovim>=0.12\") end\n    -- - Test only for one parameter that doesn't contain explicit `border`\n    if not (vim.startswith(opts_element, 'window') and opts_element:find('border') == nil) then return end\n\n    child.o.winborder = '+,-,+,|,+,-,+,|'\n    child.lua(execute_command)\n    child.expect_screenshot()\n  end,\n})\n\nT['gen_reporter']['stdout'] = new_set({\n  hooks = {\n    pre_case = function()\n      child.o.termguicolors = true\n      child.set_size(35, 120)\n      child.o.laststatus = 0\n    end,\n  },\n  parametrize = { { '' }, { 'TEST_GROUP_DEPTH=2' }, { 'TEST_QUIT_ON_FINISH=false' } },\n}, {\n  test = function(env_var)\n    helpers.skip_on_windows('Terminal tests are designed for Unix')\n\n    -- Testing \"in dynamic\" is left for manual approach\n    local path = 'tests/dir-test/init_stdout-reporter_works.lua'\n    local command = string.format([[%s %s --headless --clean -n -u %s]], env_var, vim.v.progpath, vim.inspect(path))\n    child.fn.termopen(command)\n    -- Wait until check is done and possible process is ended\n    vim.loop.sleep(terminal_wait)\n    local ignore_attr = child.fn.has('nvim-0.11') == 1 and {} or { 31, 32, 33, 34, 35 }\n    child.expect_screenshot({ ignore_attr = ignore_attr })\n  end,\n})\n\nreturn T\n"
  },
  {
    "path": "tests/test_trailspace.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('trailspace', config) end\nlocal unload_module = function() child.mini_unload('trailspace') end\nlocal set_cursor = function(...) return child.set_cursor(...) end\nlocal get_cursor = function(...) return child.get_cursor(...) end\nlocal set_lines = function(...) return child.set_lines(...) end\nlocal get_lines = function(...) return child.get_lines(...) end\nlocal type_keys = function(...) return child.type_keys(...) end\n--stylua: ignore end\n\n-- Make helpers\nlocal ensure_no_highlighting = function() child.fn.clearmatches() end\n\n-- Data =======================================================================\nlocal example_lines = { 'aa ', 'aa  ', 'aa\\t', 'aa\\t\\t', 'aa \\t', 'aa\\t ', '  aa', '\\taa' }\nlocal example_trimmed_lines = vim.tbl_map(function(x) return x:gsub('%s*$', '') end, example_lines)\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      child.set_size(10, 20)\n      child.o.hidden = true\n      set_lines(example_lines)\n      load_module()\n    end,\n    post_once = child.stop,\n  },\n  n_retry = helpers.get_n_retry(1),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniTrailspace)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniTrailspace'), 1)\n\n  -- Highlight groups\n  child.cmd('hi clear')\n  load_module()\n  expect.match(child.cmd_capture('hi MiniTrailspace'), 'links to Error')\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniTrailspace.config)'), 'table')\n\n  -- Check default values\n  eq(child.lua_get('MiniTrailspace.config.only_in_normal_buffers'), true)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ only_in_normal_buffers = false })\n  eq(child.lua_get('MiniTrailspace.config.only_in_normal_buffers'), false)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ only_in_normal_buffers = 'a' }, 'only_in_normal_buffers', 'boolean')\nend\n\nT['setup()']['ensures colors'] = function()\n  child.cmd('colorscheme default')\n  expect.match(child.cmd_capture('hi MiniTrailspace'), 'links to Error')\nend\n\nT['highlight()'] = new_set({ hooks = { pre_case = ensure_no_highlighting } })\n\nT['highlight()']['works'] = function()\n  child.expect_screenshot()\n  child.lua('MiniTrailspace.highlight()')\n  child.expect_screenshot()\nend\n\nT['highlight()']['respects `config.only_in_normal_buffers`'] = new_set({\n  parametrize = {\n    { true, '' },\n    { true, 'nofile' },\n    { true, 'help' },\n    { false, '' },\n    { false, 'nofile' },\n    { false, 'help' },\n  },\n}, {\n  test = function(option_value, buftype)\n    child.lua('MiniTrailspace.config.only_in_normal_buffers = ' .. tostring(option_value))\n    child.bo.buftype = buftype\n    child.lua('MiniTrailspace.highlight()')\n    child.expect_screenshot()\n  end,\n})\n\nT['highlight()']['respects `vim.b.minitrailspace_config`'] = function()\n  child.b.minitrailspace_config = { only_in_normal_buffers = false }\n  child.bo.buftype = 'nofile'\n  child.lua('MiniTrailspace.highlight()')\n  -- Should highlight\n  child.expect_screenshot()\nend\n\nT['highlight()']['works only in Normal mode'] = new_set({\n  parametrize = { { 'i' }, { 'v' }, { 'R' }, { ':' } },\n}, {\n  test = function(mode_key)\n    type_keys(mode_key)\n    child.lua('MiniTrailspace.highlight()')\n    -- Should be no highlighting\n    child.expect_screenshot()\n  end,\n})\n\nT['highlight()']['does not unnecessarily create match entry'] = function()\n  child.lua('MiniTrailspace.highlight()')\n  local matches = child.fn.getmatches()\n  eq(#matches, 1)\n\n  child.lua('MiniTrailspace.highlight()')\n  eq(child.fn.getmatches(), matches)\nend\n\nT['highlight()']['works after `clearmatches()`'] = function()\n  child.lua('MiniTrailspace.highlight()')\n  child.fn.clearmatches()\n  -- Should be no highlight\n  child.expect_screenshot()\n\n  child.lua('MiniTrailspace.highlight()')\n  -- Should be highlighted again\n  child.expect_screenshot()\nend\n\nT['highlight()']['respects `vim.{g,b}.minitrailspace_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child[var_type].minitrailspace_disable = true\n    child.lua('MiniTrailspace.highlight()')\n    -- Should show no highlight\n    child.expect_screenshot()\n  end,\n})\n\nT['unhighlight()'] = new_set({\n  hooks = {\n    pre_case = function() child.lua('MiniTrailspace.highlight()') end,\n  },\n})\n\nT['unhighlight()']['works'] = function()\n  child.expect_screenshot()\n  child.lua('MiniTrailspace.unhighlight()')\n  child.expect_screenshot()\nend\n\nT['unhighlight()']['works after `clearmatches()`'] = function()\n  child.fn.clearmatches()\n  child.lua('MiniTrailspace.unhighlight()')\n  child.expect_screenshot()\nend\n\nT['trim()'] = new_set()\n\nT['trim()']['works'] = function()\n  child.lua('MiniTrailspace.trim()')\n  eq(get_lines(), example_trimmed_lines)\nend\n\nT['trim()']['does not move cursor'] = function()\n  set_cursor(4, 1)\n  child.lua('MiniTrailspace.trim()')\n  eq(get_cursor(), { 4, 1 })\nend\n\nT['trim()']['does not update search pattern'] = function()\n  type_keys('/', 'aa', '<CR>')\n  child.lua('MiniTrailspace.trim()')\n  eq(child.fn.getreg('/'), 'aa')\nend\n\nT['trim_last_lines()'] = new_set()\n\nlocal validate_last_lines = function(init_lines, expected_lines)\n  set_lines(init_lines)\n  child.lua('MiniTrailspace.trim_last_lines()')\n  eq(get_lines(), expected_lines)\nend\n\nT['trim_last_lines()']['works'] = function()\n  validate_last_lines({ 'aa', '' }, { 'aa' })\n  validate_last_lines({ 'aa', ' ' }, { 'aa' })\n  validate_last_lines({ 'aa', '\\t' }, { 'aa' })\n\n  validate_last_lines({ 'aa' }, { 'aa' })\n  validate_last_lines({ '' }, { '' })\n  validate_last_lines({ 'aa ' }, { 'aa ' })\n\n  validate_last_lines({ 'aa', '', '' }, { 'aa' })\n  validate_last_lines({ 'aa', ' ', ' ' }, { 'aa' })\n  validate_last_lines({ 'aa', '', ' ', '' }, { 'aa' })\n\n  validate_last_lines({ '', 'aa', '' }, { '', 'aa' })\n  validate_last_lines({ ' ', 'aa', '' }, { ' ', 'aa' })\n\n  validate_last_lines({ ' aa', '' }, { ' aa' })\n  validate_last_lines({ 'aa ', '' }, { 'aa ' })\n\n  validate_last_lines({ 'aa', 'bb', '' }, { 'aa', 'bb' })\n  validate_last_lines({ 'aa', '', 'bb', '' }, { 'aa', '', 'bb' })\n  validate_last_lines({ 'aa', ' ', 'bb', ' ' }, { 'aa', ' ', 'bb' })\n  validate_last_lines({ '', 'aa', '', 'bb', '' }, { '', 'aa', '', 'bb' })\nend\n\n-- Integration tests ==========================================================\nT['Trailspace autohighlighting'] = new_set()\n\nT['Trailspace autohighlighting']['respects InsertEnter/InsertLeave'] = function()\n  child.lua('MiniTrailspace.highlight()')\n  child.expect_screenshot()\n\n  child.cmd('startinsert')\n  child.expect_screenshot()\n\n  child.cmd('stopinsert')\n  child.expect_screenshot()\nend\n\nT['Trailspace autohighlighting']['respects BufEnter/BufLeave'] = function()\n  child.lua('MiniTrailspace.highlight()')\n  child.expect_screenshot()\n\n  child.cmd('doautocmd BufLeave')\n  child.expect_screenshot()\n\n  child.cmd('doautocmd BufEnter')\n  child.expect_screenshot()\nend\n\nT['Trailspace autohighlighting']['respects WinEnter/WinLeave'] = function()\n  child.set_size(10, 40)\n  child.lua('MiniTrailspace.highlight()')\n  child.cmd('edit bbb | vsplit | edit aaa')\n  for _, buf_id in ipairs(child.api.nvim_list_bufs()) do\n    child.api.nvim_buf_set_lines(buf_id, 0, -1, true, example_lines)\n  end\n  local win_list = child.api.nvim_list_wins()\n\n  child.api.nvim_set_current_win(win_list[1])\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_win(win_list[2])\n  child.expect_screenshot()\n\n  child.api.nvim_set_current_win(win_list[1])\n  child.expect_screenshot()\nend\n\nT['Trailspace autohighlighting']['respects OptionSet'] = function()\n  child.lua('MiniTrailspace.highlight()')\n\n  child.bo.buftype = 'nowrite'\n  child.expect_screenshot()\n\n  child.bo.buftype = ''\n  child.expect_screenshot()\nend\n\nT['Trailspace highlighting on startup'] = new_set()\n\nT['Trailspace highlighting on startup']['works'] = function()\n  child.restart({\n    '-u',\n    'scripts/minimal_init.lua',\n    '-c',\n    [[lua require('mini.trailspace').setup()]],\n    '--',\n    'tests/dir-trailspace/file',\n  })\n  child.set_size(5, 12)\n  child.expect_screenshot({ ignore_text = helpers.is_windows() and { 4 } or {} })\nend\n\nreturn T\n"
  },
  {
    "path": "tests/test_visits.lua",
    "content": "local helpers = dofile('tests/helpers.lua')\n\nlocal child = helpers.new_child_neovim()\nlocal expect, eq = helpers.expect, helpers.expect.equality\nlocal new_set = MiniTest.new_set\n\n-- Helpers with child processes\n--stylua: ignore start\nlocal load_module = function(config) child.mini_load('visits', config) end\nlocal unload_module = function() child.mini_unload('visits') end\nlocal type_keys = function(...) return child.type_keys(...) end\nlocal sleep = function(ms) helpers.sleep(ms, child, true) end\nlocal edit = function(path) child.cmd('edit ' .. child.fn.fnameescape(path)) end\nlocal child_time = function() return child.lua_get('os.time()') end\n--stylua: ignore end\n\n-- Test paths helpers\nlocal join_path = function(...) return table.concat({ ... }, '/') end\n\nlocal full_path = function(x) return (child.fn.fnamemodify(x, ':p'):gsub('\\\\', '/'):gsub('/+', '/'):gsub('(.)/$', '%1')) end\n\nlocal test_dir = 'tests/dir-visits'\nlocal test_dir_absolute = vim.fn.fnamemodify(test_dir, ':p'):gsub('\\\\', '/'):gsub('(.)/$', '%1')\nlocal xdg_data_home = test_dir_absolute\nlocal data_std_path = xdg_data_home .. (helpers.is_windows() and '/nvim-data' or '/nvim')\n\nlocal make_testpath = function(...) return join_path(test_dir_absolute, ...) end\n\nlocal cleanup_index_file = function()\n  -- Clean up possibly written index file as it affects multiple test cases\n  local default_index_path = data_std_path .. '/mini-visits-index'\n  if vim.fn.filereadable(default_index_path) == 0 then return end\n  vim.fn.delete(default_index_path)\nend\n\n-- Common test wrappers\nlocal forward_lua = function(fun_str)\n  local lua_cmd = fun_str .. '(...)'\n  return function(...) return child.lua_get(lua_cmd, { ... }) end\nend\n\nlocal get_index = forward_lua('MiniVisits.get_index')\nlocal set_index = forward_lua('MiniVisits.set_index')\n\nlocal getcwd = function() return (child.fn.getcwd():gsub('\\\\', '/')) end\n\nlocal new_uri_scratch_buf = function()\n  local buf_id = child.api.nvim_create_buf(false, true)\n  child.api.nvim_buf_set_name(buf_id, 'xxx://hello/world')\n  return buf_id\nend\n\n-- Common test helpers\nlocal validate_buf_name = function(buf_id, name)\n  buf_id = buf_id or child.api.nvim_get_current_buf()\n  name = name ~= '' and full_path(name) or ''\n  name = name:gsub('/+$', '')\n  eq(child.api.nvim_buf_get_name(buf_id):gsub('\\\\', '/'), name)\nend\n\nlocal validate_partial_equal = function(test_tbl, ref_tbl)\n  eq(type(test_tbl), 'table')\n\n  local test_with_ref_keys = {}\n  for key, _ in pairs(ref_tbl) do\n    test_with_ref_keys[key] = test_tbl[key]\n  end\n  eq(test_with_ref_keys, ref_tbl)\nend\n\nlocal validate_index_entry = function(cwd, path, ref)\n  local index = child.lua_get('MiniVisits.get_index()')\n  local out = (index[full_path(cwd)] or {})[full_path(path)]\n  if ref == nil then\n    eq(out, nil)\n  else\n    validate_partial_equal(out, ref)\n  end\nend\n\nlocal make_ref_index_full = function(ref_index)\n  local ref_full = {}\n  for cwd, cwd_tbl in pairs(ref_index) do\n    local cwd_tbl_full = {}\n    for path, path_tbl in pairs(cwd_tbl) do\n      cwd_tbl_full[make_testpath(path)] = path_tbl\n    end\n    ref_full[make_testpath(cwd)] = cwd_tbl_full\n  end\n  return ref_full\nend\n\nlocal set_index_from_ref = function(ref) set_index(make_ref_index_full(ref)) end\n\n-- Common mocks\nlocal mock_ui_select = function(choice_index)\n  local lua_cmd = string.format(\n    [[\n    _G.ui_select_log = {}\n    vim.ui.select = function(items, opts, on_choice)\n      table.insert(_G.ui_select_log, { items = items, prompt = opts.prompt })\n      on_choice(items[%s], %s)\n    end]],\n    choice_index,\n    choice_index\n  )\n  child.lua(lua_cmd)\nend\n\nlocal get_ui_select_log = function() return child.lua_get('_G.ui_select_log') end\n\n-- Time constants\nlocal default_track_delay = 1000\nlocal small_time = helpers.get_time_const(10)\nlocal test_track_delay = 2 * small_time\n\n-- Output test set ============================================================\nlocal T = new_set({\n  hooks = {\n    pre_case = function()\n      child.setup()\n      cleanup_index_file()\n\n      -- Make `stdpath('data')` point to test directory\n      local lua_cmd = string.format([[vim.loop.os_setenv('XDG_DATA_HOME', %s)]], vim.inspect(xdg_data_home))\n      child.lua(lua_cmd)\n\n      -- Load module\n      load_module()\n\n      -- Make more comfortable screenshots\n      child.set_size(5, 60)\n      child.o.laststatus = 0\n      child.o.ruler = false\n    end,\n    post_once = function()\n      child.stop()\n      cleanup_index_file()\n      vim.fn.delete(data_std_path, 'rf')\n    end,\n  },\n  n_retry = helpers.get_n_retry(2),\n})\n\n-- Unit tests =================================================================\nT['setup()'] = new_set()\n\nT['setup()']['creates side effects'] = function()\n  -- Global variable\n  eq(child.lua_get('type(_G.MiniVisits)'), 'table')\n\n  -- Autocommand group\n  eq(child.fn.exists('#MiniVisits'), 1)\nend\n\nT['setup()']['creates `config` field'] = function()\n  eq(child.lua_get('type(_G.MiniVisits.config)'), 'table')\n\n  -- Check default values\n  local expect_config = function(field, value) eq(child.lua_get('MiniVisits.config.' .. field), value) end\n\n  expect_config('list.filter', vim.NIL)\n  expect_config('list.filter', vim.NIL)\n\n  expect_config('silent', false)\n\n  expect_config('store.autowrite', true)\n  expect_config('store.normalize', vim.NIL)\n  expect_config('store.path', child.fn.stdpath('data') .. '/mini-visits-index')\n\n  expect_config('track.event', 'BufEnter')\n  expect_config('track.delay', 1000)\nend\n\nT['setup()']['respects `config` argument'] = function()\n  unload_module()\n  load_module({ silent = true })\n  eq(child.lua_get('MiniVisits.config.silent'), true)\nend\n\nT['setup()']['validates `config` argument'] = function()\n  unload_module()\n\n  local expect_config_error = function(config, name, target_type)\n    expect.error(function() load_module(config) end, vim.pesc(name) .. '.*' .. vim.pesc(target_type))\n  end\n\n  expect_config_error('a', 'config', 'table')\n  expect_config_error({ list = 'a' }, 'list', 'table')\n  expect_config_error({ list = { filter = 'a' } }, 'list.filter', 'function')\n  expect_config_error({ list = { sort = 'a' } }, 'list.sort', 'function')\n\n  expect_config_error({ silent = 'a' }, 'silent', 'boolean')\n\n  expect_config_error({ store = 'a' }, 'store', 'table')\n  expect_config_error({ store = { autowrite = 'a' } }, 'store.autowrite', 'boolean')\n  expect_config_error({ store = { normalize = 'a' } }, 'store.normalize', 'function')\n  expect_config_error({ store = { path = 1 } }, 'store.path', 'string')\n\n  expect_config_error({ track = 'a' }, 'track', 'table')\n  expect_config_error({ track = { event = 1 } }, 'track.event', 'string')\n  expect_config_error({ track = { delay = 'a' } }, 'track.delay', 'number')\nend\n\nT['register_visit()'] = new_set()\n\nlocal register_visit = forward_lua('MiniVisits.register_visit')\n\nT['register_visit()']['works'] = function()\n  -- Should not check if arguments represent present paths on disk\n  local file_full, file_2_full = full_path('file'), full_path('dir/file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n\n  -- Should create entry if it is not present treating input as file system\n  -- entries (relative to current directory in this case)\n  eq(get_index(), {})\n  register_visit('file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 1, latest = child_time() } } })\n\n  register_visit('file', 'dir')\n  local latest_1 = child_time()\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 2, latest = latest_1 } } })\n\n  register_visit('dir/file-2', 'dir')\n  local latest_2 = child_time()\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 2, latest = latest_1 },\n      [file_2_full] = { count = 1, latest = latest_2 },\n    },\n  })\n\n  register_visit('file', 'dir-2')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 2, latest = latest_1 },\n      [file_2_full] = { count = 1, latest = latest_2 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 1, latest = child_time() },\n    },\n  })\nend\n\nT['register_visit()']['uses current data as defaults'] = function()\n  local path = make_testpath('file')\n  edit(path)\n  register_visit()\n  eq(get_index(), { [getcwd()] = { [path] = { count = 1, latest = child_time() } } })\n\n  -- Errors on non-normal buffer\n  child.api.nvim_set_current_buf(new_uri_scratch_buf())\n  expect.error(register_visit, 'not for a regular file')\nend\n\nT['register_visit()']['handles paths with \"~\" for home directory'] = function()\n  register_visit('~/file', '~/dir')\n  local home_dir = child.loop.os_homedir():gsub('\\\\', '/')\n  eq(\n    get_index(),\n    { [join_path(home_dir, 'dir')] = { [join_path(home_dir, 'file')] = { count = 1, latest = child_time() } } }\n  )\nend\n\nT['register_visit()']['does not affect other stored data'] = function()\n  local path, cwd = make_testpath('file'), test_dir_absolute\n  set_index({ [cwd] = { [path] = { count = 0, latest = 0, aaa = { bbb = true } } } })\n  register_visit(path, cwd)\n  eq(get_index(), { [cwd] = { [path] = { count = 1, latest = child_time(), aaa = { bbb = true } } } })\nend\n\nT['register_visit()']['validates arguments'] = function()\n  local validate = function(error_pattern, ...)\n    local args = { ... }\n    expect.error(function() register_visit(unpack(args)) end, error_pattern)\n  end\n\n  validate('`path`.*string', 1, 'dir')\n  validate('`cwd`.*string', 'file', 1)\n  validate('`path` and `cwd`.*not.*empty', '', 'dir')\n  validate('`path` and `cwd`.*not.*empty', 'file', '')\nend\n\nT['add_path()'] = new_set()\n\nlocal add_path = forward_lua('MiniVisits.add_path')\n\nT['add_path()']['works'] = function()\n  -- Should not check if arguments represent present paths on disk\n  local dir_full = full_path('dir')\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n\n  add_path('file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, latest = 0 } } })\n\n  -- Should do nothing if path-cwd already exists\n  add_path('file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, latest = 0 } } })\n\n  add_path('file-2', 'dir')\n  eq(\n    get_index(),\n    { [dir_full] = { [file_full] = { count = 0, latest = 0 }, [file_2_full] = { count = 0, latest = 0 } } }\n  )\nend\n\nT['add_path()']['works with empty string arguments'] = function()\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n  local init_tbl = { count = 0, latest = 0 }\n\n  -- If no visits, should result into no added paths\n  add_path('', 'dir')\n  eq(get_index(), {})\n  add_path('file', '')\n  eq(get_index(), {})\n  add_path('', '')\n  eq(get_index(), {})\n\n  -- Empty string for `path` should mean \"add all present paths in cwd\".\n  -- Not useful, but should be allowed for consistency with other functions.\n  add_path('file', 'dir')\n  add_path('', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = init_tbl } })\n\n  -- Empty string for `cwd` should mean \"add path to all visited cwds\".\n  add_path('file', 'dir-2')\n  add_path('file-2', '')\n  eq(get_index(), {\n    [dir_full] = { [file_full] = init_tbl, [file_2_full] = init_tbl },\n    [dir_2_full] = { [file_full] = init_tbl, [file_2_full] = init_tbl },\n  })\nend\n\nT['add_path()']['uses current data as defaults'] = function()\n  local path = make_testpath('file')\n  edit(path)\n  add_path()\n  eq(get_index(), { [getcwd()] = { [path] = { count = 0, latest = 0 } } })\n\n  -- Errors on non-normal buffer\n  child.api.nvim_set_current_buf(new_uri_scratch_buf())\n  expect.error(add_path, 'not for a regular file')\nend\n\nT['add_path()']['does not affect other stored data'] = function()\n  local path, cwd = make_testpath('file'), test_dir_absolute\n  set_index({ [cwd] = { [path] = { count = 0, latest = 0, aaa = { bbb = true } } } })\n  add_path(path, cwd)\n  eq(get_index(), { [cwd] = { [path] = { count = 0, latest = 0, aaa = { bbb = true } } } })\nend\n\nT['add_path()']['validates arguments'] = function()\n  expect.error(function() add_path(1, 'dir') end, '`path`.*string')\n  expect.error(function() add_path('file', 1) end, '`cwd`.*string')\nend\n\nT['add_label()'] = new_set()\n\nlocal add_label = forward_lua('MiniVisits.add_label')\n\nT['add_label()']['works'] = function()\n  -- Should not check if arguments represent present paths on disk\n  local file_full, dir_full = full_path('file'), full_path('dir')\n\n  -- Should add path if it is not present\n  add_label('aaa', 'file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, labels = { aaa = true }, latest = 0 } } })\n\n  -- Should show feedback message\n  child.expect_screenshot()\n\n  -- Should add to already existing path-cwd pair\n  add_label('bbb', 'file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, labels = { aaa = true, bbb = true }, latest = 0 } } })\n\n  -- Should not affect already present data\n  register_visit('file', 'dir')\n  add_label('ccc', 'file', 'dir')\n  eq(get_index(), {\n    [dir_full] = { [file_full] = { count = 1, labels = { aaa = true, bbb = true, ccc = true }, latest = child_time() } },\n  })\nend\n\nT['add_label()']['works with empty string arguments'] = function()\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n\n  -- If no visits, should result into no added paths and labels\n  add_path('', 'dir')\n  eq(get_index(), {})\n  add_path('file', '')\n  eq(get_index(), {})\n  add_path('', '')\n  eq(get_index(), {})\n\n  -- Empty string for `path` should mean \"add to all present paths in cwd\"\n  add_path('file', 'dir')\n  add_path('file-2', 'dir')\n  add_label('aaa', '', 'dir')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, labels = { aaa = true }, latest = 0 },\n      [file_2_full] = { count = 0, labels = { aaa = true }, latest = 0 },\n    },\n  })\n\n  -- Empty string for `cwd` should mean \"add to path in all present cwds\"\n  add_path('file', 'dir-2')\n  add_label('bbb', 'file', '')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, labels = { aaa = true, bbb = true }, latest = 0 },\n      [file_2_full] = { count = 0, labels = { aaa = true }, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, labels = { bbb = true }, latest = 0 },\n    },\n  })\n\n  -- Both empty strings should mean \"add to all present paths in present cwds\"\n  add_label('ccc', '', '')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, labels = { aaa = true, bbb = true, ccc = true }, latest = 0 },\n      [file_2_full] = { count = 0, labels = { aaa = true, ccc = true }, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, labels = { bbb = true, ccc = true }, latest = 0 },\n    },\n  })\nend\n\nT['add_label()']['uses current data as defaults for path and cwd'] = function()\n  local path = make_testpath('file')\n  edit(path)\n  add_label('aaa')\n  eq(get_index(), { [getcwd()] = { [path] = { count = 0, labels = { aaa = true }, latest = 0 } } })\n\n  -- Errors on non-normal buffer\n  child.api.nvim_set_current_buf(new_uri_scratch_buf())\n  expect.error(function() add_label('aaa') end, 'not for a regular file')\nend\n\nT['add_label()']['asks user for label if it is not supplied'] = function()\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n\n  child.lua_notify([[MiniVisits.add_label(nil, 'file', 'dir')]])\n  child.expect_screenshot()\n  type_keys('aaa', '<CR>')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, labels = { aaa = true }, latest = 0 } } })\n\n  -- Has completion with all labels from target cwd\n  add_label('abb', 'file-2', 'dir')\n  add_label('bbb', 'file', 'dir')\n  add_label('ccc', 'file', 'dir-2')\n  add_label('ddd', 'file-2', 'dir-2')\n\n  child.lua_notify([[MiniVisits.add_label(nil, 'file', 'dir')]])\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- - Should properly filter it\n  type_keys('<C-e>', 'a', '<Tab>')\n  child.expect_screenshot()\n\n  -- - Can be canceled without adding any label\n  type_keys('<C-c>')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, labels = { aaa = true, bbb = true }, latest = 0 },\n      [file_2_full] = { count = 0, labels = { abb = true }, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, labels = { ccc = true }, latest = 0 },\n      [file_2_full] = { count = 0, labels = { ddd = true }, latest = 0 },\n    },\n  })\nend\n\nT['add_label()']['does not affect other stored data'] = function()\n  local path, cwd = make_testpath('file'), test_dir_absolute\n  set_index({ [cwd] = { [path] = { count = 0, latest = 0, aaa = { bbb = true } } } })\n  add_label('xxx', path, cwd)\n  eq(get_index(), { [cwd] = { [path] = { count = 0, labels = { xxx = true }, latest = 0, aaa = { bbb = true } } } })\nend\n\nT['add_label()']['validates arguments'] = function()\n  expect.error(function() add_label(1, 'file', 'dir') end, '`label`.*string')\n  expect.error(function() add_label('aaa', 1, 'dir') end, '`path`.*string')\n  expect.error(function() add_label('aaa', 'file', 1) end, '`cwd`.*string')\nend\n\nT['remove_path()'] = new_set()\n\nlocal remove_path = forward_lua('MiniVisits.remove_path')\n\nT['remove_path()']['works'] = function()\n  -- Should not check if arguments represent present paths on disk\n  local dir_full = full_path('dir')\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n\n  add_path('file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, latest = 0 } } })\n  remove_path('file', 'dir')\n  eq(get_index(), {})\n\n  -- Should do nothing if path-cwd already absent\n  remove_path('file', 'dir')\n  eq(get_index(), {})\nend\n\nT['remove_path()']['works with empty string arguments'] = function()\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n  local init_tbl = { count = 0, latest = 0 }\n\n  -- If no visits, should result into no errors\n  remove_path('', 'dir')\n  eq(get_index(), {})\n  remove_path('file', '')\n  eq(get_index(), {})\n  remove_path('', '')\n  eq(get_index(), {})\n\n  -- Empty string for `path` should mean \"remove all present paths in cwd\".\n  add_path('file', 'dir')\n  add_path('file-2', 'dir')\n  add_path('file', 'dir-2')\n  remove_path('', 'dir')\n  eq(get_index(), { [dir_2_full] = { [file_full] = init_tbl } })\n\n  -- Empty string for `cwd` should mean \"remove path from all visited cwds\".\n  add_path('file', 'dir')\n  add_path('file-2', 'dir')\n  remove_path('file', '')\n  eq(get_index(), { [dir_full] = { [file_2_full] = init_tbl } })\n\n  -- Both empty strings should essentially mean \"remove all present\"\n  add_path('file', 'dir')\n  add_path('file-2', 'dir')\n  remove_path('', '')\n  eq(get_index(), {})\nend\n\nT['remove_path()']['uses current data as defaults'] = function()\n  local path = make_testpath('file')\n  edit(path)\n  add_path()\n  eq(get_index(), { [getcwd()] = { [path] = { count = 0, latest = 0 } } })\n\n  remove_path()\n  eq(get_index(), {})\n\n  -- Errors on non-normal buffer\n  child.api.nvim_set_current_buf(new_uri_scratch_buf())\n  expect.error(remove_path, 'not for a regular file')\nend\n\nT['remove_path()']['validates arguments'] = function()\n  expect.error(function() remove_path(1, 'dir') end, '`path`.*string')\n  expect.error(function() remove_path('file', 1) end, '`cwd`.*string')\nend\n\nT['remove_label()'] = new_set()\n\nlocal remove_label = forward_lua('MiniVisits.remove_label')\n\nT['remove_label()']['works'] = function()\n  -- Should not check if arguments represent present paths on disk\n  local file_full, dir_full = full_path('file'), full_path('dir')\n\n  add_label('aaa', 'file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, labels = { aaa = true }, latest = 0 } } })\n\n  remove_label('aaa', 'file', 'dir')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, latest = 0 } } })\n\n  -- Should show feedback message\n  child.expect_screenshot()\n\n  -- Should not affect already present data\n  register_visit('file', 'dir')\n  add_label('bbb', 'file', 'dir')\n  add_label('ccc', 'file', 'dir')\n  remove_label('bbb', 'file', 'dir')\n  eq(get_index(), {\n    [dir_full] = { [file_full] = { count = 1, labels = { ccc = true }, latest = child_time() } },\n  })\nend\n\nT['remove_label()']['works with empty string arguments'] = function()\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n\n  -- If no visits, should result into no error\n  remove_path('', 'dir')\n  eq(get_index(), {})\n  remove_path('file', '')\n  eq(get_index(), {})\n  remove_path('', '')\n  eq(get_index(), {})\n\n  -- Empty string for `path` should mean \"remove from all present paths in cwd\"\n  add_label('aaa', 'file', 'dir')\n  add_label('aaa', 'file-2', 'dir')\n  add_label('aaa', 'file', 'dir-2')\n  remove_label('aaa', '', 'dir')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, latest = 0 },\n      [file_2_full] = { count = 0, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, labels = { aaa = true }, latest = 0 },\n    },\n  })\n\n  -- Empty string for `cwd` should mean \"remove from path in all present cwds\"\n  add_label('aaa', 'file', 'dir')\n  add_label('aaa', 'file-2', 'dir')\n  remove_label('aaa', 'file', '')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, latest = 0 },\n      [file_2_full] = { count = 0, labels = { aaa = true }, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, latest = 0 },\n    },\n  })\n\n  -- Both empty should mean \"remove from all present paths in present cwds\"\n  add_label('aaa', 'file', 'dir')\n  add_label('aaa', 'file', 'dir-2')\n  remove_label('aaa', '', '')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, latest = 0 },\n      [file_2_full] = { count = 0, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, latest = 0 },\n    },\n  })\nend\n\nT['remove_label()']['uses current data as defaults for path and cwd'] = function()\n  local path = make_testpath('file')\n  edit(path)\n  add_label('aaa')\n  eq(get_index(), { [getcwd()] = { [path] = { count = 0, labels = { aaa = true }, latest = 0 } } })\n\n  remove_label('aaa')\n  eq(get_index(), { [getcwd()] = { [path] = { count = 0, latest = 0 } } })\n\n  -- Errors on non-normal buffer\n  child.api.nvim_set_current_buf(new_uri_scratch_buf())\n  expect.error(function() remove_label('aaa') end, 'not for a regular file')\nend\n\nT['remove_label()']['asks user for label if it is not supplied'] = function()\n  local file_full, file_2_full = full_path('file'), full_path('file-2')\n  local dir_full, dir_2_full = full_path('dir'), full_path('dir-2')\n\n  add_label('aaa', 'file', 'dir')\n  add_label('bbb', 'file', 'dir')\n\n  child.lua_notify([[MiniVisits.remove_label(nil, 'file', 'dir')]])\n  child.expect_screenshot()\n  type_keys('aaa', '<CR>')\n  eq(get_index(), { [dir_full] = { [file_full] = { count = 0, labels = { bbb = true }, latest = 0 } } })\n\n  -- Has completion with all labels from target path-cwd pair\n  add_label('aaa', 'file', 'dir')\n  add_label('abb', 'file', 'dir')\n  add_label('bbb', 'file', 'dir')\n\n  add_label('ccc', 'file-2', 'dir')\n  add_label('ddd', 'file', 'dir-2')\n\n  child.lua_notify([[MiniVisits.remove_label(nil, 'file', 'dir')]])\n  type_keys('<Tab>')\n  child.expect_screenshot()\n\n  -- - Should properly filter it\n  type_keys('<C-e>', 'a', '<Tab>')\n  child.expect_screenshot()\n\n  -- - Can be canceled without adding any label\n  type_keys('<C-c>')\n  eq(get_index(), {\n    [dir_full] = {\n      [file_full] = { count = 0, labels = { aaa = true, abb = true, bbb = true }, latest = 0 },\n      [file_2_full] = { count = 0, labels = { ccc = true }, latest = 0 },\n    },\n    [dir_2_full] = {\n      [file_full] = { count = 0, labels = { ddd = true }, latest = 0 },\n    },\n  })\nend\n\nT['remove_label()']['does not affect other stored data'] = function()\n  local path, cwd = make_testpath('file'), test_dir_absolute\n  set_index({ [cwd] = { [path] = { count = 0, labels = { xxx = true }, latest = 0, aaa = { bbb = true } } } })\n  remove_label('xxx', path, cwd)\n  eq(get_index(), { [cwd] = { [path] = { count = 0, latest = 0, aaa = { bbb = true } } } })\nend\n\nT['remove_label()']['validates arguments'] = function()\n  expect.error(function() remove_label(1, 'file', 'dir') end, '`label`.*string')\n  expect.error(function() remove_label('aaa', 1, 'dir') end, '`path`.*string')\n  expect.error(function() remove_label('aaa', 'file', 1) end, '`cwd`.*string')\nend\n\nT['list_paths()'] = new_set()\n\nlocal list_paths = forward_lua('MiniVisits.list_paths')\n\nT['list_paths()']['works'] = function()\n  local cur_time = child_time()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, latest = cur_time - 3 },\n      ['dir_1/file_1-2'] = { count = 1, latest = cur_time - 4 },\n    },\n    dir_2 = {\n      ['dir_2/file_2-1'] = { count = 3, latest = cur_time - 2 },\n      ['dir_1/file_1-2'] = { count = 4, latest = cur_time - 1 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  local validate_dir_1 = function(cwd)\n    eq(list_paths(cwd), { make_testpath('dir_1', 'file_1-1'), make_testpath('dir_1', 'file_1-2') })\n  end\n\n  -- Should work with relative path `cwd`\n  local rel_cwd = join_path(test_dir, 'dir_1')\n  validate_dir_1(rel_cwd)\n\n  -- Should work with absolute path `cwd`\n  local abs_cwd = full_path(rel_cwd)\n  validate_dir_1(abs_cwd)\n\n  -- Should use current working directory by default\n  child.fn.chdir(make_testpath('dir_1'))\n  validate_dir_1(nil)\n\n  -- Should work with empty string `cwd` meaning \"all visited cwds\"\n  eq(\n    list_paths(''),\n    { make_testpath('dir_1', 'file_1-2'), make_testpath('dir_2', 'file_2-1'), make_testpath('dir_1', 'file_1-1') }\n  )\n\n  -- Should not affect the index\n  eq(get_index(), make_ref_index_full(ref_index))\nend\n\nT['list_paths()']['respects `opts.filter`'] = function()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, latest = 10 },\n      ['dir_1/file_1-2'] = { count = 1, latest = 9 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  child.lua([[\n    _G.filter_args_log = {}\n    _G.filter = function(...)\n      table.insert(_G.filter_args_log, { ... })\n      local path_data = ({ ... })[1]\n      return path_data.count > 1\n    end]])\n\n  child.lua('_G.cwd = ' .. vim.inspect(make_testpath('dir_1')))\n  eq(child.lua_get([[MiniVisits.list_paths(cwd, { filter = _G.filter })]]), { make_testpath('dir_1', 'file_1-1') })\n\n  local args_log = child.lua_get('_G.filter_args_log')\n  -- - Ensure same order in test, as there is no guarantee of order\n  table.sort(args_log, function(a, b) return a[1].path < b[1].path end)\n  eq(args_log, {\n    { { count = 2, latest = 10, path = make_testpath('dir_1', 'file_1-1') } },\n    { { count = 1, latest = 9, path = make_testpath('dir_1', 'file_1-2') } },\n  })\nend\n\nT['list_paths()']['respects `opts.sort`'] = function()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, latest = 10 },\n      ['dir_1/file_1-2'] = { count = 1, latest = 9 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  child.lua([[\n    _G.sort_args_log = {}\n    _G.sort = function(...)\n      table.insert(_G.sort_args_log, { ... })\n      local path_data_arr = vim.deepcopy(({ ... })[1])\n      table.sort(path_data_arr, function(a, b) return a.count < b.count end)\n      return path_data_arr\n    end]])\n\n  child.lua('_G.cwd = ' .. vim.inspect(make_testpath('dir_1')))\n  eq(\n    child.lua_get([[MiniVisits.list_paths(_G.cwd, { sort = _G.sort })]]),\n    { make_testpath('dir_1', 'file_1-2'), make_testpath('dir_1', 'file_1-1') }\n  )\n\n  local args_log = child.lua_get('_G.sort_args_log')\n  eq(vim.tbl_count(args_log), 1)\n  local path_data_arr = args_log[1][1]\n  -- - Ensure same order in test, as there is no guarantee of order\n  table.sort(path_data_arr, function(a, b) return a.path < b.path end)\n  eq(path_data_arr, {\n    { count = 2, latest = 10, path = make_testpath('dir_1', 'file_1-1') },\n    { count = 1, latest = 9, path = make_testpath('dir_1', 'file_1-2') },\n  })\nend\n\nT['list_paths()']['allows `opts.sort` to return non-related array'] = function()\n  child.lua([[_G.sort = function() return { { path = 'bb' }, { path = 'aa' } } end]])\n  eq(child.lua_get([[MiniVisits.list_paths('', { sort = _G.sort })]]), { 'bb', 'aa' })\nend\n\nT['list_paths()']['properly merges visit data for filter and sort'] = function()\n  --stylua: ignore\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, latest = 10, aaa = 1 },\n      ['dir_1/file_1-2'] = { count = 1, latest = 9, bbb  = 'a' },\n      ['file']           = { count = 1, latest = 8, data = { bool = true, num = 2, str = 'b' } },\n    },\n    dir_2 = {\n      ['dir_1/file_1-1'] = { count = 11, latest = 100, ccc = 3 },\n      ['file']           = { count = 10, latest = 1, data = { bool2 = true, num2 = 2, str2 = 'b' } },\n    }\n  }\n  set_index_from_ref(ref_index)\n\n  child.lua([[\n    _G.filter_args_log, _G.sort_args_log = {}, {}\n    _G.filter = function(...)\n      table.insert(_G.filter_args_log, { ... })\n      return true\n    end\n    _G.sort = function(...)\n      table.insert(_G.sort_args_log, { ... })\n      return ({...})[1]\n    end]])\n\n  child.lua_get([[MiniVisits.list_paths('', { filter = _G.filter, sort = _G.sort })]])\n\n  -- Filter\n  local filter_args_log = child.lua_get('_G.filter_args_log')\n  -- - Ensure same order in test, as there is no guarantee of order\n  table.sort(filter_args_log, function(a, b) return a[1].path < b[1].path end)\n\n  eq(filter_args_log, {\n    -- `count` should be summed, `latest` should be reduced with `math.max`,\n    -- non-related fields should be merged\n    { { count = 13, latest = 100, path = make_testpath('dir_1', 'file_1-1'), aaa = 1, ccc = 3 } },\n    { { count = 1, latest = 9, path = make_testpath('dir_1', 'file_1-2'), bbb = 'a' } },\n    {\n      {\n        count = 11,\n        latest = 8,\n        path = make_testpath('file'),\n        data = { bool = true, bool2 = true, num = 2, num2 = 2, str = 'b', str2 = 'b' },\n      },\n    },\n  })\n\n  -- Sort\n  local sort_args_log = child.lua_get('_G.sort_args_log')\n  eq(vim.tbl_count(sort_args_log), 1)\n  local path_data_arr = sort_args_log[1][1]\n  -- - Ensure same order in test, as there is no guarantee of order\n  table.sort(path_data_arr, function(a, b) return a.path < b.path end)\n\n  eq(path_data_arr, {\n    { count = 13, latest = 100, path = make_testpath('dir_1', 'file_1-1'), aaa = 1, ccc = 3 },\n    { count = 1, latest = 9, path = make_testpath('dir_1', 'file_1-2'), bbb = 'a' },\n    {\n      count = 11,\n      latest = 8,\n      path = make_testpath('file'),\n      data = { bool = true, bool2 = true, num = 2, num2 = 2, str = 'b', str2 = 'b' },\n    },\n  })\nend\n\nT['list_paths()']['respects `config.list`'] = function()\n  set_index_from_ref({ dir_1 = { file = { count = 1, latest = 10 } } })\n\n  child.lua([[\n    _G.filter = function()\n      _G.filter_been_here = true\n      return true\n    end\n    _G.sort = function(...)\n      _G.sort_been_here = true\n      return ({...})[1]\n    end]])\n  child.lua('MiniVisits.config.list = { filter = _G.filter, sort = _G.sort }')\n\n  list_paths('')\n\n  eq(child.lua_get('_G.filter_been_here'), true)\n  eq(child.lua_get('_G.sort_been_here'), true)\nend\n\nT['list_paths()']['validates arguments'] = function()\n  expect.error(function() list_paths(1) end, '`cwd`.*string')\nend\n\nT['list_labels()'] = new_set()\n\nlocal list_labels = forward_lua('MiniVisits.list_labels')\n\nT['list_labels()']['works'] = function()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 0, labels = { xxx = true, bbb = true }, latest = 0 },\n      ['dir_1/file_1-2'] = { count = 0, labels = { xxx = true, aaa = true }, latest = 0 },\n    },\n    dir_2 = {\n      ['dir_2/file_2-1'] = { count = 0, latest = 0 },\n      ['dir_1/file_1-2'] = { count = 0, labels = { xxx = true, yyy = true }, latest = 0 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  -- Should first sort by decreasing frequency of appearance for different\n  -- paths. Ties should be resolved alphabetically.\n\n  -- Should work with relative paths\n  local rel_path = join_path(test_dir, 'dir_1', 'file_1-1')\n  local rel_cwd = join_path(test_dir, 'dir_1')\n  eq(list_labels(rel_path, rel_cwd), { 'bbb', 'xxx' })\n\n  -- Should work with absolute paths\n  local abs_path = full_path(rel_path)\n  local abs_cwd = full_path(rel_cwd)\n  eq(list_labels(abs_path, abs_cwd), { 'bbb', 'xxx' })\n\n  -- Should use current file and directory as defaults\n  child.fn.chdir(make_testpath('dir_1'))\n  edit('file_1-1')\n  eq(list_labels(), { 'bbb', 'xxx' })\n\n  -- Should work with empty string `path` meaning \"all paths in target cwd\"\n  eq(list_labels('', abs_cwd), { 'xxx', 'aaa', 'bbb' })\n\n  -- Should work with empty string `cwd` meaning \"path in all cwds\"\n  -- - NOTE: Although `xxx` label happens twice, it is still counted as one\n  --   because it is for the same path.\n  eq(list_labels(make_testpath('dir_1', 'file_1-2'), ''), { 'aaa', 'xxx', 'yyy' })\n\n  -- Should work with both empty strings meaning \"all visits\"\n  eq(list_labels('', ''), { 'xxx', 'aaa', 'bbb', 'yyy' })\n\n  -- Should work with empty string `cwd` meaning \"all visited cwds\"\n  eq(get_index(), make_ref_index_full(ref_index))\nend\n\nT['list_labels()']['respects `opts.filter`'] = function()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, labels = { xxx = true, aaa = true }, latest = 10 },\n      ['dir_1/file_1-2'] = { count = 1, labels = { xxx = true, bbb = true }, latest = 9 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  child.lua([[\n    _G.filter_args_log = {}\n    _G.filter = function(...)\n      table.insert(_G.filter_args_log, { ... })\n      local path_data = ({ ... })[1]\n      return path_data.count > 1\n    end]])\n\n  child.lua('_G.cwd = ' .. vim.inspect(make_testpath('dir_1')))\n  eq(child.lua_get([[MiniVisits.list_labels('', cwd, { filter = _G.filter })]]), { 'aaa', 'xxx' })\n\n  local args_log = child.lua_get('_G.filter_args_log')\n  -- - Ensure same order in test, as there is no guarantee of order\n  table.sort(args_log, function(a, b) return a[1].path < b[1].path end)\n  eq(args_log, {\n    { { count = 2, labels = { xxx = true, aaa = true }, latest = 10, path = make_testpath('dir_1', 'file_1-1') } },\n    { { count = 1, labels = { xxx = true, bbb = true }, latest = 9, path = make_testpath('dir_1', 'file_1-2') } },\n  })\nend\n\nT['list_labels()']['properly merges visit data for filter'] = function()\n  --stylua: ignore\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, labels = { xxx = true, aaa = true }, latest = 10, aaa = 1 },\n      ['dir_1/file_1-2'] = { count = 1, labels = { xxx = true, bbb = true }, latest = 9, bbb  = 'a' },\n      ['file']           = { count = 1, latest = 8, data = { bool = true, num = 2, str = 'b' } },\n    },\n    dir_2 = {\n      ['dir_1/file_1-1'] = { count = 11, labels = { xxx = true, ccc = true }, latest = 100, ccc = 3 },\n      ['file']           = { count = 10, latest = 1, data = { bool2 = true, num2 = 2, str2 = 'b' } },\n    }\n  }\n  set_index_from_ref(ref_index)\n\n  child.lua([[\n    _G.filter_args_log = {}\n    _G.filter = function(...)\n      table.insert(_G.filter_args_log, { ... })\n      return true\n    end]])\n\n  child.lua_get([[MiniVisits.list_labels('', '', { filter = _G.filter })]])\n\n  local filter_args_log = child.lua_get('_G.filter_args_log')\n  -- - Ensure same order in test, as there is no guarantee of order\n  table.sort(filter_args_log, function(a, b) return a[1].path < b[1].path end)\n\n  eq(filter_args_log, {\n    -- `count` should be summed, `latest` should be reduced with `math.max`,\n    -- non-related fields should be merged\n    {\n      {\n        count = 13,\n        labels = { xxx = true, aaa = true, ccc = true },\n        latest = 100,\n        path = make_testpath('dir_1', 'file_1-1'),\n        aaa = 1,\n        ccc = 3,\n      },\n    },\n    {\n      {\n        count = 1,\n        labels = { xxx = true, bbb = true },\n        latest = 9,\n        path = make_testpath('dir_1', 'file_1-2'),\n        bbb = 'a',\n      },\n    },\n    {\n      {\n        count = 11,\n        latest = 8,\n        path = make_testpath('file'),\n        data = { bool = true, bool2 = true, num = 2, num2 = 2, str = 'b', str2 = 'b' },\n      },\n    },\n  })\nend\n\nT['list_labels()']['respects `config.list`'] = function()\n  set_index_from_ref({ dir_1 = { file = { count = 1, labels = { xxx = true }, latest = 10 } } })\n\n  child.lua([[\n    _G.filter = function()\n      _G.filter_been_here = true\n      return true\n    end]])\n  child.lua('MiniVisits.config.list = { filter = _G.filter }')\n\n  list_labels('', '')\n  eq(child.lua_get('_G.filter_been_here'), true)\nend\n\nT['list_labels()']['validates arguments'] = function()\n  expect.error(function() list_labels(1, 'cwd') end, '`path`.*string')\n  expect.error(function() list_labels('file', 1) end, '`cwd`.*string')\n\n  child.api.nvim_set_current_buf(new_uri_scratch_buf())\n  expect.error(function() list_labels() end, 'not for a regular file')\nend\n\nT['select_path()'] = new_set({\n  hooks = {\n    pre_case = function()\n      -- Ensure consistent path separator\n      child.lua([[\n        local getcwd_orig = vim.fn.getcwd\n        vim.fn.getcwd = function() return (getcwd_orig():gsub('\\\\', '/')) end\n      ]])\n    end,\n  },\n})\n\nlocal select_path = forward_lua('MiniVisits.select_path')\n\nT['select_path()']['works'] = function()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 2, latest = 10 },\n      ['dir_1/file_1-2'] = { count = 1, latest = 9 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  child.fn.chdir(make_testpath('dir_1'))\n\n  mock_ui_select(1)\n  select_path()\n  eq(get_ui_select_log(), {\n    {\n      items = {\n        { path = make_testpath('dir_1', 'file_1-1'), text = 'file_1-1' },\n        { path = make_testpath('dir_1', 'file_1-2'), text = 'file_1-2' },\n      },\n      prompt = 'Visited paths',\n    },\n  })\n  validate_buf_name(0, 'file_1-1')\n\n  -- Should open path in relative form for nicer `:buffers`\n  expect.match(child.cmd_capture('buffers'), '[^/]file_1%-1')\nend\n\nT['select_path()']['mimics empty buffer reuse'] = function()\n  local ref_index = { dir_1 = { ['dir_1/file_1-1'] = { count = 2, latest = 10 } } }\n  set_index_from_ref(ref_index)\n  child.fn.chdir(make_testpath('dir_1'))\n  mock_ui_select(1)\n\n  local validate = function(ref_n_bufs)\n    select_path()\n    eq(#child.api.nvim_list_bufs(), ref_n_bufs)\n    child.cmd('%bwipeout!')\n  end\n\n  -- Should mimic `:h buffer-reuse` similar to how `:edit` does it\n  eq(child.api.nvim_get_current_buf() == 1, true)\n  validate(1)\n\n  eq(child.api.nvim_get_current_buf() ~= 1, true)\n  validate(1)\n\n  child.cmd('tabnew')\n  validate(2)\n\n  -- Should reuse only for strict set of conditions\n  child.api.nvim_buf_set_name(0, 'named-buf')\n  validate(2)\n\n  child.bo.buftype = 'quickfix'\n  validate(2)\n\n  child.cmd('split')\n  eq(#child.fn.win_findbuf(child.api.nvim_get_current_buf()), 2)\n  validate(2)\n\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { ' ' })\n  validate(2)\n\n  child.bo.modified = true\n  validate(2)\nend\n\nT['select_path()']['properly shortens paths'] = function()\n  local home_dir = child.loop.os_homedir()\n\n  local dir_path = make_testpath('dir_1')\n  child.fn.chdir(dir_path)\n  set_index({\n    [dir_path] = {\n      [join_path(dir_path, 'subdir', 'file_1-1-1')] = { count = 2, latest = 10 },\n      [join_path(home_dir, 'file')] = { count = 1, latest = 9 },\n    },\n  })\n\n  mock_ui_select(1)\n  select_path()\n  local items = get_ui_select_log()[1].items\n  eq(items[1].text, 'subdir/file_1-1-1')\n  eq(items[2].text, '~/file')\nend\n\nT['select_path()']['can be properly canceled'] = function()\n  local ref_index = { dir_1 = { file = { count = 1, latest = 10 } } }\n  set_index_from_ref(ref_index)\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local init_buf_name = child.api.nvim_buf_get_name(init_buf_id)\n  mock_ui_select(nil)\n  select_path()\n\n  eq(child.api.nvim_get_current_buf(), init_buf_id)\n  eq(child.api.nvim_buf_get_name(0), init_buf_name)\nend\n\nT['select_path()']['reuses current buffer when opening path'] = function()\n  local ref_index = { dir_1 = { file = { count = 1, latest = 10 } } }\n  set_index_from_ref(ref_index)\n\n  child.fn.chdir(make_testpath('dir_1'))\n  edit(make_testpath('file'))\n  local file_buf_id = child.api.nvim_get_current_buf()\n\n  edit(make_testpath('dir_1/file_1-1'))\n  child.api.nvim_buf_set_option(file_buf_id, 'buflisted', false)\n\n  mock_ui_select(1)\n  select_path()\n\n  eq(child.api.nvim_get_current_buf(), file_buf_id)\n  -- Should make unlisted buffer listed\n  eq(child.bo.buflisted, true)\nend\n\nT['select_path()']['forwards arguments to `list_paths()`'] = function()\n  local ref_index = { dir_1 = { file = { count = 1, latest = 10 } } }\n  set_index_from_ref(ref_index)\n\n  child.fn.chdir(make_testpath('dir_1'))\n  child.lua([[\n    MiniVisits.list_paths = function(...)\n      _G.list_paths_args = { ... }\n      return { 'file' }\n    end]])\n\n  mock_ui_select(1)\n  select_path('aaa', { opts = true })\n  validate_buf_name(0, 'file')\n\n  eq(child.lua_get('_G.list_paths_args'), { 'aaa', { opts = true } })\nend\n\nT['select_path()']['validates arguments'] = function()\n  expect.error(function() select_path(1) end, '`cwd`.*string')\nend\n\nT['select_label()'] = new_set()\n\nlocal select_label = forward_lua('MiniVisits.select_label')\n\nT['select_label()']['works'] = function()\n  local ref_index = {\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 3, labels = { xxx = true, aaa = true }, latest = 10 },\n      ['dir_1/file_1-2'] = { count = 2, labels = { xxx = true, bbb = true }, latest = 9 },\n      ['dir_1/subdir/file_1-1-1'] = { count = 1, labels = { bbb = true }, latest = 8 },\n    },\n  }\n  set_index_from_ref(ref_index)\n\n  child.fn.chdir(make_testpath('dir_1'))\n  edit('file')\n\n  mock_ui_select(1)\n  select_label('', getcwd())\n  eq(get_ui_select_log(), {\n    { items = { 'bbb', 'xxx', 'aaa' }, prompt = 'Visited labels' },\n    {\n      items = {\n        { path = make_testpath('dir_1', 'file_1-2'), text = 'file_1-2' },\n        { path = make_testpath('dir_1', 'subdir', 'file_1-1-1'), text = 'subdir/file_1-1-1' },\n      },\n      prompt = 'Visited paths',\n    },\n  })\n  validate_buf_name(0, 'file_1-2')\n\n  -- Should open path in relative form for nicer `:buffers`\n  expect.match(child.cmd_capture('buffers'):gsub('\\\\', '/'), '[^/]file_1%-2')\nend\n\nT['select_label()']['mimics empty buffer reuse'] = function()\n  local ref_index = { dir_1 = { ['dir_1/file_1-2'] = { count = 2, labels = { aaa = true }, latest = 9 } } }\n  set_index_from_ref(ref_index)\n  child.fn.chdir(make_testpath('dir_1'))\n  mock_ui_select(1)\n\n  local validate = function(ref_n_bufs)\n    select_label('', getcwd())\n    eq(#child.api.nvim_list_bufs(), ref_n_bufs)\n    child.cmd('%bwipeout!')\n  end\n\n  -- Should mimic `:h buffer-reuse` similar to how `:edit` does it\n  eq(child.api.nvim_get_current_buf() == 1, true)\n  validate(1)\n\n  eq(child.api.nvim_get_current_buf() ~= 1, true)\n  validate(1)\n\n  child.cmd('tabnew')\n  validate(2)\n\n  -- Should reuse only for strict set of conditions\n  child.api.nvim_buf_set_name(0, 'named-buf')\n  validate(2)\n\n  child.bo.buftype = 'quickfix'\n  validate(2)\n\n  child.cmd('split')\n  eq(#child.fn.win_findbuf(child.api.nvim_get_current_buf()), 2)\n  validate(2)\n\n  child.api.nvim_buf_set_lines(0, 0, -1, false, { ' ' })\n  validate(2)\n\n  child.bo.modified = true\n  validate(2)\nend\nT['select_label()']['can be properly canceled'] = function()\n  local ref_index = { dir_1 = { file = { count = 1, labels = { aaa = true }, latest = 10 } } }\n  set_index_from_ref(ref_index)\n\n  local init_buf_id = child.api.nvim_get_current_buf()\n  local init_buf_name = child.api.nvim_buf_get_name(init_buf_id)\n  mock_ui_select(nil)\n  select_label(make_testpath('file'))\n\n  eq(child.api.nvim_get_current_buf(), init_buf_id)\n  eq(child.api.nvim_buf_get_name(0), init_buf_name)\nend\n\nT['select_label()']['forwards arguments to `list_labels()` and `select_path()`'] = function()\n  local ref_index = { dir_1 = { file = { count = 1, labels = { aaa = true }, latest = 10 } } }\n  set_index_from_ref(ref_index)\n\n  child.fn.chdir(make_testpath('dir_1'))\n  child.lua([[\n    MiniVisits.list_labels = function(...)\n      _G.list_labels_args = { ... }\n      return { 'aaa' }\n    end\n    MiniVisits.select_path = function(...) _G.select_path_args = { ... } end]])\n\n  mock_ui_select(1)\n  select_label('path', 'cwd', { opts = true })\n\n  eq(child.lua_get('_G.list_labels_args'), { 'path', 'cwd', { opts = true } })\n  eq(child.lua_get('_G.select_path_args[1]'), 'cwd')\n\n  child.lua('_G.passed_filter = _G.select_path_args[2].filter')\n  eq(child.lua_get([[_G.passed_filter({ labels = { aaa = true } })]]), true)\n  eq(child.lua_get([[_G.passed_filter({ labels = { bbb = true } }) == true]]), false)\nend\n\nT['select_label()']['validates arguments'] = function()\n  expect.error(function() select_label(1, 'cwd') end, '`path`.*string')\n  expect.error(function() select_label('file', 1) end, '`cwd`.*string')\nend\n\nT['iterate_paths()'] = new_set()\n\nlocal iterate_paths = forward_lua('MiniVisits.iterate_paths')\n\nlocal setup_index_for_iterate = function()\n  set_index_from_ref({\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 3, latest = 3 },\n      ['dir_1/file_1-2'] = { count = 2, latest = 2 },\n      ['dir_1/file_1-3'] = { count = 1, latest = 1 },\n    },\n  })\n  local dir_path = make_testpath('dir_1')\n  child.fn.chdir(dir_path)\nend\n\nlocal validate_iterate = function(init_path, direction, opts, ref_path)\n  if init_path ~= nil then edit(init_path) end\n  iterate_paths(direction, getcwd(), opts)\n  validate_buf_name(0, ref_path)\nend\n\n--stylua: ignore\nT['iterate_paths()']['works'] = function()\n  setup_index_for_iterate()\n\n  validate_iterate('file_1-2', 'first',    {}, 'file_1-1')\n  validate_iterate('file_1-3', 'backward', {}, 'file_1-2')\n  validate_iterate('file_1-1', 'forward',  {}, 'file_1-2')\n  validate_iterate('file_1-2', 'last',     {}, 'file_1-3')\nend\n\n--stylua: ignore\nT['iterate_paths()']['works when current path is not in array'] = function()\n  setup_index_for_iterate()\n  local validate = function(...)\n    edit('file')\n    validate_iterate(...)\n  end\n\n  validate(nil, 'first',    {}, 'file_1-1')\n  validate(nil, 'backward', {}, 'file_1-3')\n  validate(nil, 'forward',  {}, 'file_1-1')\n  validate(nil, 'last',     {}, 'file_1-3')\n\n  validate(nil, 'first',    { n_times = 2 }, 'file_1-2')\n  validate(nil, 'backward', { n_times = 2 }, 'file_1-2')\n  validate(nil, 'forward',  { n_times = 2 }, 'file_1-2')\n  validate(nil, 'last',     { n_times = 2 }, 'file_1-2')\nend\n\n--stylua: ignore\nT['iterate_paths()']['works when current buffer does not have path'] = function()\n  setup_index_for_iterate()\n  local validate = function(...)\n    child.api.nvim_set_current_buf(child.api.nvim_create_buf(false, true))\n    validate_iterate(...)\n  end\n\n  validate(nil, 'first',    {}, 'file_1-1')\n  validate(nil, 'backward', {}, 'file_1-3')\n  validate(nil, 'forward',  {}, 'file_1-1')\n  validate(nil, 'last',     {}, 'file_1-3')\nend\n\nT['iterate_paths()']['works if there are not paths to iterate'] = function()\n  local validate = function(direction)\n    local init_buf = child.api.nvim_get_current_buf()\n    iterate_paths(direction)\n    eq(child.api.nvim_get_current_buf(), init_buf)\n    eq(child.api.nvim_buf_get_name(0), '')\n  end\n\n  validate('first')\n  validate('backward')\n  validate('forward')\n  validate('last')\nend\n\nT['iterate_paths()']['reuses current buffer when opening path'] = function()\n  setup_index_for_iterate()\n  edit(join_path(getcwd(), 'file_1-1'))\n  local file_buf_id = child.api.nvim_get_current_buf()\n\n  edit(join_path(getcwd(), 'file_1-2'))\n  child.api.nvim_buf_set_option(file_buf_id, 'buflisted', false)\n\n  iterate_paths('first')\n\n  eq(child.api.nvim_get_current_buf(), file_buf_id)\n  -- Should make unlisted buffer listed\n  eq(child.bo.buflisted, true)\nend\n\nT['iterate_paths()']['does not track visit'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n  setup_index_for_iterate()\n  local init_index = get_index()\n\n  iterate_paths('first')\n  sleep(test_track_delay + small_time)\n  iterate_paths('forward')\n  sleep(test_track_delay + small_time)\n  iterate_paths('backward')\n  sleep(test_track_delay + small_time)\n  iterate_paths('last')\n  sleep(test_track_delay + small_time)\n\n  eq(get_index(), init_index)\n\n  -- Should properly cleanup\n  eq(child.g.minivisits_disable, vim.NIL)\n  for _, buf_id in ipairs(child.api.nvim_list_bufs()) do\n    local lua_cmd = string.format('vim.b[%d].minivisits_disable', buf_id)\n    eq(child.lua_get(lua_cmd), vim.NIL)\n  end\nend\n\nT['iterate_paths()']['respects `cwd` argument'] = function()\n  setup_index_for_iterate()\n  child.fn.chdir('subdir')\n\n  iterate_paths('first', make_testpath('dir_1'))\n  validate_buf_name(0, make_testpath('dir_1', 'file_1-1'))\nend\n\nT['iterate_paths()']['respects `opts.filter`'] = function()\n  set_index_from_ref({\n    dir_1 = {\n      ['dir_1/file_1-1'] = { count = 1, labels = { aaa = true }, latest = 1 },\n      ['dir_1/file_1-2'] = { count = 10, latest = 10 },\n    },\n  })\n\n  iterate_paths('first', make_testpath('dir_1'), { filter = 'aaa' })\n  validate_buf_name(0, make_testpath('dir_1', 'file_1-1'))\nend\n\nT['iterate_paths()']['respects `opts.sort`'] = function()\n  child.lua([[_G.sort = function() return { { path = 'new-file' } } end]])\n  child.lua([[MiniVisits.iterate_paths('first', nil, { sort = _G.sort })]])\n  validate_buf_name(0, 'new-file')\nend\n\n--stylua: ignore\nT['iterate_paths()']['respects `opts.n_times`'] = function()\n  setup_index_for_iterate()\n\n  validate_iterate('file_1-3', 'first',    { n_times = 2 }, 'file_1-2')\n  validate_iterate('file_1-3', 'backward', { n_times = 2 }, 'file_1-1')\n  validate_iterate('file_1-1', 'forward',  { n_times = 2 }, 'file_1-3')\n  validate_iterate('file_1-1', 'last',     { n_times = 2 }, 'file_1-2')\nend\n\n--stylua: ignore\nT['iterate_paths()']['respects `opts.wrap`'] = function()\n  setup_index_for_iterate()\n\n  -- No wrap by default\n  validate_iterate('file_1-1', 'first',    { n_times = 5 }, 'file_1-3')\n  validate_iterate('file_1-2', 'backward', { n_times = 5 }, 'file_1-1')\n  validate_iterate('file_1-2', 'forward',  { n_times = 5 }, 'file_1-3')\n  validate_iterate('file_1-1', 'last',     { n_times = 5 }, 'file_1-1')\n\n  validate_iterate('file_1-1', 'first',    { n_times = 5, wrap = true }, 'file_1-2')\n  validate_iterate('file_1-2', 'backward', { n_times = 5, wrap = true }, 'file_1-3')\n  validate_iterate('file_1-2', 'forward',  { n_times = 5, wrap = true }, 'file_1-1')\n  validate_iterate('file_1-1', 'last',     { n_times = 5, wrap = true }, 'file_1-2')\nend\n\nT['iterate_paths()']['validates arguments'] = function()\n  expect.error(function() iterate_paths(1, 'cwd') end, '`direction`.*one of')\n  expect.error(function() iterate_paths('forward', 1) end, '`cwd`.*string')\nend\n\nT['get_index()'] = new_set()\n\nT['get_index()']['works'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n  eq(get_index(), {})\n\n  local path = make_testpath('file')\n  edit(path)\n  sleep(test_track_delay)\n  eq(get_index(), { [getcwd()] = { [path] = { count = 1, latest = child_time() } } })\n\n  -- Should return table copy\n  local is_ok = child.lua([[\n    _G.cur_index = MiniVisits.get_index()\n    _G.ref_index = vim.deepcopy(_G.cur_index)\n    _G.cur_index['aa'] = {}\n    return vim.deep_equal(MiniVisits.get_index(), _G.ref_index)\n  ]])\n  eq(is_ok, true)\nend\n\nT['set_index()'] = new_set()\n\nT['set_index()']['works'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n\n  local path, cwd = make_testpath('file'), getcwd()\n  child.lua(string.format('_G.path, _G.cwd = %s, %s', vim.inspect(path), vim.inspect(cwd)))\n  child.lua([[\n    _G.index_ref = { [vim.fn.getcwd():gsub('\\\\', '/')] = { [_G.path] = { count = 1, latest = 10 } } }\n    MiniVisits.set_index(_G.index_ref)\n  ]])\n\n  eq(get_index(), { [cwd] = { [path] = { count = 1, latest = 10 } } })\n\n  -- Should set table copy\n  edit(path)\n  sleep(test_track_delay)\n  eq(get_index(), { [cwd] = { [path] = { count = 2, latest = child_time() } } })\n  eq(child.lua_get('_G.index_ref'), { [cwd] = { [path] = { count = 1, latest = 10 } } })\nend\n\nT['set_index()']['treats set index as whole history and not only current session'] = function()\n  local store_path = make_testpath('tmp-index')\n  MiniTest.finally(vim.schedule_wrap(function() vim.fn.delete(store_path, 'rf') end))\n  child.fn.writefile({ 'return { aaa = { bbb = { count = 10, latest = 10 } } }' }, store_path)\n\n  child.lua('MiniVisits.config.track.delay = 10')\n  child.lua('MiniVisits.config.store.path = ' .. vim.inspect(store_path))\n\n  local path, cwd = make_testpath('file'), getcwd()\n  set_index({ [cwd] = { [path] = { count = 1, latest = child_time() } } })\n  eq(list_paths(''), { path })\nend\n\nT['set_index()']['validates arguments'] = function()\n  local validate = function(x, error_pattern)\n    expect.error(function() set_index(x) end, error_pattern)\n  end\n\n  validate(1, '`index`.*table')\n  validate({ { path = { count = 1, latest = 1 } } }, 'First level keys in `index`.*strings')\n  validate({ cwd = 1 }, 'First level values in `index`.*tables')\n  validate({ cwd = { { count = 1, latest = 1 } } }, 'Second level keys in `index`.*strings')\n  validate({ cwd = { path = 1 } }, 'Second level values in `index`.*tables')\n  validate({ cwd = { path = { count = '1', latest = 1 } } }, '`count`.*in `index`.*numbers')\n  validate({ cwd = { path = { count = 1, latest = '1' } } }, '`latest`.*in `index`.*numbers')\n  validate({ cwd = { path = { count = 1, latest = 1, labels = 1 } } }, '`labels`.*table')\n  validate({ cwd = { path = { count = 1, latest = 1, labels = { true } } } }, 'Keys in `labels`.*strings')\n  validate({ cwd = { path = { count = 1, latest = 1, labels = { aaa = 1 } } } }, 'Values in `labels`.*`true`')\nend\n\nT['reset_index()'] = new_set()\n\nlocal reset_index = forward_lua('MiniVisits.reset_index')\n\nT['reset_index()']['works'] = function()\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  child.fn.mkdir(vim.fn.fnamemodify(store_path, ':h'), 'p')\n  child.fn.writefile({ 'return { aaa = { bbb = { count = 10, latest = 10 } } }' }, store_path)\n\n  local path, cwd = make_testpath('file'), getcwd()\n  set_index({ [cwd] = { [path] = { count = 1, latest = child_time() } } })\n\n  child.lua('MiniVisits.reset_index()')\n  eq(get_index(), { aaa = { bbb = { count = 10, latest = 10 } } })\nend\n\nT['reset_index()']['does nothing if reading index failed'] = function()\n  -- No index file\n  local index = { [getcwd()] = { [make_testpath('file')] = { count = 1, latest = 10 } } }\n  set_index(index)\n\n  reset_index()\n  eq(get_index(), index)\n\n  -- Error during `MiniVisits.read_index()`\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  child.fn.mkdir(vim.fn.fnamemodify(store_path, ':h'), 'p')\n  child.fn.writefile({ 'Not a Lua code' }, store_path)\n\n  reset_index()\n  eq(get_index(), index)\nend\n\nT['normalize_index()'] = new_set()\n\nlocal normalize_index = forward_lua('MiniVisits.normalize_index')\n\nT['normalize_index()']['works'] = function()\n  local path, cwd = make_testpath('file'), getcwd()\n  local index = { [cwd] = { [path] = { count = 1, labels = { aaa = true }, latest = child_time() } } }\n  set_index(index)\n\n  -- Should return the output of `MiniVisits.gen_normalize.default` by default\n  child.lua([[MiniVisits.gen_normalize.default = function()\n    return function(...)\n      _G.normalize_args = { ... }\n      return ...\n    end\n  end]])\n\n  eq(normalize_index(), index)\n  eq(child.lua_get('_G.normalize_args'), { index })\n\n  -- Should respect input even if there is session index present\n  local index_2 = { cwd = { path = { count = 1, latest = 10 } } }\n  eq(normalize_index(index_2), index_2)\nend\n\nT['normalize_index()']['respects `config.store.normalize`'] = function()\n  local path, cwd = make_testpath('file'), getcwd()\n  local index = { [cwd] = { [path] = { count = 1, labels = { aaa = true }, latest = child_time() } } }\n  set_index(index)\n\n  -- Should return the output of `MiniVisits.gen_normalize.default` by default\n  child.lua([[MiniVisits.config.store.normalize = function(...)\n    _G.normalize_args = { ... }\n    return ...\n  end]])\n\n  eq(normalize_index(), index)\n  eq(child.lua_get('_G.normalize_args'), { index })\nend\n\nT['normalize_index()']['validates output'] = function()\n  child.lua('MiniVisits.config.store.normalize = function() return 1 end')\n  expect.error(normalize_index, '`index` after normalization')\nend\n\nT['normalize_index()']['validates arguments'] = function()\n  expect.error(function() normalize_index(1) end, '`index`.*table')\nend\n\nT['read_index()'] = new_set()\n\nlocal read_index = forward_lua('MiniVisits.read_index')\n\nT['read_index()']['works'] = function()\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  child.fn.mkdir(vim.fn.fnamemodify(store_path, ':h'), 'p')\n  child.fn.writefile({ 'return { aaa = { bbb = { count = 10, latest = 10 } } }' }, store_path)\n\n  eq(read_index(), { aaa = { bbb = { count = 10, latest = 10 } } })\nend\n\nT['read_index()']['respects `store_path` argument'] = function()\n  local store_path = make_testpath('test-index')\n  MiniTest.finally(function() vim.fn.delete(store_path) end)\n  child.fn.writefile({ 'return { aaa = { bbb = { count = 10, latest = 10 } } }' }, store_path)\n\n  eq(read_index(store_path), { aaa = { bbb = { count = 10, latest = 10 } } })\nend\n\nT['read_index()']['returns `nil` if can not locate file'] = function()\n  eq(read_index('non-existing-file'), vim.NIL)\n  eq(read_index(''), vim.NIL)\nend\n\nT['read_index()']['throws error if Lua sourcing failed'] = function()\n  local store_path = make_testpath('test-index')\n  MiniTest.finally(function() vim.fn.delete(store_path) end)\n  child.fn.writefile({ 'return {' }, store_path)\n  expect.error(function() read_index(store_path) end)\nend\n\nT['read_index()']['validates arguments'] = function()\n  expect.error(function() read_index(1) end, '`store_path`.*string')\nend\n\nT['write_index()'] = new_set()\n\nlocal write_index = forward_lua('MiniVisits.write_index')\n\nT['write_index()']['works'] = function()\n  local path, cwd = make_testpath('file'), getcwd()\n  local index = { [cwd] = { [path] = { count = 1, latest = child_time() } } }\n  set_index(index)\n\n  -- Should call `normalize_index` and write its output\n  child.lua([[MiniVisits.normalize_index = function(index)\n    _G.input_index = vim.deepcopy(index)\n    return { aaa = { bbb = { count = 10, latest = 10 } } }\n  end]])\n\n  write_index()\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  eq(\n    table.concat(vim.fn.readfile(store_path), '\\n'),\n    'return {\\n  aaa = {\\n    bbb = {\\n      count = 10,\\n      latest = 10\\n    }\\n  }\\n}'\n  )\n\n  eq(child.lua_get('_G.input_index'), index)\nend\n\nT['write_index()']['respects arguments'] = function()\n  -- Should create non-existing parent directories\n  local store_path = make_testpath('nondir/subdir/test-index')\n  MiniTest.finally(function() vim.fn.delete(store_path) end)\n  local path, cwd = make_testpath('file'), getcwd()\n  local index = { [cwd] = { [path] = { count = 1, latest = child_time() } } }\n  write_index(store_path, index)\n\n  eq(table.concat(vim.fn.readfile(store_path), '\\n'), 'return ' .. vim.inspect(index))\nend\n\nT['write_index()']['validates arguments'] = function()\n  expect.error(function() write_index(1, { aaa = { bbb = { count = 10, latest = 10 } } }) end, '`store_path`.*string')\n  expect.error(function() write_index(make_testpath('test-index'), 1) end, '`index`.*table')\nend\n\nT['rename_in_index()'] = new_set()\n\nlocal rename_in_index = forward_lua('MiniVisits.rename_in_index')\n\nT['rename_in_index()']['works for files'] = function()\n  local path, cwd = make_testpath('file'), test_dir_absolute\n  local index = {\n    [cwd] = {\n      [path] = { count = 1, latest = 10 },\n      [path .. '_suffix'] = { count = 2, latest = 11 },\n    },\n    [cwd .. '_2'] = {\n      [path] = { count = 10, latest = 100 },\n      [path .. '_suffix'] = { count = 20, latest = 110 },\n    },\n  }\n  set_index(index)\n\n  -- Should rename only full matches in whole index object\n  eq(rename_in_index(path, path .. '_new'), {\n    [cwd] = {\n      [path .. '_new'] = { count = 1, latest = 10 },\n      [path .. '_suffix'] = { count = 2, latest = 11 },\n    },\n    [cwd .. '_2'] = {\n      [path .. '_new'] = { count = 10, latest = 100 },\n      [path .. '_suffix'] = { count = 20, latest = 110 },\n    },\n  })\n\n  -- Should allow specifying index as argument\n  eq(\n    rename_in_index(path, path .. '_very_new', { [cwd] = { [path] = { count = 2, latest = 20 } } }),\n    { [cwd] = { [path .. '_very_new'] = { count = 2, latest = 20 } } }\n  )\n\n  -- Should nor affect current index\n  eq(get_index(), index)\nend\n\nT['rename_in_index()']['works for directories'] = function()\n  local path = make_testpath('dir_1', 'file_1-1')\n  local cwd, cwd_2 = make_testpath('dir_1'), make_testpath('dir_1_1')\n  local index = {\n    [cwd] = { [path] = { count = 1, latest = 10 } },\n    [cwd_2] = { [path] = { count = 10, latest = 100 } },\n  }\n  set_index(index)\n\n  -- Should rename both full matches and as a parent\n  local path_to = cwd .. '_new'\n  eq(rename_in_index(cwd, path_to), {\n    [path_to] = { [join_path(path_to, 'file_1-1')] = { count = 1, latest = 10 } },\n    [cwd_2] = { [join_path(path_to, 'file_1-1')] = { count = 10, latest = 100 } },\n  })\n\n  -- Should allow specifying index as argument\n  eq(\n    rename_in_index(cwd, cwd .. '_very_new', { [cwd] = { [path] = { count = 2, latest = 20 } } }),\n    { [cwd .. '_very_new'] = { [join_path(cwd .. '_very_new', 'file_1-1')] = { count = 2, latest = 20 } } }\n  )\n\n  -- Can rename directory to its child\n  eq(\n    rename_in_index(cwd, cwd .. '/child', { [cwd] = { [path] = { count = 2, latest = 20 } } }),\n    { [cwd .. '/child'] = { [join_path(cwd .. '/child', 'file_1-1')] = { count = 2, latest = 20 } } }\n  )\n\n  -- Should nor affect current index\n  eq(get_index(), index)\nend\n\nT['rename_in_index()']['validates_arguments'] = function()\n  expect.error(function() rename_in_index(1, 'bbb') end, '`path_from`.*string')\n  expect.error(function() rename_in_index('aaa', 2) end, '`path_to`.*string')\n  expect.error(function() rename_in_index('aaa', 'bbb', 1) end, '`index`.*table')\nend\n\nT['gen_filter'] = new_set()\n\nT['gen_filter']['default()'] = new_set()\n\nT['gen_filter']['default()']['works'] = function()\n  child.lua('_G.f = MiniVisits.gen_filter.default()')\n  eq(child.lua_get('_G.f()'), true)\n  eq(child.lua_get('_G.f({ aaa = { bbb = { count = 10, latest = 10 } } })'), true)\nend\n\nT['gen_filter']['this_session()'] = new_set()\n\nT['gen_filter']['this_session()']['works'] = function()\n  child.lua('_G.session_start = os.time()')\n  child.lua('_G.f = MiniVisits.gen_filter.this_session()')\n\n  eq(child.lua_get('_G.f({ latest = _G.session_start - 10 })'), false)\n  eq(child.lua_get('_G.f({ latest = _G.session_start + 10 })'), true)\nend\n\nT['gen_sort'] = new_set()\n\nT['gen_sort']['default()'] = new_set()\n\nlocal validate_gen_sort = function(method, path_data_arr, recency_weight, ref_paths)\n  child.lua([[_G.path_data_arr = ]] .. vim.inspect(path_data_arr))\n  child.lua([[_G.path_data_arr_ref = vim.deepcopy(_G.path_data_arr)]])\n\n  local out = child.lua_get(\n    'MiniVisits.gen_sort.' .. method .. '(...)(_G.path_data_arr)',\n    { { recency_weight = recency_weight } }\n  )\n  local out_paths = vim.tbl_map(function(x) return x.path end, out)\n  eq(out_paths, ref_paths)\n\n  -- Should not modify input array\n  eq(child.lua_get('vim.deep_equal(_G.path_data_arr, _G.path_data_arr_ref)'), true)\nend\n\n--stylua: ignore\nT['gen_sort']['default()']['works'] = function()\n  local path_data_arr = {\n    { path = 'aaa', count = 100, latest = 3 },   -- ranked 1 and 2\n    { path = 'bbb', count = 3,   latest = 2 },   -- ranked 2 and 3\n    { path = 'ccc', count = 2,   latest = 100 }, -- ranked 3 and 1\n    { path = 'ddd', count = 1,   latest = 1 },   -- ranked 4 and 4\n  }\n\n  validate_gen_sort('default', path_data_arr, nil, { 'aaa', 'ccc', 'bbb', 'ddd' })\n  validate_gen_sort('default', path_data_arr, 0.5, { 'aaa', 'ccc', 'bbb', 'ddd' })\n  validate_gen_sort('default', path_data_arr, 0,   { 'aaa', 'bbb', 'ccc', 'ddd' })\n  validate_gen_sort('default', path_data_arr, 1,   { 'ccc', 'aaa', 'bbb', 'ddd' })\nend\n\nT['gen_sort']['default()']['handles ties'] = function()\n  local path_data_arr = {\n    { path = 'aaa', count = 9, latest = 4 }, -- ranked 1 and 4 = 2.5\n    { path = 'bbb', count = 2, latest = 6 }, -- ranked 4 and 2 = 3\n    { path = 'ccc', count = 2, latest = 5 }, -- ranked 4 and 3 = 3.5\n    { path = 'ddd', count = 2, latest = 1 }, -- ranked 4 and 7 = 5.5\n    { path = 'eee', count = 2, latest = 3 }, -- ranked 4 and 5 = 4.5\n    { path = 'fff', count = 2, latest = 2 }, -- ranked 4 and 6 = 5\n    { path = 'ggg', count = 1, latest = 7 }, -- ranked 7 and 1 = 4\n  }\n\n  -- In ranks (should assign average rank)\n  validate_gen_sort('default', path_data_arr, 0.5, { 'aaa', 'bbb', 'ccc', 'ggg', 'eee', 'fff', 'ddd' })\n\n  -- In output score (should sort by path)\n  validate_gen_sort('default', path_data_arr, 0, { 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg' })\nend\n\nT['gen_sort']['z()'] = new_set()\n\nT['gen_sort']['z()']['works'] = function()\n  local cur_time = child_time()\n  local path_data_arr = {\n    { path = 'aaa', count = 2, latest = cur_time - 1 },\n    { path = 'bbb', count = 3, latest = cur_time - 10000 },\n    { path = 'ccc', count = 4, latest = cur_time - 20000 },\n    { path = 'ddd', count = 1, latest = cur_time - 30000 },\n  }\n\n  validate_gen_sort('z', path_data_arr, 0, { 'aaa', 'bbb', 'ccc', 'ddd' })\nend\n\nT['gen_normalize'] = new_set()\n\nT['gen_normalize']['default()'] = new_set()\n\nlocal validate_default_normalize = function(opts, index_input, index_ref)\n  child.lua('_G.normalize = MiniVisits.gen_normalize.default(...)', { opts })\n  eq(child.lua_get('_G.normalize(...)', { index_input }), index_ref)\nend\n\nT['gen_normalize']['default()']['works'] = function()\n  local path, path_2, path_3 =\n    make_testpath('file'), make_testpath('dir_1', 'file_1-1'), make_testpath('dir_1', 'file_1-2')\n  local cwd, cwd_2 = getcwd(), test_dir_absolute\n\n  validate_default_normalize({}, {\n    [cwd] = {\n      [path] = { count = 600, labels = { aaa = true }, latest = 10 },\n      [path_2] = { count = 400, latest = 20 },\n      [path_3] = { count = 1, latest = 30 },\n      ['non-path'] = { count = 1, latest = 40 },\n    },\n    [cwd_2] = {\n      [path] = { count = 10, labels = { bbb = true }, latest = 100 },\n      ['non-path-2'] = { count = 20, latest = 200 },\n    },\n  }, {\n    [cwd] = {\n      -- Should multiply each `count` by `800 / 1001` and keep 2 decimal places\n      [path] = { count = 479.52, labels = { aaa = true }, latest = 10 },\n      [path_2] = { count = 319.68, latest = 20 },\n      [path_3] = { count = 0.8, latest = 30 },\n      -- Should prune non-paths by default\n    },\n    [cwd_2] = {\n      -- Should decay per cwd\n      [path] = { count = 10, labels = { bbb = true }, latest = 100 },\n    },\n  })\n\n  -- Does decay even for a single entry\n  validate_default_normalize(\n    {},\n    { [cwd] = { [path] = { count = 1001, latest = 10 } } },\n    { [cwd] = { [path] = { count = 800, latest = 10 } } }\n  )\n\n  -- Works even for a very large total `count` sum\n  validate_default_normalize(\n    {},\n    { [cwd] = { [path] = { count = 10000, latest = 10 }, [path_2] = { count = 10000, latest = 20 } } },\n    { [cwd] = { [path] = { count = 400, latest = 10 }, [path_2] = { count = 400, latest = 20 } } }\n  )\nend\n\nT['gen_normalize']['default()']['prunes before and after decay'] = function()\n  local path, path_2 = make_testpath('file'), make_testpath('dir_1', 'file_1-1')\n  local cwd = getcwd()\n\n  -- Before decay\n  validate_default_normalize({}, {\n    [cwd] = {\n      [path] = { count = 999.9, latest = 10 },\n      [path_2] = { count = 0.4, latest = 20 },\n    },\n  }, {\n    [cwd] = {\n      -- There is no decay as `path_2` entry was removed before and total sum\n      -- is now below threshold\n      [path] = { count = 999.9, latest = 10 },\n    },\n  })\n\n  -- After decay\n  validate_default_normalize({}, {\n    [cwd] = {\n      [path] = { count = 1000, latest = 10 },\n      [path_2] = { count = 0.51, latest = 20 },\n    },\n  }, {\n    [cwd] = {\n      -- There is decay in `path` and no `path_2` entry as no pruning was done\n      -- before decay. After it, `path_2` has `count = 0.41` and is pruned.\n      [path] = { count = 799.59, latest = 10 },\n    },\n  })\nend\n\nT['gen_normalize']['default()']['does not prune if visit has label'] = function()\n  local path, cwd = make_testpath('file'), getcwd()\n  local index = { [cwd] = { [path] = { count = 0, labels = { aaa = true }, latest = 0 } } }\n  validate_default_normalize({}, index, index)\nend\n\nT['gen_normalize']['default()']['respects `opts.decay_threshold`'] = function()\n  local path, path_2 = make_testpath('file'), make_testpath('dir_1', 'file_1-1')\n  local cwd = getcwd()\n\n  local index = {\n    [cwd] = {\n      [path] = { count = 800, latest = 10 },\n      [path_2] = { count = 150, latest = 20 },\n    },\n  }\n\n  validate_default_normalize({}, index, index)\n\n  validate_default_normalize({ decay_threshold = 949.9 }, index, {\n    [cwd] = {\n      [path] = { count = 673.68, latest = 10 },\n      [path_2] = { count = 126.32, latest = 20 },\n    },\n  })\nend\n\nT['gen_normalize']['default()']['respects `opts.decay_target`'] = function()\n  local path, path_2 = make_testpath('file'), make_testpath('dir_1', 'file_1-1')\n  local cwd = getcwd()\n\n  local index = {\n    [cwd] = {\n      [path] = { count = 800, latest = 10 },\n      [path_2] = { count = 201, latest = 20 },\n    },\n  }\n\n  validate_default_normalize({}, index, {\n    [cwd] = {\n      [path] = { count = 639.36, latest = 10 },\n      [path_2] = { count = 160.64, latest = 20 },\n    },\n  })\n\n  validate_default_normalize({ decay_target = 100 }, index, {\n    [cwd] = {\n      [path] = { count = 79.92, latest = 10 },\n      [path_2] = { count = 20.08, latest = 20 },\n    },\n  })\nend\n\nT['gen_normalize']['default()']['respects `opts.prune_threshold`'] = function()\n  local path, path_2 = make_testpath('file'), make_testpath('dir_1', 'file_1-1')\n  local cwd = getcwd()\n\n  local index = {\n    [cwd] = {\n      [path] = { count = 0.4, latest = 10 },\n      [path_2] = { count = 1, latest = 20 },\n    },\n  }\n\n  validate_default_normalize({}, index, { [cwd] = { [path_2] = { count = 1, latest = 20 } } })\n\n  validate_default_normalize({ prune_threshold = 1.01 }, index, {})\n  validate_default_normalize({ prune_threshold = 0.1 }, index, index)\nend\n\nT['gen_normalize']['default()']['respects `opts.prune_paths`'] = function()\n  local path, path_2 = make_testpath('file'), make_testpath('dir_1', 'file_1-1')\n  local cwd, cwd_2 = getcwd(), test_dir_absolute\n\n  local index = {\n    [cwd] = {\n      [path] = { count = 10, latest = 10 },\n      ['non-path'] = { count = 10, latest = 10 },\n    },\n    ['non-cwd'] = {\n      [path] = { count = 20, latest = 20 },\n    },\n    [cwd_2] = {\n      ['non-path'] = { count = 30, latest = 30 },\n    },\n  }\n\n  -- Should not remove paths by default\n  validate_default_normalize({}, index, { [cwd] = { [path] = { count = 10, latest = 10 } } })\n\n  validate_default_normalize({ prune_paths = false }, index, index)\nend\n\nT['gen_normalize']['default()']['has output validating arguments'] = function()\n  expect.error(function() child.lua('MiniVisits.gen_normalize.default()(1)') end, '`index`.*table')\nend\n\n-- Integration tests ----------------------------------------------------------\nT['Tracking'] = new_set()\n\nT['Tracking']['works'] = function()\n  local path, path_2 = make_testpath('file'), make_testpath('dir1', 'file1-1')\n\n  edit(path)\n  eq(get_index(), {})\n\n  sleep(default_track_delay - 2 * small_time)\n  eq(get_index(), {})\n\n  -- Should implement debounce style delay\n  edit(path_2)\n  sleep(default_track_delay - 2 * small_time)\n  eq(get_index(), {})\n  -- - \"Latest\" time should use time of actual registration\n  sleep(2 * small_time)\n  eq(get_index(), { [getcwd()] = { [path_2] = { count = 1, latest = child_time() } } })\nend\n\nT['Tracking']['registers only normal buffers'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n\n  -- Scratch buffer\n  local buf_id = child.api.nvim_create_buf(false, true)\n  child.api.nvim_set_current_buf(buf_id)\n  sleep(test_track_delay + small_time)\n  eq(get_index(), {})\n\n  -- Help buffer\n  child.cmd('help')\n  sleep(test_track_delay + small_time)\n  eq(get_index(), {})\nend\n\nT['Tracking']['can register directories'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n\n  local path = make_testpath('dir1')\n  edit(path)\n  sleep(test_track_delay + small_time)\n  validate_index_entry('', path, { count = 1 })\nend\n\nT['Tracking']['does not register same path twice in a row'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n\n  local path = make_testpath('file')\n  edit(path)\n  sleep(test_track_delay + small_time)\n  validate_index_entry('', path, { count = 1 })\n\n  child.cmd('help')\n  sleep(test_track_delay + small_time)\n  validate_index_entry('', path, { count = 1 })\n\n  edit(path)\n  sleep(test_track_delay + small_time)\n  validate_index_entry('', path, { count = 1 })\nend\n\nT['Tracking']['is done on `BufEnter` by default'] = function()\n  child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n\n  local path, path_2 = make_testpath('file'), make_testpath('dir1', 'file1-1')\n  edit(path)\n  sleep(test_track_delay + small_time)\n\n  child.cmd('vertical split | edit ' .. child.fn.fnameescape(path_2))\n  sleep(test_track_delay + small_time)\n\n  -- Going back and forth should count as visits\n  child.cmd('wincmd w')\n  sleep(test_track_delay + small_time)\n  child.cmd('wincmd w')\n  sleep(test_track_delay + small_time)\n\n  validate_index_entry('', path, { count = 2 })\n  validate_index_entry('', path_2, { count = 2 })\nend\n\nT['Tracking']['respects `config.track.event`'] = function()\n  child.cmd('autocmd! MiniVisits')\n  load_module({ track = { event = 'BufHidden', delay = test_track_delay } })\n\n  local path = make_testpath('file')\n  edit(path)\n  sleep(test_track_delay + small_time)\n  eq(get_index(), {})\n\n  child.api.nvim_set_current_buf(child.api.nvim_create_buf(false, true))\n  sleep(test_track_delay + small_time)\n  validate_index_entry('', path, { count = 1 })\nend\n\nT['Tracking']['can have `config.track.event = \"\"` to disable tracking'] = function()\n  child.cmd('autocmd! MiniVisits')\n  load_module({ track = { event = '', delay = test_track_delay } })\n  eq(child.cmd_capture('au MiniVisits'):find('BufEnter'), nil)\n\n  local path = make_testpath('file')\n  edit(path)\n  sleep(test_track_delay + small_time)\n  eq(get_index(), {})\nend\n\nT['Tracking']['can have `config.track.delay = 0`'] = function()\n  child.lua('MiniVisits.config.track.delay = 0')\n  local path = make_testpath('file')\n  edit(path)\n  validate_index_entry('', path, { count = 1 })\nend\n\nT['Tracking']['respects `vim.{g,b}.minivisits_disable`'] = new_set({\n  parametrize = { { 'g' }, { 'b' } },\n}, {\n  test = function(var_type)\n    child.lua('MiniVisits.config.track.delay = ' .. test_track_delay)\n    local path, path_2 = make_testpath('file'), make_testpath('dir1', 'file1-1')\n\n    -- Setting variable after event but before delay expired should work\n    edit(path)\n    sleep(0.1 * test_track_delay)\n    child[var_type].minivisits_disable = true\n    sleep(0.9 * test_track_delay + small_time)\n    eq(get_index(), {})\n\n    -- Global variable should disable globally, buffer - per buffer\n    edit(path_2)\n    sleep(test_track_delay + small_time)\n    if var_type == 'g' then\n      eq(get_index(), {})\n    else\n      validate_index_entry('', path_2, { count = 1 })\n    end\n\n    -- Buffer-local variable should still work\n    edit(path)\n    sleep(test_track_delay + small_time)\n    validate_index_entry('', path, nil)\n  end,\n})\n\nT['Storing'] = new_set()\n\nT['Storing']['works'] = function()\n  child.cmd('doautocmd VimLeavePre')\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  eq(child.fn.readfile(store_path), { 'return {}' })\nend\n\nT['Storing']['respects `config.store.autowrite`'] = function()\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  eq(child.fn.filereadable(store_path), 0)\n\n  -- Should be respected even if set after `setup()`\n  child.lua('MiniVisits.config.store.autowrite = false')\n  child.cmd('doautocmd VimLeavePre')\n  eq(child.fn.filereadable(store_path), 0)\nend\n\nT['Storing']['respects `config.store.normalize`'] = function()\n  child.lua([[MiniVisits.config.store.normalize = function(...)\n    _G.normalize_args = { ... }\n    return { dir = { file = { count = 10, latest = 100 } } }\n  end]])\n  child.cmd('doautocmd VimLeavePre')\n  local store_path = child.lua_get('MiniVisits.config.store.path')\n  eq(\n    table.concat(child.fn.readfile(store_path), '\\n'),\n    'return {\\n  dir = {\\n    file = {\\n      count = 10,\\n      latest = 100\\n    }\\n  }\\n}'\n  )\n\n  eq(child.lua_get('_G.normalize_args'), { {} })\nend\n\nT['Storing']['respects `config.store.path`'] = function()\n  local store_path = make_testpath('test-index')\n  MiniTest.finally(function() vim.fn.delete(store_path) end)\n  child.lua('MiniVisits.config.store.path = ' .. vim.inspect(store_path))\n\n  child.stop()\n  eq(vim.fn.readfile(store_path), { 'return {}' })\nend\n\nreturn T\n"
  }
]